From 8748a3e7f0d47f1cc91a5bf3350d1cd321aff72a Mon Sep 17 00:00:00 2001 From: RedStar Date: Fri, 12 Jun 2026 13:54:08 +0200 Subject: [PATCH 01/12] refactor: switch to new stack --- .github/workflows/codeql-analysis.yml | 27 +- .github/workflows/continuous-delivery.yml | 4 +- .github/workflows/continuous-integration.yml | 9 +- .github/workflows/update-tlds.yml | 2 +- .gitignore | 8 +- .oxfmtrc.json | 2 +- .oxlintrc.json | 9 +- crowdin.yml | 6 +- package.json | 119 +- pnpm-lock.yaml | 6366 +++++------------ pnpm-workspace.yaml | 10 +- prisma/schema.prisma | 767 +- projects/bot/Dockerfile | 62 + projects/bot/package.json | 51 + .../build => projects/bot/scripts}/clean.mjs | 2 +- projects/bot/src/.env | 38 + projects/bot/src/.env.development | 35 + {src => projects/bot/src}/.env.test | 0 projects/bot/src/commands/Admin/eval.ts | 158 + .../commands/Management/Helpers/guild-info.ts | 84 +- .../commands/Management/Helpers/role-info.ts | 28 +- .../Management/Members/stickyRoles.ts | 26 +- .../Message Filters/attachmentMode.ts | 20 + .../Message Filters/capitalsMode.ts | 20 + .../Management/Message Filters/filter.ts | 90 + .../Management/Message Filters/filterMode.ts | 20 + .../Management/Message Filters/inviteMode.ts | 20 + .../Management/Message Filters/linkMode.ts | 20 + .../Management/Message Filters/messageMode.ts | 20 + .../Management/Message Filters/newlineMode.ts | 20 + .../Reaction Filters/reactionMode.ts | 20 + .../commands/Moderation/Management/history.ts | 145 + .../Moderation/Management/moderations.ts | 169 + .../src/commands/Moderation/Utilities/case.ts | 45 + .../Moderation/Utilities/permissions.ts | 45 + .../commands/Moderation/Utilities/reason.ts | 57 + .../commands/Moderation/Utilities/slowmode.ts | 8 +- .../src/commands/Moderation/Utilities/time.ts | 142 + .../bot/src/commands/Moderation/addrole.ts | 44 + projects/bot/src/commands/Moderation/ban.ts | 57 + .../bot/src}/commands/Moderation/dehoist.ts | 21 +- projects/bot/src/commands/Moderation/kick.ts | 46 + .../bot/src}/commands/Moderation/lockdown.ts | 48 +- projects/bot/src/commands/Moderation/mute.ts | 34 + projects/bot/src/commands/Moderation/prune.ts | 212 + .../bot/src/commands/Moderation/removerole.ts | 44 + .../src/commands/Moderation/setnickname.ts | 41 + .../bot/src/commands/Moderation/softban.ts | 57 + .../commands/Moderation/togglemoderationdm.ts | 13 +- projects/bot/src/commands/Moderation/unban.ts | 63 + .../bot/src/commands/Moderation/unmute.ts | 31 + .../bot/src/commands/Moderation/unwarn.ts | 71 + .../bot/src/commands/Moderation/voicekick.ts | 34 + projects/bot/src/commands/Moderation/warn.ts | 28 + projects/bot/src/commands/Tools/whois.ts | 149 + projects/bot/src/config.ts | 7 + projects/bot/src/lib/Client.ts | 73 + projects/bot/src/lib/augments.d.ts | 21 + .../src}/lib/discord/GuildMemberFetchQueue.ts | 2 + .../bot/src/lib/i18n/languageKeys/index.ts | 1 + .../bot/src/lib/i18n/languageKeys/keys/All.ts | 14 + .../lib/i18n/languageKeys/keys/Arguments.ts | 18 +- .../lib/i18n/languageKeys/keys/Assertions.ts | 0 .../src/lib/i18n/languageKeys/keys/Colors.ts | 12 + .../lib/i18n/languageKeys/keys/Commands.ts | 4 + .../lib/i18n/languageKeys/keys/FuzzySearch.ts | 0 .../lib/i18n/languageKeys/keys/Globals.ts | 9 +- .../src}/lib/i18n/languageKeys/keys/Guilds.ts | 0 .../src}/lib/i18n/languageKeys/keys/Misc.ts | 4 + .../i18n/languageKeys/keys/Preconditions.ts | 25 + .../lib/i18n/languageKeys/keys/PromptList.ts | 5 + .../lib/i18n/languageKeys/keys/Serializers.ts | 9 +- .../lib/i18n/languageKeys/keys/Settings.ts | 19 +- .../src/lib/i18n/languageKeys/keys/System.ts | 26 + .../i18n/languageKeys/keys/commands/Admin.ts | 37 + .../languageKeys/keys/commands/Management.ts | 31 +- .../languageKeys/keys/commands/Moderation.ts | 187 +- .../i18n/languageKeys/keys/commands/Whois.ts | 12 + .../lib/i18n/languageKeys/keys/events/All.ts | 7 + .../languageKeys/keys/events/NoMentionSpam.ts | 3 +- .../languageKeys/keys/events/errors/All.ts | 0 .../languageKeys/keys/events/guilds/All.ts | 2 + .../languageKeys/keys/events/guilds/Logs.ts | 25 +- .../keys/events/guilds/Members.ts | 23 + .../languageKeys/keys/events/messages/All.ts | 4 + .../keys/events/moderation/All.ts | 1 + .../keys/events/moderation/Messages.ts | 0 .../languageKeys/keys/events/reactions/All.ts | 6 + .../languageKeys/keys/settings/Channels.ts | 6 + .../languageKeys/keys/settings/Gateway.ts | 0 .../keys/settings/channels/Ignore.ts | 1 - .../keys/settings/channels/Logs.ts | 3 - projects/bot/src/lib/moderation/index.ts | 2 + .../moderation/managers/ModerationManager.ts | 208 + .../moderation/managers/StickyRoleManager.ts | 167 + .../bot/src/lib/moderation/managers/index.ts | 2 + .../structures/ModerationCommand.ts | 204 + .../structures/ModerationListener.ts | 117 + .../structures/ModerationMessageListener.ts | 231 + .../moderation/structures/ModerationTask.ts | 26 +- .../structures/SelfModerationCommand.ts | 315 + .../structures/SelfModeratorBitField.ts | 25 + .../structures/SetUpModerationCommand.ts | 80 + .../src/lib/moderation/structures/index.ts | 7 + .../lib/moderation/workers/WorkerHandler.ts | 27 +- .../lib/moderation/workers/WorkerManager.ts | 16 +- .../workers/WorkerResponseHandler.ts | 6 +- .../moderation/workers/errors/TimeoutError.ts | 0 .../lib/moderation/workers/errors/index.ts | 1 + .../bot/src/lib/moderation/workers/index.ts | 5 + .../bot/src}/lib/moderation/workers/types.ts | 0 .../bot/src/lib/moderation/workers/worker.ts | 54 +- projects/bot/src/lib/setup.ts | 2 + .../bot/src}/lib/structures/InviteStore.ts | 5 +- .../lib/structures/commands/SkyraCommand.ts | 23 + projects/bot/src/lib/structures/index.ts | 3 + .../structures/managers/LockdownManager.ts | 4 +- .../structures/managers/ScheduleManager.ts | 200 + .../bot/src/lib/structures/managers/index.ts | 2 + .../bot/src}/lib/util/Links/TLDs.ts | 46 +- .../bot/src}/lib/util/Links/UrlRegex.ts | 2 +- .../src/lib/util/Parsers/ExceededLength.ts | 132 + .../bot/src}/lib/util/Parsers/FuzzySearch.ts | 6 +- .../bot/src}/lib/util/Sanitizer/clean.ts | 2 +- .../bot/src}/lib/util/Sanitizer/initClean.ts | 2 +- .../src}/lib/util/Security/GuildSecurity.ts | 7 + .../lib/util/Security/ModerationActions.ts | 1028 +++ .../src}/lib/util/Security/RegexCreator.ts | 24 +- projects/bot/src/lib/util/bits.ts | 48 + .../bot/src}/lib/util/common/comparators.ts | 16 +- .../bot/src}/lib/util/common/guards.ts | 0 projects/bot/src/lib/util/common/index.ts | 5 + projects/bot/src/lib/util/common/iterators.ts | 51 + .../bot/src}/lib/util/common/promises.ts | 18 +- .../bot/src}/lib/util/common/times.ts | 27 - projects/bot/src/lib/util/constants.ts | 100 + .../bot/src}/lib/util/formatters.ts | 45 +- .../bot/src/lib/util/functions/booleans.ts | 7 + .../bot/src}/lib/util/functions/emojis.ts | 78 +- .../bot/src}/lib/util/functions/guild.ts | 20 +- projects/bot/src/lib/util/functions/index.ts | 5 + .../bot/src}/lib/util/functions/numbers.ts | 2 +- .../bot/src/lib/util/functions/permissions.ts | 32 + .../bot/src/lib/util/moderationConstants.ts | 192 + projects/bot/src/lib/util/util.ts | 216 + .../src/listeners/commands/commandDenied.ts | 10 +- .../src/listeners/commands/commandError.ts | 184 + .../listeners/commands/commandRunAttach.ts | 6 +- .../commands/commandSuccessAnalytics.ts | 12 + .../commands/commandSuccessAutoDelete.ts | 19 + .../commands/commandSuccessLogger.ts | 13 +- .../src/listeners/commands/unknownCommand.ts | 38 + .../bot/src}/listeners/errors/error.ts | 4 +- .../src}/listeners/errors/listenerError.ts | 5 +- .../listeners/errors/listenerErrorSentry.ts | 7 +- .../bot/src}/listeners/errors/taskError.ts | 3 +- .../src}/listeners/errors/taskErrorSentry.ts | 9 +- projects/bot/src/listeners/guildMessageLog.ts | 37 + .../src/listeners/guilds/bans/guildBanAdd.ts | 21 + .../listeners/guilds/bans/guildBanRemove.ts | 21 + .../guilds/channels/channelCreateNotify.ts | 92 +- .../guilds/channels/channelDeleteNotify.ts | 40 + .../guilds/channels/channelUpdateNotify.ts | 96 +- .../guilds/emojis/emojiCreateNotify.ts | 48 + .../guilds/emojis/emojiDeleteNotify.ts | 32 + .../guilds/emojis/emojiUpdateNotify.ts | 53 +- .../listeners/guilds/guildUpdateNotify.ts | 101 +- .../guilds/members/guildMemberAdd.ts | 61 + .../guildMemberUpdateNicknameNotify.ts | 30 +- .../members/guildMemberUpdateRolesNotify.ts | 26 +- .../members/notMutedMemberAddInitialRole.ts | 27 + .../guilds/members/notMutedMemberAddNotify.ts | 34 + .../guilds/members/rawGuildMemberRemove.ts | 8 +- .../guilds/members/rawGuildMemberUpdate.ts | 46 +- .../guilds/members/rawMemberRemoveNotify.ts | 84 + .../messages/guildUserMessageImageNotify.ts | 69 +- .../messages/guildUserMessagePointsHandler.ts | 59 + .../guildUserMessageSocialPointsAddMember.ts | 24 + ...MessageSocialPointsAddMemberRewardLevel.ts | 96 + ...rMessageSocialPointsAddMemberRewardRole.ts | 140 + .../guildUserMessageSocialPointsAddUser.ts | 16 + .../guilds/rawGuildCreateMemberFetch.ts | 10 + .../src/listeners/guilds/rawGuildDelete.ts | 12 + .../guilds/rawGuildDeleteMemberFetch.ts | 10 + .../guilds/roles/roleCreateNotify.ts | 22 +- .../src/listeners/guilds/roles/roleDelete.ts | 55 + .../guilds/roles/roleDeleteNotify.ts | 28 + .../src/listeners/guilds/roles/roleUpdate.ts | 12 + .../guilds/roles/roleUpdateNotify.ts | 48 +- .../messages/guildMessageDeleteNotify.ts | 43 + .../messages/guildMessageDeleteRichDisplay.ts | 13 + .../messages/guildMessageDeleteSnipe.ts | 7 +- .../messages/guildUserMessageMediaOnly.ts | 16 +- .../src}/listeners/messages/messageCreate.ts | 2 +- .../src}/listeners/messages/messageDelete.ts | 2 +- .../messageDeleteBulkRemoveResponses.ts | 28 +- .../messages/messageDeleteRemoveResponses.ts | 24 +- .../listeners/messages/messageUpdateNotify.ts | 51 + .../listeners/messages/rawMessageDelete.ts | 16 + .../messages/rawMessageDeleteBulk.ts | 16 + .../messages/userMessageGuildHandler.ts | 6 +- .../guildUserMessageAttachmentsHandler.ts | 26 +- .../guildUserMessageCapitalsHandler.ts | 39 +- .../guildUserMessageInvitesHandler.ts | 38 +- .../messages/guildUserMessageLinksHandler.ts | 32 +- .../guildUserMessageMentionsHandler.ts | 25 +- .../guildUserMessageMessagesHandler.ts | 36 +- .../guildUserMessageNewLinesHandler.ts | 31 +- .../messages/guildUserMessageWordsHandler.ts | 35 +- .../moderation/moderationEntryAdd.ts | 44 + .../moderation/moderationEntryEdit.ts | 128 + .../reactions/rawMessageReactionAdd.ts | 9 +- .../reactions/rawMessageReactionRemove.ts | 9 +- .../reactions/rawReactionAddBlockList.ts | 116 + .../reactions/rawReactionAddNotify.ts | 125 + .../listeners/reactions/rawReactionAddRole.ts | 36 +- .../reactions/rawReactionRemoveRole.ts | 24 +- .../bot/src}/listeners/userUpdate.ts | 39 +- .../locales/en-US/commands/management.json | 591 ++ .../locales}/en-US/commands/moderation.json | 843 +-- .../src/locales/en-US/commands/system.json | 47 + .../bot/src/locales/en-US/commands/tools.json | 309 + projects/bot/src/locales/en-US/errors.json | 10 + .../bot/src/locales}/en-US/events/errors.json | 2 +- .../locales}/en-US/events/guilds-logs.json | 47 +- .../locales}/en-US/events/guilds-members.json | 10 +- .../src/locales/en-US/events/messages.json | 4 + .../src/locales}/en-US/events/moderation.json | 4 +- .../locales}/en-US/events/noMentionSpam.json | 2 +- .../src/locales}/en-US/events/reactions.json | 3 +- .../bot/src/locales/en-US/events/twitch.json | 5 + .../bot/src/locales}/en-US/fuzzySearch.json | 2 +- .../bot/src/locales}/en-US/globals.json | 13 +- projects/bot/src/locales/en-US/guilds.json | 11 + .../bot/src/locales/en-US/humanLevels.json | 7 + .../bot/src/locales/en-US/moderation.json | 21 + .../src/locales}/en-US/moderationActions.json | 13 +- .../bot/src/locales/en-US/permissions.json | 43 + .../bot/src/locales}/en-US/preconditions.json | 29 +- .../bot/src/locales/en-US/promptList.json | 6 + .../src/locales}/en-US/selfModeration.json | 10 +- .../bot/src/locales}/en-US/settings.json | 36 +- .../bot/src/locales}/en-US/system.json | 16 +- projects/bot/src/main.ts | 49 + projects/bot/src/routes/commands.ts | 35 + .../bot/src/routes/guilds/guild.ts | 8 +- .../bot/src/routes/guilds/guild/channels.ts | 6 +- .../routes/guilds/guild/channels/channel.ts | 6 +- .../src/routes/guilds/guild/members/member.ts | 6 +- .../bot/src/routes/guilds/guild/roles.ts | 6 +- .../bot/src/routes/guilds/guild/roles/role.ts | 6 +- .../bot/src/routes/guilds/guild/settings.ts | 77 +- projects/bot/src/routes/languages.ts | 12 + projects/bot/src/routes/main.ts | 15 + .../bot/src/routes/oauth/oauthUser.ts | 14 +- .../bot/src/routes/users/user.ts | 8 +- .../bot/src/routes/users/user/settings.ts | 55 + .../tasks/moderation/moderationEndAddRole.ts | 24 + .../src/tasks/moderation/moderationEndBan.ts | 23 + .../src/tasks/moderation/moderationEndMute.ts | 20 + .../moderation/moderationEndRemoveRole.ts | 24 + .../moderation/moderationEndSetNickname.ts | 24 + .../moderation/moderationEndVoiceMute.ts | 23 + .../tasks/moderation/moderationEndWarning.ts | 24 + {src => projects/bot/src}/tasks/poststats.ts | 32 +- projects/bot/src/tasks/reminder.ts | 31 + projects/bot/src/tsconfig.json | 18 + .../bot/tests}/lib/CommandMatcher.test.ts | 0 .../bot/tests}/lib/RegexCreator.test.ts | 0 .../bot/tests}/lib/bits.test.ts | 0 .../lib/database/settings/functions.test.ts | 0 .../structures/AuditLogEnvelope.test.ts | 0 .../structures/AuditLogManager.test.ts | 0 .../structures/PermissionNodeManager.test.ts | 0 .../bot/tests}/lib/formatters.test.ts | 0 .../bot/tests}/lib/i18n/LanguageHelp.test.ts | 0 .../bot/tests}/lib/i18n/translate.test.ts | 0 .../commands/commandLogShared.test.ts | 0 .../moderation/workers/WorkerHandler.test.ts | 0 .../moderation/workers/WorkerManager.test.ts | 0 .../workers/WorkerResponseHandler.test.ts | 0 .../bot/tests}/lib/util.test.ts | 0 .../lib/util/common/comparators.test.ts | 0 .../bot/tests}/lib/util/common/times.test.ts | 0 projects/bot/tests/lib/util/constants.test.ts | 25 + .../bot/tests}/lib/util/formatters.test.ts | 0 .../lib/util/functions/auditLogEmbeds.test.ts | 0 .../functions/emojis/areEmojisEqual.test.ts | 24 + .../util/functions/emojis/getEmojiId.test.ts | 0 .../functions/emojis/getEmojiObject.test.ts | 0 .../emojis/getEmojiReactionFormat.test.ts | 0 .../functions/emojis/getEmojiString.test.ts | 0 .../emojis/getEmojiTextFormat.test.ts | 0 .../emojis/getEncodedTwemoji.test.ts | 0 .../functions/emojis/getTwemojiUrl.test.ts | 0 .../emojis/isSerializedTwemoji.test.ts | 0 .../emojis/isValidCustomEmoji.test.ts | 0 .../isValidSerializedCustomEmoji.test.ts | 0 .../emojis/isValidSerializedEmoji.test.ts | 0 .../emojis/isValidSerializedTwemoji.test.ts | 0 .../functions/emojis/isValidTwemoji.test.ts | 0 .../functions/emojis/resolveEmojiId.test.ts | 0 .../bot/tests/lib/util/sanitizeInput.test.ts | 30 + .../bot/tests}/mocks/MockInstances.ts | 0 .../bot/tests}/mocks/constants.ts | 0 {tests => projects/bot/tests}/mocks/image.png | Bin .../migrate-audit-log-to-audit-event.test.ts | 0 projects/bot/tests/tsconfig.json | 19 + {tests => projects/bot/tests}/vitest.setup.ts | 1 - projects/bot/tsconfig.eslint.json | 4 + projects/bot/tsdown.config.ts | 89 + projects/docker/README.md | 21 + projects/docker/control.ps1 | 55 + projects/docker/docker-compose.yml | 63 + projects/gateway/Dockerfile | 61 + projects/gateway/package.json | 33 + projects/gateway/scripts/clean.mjs | 8 + projects/gateway/src/.env | 15 + projects/gateway/src/.env.development | 1 + projects/gateway/src/lib/Client.ts | 57 + projects/gateway/src/lib/actions/All.ts | 113 + .../gateway/src/lib/actions/ChannelCreate.ts | 11 + .../gateway/src/lib/actions/ChannelDelete.ts | 11 + .../gateway/src/lib/actions/ChannelUpdate.ts | 12 + .../gateway/src/lib/actions/GuildBanAdd.ts | 6 + .../gateway/src/lib/actions/GuildBanRemove.ts | 6 + .../gateway/src/lib/actions/GuildCreate.ts | 26 + .../gateway/src/lib/actions/GuildDelete.ts | 9 + .../src/lib/actions/GuildEmojisUpdate.ts | 38 + .../gateway/src/lib/actions/GuildMemberAdd.ts | 7 + .../src/lib/actions/GuildMemberRemove.ts | 13 + .../src/lib/actions/GuildMemberUpdate.ts | 15 + .../src/lib/actions/GuildMembersChunk.ts | 9 + .../src/lib/actions/GuildRoleCreate.ts | 7 + .../src/lib/actions/GuildRoleDelete.ts | 13 + .../src/lib/actions/GuildRoleUpdate.ts | 8 + .../src/lib/actions/GuildStickersUpdate.ts | 38 + .../gateway/src/lib/actions/GuildUpdate.ts | 9 + .../gateway/src/lib/actions/MessageCreate.ts | 11 + .../gateway/src/lib/actions/MessageDelete.ts | 19 + .../src/lib/actions/MessageDeleteBulk.ts | 18 + .../src/lib/actions/MessageReactionAdd.ts | 6 + .../src/lib/actions/MessageReactionRemove.ts | 6 + .../lib/actions/MessageReactionRemoveAll.ts | 6 + .../lib/actions/MessageReactionRemoveEmoji.ts | 6 + .../gateway/src/lib/actions/MessageUpdate.ts | 17 + projects/gateway/src/lib/augments.d.ts | 18 + .../gateway/src/lib/structures/ws-listener.ts | 21 + .../gateway/src/listeners/ws/dispatch.mts | 6 + projects/gateway/src/listeners/ws/error.mts | 5 + projects/gateway/src/listeners/ws/ready.mts | 6 + projects/gateway/src/listeners/ws/resumed.mts | 6 + projects/gateway/src/main.ts | 55 + projects/gateway/src/tsconfig.json | 13 + projects/gateway/tests/.gitkeep | 0 projects/gateway/tsconfig.eslint.json | 4 + projects/shared/package.json | 39 + projects/shared/scripts/clean.mjs | 8 + projects/shared/src/index.ts | 51 + projects/shared/src/lib/cache/Cache.ts | 41 + .../shared/src/lib/cache/CacheChannels.ts | 7 + projects/shared/src/lib/cache/CacheEmojis.ts | 7 + projects/shared/src/lib/cache/CacheGuilds.ts | 72 + projects/shared/src/lib/cache/CacheMembers.ts | 7 + .../shared/src/lib/cache/CacheMessages.ts | 7 + projects/shared/src/lib/cache/CacheRoles.ts | 7 + .../shared/src/lib/cache/CacheStickers.ts | 7 + .../src/lib/cache/base/HashScopedCache.ts | 154 + .../shared/src/lib/cache/base/ScopedCache.ts | 22 + .../src/lib/cache/structures/Channel.ts | 95 + .../shared/src/lib/cache/structures/Emoji.ts | 98 + .../shared/src/lib/cache/structures/Guild.ts | 266 + .../shared/src/lib/cache/structures/Member.ts | 171 + .../src/lib/cache/structures/Message.ts | 242 + .../shared/src/lib/cache/structures/Role.ts | 138 + .../src/lib/cache/structures/Sticker.ts | 106 + .../structures/interfaces/BufferEncodable.ts | 3 + .../cache/structures/interfaces/IStructure.ts | 12 + .../structures/interfaces/Identifiable.ts | 3 + .../structures/interfaces/JsonEncodable.ts | 5 + .../unions/channel/GuildCategoryChannel.ts | 19 + .../unions/channel/GuildForumChannel.ts | 19 + .../unions/channel/GuildNewsChannel.ts | 19 + .../unions/channel/GuildTextChannel.ts | 46 + .../unions/channel/GuildThreadChannel.ts | 99 + .../unions/channel/GuildVoiceChannel.ts | 64 + .../unions/channel/base/GuildBasedChannel.ts | 126 + .../channel/base/GuildTextBasedChannel.ts | 55 + .../cache/structures/values/GuildFeatures.ts | 47 + projects/shared/src/lib/common/bits.ts | 3 + projects/shared/src/lib/common/util.ts | 48 + projects/shared/src/lib/data/Reader.ts | 97 + projects/shared/src/lib/data/Writer.ts | 147 + .../shared/src/lib/messaging/MessageBroker.ts | 116 + .../shared/src/lib/messaging/RedisMessage.ts | 225 + .../shared/src/lib/structures/Listener.ts | 50 + .../src/lib/structures/ListenerStore.ts | 9 + projects/shared/src/tsconfig.json | 10 + projects/shared/tests/.gitkeep | 0 projects/shared/tsconfig.eslint.json | 4 + scripts/SetFakeRoles.sql | 13 - scripts/SetMigrations.sql | 108 - scripts/dependencycache.ps1 | 26 - scripts/migrate-audit-log-to-audit-event.mjs | 178 - scripts/migrations.mjs | 12 - scripts/tlds.mjs | 6 +- src/.env | 48 - src/.env.development | 12 - src/arguments/boolean.ts | 28 - src/arguments/case.ts | 9 - src/arguments/channelName.ts | 41 - src/arguments/command.ts | 22 - src/arguments/commandMatch.ts | 26 - src/arguments/commandName.ts | 35 - src/arguments/duration.ts | 11 - src/arguments/emoji.ts | 11 - src/arguments/invite.ts | 20 - src/arguments/language.ts | 11 - src/arguments/range.ts | 18 - src/arguments/reset.ts | 10 - src/arguments/roleName.ts | 37 - src/arguments/snowflake.ts | 26 - src/arguments/textChannelName.ts | 13 - src/arguments/textOrNewsChannelName.ts | 16 - src/arguments/time.ts | 20 - src/arguments/timespan.ts | 9 - src/arguments/userName.ts | 45 - src/commands/Admin/conf.ts | 224 - src/commands/Admin/roleset.ts | 204 - src/commands/Fun/escaperope.ts | 27 - src/commands/Games/c4.ts | 66 - src/commands/Games/hungergames.ts | 272 - src/commands/Games/tictactoe.ts | 60 - src/commands/Games/trivia.ts | 111 - src/commands/General/help.ts | 208 - src/commands/General/info-deprecations.ts | 25 - src/commands/General/info.ts | 189 - src/commands/General/v7-artiel.ts | 67 - src/commands/General/v7-skyra.ts | 21 - src/commands/General/v7-teryl.ts | 26 - .../AutoModeration/automod-attachments.ts | 22 - .../AutoModeration/automod-capitals.ts | 22 - .../AutoModeration/automod-invites.ts | 22 - .../AutoModeration/automod-links.ts | 22 - .../AutoModeration/automod-newlines.ts | 22 - .../AutoModeration/automod-reactions.ts | 22 - .../Management/AutoModeration/automod-spam.ts | 22 - .../AutoModeration/automod-words.ts | 148 - .../manage-command-auto-delete.ts | 83 - .../Configuration/manage-command-channel.ts | 113 - .../Configuration/manage-reaction-roles.ts | 143 - .../Configuration/setIgnoreChannels.ts | 36 - .../Management/Configuration/setImageLogs.ts | 11 - .../Configuration/setMemberAddLogs.ts | 11 - .../Configuration/setMemberRemoveLogs.ts | 11 - .../Configuration/setMessageDeleteLogs.ts | 11 - .../Configuration/setMessageUpdateLogs.ts | 11 - .../Management/Configuration/setModLogs.ts | 11 - .../Management/Configuration/setPrefix.ts | 32 - src/commands/Management/create-mute.ts | 65 - src/commands/Management/permissionNodes.ts | 165 - src/commands/Management/roles.ts | 144 - src/commands/Misc/snipe.ts | 71 - .../Restriction/restrictAttachment.ts | 15 - .../Moderation/Restriction/restrictEmbed.ts | 15 - .../Moderation/Restriction/restrictEmoji.ts | 15 - .../Restriction/restrictReaction.ts | 15 - .../Moderation/Restriction/restrictVoice.ts | 15 - .../Restriction/unrestrictAttachment.ts | 16 - .../Moderation/Restriction/unrestrictEmbed.ts | 16 - .../Moderation/Restriction/unrestrictEmoji.ts | 16 - .../Restriction/unrestrictReaction.ts | 16 - .../Moderation/Restriction/unrestrictVoice.ts | 16 - .../Moderation/Utilities/case-deprecations.ts | 47 - src/commands/Moderation/Utilities/case.ts | 332 - .../Moderation/Utilities/permissions.ts | 139 - src/commands/Moderation/addrole.ts | 38 - src/commands/Moderation/ban.ts | 41 - src/commands/Moderation/kick.ts | 36 - src/commands/Moderation/mute.ts | 17 - src/commands/Moderation/prune.ts | 447 -- src/commands/Moderation/removerole.ts | 38 - src/commands/Moderation/setnickname.ts | 40 - src/commands/Moderation/softban.ts | 42 - src/commands/Moderation/timeout.ts | 24 - src/commands/Moderation/unban.ts | 31 - src/commands/Moderation/unmute.ts | 16 - src/commands/Moderation/untimeout.ts | 18 - src/commands/Moderation/vmute.ts | 18 - src/commands/Moderation/voicekick.ts | 18 - src/commands/Moderation/vunmute.ts | 19 - src/commands/Moderation/warn.ts | 16 - src/commands/System/Admin/eval.ts | 253 - src/commands/System/Admin/reboot.ts | 37 - src/commands/Tools/avatar.ts | 42 - src/commands/Tools/vote.ts | 34 - src/commands/Tools/whois.ts | 254 - src/commands/Twitch/twitchsubscription.ts | 43 - src/config.ts | 262 - src/index.ts | 35 - src/languages/bg/arguments.json | 98 - src/languages/bg/assertions.json | 1 - src/languages/bg/commands/admin.json | 107 - src/languages/bg/commands/animal.json | 26 - .../bg/commands/auto-moderation.json | 1 - src/languages/bg/commands/case.json | 1 - src/languages/bg/commands/fun.json | 7 - src/languages/bg/commands/game.json | 447 -- src/languages/bg/commands/general.json | 36 - src/languages/bg/commands/info.json | 1 - src/languages/bg/commands/management.json | 445 -- src/languages/bg/commands/misc.json | 8 - src/languages/bg/commands/moderation.json | 889 --- src/languages/bg/commands/shared.json | 7 - src/languages/bg/commands/system.json | 30 - src/languages/bg/commands/tools.json | 49 - src/languages/bg/commands/twitch.json | 70 - src/languages/bg/commands/whois.json | 1 - src/languages/bg/errors.json | 1 - src/languages/bg/events/errors.json | 1 - src/languages/bg/events/guilds-logs.json | 1 - src/languages/bg/events/guilds-members.json | 1 - src/languages/bg/events/messages.json | 1 - src/languages/bg/events/moderation.json | 1 - src/languages/bg/events/noMentionSpam.json | 1 - src/languages/bg/events/reactions.json | 1 - src/languages/bg/events/twitch.json | 1 - src/languages/bg/fuzzySearch.json | 1 - src/languages/bg/globals.json | 1 - src/languages/bg/guilds.json | 1 - src/languages/bg/humanLevels.json | 1 - src/languages/bg/moderation.json | 1 - src/languages/bg/moderationActions.json | 43 - src/languages/bg/permissions.json | 1 - src/languages/bg/preconditions.json | 1 - src/languages/bg/selfModeration.json | 1 - src/languages/bg/serializers.json | 1 - src/languages/bg/settings.json | 1 - src/languages/bg/system.json | 25 - src/languages/cs/arguments.json | 98 - src/languages/cs/assertions.json | 1 - src/languages/cs/commands/admin.json | 107 - src/languages/cs/commands/animal.json | 26 - .../cs/commands/auto-moderation.json | 1 - src/languages/cs/commands/case.json | 1 - src/languages/cs/commands/fun.json | 7 - src/languages/cs/commands/game.json | 447 -- src/languages/cs/commands/general.json | 36 - src/languages/cs/commands/info.json | 1 - src/languages/cs/commands/management.json | 445 -- src/languages/cs/commands/misc.json | 8 - src/languages/cs/commands/moderation.json | 889 --- src/languages/cs/commands/shared.json | 7 - src/languages/cs/commands/system.json | 30 - src/languages/cs/commands/tools.json | 49 - src/languages/cs/commands/twitch.json | 70 - src/languages/cs/commands/whois.json | 1 - src/languages/cs/errors.json | 1 - src/languages/cs/events/errors.json | 1 - src/languages/cs/events/guilds-logs.json | 1 - src/languages/cs/events/guilds-members.json | 1 - src/languages/cs/events/messages.json | 1 - src/languages/cs/events/moderation.json | 1 - src/languages/cs/events/noMentionSpam.json | 1 - src/languages/cs/events/reactions.json | 1 - src/languages/cs/events/twitch.json | 1 - src/languages/cs/fuzzySearch.json | 1 - src/languages/cs/globals.json | 1 - src/languages/cs/guilds.json | 1 - src/languages/cs/humanLevels.json | 1 - src/languages/cs/moderation.json | 1 - src/languages/cs/moderationActions.json | 43 - src/languages/cs/permissions.json | 1 - src/languages/cs/preconditions.json | 1 - src/languages/cs/selfModeration.json | 1 - src/languages/cs/serializers.json | 1 - src/languages/cs/settings.json | 1 - src/languages/cs/system.json | 25 - src/languages/da/arguments.json | 98 - src/languages/da/assertions.json | 1 - src/languages/da/commands/admin.json | 107 - src/languages/da/commands/animal.json | 26 - .../da/commands/auto-moderation.json | 1 - src/languages/da/commands/case.json | 1 - src/languages/da/commands/fun.json | 7 - src/languages/da/commands/game.json | 447 -- src/languages/da/commands/general.json | 36 - src/languages/da/commands/info.json | 1 - src/languages/da/commands/management.json | 445 -- src/languages/da/commands/misc.json | 8 - src/languages/da/commands/moderation.json | 889 --- src/languages/da/commands/shared.json | 7 - src/languages/da/commands/system.json | 30 - src/languages/da/commands/tools.json | 49 - src/languages/da/commands/twitch.json | 70 - src/languages/da/commands/whois.json | 1 - src/languages/da/errors.json | 1 - src/languages/da/events/errors.json | 1 - src/languages/da/events/guilds-logs.json | 1 - src/languages/da/events/guilds-members.json | 1 - src/languages/da/events/messages.json | 1 - src/languages/da/events/moderation.json | 1 - src/languages/da/events/noMentionSpam.json | 1 - src/languages/da/events/reactions.json | 1 - src/languages/da/events/twitch.json | 1 - src/languages/da/fuzzySearch.json | 1 - src/languages/da/globals.json | 1 - src/languages/da/guilds.json | 1 - src/languages/da/humanLevels.json | 1 - src/languages/da/moderation.json | 1 - src/languages/da/moderationActions.json | 43 - src/languages/da/permissions.json | 1 - src/languages/da/preconditions.json | 1 - src/languages/da/selfModeration.json | 1 - src/languages/da/serializers.json | 1 - src/languages/da/settings.json | 1 - src/languages/da/system.json | 25 - src/languages/de/arguments.json | 98 - src/languages/de/assertions.json | 1 - src/languages/de/commands/admin.json | 107 - src/languages/de/commands/animal.json | 26 - .../de/commands/auto-moderation.json | 1 - src/languages/de/commands/case.json | 1 - src/languages/de/commands/fun.json | 7 - src/languages/de/commands/game.json | 447 -- src/languages/de/commands/general.json | 36 - src/languages/de/commands/info.json | 1 - src/languages/de/commands/management.json | 445 -- src/languages/de/commands/misc.json | 8 - src/languages/de/commands/moderation.json | 889 --- src/languages/de/commands/shared.json | 7 - src/languages/de/commands/system.json | 30 - src/languages/de/commands/tools.json | 49 - src/languages/de/commands/twitch.json | 70 - src/languages/de/commands/whois.json | 1 - src/languages/de/constants.ts | 40 - src/languages/de/errors.json | 1 - src/languages/de/events/errors.json | 1 - src/languages/de/events/guilds-logs.json | 1 - src/languages/de/events/guilds-members.json | 1 - src/languages/de/events/messages.json | 1 - src/languages/de/events/moderation.json | 1 - src/languages/de/events/noMentionSpam.json | 1 - src/languages/de/events/reactions.json | 1 - src/languages/de/events/twitch.json | 1 - src/languages/de/fuzzySearch.json | 1 - src/languages/de/globals.json | 1 - src/languages/de/guilds.json | 1 - src/languages/de/humanLevels.json | 1 - src/languages/de/moderation.json | 1 - src/languages/de/moderationActions.json | 43 - src/languages/de/permissions.json | 1 - src/languages/de/preconditions.json | 1 - src/languages/de/selfModeration.json | 1 - src/languages/de/serializers.json | 1 - src/languages/de/settings.json | 1 - src/languages/de/system.json | 25 - src/languages/el/arguments.json | 98 - src/languages/el/assertions.json | 1 - src/languages/el/commands/admin.json | 107 - src/languages/el/commands/animal.json | 26 - .../el/commands/auto-moderation.json | 1 - src/languages/el/commands/case.json | 1 - src/languages/el/commands/fun.json | 7 - src/languages/el/commands/game.json | 447 -- src/languages/el/commands/general.json | 36 - src/languages/el/commands/info.json | 1 - src/languages/el/commands/management.json | 445 -- src/languages/el/commands/misc.json | 8 - src/languages/el/commands/moderation.json | 889 --- src/languages/el/commands/shared.json | 7 - src/languages/el/commands/system.json | 30 - src/languages/el/commands/tools.json | 49 - src/languages/el/commands/twitch.json | 70 - src/languages/el/commands/whois.json | 1 - src/languages/el/errors.json | 1 - src/languages/el/events/errors.json | 1 - src/languages/el/events/guilds-logs.json | 1 - src/languages/el/events/guilds-members.json | 1 - src/languages/el/events/messages.json | 1 - src/languages/el/events/moderation.json | 1 - src/languages/el/events/noMentionSpam.json | 1 - src/languages/el/events/reactions.json | 1 - src/languages/el/events/twitch.json | 1 - src/languages/el/fuzzySearch.json | 1 - src/languages/el/globals.json | 1 - src/languages/el/guilds.json | 1 - src/languages/el/humanLevels.json | 1 - src/languages/el/moderation.json | 1 - src/languages/el/moderationActions.json | 43 - src/languages/el/permissions.json | 1 - src/languages/el/preconditions.json | 1 - src/languages/el/selfModeration.json | 1 - src/languages/el/serializers.json | 1 - src/languages/el/settings.json | 1 - src/languages/el/system.json | 25 - src/languages/en-GB/arguments.json | 98 - src/languages/en-GB/assertions.json | 1 - src/languages/en-GB/commands/admin.json | 107 - src/languages/en-GB/commands/animal.json | 26 - .../en-GB/commands/auto-moderation.json | 1 - src/languages/en-GB/commands/case.json | 1 - src/languages/en-GB/commands/fun.json | 7 - src/languages/en-GB/commands/game.json | 447 -- src/languages/en-GB/commands/general.json | 36 - src/languages/en-GB/commands/info.json | 1 - src/languages/en-GB/commands/management.json | 445 -- src/languages/en-GB/commands/misc.json | 8 - src/languages/en-GB/commands/moderation.json | 889 --- src/languages/en-GB/commands/shared.json | 7 - src/languages/en-GB/commands/system.json | 30 - src/languages/en-GB/commands/tools.json | 49 - src/languages/en-GB/commands/twitch.json | 70 - src/languages/en-GB/commands/whois.json | 1 - src/languages/en-GB/constants.ts | 40 - src/languages/en-GB/errors.json | 1 - src/languages/en-GB/events/errors.json | 1 - src/languages/en-GB/events/guilds-logs.json | 1 - .../en-GB/events/guilds-members.json | 1 - src/languages/en-GB/events/messages.json | 1 - src/languages/en-GB/events/moderation.json | 1 - src/languages/en-GB/events/noMentionSpam.json | 1 - src/languages/en-GB/events/reactions.json | 4 - src/languages/en-GB/events/twitch.json | 1 - src/languages/en-GB/fuzzySearch.json | 6 - src/languages/en-GB/globals.json | 15 - src/languages/en-GB/guilds.json | 1 - src/languages/en-GB/humanLevels.json | 1 - src/languages/en-GB/moderation.json | 1 - src/languages/en-GB/moderationActions.json | 43 - src/languages/en-GB/permissions.json | 1 - src/languages/en-GB/preconditions.json | 1 - src/languages/en-GB/selfModeration.json | 1 - src/languages/en-GB/serializers.json | 1 - src/languages/en-GB/settings.json | 1 - src/languages/en-GB/system.json | 25 - src/languages/en-US/arguments.json | 98 - src/languages/en-US/assertions.json | 3 - src/languages/en-US/colors.json | 12 - src/languages/en-US/commands/admin.json | 64 - .../en-US/commands/auto-moderation.json | 77 - src/languages/en-US/commands/case.json | 55 - src/languages/en-US/commands/conf.json | 60 - src/languages/en-US/commands/fun.json | 7 - src/languages/en-US/commands/game.json | 447 -- src/languages/en-US/commands/general.json | 40 - src/languages/en-US/commands/info.json | 15 - src/languages/en-US/commands/management.json | 445 -- src/languages/en-US/commands/permissions.json | 14 - src/languages/en-US/commands/shared.json | 7 - src/languages/en-US/commands/snipe.json | 6 - src/languages/en-US/commands/system.json | 30 - src/languages/en-US/commands/tools.json | 49 - src/languages/en-US/commands/whois.json | 15 - src/languages/en-US/constants.ts | 40 - src/languages/en-US/errors.json | 18 - src/languages/en-US/events/messages.json | 14 - src/languages/en-US/guilds.json | 13 - src/languages/en-US/humanLevels.json | 7 - src/languages/en-US/moderation.json | 42 - src/languages/en-US/permissions.json | 52 - src/languages/en-US/serializers.json | 49 - src/languages/es-419/arguments.json | 98 - src/languages/es-419/assertions.json | 3 - src/languages/es-419/commands/admin.json | 107 - src/languages/es-419/commands/animal.json | 26 - .../es-419/commands/auto-moderation.json | 77 - src/languages/es-419/commands/case.json | 55 - src/languages/es-419/commands/fun.json | 7 - src/languages/es-419/commands/game.json | 447 -- src/languages/es-419/commands/general.json | 36 - src/languages/es-419/commands/info.json | 15 - src/languages/es-419/commands/management.json | 445 -- src/languages/es-419/commands/misc.json | 8 - src/languages/es-419/commands/moderation.json | 889 --- src/languages/es-419/commands/shared.json | 7 - src/languages/es-419/commands/system.json | 30 - src/languages/es-419/commands/tools.json | 49 - src/languages/es-419/commands/twitch.json | 70 - src/languages/es-419/commands/whois.json | 15 - src/languages/es-419/constants.ts | 40 - src/languages/es-419/errors.json | 9 - src/languages/es-419/events/errors.json | 5 - src/languages/es-419/events/guilds-logs.json | 109 - .../es-419/events/guilds-members.json | 18 - src/languages/es-419/events/messages.json | 4 - src/languages/es-419/events/moderation.json | 32 - .../es-419/events/noMentionSpam.json | 6 - src/languages/es-419/events/reactions.json | 5 - src/languages/es-419/fuzzySearch.json | 6 - src/languages/es-419/globals.json | 17 - src/languages/es-419/guilds.json | 13 - src/languages/es-419/humanLevels.json | 7 - src/languages/es-419/moderation.json | 6 - src/languages/es-419/moderationActions.json | 43 - src/languages/es-419/permissions.json | 48 - src/languages/es-419/preconditions.json | 26 - src/languages/es-419/selfModeration.json | 29 - src/languages/es-419/serializers.json | 41 - src/languages/es-419/settings.json | 25 - src/languages/es-419/system.json | 25 - src/languages/es-ES/arguments.json | 98 - src/languages/es-ES/assertions.json | 3 - src/languages/es-ES/commands/admin.json | 107 - src/languages/es-ES/commands/animal.json | 26 - .../es-ES/commands/auto-moderation.json | 77 - src/languages/es-ES/commands/case.json | 55 - src/languages/es-ES/commands/fun.json | 7 - src/languages/es-ES/commands/game.json | 447 -- src/languages/es-ES/commands/general.json | 36 - src/languages/es-ES/commands/info.json | 15 - src/languages/es-ES/commands/management.json | 445 -- src/languages/es-ES/commands/misc.json | 8 - src/languages/es-ES/commands/moderation.json | 889 --- src/languages/es-ES/commands/shared.json | 7 - src/languages/es-ES/commands/system.json | 30 - src/languages/es-ES/commands/tools.json | 49 - src/languages/es-ES/commands/twitch.json | 70 - src/languages/es-ES/commands/whois.json | 15 - src/languages/es-ES/constants.ts | 40 - src/languages/es-ES/errors.json | 9 - src/languages/es-ES/events/errors.json | 5 - src/languages/es-ES/events/guilds-logs.json | 109 - .../es-ES/events/guilds-members.json | 18 - src/languages/es-ES/events/messages.json | 4 - src/languages/es-ES/events/moderation.json | 32 - src/languages/es-ES/events/noMentionSpam.json | 6 - src/languages/es-ES/events/reactions.json | 5 - src/languages/es-ES/fuzzySearch.json | 6 - src/languages/es-ES/globals.json | 17 - src/languages/es-ES/guilds.json | 13 - src/languages/es-ES/humanLevels.json | 7 - src/languages/es-ES/moderation.json | 6 - src/languages/es-ES/moderationActions.json | 43 - src/languages/es-ES/permissions.json | 48 - src/languages/es-ES/preconditions.json | 26 - src/languages/es-ES/selfModeration.json | 29 - src/languages/es-ES/serializers.json | 41 - src/languages/es-ES/settings.json | 25 - src/languages/es-ES/system.json | 25 - src/languages/fi/arguments.json | 98 - src/languages/fi/assertions.json | 1 - src/languages/fi/commands/admin.json | 107 - src/languages/fi/commands/animal.json | 26 - .../fi/commands/auto-moderation.json | 1 - src/languages/fi/commands/case.json | 1 - src/languages/fi/commands/fun.json | 7 - src/languages/fi/commands/game.json | 447 -- src/languages/fi/commands/general.json | 36 - src/languages/fi/commands/info.json | 1 - src/languages/fi/commands/management.json | 445 -- src/languages/fi/commands/misc.json | 8 - src/languages/fi/commands/moderation.json | 889 --- src/languages/fi/commands/shared.json | 7 - src/languages/fi/commands/system.json | 30 - src/languages/fi/commands/tools.json | 49 - src/languages/fi/commands/twitch.json | 70 - src/languages/fi/commands/whois.json | 1 - src/languages/fi/errors.json | 1 - src/languages/fi/events/errors.json | 1 - src/languages/fi/events/guilds-logs.json | 1 - src/languages/fi/events/guilds-members.json | 1 - src/languages/fi/events/messages.json | 1 - src/languages/fi/events/moderation.json | 1 - src/languages/fi/events/noMentionSpam.json | 1 - src/languages/fi/events/reactions.json | 1 - src/languages/fi/events/twitch.json | 1 - src/languages/fi/fuzzySearch.json | 1 - src/languages/fi/globals.json | 1 - src/languages/fi/guilds.json | 1 - src/languages/fi/humanLevels.json | 1 - src/languages/fi/moderation.json | 1 - src/languages/fi/moderationActions.json | 43 - src/languages/fi/permissions.json | 1 - src/languages/fi/preconditions.json | 1 - src/languages/fi/selfModeration.json | 1 - src/languages/fi/serializers.json | 1 - src/languages/fi/settings.json | 1 - src/languages/fi/system.json | 25 - src/languages/fr/arguments.json | 98 - src/languages/fr/assertions.json | 1 - src/languages/fr/commands/admin.json | 107 - src/languages/fr/commands/animal.json | 26 - .../fr/commands/auto-moderation.json | 1 - src/languages/fr/commands/case.json | 1 - src/languages/fr/commands/fun.json | 7 - src/languages/fr/commands/game.json | 447 -- src/languages/fr/commands/general.json | 36 - src/languages/fr/commands/info.json | 1 - src/languages/fr/commands/management.json | 445 -- src/languages/fr/commands/misc.json | 8 - src/languages/fr/commands/moderation.json | 889 --- src/languages/fr/commands/shared.json | 7 - src/languages/fr/commands/system.json | 30 - src/languages/fr/commands/tools.json | 49 - src/languages/fr/commands/twitch.json | 70 - src/languages/fr/commands/whois.json | 1 - src/languages/fr/errors.json | 1 - src/languages/fr/events/errors.json | 1 - src/languages/fr/events/guilds-logs.json | 1 - src/languages/fr/events/guilds-members.json | 1 - src/languages/fr/events/messages.json | 1 - src/languages/fr/events/moderation.json | 1 - src/languages/fr/events/noMentionSpam.json | 1 - src/languages/fr/events/reactions.json | 1 - src/languages/fr/events/twitch.json | 1 - src/languages/fr/fuzzySearch.json | 1 - src/languages/fr/globals.json | 1 - src/languages/fr/guilds.json | 1 - src/languages/fr/humanLevels.json | 1 - src/languages/fr/moderation.json | 1 - src/languages/fr/moderationActions.json | 43 - src/languages/fr/permissions.json | 1 - src/languages/fr/preconditions.json | 1 - src/languages/fr/selfModeration.json | 1 - src/languages/fr/serializers.json | 1 - src/languages/fr/settings.json | 1 - src/languages/fr/system.json | 25 - src/languages/hi/arguments.json | 98 - src/languages/hi/assertions.json | 1 - src/languages/hi/commands/admin.json | 107 - src/languages/hi/commands/animal.json | 26 - .../hi/commands/auto-moderation.json | 1 - src/languages/hi/commands/case.json | 1 - src/languages/hi/commands/fun.json | 7 - src/languages/hi/commands/game.json | 447 -- src/languages/hi/commands/general.json | 36 - src/languages/hi/commands/info.json | 1 - src/languages/hi/commands/management.json | 445 -- src/languages/hi/commands/misc.json | 8 - src/languages/hi/commands/moderation.json | 889 --- src/languages/hi/commands/shared.json | 7 - src/languages/hi/commands/system.json | 30 - src/languages/hi/commands/tools.json | 49 - src/languages/hi/commands/twitch.json | 70 - src/languages/hi/commands/whois.json | 1 - src/languages/hi/errors.json | 1 - src/languages/hi/events/errors.json | 5 - src/languages/hi/events/guilds-logs.json | 128 - src/languages/hi/events/guilds-members.json | 18 - src/languages/hi/events/messages.json | 4 - src/languages/hi/events/moderation.json | 32 - src/languages/hi/events/noMentionSpam.json | 5 - src/languages/hi/events/reactions.json | 5 - src/languages/hi/events/twitch.json | 5 - src/languages/hi/fuzzySearch.json | 1 - src/languages/hi/globals.json | 1 - src/languages/hi/guilds.json | 5 - src/languages/hi/humanLevels.json | 1 - src/languages/hi/moderation.json | 6 - src/languages/hi/moderationActions.json | 43 - src/languages/hi/permissions.json | 1 - src/languages/hi/preconditions.json | 1 - src/languages/hi/selfModeration.json | 1 - src/languages/hi/serializers.json | 1 - src/languages/hi/settings.json | 1 - src/languages/hi/system.json | 25 - src/languages/hr/arguments.json | 98 - src/languages/hr/assertions.json | 1 - src/languages/hr/commands/admin.json | 107 - src/languages/hr/commands/animal.json | 26 - .../hr/commands/auto-moderation.json | 1 - src/languages/hr/commands/case.json | 1 - src/languages/hr/commands/fun.json | 7 - src/languages/hr/commands/game.json | 447 -- src/languages/hr/commands/general.json | 36 - src/languages/hr/commands/info.json | 1 - src/languages/hr/commands/management.json | 445 -- src/languages/hr/commands/misc.json | 8 - src/languages/hr/commands/moderation.json | 889 --- src/languages/hr/commands/shared.json | 7 - src/languages/hr/commands/system.json | 30 - src/languages/hr/commands/tools.json | 49 - src/languages/hr/commands/twitch.json | 70 - src/languages/hr/commands/whois.json | 1 - src/languages/hr/errors.json | 1 - src/languages/hr/events/errors.json | 1 - src/languages/hr/events/guilds-logs.json | 1 - src/languages/hr/events/guilds-members.json | 1 - src/languages/hr/events/messages.json | 1 - src/languages/hr/events/moderation.json | 1 - src/languages/hr/events/noMentionSpam.json | 1 - src/languages/hr/events/reactions.json | 1 - src/languages/hr/events/twitch.json | 1 - src/languages/hr/fuzzySearch.json | 1 - src/languages/hr/globals.json | 1 - src/languages/hr/guilds.json | 1 - src/languages/hr/humanLevels.json | 1 - src/languages/hr/moderation.json | 1 - src/languages/hr/moderationActions.json | 43 - src/languages/hr/permissions.json | 1 - src/languages/hr/preconditions.json | 1 - src/languages/hr/selfModeration.json | 1 - src/languages/hr/serializers.json | 1 - src/languages/hr/settings.json | 1 - src/languages/hr/system.json | 25 - src/languages/hu/arguments.json | 98 - src/languages/hu/assertions.json | 1 - src/languages/hu/commands/admin.json | 107 - src/languages/hu/commands/animal.json | 26 - .../hu/commands/auto-moderation.json | 1 - src/languages/hu/commands/case.json | 1 - src/languages/hu/commands/fun.json | 7 - src/languages/hu/commands/game.json | 447 -- src/languages/hu/commands/general.json | 36 - src/languages/hu/commands/info.json | 1 - src/languages/hu/commands/management.json | 445 -- src/languages/hu/commands/misc.json | 8 - src/languages/hu/commands/moderation.json | 889 --- src/languages/hu/commands/shared.json | 7 - src/languages/hu/commands/system.json | 30 - src/languages/hu/commands/tools.json | 49 - src/languages/hu/commands/twitch.json | 70 - src/languages/hu/commands/whois.json | 1 - src/languages/hu/errors.json | 1 - src/languages/hu/events/errors.json | 1 - src/languages/hu/events/guilds-logs.json | 1 - src/languages/hu/events/guilds-members.json | 1 - src/languages/hu/events/messages.json | 1 - src/languages/hu/events/moderation.json | 1 - src/languages/hu/events/noMentionSpam.json | 1 - src/languages/hu/events/reactions.json | 1 - src/languages/hu/events/twitch.json | 1 - src/languages/hu/fuzzySearch.json | 1 - src/languages/hu/globals.json | 1 - src/languages/hu/guilds.json | 1 - src/languages/hu/humanLevels.json | 1 - src/languages/hu/moderation.json | 1 - src/languages/hu/moderationActions.json | 43 - src/languages/hu/permissions.json | 1 - src/languages/hu/preconditions.json | 1 - src/languages/hu/selfModeration.json | 1 - src/languages/hu/serializers.json | 1 - src/languages/hu/settings.json | 1 - src/languages/hu/system.json | 25 - src/languages/id/arguments.json | 98 - src/languages/id/assertions.json | 1 - src/languages/id/commands/admin.json | 107 - src/languages/id/commands/animal.json | 26 - .../id/commands/auto-moderation.json | 1 - src/languages/id/commands/case.json | 1 - src/languages/id/commands/fun.json | 7 - src/languages/id/commands/game.json | 447 -- src/languages/id/commands/general.json | 36 - src/languages/id/commands/info.json | 1 - src/languages/id/commands/management.json | 445 -- src/languages/id/commands/misc.json | 8 - src/languages/id/commands/moderation.json | 889 --- src/languages/id/commands/shared.json | 7 - src/languages/id/commands/system.json | 30 - src/languages/id/commands/tools.json | 49 - src/languages/id/commands/twitch.json | 70 - src/languages/id/commands/whois.json | 1 - src/languages/id/errors.json | 1 - src/languages/id/events/errors.json | 1 - src/languages/id/events/guilds-logs.json | 1 - src/languages/id/events/guilds-members.json | 1 - src/languages/id/events/messages.json | 1 - src/languages/id/events/moderation.json | 1 - src/languages/id/events/noMentionSpam.json | 1 - src/languages/id/events/reactions.json | 1 - src/languages/id/events/twitch.json | 1 - src/languages/id/fuzzySearch.json | 1 - src/languages/id/globals.json | 1 - src/languages/id/guilds.json | 1 - src/languages/id/humanLevels.json | 1 - src/languages/id/moderation.json | 1 - src/languages/id/moderationActions.json | 43 - src/languages/id/permissions.json | 1 - src/languages/id/preconditions.json | 1 - src/languages/id/selfModeration.json | 1 - src/languages/id/serializers.json | 1 - src/languages/id/settings.json | 1 - src/languages/id/system.json | 25 - src/languages/index.ts | 19 - src/languages/it/arguments.json | 98 - src/languages/it/assertions.json | 1 - src/languages/it/commands/admin.json | 107 - src/languages/it/commands/animal.json | 26 - .../it/commands/auto-moderation.json | 1 - src/languages/it/commands/case.json | 1 - src/languages/it/commands/fun.json | 7 - src/languages/it/commands/game.json | 447 -- src/languages/it/commands/general.json | 36 - src/languages/it/commands/info.json | 1 - src/languages/it/commands/management.json | 445 -- src/languages/it/commands/misc.json | 8 - src/languages/it/commands/moderation.json | 889 --- src/languages/it/commands/shared.json | 7 - src/languages/it/commands/system.json | 30 - src/languages/it/commands/tools.json | 49 - src/languages/it/commands/twitch.json | 70 - src/languages/it/commands/whois.json | 1 - src/languages/it/errors.json | 1 - src/languages/it/events/errors.json | 1 - src/languages/it/events/guilds-logs.json | 1 - src/languages/it/events/guilds-members.json | 1 - src/languages/it/events/messages.json | 1 - src/languages/it/events/moderation.json | 1 - src/languages/it/events/noMentionSpam.json | 1 - src/languages/it/events/reactions.json | 1 - src/languages/it/events/twitch.json | 1 - src/languages/it/fuzzySearch.json | 1 - src/languages/it/globals.json | 1 - src/languages/it/guilds.json | 1 - src/languages/it/humanLevels.json | 1 - src/languages/it/moderation.json | 1 - src/languages/it/moderationActions.json | 43 - src/languages/it/permissions.json | 1 - src/languages/it/preconditions.json | 1 - src/languages/it/selfModeration.json | 1 - src/languages/it/serializers.json | 1 - src/languages/it/settings.json | 1 - src/languages/it/system.json | 25 - src/languages/ja/arguments.json | 98 - src/languages/ja/assertions.json | 1 - src/languages/ja/commands/admin.json | 107 - src/languages/ja/commands/animal.json | 26 - .../ja/commands/auto-moderation.json | 1 - src/languages/ja/commands/case.json | 1 - src/languages/ja/commands/fun.json | 7 - src/languages/ja/commands/game.json | 447 -- src/languages/ja/commands/general.json | 36 - src/languages/ja/commands/info.json | 1 - src/languages/ja/commands/management.json | 445 -- src/languages/ja/commands/misc.json | 8 - src/languages/ja/commands/moderation.json | 889 --- src/languages/ja/commands/shared.json | 7 - src/languages/ja/commands/system.json | 30 - src/languages/ja/commands/tools.json | 49 - src/languages/ja/commands/twitch.json | 70 - src/languages/ja/commands/whois.json | 1 - src/languages/ja/errors.json | 1 - src/languages/ja/events/errors.json | 1 - src/languages/ja/events/guilds-logs.json | 1 - src/languages/ja/events/guilds-members.json | 1 - src/languages/ja/events/messages.json | 1 - src/languages/ja/events/moderation.json | 1 - src/languages/ja/events/noMentionSpam.json | 1 - src/languages/ja/events/reactions.json | 1 - src/languages/ja/events/twitch.json | 1 - src/languages/ja/fuzzySearch.json | 1 - src/languages/ja/globals.json | 1 - src/languages/ja/guilds.json | 1 - src/languages/ja/humanLevels.json | 1 - src/languages/ja/moderation.json | 1 - src/languages/ja/moderationActions.json | 43 - src/languages/ja/permissions.json | 1 - src/languages/ja/preconditions.json | 1 - src/languages/ja/selfModeration.json | 1 - src/languages/ja/serializers.json | 1 - src/languages/ja/settings.json | 1 - src/languages/ja/system.json | 25 - src/languages/ko/arguments.json | 98 - src/languages/ko/assertions.json | 1 - src/languages/ko/commands/admin.json | 107 - src/languages/ko/commands/animal.json | 26 - .../ko/commands/auto-moderation.json | 1 - src/languages/ko/commands/case.json | 1 - src/languages/ko/commands/fun.json | 7 - src/languages/ko/commands/game.json | 447 -- src/languages/ko/commands/general.json | 36 - src/languages/ko/commands/info.json | 1 - src/languages/ko/commands/management.json | 445 -- src/languages/ko/commands/misc.json | 8 - src/languages/ko/commands/moderation.json | 889 --- src/languages/ko/commands/shared.json | 7 - src/languages/ko/commands/system.json | 30 - src/languages/ko/commands/tools.json | 49 - src/languages/ko/commands/twitch.json | 70 - src/languages/ko/commands/whois.json | 1 - src/languages/ko/errors.json | 1 - src/languages/ko/events/errors.json | 1 - src/languages/ko/events/guilds-logs.json | 1 - src/languages/ko/events/guilds-members.json | 1 - src/languages/ko/events/messages.json | 1 - src/languages/ko/events/moderation.json | 1 - src/languages/ko/events/noMentionSpam.json | 1 - src/languages/ko/events/reactions.json | 1 - src/languages/ko/events/twitch.json | 1 - src/languages/ko/fuzzySearch.json | 1 - src/languages/ko/globals.json | 1 - src/languages/ko/guilds.json | 1 - src/languages/ko/humanLevels.json | 1 - src/languages/ko/moderation.json | 1 - src/languages/ko/moderationActions.json | 43 - src/languages/ko/permissions.json | 1 - src/languages/ko/preconditions.json | 1 - src/languages/ko/selfModeration.json | 1 - src/languages/ko/serializers.json | 1 - src/languages/ko/settings.json | 1 - src/languages/ko/system.json | 25 - src/languages/lt/arguments.json | 98 - src/languages/lt/assertions.json | 1 - src/languages/lt/commands/admin.json | 107 - src/languages/lt/commands/animal.json | 26 - .../lt/commands/auto-moderation.json | 1 - src/languages/lt/commands/case.json | 1 - src/languages/lt/commands/fun.json | 7 - src/languages/lt/commands/game.json | 447 -- src/languages/lt/commands/general.json | 36 - src/languages/lt/commands/info.json | 1 - src/languages/lt/commands/management.json | 445 -- src/languages/lt/commands/misc.json | 8 - src/languages/lt/commands/moderation.json | 889 --- src/languages/lt/commands/shared.json | 7 - src/languages/lt/commands/system.json | 30 - src/languages/lt/commands/tools.json | 49 - src/languages/lt/commands/twitch.json | 70 - src/languages/lt/commands/whois.json | 1 - src/languages/lt/errors.json | 1 - src/languages/lt/events/errors.json | 1 - src/languages/lt/events/guilds-logs.json | 1 - src/languages/lt/events/guilds-members.json | 1 - src/languages/lt/events/messages.json | 1 - src/languages/lt/events/moderation.json | 1 - src/languages/lt/events/noMentionSpam.json | 1 - src/languages/lt/events/reactions.json | 1 - src/languages/lt/events/twitch.json | 1 - src/languages/lt/fuzzySearch.json | 1 - src/languages/lt/globals.json | 1 - src/languages/lt/guilds.json | 1 - src/languages/lt/humanLevels.json | 1 - src/languages/lt/moderation.json | 1 - src/languages/lt/moderationActions.json | 43 - src/languages/lt/permissions.json | 1 - src/languages/lt/preconditions.json | 1 - src/languages/lt/selfModeration.json | 1 - src/languages/lt/serializers.json | 1 - src/languages/lt/settings.json | 1 - src/languages/lt/system.json | 25 - src/languages/nl/arguments.json | 98 - src/languages/nl/assertions.json | 3 - src/languages/nl/commands/admin.json | 107 - src/languages/nl/commands/animal.json | 26 - .../nl/commands/auto-moderation.json | 1 - src/languages/nl/commands/case.json | 1 - src/languages/nl/commands/fun.json | 7 - src/languages/nl/commands/game.json | 447 -- src/languages/nl/commands/general.json | 36 - src/languages/nl/commands/info.json | 1 - src/languages/nl/commands/management.json | 445 -- src/languages/nl/commands/misc.json | 8 - src/languages/nl/commands/moderation.json | 889 --- src/languages/nl/commands/shared.json | 7 - src/languages/nl/commands/system.json | 30 - src/languages/nl/commands/tools.json | 49 - src/languages/nl/commands/twitch.json | 70 - src/languages/nl/commands/whois.json | 1 - src/languages/nl/constants.ts | 40 - src/languages/nl/errors.json | 9 - src/languages/nl/events/errors.json | 1 - src/languages/nl/events/guilds-logs.json | 1 - src/languages/nl/events/guilds-members.json | 1 - src/languages/nl/events/messages.json | 4 - src/languages/nl/events/moderation.json | 1 - src/languages/nl/events/noMentionSpam.json | 1 - src/languages/nl/events/reactions.json | 1 - src/languages/nl/events/twitch.json | 1 - src/languages/nl/fuzzySearch.json | 6 - src/languages/nl/globals.json | 17 - src/languages/nl/guilds.json | 1 - src/languages/nl/humanLevels.json | 7 - src/languages/nl/moderation.json | 1 - src/languages/nl/moderationActions.json | 43 - src/languages/nl/permissions.json | 1 - src/languages/nl/preconditions.json | 1 - src/languages/nl/selfModeration.json | 1 - src/languages/nl/serializers.json | 1 - src/languages/nl/settings.json | 1 - src/languages/nl/system.json | 25 - src/languages/no/arguments.json | 98 - src/languages/no/assertions.json | 1 - src/languages/no/commands/admin.json | 107 - src/languages/no/commands/animal.json | 26 - .../no/commands/auto-moderation.json | 1 - src/languages/no/commands/case.json | 1 - src/languages/no/commands/fun.json | 7 - src/languages/no/commands/game.json | 447 -- src/languages/no/commands/general.json | 36 - src/languages/no/commands/info.json | 1 - src/languages/no/commands/management.json | 445 -- src/languages/no/commands/misc.json | 8 - src/languages/no/commands/moderation.json | 889 --- src/languages/no/commands/shared.json | 7 - src/languages/no/commands/system.json | 30 - src/languages/no/commands/tools.json | 49 - src/languages/no/commands/twitch.json | 70 - src/languages/no/commands/whois.json | 1 - src/languages/no/errors.json | 1 - src/languages/no/events/errors.json | 1 - src/languages/no/events/guilds-logs.json | 1 - src/languages/no/events/guilds-members.json | 1 - src/languages/no/events/messages.json | 1 - src/languages/no/events/moderation.json | 1 - src/languages/no/events/noMentionSpam.json | 1 - src/languages/no/events/reactions.json | 1 - src/languages/no/events/twitch.json | 1 - src/languages/no/fuzzySearch.json | 1 - src/languages/no/globals.json | 1 - src/languages/no/guilds.json | 1 - src/languages/no/humanLevels.json | 1 - src/languages/no/moderation.json | 1 - src/languages/no/moderationActions.json | 43 - src/languages/no/permissions.json | 1 - src/languages/no/preconditions.json | 1 - src/languages/no/selfModeration.json | 1 - src/languages/no/serializers.json | 1 - src/languages/no/settings.json | 1 - src/languages/no/system.json | 25 - src/languages/pl/arguments.json | 98 - src/languages/pl/assertions.json | 1 - src/languages/pl/commands/admin.json | 107 - src/languages/pl/commands/animal.json | 26 - .../pl/commands/auto-moderation.json | 1 - src/languages/pl/commands/case.json | 1 - src/languages/pl/commands/fun.json | 7 - src/languages/pl/commands/game.json | 447 -- src/languages/pl/commands/general.json | 36 - src/languages/pl/commands/info.json | 1 - src/languages/pl/commands/management.json | 445 -- src/languages/pl/commands/misc.json | 8 - src/languages/pl/commands/moderation.json | 889 --- src/languages/pl/commands/shared.json | 7 - src/languages/pl/commands/system.json | 30 - src/languages/pl/commands/tools.json | 49 - src/languages/pl/commands/twitch.json | 70 - src/languages/pl/commands/whois.json | 1 - src/languages/pl/errors.json | 1 - src/languages/pl/events/errors.json | 1 - src/languages/pl/events/guilds-logs.json | 1 - src/languages/pl/events/guilds-members.json | 1 - src/languages/pl/events/messages.json | 1 - src/languages/pl/events/moderation.json | 1 - src/languages/pl/events/noMentionSpam.json | 1 - src/languages/pl/events/reactions.json | 1 - src/languages/pl/events/twitch.json | 1 - src/languages/pl/fuzzySearch.json | 1 - src/languages/pl/globals.json | 1 - src/languages/pl/guilds.json | 1 - src/languages/pl/humanLevels.json | 1 - src/languages/pl/moderation.json | 1 - src/languages/pl/moderationActions.json | 43 - src/languages/pl/permissions.json | 1 - src/languages/pl/preconditions.json | 1 - src/languages/pl/selfModeration.json | 1 - src/languages/pl/serializers.json | 1 - src/languages/pl/settings.json | 1 - src/languages/pl/system.json | 25 - src/languages/pt-BR/arguments.json | 98 - src/languages/pt-BR/assertions.json | 1 - src/languages/pt-BR/commands/admin.json | 107 - src/languages/pt-BR/commands/animal.json | 26 - .../pt-BR/commands/auto-moderation.json | 1 - src/languages/pt-BR/commands/case.json | 1 - src/languages/pt-BR/commands/fun.json | 7 - src/languages/pt-BR/commands/game.json | 447 -- src/languages/pt-BR/commands/general.json | 36 - src/languages/pt-BR/commands/info.json | 1 - src/languages/pt-BR/commands/management.json | 445 -- src/languages/pt-BR/commands/misc.json | 8 - src/languages/pt-BR/commands/moderation.json | 889 --- src/languages/pt-BR/commands/shared.json | 7 - src/languages/pt-BR/commands/system.json | 30 - src/languages/pt-BR/commands/tools.json | 49 - src/languages/pt-BR/commands/twitch.json | 70 - src/languages/pt-BR/commands/whois.json | 1 - src/languages/pt-BR/errors.json | 1 - src/languages/pt-BR/events/errors.json | 1 - src/languages/pt-BR/events/guilds-logs.json | 1 - .../pt-BR/events/guilds-members.json | 1 - src/languages/pt-BR/events/messages.json | 1 - src/languages/pt-BR/events/moderation.json | 1 - src/languages/pt-BR/events/noMentionSpam.json | 1 - src/languages/pt-BR/events/reactions.json | 1 - src/languages/pt-BR/events/twitch.json | 1 - src/languages/pt-BR/fuzzySearch.json | 1 - src/languages/pt-BR/globals.json | 1 - src/languages/pt-BR/guilds.json | 1 - src/languages/pt-BR/humanLevels.json | 1 - src/languages/pt-BR/moderation.json | 1 - src/languages/pt-BR/moderationActions.json | 43 - src/languages/pt-BR/permissions.json | 1 - src/languages/pt-BR/preconditions.json | 1 - src/languages/pt-BR/selfModeration.json | 1 - src/languages/pt-BR/serializers.json | 1 - src/languages/pt-BR/settings.json | 1 - src/languages/pt-BR/system.json | 25 - src/languages/ro/arguments.json | 98 - src/languages/ro/assertions.json | 1 - src/languages/ro/commands/admin.json | 107 - src/languages/ro/commands/animal.json | 26 - .../ro/commands/auto-moderation.json | 1 - src/languages/ro/commands/case.json | 1 - src/languages/ro/commands/fun.json | 7 - src/languages/ro/commands/game.json | 447 -- src/languages/ro/commands/general.json | 36 - src/languages/ro/commands/info.json | 1 - src/languages/ro/commands/management.json | 445 -- src/languages/ro/commands/misc.json | 8 - src/languages/ro/commands/moderation.json | 889 --- src/languages/ro/commands/shared.json | 7 - src/languages/ro/commands/system.json | 30 - src/languages/ro/commands/tools.json | 49 - src/languages/ro/commands/twitch.json | 70 - src/languages/ro/commands/whois.json | 1 - src/languages/ro/errors.json | 1 - src/languages/ro/events/errors.json | 1 - src/languages/ro/events/guilds-logs.json | 1 - src/languages/ro/events/guilds-members.json | 1 - src/languages/ro/events/messages.json | 1 - src/languages/ro/events/moderation.json | 1 - src/languages/ro/events/noMentionSpam.json | 1 - src/languages/ro/events/reactions.json | 1 - src/languages/ro/events/twitch.json | 1 - src/languages/ro/fuzzySearch.json | 6 - src/languages/ro/globals.json | 13 - src/languages/ro/guilds.json | 1 - src/languages/ro/humanLevels.json | 1 - src/languages/ro/moderation.json | 1 - src/languages/ro/moderationActions.json | 43 - src/languages/ro/permissions.json | 1 - src/languages/ro/preconditions.json | 1 - src/languages/ro/selfModeration.json | 1 - src/languages/ro/serializers.json | 1 - src/languages/ro/settings.json | 1 - src/languages/ro/system.json | 25 - src/languages/ru/arguments.json | 98 - src/languages/ru/assertions.json | 1 - src/languages/ru/commands/admin.json | 107 - src/languages/ru/commands/animal.json | 26 - .../ru/commands/auto-moderation.json | 1 - src/languages/ru/commands/case.json | 1 - src/languages/ru/commands/fun.json | 7 - src/languages/ru/commands/game.json | 447 -- src/languages/ru/commands/general.json | 36 - src/languages/ru/commands/info.json | 1 - src/languages/ru/commands/management.json | 445 -- src/languages/ru/commands/misc.json | 8 - src/languages/ru/commands/moderation.json | 889 --- src/languages/ru/commands/shared.json | 7 - src/languages/ru/commands/system.json | 30 - src/languages/ru/commands/tools.json | 49 - src/languages/ru/commands/twitch.json | 70 - src/languages/ru/commands/whois.json | 1 - src/languages/ru/errors.json | 1 - src/languages/ru/events/errors.json | 1 - src/languages/ru/events/guilds-logs.json | 1 - src/languages/ru/events/guilds-members.json | 1 - src/languages/ru/events/messages.json | 4 - src/languages/ru/events/moderation.json | 1 - src/languages/ru/events/noMentionSpam.json | 1 - src/languages/ru/events/reactions.json | 4 - src/languages/ru/events/twitch.json | 4 - src/languages/ru/fuzzySearch.json | 1 - src/languages/ru/globals.json | 10 - src/languages/ru/guilds.json | 1 - src/languages/ru/humanLevels.json | 1 - src/languages/ru/moderation.json | 1 - src/languages/ru/moderationActions.json | 43 - src/languages/ru/permissions.json | 1 - src/languages/ru/preconditions.json | 4 - src/languages/ru/selfModeration.json | 1 - src/languages/ru/serializers.json | 1 - src/languages/ru/settings.json | 1 - src/languages/ru/system.json | 25 - src/languages/sv-SE/arguments.json | 98 - src/languages/sv-SE/assertions.json | 1 - src/languages/sv-SE/commands/admin.json | 107 - src/languages/sv-SE/commands/animal.json | 26 - .../sv-SE/commands/auto-moderation.json | 1 - src/languages/sv-SE/commands/case.json | 1 - src/languages/sv-SE/commands/fun.json | 7 - src/languages/sv-SE/commands/game.json | 447 -- src/languages/sv-SE/commands/general.json | 36 - src/languages/sv-SE/commands/info.json | 1 - src/languages/sv-SE/commands/management.json | 445 -- src/languages/sv-SE/commands/misc.json | 8 - src/languages/sv-SE/commands/moderation.json | 889 --- src/languages/sv-SE/commands/shared.json | 7 - src/languages/sv-SE/commands/system.json | 30 - src/languages/sv-SE/commands/tools.json | 49 - src/languages/sv-SE/commands/twitch.json | 70 - src/languages/sv-SE/commands/whois.json | 1 - src/languages/sv-SE/errors.json | 1 - src/languages/sv-SE/events/errors.json | 1 - src/languages/sv-SE/events/guilds-logs.json | 1 - .../sv-SE/events/guilds-members.json | 1 - src/languages/sv-SE/events/messages.json | 1 - src/languages/sv-SE/events/moderation.json | 1 - src/languages/sv-SE/events/noMentionSpam.json | 1 - src/languages/sv-SE/events/reactions.json | 1 - src/languages/sv-SE/events/twitch.json | 1 - src/languages/sv-SE/fuzzySearch.json | 1 - src/languages/sv-SE/globals.json | 1 - src/languages/sv-SE/guilds.json | 1 - src/languages/sv-SE/humanLevels.json | 1 - src/languages/sv-SE/moderation.json | 1 - src/languages/sv-SE/moderationActions.json | 43 - src/languages/sv-SE/permissions.json | 1 - src/languages/sv-SE/preconditions.json | 1 - src/languages/sv-SE/selfModeration.json | 1 - src/languages/sv-SE/serializers.json | 1 - src/languages/sv-SE/settings.json | 1 - src/languages/sv-SE/system.json | 25 - src/languages/th/arguments.json | 98 - src/languages/th/assertions.json | 1 - src/languages/th/commands/admin.json | 107 - src/languages/th/commands/animal.json | 26 - .../th/commands/auto-moderation.json | 1 - src/languages/th/commands/case.json | 1 - src/languages/th/commands/fun.json | 7 - src/languages/th/commands/game.json | 447 -- src/languages/th/commands/general.json | 36 - src/languages/th/commands/info.json | 1 - src/languages/th/commands/management.json | 445 -- src/languages/th/commands/misc.json | 8 - src/languages/th/commands/moderation.json | 889 --- src/languages/th/commands/shared.json | 7 - src/languages/th/commands/system.json | 30 - src/languages/th/commands/tools.json | 49 - src/languages/th/commands/twitch.json | 70 - src/languages/th/commands/whois.json | 1 - src/languages/th/errors.json | 1 - src/languages/th/events/errors.json | 1 - src/languages/th/events/guilds-logs.json | 1 - src/languages/th/events/guilds-members.json | 1 - src/languages/th/events/messages.json | 1 - src/languages/th/events/moderation.json | 1 - src/languages/th/events/noMentionSpam.json | 1 - src/languages/th/events/reactions.json | 1 - src/languages/th/events/twitch.json | 1 - src/languages/th/fuzzySearch.json | 1 - src/languages/th/globals.json | 1 - src/languages/th/guilds.json | 1 - src/languages/th/humanLevels.json | 1 - src/languages/th/moderation.json | 1 - src/languages/th/moderationActions.json | 43 - src/languages/th/permissions.json | 1 - src/languages/th/preconditions.json | 1 - src/languages/th/selfModeration.json | 1 - src/languages/th/serializers.json | 1 - src/languages/th/settings.json | 1 - src/languages/th/system.json | 25 - src/languages/tr/arguments.json | 98 - src/languages/tr/assertions.json | 1 - src/languages/tr/commands/admin.json | 107 - src/languages/tr/commands/animal.json | 26 - .../tr/commands/auto-moderation.json | 1 - src/languages/tr/commands/case.json | 1 - src/languages/tr/commands/fun.json | 7 - src/languages/tr/commands/game.json | 447 -- src/languages/tr/commands/general.json | 36 - src/languages/tr/commands/info.json | 1 - src/languages/tr/commands/management.json | 445 -- src/languages/tr/commands/misc.json | 8 - src/languages/tr/commands/moderation.json | 889 --- src/languages/tr/commands/shared.json | 7 - src/languages/tr/commands/system.json | 30 - src/languages/tr/commands/tools.json | 49 - src/languages/tr/commands/twitch.json | 70 - src/languages/tr/commands/whois.json | 1 - src/languages/tr/errors.json | 1 - src/languages/tr/events/errors.json | 1 - src/languages/tr/events/guilds-logs.json | 1 - src/languages/tr/events/guilds-members.json | 1 - src/languages/tr/events/messages.json | 1 - src/languages/tr/events/moderation.json | 1 - src/languages/tr/events/noMentionSpam.json | 1 - src/languages/tr/events/reactions.json | 1 - src/languages/tr/events/twitch.json | 1 - src/languages/tr/fuzzySearch.json | 1 - src/languages/tr/globals.json | 1 - src/languages/tr/guilds.json | 1 - src/languages/tr/humanLevels.json | 1 - src/languages/tr/moderation.json | 1 - src/languages/tr/moderationActions.json | 43 - src/languages/tr/permissions.json | 1 - src/languages/tr/preconditions.json | 1 - src/languages/tr/selfModeration.json | 1 - src/languages/tr/serializers.json | 1 - src/languages/tr/settings.json | 1 - src/languages/tr/system.json | 25 - src/languages/uk/arguments.json | 98 - src/languages/uk/assertions.json | 1 - src/languages/uk/commands/admin.json | 107 - src/languages/uk/commands/animal.json | 26 - .../uk/commands/auto-moderation.json | 1 - src/languages/uk/commands/case.json | 1 - src/languages/uk/commands/fun.json | 7 - src/languages/uk/commands/game.json | 447 -- src/languages/uk/commands/general.json | 36 - src/languages/uk/commands/info.json | 1 - src/languages/uk/commands/management.json | 445 -- src/languages/uk/commands/misc.json | 8 - src/languages/uk/commands/moderation.json | 889 --- src/languages/uk/commands/shared.json | 7 - src/languages/uk/commands/system.json | 30 - src/languages/uk/commands/tools.json | 49 - src/languages/uk/commands/twitch.json | 70 - src/languages/uk/commands/whois.json | 1 - src/languages/uk/errors.json | 1 - src/languages/uk/events/errors.json | 1 - src/languages/uk/events/guilds-logs.json | 1 - src/languages/uk/events/guilds-members.json | 1 - src/languages/uk/events/messages.json | 1 - src/languages/uk/events/moderation.json | 1 - src/languages/uk/events/noMentionSpam.json | 1 - src/languages/uk/events/reactions.json | 1 - src/languages/uk/events/twitch.json | 1 - src/languages/uk/fuzzySearch.json | 1 - src/languages/uk/globals.json | 1 - src/languages/uk/guilds.json | 1 - src/languages/uk/humanLevels.json | 1 - src/languages/uk/moderation.json | 1 - src/languages/uk/moderationActions.json | 43 - src/languages/uk/permissions.json | 1 - src/languages/uk/preconditions.json | 1 - src/languages/uk/selfModeration.json | 1 - src/languages/uk/serializers.json | 1 - src/languages/uk/settings.json | 1 - src/languages/uk/system.json | 25 - src/languages/vi/arguments.json | 98 - src/languages/vi/assertions.json | 1 - src/languages/vi/commands/admin.json | 107 - src/languages/vi/commands/animal.json | 26 - .../vi/commands/auto-moderation.json | 1 - src/languages/vi/commands/case.json | 1 - src/languages/vi/commands/fun.json | 7 - src/languages/vi/commands/game.json | 447 -- src/languages/vi/commands/general.json | 36 - src/languages/vi/commands/info.json | 1 - src/languages/vi/commands/management.json | 445 -- src/languages/vi/commands/misc.json | 8 - src/languages/vi/commands/moderation.json | 889 --- src/languages/vi/commands/shared.json | 7 - src/languages/vi/commands/system.json | 30 - src/languages/vi/commands/tools.json | 49 - src/languages/vi/commands/twitch.json | 70 - src/languages/vi/commands/whois.json | 1 - src/languages/vi/errors.json | 1 - src/languages/vi/events/errors.json | 1 - src/languages/vi/events/guilds-logs.json | 1 - src/languages/vi/events/guilds-members.json | 1 - src/languages/vi/events/messages.json | 1 - src/languages/vi/events/moderation.json | 1 - src/languages/vi/events/noMentionSpam.json | 1 - src/languages/vi/events/reactions.json | 1 - src/languages/vi/events/twitch.json | 1 - src/languages/vi/fuzzySearch.json | 1 - src/languages/vi/globals.json | 1 - src/languages/vi/guilds.json | 1 - src/languages/vi/humanLevels.json | 1 - src/languages/vi/moderation.json | 1 - src/languages/vi/moderationActions.json | 43 - src/languages/vi/permissions.json | 1 - src/languages/vi/preconditions.json | 1 - src/languages/vi/selfModeration.json | 1 - src/languages/vi/serializers.json | 1 - src/languages/vi/settings.json | 1 - src/languages/vi/system.json | 25 - src/languages/zh-CN/arguments.json | 98 - src/languages/zh-CN/assertions.json | 1 - src/languages/zh-CN/commands/admin.json | 107 - src/languages/zh-CN/commands/animal.json | 26 - .../zh-CN/commands/auto-moderation.json | 1 - src/languages/zh-CN/commands/case.json | 1 - src/languages/zh-CN/commands/fun.json | 7 - src/languages/zh-CN/commands/game.json | 447 -- src/languages/zh-CN/commands/general.json | 36 - src/languages/zh-CN/commands/info.json | 1 - src/languages/zh-CN/commands/management.json | 445 -- src/languages/zh-CN/commands/misc.json | 8 - src/languages/zh-CN/commands/moderation.json | 889 --- src/languages/zh-CN/commands/shared.json | 7 - src/languages/zh-CN/commands/system.json | 30 - src/languages/zh-CN/commands/tools.json | 49 - src/languages/zh-CN/commands/twitch.json | 70 - src/languages/zh-CN/commands/whois.json | 1 - src/languages/zh-CN/errors.json | 1 - src/languages/zh-CN/events/errors.json | 1 - src/languages/zh-CN/events/guilds-logs.json | 1 - .../zh-CN/events/guilds-members.json | 1 - src/languages/zh-CN/events/messages.json | 1 - src/languages/zh-CN/events/moderation.json | 1 - src/languages/zh-CN/events/noMentionSpam.json | 1 - src/languages/zh-CN/events/reactions.json | 1 - src/languages/zh-CN/events/twitch.json | 1 - src/languages/zh-CN/fuzzySearch.json | 1 - src/languages/zh-CN/globals.json | 1 - src/languages/zh-CN/guilds.json | 1 - src/languages/zh-CN/humanLevels.json | 1 - src/languages/zh-CN/moderation.json | 1 - src/languages/zh-CN/moderationActions.json | 43 - src/languages/zh-CN/permissions.json | 1 - src/languages/zh-CN/preconditions.json | 1 - src/languages/zh-CN/selfModeration.json | 1 - src/languages/zh-CN/serializers.json | 1 - src/languages/zh-CN/settings.json | 1 - src/languages/zh-CN/system.json | 25 - src/languages/zh-TW/arguments.json | 98 - src/languages/zh-TW/assertions.json | 1 - src/languages/zh-TW/commands/admin.json | 107 - src/languages/zh-TW/commands/animal.json | 26 - .../zh-TW/commands/auto-moderation.json | 1 - src/languages/zh-TW/commands/case.json | 1 - src/languages/zh-TW/commands/fun.json | 7 - src/languages/zh-TW/commands/game.json | 447 -- src/languages/zh-TW/commands/general.json | 36 - src/languages/zh-TW/commands/info.json | 1 - src/languages/zh-TW/commands/management.json | 445 -- src/languages/zh-TW/commands/misc.json | 8 - src/languages/zh-TW/commands/moderation.json | 889 --- src/languages/zh-TW/commands/shared.json | 7 - src/languages/zh-TW/commands/system.json | 30 - src/languages/zh-TW/commands/tools.json | 49 - src/languages/zh-TW/commands/twitch.json | 70 - src/languages/zh-TW/commands/whois.json | 1 - src/languages/zh-TW/errors.json | 1 - src/languages/zh-TW/events/errors.json | 1 - src/languages/zh-TW/events/guilds-logs.json | 1 - .../zh-TW/events/guilds-members.json | 1 - src/languages/zh-TW/events/messages.json | 1 - src/languages/zh-TW/events/moderation.json | 1 - src/languages/zh-TW/events/noMentionSpam.json | 1 - src/languages/zh-TW/events/reactions.json | 1 - src/languages/zh-TW/events/twitch.json | 1 - src/languages/zh-TW/fuzzySearch.json | 1 - src/languages/zh-TW/globals.json | 1 - src/languages/zh-TW/guilds.json | 1 - src/languages/zh-TW/humanLevels.json | 1 - src/languages/zh-TW/moderation.json | 1 - src/languages/zh-TW/moderationActions.json | 43 - src/languages/zh-TW/permissions.json | 1 - src/languages/zh-TW/preconditions.json | 1 - src/languages/zh-TW/selfModeration.json | 1 - src/languages/zh-TW/serializers.json | 1 - src/languages/zh-TW/settings.json | 1 - src/languages/zh-TW/system.json | 25 - src/lib/WolfClient.ts | 100 - src/lib/api/ApiTransformers.ts | 365 - src/lib/api/types.ts | 22 - src/lib/api/utils.ts | 140 - src/lib/database/index.ts | 2 - src/lib/database/settings/Utils.ts | 65 - src/lib/database/settings/auditActions.ts | 15 - .../database/settings/base/ISchemaValue.ts | 11 - src/lib/database/settings/configuration.ts | 1051 --- src/lib/database/settings/constants.ts | 167 - .../settings/context/SettingsContext.ts | 60 - .../database/settings/context/functions.ts | 27 - src/lib/database/settings/functions.ts | 234 - src/lib/database/settings/index.ts | 14 - .../database/settings/schema/SchemaGroup.ts | 115 - src/lib/database/settings/schema/SchemaKey.ts | 141 - .../settings/structures/AdderManager.ts | 53 - .../settings/structures/AuditLogEnvelope.ts | 31 - .../settings/structures/AuditLogManager.ts | 195 - .../structures/PermissionNodeManager.ts | 239 - .../settings/structures/Serializer.ts | 187 - .../settings/structures/SerializerStore.ts | 12 - .../collections/AliasedCollection.ts | 12 - src/lib/database/settings/types.ts | 77 - src/lib/database/utils/Adder.ts | 116 - src/lib/database/utils/matchers/Command.ts | 120 - src/lib/database/utils/matchers/index.ts | 1 - src/lib/discord/Api.ts | 6 - src/lib/discord/index.ts | 1 - src/lib/games/HungerGamesUsage.ts | 49 - src/lib/games/TriviaManager.ts | 77 - src/lib/games/base/BaseBotController.ts | 11 - src/lib/games/base/BaseController.ts | 24 - src/lib/games/base/BaseGame.ts | 85 - src/lib/games/base/BaseReactionController.ts | 55 - src/lib/games/base/BaseReactionGame.ts | 48 - .../connect-four/ConnectFourBotController.ts | 19 - src/lib/games/connect-four/ConnectFourGame.ts | 307 - .../ConnectFourHumanController.ts | 19 - src/lib/games/connect-four/lib/constants.ts | 7 - .../tic-tac-toe/TicTacToeBotController.ts | 12 - src/lib/games/tic-tac-toe/TicTacToeGame.ts | 98 - .../tic-tac-toe/TicTacToeHumanController.ts | 19 - src/lib/i18n/LanguageHelp.ts | 96 - src/lib/i18n/index.ts | 1 - src/lib/i18n/languageKeys/index.ts | 1 - src/lib/i18n/languageKeys/keys/All.ts | 14 - src/lib/i18n/languageKeys/keys/Commands.ts | 16 - .../keys/CustomCommandSerializer/All.ts | 9 - .../keys/DisabledCommandChannels/All.ts | 4 - src/lib/i18n/languageKeys/keys/Errors.ts | 11 - src/lib/i18n/languageKeys/keys/Moderation.ts | 45 - .../i18n/languageKeys/keys/Preconditions.ts | 44 - src/lib/i18n/languageKeys/keys/System.ts | 14 - .../i18n/languageKeys/keys/commands/Admin.ts | 14 - .../keys/commands/AutoModeration.ts | 69 - .../i18n/languageKeys/keys/commands/Case.ts | 48 - .../i18n/languageKeys/keys/commands/Conf.ts | 46 - .../i18n/languageKeys/keys/commands/Fun.ts | 6 - .../i18n/languageKeys/keys/commands/Games.ts | 40 - .../languageKeys/keys/commands/General.ts | 45 - .../i18n/languageKeys/keys/commands/Info.ts | 23 - .../languageKeys/keys/commands/Permissions.ts | 14 - .../i18n/languageKeys/keys/commands/Shared.ts | 6 - .../i18n/languageKeys/keys/commands/Snipe.ts | 6 - .../i18n/languageKeys/keys/commands/System.ts | 10 - .../i18n/languageKeys/keys/commands/Tools.ts | 12 - .../i18n/languageKeys/keys/commands/Whois.ts | 20 - src/lib/i18n/languageKeys/keys/events/All.ts | 6 - .../languageKeys/keys/events/guilds/All.ts | 2 - .../keys/events/guilds/Members.ts | 23 - .../languageKeys/keys/events/messages/All.ts | 13 - .../keys/events/moderation/All.ts | 1 - .../languageKeys/keys/events/reactions/All.ts | 7 - .../languageKeys/keys/settings/Channels.ts | 6 - src/lib/i18n/structures/Handler.ts | 18 - src/lib/i18n/translate.ts | 162 - .../moderation/actions/ModerationActionBan.ts | 35 - .../actions/ModerationActionKick.ts | 18 - .../actions/ModerationActionRestrictedAll.ts | 25 - .../ModerationActionRestrictedAttachment.ts | 16 - .../ModerationActionRestrictedEmbed.ts | 16 - .../ModerationActionRestrictedEmoji.ts | 16 - .../ModerationActionRestrictedReaction.ts | 16 - .../ModerationActionRestrictedVoice.ts | 16 - .../actions/ModerationActionRoleAdd.ts | 49 - .../actions/ModerationActionRoleRemove.ts | 49 - .../actions/ModerationActionSetNickname.ts | 47 - .../actions/ModerationActionSoftBan.ts | 36 - .../actions/ModerationActionTimeout.ts | 56 - .../actions/ModerationActionVoiceKick.ts | 19 - .../actions/ModerationActionVoiceMute.ts | 34 - .../actions/ModerationActionWarning.ts | 12 - .../actions/base/ModerationAction.ts | 430 -- .../actions/base/RoleModerationAction.ts | 436 -- src/lib/moderation/actions/index.ts | 72 - src/lib/moderation/common/constants.ts | 149 - src/lib/moderation/common/index.ts | 2 - src/lib/moderation/common/util.ts | 70 - src/lib/moderation/index.ts | 3 - src/lib/moderation/managers/LoggerManager.ts | 134 - .../moderation/managers/ModerationManager.ts | 411 -- .../managers/ModerationManagerEntry.ts | 357 - .../moderation/managers/StickyRoleManager.ts | 161 - src/lib/moderation/managers/index.ts | 5 - .../loggers/PruneLoggerTypeManager.ts | 8 - .../loggers/TimeoutLoggerTypeManager.ts | 13 - .../loggers/base/LoggerTypeManager.ts | 199 - src/lib/moderation/managers/loggers/index.ts | 2 - .../structures/AutoModerationCommand.ts | 434 -- .../structures/AutoModerationOnInfraction.ts | 17 - .../structures/ModerationCommand.ts | 404 -- .../structures/ModerationListener.ts | 121 - .../structures/ModerationMessageListener.ts | 216 - .../structures/SetUpModerationCommand.ts | 87 - src/lib/moderation/structures/index.ts | 7 - src/lib/moderation/workers/index.ts | 5 - src/lib/schedule/index.ts | 4 - src/lib/schedule/manager/ScheduleEntry.ts | 168 - src/lib/schedule/manager/ScheduleManager.ts | 197 - src/lib/schedule/structures/Task.ts | 15 - src/lib/schedule/structures/TaskStore.ts | 12 - src/lib/setup/index.ts | 16 - src/lib/setup/inspect.ts | 4 - src/lib/setup/paginated-message.ts | 23 - src/lib/setup/prisma.ts | 51 - src/lib/structures/AnalyticsData.ts | 16 - src/lib/structures/SettingsMenu.ts | 744 -- .../commands/ChannelConfigurationCommand.ts | 57 - src/lib/structures/commands/WolfArgs.ts | 78 - src/lib/structures/commands/WolfCommand.ts | 87 - src/lib/structures/commands/WolfSubcommand.ts | 79 - .../commands/base/BaseWolfCommandUtilities.ts | 79 - src/lib/structures/commands/index.ts | 4 - src/lib/structures/data/SortedCollection.ts | 229 - src/lib/structures/data/index.ts | 1 - src/lib/structures/index.ts | 7 - .../structures/listeners/AnalyticsListener.ts | 41 - src/lib/structures/listeners/ShardListener.ts | 10 - src/lib/structures/listeners/index.ts | 2 - src/lib/structures/managers/index.ts | 1 - .../preconditions/PermissionsPrecondition.ts | 72 - src/lib/structures/preconditions/index.ts | 1 - src/lib/types/AnalyticsSchema.ts | 27 - src/lib/types/Augments.d.ts | 185 - src/lib/types/Discord.ts | 5 - src/lib/types/Enums.ts | 59 - src/lib/types/Internals.ts | 7 - src/lib/types/Utils.ts | 33 - src/lib/types/index.ts | 5 - src/lib/util/External/escapeMarkdown.ts | 204 - .../util/LongLivingInteractionCollector.ts | 80 - src/lib/util/LongLivingReactionCollector.ts | 98 - src/lib/util/Timers.ts | 34 - src/lib/util/bits.ts | 15 - src/lib/util/common/error.ts | 80 - src/lib/util/common/guild.ts | 9 - src/lib/util/common/index.ts | 7 - src/lib/util/common/parse.ts | 11 - src/lib/util/constants.ts | 151 - src/lib/util/deprecate.ts | 64 - src/lib/util/functions/auditLogEmbeds.ts | 119 - src/lib/util/functions/channels.ts | 43 - src/lib/util/functions/embeds.ts | 44 - src/lib/util/functions/index.ts | 10 - src/lib/util/functions/messages.ts | 190 - src/lib/util/functions/permissions.ts | 36 - src/lib/util/functions/pieces.ts | 10 - src/lib/util/functions/users.ts | 35 - src/lib/util/moderation-utilities.ts | 27 - src/lib/util/moderationConstants.ts | 50 - src/lib/util/resolvers/Case.ts | 27 - src/lib/util/resolvers/TimeSpan.ts | 41 - src/lib/util/resolvers/index.ts | 2 - src/lib/util/util.ts | 363 - src/listeners/analytics/analyticsSync.ts | 42 - .../analytics/commandUsageAnalytics.ts | 16 - .../analytics/guilds/guildCreateAnalytics.ts | 26 - .../analytics/guilds/guildDeleteAnalytics.ts | 26 - .../analytics/messages/messageAnalytics.ts | 10 - .../analytics/resourceAnalyticsSync.ts | 32 - src/listeners/commands/_chat-input-shared.ts | 18 - src/listeners/commands/_command-log-shared.ts | 47 - src/listeners/commands/_message-shared.ts | 177 - src/listeners/commands/_shared.ts | 106 - .../commands/chatInputCommandError.ts | 8 - .../chatInputCommandErrorCommandLog.ts | 20 - .../chatInputCommandSuccessAnalytics.ts | 31 - .../chatInputCommandSuccessCommandLog.ts | 22 - .../commands/chatInputCommandSuccessLogger.ts | 24 - .../commands/chatInputSubcommandError.ts | 9 - .../commands/contextMenuCommandError.ts | 7 - .../contextMenuCommandErrorCommandLog.ts | 20 - .../contextMenuCommandSuccessAnalytics.ts | 24 - .../contextMenuCommandSuccessCommandLog.ts | 22 - .../contextMenuCommandSuccessLogger.ts | 24 - src/listeners/commands/messageCommandError.ts | 8 - .../commands/messageCommandErrorCommandLog.ts | 21 - .../messageCommandSuccessAnalytics.ts | 24 - .../messageCommandSuccessAutoDelete.ts | 18 - .../messageCommandSuccessCommandLog.ts | 23 - .../commands/messageSubcommandError.ts | 9 - src/listeners/guildMessageLog.ts | 43 - src/listeners/guilds/bans/guildBanAdd.ts | 20 - src/listeners/guilds/bans/guildBanRemove.ts | 20 - .../guilds/channels/channelDeleteNotify.ts | 40 - .../guilds/channels/voiceStateUpdateNotify.ts | 88 - .../guilds/emojis/emojiCreateNotify.ts | 45 - .../guilds/emojis/emojiDeleteNotify.ts | 29 - .../guilds/members/guildMemberAdd.ts | 104 - .../members/guildMemberUpdateTimeoutNotify.ts | 63 - .../members/notMutedMemberAddInitialRole.ts | 43 - .../guilds/members/notMutedMemberAddNotify.ts | 40 - .../guilds/members/rawMemberRemoveNotify.ts | 89 - .../rawGuildAuditLogEntryCreateLoggerTrack.ts | 35 - .../guilds/rawGuildCreateMemberFetch.ts | 10 - src/listeners/guilds/rawGuildDelete.ts | 13 - .../guilds/rawGuildDeleteMemberFetch.ts | 10 - src/listeners/guilds/roles/roleDelete.ts | 58 - .../guilds/roles/roleDeleteNotify.ts | 28 - src/listeners/guilds/roles/roleUpdate.ts | 18 - .../interactions/interactionCreate.ts | 23 - src/listeners/mentionPrefixOnly.ts | 27 - src/listeners/mentionSpamExceeded.ts | 34 - src/listeners/mentionSpamWarning.ts | 11 - .../messages/rawMessageDeleteBulkNotify.ts | 93 - .../messages/rawMessageDeleteNotify.ts | 82 - .../messages/rawMessageUpdateNotify.ts | 96 - .../moderation/moderationEntryAdd.ts | 52 - .../moderation/moderationEntryEdit.ts | 148 - .../reactions/rawReactionAddBlockList.ts | 102 - .../reactions/rawReactionAddNotify.ts | 175 - src/listeners/ready.ts | 193 - src/listeners/shard/shardDisconnect.ts | 11 - src/listeners/shard/shardError.ts | 10 - src/listeners/shard/shardReady.ts | 10 - src/listeners/shard/shardReconnecting.ts | 10 - src/listeners/shard/shardResume.ts | 10 - src/preconditions/Administrator.ts | 10 - src/preconditions/BotOwner.ts | 9 - src/preconditions/Enabled.ts | 73 - src/preconditions/Everyone.ts | 9 - src/preconditions/Moderator.ts | 10 - src/preconditions/ServerOwner.ts | 9 - src/routes/commands.get.ts | 38 - src/routes/guilds/[guild]/audit-logs.get.ts | 121 - src/routes/guilds/[guild]/command-logs.get.ts | 63 - src/routes/guilds/[guild]/settings.get.ts | 30 - src/routes/index.get.ts | 7 - src/routes/languages.get.ts | 10 - src/serializers/boolean.ts | 17 - src/serializers/categoryortextchannel.ts | 28 - src/serializers/channel.ts | 49 - src/serializers/command.ts | 23 - src/serializers/commandautodelete.ts | 34 - src/serializers/commandmatch.ts | 19 - src/serializers/disabledcommandchannel.ts | 44 - src/serializers/emoji.ts | 23 - src/serializers/guild.ts | 22 - src/serializers/invite.ts | 21 - src/serializers/language.ts | 12 - src/serializers/notAllowed.ts | 12 - src/serializers/number.ts | 32 - src/serializers/permissionnode.ts | 83 - src/serializers/reactionrole.ts | 32 - src/serializers/role.ts | 22 - src/serializers/snowflake.ts | 30 - src/serializers/stickyrole.ts | 28 - src/serializers/string.ts | 12 - src/serializers/timespan.ts | 18 - src/serializers/uniqueroleset.ts | 36 - src/serializers/url.ts | 41 - src/serializers/user.ts | 33 - src/serializers/word.ts | 36 - src/tasks/moderation/moderationEndAddRole.ts | 17 - src/tasks/moderation/moderationEndBan.ts | 17 - src/tasks/moderation/moderationEndMute.ts | 14 - .../moderation/moderationEndRemoveRole.ts | 17 - .../moderationEndRestrictionAttachment.ts | 17 - .../moderationEndRestrictionEmbed.ts | 17 - .../moderationEndRestrictionEmoji.ts | 17 - .../moderationEndRestrictionReaction.ts | 17 - .../moderationEndRestrictionVoice.ts | 17 - .../moderation/moderationEndSetNickname.ts | 17 - src/tasks/moderation/moderationEndTimeout.ts | 24 - .../moderation/moderationEndVoiceMute.ts | 17 - src/tasks/moderation/moderationEndWarning.ts | 17 - src/tasks/syncResourceAnalytics.ts | 9 - src/tsconfig.json | 14 - tests/tsconfig.json | 15 - tsconfig.base.json | 7 +- tsdown.config.ts | 99 - vitest.config.ts | 75 +- 2032 files changed, 16601 insertions(+), 105500 deletions(-) create mode 100644 projects/bot/Dockerfile create mode 100644 projects/bot/package.json rename {scripts/build => projects/bot/scripts}/clean.mjs (75%) create mode 100644 projects/bot/src/.env create mode 100644 projects/bot/src/.env.development rename {src => projects/bot/src}/.env.test (100%) create mode 100644 projects/bot/src/commands/Admin/eval.ts rename {src => projects/bot/src}/commands/Management/Helpers/guild-info.ts (67%) rename {src => projects/bot/src}/commands/Management/Helpers/role-info.ts (64%) rename {src => projects/bot/src}/commands/Management/Members/stickyRoles.ts (76%) create mode 100644 projects/bot/src/commands/Management/Message Filters/attachmentMode.ts create mode 100644 projects/bot/src/commands/Management/Message Filters/capitalsMode.ts create mode 100644 projects/bot/src/commands/Management/Message Filters/filter.ts create mode 100644 projects/bot/src/commands/Management/Message Filters/filterMode.ts create mode 100644 projects/bot/src/commands/Management/Message Filters/inviteMode.ts create mode 100644 projects/bot/src/commands/Management/Message Filters/linkMode.ts create mode 100644 projects/bot/src/commands/Management/Message Filters/messageMode.ts create mode 100644 projects/bot/src/commands/Management/Message Filters/newlineMode.ts create mode 100644 projects/bot/src/commands/Management/Reaction Filters/reactionMode.ts create mode 100644 projects/bot/src/commands/Moderation/Management/history.ts create mode 100644 projects/bot/src/commands/Moderation/Management/moderations.ts create mode 100644 projects/bot/src/commands/Moderation/Utilities/case.ts create mode 100644 projects/bot/src/commands/Moderation/Utilities/permissions.ts create mode 100644 projects/bot/src/commands/Moderation/Utilities/reason.ts rename {src => projects/bot/src}/commands/Moderation/Utilities/slowmode.ts (81%) create mode 100644 projects/bot/src/commands/Moderation/Utilities/time.ts create mode 100644 projects/bot/src/commands/Moderation/addrole.ts create mode 100644 projects/bot/src/commands/Moderation/ban.ts rename {src => projects/bot/src}/commands/Moderation/dehoist.ts (82%) create mode 100644 projects/bot/src/commands/Moderation/kick.ts rename {src => projects/bot/src}/commands/Moderation/lockdown.ts (77%) create mode 100644 projects/bot/src/commands/Moderation/mute.ts create mode 100644 projects/bot/src/commands/Moderation/prune.ts create mode 100644 projects/bot/src/commands/Moderation/removerole.ts create mode 100644 projects/bot/src/commands/Moderation/setnickname.ts create mode 100644 projects/bot/src/commands/Moderation/softban.ts rename {src => projects/bot/src}/commands/Moderation/togglemoderationdm.ts (70%) create mode 100644 projects/bot/src/commands/Moderation/unban.ts create mode 100644 projects/bot/src/commands/Moderation/unmute.ts create mode 100644 projects/bot/src/commands/Moderation/unwarn.ts create mode 100644 projects/bot/src/commands/Moderation/voicekick.ts create mode 100644 projects/bot/src/commands/Moderation/warn.ts create mode 100644 projects/bot/src/commands/Tools/whois.ts create mode 100644 projects/bot/src/config.ts create mode 100644 projects/bot/src/lib/Client.ts create mode 100644 projects/bot/src/lib/augments.d.ts rename {src => projects/bot/src}/lib/discord/GuildMemberFetchQueue.ts (98%) create mode 100644 projects/bot/src/lib/i18n/languageKeys/index.ts create mode 100644 projects/bot/src/lib/i18n/languageKeys/keys/All.ts rename {src => projects/bot/src}/lib/i18n/languageKeys/keys/Arguments.ts (88%) rename {src => projects/bot/src}/lib/i18n/languageKeys/keys/Assertions.ts (100%) create mode 100644 projects/bot/src/lib/i18n/languageKeys/keys/Colors.ts create mode 100644 projects/bot/src/lib/i18n/languageKeys/keys/Commands.ts rename {src => projects/bot/src}/lib/i18n/languageKeys/keys/FuzzySearch.ts (100%) rename {src => projects/bot/src}/lib/i18n/languageKeys/keys/Globals.ts (72%) rename {src => projects/bot/src}/lib/i18n/languageKeys/keys/Guilds.ts (100%) rename {src => projects/bot/src}/lib/i18n/languageKeys/keys/Misc.ts (57%) create mode 100644 projects/bot/src/lib/i18n/languageKeys/keys/Preconditions.ts create mode 100644 projects/bot/src/lib/i18n/languageKeys/keys/PromptList.ts rename {src => projects/bot/src}/lib/i18n/languageKeys/keys/Serializers.ts (85%) rename {src => projects/bot/src}/lib/i18n/languageKeys/keys/Settings.ts (85%) create mode 100644 projects/bot/src/lib/i18n/languageKeys/keys/System.ts create mode 100644 projects/bot/src/lib/i18n/languageKeys/keys/commands/Admin.ts rename {src => projects/bot/src}/lib/i18n/languageKeys/keys/commands/Management.ts (81%) rename {src => projects/bot/src}/lib/i18n/languageKeys/keys/commands/Moderation.ts (57%) create mode 100644 projects/bot/src/lib/i18n/languageKeys/keys/commands/Whois.ts create mode 100644 projects/bot/src/lib/i18n/languageKeys/keys/events/All.ts rename {src => projects/bot/src}/lib/i18n/languageKeys/keys/events/NoMentionSpam.ts (67%) rename {src => projects/bot/src}/lib/i18n/languageKeys/keys/events/errors/All.ts (100%) create mode 100644 projects/bot/src/lib/i18n/languageKeys/keys/events/guilds/All.ts rename {src => projects/bot/src}/lib/i18n/languageKeys/keys/events/guilds/Logs.ts (87%) create mode 100644 projects/bot/src/lib/i18n/languageKeys/keys/events/guilds/Members.ts create mode 100644 projects/bot/src/lib/i18n/languageKeys/keys/events/messages/All.ts create mode 100644 projects/bot/src/lib/i18n/languageKeys/keys/events/moderation/All.ts rename {src => projects/bot/src}/lib/i18n/languageKeys/keys/events/moderation/Messages.ts (100%) create mode 100644 projects/bot/src/lib/i18n/languageKeys/keys/events/reactions/All.ts create mode 100644 projects/bot/src/lib/i18n/languageKeys/keys/settings/Channels.ts rename {src => projects/bot/src}/lib/i18n/languageKeys/keys/settings/Gateway.ts (100%) rename {src => projects/bot/src}/lib/i18n/languageKeys/keys/settings/channels/Ignore.ts (80%) rename {src => projects/bot/src}/lib/i18n/languageKeys/keys/settings/channels/Logs.ts (89%) create mode 100644 projects/bot/src/lib/moderation/index.ts create mode 100644 projects/bot/src/lib/moderation/managers/ModerationManager.ts create mode 100644 projects/bot/src/lib/moderation/managers/StickyRoleManager.ts create mode 100644 projects/bot/src/lib/moderation/managers/index.ts create mode 100644 projects/bot/src/lib/moderation/structures/ModerationCommand.ts create mode 100644 projects/bot/src/lib/moderation/structures/ModerationListener.ts create mode 100644 projects/bot/src/lib/moderation/structures/ModerationMessageListener.ts rename {src => projects/bot/src}/lib/moderation/structures/ModerationTask.ts (54%) create mode 100644 projects/bot/src/lib/moderation/structures/SelfModerationCommand.ts create mode 100644 projects/bot/src/lib/moderation/structures/SelfModeratorBitField.ts create mode 100644 projects/bot/src/lib/moderation/structures/SetUpModerationCommand.ts create mode 100644 projects/bot/src/lib/moderation/structures/index.ts rename {src => projects/bot/src}/lib/moderation/workers/WorkerHandler.ts (81%) rename {src => projects/bot/src}/lib/moderation/workers/WorkerManager.ts (59%) rename {src => projects/bot/src}/lib/moderation/workers/WorkerResponseHandler.ts (83%) rename {src => projects/bot/src}/lib/moderation/workers/errors/TimeoutError.ts (100%) create mode 100644 projects/bot/src/lib/moderation/workers/errors/index.ts create mode 100644 projects/bot/src/lib/moderation/workers/index.ts rename {src => projects/bot/src}/lib/moderation/workers/types.ts (100%) rename src/lib/moderation/workers/worker.mjs => projects/bot/src/lib/moderation/workers/worker.ts (50%) create mode 100644 projects/bot/src/lib/setup.ts rename {src => projects/bot/src}/lib/structures/InviteStore.ts (80%) create mode 100644 projects/bot/src/lib/structures/commands/SkyraCommand.ts create mode 100644 projects/bot/src/lib/structures/index.ts rename {src => projects/bot/src}/lib/structures/managers/LockdownManager.ts (95%) create mode 100644 projects/bot/src/lib/structures/managers/ScheduleManager.ts create mode 100644 projects/bot/src/lib/structures/managers/index.ts rename {src => projects/bot/src}/lib/util/Links/TLDs.ts (96%) rename {src => projects/bot/src}/lib/util/Links/UrlRegex.ts (97%) create mode 100644 projects/bot/src/lib/util/Parsers/ExceededLength.ts rename {src => projects/bot/src}/lib/util/Parsers/FuzzySearch.ts (93%) rename {src => projects/bot/src}/lib/util/Sanitizer/clean.ts (96%) rename {src => projects/bot/src}/lib/util/Sanitizer/initClean.ts (83%) rename {src => projects/bot/src}/lib/util/Security/GuildSecurity.ts (67%) create mode 100644 projects/bot/src/lib/util/Security/ModerationActions.ts rename {src => projects/bot/src}/lib/util/Security/RegexCreator.ts (90%) create mode 100644 projects/bot/src/lib/util/bits.ts rename {src => projects/bot/src}/lib/util/common/comparators.ts (81%) rename {src => projects/bot/src}/lib/util/common/guards.ts (100%) create mode 100644 projects/bot/src/lib/util/common/index.ts create mode 100644 projects/bot/src/lib/util/common/iterators.ts rename {src => projects/bot/src}/lib/util/common/promises.ts (63%) rename {src => projects/bot/src}/lib/util/common/times.ts (75%) create mode 100644 projects/bot/src/lib/util/constants.ts rename {src => projects/bot/src}/lib/util/formatters.ts (66%) create mode 100644 projects/bot/src/lib/util/functions/booleans.ts rename {src => projects/bot/src}/lib/util/functions/emojis.ts (59%) rename {src => projects/bot/src}/lib/util/functions/guild.ts (66%) create mode 100644 projects/bot/src/lib/util/functions/index.ts rename {src => projects/bot/src}/lib/util/functions/numbers.ts (74%) create mode 100644 projects/bot/src/lib/util/functions/permissions.ts create mode 100644 projects/bot/src/lib/util/moderationConstants.ts create mode 100644 projects/bot/src/lib/util/util.ts rename src/listeners/commands/messageCommandDenied.ts => projects/bot/src/listeners/commands/commandDenied.ts (62%) create mode 100644 projects/bot/src/listeners/commands/commandError.ts rename src/listeners/commands/messageCommandRunAttach.ts => projects/bot/src/listeners/commands/commandRunAttach.ts (58%) create mode 100644 projects/bot/src/listeners/commands/commandSuccessAnalytics.ts create mode 100644 projects/bot/src/listeners/commands/commandSuccessAutoDelete.ts rename src/listeners/commands/messageCommandSuccessLogger.ts => projects/bot/src/listeners/commands/commandSuccessLogger.ts (65%) create mode 100644 projects/bot/src/listeners/commands/unknownCommand.ts rename {src => projects/bot/src}/listeners/errors/error.ts (71%) rename {src => projects/bot/src}/listeners/errors/listenerError.ts (51%) rename {src => projects/bot/src}/listeners/errors/listenerErrorSentry.ts (56%) rename {src => projects/bot/src}/listeners/errors/taskError.ts (72%) rename {src => projects/bot/src}/listeners/errors/taskErrorSentry.ts (59%) create mode 100644 projects/bot/src/listeners/guildMessageLog.ts create mode 100644 projects/bot/src/listeners/guilds/bans/guildBanAdd.ts create mode 100644 projects/bot/src/listeners/guilds/bans/guildBanRemove.ts rename {src => projects/bot/src}/listeners/guilds/channels/channelCreateNotify.ts (62%) create mode 100644 projects/bot/src/listeners/guilds/channels/channelDeleteNotify.ts rename {src => projects/bot/src}/listeners/guilds/channels/channelUpdateNotify.ts (80%) create mode 100644 projects/bot/src/listeners/guilds/emojis/emojiCreateNotify.ts create mode 100644 projects/bot/src/listeners/guilds/emojis/emojiDeleteNotify.ts rename {src => projects/bot/src}/listeners/guilds/emojis/emojiUpdateNotify.ts (60%) rename {src => projects/bot/src}/listeners/guilds/guildUpdateNotify.ts (84%) create mode 100644 projects/bot/src/listeners/guilds/members/guildMemberAdd.ts rename {src => projects/bot/src}/listeners/guilds/members/guildMemberUpdateNicknameNotify.ts (63%) rename {src => projects/bot/src}/listeners/guilds/members/guildMemberUpdateRolesNotify.ts (72%) create mode 100644 projects/bot/src/listeners/guilds/members/notMutedMemberAddInitialRole.ts create mode 100644 projects/bot/src/listeners/guilds/members/notMutedMemberAddNotify.ts rename {src => projects/bot/src}/listeners/guilds/members/rawGuildMemberRemove.ts (57%) rename {src => projects/bot/src}/listeners/guilds/members/rawGuildMemberUpdate.ts (61%) create mode 100644 projects/bot/src/listeners/guilds/members/rawMemberRemoveNotify.ts rename {src => projects/bot/src}/listeners/guilds/messages/guildUserMessageImageNotify.ts (60%) create mode 100644 projects/bot/src/listeners/guilds/messages/guildUserMessagePointsHandler.ts create mode 100644 projects/bot/src/listeners/guilds/messages/guildUserMessageSocialPointsAddMember.ts create mode 100644 projects/bot/src/listeners/guilds/messages/guildUserMessageSocialPointsAddMemberRewardLevel.ts create mode 100644 projects/bot/src/listeners/guilds/messages/guildUserMessageSocialPointsAddMemberRewardRole.ts create mode 100644 projects/bot/src/listeners/guilds/messages/guildUserMessageSocialPointsAddUser.ts create mode 100644 projects/bot/src/listeners/guilds/rawGuildCreateMemberFetch.ts create mode 100644 projects/bot/src/listeners/guilds/rawGuildDelete.ts create mode 100644 projects/bot/src/listeners/guilds/rawGuildDeleteMemberFetch.ts rename {src => projects/bot/src}/listeners/guilds/roles/roleCreateNotify.ts (68%) create mode 100644 projects/bot/src/listeners/guilds/roles/roleDelete.ts create mode 100644 projects/bot/src/listeners/guilds/roles/roleDeleteNotify.ts create mode 100644 projects/bot/src/listeners/guilds/roles/roleUpdate.ts rename {src => projects/bot/src}/listeners/guilds/roles/roleUpdateNotify.ts (62%) create mode 100644 projects/bot/src/listeners/messages/guildMessageDeleteNotify.ts create mode 100644 projects/bot/src/listeners/messages/guildMessageDeleteRichDisplay.ts rename {src => projects/bot/src}/listeners/messages/guildMessageDeleteSnipe.ts (51%) rename {src => projects/bot/src}/listeners/messages/guildUserMessageMediaOnly.ts (63%) rename {src => projects/bot/src}/listeners/messages/messageCreate.ts (92%) rename {src => projects/bot/src}/listeners/messages/messageDelete.ts (89%) rename {src => projects/bot/src}/listeners/messages/messageDeleteBulkRemoveResponses.ts (68%) rename {src => projects/bot/src}/listeners/messages/messageDeleteRemoveResponses.ts (54%) create mode 100644 projects/bot/src/listeners/messages/messageUpdateNotify.ts create mode 100644 projects/bot/src/listeners/messages/rawMessageDelete.ts create mode 100644 projects/bot/src/listeners/messages/rawMessageDeleteBulk.ts rename {src => projects/bot/src}/listeners/messages/userMessageGuildHandler.ts (60%) rename {src => projects/bot/src}/listeners/moderation/messages/guildUserMessageAttachmentsHandler.ts (65%) rename {src => projects/bot/src}/listeners/moderation/messages/guildUserMessageCapitalsHandler.ts (63%) rename {src => projects/bot/src}/listeners/moderation/messages/guildUserMessageInvitesHandler.ts (76%) rename {src => projects/bot/src}/listeners/moderation/messages/guildUserMessageLinksHandler.ts (69%) rename {src => projects/bot/src}/listeners/moderation/messages/guildUserMessageMentionsHandler.ts (56%) rename {src => projects/bot/src}/listeners/moderation/messages/guildUserMessageMessagesHandler.ts (72%) rename {src => projects/bot/src}/listeners/moderation/messages/guildUserMessageNewLinesHandler.ts (65%) rename {src => projects/bot/src}/listeners/moderation/messages/guildUserMessageWordsHandler.ts (65%) create mode 100644 projects/bot/src/listeners/moderation/moderationEntryAdd.ts create mode 100644 projects/bot/src/listeners/moderation/moderationEntryEdit.ts rename {src => projects/bot/src}/listeners/reactions/rawMessageReactionAdd.ts (78%) rename {src => projects/bot/src}/listeners/reactions/rawMessageReactionRemove.ts (58%) create mode 100644 projects/bot/src/listeners/reactions/rawReactionAddBlockList.ts create mode 100644 projects/bot/src/listeners/reactions/rawReactionAddNotify.ts rename {src => projects/bot/src}/listeners/reactions/rawReactionAddRole.ts (59%) rename {src => projects/bot/src}/listeners/reactions/rawReactionRemoveRole.ts (53%) rename {src => projects/bot/src}/listeners/userUpdate.ts (58%) create mode 100644 projects/bot/src/locales/en-US/commands/management.json rename {src/languages => projects/bot/src/locales}/en-US/commands/moderation.json (50%) create mode 100644 projects/bot/src/locales/en-US/commands/system.json create mode 100644 projects/bot/src/locales/en-US/commands/tools.json create mode 100644 projects/bot/src/locales/en-US/errors.json rename {src/languages => projects/bot/src/locales}/en-US/events/errors.json (99%) rename {src/languages => projects/bot/src/locales}/en-US/events/guilds-logs.json (89%) rename {src/languages => projects/bot/src/locales}/en-US/events/guilds-members.json (74%) create mode 100644 projects/bot/src/locales/en-US/events/messages.json rename {src/languages => projects/bot/src/locales}/en-US/events/moderation.json (95%) rename {src/languages => projects/bot/src/locales}/en-US/events/noMentionSpam.json (61%) rename {src/languages => projects/bot/src/locales}/en-US/events/reactions.json (70%) create mode 100644 projects/bot/src/locales/en-US/events/twitch.json rename {src/languages => projects/bot/src/locales}/en-US/fuzzySearch.json (99%) rename {src/languages => projects/bot/src/locales}/en-US/globals.json (67%) create mode 100644 projects/bot/src/locales/en-US/guilds.json create mode 100644 projects/bot/src/locales/en-US/humanLevels.json create mode 100644 projects/bot/src/locales/en-US/moderation.json rename {src/languages => projects/bot/src/locales}/en-US/moderationActions.json (77%) create mode 100644 projects/bot/src/locales/en-US/permissions.json rename {src/languages => projects/bot/src/locales}/en-US/preconditions.json (57%) create mode 100644 projects/bot/src/locales/en-US/promptList.json rename {src/languages => projects/bot/src/locales}/en-US/selfModeration.json (88%) rename {src/languages => projects/bot/src/locales}/en-US/settings.json (79%) rename {src/languages => projects/bot/src/locales}/en-US/system.json (50%) create mode 100644 projects/bot/src/main.ts create mode 100644 projects/bot/src/routes/commands.ts rename src/routes/guilds/[guild]/index.get.ts => projects/bot/src/routes/guilds/guild.ts (68%) rename src/routes/guilds/[guild]/channels.get.ts => projects/bot/src/routes/guilds/guild/channels.ts (70%) rename src/routes/guilds/[guild]/channels/[channel].get.ts => projects/bot/src/routes/guilds/guild/channels/channel.ts (73%) rename src/routes/guilds/[guild]/members/[member].get.ts => projects/bot/src/routes/guilds/guild/members/member.ts (74%) rename src/routes/guilds/[guild]/roles.get.ts => projects/bot/src/routes/guilds/guild/roles.ts (70%) rename src/routes/guilds/[guild]/roles/[role].get.ts => projects/bot/src/routes/guilds/guild/roles/role.ts (73%) rename src/routes/guilds/[guild]/settings.patch.ts => projects/bot/src/routes/guilds/guild/settings.ts (50%) create mode 100644 projects/bot/src/routes/languages.ts create mode 100644 projects/bot/src/routes/main.ts rename src/routes/oauth/user.post.ts => projects/bot/src/routes/oauth/oauthUser.ts (78%) rename src/routes/users/@me.get.ts => projects/bot/src/routes/users/user.ts (62%) create mode 100644 projects/bot/src/routes/users/user/settings.ts create mode 100644 projects/bot/src/tasks/moderation/moderationEndAddRole.ts create mode 100644 projects/bot/src/tasks/moderation/moderationEndBan.ts create mode 100644 projects/bot/src/tasks/moderation/moderationEndMute.ts create mode 100644 projects/bot/src/tasks/moderation/moderationEndRemoveRole.ts create mode 100644 projects/bot/src/tasks/moderation/moderationEndSetNickname.ts create mode 100644 projects/bot/src/tasks/moderation/moderationEndVoiceMute.ts create mode 100644 projects/bot/src/tasks/moderation/moderationEndWarning.ts rename {src => projects/bot/src}/tasks/poststats.ts (74%) create mode 100644 projects/bot/src/tasks/reminder.ts create mode 100644 projects/bot/src/tsconfig.json rename {tests => projects/bot/tests}/lib/CommandMatcher.test.ts (100%) rename {tests => projects/bot/tests}/lib/RegexCreator.test.ts (100%) rename {tests => projects/bot/tests}/lib/bits.test.ts (100%) rename {tests => projects/bot/tests}/lib/database/settings/functions.test.ts (100%) rename {tests => projects/bot/tests}/lib/database/settings/structures/AuditLogEnvelope.test.ts (100%) rename {tests => projects/bot/tests}/lib/database/settings/structures/AuditLogManager.test.ts (100%) rename {tests => projects/bot/tests}/lib/database/settings/structures/PermissionNodeManager.test.ts (100%) rename {tests => projects/bot/tests}/lib/formatters.test.ts (100%) rename {tests => projects/bot/tests}/lib/i18n/LanguageHelp.test.ts (100%) rename {tests => projects/bot/tests}/lib/i18n/translate.test.ts (100%) rename {tests => projects/bot/tests}/lib/listeners/commands/commandLogShared.test.ts (100%) rename {tests => projects/bot/tests}/lib/moderation/workers/WorkerHandler.test.ts (100%) rename {tests => projects/bot/tests}/lib/moderation/workers/WorkerManager.test.ts (100%) rename {tests => projects/bot/tests}/lib/moderation/workers/WorkerResponseHandler.test.ts (100%) rename {tests => projects/bot/tests}/lib/util.test.ts (100%) rename {tests => projects/bot/tests}/lib/util/common/comparators.test.ts (100%) rename {tests => projects/bot/tests}/lib/util/common/times.test.ts (100%) create mode 100644 projects/bot/tests/lib/util/constants.test.ts rename {tests => projects/bot/tests}/lib/util/formatters.test.ts (100%) rename {tests => projects/bot/tests}/lib/util/functions/auditLogEmbeds.test.ts (100%) create mode 100644 projects/bot/tests/lib/util/functions/emojis/areEmojisEqual.test.ts rename {tests => projects/bot/tests}/lib/util/functions/emojis/getEmojiId.test.ts (100%) rename {tests => projects/bot/tests}/lib/util/functions/emojis/getEmojiObject.test.ts (100%) rename {tests => projects/bot/tests}/lib/util/functions/emojis/getEmojiReactionFormat.test.ts (100%) rename {tests => projects/bot/tests}/lib/util/functions/emojis/getEmojiString.test.ts (100%) rename {tests => projects/bot/tests}/lib/util/functions/emojis/getEmojiTextFormat.test.ts (100%) rename {tests => projects/bot/tests}/lib/util/functions/emojis/getEncodedTwemoji.test.ts (100%) rename {tests => projects/bot/tests}/lib/util/functions/emojis/getTwemojiUrl.test.ts (100%) rename {tests => projects/bot/tests}/lib/util/functions/emojis/isSerializedTwemoji.test.ts (100%) rename {tests => projects/bot/tests}/lib/util/functions/emojis/isValidCustomEmoji.test.ts (100%) rename {tests => projects/bot/tests}/lib/util/functions/emojis/isValidSerializedCustomEmoji.test.ts (100%) rename {tests => projects/bot/tests}/lib/util/functions/emojis/isValidSerializedEmoji.test.ts (100%) rename {tests => projects/bot/tests}/lib/util/functions/emojis/isValidSerializedTwemoji.test.ts (100%) rename {tests => projects/bot/tests}/lib/util/functions/emojis/isValidTwemoji.test.ts (100%) rename {tests => projects/bot/tests}/lib/util/functions/emojis/resolveEmojiId.test.ts (100%) create mode 100644 projects/bot/tests/lib/util/sanitizeInput.test.ts rename {tests => projects/bot/tests}/mocks/MockInstances.ts (100%) rename {tests => projects/bot/tests}/mocks/constants.ts (100%) rename {tests => projects/bot/tests}/mocks/image.png (100%) rename {tests => projects/bot/tests}/scripts/migrate-audit-log-to-audit-event.test.ts (100%) create mode 100644 projects/bot/tests/tsconfig.json rename {tests => projects/bot/tests}/vitest.setup.ts (83%) create mode 100644 projects/bot/tsconfig.eslint.json create mode 100644 projects/bot/tsdown.config.ts create mode 100644 projects/docker/README.md create mode 100644 projects/docker/control.ps1 create mode 100644 projects/docker/docker-compose.yml create mode 100644 projects/gateway/Dockerfile create mode 100644 projects/gateway/package.json create mode 100644 projects/gateway/scripts/clean.mjs create mode 100644 projects/gateway/src/.env create mode 100644 projects/gateway/src/.env.development create mode 100644 projects/gateway/src/lib/Client.ts create mode 100644 projects/gateway/src/lib/actions/All.ts create mode 100644 projects/gateway/src/lib/actions/ChannelCreate.ts create mode 100644 projects/gateway/src/lib/actions/ChannelDelete.ts create mode 100644 projects/gateway/src/lib/actions/ChannelUpdate.ts create mode 100644 projects/gateway/src/lib/actions/GuildBanAdd.ts create mode 100644 projects/gateway/src/lib/actions/GuildBanRemove.ts create mode 100644 projects/gateway/src/lib/actions/GuildCreate.ts create mode 100644 projects/gateway/src/lib/actions/GuildDelete.ts create mode 100644 projects/gateway/src/lib/actions/GuildEmojisUpdate.ts create mode 100644 projects/gateway/src/lib/actions/GuildMemberAdd.ts create mode 100644 projects/gateway/src/lib/actions/GuildMemberRemove.ts create mode 100644 projects/gateway/src/lib/actions/GuildMemberUpdate.ts create mode 100644 projects/gateway/src/lib/actions/GuildMembersChunk.ts create mode 100644 projects/gateway/src/lib/actions/GuildRoleCreate.ts create mode 100644 projects/gateway/src/lib/actions/GuildRoleDelete.ts create mode 100644 projects/gateway/src/lib/actions/GuildRoleUpdate.ts create mode 100644 projects/gateway/src/lib/actions/GuildStickersUpdate.ts create mode 100644 projects/gateway/src/lib/actions/GuildUpdate.ts create mode 100644 projects/gateway/src/lib/actions/MessageCreate.ts create mode 100644 projects/gateway/src/lib/actions/MessageDelete.ts create mode 100644 projects/gateway/src/lib/actions/MessageDeleteBulk.ts create mode 100644 projects/gateway/src/lib/actions/MessageReactionAdd.ts create mode 100644 projects/gateway/src/lib/actions/MessageReactionRemove.ts create mode 100644 projects/gateway/src/lib/actions/MessageReactionRemoveAll.ts create mode 100644 projects/gateway/src/lib/actions/MessageReactionRemoveEmoji.ts create mode 100644 projects/gateway/src/lib/actions/MessageUpdate.ts create mode 100644 projects/gateway/src/lib/augments.d.ts create mode 100644 projects/gateway/src/lib/structures/ws-listener.ts create mode 100644 projects/gateway/src/listeners/ws/dispatch.mts create mode 100644 projects/gateway/src/listeners/ws/error.mts create mode 100644 projects/gateway/src/listeners/ws/ready.mts create mode 100644 projects/gateway/src/listeners/ws/resumed.mts create mode 100644 projects/gateway/src/main.ts create mode 100644 projects/gateway/src/tsconfig.json create mode 100644 projects/gateway/tests/.gitkeep create mode 100644 projects/gateway/tsconfig.eslint.json create mode 100644 projects/shared/package.json create mode 100644 projects/shared/scripts/clean.mjs create mode 100644 projects/shared/src/index.ts create mode 100644 projects/shared/src/lib/cache/Cache.ts create mode 100644 projects/shared/src/lib/cache/CacheChannels.ts create mode 100644 projects/shared/src/lib/cache/CacheEmojis.ts create mode 100644 projects/shared/src/lib/cache/CacheGuilds.ts create mode 100644 projects/shared/src/lib/cache/CacheMembers.ts create mode 100644 projects/shared/src/lib/cache/CacheMessages.ts create mode 100644 projects/shared/src/lib/cache/CacheRoles.ts create mode 100644 projects/shared/src/lib/cache/CacheStickers.ts create mode 100644 projects/shared/src/lib/cache/base/HashScopedCache.ts create mode 100644 projects/shared/src/lib/cache/base/ScopedCache.ts create mode 100644 projects/shared/src/lib/cache/structures/Channel.ts create mode 100644 projects/shared/src/lib/cache/structures/Emoji.ts create mode 100644 projects/shared/src/lib/cache/structures/Guild.ts create mode 100644 projects/shared/src/lib/cache/structures/Member.ts create mode 100644 projects/shared/src/lib/cache/structures/Message.ts create mode 100644 projects/shared/src/lib/cache/structures/Role.ts create mode 100644 projects/shared/src/lib/cache/structures/Sticker.ts create mode 100644 projects/shared/src/lib/cache/structures/interfaces/BufferEncodable.ts create mode 100644 projects/shared/src/lib/cache/structures/interfaces/IStructure.ts create mode 100644 projects/shared/src/lib/cache/structures/interfaces/Identifiable.ts create mode 100644 projects/shared/src/lib/cache/structures/interfaces/JsonEncodable.ts create mode 100644 projects/shared/src/lib/cache/structures/unions/channel/GuildCategoryChannel.ts create mode 100644 projects/shared/src/lib/cache/structures/unions/channel/GuildForumChannel.ts create mode 100644 projects/shared/src/lib/cache/structures/unions/channel/GuildNewsChannel.ts create mode 100644 projects/shared/src/lib/cache/structures/unions/channel/GuildTextChannel.ts create mode 100644 projects/shared/src/lib/cache/structures/unions/channel/GuildThreadChannel.ts create mode 100644 projects/shared/src/lib/cache/structures/unions/channel/GuildVoiceChannel.ts create mode 100644 projects/shared/src/lib/cache/structures/unions/channel/base/GuildBasedChannel.ts create mode 100644 projects/shared/src/lib/cache/structures/unions/channel/base/GuildTextBasedChannel.ts create mode 100644 projects/shared/src/lib/cache/structures/values/GuildFeatures.ts create mode 100644 projects/shared/src/lib/common/bits.ts create mode 100644 projects/shared/src/lib/common/util.ts create mode 100644 projects/shared/src/lib/data/Reader.ts create mode 100644 projects/shared/src/lib/data/Writer.ts create mode 100644 projects/shared/src/lib/messaging/MessageBroker.ts create mode 100644 projects/shared/src/lib/messaging/RedisMessage.ts create mode 100644 projects/shared/src/lib/structures/Listener.ts create mode 100644 projects/shared/src/lib/structures/ListenerStore.ts create mode 100644 projects/shared/src/tsconfig.json create mode 100644 projects/shared/tests/.gitkeep create mode 100644 projects/shared/tsconfig.eslint.json delete mode 100644 scripts/SetFakeRoles.sql delete mode 100644 scripts/SetMigrations.sql delete mode 100644 scripts/dependencycache.ps1 delete mode 100644 scripts/migrate-audit-log-to-audit-event.mjs delete mode 100644 scripts/migrations.mjs delete mode 100644 src/.env delete mode 100644 src/.env.development delete mode 100644 src/arguments/boolean.ts delete mode 100644 src/arguments/case.ts delete mode 100644 src/arguments/channelName.ts delete mode 100644 src/arguments/command.ts delete mode 100644 src/arguments/commandMatch.ts delete mode 100644 src/arguments/commandName.ts delete mode 100644 src/arguments/duration.ts delete mode 100644 src/arguments/emoji.ts delete mode 100644 src/arguments/invite.ts delete mode 100644 src/arguments/language.ts delete mode 100644 src/arguments/range.ts delete mode 100644 src/arguments/reset.ts delete mode 100644 src/arguments/roleName.ts delete mode 100644 src/arguments/snowflake.ts delete mode 100644 src/arguments/textChannelName.ts delete mode 100644 src/arguments/textOrNewsChannelName.ts delete mode 100644 src/arguments/time.ts delete mode 100644 src/arguments/timespan.ts delete mode 100644 src/arguments/userName.ts delete mode 100644 src/commands/Admin/conf.ts delete mode 100644 src/commands/Admin/roleset.ts delete mode 100644 src/commands/Fun/escaperope.ts delete mode 100644 src/commands/Games/c4.ts delete mode 100644 src/commands/Games/hungergames.ts delete mode 100644 src/commands/Games/tictactoe.ts delete mode 100644 src/commands/Games/trivia.ts delete mode 100644 src/commands/General/help.ts delete mode 100644 src/commands/General/info-deprecations.ts delete mode 100644 src/commands/General/info.ts delete mode 100644 src/commands/General/v7-artiel.ts delete mode 100644 src/commands/General/v7-skyra.ts delete mode 100644 src/commands/General/v7-teryl.ts delete mode 100644 src/commands/Management/AutoModeration/automod-attachments.ts delete mode 100644 src/commands/Management/AutoModeration/automod-capitals.ts delete mode 100644 src/commands/Management/AutoModeration/automod-invites.ts delete mode 100644 src/commands/Management/AutoModeration/automod-links.ts delete mode 100644 src/commands/Management/AutoModeration/automod-newlines.ts delete mode 100644 src/commands/Management/AutoModeration/automod-reactions.ts delete mode 100644 src/commands/Management/AutoModeration/automod-spam.ts delete mode 100644 src/commands/Management/AutoModeration/automod-words.ts delete mode 100644 src/commands/Management/Configuration/manage-command-auto-delete.ts delete mode 100644 src/commands/Management/Configuration/manage-command-channel.ts delete mode 100644 src/commands/Management/Configuration/manage-reaction-roles.ts delete mode 100644 src/commands/Management/Configuration/setIgnoreChannels.ts delete mode 100644 src/commands/Management/Configuration/setImageLogs.ts delete mode 100644 src/commands/Management/Configuration/setMemberAddLogs.ts delete mode 100644 src/commands/Management/Configuration/setMemberRemoveLogs.ts delete mode 100644 src/commands/Management/Configuration/setMessageDeleteLogs.ts delete mode 100644 src/commands/Management/Configuration/setMessageUpdateLogs.ts delete mode 100644 src/commands/Management/Configuration/setModLogs.ts delete mode 100644 src/commands/Management/Configuration/setPrefix.ts delete mode 100644 src/commands/Management/create-mute.ts delete mode 100644 src/commands/Management/permissionNodes.ts delete mode 100644 src/commands/Management/roles.ts delete mode 100644 src/commands/Misc/snipe.ts delete mode 100644 src/commands/Moderation/Restriction/restrictAttachment.ts delete mode 100644 src/commands/Moderation/Restriction/restrictEmbed.ts delete mode 100644 src/commands/Moderation/Restriction/restrictEmoji.ts delete mode 100644 src/commands/Moderation/Restriction/restrictReaction.ts delete mode 100644 src/commands/Moderation/Restriction/restrictVoice.ts delete mode 100644 src/commands/Moderation/Restriction/unrestrictAttachment.ts delete mode 100644 src/commands/Moderation/Restriction/unrestrictEmbed.ts delete mode 100644 src/commands/Moderation/Restriction/unrestrictEmoji.ts delete mode 100644 src/commands/Moderation/Restriction/unrestrictReaction.ts delete mode 100644 src/commands/Moderation/Restriction/unrestrictVoice.ts delete mode 100644 src/commands/Moderation/Utilities/case-deprecations.ts delete mode 100644 src/commands/Moderation/Utilities/case.ts delete mode 100644 src/commands/Moderation/Utilities/permissions.ts delete mode 100644 src/commands/Moderation/addrole.ts delete mode 100644 src/commands/Moderation/ban.ts delete mode 100644 src/commands/Moderation/kick.ts delete mode 100644 src/commands/Moderation/mute.ts delete mode 100644 src/commands/Moderation/prune.ts delete mode 100644 src/commands/Moderation/removerole.ts delete mode 100644 src/commands/Moderation/setnickname.ts delete mode 100644 src/commands/Moderation/softban.ts delete mode 100644 src/commands/Moderation/timeout.ts delete mode 100644 src/commands/Moderation/unban.ts delete mode 100644 src/commands/Moderation/unmute.ts delete mode 100644 src/commands/Moderation/untimeout.ts delete mode 100644 src/commands/Moderation/vmute.ts delete mode 100644 src/commands/Moderation/voicekick.ts delete mode 100644 src/commands/Moderation/vunmute.ts delete mode 100644 src/commands/Moderation/warn.ts delete mode 100644 src/commands/System/Admin/eval.ts delete mode 100644 src/commands/System/Admin/reboot.ts delete mode 100644 src/commands/Tools/avatar.ts delete mode 100644 src/commands/Tools/vote.ts delete mode 100644 src/commands/Tools/whois.ts delete mode 100644 src/commands/Twitch/twitchsubscription.ts delete mode 100644 src/config.ts delete mode 100644 src/index.ts delete mode 100644 src/languages/bg/arguments.json delete mode 100644 src/languages/bg/assertions.json delete mode 100644 src/languages/bg/commands/admin.json delete mode 100644 src/languages/bg/commands/animal.json delete mode 100644 src/languages/bg/commands/auto-moderation.json delete mode 100644 src/languages/bg/commands/case.json delete mode 100644 src/languages/bg/commands/fun.json delete mode 100644 src/languages/bg/commands/game.json delete mode 100644 src/languages/bg/commands/general.json delete mode 100644 src/languages/bg/commands/info.json delete mode 100644 src/languages/bg/commands/management.json delete mode 100644 src/languages/bg/commands/misc.json delete mode 100644 src/languages/bg/commands/moderation.json delete mode 100644 src/languages/bg/commands/shared.json delete mode 100644 src/languages/bg/commands/system.json delete mode 100644 src/languages/bg/commands/tools.json delete mode 100644 src/languages/bg/commands/twitch.json delete mode 100644 src/languages/bg/commands/whois.json delete mode 100644 src/languages/bg/errors.json delete mode 100644 src/languages/bg/events/errors.json delete mode 100644 src/languages/bg/events/guilds-logs.json delete mode 100644 src/languages/bg/events/guilds-members.json delete mode 100644 src/languages/bg/events/messages.json delete mode 100644 src/languages/bg/events/moderation.json delete mode 100644 src/languages/bg/events/noMentionSpam.json delete mode 100644 src/languages/bg/events/reactions.json delete mode 100644 src/languages/bg/events/twitch.json delete mode 100644 src/languages/bg/fuzzySearch.json delete mode 100644 src/languages/bg/globals.json delete mode 100644 src/languages/bg/guilds.json delete mode 100644 src/languages/bg/humanLevels.json delete mode 100644 src/languages/bg/moderation.json delete mode 100644 src/languages/bg/moderationActions.json delete mode 100644 src/languages/bg/permissions.json delete mode 100644 src/languages/bg/preconditions.json delete mode 100644 src/languages/bg/selfModeration.json delete mode 100644 src/languages/bg/serializers.json delete mode 100644 src/languages/bg/settings.json delete mode 100644 src/languages/bg/system.json delete mode 100644 src/languages/cs/arguments.json delete mode 100644 src/languages/cs/assertions.json delete mode 100644 src/languages/cs/commands/admin.json delete mode 100644 src/languages/cs/commands/animal.json delete mode 100644 src/languages/cs/commands/auto-moderation.json delete mode 100644 src/languages/cs/commands/case.json delete mode 100644 src/languages/cs/commands/fun.json delete mode 100644 src/languages/cs/commands/game.json delete mode 100644 src/languages/cs/commands/general.json delete mode 100644 src/languages/cs/commands/info.json delete mode 100644 src/languages/cs/commands/management.json delete mode 100644 src/languages/cs/commands/misc.json delete mode 100644 src/languages/cs/commands/moderation.json delete mode 100644 src/languages/cs/commands/shared.json delete mode 100644 src/languages/cs/commands/system.json delete mode 100644 src/languages/cs/commands/tools.json delete mode 100644 src/languages/cs/commands/twitch.json delete mode 100644 src/languages/cs/commands/whois.json delete mode 100644 src/languages/cs/errors.json delete mode 100644 src/languages/cs/events/errors.json delete mode 100644 src/languages/cs/events/guilds-logs.json delete mode 100644 src/languages/cs/events/guilds-members.json delete mode 100644 src/languages/cs/events/messages.json delete mode 100644 src/languages/cs/events/moderation.json delete mode 100644 src/languages/cs/events/noMentionSpam.json delete mode 100644 src/languages/cs/events/reactions.json delete mode 100644 src/languages/cs/events/twitch.json delete mode 100644 src/languages/cs/fuzzySearch.json delete mode 100644 src/languages/cs/globals.json delete mode 100644 src/languages/cs/guilds.json delete mode 100644 src/languages/cs/humanLevels.json delete mode 100644 src/languages/cs/moderation.json delete mode 100644 src/languages/cs/moderationActions.json delete mode 100644 src/languages/cs/permissions.json delete mode 100644 src/languages/cs/preconditions.json delete mode 100644 src/languages/cs/selfModeration.json delete mode 100644 src/languages/cs/serializers.json delete mode 100644 src/languages/cs/settings.json delete mode 100644 src/languages/cs/system.json delete mode 100644 src/languages/da/arguments.json delete mode 100644 src/languages/da/assertions.json delete mode 100644 src/languages/da/commands/admin.json delete mode 100644 src/languages/da/commands/animal.json delete mode 100644 src/languages/da/commands/auto-moderation.json delete mode 100644 src/languages/da/commands/case.json delete mode 100644 src/languages/da/commands/fun.json delete mode 100644 src/languages/da/commands/game.json delete mode 100644 src/languages/da/commands/general.json delete mode 100644 src/languages/da/commands/info.json delete mode 100644 src/languages/da/commands/management.json delete mode 100644 src/languages/da/commands/misc.json delete mode 100644 src/languages/da/commands/moderation.json delete mode 100644 src/languages/da/commands/shared.json delete mode 100644 src/languages/da/commands/system.json delete mode 100644 src/languages/da/commands/tools.json delete mode 100644 src/languages/da/commands/twitch.json delete mode 100644 src/languages/da/commands/whois.json delete mode 100644 src/languages/da/errors.json delete mode 100644 src/languages/da/events/errors.json delete mode 100644 src/languages/da/events/guilds-logs.json delete mode 100644 src/languages/da/events/guilds-members.json delete mode 100644 src/languages/da/events/messages.json delete mode 100644 src/languages/da/events/moderation.json delete mode 100644 src/languages/da/events/noMentionSpam.json delete mode 100644 src/languages/da/events/reactions.json delete mode 100644 src/languages/da/events/twitch.json delete mode 100644 src/languages/da/fuzzySearch.json delete mode 100644 src/languages/da/globals.json delete mode 100644 src/languages/da/guilds.json delete mode 100644 src/languages/da/humanLevels.json delete mode 100644 src/languages/da/moderation.json delete mode 100644 src/languages/da/moderationActions.json delete mode 100644 src/languages/da/permissions.json delete mode 100644 src/languages/da/preconditions.json delete mode 100644 src/languages/da/selfModeration.json delete mode 100644 src/languages/da/serializers.json delete mode 100644 src/languages/da/settings.json delete mode 100644 src/languages/da/system.json delete mode 100644 src/languages/de/arguments.json delete mode 100644 src/languages/de/assertions.json delete mode 100644 src/languages/de/commands/admin.json delete mode 100644 src/languages/de/commands/animal.json delete mode 100644 src/languages/de/commands/auto-moderation.json delete mode 100644 src/languages/de/commands/case.json delete mode 100644 src/languages/de/commands/fun.json delete mode 100644 src/languages/de/commands/game.json delete mode 100644 src/languages/de/commands/general.json delete mode 100644 src/languages/de/commands/info.json delete mode 100644 src/languages/de/commands/management.json delete mode 100644 src/languages/de/commands/misc.json delete mode 100644 src/languages/de/commands/moderation.json delete mode 100644 src/languages/de/commands/shared.json delete mode 100644 src/languages/de/commands/system.json delete mode 100644 src/languages/de/commands/tools.json delete mode 100644 src/languages/de/commands/twitch.json delete mode 100644 src/languages/de/commands/whois.json delete mode 100644 src/languages/de/constants.ts delete mode 100644 src/languages/de/errors.json delete mode 100644 src/languages/de/events/errors.json delete mode 100644 src/languages/de/events/guilds-logs.json delete mode 100644 src/languages/de/events/guilds-members.json delete mode 100644 src/languages/de/events/messages.json delete mode 100644 src/languages/de/events/moderation.json delete mode 100644 src/languages/de/events/noMentionSpam.json delete mode 100644 src/languages/de/events/reactions.json delete mode 100644 src/languages/de/events/twitch.json delete mode 100644 src/languages/de/fuzzySearch.json delete mode 100644 src/languages/de/globals.json delete mode 100644 src/languages/de/guilds.json delete mode 100644 src/languages/de/humanLevels.json delete mode 100644 src/languages/de/moderation.json delete mode 100644 src/languages/de/moderationActions.json delete mode 100644 src/languages/de/permissions.json delete mode 100644 src/languages/de/preconditions.json delete mode 100644 src/languages/de/selfModeration.json delete mode 100644 src/languages/de/serializers.json delete mode 100644 src/languages/de/settings.json delete mode 100644 src/languages/de/system.json delete mode 100644 src/languages/el/arguments.json delete mode 100644 src/languages/el/assertions.json delete mode 100644 src/languages/el/commands/admin.json delete mode 100644 src/languages/el/commands/animal.json delete mode 100644 src/languages/el/commands/auto-moderation.json delete mode 100644 src/languages/el/commands/case.json delete mode 100644 src/languages/el/commands/fun.json delete mode 100644 src/languages/el/commands/game.json delete mode 100644 src/languages/el/commands/general.json delete mode 100644 src/languages/el/commands/info.json delete mode 100644 src/languages/el/commands/management.json delete mode 100644 src/languages/el/commands/misc.json delete mode 100644 src/languages/el/commands/moderation.json delete mode 100644 src/languages/el/commands/shared.json delete mode 100644 src/languages/el/commands/system.json delete mode 100644 src/languages/el/commands/tools.json delete mode 100644 src/languages/el/commands/twitch.json delete mode 100644 src/languages/el/commands/whois.json delete mode 100644 src/languages/el/errors.json delete mode 100644 src/languages/el/events/errors.json delete mode 100644 src/languages/el/events/guilds-logs.json delete mode 100644 src/languages/el/events/guilds-members.json delete mode 100644 src/languages/el/events/messages.json delete mode 100644 src/languages/el/events/moderation.json delete mode 100644 src/languages/el/events/noMentionSpam.json delete mode 100644 src/languages/el/events/reactions.json delete mode 100644 src/languages/el/events/twitch.json delete mode 100644 src/languages/el/fuzzySearch.json delete mode 100644 src/languages/el/globals.json delete mode 100644 src/languages/el/guilds.json delete mode 100644 src/languages/el/humanLevels.json delete mode 100644 src/languages/el/moderation.json delete mode 100644 src/languages/el/moderationActions.json delete mode 100644 src/languages/el/permissions.json delete mode 100644 src/languages/el/preconditions.json delete mode 100644 src/languages/el/selfModeration.json delete mode 100644 src/languages/el/serializers.json delete mode 100644 src/languages/el/settings.json delete mode 100644 src/languages/el/system.json delete mode 100644 src/languages/en-GB/arguments.json delete mode 100644 src/languages/en-GB/assertions.json delete mode 100644 src/languages/en-GB/commands/admin.json delete mode 100644 src/languages/en-GB/commands/animal.json delete mode 100644 src/languages/en-GB/commands/auto-moderation.json delete mode 100644 src/languages/en-GB/commands/case.json delete mode 100644 src/languages/en-GB/commands/fun.json delete mode 100644 src/languages/en-GB/commands/game.json delete mode 100644 src/languages/en-GB/commands/general.json delete mode 100644 src/languages/en-GB/commands/info.json delete mode 100644 src/languages/en-GB/commands/management.json delete mode 100644 src/languages/en-GB/commands/misc.json delete mode 100644 src/languages/en-GB/commands/moderation.json delete mode 100644 src/languages/en-GB/commands/shared.json delete mode 100644 src/languages/en-GB/commands/system.json delete mode 100644 src/languages/en-GB/commands/tools.json delete mode 100644 src/languages/en-GB/commands/twitch.json delete mode 100644 src/languages/en-GB/commands/whois.json delete mode 100644 src/languages/en-GB/constants.ts delete mode 100644 src/languages/en-GB/errors.json delete mode 100644 src/languages/en-GB/events/errors.json delete mode 100644 src/languages/en-GB/events/guilds-logs.json delete mode 100644 src/languages/en-GB/events/guilds-members.json delete mode 100644 src/languages/en-GB/events/messages.json delete mode 100644 src/languages/en-GB/events/moderation.json delete mode 100644 src/languages/en-GB/events/noMentionSpam.json delete mode 100644 src/languages/en-GB/events/reactions.json delete mode 100644 src/languages/en-GB/events/twitch.json delete mode 100644 src/languages/en-GB/fuzzySearch.json delete mode 100644 src/languages/en-GB/globals.json delete mode 100644 src/languages/en-GB/guilds.json delete mode 100644 src/languages/en-GB/humanLevels.json delete mode 100644 src/languages/en-GB/moderation.json delete mode 100644 src/languages/en-GB/moderationActions.json delete mode 100644 src/languages/en-GB/permissions.json delete mode 100644 src/languages/en-GB/preconditions.json delete mode 100644 src/languages/en-GB/selfModeration.json delete mode 100644 src/languages/en-GB/serializers.json delete mode 100644 src/languages/en-GB/settings.json delete mode 100644 src/languages/en-GB/system.json delete mode 100644 src/languages/en-US/arguments.json delete mode 100644 src/languages/en-US/assertions.json delete mode 100644 src/languages/en-US/colors.json delete mode 100644 src/languages/en-US/commands/admin.json delete mode 100644 src/languages/en-US/commands/auto-moderation.json delete mode 100644 src/languages/en-US/commands/case.json delete mode 100644 src/languages/en-US/commands/conf.json delete mode 100644 src/languages/en-US/commands/fun.json delete mode 100644 src/languages/en-US/commands/game.json delete mode 100644 src/languages/en-US/commands/general.json delete mode 100644 src/languages/en-US/commands/info.json delete mode 100644 src/languages/en-US/commands/management.json delete mode 100644 src/languages/en-US/commands/permissions.json delete mode 100644 src/languages/en-US/commands/shared.json delete mode 100644 src/languages/en-US/commands/snipe.json delete mode 100644 src/languages/en-US/commands/system.json delete mode 100644 src/languages/en-US/commands/tools.json delete mode 100644 src/languages/en-US/commands/whois.json delete mode 100644 src/languages/en-US/constants.ts delete mode 100644 src/languages/en-US/errors.json delete mode 100644 src/languages/en-US/events/messages.json delete mode 100644 src/languages/en-US/guilds.json delete mode 100644 src/languages/en-US/humanLevels.json delete mode 100644 src/languages/en-US/moderation.json delete mode 100644 src/languages/en-US/permissions.json delete mode 100644 src/languages/en-US/serializers.json delete mode 100644 src/languages/es-419/arguments.json delete mode 100644 src/languages/es-419/assertions.json delete mode 100644 src/languages/es-419/commands/admin.json delete mode 100644 src/languages/es-419/commands/animal.json delete mode 100644 src/languages/es-419/commands/auto-moderation.json delete mode 100644 src/languages/es-419/commands/case.json delete mode 100644 src/languages/es-419/commands/fun.json delete mode 100644 src/languages/es-419/commands/game.json delete mode 100644 src/languages/es-419/commands/general.json delete mode 100644 src/languages/es-419/commands/info.json delete mode 100644 src/languages/es-419/commands/management.json delete mode 100644 src/languages/es-419/commands/misc.json delete mode 100644 src/languages/es-419/commands/moderation.json delete mode 100644 src/languages/es-419/commands/shared.json delete mode 100644 src/languages/es-419/commands/system.json delete mode 100644 src/languages/es-419/commands/tools.json delete mode 100644 src/languages/es-419/commands/twitch.json delete mode 100644 src/languages/es-419/commands/whois.json delete mode 100644 src/languages/es-419/constants.ts delete mode 100644 src/languages/es-419/errors.json delete mode 100644 src/languages/es-419/events/errors.json delete mode 100644 src/languages/es-419/events/guilds-logs.json delete mode 100644 src/languages/es-419/events/guilds-members.json delete mode 100644 src/languages/es-419/events/messages.json delete mode 100644 src/languages/es-419/events/moderation.json delete mode 100644 src/languages/es-419/events/noMentionSpam.json delete mode 100644 src/languages/es-419/events/reactions.json delete mode 100644 src/languages/es-419/fuzzySearch.json delete mode 100644 src/languages/es-419/globals.json delete mode 100644 src/languages/es-419/guilds.json delete mode 100644 src/languages/es-419/humanLevels.json delete mode 100644 src/languages/es-419/moderation.json delete mode 100644 src/languages/es-419/moderationActions.json delete mode 100644 src/languages/es-419/permissions.json delete mode 100644 src/languages/es-419/preconditions.json delete mode 100644 src/languages/es-419/selfModeration.json delete mode 100644 src/languages/es-419/serializers.json delete mode 100644 src/languages/es-419/settings.json delete mode 100644 src/languages/es-419/system.json delete mode 100644 src/languages/es-ES/arguments.json delete mode 100644 src/languages/es-ES/assertions.json delete mode 100644 src/languages/es-ES/commands/admin.json delete mode 100644 src/languages/es-ES/commands/animal.json delete mode 100644 src/languages/es-ES/commands/auto-moderation.json delete mode 100644 src/languages/es-ES/commands/case.json delete mode 100644 src/languages/es-ES/commands/fun.json delete mode 100644 src/languages/es-ES/commands/game.json delete mode 100644 src/languages/es-ES/commands/general.json delete mode 100644 src/languages/es-ES/commands/info.json delete mode 100644 src/languages/es-ES/commands/management.json delete mode 100644 src/languages/es-ES/commands/misc.json delete mode 100644 src/languages/es-ES/commands/moderation.json delete mode 100644 src/languages/es-ES/commands/shared.json delete mode 100644 src/languages/es-ES/commands/system.json delete mode 100644 src/languages/es-ES/commands/tools.json delete mode 100644 src/languages/es-ES/commands/twitch.json delete mode 100644 src/languages/es-ES/commands/whois.json delete mode 100644 src/languages/es-ES/constants.ts delete mode 100644 src/languages/es-ES/errors.json delete mode 100644 src/languages/es-ES/events/errors.json delete mode 100644 src/languages/es-ES/events/guilds-logs.json delete mode 100644 src/languages/es-ES/events/guilds-members.json delete mode 100644 src/languages/es-ES/events/messages.json delete mode 100644 src/languages/es-ES/events/moderation.json delete mode 100644 src/languages/es-ES/events/noMentionSpam.json delete mode 100644 src/languages/es-ES/events/reactions.json delete mode 100644 src/languages/es-ES/fuzzySearch.json delete mode 100644 src/languages/es-ES/globals.json delete mode 100644 src/languages/es-ES/guilds.json delete mode 100644 src/languages/es-ES/humanLevels.json delete mode 100644 src/languages/es-ES/moderation.json delete mode 100644 src/languages/es-ES/moderationActions.json delete mode 100644 src/languages/es-ES/permissions.json delete mode 100644 src/languages/es-ES/preconditions.json delete mode 100644 src/languages/es-ES/selfModeration.json delete mode 100644 src/languages/es-ES/serializers.json delete mode 100644 src/languages/es-ES/settings.json delete mode 100644 src/languages/es-ES/system.json delete mode 100644 src/languages/fi/arguments.json delete mode 100644 src/languages/fi/assertions.json delete mode 100644 src/languages/fi/commands/admin.json delete mode 100644 src/languages/fi/commands/animal.json delete mode 100644 src/languages/fi/commands/auto-moderation.json delete mode 100644 src/languages/fi/commands/case.json delete mode 100644 src/languages/fi/commands/fun.json delete mode 100644 src/languages/fi/commands/game.json delete mode 100644 src/languages/fi/commands/general.json delete mode 100644 src/languages/fi/commands/info.json delete mode 100644 src/languages/fi/commands/management.json delete mode 100644 src/languages/fi/commands/misc.json delete mode 100644 src/languages/fi/commands/moderation.json delete mode 100644 src/languages/fi/commands/shared.json delete mode 100644 src/languages/fi/commands/system.json delete mode 100644 src/languages/fi/commands/tools.json delete mode 100644 src/languages/fi/commands/twitch.json delete mode 100644 src/languages/fi/commands/whois.json delete mode 100644 src/languages/fi/errors.json delete mode 100644 src/languages/fi/events/errors.json delete mode 100644 src/languages/fi/events/guilds-logs.json delete mode 100644 src/languages/fi/events/guilds-members.json delete mode 100644 src/languages/fi/events/messages.json delete mode 100644 src/languages/fi/events/moderation.json delete mode 100644 src/languages/fi/events/noMentionSpam.json delete mode 100644 src/languages/fi/events/reactions.json delete mode 100644 src/languages/fi/events/twitch.json delete mode 100644 src/languages/fi/fuzzySearch.json delete mode 100644 src/languages/fi/globals.json delete mode 100644 src/languages/fi/guilds.json delete mode 100644 src/languages/fi/humanLevels.json delete mode 100644 src/languages/fi/moderation.json delete mode 100644 src/languages/fi/moderationActions.json delete mode 100644 src/languages/fi/permissions.json delete mode 100644 src/languages/fi/preconditions.json delete mode 100644 src/languages/fi/selfModeration.json delete mode 100644 src/languages/fi/serializers.json delete mode 100644 src/languages/fi/settings.json delete mode 100644 src/languages/fi/system.json delete mode 100644 src/languages/fr/arguments.json delete mode 100644 src/languages/fr/assertions.json delete mode 100644 src/languages/fr/commands/admin.json delete mode 100644 src/languages/fr/commands/animal.json delete mode 100644 src/languages/fr/commands/auto-moderation.json delete mode 100644 src/languages/fr/commands/case.json delete mode 100644 src/languages/fr/commands/fun.json delete mode 100644 src/languages/fr/commands/game.json delete mode 100644 src/languages/fr/commands/general.json delete mode 100644 src/languages/fr/commands/info.json delete mode 100644 src/languages/fr/commands/management.json delete mode 100644 src/languages/fr/commands/misc.json delete mode 100644 src/languages/fr/commands/moderation.json delete mode 100644 src/languages/fr/commands/shared.json delete mode 100644 src/languages/fr/commands/system.json delete mode 100644 src/languages/fr/commands/tools.json delete mode 100644 src/languages/fr/commands/twitch.json delete mode 100644 src/languages/fr/commands/whois.json delete mode 100644 src/languages/fr/errors.json delete mode 100644 src/languages/fr/events/errors.json delete mode 100644 src/languages/fr/events/guilds-logs.json delete mode 100644 src/languages/fr/events/guilds-members.json delete mode 100644 src/languages/fr/events/messages.json delete mode 100644 src/languages/fr/events/moderation.json delete mode 100644 src/languages/fr/events/noMentionSpam.json delete mode 100644 src/languages/fr/events/reactions.json delete mode 100644 src/languages/fr/events/twitch.json delete mode 100644 src/languages/fr/fuzzySearch.json delete mode 100644 src/languages/fr/globals.json delete mode 100644 src/languages/fr/guilds.json delete mode 100644 src/languages/fr/humanLevels.json delete mode 100644 src/languages/fr/moderation.json delete mode 100644 src/languages/fr/moderationActions.json delete mode 100644 src/languages/fr/permissions.json delete mode 100644 src/languages/fr/preconditions.json delete mode 100644 src/languages/fr/selfModeration.json delete mode 100644 src/languages/fr/serializers.json delete mode 100644 src/languages/fr/settings.json delete mode 100644 src/languages/fr/system.json delete mode 100644 src/languages/hi/arguments.json delete mode 100644 src/languages/hi/assertions.json delete mode 100644 src/languages/hi/commands/admin.json delete mode 100644 src/languages/hi/commands/animal.json delete mode 100644 src/languages/hi/commands/auto-moderation.json delete mode 100644 src/languages/hi/commands/case.json delete mode 100644 src/languages/hi/commands/fun.json delete mode 100644 src/languages/hi/commands/game.json delete mode 100644 src/languages/hi/commands/general.json delete mode 100644 src/languages/hi/commands/info.json delete mode 100644 src/languages/hi/commands/management.json delete mode 100644 src/languages/hi/commands/misc.json delete mode 100644 src/languages/hi/commands/moderation.json delete mode 100644 src/languages/hi/commands/shared.json delete mode 100644 src/languages/hi/commands/system.json delete mode 100644 src/languages/hi/commands/tools.json delete mode 100644 src/languages/hi/commands/twitch.json delete mode 100644 src/languages/hi/commands/whois.json delete mode 100644 src/languages/hi/errors.json delete mode 100644 src/languages/hi/events/errors.json delete mode 100644 src/languages/hi/events/guilds-logs.json delete mode 100644 src/languages/hi/events/guilds-members.json delete mode 100644 src/languages/hi/events/messages.json delete mode 100644 src/languages/hi/events/moderation.json delete mode 100644 src/languages/hi/events/noMentionSpam.json delete mode 100644 src/languages/hi/events/reactions.json delete mode 100644 src/languages/hi/events/twitch.json delete mode 100644 src/languages/hi/fuzzySearch.json delete mode 100644 src/languages/hi/globals.json delete mode 100644 src/languages/hi/guilds.json delete mode 100644 src/languages/hi/humanLevels.json delete mode 100644 src/languages/hi/moderation.json delete mode 100644 src/languages/hi/moderationActions.json delete mode 100644 src/languages/hi/permissions.json delete mode 100644 src/languages/hi/preconditions.json delete mode 100644 src/languages/hi/selfModeration.json delete mode 100644 src/languages/hi/serializers.json delete mode 100644 src/languages/hi/settings.json delete mode 100644 src/languages/hi/system.json delete mode 100644 src/languages/hr/arguments.json delete mode 100644 src/languages/hr/assertions.json delete mode 100644 src/languages/hr/commands/admin.json delete mode 100644 src/languages/hr/commands/animal.json delete mode 100644 src/languages/hr/commands/auto-moderation.json delete mode 100644 src/languages/hr/commands/case.json delete mode 100644 src/languages/hr/commands/fun.json delete mode 100644 src/languages/hr/commands/game.json delete mode 100644 src/languages/hr/commands/general.json delete mode 100644 src/languages/hr/commands/info.json delete mode 100644 src/languages/hr/commands/management.json delete mode 100644 src/languages/hr/commands/misc.json delete mode 100644 src/languages/hr/commands/moderation.json delete mode 100644 src/languages/hr/commands/shared.json delete mode 100644 src/languages/hr/commands/system.json delete mode 100644 src/languages/hr/commands/tools.json delete mode 100644 src/languages/hr/commands/twitch.json delete mode 100644 src/languages/hr/commands/whois.json delete mode 100644 src/languages/hr/errors.json delete mode 100644 src/languages/hr/events/errors.json delete mode 100644 src/languages/hr/events/guilds-logs.json delete mode 100644 src/languages/hr/events/guilds-members.json delete mode 100644 src/languages/hr/events/messages.json delete mode 100644 src/languages/hr/events/moderation.json delete mode 100644 src/languages/hr/events/noMentionSpam.json delete mode 100644 src/languages/hr/events/reactions.json delete mode 100644 src/languages/hr/events/twitch.json delete mode 100644 src/languages/hr/fuzzySearch.json delete mode 100644 src/languages/hr/globals.json delete mode 100644 src/languages/hr/guilds.json delete mode 100644 src/languages/hr/humanLevels.json delete mode 100644 src/languages/hr/moderation.json delete mode 100644 src/languages/hr/moderationActions.json delete mode 100644 src/languages/hr/permissions.json delete mode 100644 src/languages/hr/preconditions.json delete mode 100644 src/languages/hr/selfModeration.json delete mode 100644 src/languages/hr/serializers.json delete mode 100644 src/languages/hr/settings.json delete mode 100644 src/languages/hr/system.json delete mode 100644 src/languages/hu/arguments.json delete mode 100644 src/languages/hu/assertions.json delete mode 100644 src/languages/hu/commands/admin.json delete mode 100644 src/languages/hu/commands/animal.json delete mode 100644 src/languages/hu/commands/auto-moderation.json delete mode 100644 src/languages/hu/commands/case.json delete mode 100644 src/languages/hu/commands/fun.json delete mode 100644 src/languages/hu/commands/game.json delete mode 100644 src/languages/hu/commands/general.json delete mode 100644 src/languages/hu/commands/info.json delete mode 100644 src/languages/hu/commands/management.json delete mode 100644 src/languages/hu/commands/misc.json delete mode 100644 src/languages/hu/commands/moderation.json delete mode 100644 src/languages/hu/commands/shared.json delete mode 100644 src/languages/hu/commands/system.json delete mode 100644 src/languages/hu/commands/tools.json delete mode 100644 src/languages/hu/commands/twitch.json delete mode 100644 src/languages/hu/commands/whois.json delete mode 100644 src/languages/hu/errors.json delete mode 100644 src/languages/hu/events/errors.json delete mode 100644 src/languages/hu/events/guilds-logs.json delete mode 100644 src/languages/hu/events/guilds-members.json delete mode 100644 src/languages/hu/events/messages.json delete mode 100644 src/languages/hu/events/moderation.json delete mode 100644 src/languages/hu/events/noMentionSpam.json delete mode 100644 src/languages/hu/events/reactions.json delete mode 100644 src/languages/hu/events/twitch.json delete mode 100644 src/languages/hu/fuzzySearch.json delete mode 100644 src/languages/hu/globals.json delete mode 100644 src/languages/hu/guilds.json delete mode 100644 src/languages/hu/humanLevels.json delete mode 100644 src/languages/hu/moderation.json delete mode 100644 src/languages/hu/moderationActions.json delete mode 100644 src/languages/hu/permissions.json delete mode 100644 src/languages/hu/preconditions.json delete mode 100644 src/languages/hu/selfModeration.json delete mode 100644 src/languages/hu/serializers.json delete mode 100644 src/languages/hu/settings.json delete mode 100644 src/languages/hu/system.json delete mode 100644 src/languages/id/arguments.json delete mode 100644 src/languages/id/assertions.json delete mode 100644 src/languages/id/commands/admin.json delete mode 100644 src/languages/id/commands/animal.json delete mode 100644 src/languages/id/commands/auto-moderation.json delete mode 100644 src/languages/id/commands/case.json delete mode 100644 src/languages/id/commands/fun.json delete mode 100644 src/languages/id/commands/game.json delete mode 100644 src/languages/id/commands/general.json delete mode 100644 src/languages/id/commands/info.json delete mode 100644 src/languages/id/commands/management.json delete mode 100644 src/languages/id/commands/misc.json delete mode 100644 src/languages/id/commands/moderation.json delete mode 100644 src/languages/id/commands/shared.json delete mode 100644 src/languages/id/commands/system.json delete mode 100644 src/languages/id/commands/tools.json delete mode 100644 src/languages/id/commands/twitch.json delete mode 100644 src/languages/id/commands/whois.json delete mode 100644 src/languages/id/errors.json delete mode 100644 src/languages/id/events/errors.json delete mode 100644 src/languages/id/events/guilds-logs.json delete mode 100644 src/languages/id/events/guilds-members.json delete mode 100644 src/languages/id/events/messages.json delete mode 100644 src/languages/id/events/moderation.json delete mode 100644 src/languages/id/events/noMentionSpam.json delete mode 100644 src/languages/id/events/reactions.json delete mode 100644 src/languages/id/events/twitch.json delete mode 100644 src/languages/id/fuzzySearch.json delete mode 100644 src/languages/id/globals.json delete mode 100644 src/languages/id/guilds.json delete mode 100644 src/languages/id/humanLevels.json delete mode 100644 src/languages/id/moderation.json delete mode 100644 src/languages/id/moderationActions.json delete mode 100644 src/languages/id/permissions.json delete mode 100644 src/languages/id/preconditions.json delete mode 100644 src/languages/id/selfModeration.json delete mode 100644 src/languages/id/serializers.json delete mode 100644 src/languages/id/settings.json delete mode 100644 src/languages/id/system.json delete mode 100644 src/languages/index.ts delete mode 100644 src/languages/it/arguments.json delete mode 100644 src/languages/it/assertions.json delete mode 100644 src/languages/it/commands/admin.json delete mode 100644 src/languages/it/commands/animal.json delete mode 100644 src/languages/it/commands/auto-moderation.json delete mode 100644 src/languages/it/commands/case.json delete mode 100644 src/languages/it/commands/fun.json delete mode 100644 src/languages/it/commands/game.json delete mode 100644 src/languages/it/commands/general.json delete mode 100644 src/languages/it/commands/info.json delete mode 100644 src/languages/it/commands/management.json delete mode 100644 src/languages/it/commands/misc.json delete mode 100644 src/languages/it/commands/moderation.json delete mode 100644 src/languages/it/commands/shared.json delete mode 100644 src/languages/it/commands/system.json delete mode 100644 src/languages/it/commands/tools.json delete mode 100644 src/languages/it/commands/twitch.json delete mode 100644 src/languages/it/commands/whois.json delete mode 100644 src/languages/it/errors.json delete mode 100644 src/languages/it/events/errors.json delete mode 100644 src/languages/it/events/guilds-logs.json delete mode 100644 src/languages/it/events/guilds-members.json delete mode 100644 src/languages/it/events/messages.json delete mode 100644 src/languages/it/events/moderation.json delete mode 100644 src/languages/it/events/noMentionSpam.json delete mode 100644 src/languages/it/events/reactions.json delete mode 100644 src/languages/it/events/twitch.json delete mode 100644 src/languages/it/fuzzySearch.json delete mode 100644 src/languages/it/globals.json delete mode 100644 src/languages/it/guilds.json delete mode 100644 src/languages/it/humanLevels.json delete mode 100644 src/languages/it/moderation.json delete mode 100644 src/languages/it/moderationActions.json delete mode 100644 src/languages/it/permissions.json delete mode 100644 src/languages/it/preconditions.json delete mode 100644 src/languages/it/selfModeration.json delete mode 100644 src/languages/it/serializers.json delete mode 100644 src/languages/it/settings.json delete mode 100644 src/languages/it/system.json delete mode 100644 src/languages/ja/arguments.json delete mode 100644 src/languages/ja/assertions.json delete mode 100644 src/languages/ja/commands/admin.json delete mode 100644 src/languages/ja/commands/animal.json delete mode 100644 src/languages/ja/commands/auto-moderation.json delete mode 100644 src/languages/ja/commands/case.json delete mode 100644 src/languages/ja/commands/fun.json delete mode 100644 src/languages/ja/commands/game.json delete mode 100644 src/languages/ja/commands/general.json delete mode 100644 src/languages/ja/commands/info.json delete mode 100644 src/languages/ja/commands/management.json delete mode 100644 src/languages/ja/commands/misc.json delete mode 100644 src/languages/ja/commands/moderation.json delete mode 100644 src/languages/ja/commands/shared.json delete mode 100644 src/languages/ja/commands/system.json delete mode 100644 src/languages/ja/commands/tools.json delete mode 100644 src/languages/ja/commands/twitch.json delete mode 100644 src/languages/ja/commands/whois.json delete mode 100644 src/languages/ja/errors.json delete mode 100644 src/languages/ja/events/errors.json delete mode 100644 src/languages/ja/events/guilds-logs.json delete mode 100644 src/languages/ja/events/guilds-members.json delete mode 100644 src/languages/ja/events/messages.json delete mode 100644 src/languages/ja/events/moderation.json delete mode 100644 src/languages/ja/events/noMentionSpam.json delete mode 100644 src/languages/ja/events/reactions.json delete mode 100644 src/languages/ja/events/twitch.json delete mode 100644 src/languages/ja/fuzzySearch.json delete mode 100644 src/languages/ja/globals.json delete mode 100644 src/languages/ja/guilds.json delete mode 100644 src/languages/ja/humanLevels.json delete mode 100644 src/languages/ja/moderation.json delete mode 100644 src/languages/ja/moderationActions.json delete mode 100644 src/languages/ja/permissions.json delete mode 100644 src/languages/ja/preconditions.json delete mode 100644 src/languages/ja/selfModeration.json delete mode 100644 src/languages/ja/serializers.json delete mode 100644 src/languages/ja/settings.json delete mode 100644 src/languages/ja/system.json delete mode 100644 src/languages/ko/arguments.json delete mode 100644 src/languages/ko/assertions.json delete mode 100644 src/languages/ko/commands/admin.json delete mode 100644 src/languages/ko/commands/animal.json delete mode 100644 src/languages/ko/commands/auto-moderation.json delete mode 100644 src/languages/ko/commands/case.json delete mode 100644 src/languages/ko/commands/fun.json delete mode 100644 src/languages/ko/commands/game.json delete mode 100644 src/languages/ko/commands/general.json delete mode 100644 src/languages/ko/commands/info.json delete mode 100644 src/languages/ko/commands/management.json delete mode 100644 src/languages/ko/commands/misc.json delete mode 100644 src/languages/ko/commands/moderation.json delete mode 100644 src/languages/ko/commands/shared.json delete mode 100644 src/languages/ko/commands/system.json delete mode 100644 src/languages/ko/commands/tools.json delete mode 100644 src/languages/ko/commands/twitch.json delete mode 100644 src/languages/ko/commands/whois.json delete mode 100644 src/languages/ko/errors.json delete mode 100644 src/languages/ko/events/errors.json delete mode 100644 src/languages/ko/events/guilds-logs.json delete mode 100644 src/languages/ko/events/guilds-members.json delete mode 100644 src/languages/ko/events/messages.json delete mode 100644 src/languages/ko/events/moderation.json delete mode 100644 src/languages/ko/events/noMentionSpam.json delete mode 100644 src/languages/ko/events/reactions.json delete mode 100644 src/languages/ko/events/twitch.json delete mode 100644 src/languages/ko/fuzzySearch.json delete mode 100644 src/languages/ko/globals.json delete mode 100644 src/languages/ko/guilds.json delete mode 100644 src/languages/ko/humanLevels.json delete mode 100644 src/languages/ko/moderation.json delete mode 100644 src/languages/ko/moderationActions.json delete mode 100644 src/languages/ko/permissions.json delete mode 100644 src/languages/ko/preconditions.json delete mode 100644 src/languages/ko/selfModeration.json delete mode 100644 src/languages/ko/serializers.json delete mode 100644 src/languages/ko/settings.json delete mode 100644 src/languages/ko/system.json delete mode 100644 src/languages/lt/arguments.json delete mode 100644 src/languages/lt/assertions.json delete mode 100644 src/languages/lt/commands/admin.json delete mode 100644 src/languages/lt/commands/animal.json delete mode 100644 src/languages/lt/commands/auto-moderation.json delete mode 100644 src/languages/lt/commands/case.json delete mode 100644 src/languages/lt/commands/fun.json delete mode 100644 src/languages/lt/commands/game.json delete mode 100644 src/languages/lt/commands/general.json delete mode 100644 src/languages/lt/commands/info.json delete mode 100644 src/languages/lt/commands/management.json delete mode 100644 src/languages/lt/commands/misc.json delete mode 100644 src/languages/lt/commands/moderation.json delete mode 100644 src/languages/lt/commands/shared.json delete mode 100644 src/languages/lt/commands/system.json delete mode 100644 src/languages/lt/commands/tools.json delete mode 100644 src/languages/lt/commands/twitch.json delete mode 100644 src/languages/lt/commands/whois.json delete mode 100644 src/languages/lt/errors.json delete mode 100644 src/languages/lt/events/errors.json delete mode 100644 src/languages/lt/events/guilds-logs.json delete mode 100644 src/languages/lt/events/guilds-members.json delete mode 100644 src/languages/lt/events/messages.json delete mode 100644 src/languages/lt/events/moderation.json delete mode 100644 src/languages/lt/events/noMentionSpam.json delete mode 100644 src/languages/lt/events/reactions.json delete mode 100644 src/languages/lt/events/twitch.json delete mode 100644 src/languages/lt/fuzzySearch.json delete mode 100644 src/languages/lt/globals.json delete mode 100644 src/languages/lt/guilds.json delete mode 100644 src/languages/lt/humanLevels.json delete mode 100644 src/languages/lt/moderation.json delete mode 100644 src/languages/lt/moderationActions.json delete mode 100644 src/languages/lt/permissions.json delete mode 100644 src/languages/lt/preconditions.json delete mode 100644 src/languages/lt/selfModeration.json delete mode 100644 src/languages/lt/serializers.json delete mode 100644 src/languages/lt/settings.json delete mode 100644 src/languages/lt/system.json delete mode 100644 src/languages/nl/arguments.json delete mode 100644 src/languages/nl/assertions.json delete mode 100644 src/languages/nl/commands/admin.json delete mode 100644 src/languages/nl/commands/animal.json delete mode 100644 src/languages/nl/commands/auto-moderation.json delete mode 100644 src/languages/nl/commands/case.json delete mode 100644 src/languages/nl/commands/fun.json delete mode 100644 src/languages/nl/commands/game.json delete mode 100644 src/languages/nl/commands/general.json delete mode 100644 src/languages/nl/commands/info.json delete mode 100644 src/languages/nl/commands/management.json delete mode 100644 src/languages/nl/commands/misc.json delete mode 100644 src/languages/nl/commands/moderation.json delete mode 100644 src/languages/nl/commands/shared.json delete mode 100644 src/languages/nl/commands/system.json delete mode 100644 src/languages/nl/commands/tools.json delete mode 100644 src/languages/nl/commands/twitch.json delete mode 100644 src/languages/nl/commands/whois.json delete mode 100644 src/languages/nl/constants.ts delete mode 100644 src/languages/nl/errors.json delete mode 100644 src/languages/nl/events/errors.json delete mode 100644 src/languages/nl/events/guilds-logs.json delete mode 100644 src/languages/nl/events/guilds-members.json delete mode 100644 src/languages/nl/events/messages.json delete mode 100644 src/languages/nl/events/moderation.json delete mode 100644 src/languages/nl/events/noMentionSpam.json delete mode 100644 src/languages/nl/events/reactions.json delete mode 100644 src/languages/nl/events/twitch.json delete mode 100644 src/languages/nl/fuzzySearch.json delete mode 100644 src/languages/nl/globals.json delete mode 100644 src/languages/nl/guilds.json delete mode 100644 src/languages/nl/humanLevels.json delete mode 100644 src/languages/nl/moderation.json delete mode 100644 src/languages/nl/moderationActions.json delete mode 100644 src/languages/nl/permissions.json delete mode 100644 src/languages/nl/preconditions.json delete mode 100644 src/languages/nl/selfModeration.json delete mode 100644 src/languages/nl/serializers.json delete mode 100644 src/languages/nl/settings.json delete mode 100644 src/languages/nl/system.json delete mode 100644 src/languages/no/arguments.json delete mode 100644 src/languages/no/assertions.json delete mode 100644 src/languages/no/commands/admin.json delete mode 100644 src/languages/no/commands/animal.json delete mode 100644 src/languages/no/commands/auto-moderation.json delete mode 100644 src/languages/no/commands/case.json delete mode 100644 src/languages/no/commands/fun.json delete mode 100644 src/languages/no/commands/game.json delete mode 100644 src/languages/no/commands/general.json delete mode 100644 src/languages/no/commands/info.json delete mode 100644 src/languages/no/commands/management.json delete mode 100644 src/languages/no/commands/misc.json delete mode 100644 src/languages/no/commands/moderation.json delete mode 100644 src/languages/no/commands/shared.json delete mode 100644 src/languages/no/commands/system.json delete mode 100644 src/languages/no/commands/tools.json delete mode 100644 src/languages/no/commands/twitch.json delete mode 100644 src/languages/no/commands/whois.json delete mode 100644 src/languages/no/errors.json delete mode 100644 src/languages/no/events/errors.json delete mode 100644 src/languages/no/events/guilds-logs.json delete mode 100644 src/languages/no/events/guilds-members.json delete mode 100644 src/languages/no/events/messages.json delete mode 100644 src/languages/no/events/moderation.json delete mode 100644 src/languages/no/events/noMentionSpam.json delete mode 100644 src/languages/no/events/reactions.json delete mode 100644 src/languages/no/events/twitch.json delete mode 100644 src/languages/no/fuzzySearch.json delete mode 100644 src/languages/no/globals.json delete mode 100644 src/languages/no/guilds.json delete mode 100644 src/languages/no/humanLevels.json delete mode 100644 src/languages/no/moderation.json delete mode 100644 src/languages/no/moderationActions.json delete mode 100644 src/languages/no/permissions.json delete mode 100644 src/languages/no/preconditions.json delete mode 100644 src/languages/no/selfModeration.json delete mode 100644 src/languages/no/serializers.json delete mode 100644 src/languages/no/settings.json delete mode 100644 src/languages/no/system.json delete mode 100644 src/languages/pl/arguments.json delete mode 100644 src/languages/pl/assertions.json delete mode 100644 src/languages/pl/commands/admin.json delete mode 100644 src/languages/pl/commands/animal.json delete mode 100644 src/languages/pl/commands/auto-moderation.json delete mode 100644 src/languages/pl/commands/case.json delete mode 100644 src/languages/pl/commands/fun.json delete mode 100644 src/languages/pl/commands/game.json delete mode 100644 src/languages/pl/commands/general.json delete mode 100644 src/languages/pl/commands/info.json delete mode 100644 src/languages/pl/commands/management.json delete mode 100644 src/languages/pl/commands/misc.json delete mode 100644 src/languages/pl/commands/moderation.json delete mode 100644 src/languages/pl/commands/shared.json delete mode 100644 src/languages/pl/commands/system.json delete mode 100644 src/languages/pl/commands/tools.json delete mode 100644 src/languages/pl/commands/twitch.json delete mode 100644 src/languages/pl/commands/whois.json delete mode 100644 src/languages/pl/errors.json delete mode 100644 src/languages/pl/events/errors.json delete mode 100644 src/languages/pl/events/guilds-logs.json delete mode 100644 src/languages/pl/events/guilds-members.json delete mode 100644 src/languages/pl/events/messages.json delete mode 100644 src/languages/pl/events/moderation.json delete mode 100644 src/languages/pl/events/noMentionSpam.json delete mode 100644 src/languages/pl/events/reactions.json delete mode 100644 src/languages/pl/events/twitch.json delete mode 100644 src/languages/pl/fuzzySearch.json delete mode 100644 src/languages/pl/globals.json delete mode 100644 src/languages/pl/guilds.json delete mode 100644 src/languages/pl/humanLevels.json delete mode 100644 src/languages/pl/moderation.json delete mode 100644 src/languages/pl/moderationActions.json delete mode 100644 src/languages/pl/permissions.json delete mode 100644 src/languages/pl/preconditions.json delete mode 100644 src/languages/pl/selfModeration.json delete mode 100644 src/languages/pl/serializers.json delete mode 100644 src/languages/pl/settings.json delete mode 100644 src/languages/pl/system.json delete mode 100644 src/languages/pt-BR/arguments.json delete mode 100644 src/languages/pt-BR/assertions.json delete mode 100644 src/languages/pt-BR/commands/admin.json delete mode 100644 src/languages/pt-BR/commands/animal.json delete mode 100644 src/languages/pt-BR/commands/auto-moderation.json delete mode 100644 src/languages/pt-BR/commands/case.json delete mode 100644 src/languages/pt-BR/commands/fun.json delete mode 100644 src/languages/pt-BR/commands/game.json delete mode 100644 src/languages/pt-BR/commands/general.json delete mode 100644 src/languages/pt-BR/commands/info.json delete mode 100644 src/languages/pt-BR/commands/management.json delete mode 100644 src/languages/pt-BR/commands/misc.json delete mode 100644 src/languages/pt-BR/commands/moderation.json delete mode 100644 src/languages/pt-BR/commands/shared.json delete mode 100644 src/languages/pt-BR/commands/system.json delete mode 100644 src/languages/pt-BR/commands/tools.json delete mode 100644 src/languages/pt-BR/commands/twitch.json delete mode 100644 src/languages/pt-BR/commands/whois.json delete mode 100644 src/languages/pt-BR/errors.json delete mode 100644 src/languages/pt-BR/events/errors.json delete mode 100644 src/languages/pt-BR/events/guilds-logs.json delete mode 100644 src/languages/pt-BR/events/guilds-members.json delete mode 100644 src/languages/pt-BR/events/messages.json delete mode 100644 src/languages/pt-BR/events/moderation.json delete mode 100644 src/languages/pt-BR/events/noMentionSpam.json delete mode 100644 src/languages/pt-BR/events/reactions.json delete mode 100644 src/languages/pt-BR/events/twitch.json delete mode 100644 src/languages/pt-BR/fuzzySearch.json delete mode 100644 src/languages/pt-BR/globals.json delete mode 100644 src/languages/pt-BR/guilds.json delete mode 100644 src/languages/pt-BR/humanLevels.json delete mode 100644 src/languages/pt-BR/moderation.json delete mode 100644 src/languages/pt-BR/moderationActions.json delete mode 100644 src/languages/pt-BR/permissions.json delete mode 100644 src/languages/pt-BR/preconditions.json delete mode 100644 src/languages/pt-BR/selfModeration.json delete mode 100644 src/languages/pt-BR/serializers.json delete mode 100644 src/languages/pt-BR/settings.json delete mode 100644 src/languages/pt-BR/system.json delete mode 100644 src/languages/ro/arguments.json delete mode 100644 src/languages/ro/assertions.json delete mode 100644 src/languages/ro/commands/admin.json delete mode 100644 src/languages/ro/commands/animal.json delete mode 100644 src/languages/ro/commands/auto-moderation.json delete mode 100644 src/languages/ro/commands/case.json delete mode 100644 src/languages/ro/commands/fun.json delete mode 100644 src/languages/ro/commands/game.json delete mode 100644 src/languages/ro/commands/general.json delete mode 100644 src/languages/ro/commands/info.json delete mode 100644 src/languages/ro/commands/management.json delete mode 100644 src/languages/ro/commands/misc.json delete mode 100644 src/languages/ro/commands/moderation.json delete mode 100644 src/languages/ro/commands/shared.json delete mode 100644 src/languages/ro/commands/system.json delete mode 100644 src/languages/ro/commands/tools.json delete mode 100644 src/languages/ro/commands/twitch.json delete mode 100644 src/languages/ro/commands/whois.json delete mode 100644 src/languages/ro/errors.json delete mode 100644 src/languages/ro/events/errors.json delete mode 100644 src/languages/ro/events/guilds-logs.json delete mode 100644 src/languages/ro/events/guilds-members.json delete mode 100644 src/languages/ro/events/messages.json delete mode 100644 src/languages/ro/events/moderation.json delete mode 100644 src/languages/ro/events/noMentionSpam.json delete mode 100644 src/languages/ro/events/reactions.json delete mode 100644 src/languages/ro/events/twitch.json delete mode 100644 src/languages/ro/fuzzySearch.json delete mode 100644 src/languages/ro/globals.json delete mode 100644 src/languages/ro/guilds.json delete mode 100644 src/languages/ro/humanLevels.json delete mode 100644 src/languages/ro/moderation.json delete mode 100644 src/languages/ro/moderationActions.json delete mode 100644 src/languages/ro/permissions.json delete mode 100644 src/languages/ro/preconditions.json delete mode 100644 src/languages/ro/selfModeration.json delete mode 100644 src/languages/ro/serializers.json delete mode 100644 src/languages/ro/settings.json delete mode 100644 src/languages/ro/system.json delete mode 100644 src/languages/ru/arguments.json delete mode 100644 src/languages/ru/assertions.json delete mode 100644 src/languages/ru/commands/admin.json delete mode 100644 src/languages/ru/commands/animal.json delete mode 100644 src/languages/ru/commands/auto-moderation.json delete mode 100644 src/languages/ru/commands/case.json delete mode 100644 src/languages/ru/commands/fun.json delete mode 100644 src/languages/ru/commands/game.json delete mode 100644 src/languages/ru/commands/general.json delete mode 100644 src/languages/ru/commands/info.json delete mode 100644 src/languages/ru/commands/management.json delete mode 100644 src/languages/ru/commands/misc.json delete mode 100644 src/languages/ru/commands/moderation.json delete mode 100644 src/languages/ru/commands/shared.json delete mode 100644 src/languages/ru/commands/system.json delete mode 100644 src/languages/ru/commands/tools.json delete mode 100644 src/languages/ru/commands/twitch.json delete mode 100644 src/languages/ru/commands/whois.json delete mode 100644 src/languages/ru/errors.json delete mode 100644 src/languages/ru/events/errors.json delete mode 100644 src/languages/ru/events/guilds-logs.json delete mode 100644 src/languages/ru/events/guilds-members.json delete mode 100644 src/languages/ru/events/messages.json delete mode 100644 src/languages/ru/events/moderation.json delete mode 100644 src/languages/ru/events/noMentionSpam.json delete mode 100644 src/languages/ru/events/reactions.json delete mode 100644 src/languages/ru/events/twitch.json delete mode 100644 src/languages/ru/fuzzySearch.json delete mode 100644 src/languages/ru/globals.json delete mode 100644 src/languages/ru/guilds.json delete mode 100644 src/languages/ru/humanLevels.json delete mode 100644 src/languages/ru/moderation.json delete mode 100644 src/languages/ru/moderationActions.json delete mode 100644 src/languages/ru/permissions.json delete mode 100644 src/languages/ru/preconditions.json delete mode 100644 src/languages/ru/selfModeration.json delete mode 100644 src/languages/ru/serializers.json delete mode 100644 src/languages/ru/settings.json delete mode 100644 src/languages/ru/system.json delete mode 100644 src/languages/sv-SE/arguments.json delete mode 100644 src/languages/sv-SE/assertions.json delete mode 100644 src/languages/sv-SE/commands/admin.json delete mode 100644 src/languages/sv-SE/commands/animal.json delete mode 100644 src/languages/sv-SE/commands/auto-moderation.json delete mode 100644 src/languages/sv-SE/commands/case.json delete mode 100644 src/languages/sv-SE/commands/fun.json delete mode 100644 src/languages/sv-SE/commands/game.json delete mode 100644 src/languages/sv-SE/commands/general.json delete mode 100644 src/languages/sv-SE/commands/info.json delete mode 100644 src/languages/sv-SE/commands/management.json delete mode 100644 src/languages/sv-SE/commands/misc.json delete mode 100644 src/languages/sv-SE/commands/moderation.json delete mode 100644 src/languages/sv-SE/commands/shared.json delete mode 100644 src/languages/sv-SE/commands/system.json delete mode 100644 src/languages/sv-SE/commands/tools.json delete mode 100644 src/languages/sv-SE/commands/twitch.json delete mode 100644 src/languages/sv-SE/commands/whois.json delete mode 100644 src/languages/sv-SE/errors.json delete mode 100644 src/languages/sv-SE/events/errors.json delete mode 100644 src/languages/sv-SE/events/guilds-logs.json delete mode 100644 src/languages/sv-SE/events/guilds-members.json delete mode 100644 src/languages/sv-SE/events/messages.json delete mode 100644 src/languages/sv-SE/events/moderation.json delete mode 100644 src/languages/sv-SE/events/noMentionSpam.json delete mode 100644 src/languages/sv-SE/events/reactions.json delete mode 100644 src/languages/sv-SE/events/twitch.json delete mode 100644 src/languages/sv-SE/fuzzySearch.json delete mode 100644 src/languages/sv-SE/globals.json delete mode 100644 src/languages/sv-SE/guilds.json delete mode 100644 src/languages/sv-SE/humanLevels.json delete mode 100644 src/languages/sv-SE/moderation.json delete mode 100644 src/languages/sv-SE/moderationActions.json delete mode 100644 src/languages/sv-SE/permissions.json delete mode 100644 src/languages/sv-SE/preconditions.json delete mode 100644 src/languages/sv-SE/selfModeration.json delete mode 100644 src/languages/sv-SE/serializers.json delete mode 100644 src/languages/sv-SE/settings.json delete mode 100644 src/languages/sv-SE/system.json delete mode 100644 src/languages/th/arguments.json delete mode 100644 src/languages/th/assertions.json delete mode 100644 src/languages/th/commands/admin.json delete mode 100644 src/languages/th/commands/animal.json delete mode 100644 src/languages/th/commands/auto-moderation.json delete mode 100644 src/languages/th/commands/case.json delete mode 100644 src/languages/th/commands/fun.json delete mode 100644 src/languages/th/commands/game.json delete mode 100644 src/languages/th/commands/general.json delete mode 100644 src/languages/th/commands/info.json delete mode 100644 src/languages/th/commands/management.json delete mode 100644 src/languages/th/commands/misc.json delete mode 100644 src/languages/th/commands/moderation.json delete mode 100644 src/languages/th/commands/shared.json delete mode 100644 src/languages/th/commands/system.json delete mode 100644 src/languages/th/commands/tools.json delete mode 100644 src/languages/th/commands/twitch.json delete mode 100644 src/languages/th/commands/whois.json delete mode 100644 src/languages/th/errors.json delete mode 100644 src/languages/th/events/errors.json delete mode 100644 src/languages/th/events/guilds-logs.json delete mode 100644 src/languages/th/events/guilds-members.json delete mode 100644 src/languages/th/events/messages.json delete mode 100644 src/languages/th/events/moderation.json delete mode 100644 src/languages/th/events/noMentionSpam.json delete mode 100644 src/languages/th/events/reactions.json delete mode 100644 src/languages/th/events/twitch.json delete mode 100644 src/languages/th/fuzzySearch.json delete mode 100644 src/languages/th/globals.json delete mode 100644 src/languages/th/guilds.json delete mode 100644 src/languages/th/humanLevels.json delete mode 100644 src/languages/th/moderation.json delete mode 100644 src/languages/th/moderationActions.json delete mode 100644 src/languages/th/permissions.json delete mode 100644 src/languages/th/preconditions.json delete mode 100644 src/languages/th/selfModeration.json delete mode 100644 src/languages/th/serializers.json delete mode 100644 src/languages/th/settings.json delete mode 100644 src/languages/th/system.json delete mode 100644 src/languages/tr/arguments.json delete mode 100644 src/languages/tr/assertions.json delete mode 100644 src/languages/tr/commands/admin.json delete mode 100644 src/languages/tr/commands/animal.json delete mode 100644 src/languages/tr/commands/auto-moderation.json delete mode 100644 src/languages/tr/commands/case.json delete mode 100644 src/languages/tr/commands/fun.json delete mode 100644 src/languages/tr/commands/game.json delete mode 100644 src/languages/tr/commands/general.json delete mode 100644 src/languages/tr/commands/info.json delete mode 100644 src/languages/tr/commands/management.json delete mode 100644 src/languages/tr/commands/misc.json delete mode 100644 src/languages/tr/commands/moderation.json delete mode 100644 src/languages/tr/commands/shared.json delete mode 100644 src/languages/tr/commands/system.json delete mode 100644 src/languages/tr/commands/tools.json delete mode 100644 src/languages/tr/commands/twitch.json delete mode 100644 src/languages/tr/commands/whois.json delete mode 100644 src/languages/tr/errors.json delete mode 100644 src/languages/tr/events/errors.json delete mode 100644 src/languages/tr/events/guilds-logs.json delete mode 100644 src/languages/tr/events/guilds-members.json delete mode 100644 src/languages/tr/events/messages.json delete mode 100644 src/languages/tr/events/moderation.json delete mode 100644 src/languages/tr/events/noMentionSpam.json delete mode 100644 src/languages/tr/events/reactions.json delete mode 100644 src/languages/tr/events/twitch.json delete mode 100644 src/languages/tr/fuzzySearch.json delete mode 100644 src/languages/tr/globals.json delete mode 100644 src/languages/tr/guilds.json delete mode 100644 src/languages/tr/humanLevels.json delete mode 100644 src/languages/tr/moderation.json delete mode 100644 src/languages/tr/moderationActions.json delete mode 100644 src/languages/tr/permissions.json delete mode 100644 src/languages/tr/preconditions.json delete mode 100644 src/languages/tr/selfModeration.json delete mode 100644 src/languages/tr/serializers.json delete mode 100644 src/languages/tr/settings.json delete mode 100644 src/languages/tr/system.json delete mode 100644 src/languages/uk/arguments.json delete mode 100644 src/languages/uk/assertions.json delete mode 100644 src/languages/uk/commands/admin.json delete mode 100644 src/languages/uk/commands/animal.json delete mode 100644 src/languages/uk/commands/auto-moderation.json delete mode 100644 src/languages/uk/commands/case.json delete mode 100644 src/languages/uk/commands/fun.json delete mode 100644 src/languages/uk/commands/game.json delete mode 100644 src/languages/uk/commands/general.json delete mode 100644 src/languages/uk/commands/info.json delete mode 100644 src/languages/uk/commands/management.json delete mode 100644 src/languages/uk/commands/misc.json delete mode 100644 src/languages/uk/commands/moderation.json delete mode 100644 src/languages/uk/commands/shared.json delete mode 100644 src/languages/uk/commands/system.json delete mode 100644 src/languages/uk/commands/tools.json delete mode 100644 src/languages/uk/commands/twitch.json delete mode 100644 src/languages/uk/commands/whois.json delete mode 100644 src/languages/uk/errors.json delete mode 100644 src/languages/uk/events/errors.json delete mode 100644 src/languages/uk/events/guilds-logs.json delete mode 100644 src/languages/uk/events/guilds-members.json delete mode 100644 src/languages/uk/events/messages.json delete mode 100644 src/languages/uk/events/moderation.json delete mode 100644 src/languages/uk/events/noMentionSpam.json delete mode 100644 src/languages/uk/events/reactions.json delete mode 100644 src/languages/uk/events/twitch.json delete mode 100644 src/languages/uk/fuzzySearch.json delete mode 100644 src/languages/uk/globals.json delete mode 100644 src/languages/uk/guilds.json delete mode 100644 src/languages/uk/humanLevels.json delete mode 100644 src/languages/uk/moderation.json delete mode 100644 src/languages/uk/moderationActions.json delete mode 100644 src/languages/uk/permissions.json delete mode 100644 src/languages/uk/preconditions.json delete mode 100644 src/languages/uk/selfModeration.json delete mode 100644 src/languages/uk/serializers.json delete mode 100644 src/languages/uk/settings.json delete mode 100644 src/languages/uk/system.json delete mode 100644 src/languages/vi/arguments.json delete mode 100644 src/languages/vi/assertions.json delete mode 100644 src/languages/vi/commands/admin.json delete mode 100644 src/languages/vi/commands/animal.json delete mode 100644 src/languages/vi/commands/auto-moderation.json delete mode 100644 src/languages/vi/commands/case.json delete mode 100644 src/languages/vi/commands/fun.json delete mode 100644 src/languages/vi/commands/game.json delete mode 100644 src/languages/vi/commands/general.json delete mode 100644 src/languages/vi/commands/info.json delete mode 100644 src/languages/vi/commands/management.json delete mode 100644 src/languages/vi/commands/misc.json delete mode 100644 src/languages/vi/commands/moderation.json delete mode 100644 src/languages/vi/commands/shared.json delete mode 100644 src/languages/vi/commands/system.json delete mode 100644 src/languages/vi/commands/tools.json delete mode 100644 src/languages/vi/commands/twitch.json delete mode 100644 src/languages/vi/commands/whois.json delete mode 100644 src/languages/vi/errors.json delete mode 100644 src/languages/vi/events/errors.json delete mode 100644 src/languages/vi/events/guilds-logs.json delete mode 100644 src/languages/vi/events/guilds-members.json delete mode 100644 src/languages/vi/events/messages.json delete mode 100644 src/languages/vi/events/moderation.json delete mode 100644 src/languages/vi/events/noMentionSpam.json delete mode 100644 src/languages/vi/events/reactions.json delete mode 100644 src/languages/vi/events/twitch.json delete mode 100644 src/languages/vi/fuzzySearch.json delete mode 100644 src/languages/vi/globals.json delete mode 100644 src/languages/vi/guilds.json delete mode 100644 src/languages/vi/humanLevels.json delete mode 100644 src/languages/vi/moderation.json delete mode 100644 src/languages/vi/moderationActions.json delete mode 100644 src/languages/vi/permissions.json delete mode 100644 src/languages/vi/preconditions.json delete mode 100644 src/languages/vi/selfModeration.json delete mode 100644 src/languages/vi/serializers.json delete mode 100644 src/languages/vi/settings.json delete mode 100644 src/languages/vi/system.json delete mode 100644 src/languages/zh-CN/arguments.json delete mode 100644 src/languages/zh-CN/assertions.json delete mode 100644 src/languages/zh-CN/commands/admin.json delete mode 100644 src/languages/zh-CN/commands/animal.json delete mode 100644 src/languages/zh-CN/commands/auto-moderation.json delete mode 100644 src/languages/zh-CN/commands/case.json delete mode 100644 src/languages/zh-CN/commands/fun.json delete mode 100644 src/languages/zh-CN/commands/game.json delete mode 100644 src/languages/zh-CN/commands/general.json delete mode 100644 src/languages/zh-CN/commands/info.json delete mode 100644 src/languages/zh-CN/commands/management.json delete mode 100644 src/languages/zh-CN/commands/misc.json delete mode 100644 src/languages/zh-CN/commands/moderation.json delete mode 100644 src/languages/zh-CN/commands/shared.json delete mode 100644 src/languages/zh-CN/commands/system.json delete mode 100644 src/languages/zh-CN/commands/tools.json delete mode 100644 src/languages/zh-CN/commands/twitch.json delete mode 100644 src/languages/zh-CN/commands/whois.json delete mode 100644 src/languages/zh-CN/errors.json delete mode 100644 src/languages/zh-CN/events/errors.json delete mode 100644 src/languages/zh-CN/events/guilds-logs.json delete mode 100644 src/languages/zh-CN/events/guilds-members.json delete mode 100644 src/languages/zh-CN/events/messages.json delete mode 100644 src/languages/zh-CN/events/moderation.json delete mode 100644 src/languages/zh-CN/events/noMentionSpam.json delete mode 100644 src/languages/zh-CN/events/reactions.json delete mode 100644 src/languages/zh-CN/events/twitch.json delete mode 100644 src/languages/zh-CN/fuzzySearch.json delete mode 100644 src/languages/zh-CN/globals.json delete mode 100644 src/languages/zh-CN/guilds.json delete mode 100644 src/languages/zh-CN/humanLevels.json delete mode 100644 src/languages/zh-CN/moderation.json delete mode 100644 src/languages/zh-CN/moderationActions.json delete mode 100644 src/languages/zh-CN/permissions.json delete mode 100644 src/languages/zh-CN/preconditions.json delete mode 100644 src/languages/zh-CN/selfModeration.json delete mode 100644 src/languages/zh-CN/serializers.json delete mode 100644 src/languages/zh-CN/settings.json delete mode 100644 src/languages/zh-CN/system.json delete mode 100644 src/languages/zh-TW/arguments.json delete mode 100644 src/languages/zh-TW/assertions.json delete mode 100644 src/languages/zh-TW/commands/admin.json delete mode 100644 src/languages/zh-TW/commands/animal.json delete mode 100644 src/languages/zh-TW/commands/auto-moderation.json delete mode 100644 src/languages/zh-TW/commands/case.json delete mode 100644 src/languages/zh-TW/commands/fun.json delete mode 100644 src/languages/zh-TW/commands/game.json delete mode 100644 src/languages/zh-TW/commands/general.json delete mode 100644 src/languages/zh-TW/commands/info.json delete mode 100644 src/languages/zh-TW/commands/management.json delete mode 100644 src/languages/zh-TW/commands/misc.json delete mode 100644 src/languages/zh-TW/commands/moderation.json delete mode 100644 src/languages/zh-TW/commands/shared.json delete mode 100644 src/languages/zh-TW/commands/system.json delete mode 100644 src/languages/zh-TW/commands/tools.json delete mode 100644 src/languages/zh-TW/commands/twitch.json delete mode 100644 src/languages/zh-TW/commands/whois.json delete mode 100644 src/languages/zh-TW/errors.json delete mode 100644 src/languages/zh-TW/events/errors.json delete mode 100644 src/languages/zh-TW/events/guilds-logs.json delete mode 100644 src/languages/zh-TW/events/guilds-members.json delete mode 100644 src/languages/zh-TW/events/messages.json delete mode 100644 src/languages/zh-TW/events/moderation.json delete mode 100644 src/languages/zh-TW/events/noMentionSpam.json delete mode 100644 src/languages/zh-TW/events/reactions.json delete mode 100644 src/languages/zh-TW/events/twitch.json delete mode 100644 src/languages/zh-TW/fuzzySearch.json delete mode 100644 src/languages/zh-TW/globals.json delete mode 100644 src/languages/zh-TW/guilds.json delete mode 100644 src/languages/zh-TW/humanLevels.json delete mode 100644 src/languages/zh-TW/moderation.json delete mode 100644 src/languages/zh-TW/moderationActions.json delete mode 100644 src/languages/zh-TW/permissions.json delete mode 100644 src/languages/zh-TW/preconditions.json delete mode 100644 src/languages/zh-TW/selfModeration.json delete mode 100644 src/languages/zh-TW/serializers.json delete mode 100644 src/languages/zh-TW/settings.json delete mode 100644 src/languages/zh-TW/system.json delete mode 100644 src/lib/WolfClient.ts delete mode 100644 src/lib/api/ApiTransformers.ts delete mode 100644 src/lib/api/types.ts delete mode 100644 src/lib/api/utils.ts delete mode 100644 src/lib/database/index.ts delete mode 100644 src/lib/database/settings/Utils.ts delete mode 100644 src/lib/database/settings/auditActions.ts delete mode 100644 src/lib/database/settings/base/ISchemaValue.ts delete mode 100644 src/lib/database/settings/configuration.ts delete mode 100644 src/lib/database/settings/constants.ts delete mode 100644 src/lib/database/settings/context/SettingsContext.ts delete mode 100644 src/lib/database/settings/context/functions.ts delete mode 100644 src/lib/database/settings/functions.ts delete mode 100644 src/lib/database/settings/index.ts delete mode 100644 src/lib/database/settings/schema/SchemaGroup.ts delete mode 100644 src/lib/database/settings/schema/SchemaKey.ts delete mode 100644 src/lib/database/settings/structures/AdderManager.ts delete mode 100644 src/lib/database/settings/structures/AuditLogEnvelope.ts delete mode 100644 src/lib/database/settings/structures/AuditLogManager.ts delete mode 100644 src/lib/database/settings/structures/PermissionNodeManager.ts delete mode 100644 src/lib/database/settings/structures/Serializer.ts delete mode 100644 src/lib/database/settings/structures/SerializerStore.ts delete mode 100644 src/lib/database/settings/structures/collections/AliasedCollection.ts delete mode 100644 src/lib/database/settings/types.ts delete mode 100644 src/lib/database/utils/Adder.ts delete mode 100644 src/lib/database/utils/matchers/Command.ts delete mode 100644 src/lib/database/utils/matchers/index.ts delete mode 100644 src/lib/discord/Api.ts delete mode 100644 src/lib/discord/index.ts delete mode 100644 src/lib/games/HungerGamesUsage.ts delete mode 100644 src/lib/games/TriviaManager.ts delete mode 100644 src/lib/games/base/BaseBotController.ts delete mode 100644 src/lib/games/base/BaseController.ts delete mode 100644 src/lib/games/base/BaseGame.ts delete mode 100644 src/lib/games/base/BaseReactionController.ts delete mode 100644 src/lib/games/base/BaseReactionGame.ts delete mode 100644 src/lib/games/connect-four/ConnectFourBotController.ts delete mode 100644 src/lib/games/connect-four/ConnectFourGame.ts delete mode 100644 src/lib/games/connect-four/ConnectFourHumanController.ts delete mode 100644 src/lib/games/connect-four/lib/constants.ts delete mode 100644 src/lib/games/tic-tac-toe/TicTacToeBotController.ts delete mode 100644 src/lib/games/tic-tac-toe/TicTacToeGame.ts delete mode 100644 src/lib/games/tic-tac-toe/TicTacToeHumanController.ts delete mode 100644 src/lib/i18n/LanguageHelp.ts delete mode 100644 src/lib/i18n/index.ts delete mode 100644 src/lib/i18n/languageKeys/index.ts delete mode 100644 src/lib/i18n/languageKeys/keys/All.ts delete mode 100644 src/lib/i18n/languageKeys/keys/Commands.ts delete mode 100644 src/lib/i18n/languageKeys/keys/CustomCommandSerializer/All.ts delete mode 100644 src/lib/i18n/languageKeys/keys/DisabledCommandChannels/All.ts delete mode 100644 src/lib/i18n/languageKeys/keys/Errors.ts delete mode 100644 src/lib/i18n/languageKeys/keys/Moderation.ts delete mode 100644 src/lib/i18n/languageKeys/keys/Preconditions.ts delete mode 100644 src/lib/i18n/languageKeys/keys/System.ts delete mode 100644 src/lib/i18n/languageKeys/keys/commands/Admin.ts delete mode 100644 src/lib/i18n/languageKeys/keys/commands/AutoModeration.ts delete mode 100644 src/lib/i18n/languageKeys/keys/commands/Case.ts delete mode 100644 src/lib/i18n/languageKeys/keys/commands/Conf.ts delete mode 100644 src/lib/i18n/languageKeys/keys/commands/Fun.ts delete mode 100644 src/lib/i18n/languageKeys/keys/commands/Games.ts delete mode 100644 src/lib/i18n/languageKeys/keys/commands/General.ts delete mode 100644 src/lib/i18n/languageKeys/keys/commands/Info.ts delete mode 100644 src/lib/i18n/languageKeys/keys/commands/Permissions.ts delete mode 100644 src/lib/i18n/languageKeys/keys/commands/Shared.ts delete mode 100644 src/lib/i18n/languageKeys/keys/commands/Snipe.ts delete mode 100644 src/lib/i18n/languageKeys/keys/commands/System.ts delete mode 100644 src/lib/i18n/languageKeys/keys/commands/Tools.ts delete mode 100644 src/lib/i18n/languageKeys/keys/commands/Whois.ts delete mode 100644 src/lib/i18n/languageKeys/keys/events/All.ts delete mode 100644 src/lib/i18n/languageKeys/keys/events/guilds/All.ts delete mode 100644 src/lib/i18n/languageKeys/keys/events/guilds/Members.ts delete mode 100644 src/lib/i18n/languageKeys/keys/events/messages/All.ts delete mode 100644 src/lib/i18n/languageKeys/keys/events/moderation/All.ts delete mode 100644 src/lib/i18n/languageKeys/keys/events/reactions/All.ts delete mode 100644 src/lib/i18n/languageKeys/keys/settings/Channels.ts delete mode 100644 src/lib/i18n/structures/Handler.ts delete mode 100644 src/lib/i18n/translate.ts delete mode 100644 src/lib/moderation/actions/ModerationActionBan.ts delete mode 100644 src/lib/moderation/actions/ModerationActionKick.ts delete mode 100644 src/lib/moderation/actions/ModerationActionRestrictedAll.ts delete mode 100644 src/lib/moderation/actions/ModerationActionRestrictedAttachment.ts delete mode 100644 src/lib/moderation/actions/ModerationActionRestrictedEmbed.ts delete mode 100644 src/lib/moderation/actions/ModerationActionRestrictedEmoji.ts delete mode 100644 src/lib/moderation/actions/ModerationActionRestrictedReaction.ts delete mode 100644 src/lib/moderation/actions/ModerationActionRestrictedVoice.ts delete mode 100644 src/lib/moderation/actions/ModerationActionRoleAdd.ts delete mode 100644 src/lib/moderation/actions/ModerationActionRoleRemove.ts delete mode 100644 src/lib/moderation/actions/ModerationActionSetNickname.ts delete mode 100644 src/lib/moderation/actions/ModerationActionSoftBan.ts delete mode 100644 src/lib/moderation/actions/ModerationActionTimeout.ts delete mode 100644 src/lib/moderation/actions/ModerationActionVoiceKick.ts delete mode 100644 src/lib/moderation/actions/ModerationActionVoiceMute.ts delete mode 100644 src/lib/moderation/actions/ModerationActionWarning.ts delete mode 100644 src/lib/moderation/actions/base/ModerationAction.ts delete mode 100644 src/lib/moderation/actions/base/RoleModerationAction.ts delete mode 100644 src/lib/moderation/actions/index.ts delete mode 100644 src/lib/moderation/common/constants.ts delete mode 100644 src/lib/moderation/common/index.ts delete mode 100644 src/lib/moderation/common/util.ts delete mode 100644 src/lib/moderation/index.ts delete mode 100644 src/lib/moderation/managers/LoggerManager.ts delete mode 100644 src/lib/moderation/managers/ModerationManager.ts delete mode 100644 src/lib/moderation/managers/ModerationManagerEntry.ts delete mode 100644 src/lib/moderation/managers/StickyRoleManager.ts delete mode 100644 src/lib/moderation/managers/index.ts delete mode 100644 src/lib/moderation/managers/loggers/PruneLoggerTypeManager.ts delete mode 100644 src/lib/moderation/managers/loggers/TimeoutLoggerTypeManager.ts delete mode 100644 src/lib/moderation/managers/loggers/base/LoggerTypeManager.ts delete mode 100644 src/lib/moderation/managers/loggers/index.ts delete mode 100644 src/lib/moderation/structures/AutoModerationCommand.ts delete mode 100644 src/lib/moderation/structures/AutoModerationOnInfraction.ts delete mode 100644 src/lib/moderation/structures/ModerationCommand.ts delete mode 100644 src/lib/moderation/structures/ModerationListener.ts delete mode 100644 src/lib/moderation/structures/ModerationMessageListener.ts delete mode 100644 src/lib/moderation/structures/SetUpModerationCommand.ts delete mode 100644 src/lib/moderation/structures/index.ts delete mode 100644 src/lib/moderation/workers/index.ts delete mode 100644 src/lib/schedule/index.ts delete mode 100644 src/lib/schedule/manager/ScheduleEntry.ts delete mode 100644 src/lib/schedule/manager/ScheduleManager.ts delete mode 100644 src/lib/schedule/structures/Task.ts delete mode 100644 src/lib/schedule/structures/TaskStore.ts delete mode 100644 src/lib/setup/index.ts delete mode 100644 src/lib/setup/inspect.ts delete mode 100644 src/lib/setup/paginated-message.ts delete mode 100644 src/lib/setup/prisma.ts delete mode 100644 src/lib/structures/AnalyticsData.ts delete mode 100644 src/lib/structures/SettingsMenu.ts delete mode 100644 src/lib/structures/commands/ChannelConfigurationCommand.ts delete mode 100644 src/lib/structures/commands/WolfArgs.ts delete mode 100644 src/lib/structures/commands/WolfCommand.ts delete mode 100644 src/lib/structures/commands/WolfSubcommand.ts delete mode 100644 src/lib/structures/commands/base/BaseWolfCommandUtilities.ts delete mode 100644 src/lib/structures/commands/index.ts delete mode 100644 src/lib/structures/data/SortedCollection.ts delete mode 100644 src/lib/structures/data/index.ts delete mode 100644 src/lib/structures/index.ts delete mode 100644 src/lib/structures/listeners/AnalyticsListener.ts delete mode 100644 src/lib/structures/listeners/ShardListener.ts delete mode 100644 src/lib/structures/listeners/index.ts delete mode 100644 src/lib/structures/managers/index.ts delete mode 100644 src/lib/structures/preconditions/PermissionsPrecondition.ts delete mode 100644 src/lib/structures/preconditions/index.ts delete mode 100644 src/lib/types/AnalyticsSchema.ts delete mode 100644 src/lib/types/Augments.d.ts delete mode 100644 src/lib/types/Discord.ts delete mode 100644 src/lib/types/Enums.ts delete mode 100644 src/lib/types/Internals.ts delete mode 100644 src/lib/types/Utils.ts delete mode 100644 src/lib/types/index.ts delete mode 100644 src/lib/util/External/escapeMarkdown.ts delete mode 100644 src/lib/util/LongLivingInteractionCollector.ts delete mode 100644 src/lib/util/LongLivingReactionCollector.ts delete mode 100644 src/lib/util/Timers.ts delete mode 100644 src/lib/util/bits.ts delete mode 100644 src/lib/util/common/error.ts delete mode 100644 src/lib/util/common/guild.ts delete mode 100644 src/lib/util/common/index.ts delete mode 100644 src/lib/util/common/parse.ts delete mode 100644 src/lib/util/constants.ts delete mode 100644 src/lib/util/deprecate.ts delete mode 100644 src/lib/util/functions/auditLogEmbeds.ts delete mode 100644 src/lib/util/functions/channels.ts delete mode 100644 src/lib/util/functions/embeds.ts delete mode 100644 src/lib/util/functions/index.ts delete mode 100644 src/lib/util/functions/messages.ts delete mode 100644 src/lib/util/functions/permissions.ts delete mode 100644 src/lib/util/functions/pieces.ts delete mode 100644 src/lib/util/functions/users.ts delete mode 100644 src/lib/util/moderation-utilities.ts delete mode 100644 src/lib/util/moderationConstants.ts delete mode 100644 src/lib/util/resolvers/Case.ts delete mode 100644 src/lib/util/resolvers/TimeSpan.ts delete mode 100644 src/lib/util/resolvers/index.ts delete mode 100644 src/lib/util/util.ts delete mode 100644 src/listeners/analytics/analyticsSync.ts delete mode 100644 src/listeners/analytics/commandUsageAnalytics.ts delete mode 100644 src/listeners/analytics/guilds/guildCreateAnalytics.ts delete mode 100644 src/listeners/analytics/guilds/guildDeleteAnalytics.ts delete mode 100644 src/listeners/analytics/messages/messageAnalytics.ts delete mode 100644 src/listeners/analytics/resourceAnalyticsSync.ts delete mode 100644 src/listeners/commands/_chat-input-shared.ts delete mode 100644 src/listeners/commands/_command-log-shared.ts delete mode 100644 src/listeners/commands/_message-shared.ts delete mode 100644 src/listeners/commands/_shared.ts delete mode 100644 src/listeners/commands/chatInputCommandError.ts delete mode 100644 src/listeners/commands/chatInputCommandErrorCommandLog.ts delete mode 100644 src/listeners/commands/chatInputCommandSuccessAnalytics.ts delete mode 100644 src/listeners/commands/chatInputCommandSuccessCommandLog.ts delete mode 100644 src/listeners/commands/chatInputCommandSuccessLogger.ts delete mode 100644 src/listeners/commands/chatInputSubcommandError.ts delete mode 100644 src/listeners/commands/contextMenuCommandError.ts delete mode 100644 src/listeners/commands/contextMenuCommandErrorCommandLog.ts delete mode 100644 src/listeners/commands/contextMenuCommandSuccessAnalytics.ts delete mode 100644 src/listeners/commands/contextMenuCommandSuccessCommandLog.ts delete mode 100644 src/listeners/commands/contextMenuCommandSuccessLogger.ts delete mode 100644 src/listeners/commands/messageCommandError.ts delete mode 100644 src/listeners/commands/messageCommandErrorCommandLog.ts delete mode 100644 src/listeners/commands/messageCommandSuccessAnalytics.ts delete mode 100644 src/listeners/commands/messageCommandSuccessAutoDelete.ts delete mode 100644 src/listeners/commands/messageCommandSuccessCommandLog.ts delete mode 100644 src/listeners/commands/messageSubcommandError.ts delete mode 100644 src/listeners/guildMessageLog.ts delete mode 100644 src/listeners/guilds/bans/guildBanAdd.ts delete mode 100644 src/listeners/guilds/bans/guildBanRemove.ts delete mode 100644 src/listeners/guilds/channels/channelDeleteNotify.ts delete mode 100644 src/listeners/guilds/channels/voiceStateUpdateNotify.ts delete mode 100644 src/listeners/guilds/emojis/emojiCreateNotify.ts delete mode 100644 src/listeners/guilds/emojis/emojiDeleteNotify.ts delete mode 100644 src/listeners/guilds/members/guildMemberAdd.ts delete mode 100644 src/listeners/guilds/members/guildMemberUpdateTimeoutNotify.ts delete mode 100644 src/listeners/guilds/members/notMutedMemberAddInitialRole.ts delete mode 100644 src/listeners/guilds/members/notMutedMemberAddNotify.ts delete mode 100644 src/listeners/guilds/members/rawMemberRemoveNotify.ts delete mode 100644 src/listeners/guilds/rawGuildAuditLogEntryCreateLoggerTrack.ts delete mode 100644 src/listeners/guilds/rawGuildCreateMemberFetch.ts delete mode 100644 src/listeners/guilds/rawGuildDelete.ts delete mode 100644 src/listeners/guilds/rawGuildDeleteMemberFetch.ts delete mode 100644 src/listeners/guilds/roles/roleDelete.ts delete mode 100644 src/listeners/guilds/roles/roleDeleteNotify.ts delete mode 100644 src/listeners/guilds/roles/roleUpdate.ts delete mode 100644 src/listeners/interactions/interactionCreate.ts delete mode 100644 src/listeners/mentionPrefixOnly.ts delete mode 100644 src/listeners/mentionSpamExceeded.ts delete mode 100644 src/listeners/mentionSpamWarning.ts delete mode 100644 src/listeners/messages/rawMessageDeleteBulkNotify.ts delete mode 100644 src/listeners/messages/rawMessageDeleteNotify.ts delete mode 100644 src/listeners/messages/rawMessageUpdateNotify.ts delete mode 100644 src/listeners/moderation/moderationEntryAdd.ts delete mode 100644 src/listeners/moderation/moderationEntryEdit.ts delete mode 100644 src/listeners/reactions/rawReactionAddBlockList.ts delete mode 100644 src/listeners/reactions/rawReactionAddNotify.ts delete mode 100644 src/listeners/ready.ts delete mode 100644 src/listeners/shard/shardDisconnect.ts delete mode 100644 src/listeners/shard/shardError.ts delete mode 100644 src/listeners/shard/shardReady.ts delete mode 100644 src/listeners/shard/shardReconnecting.ts delete mode 100644 src/listeners/shard/shardResume.ts delete mode 100644 src/preconditions/Administrator.ts delete mode 100644 src/preconditions/BotOwner.ts delete mode 100644 src/preconditions/Enabled.ts delete mode 100644 src/preconditions/Everyone.ts delete mode 100644 src/preconditions/Moderator.ts delete mode 100644 src/preconditions/ServerOwner.ts delete mode 100644 src/routes/commands.get.ts delete mode 100644 src/routes/guilds/[guild]/audit-logs.get.ts delete mode 100644 src/routes/guilds/[guild]/command-logs.get.ts delete mode 100644 src/routes/guilds/[guild]/settings.get.ts delete mode 100644 src/routes/index.get.ts delete mode 100644 src/routes/languages.get.ts delete mode 100644 src/serializers/boolean.ts delete mode 100644 src/serializers/categoryortextchannel.ts delete mode 100644 src/serializers/channel.ts delete mode 100644 src/serializers/command.ts delete mode 100644 src/serializers/commandautodelete.ts delete mode 100644 src/serializers/commandmatch.ts delete mode 100644 src/serializers/disabledcommandchannel.ts delete mode 100644 src/serializers/emoji.ts delete mode 100644 src/serializers/guild.ts delete mode 100644 src/serializers/invite.ts delete mode 100644 src/serializers/language.ts delete mode 100644 src/serializers/notAllowed.ts delete mode 100644 src/serializers/number.ts delete mode 100644 src/serializers/permissionnode.ts delete mode 100644 src/serializers/reactionrole.ts delete mode 100644 src/serializers/role.ts delete mode 100644 src/serializers/snowflake.ts delete mode 100644 src/serializers/stickyrole.ts delete mode 100644 src/serializers/string.ts delete mode 100644 src/serializers/timespan.ts delete mode 100644 src/serializers/uniqueroleset.ts delete mode 100644 src/serializers/url.ts delete mode 100644 src/serializers/user.ts delete mode 100644 src/serializers/word.ts delete mode 100644 src/tasks/moderation/moderationEndAddRole.ts delete mode 100644 src/tasks/moderation/moderationEndBan.ts delete mode 100644 src/tasks/moderation/moderationEndMute.ts delete mode 100644 src/tasks/moderation/moderationEndRemoveRole.ts delete mode 100644 src/tasks/moderation/moderationEndRestrictionAttachment.ts delete mode 100644 src/tasks/moderation/moderationEndRestrictionEmbed.ts delete mode 100644 src/tasks/moderation/moderationEndRestrictionEmoji.ts delete mode 100644 src/tasks/moderation/moderationEndRestrictionReaction.ts delete mode 100644 src/tasks/moderation/moderationEndRestrictionVoice.ts delete mode 100644 src/tasks/moderation/moderationEndSetNickname.ts delete mode 100644 src/tasks/moderation/moderationEndTimeout.ts delete mode 100644 src/tasks/moderation/moderationEndVoiceMute.ts delete mode 100644 src/tasks/moderation/moderationEndWarning.ts delete mode 100644 src/tasks/syncResourceAnalytics.ts delete mode 100644 src/tsconfig.json delete mode 100644 tests/tsconfig.json delete mode 100644 tsdown.config.ts diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 1ccb73b57..d4ccf4da6 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -1,14 +1,25 @@ name: Code Scanning on: - push: - branches: - - main - pull_request: + push: + branches: + - main + pull_request: jobs: - CodeQL: - name: Analysis - uses: sapphiredev/.github/.github/workflows/reusable-codeql.yml@main + CodeQL: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3 with: - with-auto-build: false + submodules: true + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@3e7e3b32d0fb8283594bb0a76cc60a00918b0969 # tag=v2 + with: + languages: typescript + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@3e7e3b32d0fb8283594bb0a76cc60a00918b0969 # tag=v2 diff --git a/.github/workflows/continuous-delivery.yml b/.github/workflows/continuous-delivery.yml index d4307c4b5..b2c4b16cc 100644 --- a/.github/workflows/continuous-delivery.yml +++ b/.github/workflows/continuous-delivery.yml @@ -6,10 +6,12 @@ on: branches: - main paths: - - 'src/**' + - 'projects/**' - 'Dockerfile' - '.github/workflows/continuous-delivery.yml' - 'package.json' + - 'pnpm-lock.yaml' + permissions: contents: read packages: write diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 7675055cf..47e49124e 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -11,7 +11,6 @@ on: branches: - main -# cancel in-progress runs on new commits to same PR (github.event.number) concurrency: group: ${{ github.workflow }}-${{ github.event.number || github.sha }} cancel-in-progress: true @@ -47,7 +46,7 @@ jobs: steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/setup-node@48b55a011bda9f5c9604345a0b591c3020ee971a93 # v6.4.0 with: node-version: lts/* @@ -58,7 +57,7 @@ jobs: run: pnpm install --frozen-lockfile - name: Generate prisma types - run: pnpm prisma:generate + run: pnpm --filter wolfstar-shared prisma:generate - name: Build project run: pnpm build @@ -81,10 +80,10 @@ jobs: run: pnpm install --frozen-lockfile - name: Generate prisma types - run: pnpm prisma:generate + run: pnpm --filter wolfstar-shared prisma:generate - name: Run unit tests - run: pnpm test --coverage + run: pnpm test -- --coverage - name: Codecov Upload uses: codecov/codecov-action@v6 diff --git a/.github/workflows/update-tlds.yml b/.github/workflows/update-tlds.yml index 573282cc2..ee7e4b3f6 100644 --- a/.github/workflows/update-tlds.yml +++ b/.github/workflows/update-tlds.yml @@ -26,7 +26,7 @@ jobs: - name: Install dependencies run: pnpm install --frozen-lockfile - name: Run the TLD updater script - run: yarn scripts:tlds + run: pnpm scripts:tlds - name: Commit any changes and create a pull request env: GITHUB_USER: github-actions[bot] diff --git a/.gitignore b/.gitignore index 674286280..aa73e5638 100644 --- a/.gitignore +++ b/.gitignore @@ -16,7 +16,6 @@ coverage/ .env.development.local .env.test.local .env.production.local -/.env redis.local.conf # Ignore bwd folders @@ -38,7 +37,12 @@ gh # Ignore the "wiki" folder so we can checkout the wiki inside the same folder wiki/ -plans/ # Profiler data *.0x + +# Claude +.claude/state + +# Plans +plans/ diff --git a/.oxfmtrc.json b/.oxfmtrc.json index 4fe644a36..97ce8f24d 100644 --- a/.oxfmtrc.json +++ b/.oxfmtrc.json @@ -9,7 +9,7 @@ "trailingComma": "none", "useTabs": true, "sortPackageJson": false, - "ignorePatterns": ["src/languages/**/*.json", "dist/"], + "ignorePatterns": ["projects/**/src/languages/**/*.json", "dist/", "projects/**/dist/"], "overrides": [ { "files": ["README.md"], diff --git a/.oxlintrc.json b/.oxlintrc.json index b9a7f09e8..865394a8a 100644 --- a/.oxlintrc.json +++ b/.oxlintrc.json @@ -136,7 +136,14 @@ "unicorn/prefer-set-has": "off", "vitest/require-mock-type-parameters": "off" }, - "ignorePatterns": ["dist/**", "node_modules/**", "coverage/**", "src/languages/**/*.json", "src/lib/util/Links/TLDs.ts"], + "ignorePatterns": [ + "dist/**", + "node_modules/**", + "coverage/**", + "projects/**/dist/**", + "projects/**/src/languages/**/*.json", + "projects/bot/src/lib/util/Links/TLDs.ts" + ], "overrides": [ { "files": ["**/*.?([cm])ts"], diff --git a/crowdin.yml b/crowdin.yml index 36bcd7d29..a43edd085 100644 --- a/crowdin.yml +++ b/crowdin.yml @@ -1,9 +1,9 @@ -project_id: '686068' +project_id: '434340' api_token_env: 'CROWDIN_PERSONAL_TOKEN' pull_request_title: 'chore(i18n-crowdin): new crowdin translation 🌐' commit_message: 'chore(i18n-crowdin): new translations for %original_file_name% (%language%)' append_commit_message: false files: - - source: /src/languages/en-US/**/*.json - translation: /src/languages/%locale%/**/%original_file_name% + - source: /src/languages/en-US/**/*.json + translation: /src/languages/%locale%/**/%original_file_name% diff --git a/package.json b/package.json index 6961e2438..b91e62b77 100644 --- a/package.json +++ b/package.json @@ -1,130 +1,53 @@ { "name": "wolfstar", - "version": "6.3.0", + "version": "7.0.0", "description": "Multipurpose Discord Bot built on Sapphire Framework", "author": "WolfStar Project", "license": "Apache-2.0", - "main": "./dist/index.mjs", + "private": true, "type": "module", - "imports": { - "#utils/common": "./dist/lib/util/common/index.mjs", - "#utils/functions": "./dist/lib/util/functions/index.mjs", - "#utils/resolvers": "./dist/lib/util/resolvers/index.mjs", - "#utils/*": "./dist/lib/util/*.mjs", - "#lib/database/entities": "./dist/lib/database/entities/index.mjs", - "#lib/database/settings": "./dist/lib/database/settings/index.mjs", - "#lib/database": "./dist/lib/database/index.mjs", - "#lib/discord": "./dist/lib/discord/index.mjs", - "#lib/moderation/actions": "./dist/lib/moderation/actions/index.mjs", - "#lib/moderation/common": "./dist/lib/moderation/common/index.mjs", - "#lib/moderation/managers/loggers": "./dist/lib/moderation/managers/loggers/index.mjs", - "#lib/moderation/managers": "./dist/lib/moderation/managers/index.mjs", - "#lib/moderation/workers": "./dist/lib/moderation/workers/index.mjs", - "#lib/moderation": "./dist/lib/moderation/index.mjs", - "#lib/schedule": "./dist/lib/schedule/index.mjs", - "#lib/structures/data": "./dist/lib/structures/data/index.mjs", - "#lib/structures/managers": "./dist/lib/structures/managers/index.mjs", - "#lib/structures": "./dist/lib/structures/index.mjs", - "#lib/setup": "./dist/lib/setup/index.mjs", - "#lib/types": "./dist/lib/types/index.mjs", - "#lib/i18n/languageKeys": "./dist/lib/i18n/languageKeys/index.mjs", - "#lib/i18n": "./dist/lib/i18n/index.mjs", - "#lib/*": "./dist/lib/*.mjs", - "#generated/prisma": "./dist/generated/prisma/client.mjs", - "#languages": "./dist/languages/index.mjs", - "#root/*": "./dist/*.mjs" - }, "scripts": { - "build": "tsdown", - "dev": "pnpm build --onSuccess \"pnpm start\"", - "watch": "pnpm build --watch", - "watch:start": "pnpm build --watch --onSuccess \"pnpm start\"", - "prisma:generate": "pnpm prisma generate", - "clean": "node scripts/build/clean.mjs", - "start": "node --enable-source-maps dist/index.mjs", - "start:profiler:0x": "0x --collect-only dist/index.mjs", - "test": "vitest run", + "build": "pnpm -r run build", + "dev": "pnpm --filter wolfstar-bot dev", + "watch": "pnpm --filter wolfstar-bot watch", + "prisma:generate": "pnpm --filter wolfstar-shared prisma:generate", + "clean": "pnpm -r run clean", + "test": "vitest run --config vitest.config.ts", "lint:fix": "oxlint --fix && oxfmt", "lint": "oxlint && oxfmt --check", - "format": "prettier --write --log-level=warn \"{src,tests}/**/*.{js,mjs,ts,json}\"", + "format": "prettier --write --log-level=warn \"projects/**/*.{js,mjs,ts,json}\"", "audit:verify": "node scripts/audit-verify.mjs", "scripts:tlds": "node scripts/tlds.mjs", - "scripts:migration": "node scripts/migrations.mjs", - "dockerps": "pwsh -NoLogo ./.docker/control.ps1", "prepare": "husky" }, - "dependencies": { - "evlog": "^2.16.0", - "@discordjs/builders": "^1.14.1", - "@discordjs/collection": "^2.1.1", - "@discordjs/core": "^1.2.0", - "@influxdata/influxdb-client": "^1.35.0", - "@influxdata/influxdb-client-apis": "^1.35.0", - "@prisma/adapter-pg": "^7.8.0", - "@prisma/client": "^7.8.0", - "@rollup/plugin-alias": "^6.0.0", - "@sapphire/async-queue": "^1.5.5", - "@sapphire/bitfield": "^1.2.4", - "@sapphire/decorators": "^6.2.0", - "@sapphire/discord.js-utilities": "7.3.3", - "@sapphire/fetch": "^3.0.5", - "@sapphire/framework": "5.5.0", - "@sapphire/iterator-utilities": "^2.0.1", - "@sapphire/plugin-api": "^8.3.1", - "@sapphire/plugin-editable-commands": "^4.0.4", - "@sapphire/plugin-i18next": "^8.0.0", - "@sapphire/plugin-logger": "^4.1.0", - "@sapphire/plugin-subcommands": "^7.0.1", - "@sapphire/ratelimits": "^2.4.11", - "@sapphire/snowflake": "^3.5.5", - "@sapphire/stopwatch": "^1.5.4", - "@sapphire/time-utilities": "^1.7.14", - "@sapphire/utilities": "^3.18.2", - "@sentry/node": "^10.53.1", - "@skyra/ai": "^2.0.1", - "@skyra/char": "^1.0.3", - "@skyra/env-utilities": "^2.0.1", - "@skyra/jaro-winkler": "^1.1.1", - "bufferutil": "^4.1.0", - "colorette": "^2.0.20", - "confusables": "^1.1.1", - "diff": "^9.0.0", - "discord-api-types": "^0.38.34", - "discord.js": "~14.26.4", - "he": "^1.2.0", - "husky": "^9.1.7", - "pg": "^8.21.0", - "zlib-sync": "^0.1.10" - }, "devDependencies": { - "0x": "^6.0.0", "@commitlint/cli": "^20.5.3", "@commitlint/config-conventional": "^20.5.3", "@sapphire/prettier-config": "^2.0.0", "@sapphire/ts-config": "^5.0.3", - "@types/backoff": "^2.5.5", - "@types/diff": "^6.0.0", - "@types/he": "^1.2.3", "@types/node": "^22.8.7", - "@types/pg": "^8.20.0", - "@types/ws": "^8.18.1", "@vitest/coverage-v8": "^4.1.7", "cz-conventional-changelog": "^3.3.0", + "husky": "^9.1.7", "lint-staged": "^16.4.0", "oxfmt": "^0.51.0", "oxlint": "^1.66.0", "prettier": "^3.8.3", - "prisma": "^7.8.0", - "prisma-json-types-generator": "^5.0.0", + "prisma": "^4.1.1", "taze": "^19.13.0", - "tsdown": "^0.22.0", - "typescript": "^6.0.2", + "tsdown": "latest", + "typescript": "^4.7.4", + "vite": "^6.3.5", "vitest": "^4.1.7" }, "repository": { "type": "git", "url": "git+https://github.com/wolfstar-project/wolfstar.git" }, + "engines": { + "node": ">=24", + "pnpm": ">=10" + }, "commitlint": { "extends": [ "@commitlint/config-conventional" @@ -140,9 +63,5 @@ } }, "prettier": "@sapphire/prettier-config", - "packageManager": "pnpm@10.33.4", - "engines": { - "node": ">=24", - "pnpm": ">=10" - } + "packageManager": "pnpm@10.33.4" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e9985006b..0a957cced 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,142 +8,16 @@ settings: overrides: ansi-regex: ^5.0.1 discord-api-types: ^0.38.34 - minimist: ^1.2.8 + minimist: ^1.2.6 + vite: ^6.3.5 importers: .: - dependencies: - '@discordjs/builders': - specifier: ^1.14.1 - version: 1.14.1 - '@discordjs/collection': - specifier: ^2.1.1 - version: 2.1.1 - '@discordjs/core': - specifier: ^1.2.0 - version: 1.2.0(bufferutil@4.1.0) - '@influxdata/influxdb-client': - specifier: ^1.35.0 - version: 1.35.0 - '@influxdata/influxdb-client-apis': - specifier: ^1.35.0 - version: 1.35.0(@influxdata/influxdb-client@1.35.0) - '@prisma/adapter-pg': - specifier: ^7.8.0 - version: 7.8.0 - '@prisma/client': - specifier: ^7.8.0 - version: 7.8.0(prisma@7.8.0)(typescript@6.0.3) - '@rollup/plugin-alias': - specifier: ^6.0.0 - version: 6.0.0(rollup@4.60.3) - '@sapphire/async-queue': - specifier: ^1.5.5 - version: 1.5.5 - '@sapphire/bitfield': - specifier: ^1.2.4 - version: 1.2.4 - '@sapphire/decorators': - specifier: ^6.2.0 - version: 6.2.0 - '@sapphire/discord.js-utilities': - specifier: 7.3.3 - version: 7.3.3 - '@sapphire/fetch': - specifier: ^3.0.5 - version: 3.0.5 - '@sapphire/framework': - specifier: 5.5.0 - version: 5.5.0 - '@sapphire/iterator-utilities': - specifier: ^2.0.1 - version: 2.0.1 - '@sapphire/plugin-api': - specifier: ^8.3.1 - version: 8.3.1 - '@sapphire/plugin-editable-commands': - specifier: ^4.0.4 - version: 4.0.4 - '@sapphire/plugin-i18next': - specifier: ^8.0.0 - version: 8.0.0(typescript@6.0.3) - '@sapphire/plugin-logger': - specifier: ^4.1.0 - version: 4.1.0 - '@sapphire/plugin-subcommands': - specifier: ^7.0.1 - version: 7.0.1 - '@sapphire/ratelimits': - specifier: ^2.4.11 - version: 2.4.11 - '@sapphire/snowflake': - specifier: ^3.5.5 - version: 3.5.5 - '@sapphire/stopwatch': - specifier: ^1.5.4 - version: 1.5.4 - '@sapphire/time-utilities': - specifier: ^1.7.14 - version: 1.7.14 - '@sapphire/utilities': - specifier: ^3.18.2 - version: 3.18.2 - '@sentry/node': - specifier: ^10.53.1 - version: 10.53.1 - '@skyra/ai': - specifier: ^2.0.1 - version: 2.0.1 - '@skyra/char': - specifier: ^1.0.3 - version: 1.0.3 - '@skyra/env-utilities': - specifier: ^2.0.1 - version: 2.0.1 - '@skyra/jaro-winkler': - specifier: ^1.1.1 - version: 1.1.1 - bufferutil: - specifier: ^4.1.0 - version: 4.1.0 - colorette: - specifier: ^2.0.20 - version: 2.0.20 - confusables: - specifier: ^1.1.1 - version: 1.1.1 - diff: - specifier: ^9.0.0 - version: 9.0.0 - discord-api-types: - specifier: ^0.38.34 - version: 0.38.34 - discord.js: - specifier: ~14.26.4 - version: 14.26.4(bufferutil@4.1.0) - evlog: - specifier: ^2.16.0 - version: 2.16.0(hono@4.12.12)(ofetch@1.5.1)(react@19.2.5)(vite@7.2.4) - he: - specifier: ^1.2.0 - version: 1.2.0 - husky: - specifier: ^9.1.7 - version: 9.1.7 - pg: - specifier: ^8.21.0 - version: 8.21.0 - zlib-sync: - specifier: ^0.1.10 - version: 0.1.10 devDependencies: - 0x: - specifier: ^6.0.0 - version: 6.0.0 '@commitlint/cli': specifier: ^20.5.3 - version: 20.5.3(@types/node@22.19.1)(conventional-commits-parser@6.4.0)(typescript@6.0.3) + version: 20.5.3(@types/node@22.19.21)(conventional-commits-parser@6.4.0)(typescript@4.9.5) '@commitlint/config-conventional': specifier: ^20.5.3 version: 20.5.3 @@ -153,30 +27,18 @@ importers: '@sapphire/ts-config': specifier: ^5.0.3 version: 5.0.3 - '@types/backoff': - specifier: ^2.5.5 - version: 2.5.5 - '@types/diff': - specifier: ^6.0.0 - version: 6.0.0 - '@types/he': - specifier: ^1.2.3 - version: 1.2.3 '@types/node': specifier: ^22.8.7 - version: 22.19.1 - '@types/pg': - specifier: ^8.20.0 - version: 8.20.0 - '@types/ws': - specifier: ^8.18.1 - version: 8.18.1 + version: 22.19.21 '@vitest/coverage-v8': specifier: ^4.1.7 - version: 4.1.7(vitest@4.1.7) + version: 4.1.8(vitest@4.1.8) cz-conventional-changelog: specifier: ^3.3.0 - version: 3.3.0(@types/node@22.19.1)(typescript@6.0.3) + version: 3.3.0(@types/node@22.19.21)(typescript@4.9.5) + husky: + specifier: ^9.1.7 + version: 9.1.7 lint-staged: specifier: ^16.4.0 version: 16.4.0 @@ -185,90 +47,221 @@ importers: version: 0.51.0 oxlint: specifier: ^1.66.0 - version: 1.66.0 + version: 1.69.0 prettier: specifier: ^3.8.3 - version: 3.8.3 + version: 3.8.4 prisma: - specifier: ^7.8.0 - version: 7.8.0(@types/react@19.2.14)(magicast@0.5.2)(react-dom@19.2.5)(react@19.2.5)(typescript@6.0.3) - prisma-json-types-generator: - specifier: ^5.0.0 - version: 5.0.0(@prisma/client@7.8.0)(prisma@7.8.0)(typescript@6.0.3) + specifier: ^4.1.1 + version: 4.16.2 taze: specifier: ^19.13.0 - version: 19.13.0 + version: 19.14.1 tsdown: - specifier: ^0.22.0 - version: 0.22.0(typescript@6.0.3)(unrun@0.2.37) + specifier: latest + version: 0.22.2(typescript@4.9.5) typescript: - specifier: ^6.0.2 - version: 6.0.3 + specifier: ^4.7.4 + version: 4.9.5 + vite: + specifier: ^6.3.5 + version: 6.4.3(@types/node@22.19.21)(jiti@2.6.1)(yaml@2.9.0) vitest: specifier: ^4.1.7 - version: 4.1.7(@opentelemetry/api@1.9.1)(@types/node@22.19.1)(@vitest/coverage-v8@4.1.7)(vite@7.2.4) + version: 4.1.8(@opentelemetry/api@1.9.1)(@types/node@22.19.21)(@vitest/coverage-v8@4.1.8)(vite@6.4.3) -packages: + projects/bot: + dependencies: + '@discordjs/builders': + specifier: ^1.1.0 + version: 1.14.1 + '@discordjs/collection': + specifier: ^1.0.1 + version: 1.5.3 + '@prisma/client': + specifier: ^4.1.1 + version: 4.16.2(prisma@4.16.2) + '@sapphire/async-queue': + specifier: ^1.3.2 + version: 1.5.5 + '@sapphire/result': + specifier: ^2.1.1 + version: 2.8.0 + '@sapphire/utilities': + specifier: ^3.8.0 + version: 3.18.2 + '@sentry/integrations': + specifier: ^7.8.0 + version: 7.114.0 + '@sentry/node': + specifier: ^7.8.0 + version: 7.120.4 + '@skyra/char': + specifier: ^1.0.3 + version: 1.0.3 + '@skyra/jaro-winkler': + specifier: ^1.1.1 + version: 1.1.1 + '@wolfstar/env-utilities': + specifier: ^3.0.1 + version: 3.0.1 + '@wolfstar/http-framework': + specifier: ^3.0.1 + version: 3.0.1 + '@wolfstar/http-framework-i18n': + specifier: ^3.0.1 + version: 3.0.1 + '@wolfstar/shared-http-pieces': + specifier: ^3.0.1 + version: 3.0.1 + '@wolfstar/start-banner': + specifier: ^3.0.1 + version: 3.0.1 + colorette: + specifier: ^2.0.19 + version: 2.0.20 + discord-api-types: + specifier: ^0.38.34 + version: 0.38.48 + gradient-string: + specifier: ^2.0.1 + version: 2.0.2 + tslib: + specifier: ^2.4.0 + version: 2.8.1 + wolfstar-shared: + specifier: workspace:^ + version: link:../shared + devDependencies: + '@rollup/plugin-alias': + specifier: latest + version: 6.0.0(rollup@4.61.1) + '@sapphire/framework': + specifier: ^4.5.0 + version: 4.8.5 + discord.js: + specifier: ^14.14.1 + version: 14.26.4 + tsdown: + specifier: latest + version: 0.22.2(typescript@6.0.3) + typescript: + specifier: ^6.0.0 + version: 6.0.3 - 0x@6.0.0: - resolution: {integrity: sha512-4JrGHSPTaoEL3MZiKYH5BlNv67X2F48FmR3dKJZOoR/Z1CLVtVOwUb/n4PMf7B+sP9RPz+X50EbIFuwtfYguRQ==} - engines: {node: '>=8.5.0'} - hasBin: true + projects/gateway: + dependencies: + '@discordjs/rest': + specifier: ^1.0.1 + version: 1.7.1 + '@discordjs/ws': + specifier: ^0.2.0 + version: 0.2.0 + '@sapphire/utilities': + specifier: ^3.8.0 + version: 3.18.2 + '@wolfstar/env-utilities': + specifier: ^3.0.1 + version: 3.0.1 + '@wolfstar/start-banner': + specifier: ^3.0.1 + version: 3.0.1 + discord-api-types: + specifier: ^0.38.34 + version: 0.38.48 + gradient-string: + specifier: ^2.0.1 + version: 2.0.2 + wolfstar-shared: + specifier: workspace:^ + version: link:../shared + devDependencies: + typescript: + specifier: ^4.7.4 + version: 4.9.5 + + projects/shared: + dependencies: + '@discordjs/collection': + specifier: ^1.0.1 + version: 1.5.3 + '@sapphire/pieces': + specifier: ^3.3.5 + version: 3.10.0 + '@sapphire/result': + specifier: ^2.1.1 + version: 2.8.0 + '@sapphire/utilities': + specifier: ^3.8.0 + version: 3.18.2 + '@vladfrangu/async_event_emitter': + specifier: ^2.0.1 + version: 2.4.7 + discord-api-types: + specifier: ^0.38.34 + version: 0.38.48 + ioredis: + specifier: ^5.2.2 + version: 5.11.1 + ix: + specifier: ^5.0.0 + version: 5.0.0 + devDependencies: + typescript: + specifier: ^4.7.4 + version: 4.9.5 + +packages: '@antfu/ni@30.1.0': resolution: {integrity: sha512-3VuAbPjgY52rQNn4wABaXMhBU2Oq91uy6L8nX49eJ35OLI68CyckGU+HZxcaHix4ymuGM2nFL1D6sLpgODK5xw==} engines: {node: '>=20.19.0'} hasBin: true - '@babel/code-frame@7.27.1': - resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + '@babel/code-frame@7.29.7': + resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} engines: {node: '>=6.9.0'} - '@babel/generator@8.0.0-rc.5': - resolution: {integrity: sha512-nFZPWz3FHIS7y6rMIVoa/WBwjdutfIaRJIBQjzn+t3RnecZoRNlGmGcyR2wb0T/IgSd50Kz/6dG8/LvMCRunjg==} + '@babel/generator@8.0.0-rc.6': + resolution: {integrity: sha512-6mIzgVK8DgEzvIapoQwhXTMnnkuE4STQmVv9H03i/tZ2ml8oev3TRvZJgTenK2Bsq0YWNtzOrFdTyNzCMFtjJQ==} engines: {node: ^22.18.0 || >=24.11.0} - '@babel/helper-string-parser@7.27.1': - resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + '@babel/helper-string-parser@7.29.7': + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} engines: {node: '>=6.9.0'} - '@babel/helper-string-parser@8.0.0-rc.5': - resolution: {integrity: sha512-sN7R8rBvDurfaziNfDEIjIntlazmlkCDGO4SNl2RJ3wRCn+QxspLV7hzYAE8WWVd2joVuT8sUxeePdLp2idI1A==} + '@babel/helper-string-parser@8.0.0-rc.6': + resolution: {integrity: sha512-BCkFy+zN6kXQed3YOT7aJl93NfDSzQc3pBfsvTVPs9gU9X3V0aefEF5kwBT0E+mDWH9QgKaZstYUQN9VdQZT4g==} engines: {node: ^22.18.0 || >=24.11.0} - '@babel/helper-validator-identifier@7.28.5': - resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@8.0.0-rc.5': - resolution: {integrity: sha512-ehJDxHvtbZ85RtX/L2fi0h9AGsBNqB5Euv1EB8RMAvGYvD+2X+QbpzzOpbklnNXO+WSZJNOaetw2BBj27xsWVg==} + '@babel/helper-validator-identifier@8.0.0-rc.6': + resolution: {integrity: sha512-nVJ+1JcCgntv8d78rRo++o2wuODT0Irknx2BF8Np4Ft2CRgjLqIs4qzSZ8b66yGbBdMWGmZBO9WEZv1hhNiSpg==} engines: {node: ^22.18.0 || >=24.11.0} - '@babel/parser@7.29.3': - resolution: {integrity: sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==} + '@babel/parser@7.29.7': + resolution: {integrity: sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==} engines: {node: '>=6.0.0'} hasBin: true - '@babel/parser@8.0.0-rc.4': - resolution: {integrity: sha512-0S/1yefMa15N4i2v3t8Fw9pgMHhf2gF6Lc1UEXI96Ls6FNAjqvHHZouZ2ZS/deqLhbMFtmfVeFac6iTsvFbLwA==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - - '@babel/parser@8.0.0-rc.5': - resolution: {integrity: sha512-/Mfg83rK3+jsRbl4Vbd0jqxc6M1A1/WNFtgrowRM1unEsD3XcNnrBdMM0JWakd0/RN9lseQKwPduW1TiEwKOlQ==} + '@babel/parser@8.0.0-rc.6': + resolution: {integrity: sha512-rOS8IpdO7mQELkTPlCsTgPejO0bFuZdEDCGQJouYbYf9e1FLTym7Fei2pEjq8q7MWbX0ravcd7QQYKs1TxOuog==} engines: {node: ^22.18.0 || >=24.11.0} hasBin: true - '@babel/runtime@7.28.4': - resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} + '@babel/runtime@7.29.7': + resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==} engines: {node: '>=6.9.0'} - '@babel/types@7.29.0': - resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} + '@babel/types@7.29.7': + resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==} engines: {node: '>=6.9.0'} - '@babel/types@8.0.0-rc.5': - resolution: {integrity: sha512-JeSVu/m8x/zpp4CLjYHVNXuhEyOkhPXuxM8YOXjh6L4LlvQNKuUNOTo5KdBuKAcTDHw8DquToTaEkhsBqPXOaA==} + '@babel/types@8.0.0-rc.6': + resolution: {integrity: sha512-p7/ABylAYlexb31wtRdIfH9L9A0Z2T/9H6zAqzqndkY2PLkvNNc580wGhp/gGKN4Sp9sQvSkhc6Oga8/O+wTyw==} engines: {node: ^22.18.0 || >=24.11.0} '@bcoe/v8-coverage@1.0.2': @@ -284,14 +277,14 @@ packages: resolution: {integrity: sha512-j34Qqeaa152chJgz2ysyk0BCpHenJn1lV0Rx0VXf8k3ccQcED+48EZrzMvo9jLmJUyBrrBwvu89I+2er4gW7QQ==} engines: {node: '>=v18'} - '@commitlint/config-validator@20.0.0': - resolution: {integrity: sha512-BeyLMaRIJDdroJuYM2EGhDMGwVBMZna9UiIqV9hxj+J551Ctc6yoGuGSmghOy/qPhBSuhA6oMtbEiTmxECafsg==} - engines: {node: '>=v18'} - '@commitlint/config-validator@20.5.0': resolution: {integrity: sha512-T/Uh6iJUzyx7j35GmHWdIiGRQB+ouZDk0pwAaYq4SXgB54KZhFdJ0vYmxiW6AMYICTIWuyMxDBl1jK74oFp/Gw==} engines: {node: '>=v18'} + '@commitlint/config-validator@21.0.1': + resolution: {integrity: sha512-Zd2UFdndeMMaW2O96HK0tdfT4gOImUvidMpAd/pws2zZ4m1nrAZ/9b/v2JYuE8fs86GpXv9F7LNaIuCIWhY+pA==} + engines: {node: '>=22.12.0'} + '@commitlint/ensure@20.5.3': resolution: {integrity: sha512-4i4AgNvH62owG9MwSiWKrle7HGNpBHHdLnWFIp5fTsHUYe5kRuh15t08L/0pdbbrRk8JKXQxxN4hZQcn+szkrw==} engines: {node: '>=v18'} @@ -300,6 +293,10 @@ packages: resolution: {integrity: sha512-xyCoOShoPuPL44gVa+5EdZsBVao/pNzpQhkzq3RdtlFdKZtjWcLlUFQHSWBuhk5utKYykeJPSz2i8ABHQA+ZZw==} engines: {node: '>=v18'} + '@commitlint/execute-rule@21.0.1': + resolution: {integrity: sha512-RifH+FmImozKBE6mozhF4K3r2RRKP7SMi/Q/zLCmExtp5e05lhHOUYqGBlFBAGNHaZxU/WYw1XuugYK9jQzqnA==} + engines: {node: '>=22.12.0'} + '@commitlint/format@20.5.0': resolution: {integrity: sha512-TI9EwFU/qZWSK7a5qyXMpKPPv3qta7FO4tKW+Wt2al7sgMbLWTsAcDpX1cU8k16TRdsiiet9aOw0zpvRXNJu7Q==} engines: {node: '>=v18'} @@ -312,14 +309,14 @@ packages: resolution: {integrity: sha512-M7JbWBNr2gXKaPc4i/KipsuW1gkDHpj35KPjWtKy3Z+2AQw5wu1gBi1LIO0uoaij67CqY4K8PxPZSGens4evCw==} engines: {node: '>=v18'} - '@commitlint/load@20.1.0': - resolution: {integrity: sha512-qo9ER0XiAimATQR5QhvvzePfeDfApi/AFlC1G+YN+ZAY8/Ua6IRrDrxRvQAr+YXUKAxUsTDSp9KXeXLBPsNRWg==} - engines: {node: '>=v18'} - '@commitlint/load@20.5.3': resolution: {integrity: sha512-1FDZWuKyu98Myb8i7Tp31jPU2rZpOwAdYRyJcy2KoGg7Xk2A+bgHN8smhMaaNSNkmE8fwt53BokywZq8Gv/5XQ==} engines: {node: '>=v18'} + '@commitlint/load@21.0.2': + resolution: {integrity: sha512-lwUE70hN0/qE/ZRROhbaX65ly/FF12DrqfReLCESo37M0OQCFAf2jRS+2tSCSORq+bm4Kdju7qNDj46uc1QzTA==} + engines: {node: '>=22.12.0'} + '@commitlint/message@20.4.3': resolution: {integrity: sha512-6akwCYrzcrFcTYz9GyUaWlhisY4lmQ3KvrnabmhoeAV8nRH4dXJAh4+EUQ3uArtxxKQkvxJS78hNX2EU3USgxQ==} engines: {node: '>=v18'} @@ -332,14 +329,14 @@ packages: resolution: {integrity: sha512-JDEIJ2+GnWpK8QqwfmW7O42h0aycJEWNqcdkJnyzLD11nf9dW2dWLTVEa8Wtlo4IZFGLPATjR5neA5QlOvIH1w==} engines: {node: '>=v18'} - '@commitlint/resolve-extends@20.1.0': - resolution: {integrity: sha512-cxKXQrqHjZT3o+XPdqDCwOWVFQiae++uwd9dUBC7f2MdV58ons3uUvASdW7m55eat5sRiQ6xUHyMWMRm6atZWw==} - engines: {node: '>=v18'} - '@commitlint/resolve-extends@20.5.3': resolution: {integrity: sha512-+ogW9v/u9JqpvAgTrLra/YTFo0KkjU6iNblF89pPsj4NebNc+DAWctsludwezI8YnsjBmfHpApSwcXprN/f/ew==} engines: {node: '>=v18'} + '@commitlint/resolve-extends@21.0.1': + resolution: {integrity: sha512-0DhjYWL6uYrY16Efa032fYk3woGJDU4AGWiG1XXltT9AMUNYKyb5cIZU2ivbaMZ3+kKFqUjikD2cjh66Sbh/Sg==} + engines: {node: '>=22.12.0'} + '@commitlint/rules@20.5.3': resolution: {integrity: sha512-MPlMnb9D3wbszYMp+1hPtuhtPJndRo6I6yfkZVA4+jR8w7Kqp0u2u/Y+gzbaItx5Lltq5rw7FSZQWJMoXUC4NQ==} engines: {node: '>=v18'} @@ -352,14 +349,14 @@ packages: resolution: {integrity: sha512-qD9xfP6dFg5jQ3NMrOhG0/w5y3bBUsVGyJvXxdWEwBm8hyx4WOk3kKXw28T5czBYvyeCVJgJJ6aoJZUWDpaacQ==} engines: {node: '>=v18'} - '@commitlint/types@20.0.0': - resolution: {integrity: sha512-bVUNBqG6aznYcYjTjnc3+Cat/iBgbgpflxbIBTnsHTX0YVpnmINPEkSRWymT2Q8aSH3Y7aKnEbunilkYe8TybA==} - engines: {node: '>=v18'} - '@commitlint/types@20.5.0': resolution: {integrity: sha512-ZJoS8oSq2CAZEpc/YI9SulLrdiIyXeHb/OGqGrkUP6Q7YV+0ouNAa7GjqRdXeQPncHQIDz/jbCTlHScvYvO/gA==} engines: {node: '>=v18'} + '@commitlint/types@21.0.1': + resolution: {integrity: sha512-4u7w8jcoCUFWhjWnASYzZHAP34OqOtuFBN87nQmFvqda03YU0T6z+yB4w0gSAMpekiRqqGk5rt+qSlW+a2vSEg==} + engines: {node: '>=22.12.0'} + '@conventional-changelog/git-client@2.7.0': resolution: {integrity: sha512-j7A8/LBEQ+3rugMzPXoKYzyUPpw/0CBQCyvtTR7Lmu4olG4yRC/Tfkq79Mr3yuPs0SUitlO2HwGP3gitMJnRFw==} engines: {node: '>=18'} @@ -384,56 +381,42 @@ packages: resolution: {integrity: sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg==} engines: {node: '>=18'} - '@discordjs/core@1.2.0': - resolution: {integrity: sha512-Swnw6OJXkY+n+Kh/HjAsC52poaxSRRr+vFO7EzPtKJ7MF+3KyhfvsN2r4bH5NTvossoHPExw3Pcq+9pKwmK8/Q==} - engines: {node: '>=18'} - '@discordjs/formatters@0.6.2': resolution: {integrity: sha512-y4UPwWhH6vChKRkGdMB4odasUbHOUwy7KL+OVwF86PvT6QVOwElx+TiI1/6kcmcEe+g5YRXJFiXSXUdabqZOvQ==} engines: {node: '>=16.11.0'} - '@discordjs/rest@2.6.0': - resolution: {integrity: sha512-RDYrhmpB7mTvmCKcpj+pc5k7POKszS4E2O9TYc+U+Y4iaCP+r910QdO43qmpOja8LRr1RJ0b3U+CqVsnPqzf4w==} - engines: {node: '>=18'} + '@discordjs/rest@1.7.1': + resolution: {integrity: sha512-Ofa9UqT0U45G/eX86cURQnX7gzOJLG2oC28VhIk/G6IliYgQF7jFByBJEykPSHE4MxPhqCleYvmsrtfKh1nYmQ==} + engines: {node: '>=16.9.0'} '@discordjs/rest@2.6.1': resolution: {integrity: sha512-wwQdgjeaoYFiaG+atbqx6aJDpqW7JHAo0HrQkBTbYzM3/PJ3GweQIpgElNcGZ26DCUOXMyawYd0YF7vtr+fZXg==} engines: {node: '>=18'} - '@discordjs/util@1.1.1': - resolution: {integrity: sha512-eddz6UnOBEB1oITPinyrB2Pttej49M9FZQY8NxgEvc3tq6ZICZ19m70RsmzRdDHk80O9NoYN/25AqJl8vPVf/g==} - engines: {node: '>=18'} + '@discordjs/util@0.3.1': + resolution: {integrity: sha512-HxXKYKg7vohx2/OupUN/4Sd02Ev3PBJ5q0gtjdcvXb0ErCva8jNHWfe/v5sU3UKjIB/uxOhc+TDOnhqffj9pRA==} + engines: {node: '>=16.9.0'} '@discordjs/util@1.2.0': resolution: {integrity: sha512-3LKP7F2+atl9vJFhaBjn4nOaSWahZ/yWjOvA4e5pnXkt2qyXRCHLxoBQy81GFtLGCq7K9lPm9R517M1U+/90Qg==} engines: {node: '>=18'} + '@discordjs/ws@0.2.0': + resolution: {integrity: sha512-IYcxeWixOidlVwMIWh3xwac2n2V+8p47N4m6ZCjaHqJYHdVw/feK3zmsVYL7TEqpxrF1GHwoDp7DgI77yeEDFg==} + engines: {node: '>=16.9.0'} + '@discordjs/ws@1.2.3': resolution: {integrity: sha512-wPlQDxEmlDg5IxhJPuxXr3Vy9AjYq5xCvFWGJyD7w7Np8ZGu+Mc+97LCoEc/+AYCo2IDpKioiH0/c/mj5ZR9Uw==} engines: {node: '>=16.11.0'} - '@electric-sql/pglite-socket@0.1.1': - resolution: {integrity: sha512-p2hoXw3Z3LQHwTeikdZNsFBOvXGqKY2hk51BBw+8NKND8eoH+8LFOtW9Z8CQKmTJ2qqGYu82ipqiyFZOTTXNfw==} - hasBin: true - peerDependencies: - '@electric-sql/pglite': 0.4.1 - - '@electric-sql/pglite-tools@0.3.1': - resolution: {integrity: sha512-C+T3oivmy9bpQvSxVqXA1UDY8cB9Eb9vZHL9zxWwEUfDixbXv4G3r2LjoTdR33LD8aomR3O9ZXEO3XEwr/cUCA==} - peerDependencies: - '@electric-sql/pglite': 0.4.1 - - '@electric-sql/pglite@0.4.1': - resolution: {integrity: sha512-mZ9NzzUSYPOCnxHH1oAHPRzoMFJHY472raDKwXl/+6oPbpdJ7g8LsCN4FSaIIfkiCKHhb3iF/Zqo3NYxaIhU7Q==} + '@emnapi/core@1.11.0': + resolution: {integrity: sha512-l9Oo58x0HOP5znGzVhYW9U3e5wVuA4LAZU2AGezTmkhO1CgQRFDhDg4nneHsu/t3WniXg9QrG2nIXL/ZS8ln8Q==} - '@emnapi/core@1.10.0': - resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} + '@emnapi/runtime@1.11.0': + resolution: {integrity: sha512-55coeOFKHv1ywEcUXJtWU5f+Jr/W5tZDvZig8DLKSwUN1JpROQ4rk/SNOQiFWmaR/VKF4zuFyW1B8JduOSv6Pg==} - '@emnapi/runtime@1.10.0': - resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} - - '@emnapi/wasi-threads@1.2.1': - resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + '@emnapi/wasi-threads@1.2.2': + resolution: {integrity: sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==} '@esbuild/aix-ppc64@0.25.12': resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} @@ -591,27 +574,15 @@ packages: cpu: [x64] os: [win32] - '@fastify/otel@0.18.0': - resolution: {integrity: sha512-3TASCATfw+ctICSb4ymrv7iCm0qJ0N9CarB+CZ7zIJ7KqNbwI5JjyDL1/sxoC0ccTO1Zyd1iQ+oqncPg5FJXaA==} - peerDependencies: - '@opentelemetry/api': ^1.9.0 + '@fastify/busboy@2.1.1': + resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} + engines: {node: '>=14'} '@henrygd/queue@1.2.0': resolution: {integrity: sha512-jW/BLSTpcvExDhqJGxtIPgGr2O0IFF8XUNDwEbfCfhrXT8a4xztQ9Lv6U/vbYzYC0xVWn+3zv6YnLUh3bEFUKA==} - '@hono/node-server@1.19.11': - resolution: {integrity: sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g==} - engines: {node: '>=18.14.1'} - peerDependencies: - hono: ^4 - - '@influxdata/influxdb-client-apis@1.35.0': - resolution: {integrity: sha512-+7h6smVPHYBge2rNKgYh/5k+SriYvPMsoJDfbUiQt1vJtpWnElwgBDLDl7Cr6d9XPC+FCI9GP4GQEMv7y8WxdA==} - peerDependencies: - '@influxdata/influxdb-client': '*' - - '@influxdata/influxdb-client@1.35.0': - resolution: {integrity: sha512-woWMi8PDpPQpvTsRaUw4Ig+nOGS/CWwAwS66Fa1Vr/EkW+NEwxI8YfPBsdBMn33jK2Y86/qMiiuX/ROHIkJLTw==} + '@ioredis/commands@1.10.0': + resolution: {integrity: sha512-UmeW7z4LfctwoQ5wkhVzgq8tXkreED2xZGpX+Bg+zA+WJFZCT6c062AfCK/Dfk81xZnnwdhJCUMkitihRaoC2Q==} '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -626,196 +597,238 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - '@kurkle/color@0.3.4': - resolution: {integrity: sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==} - - '@napi-rs/wasm-runtime@1.1.4': - resolution: {integrity: sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==} + '@napi-rs/wasm-runtime@1.1.5': + resolution: {integrity: sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==} peerDependencies: '@emnapi/core': ^1.7.1 '@emnapi/runtime': ^1.7.1 - '@opentelemetry/api-logs@0.207.0': - resolution: {integrity: sha512-lAb0jQRVyleQQGiuuvCOTDVspc14nx6XJjP4FspJ1sNARo3Regq4ZZbrc3rN4b1TYSuUCvgH+UXUPug4SLOqEQ==} - engines: {node: '>=8.0.0'} + '@opentelemetry/api-logs@0.53.0': + resolution: {integrity: sha512-8HArjKx+RaAI8uEIgcORbZIPklyh1YLjPSBus8hjRmvLi6DeFzgOcdZ7KwPabKj8mXF8dX0hyfAyGfycz0DbFw==} + engines: {node: '>=14'} - '@opentelemetry/api-logs@0.212.0': - resolution: {integrity: sha512-TEEVrLbNROUkYY51sBJGk7lO/OLjuepch8+hmpM6ffMJQ2z/KVCjdHuCFX6fJj8OkJP2zckPjrJzQtXU3IAsFg==} - engines: {node: '>=8.0.0'} + '@opentelemetry/api-logs@0.57.1': + resolution: {integrity: sha512-I4PHczeujhQAQv6ZBzqHYEUiggZL4IdSMixtVD3EYqbdrjujE7kRfI5QohjlPoJm8BvenoW5YaTMWRrbpot6tg==} + engines: {node: '>=14'} - '@opentelemetry/api-logs@0.214.0': - resolution: {integrity: sha512-40lSJeqYO8Uz2Yj7u94/SJWE/wONa7rmMKjI1ZcIjgf3MHNHv1OZUCrCETGuaRF62d5pQD1wKIW+L4lmSMTzZA==} - engines: {node: '>=8.0.0'} + '@opentelemetry/api-logs@0.57.2': + resolution: {integrity: sha512-uIX52NnTM0iBh84MShlpouI7UKqkZ7MrUszTmaypHBu4r7NofznSnQRfJ+uUeDtQDj6w8eFGg5KBLDAwAPz1+A==} + engines: {node: '>=14'} '@opentelemetry/api@1.9.1': resolution: {integrity: sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==} engines: {node: '>=8.0.0'} - '@opentelemetry/core@2.6.1': - resolution: {integrity: sha512-8xHSGWpJP9wBxgBpnqGL0R3PbdWQndL1Qp50qrg71+B28zK5OQmUgcDKLJgzyAAV38t4tOyLMGDD60LneR5W8g==} - engines: {node: ^18.19.0 || >=20.6.0} + '@opentelemetry/context-async-hooks@1.30.1': + resolution: {integrity: sha512-s5vvxXPVdjqS3kTLKMeBMvop9hbWkwzBpu+mUO2M7sZtlkyDJGwFe33wRKnbaYDo8ExRVBIIdwIGrqpxHuKttA==} + engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' - '@opentelemetry/core@2.7.1': - resolution: {integrity: sha512-QAqIj32AtK6+pEVNG7EOVxHdE06RP+FM5qpiEJ4RtDcFIqKUZHYhl7/7UY5efhwmwNAg7j8QbJVBLxMerc0+gw==} - engines: {node: ^18.19.0 || >=20.6.0} + '@opentelemetry/core@1.30.1': + resolution: {integrity: sha512-OOCM2C/QIURhJMuKaekP3TRBxBKxG/TWWA0TL2J6nXUtDnuCtccy49LUJF8xPFXMX+0LMcxFpCo8M9cGY1W6rQ==} + engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' - '@opentelemetry/instrumentation-amqplib@0.61.0': - resolution: {integrity: sha512-mCKoyTGfRNisge4br0NpOFSy2Z1NnEW8hbCJdUDdJFHrPqVzc4IIBPA/vX0U+LUcQqrQvJX+HMIU0dbDRe0i0Q==} - engines: {node: ^18.19.0 || >=20.6.0} + '@opentelemetry/instrumentation-amqplib@0.46.1': + resolution: {integrity: sha512-AyXVnlCf/xV3K/rNumzKxZqsULyITJH6OVLiW6730JPRqWA7Zc9bvYoVNpN6iOpTU8CasH34SU/ksVJmObFibQ==} + engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-connect@0.57.0': - resolution: {integrity: sha512-FMEBChnI4FLN5TE9DHwfH7QpNir1JzXno1uz/TAucVdLCyrG0jTrKIcNHt/i30A0M2AunNBCkcd8Ei26dIPKdg==} - engines: {node: ^18.19.0 || >=20.6.0} + '@opentelemetry/instrumentation-connect@0.43.0': + resolution: {integrity: sha512-Q57JGpH6T4dkYHo9tKXONgLtxzsh1ZEW5M9A/OwKrZFyEpLqWgjhcZ3hIuVvDlhb426iDF1f9FPToV/mi5rpeA==} + engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-dataloader@0.31.0': - resolution: {integrity: sha512-f654tZFQXS5YeLDNb9KySrwtg7SnqZN119FauD7acBoTzuLduaiGTNz88ixcVSOOMGZ+EjJu/RFtx5klObC95g==} - engines: {node: ^18.19.0 || >=20.6.0} + '@opentelemetry/instrumentation-dataloader@0.16.0': + resolution: {integrity: sha512-88+qCHZC02up8PwKHk0UQKLLqGGURzS3hFQBZC7PnGwReuoKjHXS1o29H58S+QkXJpkTr2GACbx8j6mUoGjNPA==} + engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-fs@0.33.0': - resolution: {integrity: sha512-sCZWXGalQ01wr3tAhSR9ucqFJ0phidpAle6/17HVjD6gN8FLmZMK/8sKxdXYHy3PbnlV1P4zeiSVFNKpbFMNLA==} - engines: {node: ^18.19.0 || >=20.6.0} + '@opentelemetry/instrumentation-express@0.47.0': + resolution: {integrity: sha512-XFWVx6k0XlU8lu6cBlCa29ONtVt6ADEjmxtyAyeF2+rifk8uBJbk1La0yIVfI0DoKURGbaEDTNelaXG9l/lNNQ==} + engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-generic-pool@0.57.0': - resolution: {integrity: sha512-orhmlaK+ZIW9hKU+nHTbXrCSXZcH83AescTqmpamHRobRmYSQwRbD0a1odc0yAzuzOtxYiHiXAnpnIpaSSY7Ow==} - engines: {node: ^18.19.0 || >=20.6.0} + '@opentelemetry/instrumentation-fastify@0.44.1': + resolution: {integrity: sha512-RoVeMGKcNttNfXMSl6W4fsYoCAYP1vi6ZAWIGhBY+o7R9Y0afA7f9JJL0j8LHbyb0P0QhSYk+6O56OwI2k4iRQ==} + engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-graphql@0.62.0': - resolution: {integrity: sha512-3YNuLVPUxafXkH1jBAbGsKNsP3XVzcFDhCDCE3OqBwCwShlqQbLMRMFh1T/d5jaVZiGVmSsfof+ICKD2iOV8xg==} - engines: {node: ^18.19.0 || >=20.6.0} + '@opentelemetry/instrumentation-fs@0.19.0': + resolution: {integrity: sha512-JGwmHhBkRT2G/BYNV1aGI+bBjJu4fJUD/5/Jat0EWZa2ftrLV3YE8z84Fiij/wK32oMZ88eS8DI4ecLGZhpqsQ==} + engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-hapi@0.60.0': - resolution: {integrity: sha512-aNljZKYrEa7obLAxd1bCEDxF7kzCLGXTuTJZ8lMR9rIVEjmuKBXN1gfqpm/OB//Zc2zP4iIve1jBp7sr3mQV6w==} - engines: {node: ^18.19.0 || >=20.6.0} + '@opentelemetry/instrumentation-generic-pool@0.43.0': + resolution: {integrity: sha512-at8GceTtNxD1NfFKGAuwtqM41ot/TpcLh+YsGe4dhf7gvv1HW/ZWdq6nfRtS6UjIvZJOokViqLPJ3GVtZItAnQ==} + engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-http@0.214.0': - resolution: {integrity: sha512-FlkDhZDRjDJDcO2LcSCtjRpkal1NJ8y0fBqBhTvfAR3JSYY2jAIj1kSS5IjmEBt4c3aWv+u/lqLuoCDrrKCSKg==} - engines: {node: ^18.19.0 || >=20.6.0} + '@opentelemetry/instrumentation-graphql@0.47.0': + resolution: {integrity: sha512-Cc8SMf+nLqp0fi8oAnooNEfwZWFnzMiBHCGmDFYqmgjPylyLmi83b+NiTns/rKGwlErpW0AGPt0sMpkbNlzn8w==} + engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-kafkajs@0.23.0': - resolution: {integrity: sha512-4K+nVo+zI+aDz0Z85SObwbdixIbzS9moIuKJaYsdlzcHYnKOPtB7ya8r8Ezivy/GVIBHiKJVq4tv+BEkgOMLaQ==} - engines: {node: ^18.19.0 || >=20.6.0} + '@opentelemetry/instrumentation-hapi@0.45.1': + resolution: {integrity: sha512-VH6mU3YqAKTePPfUPwfq4/xr049774qWtfTuJqVHoVspCLiT3bW+fCQ1toZxt6cxRPYASoYaBsMA3CWo8B8rcw==} + engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-knex@0.58.0': - resolution: {integrity: sha512-Hc/o8fSsaWxZ8r1Yw4rNDLwTpUopTf4X32y4W6UhlHmW8Wizz8wfhgOKIelSeqFVTKBBPIDUOsQWuIMxBmu8Bw==} - engines: {node: ^18.19.0 || >=20.6.0} + '@opentelemetry/instrumentation-http@0.57.1': + resolution: {integrity: sha512-ThLmzAQDs7b/tdKI3BV2+yawuF09jF111OFsovqT1Qj3D8vjwKBwhi/rDE5xethwn4tSXtZcJ9hBsVAlWFQZ7g==} + engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-koa@0.62.0': - resolution: {integrity: sha512-uVip0VuGUQXZ+vFxkKxAUNq8qNl+VFlyHDh/U6IQ8COOEDfbEchdaHnpFrMYF3psZRUuoSIgb7xOeXj00RdwDA==} - engines: {node: ^18.19.0 || >=20.6.0} + '@opentelemetry/instrumentation-ioredis@0.47.0': + resolution: {integrity: sha512-4HqP9IBC8e7pW9p90P3q4ox0XlbLGme65YTrA3UTLvqvo4Z6b0puqZQP203YFu8m9rE/luLfaG7/xrwwqMUpJw==} + engines: {node: '>=14'} peerDependencies: - '@opentelemetry/api': ^1.9.0 + '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-lru-memoizer@0.58.0': - resolution: {integrity: sha512-6grM3TdMyHzlGY1cUA+mwoPueB1F3dYKgKtZIH6jOFXqfHAByyLTc+6PFjGM9tKh52CFBJaDwodNlL/Td39z7Q==} - engines: {node: ^18.19.0 || >=20.6.0} + '@opentelemetry/instrumentation-kafkajs@0.7.0': + resolution: {integrity: sha512-LB+3xiNzc034zHfCtgs4ITWhq6Xvdo8bsq7amR058jZlf2aXXDrN9SV4si4z2ya9QX4tz6r4eZJwDkXOp14/AQ==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-knex@0.44.0': + resolution: {integrity: sha512-SlT0+bLA0Lg3VthGje+bSZatlGHw/vwgQywx0R/5u9QC59FddTQSPJeWNw29M6f8ScORMeUOOTwihlQAn4GkJQ==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-koa@0.47.0': + resolution: {integrity: sha512-HFdvqf2+w8sWOuwtEXayGzdZ2vWpCKEQv5F7+2DSA74Te/Cv4rvb2E5So5/lh+ok4/RAIPuvCbCb/SHQFzMmbw==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-lru-memoizer@0.44.0': + resolution: {integrity: sha512-Tn7emHAlvYDFik3vGU0mdwvWJDwtITtkJ+5eT2cUquct6nIs+H8M47sqMJkCpyPe5QIBJoTOHxmc6mj9lz6zDw==} + engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-mongodb@0.67.0': - resolution: {integrity: sha512-1WJp5N1lYfHq2IhECOTewFs5Tf2NfUOwQRqs/rZdXKTezArMlucxgzAaqcgp3A3YREXopXTpXHsxZTGHjNhMdQ==} - engines: {node: ^18.19.0 || >=20.6.0} + '@opentelemetry/instrumentation-mongodb@0.51.0': + resolution: {integrity: sha512-cMKASxCX4aFxesoj3WK8uoQ0YUrRvnfxaO72QWI2xLu5ZtgX/QvdGBlU3Ehdond5eb74c2s1cqRQUIptBnKz1g==} + engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-mongoose@0.60.0': - resolution: {integrity: sha512-8BahAZpKsOoc+lrZGb7Ofn4g3z8qtp5IxDfvAVpKXsEheQN7ONMH5djT5ihy6yf8yyeQJGS0gXFfpEAEeEHqQg==} - engines: {node: ^18.19.0 || >=20.6.0} + '@opentelemetry/instrumentation-mongoose@0.46.0': + resolution: {integrity: sha512-mtVv6UeaaSaWTeZtLo4cx4P5/ING2obSqfWGItIFSunQBrYROfhuVe7wdIrFUs2RH1tn2YYpAJyMaRe/bnTTIQ==} + engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-mysql2@0.60.0': - resolution: {integrity: sha512-m/5d3bxQALllCzezYDk/6vajh0tj5OijMMvOZGr+qN1NMXm1dzMNwyJ0gNZW7Fo3YFRyj/jJMxIw+W7d525dlw==} - engines: {node: ^18.19.0 || >=20.6.0} + '@opentelemetry/instrumentation-mysql2@0.45.0': + resolution: {integrity: sha512-qLslv/EPuLj0IXFvcE3b0EqhWI8LKmrgRPIa4gUd8DllbBpqJAvLNJSv3cC6vWwovpbSI3bagNO/3Q2SuXv2xA==} + engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-mysql@0.60.0': - resolution: {integrity: sha512-08pO8GFPEIz2zquKDGteBZDNmwketdgH8hTe9rVYgW9kCJXq1Psj3wPQGx+VaX4ZJKCfPeoLMYup9+cxHvZyVQ==} - engines: {node: ^18.19.0 || >=20.6.0} + '@opentelemetry/instrumentation-mysql@0.45.0': + resolution: {integrity: sha512-tWWyymgwYcTwZ4t8/rLDfPYbOTF3oYB8SxnYMtIQ1zEf5uDm90Ku3i6U/vhaMyfHNlIHvDhvJh+qx5Nc4Z3Acg==} + engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-pg@0.66.0': - resolution: {integrity: sha512-KxfLGXBb7k2ueaPJfq2GXBDXBly8P+SpR/4Mj410hhNgmQF3sCqwXvUBQxZQkDAmsdBAoenM+yV1LhtsMRamcA==} - engines: {node: ^18.19.0 || >=20.6.0} + '@opentelemetry/instrumentation-nestjs-core@0.44.0': + resolution: {integrity: sha512-t16pQ7A4WYu1yyQJZhRKIfUNvl5PAaF2pEteLvgJb/BWdd1oNuU1rOYt4S825kMy+0q4ngiX281Ss9qiwHfxFQ==} + engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-tedious@0.33.0': - resolution: {integrity: sha512-Q6WQwAD01MMTub31GlejoiFACYNw26J426wyjvU7by7fDIr2nZXNW4vhTGs7i7F0TnXBO3xN688g1tdUgYwJ5w==} - engines: {node: ^18.19.0 || >=20.6.0} + '@opentelemetry/instrumentation-pg@0.50.0': + resolution: {integrity: sha512-TtLxDdYZmBhFswm8UIsrDjh/HFBeDXd4BLmE8h2MxirNHewLJ0VS9UUddKKEverb5Sm2qFVjqRjcU+8Iw4FJ3w==} + engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation@0.207.0': - resolution: {integrity: sha512-y6eeli9+TLKnznrR8AZlQMSJT7wILpXH+6EYq5Vf/4Ao+huI7EedxQHwRgVUOMLFbe7VFDvHJrX9/f4lcwnJsA==} - engines: {node: ^18.19.0 || >=20.6.0} + '@opentelemetry/instrumentation-redis-4@0.46.0': + resolution: {integrity: sha512-aTUWbzbFMFeRODn3720TZO0tsh/49T8H3h8vVnVKJ+yE36AeW38Uj/8zykQ/9nO8Vrtjr5yKuX3uMiG/W8FKNw==} + engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation@0.212.0': - resolution: {integrity: sha512-IyXmpNnifNouMOe0I/gX7ENfv2ZCNdYTF0FpCsoBcpbIHzk81Ww9rQTYTnvghszCg7qGrIhNvWC8dhEifgX9Jg==} - engines: {node: ^18.19.0 || >=20.6.0} + '@opentelemetry/instrumentation-tedious@0.18.0': + resolution: {integrity: sha512-9zhjDpUDOtD+coeADnYEJQ0IeLVCj7w/hqzIutdp5NqS1VqTAanaEfsEcSypyvYv5DX3YOsTUoF+nr2wDXPETA==} + engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation@0.214.0': - resolution: {integrity: sha512-MHqEX5Dk59cqVah5LiARMACku7jXSVk9iVDWOea4x3cr7VfdByeDCURK6o1lntT1JS/Tsovw01UJrBhN3/uC5w==} - engines: {node: ^18.19.0 || >=20.6.0} + '@opentelemetry/instrumentation-undici@0.10.0': + resolution: {integrity: sha512-vm+V255NGw9gaSsPD6CP0oGo8L55BffBc8KnxqsMuc6XiAD1L8SFNzsW0RHhxJFqy9CJaJh+YiJ5EHXuZ5rZBw==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.7.0 + + '@opentelemetry/instrumentation@0.53.0': + resolution: {integrity: sha512-DMwg0hy4wzf7K73JJtl95m/e0boSoWhH07rfvHvYzQtBD3Bmv0Wc1x733vyZBqmFm8OjJD0/pfiUg1W3JjFX0A==} + engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/resources@2.7.1': - resolution: {integrity: sha512-DeT6KKolmC4e/dRQvMQ/RwlnzhaqeiFOXY5ngoOPJ07GgVVKxZOg9EcrNZb5aTzUn+iCrJldAgOfQm1O/QfPAQ==} - engines: {node: ^18.19.0 || >=20.6.0} + '@opentelemetry/instrumentation@0.57.1': + resolution: {integrity: sha512-SgHEKXoVxOjc20ZYusPG3Fh+RLIZTSa4x8QtD3NfgAUDyqdFFS9W1F2ZVbZkqDCdyMcQG02Ok4duUGLHJXHgbA==} + engines: {node: '>=14'} peerDependencies: - '@opentelemetry/api': '>=1.3.0 <1.10.0' + '@opentelemetry/api': ^1.3.0 - '@opentelemetry/sdk-trace-base@2.7.1': - resolution: {integrity: sha512-NAYIlsF8MPUsKqJMiDQJTMPOmlbawC1Iz/omMLygZ1C9am8fTKYjTaI+OZM+WTY3t3Glo0wnOg/6/pac6RGPPw==} - engines: {node: ^18.19.0 || >=20.6.0} + '@opentelemetry/instrumentation@0.57.2': + resolution: {integrity: sha512-BdBGhQBh8IjZ2oIIX6F2/Q3LKm/FDDKi6ccYKcBTeilh6SNdNKveDOLk73BkSJjQLJk6qe4Yh+hHw1UPhCDdrg==} + engines: {node: '>=14'} peerDependencies: - '@opentelemetry/api': '>=1.3.0 <1.10.0' + '@opentelemetry/api': ^1.3.0 - '@opentelemetry/semantic-conventions@1.40.0': - resolution: {integrity: sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw==} + '@opentelemetry/redis-common@0.36.2': + resolution: {integrity: sha512-faYX1N0gpLhej/6nyp6bgRjzAKXn5GOEMYY7YhciSfCoITAktLUtQ36d24QEWNA1/WA1y6qQunCe0OhHRkVl9g==} engines: {node: '>=14'} - '@opentelemetry/sql-common@0.41.2': - resolution: {integrity: sha512-4mhWm3Z8z+i508zQJ7r6Xi7y4mmoJpdvH0fZPFRkWrdp5fq7hhZ2HhYokEOLkfqSMgPR4Z9EyB3DBkbKGOqZiQ==} - engines: {node: ^18.19.0 || >=20.6.0} + '@opentelemetry/resources@1.30.1': + resolution: {integrity: sha512-5UxZqiAgLYGFjS4s9qm5mBVo433u+dSPUFWVWXmLAD4wB65oMCoXaJP1KJa9DIYYMeHu3z4BZcStG3LC593cWA==} + engines: {node: '>=14'} peerDependencies: - '@opentelemetry/api': ^1.1.0 + '@opentelemetry/api': '>=1.0.0 <1.10.0' - '@oxc-project/types@0.127.0': - resolution: {integrity: sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==} + '@opentelemetry/sdk-trace-base@1.30.1': + resolution: {integrity: sha512-jVPgBbH1gCy2Lb7X0AVQ8XAfgg0pJ4nvl8/IiQA6nxOsPvS+0zMJaFSs2ltXe0J6C8dqjcnpyqINDJmU30+uOg==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/semantic-conventions@1.27.0': + resolution: {integrity: sha512-sAay1RrB+ONOem0OZanAR1ZI/k7yDpnOQSQmTMuGImUQb2y8EbSaCJ94FQluM74xoU03vlb2d2U90hZluL6nQg==} + engines: {node: '>=14'} + + '@opentelemetry/semantic-conventions@1.28.0': + resolution: {integrity: sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA==} + engines: {node: '>=14'} + + '@opentelemetry/semantic-conventions@1.41.1': + resolution: {integrity: sha512-/UhIkaZgPutTFmQ7RnIJGgDXZmtEJ7Dvi86xNTFWcnRxVRNk/aotsqDJYeEvDP+FSMB2SdW+pQzNMcWP0rwuNA==} + engines: {node: '>=14'} + + '@opentelemetry/sql-common@0.40.1': + resolution: {integrity: sha512-nSDlnHSqzC3pXn/wZEZVLuAuJ1MYMXPBwtv2qAbCa3847SaHItdE7SzUq/Jtb0KZmh1zfAbNi3AAMjztTT4Ugg==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.1.0 - '@oxc-project/types@0.132.0': - resolution: {integrity: sha512-FESMOxil5Se014ui/Eq8fT5uHJo6nIRwH0PfJrZJXs6Gek3ZVFOrpUv3YIZT20m+extU98Hg1Ym72U58rlsxUQ==} + '@oxc-project/types@0.135.0': + resolution: {integrity: sha512-wR+xRdFkUBMvcAjBJ2q2kcZM6d+DKu2NgoOyxZgYwZdLhmiv6+rnO8PZ/P68kMiZtIKm+pW7zyEJ4kSOs0vo+Q==} '@oxfmt/binding-android-arm-eabi@0.51.0': resolution: {integrity: sha512-Ni0sCqg5CIHaLIYFGj+ncbcumylvNC6FE4rfD0KfdmnWHbPJ+zev0qZCXKxy2hFVa0fYRK0yPzf5nzPbkZou7g==} @@ -939,479 +952,244 @@ packages: cpu: [x64] os: [win32] - '@oxlint/binding-android-arm-eabi@1.66.0': - resolution: {integrity: sha512-f7kq8N51T4phpzqfBpA2qaVTI/KrkCmNwaj3t/97I/WLTDI+UhlP5GL9eER+zVxBhtlx5rKXWByJU1/zDAvyaw==} + '@oxlint/binding-android-arm-eabi@1.69.0': + resolution: {integrity: sha512-DKQQbD5cZ/MYfDgDI7YGyGD9FSxABlsBsYFo5p26lloob543tP9+4N3guwdXIYJN+7HSZxLe8YJuwcOWw5qnHg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [android] - '@oxlint/binding-android-arm64@1.66.0': - resolution: {integrity: sha512-xu6QO71tdDS9mjmLZ3AqhtaVHBvdmsOKkYnReNNDgh+XiwnsipeQOIxbiYOOO0iAXycJ+GK0wdMSZP/2j/AmSg==} + '@oxlint/binding-android-arm64@1.69.0': + resolution: {integrity: sha512-lEhb+I5pr4inux+JFwfCa1HRq3Os7NirEFQ0H1I35SVEHPm6byX0Ah47xmRha3qi6LAkxUcxViL8o/9PivjzBg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@oxlint/binding-darwin-arm64@1.66.0': - resolution: {integrity: sha512-HZ24VimSOC7mxuEA99e0H2FS0C1yO3+iW13jPRAk+e2njsUs3QeAXsafCDyaIrV/MirdOVez+etQNQsJE43zNQ==} + '@oxlint/binding-darwin-arm64@1.69.0': + resolution: {integrity: sha512-GY2YE8lOZW59BW1Ia1y+1gR0XyjrZRvVWHAr8LGeGhYHE0OQJ/7cRKXTkx1P+E9/6awEc3SX8a68SFTjh/E//A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@oxlint/binding-darwin-x64@1.66.0': - resolution: {integrity: sha512-awhj8ZvJrrRSnXj7V++rpZvTmnl99L6mi0B7gg7Cp7BN6cKpzuI481bHNLvXGA9GB1/oEgA3ponuyoAc6Md12A==} + '@oxlint/binding-darwin-x64@1.69.0': + resolution: {integrity: sha512-ax1oZnOjHX3LB7myQyHEaQkDwfLb6str3/nSP6O7EVUviQGNkEGzGV0EqcBJWK+Ufwx0l4xPgyYayurvhAdl2Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@oxlint/binding-freebsd-x64@1.66.0': - resolution: {integrity: sha512-KQF0oVV21/FjIqkRuL8Q1vh8ECsE5+ocdH5tcqTQ4ZnYuDVoYibQUNfqBjQaUsP6UIIda5Y75Wpm5p4RgQWiWw==} + '@oxlint/binding-freebsd-x64@1.69.0': + resolution: {integrity: sha512-kHWeHv4g2h8NY+mpCxzCtY4uerMJWTN/TSnNj1CPbakFpHEJ6cTya2wWV0pDSYWOJ2+0UiEbhn3AtXxHtsnKjg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@oxlint/binding-linux-arm-gnueabihf@1.66.0': - resolution: {integrity: sha512-9u1rgwZSEXWb30vbFZzQ78HVXBo0WCKNwJ3a2InRUTNMRng+PUDIoSFmA+m4HdUfBaIqftShq8J8qHc+eE/Vig==} + '@oxlint/binding-linux-arm-gnueabihf@1.69.0': + resolution: {integrity: sha512-gq84vM1a1oEehXo27YCDzGVcxPsZDI1yswZwz2Da1/cbnWtrL16XZZnz0G/+gIU8edtHpfjxq5c+vWEHqJfWoQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxlint/binding-linux-arm-musleabihf@1.66.0': - resolution: {integrity: sha512-Ynot2HR1bHxUaNWoC280MVTDfZuaWuP3XfSMRDhyuZrVjhzoaBCVFlw8h8qeZjWKVUBhPWFIxB7AQTlK8Z2WWg==} + '@oxlint/binding-linux-arm-musleabihf@1.69.0': + resolution: {integrity: sha512-kIqEa98JQ0VRyrcncxA417m2AzasqTlD+FyVT1AksjvjkqQcvm7pBWYvoW3/mpyOP2XYvi5nSCCTIe6De1yu5g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxlint/binding-linux-arm64-gnu@1.66.0': - resolution: {integrity: sha512-xCbgzciGgo+A4aQZEknsNrNiIwY7sU5SfRuMmRjPIvZAgdF34cIHiKvwOsS5XRLjlTVSFwitmq6YclTtHTfU+g==} + '@oxlint/binding-linux-arm64-gnu@1.69.0': + resolution: {integrity: sha512-j+xYiXozxGWx2cpjCrwwGR4awTxPFsRv3JZrv23RCogEPMc4R7UqjHW47p/RG0aRlbWiROCJ8coUfCwy0dvzHA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-arm64-musl@1.66.0': - resolution: {integrity: sha512-hmo+ZB/lHkR1HdDmnziNpzSLmulnUSu10VEqX2Yex7OwvoBAbjJQLvy4gIBRV3AAwWnCvAxKp5Nv1GE6LU1QMg==} + '@oxlint/binding-linux-arm64-musl@1.69.0': + resolution: {integrity: sha512-xEPpNppTfN1l/nM7gYSf9iocscu/as+p/7vxkLeLEKnYU+09Dm+5V6IhDYDh+Uz6FajEupWwCLt5SOG0y1PCKg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@oxlint/binding-linux-ppc64-gnu@1.66.0': - resolution: {integrity: sha512-2Invd4Uyy81mVooQC5FBtfxSNrvcX1OxbMlVQ6M2erRrNI2awFYF26YNW2yFxdVFZ4ffNOWKghtMjhnUPsXsVA==} + '@oxlint/binding-linux-ppc64-gnu@1.69.0': + resolution: {integrity: sha512-Ug0+eU7HJBlek+SjklYH62IlOMirEJsdxpihH0kSqX0XdrDD4NdHpQc10fK1JC35yn6KrrcN+uYzlHD38XAf8Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-riscv64-gnu@1.66.0': - resolution: {integrity: sha512-s0iXPDQVdgayE3RGa/N2DZF7tjgg0TwEtD1sGoDxqPDGrIXgo45H0yHknT0f9A0yteASsweYZtDyTuVlM4aSag==} + '@oxlint/binding-linux-riscv64-gnu@1.69.0': + resolution: {integrity: sha512-iEyI3GIg0l/s3G4qy2TlaaWKdzj4PJJStwtlocpDTC00PY9hZueotf6OKUj9+yfQh0lrpBW/pLMgTztbAHKJEg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-riscv64-musl@1.66.0': - resolution: {integrity: sha512-OekL4XFiu7RPK0JIZi8VeHgtIXPREf42t8Cy/rKEsC+P3gcqDgNAAGiyuUOpdbG4wwbfue1q4CHcCO7spSve6w==} + '@oxlint/binding-linux-riscv64-musl@1.69.0': + resolution: {integrity: sha512-NjHjpiI4WIKSMwuoJSZi5VToPeoYOS1FR52HLIDG6lidMdqquusgtODb4iLk0+lb1q3Z0nv2/aPRcC/olmpQGg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [musl] - '@oxlint/binding-linux-s390x-gnu@1.66.0': - resolution: {integrity: sha512-Ga1D0kj1SFslm34ThA/BdkUlyAYEnTsXyRC4pF0C5agZSwtGdHYWMTQWemUfBGp4RCG4QWXgdO+HmmmKqOtlBg==} + '@oxlint/binding-linux-s390x-gnu@1.69.0': + resolution: {integrity: sha512-Ai/prDewoItkDXbp38gwGZi41DycZbUTZJ3UidwoHgQC0/DaqC2TGdtBTQLJ6hSD+SAxASzh8+/eSBPmxfOacA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@oxlint/binding-linux-x64-gnu@1.66.0': - resolution: {integrity: sha512-p5jfP1wUZe/IC3qpQO84n9DRnf9g3lKRtLBlQq23ykyrDglHcVx7sWmVTlPuU6SBw8mNnPzyOn022G3XZHnlww==} + '@oxlint/binding-linux-x64-gnu@1.69.0': + resolution: {integrity: sha512-Gt3KHgp46mRKz4sJeaASmKvD8ayXookRw07RMf+NowhEztGGDZ7VrXpoW96XuKJLjFukWizOFVNjmYb/u7caNQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@oxlint/binding-linux-x64-musl@1.66.0': - resolution: {integrity: sha512-vUB/sYlYZorDL1ZD+o9mRv7zbsykrrFRtmgS6R8musZqLtrPRQn1gc1eGpuX+sfdccz42STl/AqldY6XRb2upQ==} + '@oxlint/binding-linux-x64-musl@1.69.0': + resolution: {integrity: sha512-7tQhJ2+p/oHv1zcfnjYI7YVzC/7iBaVOfIvFYtxdJ5F45mWgEdrCyXZXZGfiLey5t/5JhOhsaMnnv1kAzckd7g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@oxlint/binding-openharmony-arm64@1.66.0': - resolution: {integrity: sha512-yde+6p/F59xRkGR9H1HfngWRif1QRJjynZK349l+UI0H6w9hL3G8/AVaTHFyTtLVQ56qtNbX2/5Dc77n1ovnOg==} + '@oxlint/binding-openharmony-arm64@1.69.0': + resolution: {integrity: sha512-vmWz6TKp/3hfA4lksR0zHBv/6xuX1jhym6eqOjdH2DXsDDHZWcp2f0KG0VCAnlVbIrjk29G4wAWMXb/Hn1YobA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@oxlint/binding-win32-arm64-msvc@1.66.0': - resolution: {integrity: sha512-O9GLucgoTdmOrbBX+EjzNe7o/Ze5TFOvXcib6bzUOtBOmj6cV+zw18NgB+cGKAkDw1Pdqs8vGkfHbbsLuDtXWg==} + '@oxlint/binding-win32-arm64-msvc@1.69.0': + resolution: {integrity: sha512-9RExaLgmaw6IoIkU9cTpT71mLfI0xZ86iZH8x518LVsOkjquJMYqb9P7KpC8lgd1t0Dxs41p2pxynq4XR3Ttzw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@oxlint/binding-win32-ia32-msvc@1.66.0': - resolution: {integrity: sha512-m3Pjwc2MfTcom4E4gOv7DyuGyt7OfGNCbmqDHd+N7EzXmP+ppHuudm2NjcA3AjV5TSeGxaguVF4SbTKHe1USYA==} + '@oxlint/binding-win32-ia32-msvc@1.69.0': + resolution: {integrity: sha512-1907kRPF8/PrcIw1E7LMs9JbVrpgnt/MvFdss3an8oDkYNAACXzTntV3t3869ZZhMZxb2AzRGbz1pA/jdFatXA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ia32] os: [win32] - '@oxlint/binding-win32-x64-msvc@1.66.0': - resolution: {integrity: sha512-/DbBvw8UFBhja6PqudUjV4UtfsJr0Oa7jUjWVKB0g86lj/VwnPrkngn0sFql3c9RDA0O16dh7ozsXb6GjNAzBQ==} + '@oxlint/binding-win32-x64-msvc@1.69.0': + resolution: {integrity: sha512-w8SOXv3mT9Fi6jY8OXdXCfnvX/3KNLXGNr4HEz2TA7S4Mv/PYAOmpB8y/ge40mxvBMgGNaSaaDwZpAsQn7HtWA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] - '@pkgr/core@0.2.9': - resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} - engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - - '@prisma/adapter-pg@7.8.0': - resolution: {integrity: sha512-ygb3UkerK3v8MDpXVgCISdRNDozpxh6+JVJgiIGbSr5KBgz10LLf5ejUskPGoXlsIjxsOu6nuy1JVQr2EKGSlg==} - - '@prisma/client-runtime-utils@7.8.0': - resolution: {integrity: sha512-5NQZztQ0oY/ADFkmd9gPuweH5A1/CCY8YQPorLLO0Mu6a87mY5gsnDkzmFmIHs9NFaLnZojzgddFVN4RpKYrdw==} - - '@prisma/client@7.8.0': - resolution: {integrity: sha512-HFp3Dawv/3sU3JtlPha90IB+48lS7zHiH4LKZPjmcE8YH5P9DOXGPvo8dqOtO7MqLDd1p2hOWMcFlRT1DMblHw==} - engines: {node: ^20.19 || ^22.12 || >=24.0} + '@prisma/client@4.16.2': + resolution: {integrity: sha512-qCoEyxv1ZrQ4bKy39GnylE8Zq31IRmm8bNhNbZx7bF2cU5aiCCnSa93J2imF88MBjn7J9eUQneNxUQVJdl/rPQ==} + engines: {node: '>=14.17'} peerDependencies: prisma: '*' - typescript: '>=5.4.0' peerDependenciesMeta: prisma: optional: true - typescript: - optional: true - '@prisma/config@7.8.0': - resolution: {integrity: sha512-HFESzd9rx2ZQxlK+TL7tu1HPvCqrHiL6LCxYykI2c34mvaUuIVVl3lYuicJD/MNnzgPnyeBEMlK4WTomJCV5jw==} + '@prisma/engines-version@4.16.1-1.4bc8b6e1b66cb932731fb1bdbbc550d1e010de81': + resolution: {integrity: sha512-q617EUWfRIDTriWADZ4YiWRZXCa/WuhNgLTVd+HqWLffjMSPzyM5uOWoauX91wvQClSKZU4pzI4JJLQ9Kl62Qg==} - '@prisma/debug@7.2.0': - resolution: {integrity: sha512-YSGTiSlBAVJPzX4ONZmMotL+ozJwQjRmZweQNIq/ER0tQJKJynNkRB3kyvt37eOfsbMCXk3gnLF6J9OJ4QWftw==} + '@prisma/engines@4.16.2': + resolution: {integrity: sha512-vx1nxVvN4QeT/cepQce68deh/Turxy5Mr+4L4zClFuK1GlxN3+ivxfuv+ej/gvidWn1cE1uAhW7ALLNlYbRUAw==} - '@prisma/debug@7.8.0': - resolution: {integrity: sha512-p+QZReysDUqXC+mk17q9a+Y/qzh4c2KYliDK30buYUyfrGeTGSyfmc0AIrJRhZJrLHhRiJa9Au/J72h3C+szvA==} + '@prisma/instrumentation@5.22.0': + resolution: {integrity: sha512-LxccF392NN37ISGxIurUljZSh1YWnphO34V5a0+T7FVQG2u9bhAXRTJpgmQ3483woVhkraQZFF7cbRrpbw/F4Q==} - '@prisma/dev@0.24.3': - resolution: {integrity: sha512-ffHlQuKXZiaDt9Go0OnCTdJZrHxK0k7omJKNV86/VjpsXu5EIHZLK0T7JSWgvNlJwh56kW9JFu9v0qJciFzepg==} + '@quansync/fs@1.0.0': + resolution: {integrity: sha512-4TJ3DFtlf1L5LDMaM6CanJ/0lckGNtJcMjQ1NAV6zDmA0tEHKZtxNKin8EgPaVX1YzljbxckyT2tJrpQKAtngQ==} - '@prisma/dmmf@7.8.0': - resolution: {integrity: sha512-7xzcSFWO6J+dFUgIX7jL7QqUhEDfaa8GSZGsjjHyZct1Su+6KrvMl3S2+fnRkuKUIoTPg3Mj02oZuUdaNSfsaw==} + '@rolldown/binding-android-arm64@1.1.1': + resolution: {integrity: sha512-BLf9Wak/gfwVb7NQTQW4wBgL3oAfPy7ArEkhwV543OVw/uY6B47z5xYsqPSZ9PDOorvURPinws6ThaFuNgGLgA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] - '@prisma/driver-adapter-utils@7.8.0': - resolution: {integrity: sha512-/Q13o0ZT0rjc1Xk0Q9KhZYwuq2EW/vSbWUBKfgEKkaCuB/Sg6bqnjmTZqC5cD4d6y1vfFAEwBRzfzoSMIVJ55A==} + '@rolldown/binding-darwin-arm64@1.1.1': + resolution: {integrity: sha512-rRZRPy/Ynb+Mxu0O6tfPldHeDgAn0sRij+IOUy6sFdUlv3hArGW/DloE3GfAxtqpOJuRNgF74Nr5gM4xBeU2jQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] - '@prisma/engines-version@7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a': - resolution: {integrity: sha512-fJPQxCkLgA5EayWaW8eArgCvjJ+N+Kz3VyeNKMEeYiQC4alNkxRKFVAGxv/ZUzuJISKqdw+zGeDbS6mn6RCPOA==} + '@rolldown/binding-darwin-x64@1.1.1': + resolution: {integrity: sha512-/MtefPxhKPyWWFM8L45OWiEqRf+eSU2Qv9ZAyTaoZOoGcoPKxbbhjTJO2/U2IThv0uDZ4NWHc3/oTsR6IEOtww==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] - '@prisma/engines@7.8.0': - resolution: {integrity: sha512-jx3rCnNNrt5uzbkKlegtQ2GZHxSlihMCzutgT/BP6UIDF1r9tDI39hV/0T/cHZgzJ3ELbuQPXlVZy+Y1n0pcgw==} + '@rolldown/binding-freebsd-x64@1.1.1': + resolution: {integrity: sha512-202K+cpIi1kx/Zn7AtxBi4LTXSY67Aszb2K9rNsuW7FeBeh0nqoNmYLOSZidV0p88VPBzMmTZcHAdPNo3kRYzQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] - '@prisma/fetch-engine@7.8.0': - resolution: {integrity: sha512-gwB0Euiz/DDRyxFRpLXYlK3RfaZUj1c5dAYMuhZYfApg7arknJlcb9bIsOHDppJmbqYaVA+yBIiFMDBfprsNPQ==} + '@rolldown/binding-linux-arm-gnueabihf@1.1.1': + resolution: {integrity: sha512-wl9NfeXNUwrXtUc063tddmZFUI6qiNs1CNOwni0OL4vC7MqVSYugra3ZgtDmtVy8e0DluJTENmzIv2BwqLzT4Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] - '@prisma/generator-helper@7.8.0': - resolution: {integrity: sha512-i+2Gad6D/0dS0YHKFdYX3M8KYN1gwNkET813WXKfW2HeWmgipmSJsNSzOA44kTM+Rx6Dev3yBQwx5sZXXdtgtQ==} + '@rolldown/binding-linux-arm64-gnu@1.1.1': + resolution: {integrity: sha512-at2EO4o7D/PJLC4Xik16bU4CcjQE2tSv1LfqMA0TRYQYQihRm3gZeDB8xaX28A9SFedibcAk5DeMCKt4REKG0A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] - '@prisma/generator@7.8.0': - resolution: {integrity: sha512-KHGB0b8/9pNWyiK9EPJNE2/v1bMtqJgJldqjNNVvoE4uOhNSSWTmhHhPVfRsiuOVybzHCdCUQ/gdidCbpYAD5w==} + '@rolldown/binding-linux-arm64-musl@1.1.1': + resolution: {integrity: sha512-5PUjZx366h9tkJTPJF5eibxOlK3sGoeRiBJLLjjEB5/kLDuhr6qB3LkhqLz1smXNgsX+pBhnbcJBrPE30HznAA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] - '@prisma/get-platform@7.2.0': - resolution: {integrity: sha512-k1V0l0Td1732EHpAfi2eySTezyllok9dXb6UQanajkJQzPUGi3vO2z7jdkz67SypFTdmbnyGYxvEvYZdZsMAVA==} + '@rolldown/binding-linux-ppc64-gnu@1.1.1': + resolution: {integrity: sha512-1WK84XPeio3tjP1sM/TMXiC0G1i1iq1qGZ71KfNQjEFLU1kwD+Cv5T8nGySg/JUFwLbaScu6ve9DmeXlmqpkFA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] - '@prisma/get-platform@7.8.0': - resolution: {integrity: sha512-WlxgRGnolL8VH2EmkH1R/DkKNr/mVdS3G2h42IZFFZ3eUrH9OT6t73kIOSlkkrv50wG123Iq8d96ufv5LlZktw==} + '@rolldown/binding-linux-s390x-gnu@1.1.1': + resolution: {integrity: sha512-1nS1X5z1uMJ369RU25hTpKCFvUwXZp12dIzlzk4S+UxCTcSVGsAE6tzkOSufv/7jnmAtK0ZlrsJxh2fGmsnVSw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] - '@prisma/instrumentation@7.6.0': - resolution: {integrity: sha512-ZPW2gRiwpPzEfgeZgaekhqXrbW+Y2RJKHVqUmlhZhKzRNCcvR6DykzylDrynpArKKRQtLxoZy36fK7U0p3pdgQ==} - peerDependencies: - '@opentelemetry/api': ^1.8 + '@rolldown/binding-linux-x64-gnu@1.1.1': + resolution: {integrity: sha512-NwX/wspnq4vYyMFsqbYvzums3ki/Tk8FZbMzMAovPDp3OfLeYKby/D+9osokadXuYEV3OvpeHlwnr/bG8QMixA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] - '@prisma/query-plan-executor@7.2.0': - resolution: {integrity: sha512-EOZmNzcV8uJ0mae3DhTsiHgoNCuu1J9mULQpGCh62zN3PxPTd+qI9tJvk5jOst8WHKQNwJWR3b39t0XvfBB0WQ==} + '@rolldown/binding-linux-x64-musl@1.1.1': + resolution: {integrity: sha512-+n46LhDrJFQM+229y4oXtVpj1G50U/+XuHMlpnisFTEXhrg9f/YIjp/HymX+PVJjBEr7XHRs3CFLelV464pqwA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] - '@prisma/streams-local@0.1.2': - resolution: {integrity: sha512-l49yTxKKF2odFxaAXTmwmkBKL3+bVQ1tFOooGifu4xkdb9NMNLxHj27XAhTylWZod8I+ISGM5erU1xcl/oBCtg==} - engines: {bun: '>=1.3.6', node: '>=22.0.0'} + '@rolldown/binding-openharmony-arm64@1.1.1': + resolution: {integrity: sha512-qGwEu47zOWYo7LdRHhCWTNhzwGtxXpdY6CERs8QEOqC0PXGGics/e3vHnyEUKt8xK6YkbZXFUCeklrpB6js8ag==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] - '@prisma/studio-core@0.27.3': - resolution: {integrity: sha512-AADjNFPdsrglxHQVTmHFqv6DuKQZ5WY4p5/gVFY017twvNrSwpLJ9lqUbYYxEu2W7nbvVxTZA8deJ8LseNALsw==} - engines: {node: ^20.19 || ^22.12 || >=24.0, pnpm: '8'} - peerDependencies: - '@types/react': ^18.0.0 || ^19.0.0 - react: ^18.0.0 || ^19.0.0 - react-dom: ^18.0.0 || ^19.0.0 - - '@quansync/fs@1.0.0': - resolution: {integrity: sha512-4TJ3DFtlf1L5LDMaM6CanJ/0lckGNtJcMjQ1NAV6zDmA0tEHKZtxNKin8EgPaVX1YzljbxckyT2tJrpQKAtngQ==} - - '@radix-ui/primitive@1.1.3': - resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==} - - '@radix-ui/react-compose-refs@1.1.2': - resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-primitive@2.1.3': - resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-slot@1.2.3': - resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-toggle@1.1.10': - resolution: {integrity: sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-use-controllable-state@1.2.2': - resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-effect-event@0.0.2': - resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-layout-effect@1.1.1': - resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@rolldown/binding-android-arm64@1.0.0-rc.17': - resolution: {integrity: sha512-s70pVGhw4zqGeFnXWvAzJDlvxhlRollagdCCKRgOsgUOH3N1l0LIxf83AtGzmb5SiVM4Hjl5HyarMRfdfj3DaQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [android] - - '@rolldown/binding-android-arm64@1.0.2': - resolution: {integrity: sha512-ZS4D1JPGn/MYQN/SYDWftIE/nVsM8j/AFOYEzAoOE2O3NktQOZru+/vYXGbR/qtdLdIfGCP0lcoJiYVzsEz+iQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [android] - - '@rolldown/binding-darwin-arm64@1.0.0-rc.17': - resolution: {integrity: sha512-4ksWc9n0mhlZpZ9PMZgTGjeOPRu8MB1Z3Tz0Mo02eWfWCHMW1zN82Qz/pL/rC+yQa+8ZnutMF0JjJe7PjwasYw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [darwin] - - '@rolldown/binding-darwin-arm64@1.0.2': - resolution: {integrity: sha512-vdFA9+C/rekyGce7WqHs/xoT0ioZEWaOFyZLIV1mEeNFaFDUQrPIo8Vs2GvJ6eetb3rzDUtUBgzto3ExpXJB3w==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [darwin] - - '@rolldown/binding-darwin-x64@1.0.0-rc.17': - resolution: {integrity: sha512-SUSDOI6WwUVNcWxd02QEBjLdY1VPHvlEkw6T/8nYG322iYWCTxRb1vzk4E+mWWYehTp7ERibq54LSJGjmouOsw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [darwin] - - '@rolldown/binding-darwin-x64@1.0.2': - resolution: {integrity: sha512-BewSOwTHazv77DTYiAZXSqqKZ4KP/KonFisDMVU7PImxoWfB2aepnPhd2E4SWz3zDzYgDNbs6jBmTdgNnF02GA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [darwin] - - '@rolldown/binding-freebsd-x64@1.0.0-rc.17': - resolution: {integrity: sha512-hwnz3nw9dbJ05EDO/PvcjaaewqqDy7Y1rn1UO81l8iIK1GjenME75dl16ajbvSSMfv66WXSRCYKIqfgq2KCfxw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [freebsd] - - '@rolldown/binding-freebsd-x64@1.0.2': - resolution: {integrity: sha512-m41o7M0YWtUdqk61Tb+jnKb2rN++iRdIASlExkUoKfIAH30DOHCB8fVLzSUpbWHHU8esmEioY62PxzexE8MBuA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [freebsd] - - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.17': - resolution: {integrity: sha512-IS+W7epTcwANmFSQFrS1SivEXHtl1JtuQA9wlxrZTcNi6mx+FDOYrakGevvvTwgj2JvWiK8B29/qD9BELZPyXQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [linux] - - '@rolldown/binding-linux-arm-gnueabihf@1.0.2': - resolution: {integrity: sha512-jcojB9H7W/jS29pMKWAK1N+fU99vXodHDTatS3b3y/XSOCiHo0kkA74pL3jJmkoQtYpOCxDvaKs1fo2Ij/1X5w==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [linux] - - '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.17': - resolution: {integrity: sha512-e6usGaHKW5BMNZOymS1UcEYGowQMWcgZ71Z17Sl/h2+ZziNJ1a9n3Zvcz6LdRyIW5572wBCTH/Z+bKuZouGk9Q==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-arm64-gnu@1.0.2': - resolution: {integrity: sha512-1jn6qDU5iiOgFgygDzKUuKP0maTi0/f1+sBLgvij/76C77Nm3ts6ufz9Bjg5q5dduxiUIxtq86JIoBvo1xQ4Ig==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-arm64-musl@1.0.0-rc.17': - resolution: {integrity: sha512-b/CgbwAJpmrRLp02RPfhbudf5tZnN9nsPWK82znefso832etkem8H7FSZwxrOI9djcdTP7U6YfNhbRnh7djErg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@rolldown/binding-linux-arm64-musl@1.0.2': - resolution: {integrity: sha512-QVLO/czFMdoMFSqlX3bcswcJNm/23r+qoa/jgtmFc/qEp6/jXmIkDjF/XIo8dPfGaiwy1xfQn8o77L79GeXFgw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.17': - resolution: {integrity: sha512-4EII1iNGRUN5WwGbF/kOh/EIkoDN9HsupgLQoXfY+D1oyJm7/F4t5PYU5n8SWZgG0FEwakyM8pGgwcBYruGTlA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [ppc64] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-ppc64-gnu@1.0.2': - resolution: {integrity: sha512-hgO5Abm0w5UL6FEa2iFnZqo2KlK7TQ5QhV5x09hujBf7t5KzHQ1VmfPuTpqRy/rNlSxua3eWH374xxiVrP+lcA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [ppc64] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.17': - resolution: {integrity: sha512-AH8oq3XqQo4IibpVXvPeLDI5pzkpYn0WiZAfT05kFzoJ6tQNzwRdDYQ45M8I/gslbodRZwW8uxLhbSBbkv96rA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [s390x] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-s390x-gnu@1.0.2': - resolution: {integrity: sha512-fy8rXxuYEu602abC8MUNaPjYLIFzReOaEIEMKMUa0rFEUxNpVXhs15KSSQ4qlqSaM7B6rcj9rDZgADh/IGDzLQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [s390x] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-x64-gnu@1.0.0-rc.17': - resolution: {integrity: sha512-cLnjV3xfo7KslbU41Z7z8BH/E1y5mzUYzAqih1d1MDaIGZRCMqTijqLv76/P7fyHuvUcfGsIpqCdddbxLLK9rA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-x64-gnu@1.0.2': - resolution: {integrity: sha512-0+bOkiQ779+r1WpoHOWHqncvyySci0vKph+myNDYb+im6meJAzHQXay6oEgnkHuUGouM1LKTZwqKpBow6Kj7CQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-x64-musl@1.0.0-rc.17': - resolution: {integrity: sha512-0phclDw1spsL7dUB37sIARuis2tAgomCJXAHZlpt8PXZ4Ba0dRP1e+66lsRqrfhISeN9bEGNjQs+T/Fbd7oYGw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [musl] - - '@rolldown/binding-linux-x64-musl@1.0.2': - resolution: {integrity: sha512-mjSkrzZK5Qsl0a9d1JgILOiuZOSDTVdKENcSXBoqbzSrspLR/4/IRVDo5wd2GgZjNss/viBFJdeq+j7qH2nypw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [musl] - - '@rolldown/binding-openharmony-arm64@1.0.0-rc.17': - resolution: {integrity: sha512-0ag/hEgXOwgw4t8QyQvUCxvEg+V0KBcA6YuOx9g0r02MprutRF5dyljgm3EmR02O292UX7UeS6HzWHAl6KgyhA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [openharmony] - - '@rolldown/binding-openharmony-arm64@1.0.2': - resolution: {integrity: sha512-1v5vHasdfQAZoEHakBV72LIFAC9JjnymsiKxp+GEr/ma3+NJCPSaYK+qavInOovJkgwFrs7GccX2d6IgDA3Z5w==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [openharmony] - - '@rolldown/binding-wasm32-wasi@1.0.0-rc.17': - resolution: {integrity: sha512-LEXei6vo0E5wTGwpkJ4KoT3OZJRnglwldt5ziLzOlc6qqb55z4tWNq2A+PFqCJuvWWdP53CVhG1Z9NtToDPJrA==} + '@rolldown/binding-wasm32-wasi@1.1.1': + resolution: {integrity: sha512-qczfgEH8u0wHGGOXtA7UMAybNKuQjjEXairyQaw4WzjiMztfbgatG1h4OKays/smhtwbWltpKCRGtVhU6h40Sg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [wasm32] - '@rolldown/binding-wasm32-wasi@1.0.2': - resolution: {integrity: sha512-mb1VobWn6NheziTk5/WEaR6AKVbrwT5sOi6C7zk3gy/pD1qtJfU1j4PgTo2NJnOtbL9Dl3Aeei8w9jJ7qC2jZQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [wasm32] - - '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.17': - resolution: {integrity: sha512-gUmyzBl3SPMa6hrqFUth9sVfcLBlYsbMzBx5PlexMroZStgzGqlZ26pYG89rBb45Mnia+oil6YAIFeEWGWhoZA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [win32] - - '@rolldown/binding-win32-arm64-msvc@1.0.2': - resolution: {integrity: sha512-SqKonF56vA/L2yHwHYcEp2P34URpOZ7d1fS635cTkpDnUtEGdUbhI6NzsPdqeSWvAAeGDrxjWjNmibDIdFf9/A==} + '@rolldown/binding-win32-arm64-msvc@1.1.1': + resolution: {integrity: sha512-4psXSh63mSbwJF+mB8/9yfUUEzBiHYcUjxa32EO9ZwKy0Ypwjcg4F10D8SvVXgd+isy2UUUjF9HJJnDu1T/4Gg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.0.0-rc.17': - resolution: {integrity: sha512-3hkiolcUAvPB9FLb3UZdfjVVNWherN1f/skkGWJP/fgSQhYUZpSIRr0/I8ZK9TkF3F7kxvJAk0+IcKvPHk9qQg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [win32] - - '@rolldown/binding-win32-x64-msvc@1.0.2': - resolution: {integrity: sha512-v7qRI7gXLRINcOGXt+7YmAZ6iFuyZVMIoXAxhd8oP+DR9dLfL9GfNIx7PLMxmhZdvq8waUJBQiWN9EKNy+TRBQ==} + '@rolldown/binding-win32-x64-msvc@1.1.1': + resolution: {integrity: sha512-MUvC/HLXVjzkQkWiExdVTEEWf0py+GfWm8WKSZsekG3ih6a21iy0BHPF07X3JIf3ifoklZXTIaHTLPBgH1C3dw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] - '@rolldown/pluginutils@1.0.0-rc.17': - resolution: {integrity: sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==} - '@rolldown/pluginutils@1.0.1': resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} @@ -1424,141 +1202,141 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.60.3': - resolution: {integrity: sha512-x35CNW/ANXG3hE/EZpRU8MXX1JDN86hBb2wMGAtltkz7pc6cxgjpy1OMMfDosOQ+2hWqIkag/fGok1Yady9nGw==} + '@rollup/rollup-android-arm-eabi@4.61.1': + resolution: {integrity: sha512-JnBB8MdXj45cajvTuO5FmPlvFVJRQgvrz1uSEl3NwqFnReAPGwb8EanbGi4z2nRaqLzjJSv5/JmycoTKlRZxHA==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.60.3': - resolution: {integrity: sha512-xw3xtkDApIOGayehp2+Rz4zimfkaX65r4t47iy+ymQB2G4iJCBBfj0ogVg5jpvjpn8UWn/+q9tprxleYeNp3Hw==} + '@rollup/rollup-android-arm64@4.61.1': + resolution: {integrity: sha512-Jx2g7iSjw4AOT0HDPHM9RV3GNjRXwybWtSFZiZAYUTjUwjVrYIwq3kBf+LnhqJlzXFAqTAh2F7IGI+O568exPw==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.60.3': - resolution: {integrity: sha512-vo6Y5Qfpx7/5EaamIwi0WqW2+zfiusVihKatLvtN1VFVy3D13uERk/6gZLU1UiHRL6fDXqj/ELIeVRGnvcTE1g==} + '@rollup/rollup-darwin-arm64@4.61.1': + resolution: {integrity: sha512-0F1L/Z3Eqv8mT2n3dCpeO8GcTvHvVqkP5/t6DMsn0KzhYVcg+s7Ncl5DS8qjKYEeio6Az0Gt6nyBORay5qIlCA==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.60.3': - resolution: {integrity: sha512-D+0QGcZhBzTN82weOnsSlY7V7+RMmPuF1CkbxyMAGE8+ZHeUjyb76ZiWmBlCu//AQQONvxcqRbwZTajZKqjuOw==} + '@rollup/rollup-darwin-x64@4.61.1': + resolution: {integrity: sha512-qLttcH871ujY4YcVfUSShhOw+CsoTatYz8gRbHO7Bb92QH059/P0y5do1KMs41fY0BpD2x4AJH/gID0zFiqVKQ==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.60.3': - resolution: {integrity: sha512-6HnvHCT7fDyj6R0Ph7A6x8dQS/S38MClRWeDLqc0MdfWkxjiu1HSDYrdPhqSILzjTIC/pnXbbJbo+ft+gy/9hQ==} + '@rollup/rollup-freebsd-arm64@4.61.1': + resolution: {integrity: sha512-fUI4RapGE0Oh3mb8mgfvC1O2nU1RpDZUKnDQm3xB1Ipg7C2wTs5Kstz7G2uWK99a8S2yTMq8/P4uycwNa0nJyw==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.60.3': - resolution: {integrity: sha512-KHLgC3WKlUYW3ShFKnnosZDOJ0xjg9zp7au3sIm2bs/tGBeC2ipmvRh/N7JKi0t9Ue20C0dpEshi8WUubg+cnA==} + '@rollup/rollup-freebsd-x64@4.61.1': + resolution: {integrity: sha512-H5YrdvJaDtI/U9/emrD4b++xkvp3y/JvOe4rizHbxvkyMfRS/CiRYdji+Pl8D0brEaNFWUh1drQxgAGIl6Xudw==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.60.3': - resolution: {integrity: sha512-DV6fJoxEYWJOvaZIsok7KrYl0tPvga5OZ2yvKHNNYyk/2roMLqQAbGhr78EQ5YhHpnhLKJD3S1WFusAkmUuV5g==} + '@rollup/rollup-linux-arm-gnueabihf@4.61.1': + resolution: {integrity: sha512-Q8CBCCQtDFrYtXoeUXSrnFXKOnyUhx6bz+SkL6A0E7V8kAiCJ5pamq1WtbfpVGhR5TSpXY6ak3avmDc5fHTyJA==} cpu: [arm] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm-musleabihf@4.60.3': - resolution: {integrity: sha512-mQKoJAzvuOs6F+TZybQO4GOTSMUu7v0WdxEk24krQ/uUxXoPTtHjuaUuPmFhtBcM4K0ons8nrE3JyhTuCFtT/w==} + '@rollup/rollup-linux-arm-musleabihf@4.61.1': + resolution: {integrity: sha512-nwnhk1581l0FBVellGcVCAT0Oi06onEA3WB53sf01VO3I0UPBkMH9sXONYME2K0ovXcNayJfNtHfm6mpJElatQ==} cpu: [arm] os: [linux] libc: [musl] - '@rollup/rollup-linux-arm64-gnu@4.60.3': - resolution: {integrity: sha512-Whjj2qoiJ6+OOJMGptTYazaJvjOJm+iKHpXQM1P3LzGjt7Ff++Tp7nH4N8J/BUA7R9IHfDyx4DJIflifwnbmIA==} + '@rollup/rollup-linux-arm64-gnu@4.61.1': + resolution: {integrity: sha512-x5Xr49hwt3hdW75UOZm3395YwwzPyauktslv29KpWL/T+vVAzoT3azLcTWv0eMciBNrx+DYjH4paehHoLpPvpg==} cpu: [arm64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm64-musl@4.60.3': - resolution: {integrity: sha512-4YTNHKqGng5+yiZt3mg77nmyuCfmNfX4fPmyUapBcIk+BdwSwmCWGXOUxhXbBEkFHtoN5boLj/5NON+u5QC9tg==} + '@rollup/rollup-linux-arm64-musl@4.61.1': + resolution: {integrity: sha512-unMS3H73DpaoPyyEVPjGKleM/s0mkmsauTENpw4INQY8y4+IuLNjkueQ5QCtC0D3N38Y38yhAU8OoZ20S2Tm6w==} cpu: [arm64] os: [linux] libc: [musl] - '@rollup/rollup-linux-loong64-gnu@4.60.3': - resolution: {integrity: sha512-SU3kNlhkpI4UqlUc2VXPGK9o886ZsSeGfMAX2ba2b8DKmMXq4AL7KUrkSWVbb7koVqx41Yczx6dx5PNargIrEA==} + '@rollup/rollup-linux-loong64-gnu@4.61.1': + resolution: {integrity: sha512-zNZzGRnAhwjFEYmvphJRV5XaQGjs62cCmeYYHUT//NbvEnHauw+I85nGG+SiVg5ld4GX8D1IbKIX+ozITQnhMQ==} cpu: [loong64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-loong64-musl@4.60.3': - resolution: {integrity: sha512-6lDLl5h4TXpB1mTf2rQWnAk/LcXrx9vBfu/DT5TIPhvMhRWaZ5MxkIc8u4lJAmBo6klTe1ywXIUHFjylW505sg==} + '@rollup/rollup-linux-loong64-musl@4.61.1': + resolution: {integrity: sha512-LdpWGL8X209B2SIvWjqlc8VZgM6PKfontSerGepuldQmHYrAOtnMCXeJkxXGbC+PPZVOuu5czJo7fNV6aeW8rQ==} cpu: [loong64] os: [linux] libc: [musl] - '@rollup/rollup-linux-ppc64-gnu@4.60.3': - resolution: {integrity: sha512-BMo8bOw8evlup/8G+cj5xWtPyp93xPdyoSN16Zy90Q2QZ0ZYRhCt6ZJSwbrRzG9HApFabjwj2p25TUPDWrhzqQ==} + '@rollup/rollup-linux-ppc64-gnu@4.61.1': + resolution: {integrity: sha512-EC5kTtNaNGOmbMGqar8dvJy6y/hg99GAwjfBz++pxZhQATXGcRjd6c5en5wcbru0vkRmiMGsQKdMJOOf6sza4g==} cpu: [ppc64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-ppc64-musl@4.60.3': - resolution: {integrity: sha512-E0L8X1dZN1/Rph+5VPF6Xj2G7JJvMACVXtamTJIDrVI44Y3K+G8gQaMEAavbqCGTa16InptiVrX6eM6pmJ+7qA==} + '@rollup/rollup-linux-ppc64-musl@4.61.1': + resolution: {integrity: sha512-8hiwp6D4acEcNK78I4rP0/XtS1sknWIAMJBPdR4l6zUtyTm5KiTDr5bXmWt4foY7nAN7AThDHgkLIEZOWKbzWw==} cpu: [ppc64] os: [linux] libc: [musl] - '@rollup/rollup-linux-riscv64-gnu@4.60.3': - resolution: {integrity: sha512-oZJ/WHaVfHUiRAtmTAeo3DcevNsVvH8mbvodjZy7D5QKvCefO371SiKRpxoDcCxB3PTRTLayWBkvmDQKTcX/sw==} + '@rollup/rollup-linux-riscv64-gnu@4.61.1': + resolution: {integrity: sha512-10dh/h/BqA7DuMPWSxkR8uks18FRwnwOEqr5zOTEl+NOwP/OMzKX8OFR/Of9xxDA7D5qef1Nzar5WDD2kCCr1g==} cpu: [riscv64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-riscv64-musl@4.60.3': - resolution: {integrity: sha512-Dhbyh7j9FybM3YaTgaHmVALwA8AkUwTPccyCQ79TG9AJUsMQqgN1DDEZNr4+QUfwiWvLDumW5vdwzoeUF+TNxQ==} + '@rollup/rollup-linux-riscv64-musl@4.61.1': + resolution: {integrity: sha512-YKJ5lg35DP17gcAOggnihe+APw9HLyj1Xn7gsmGumBJAUDa6NGXNixJzmkWLhcK9TOuuyQjdamzvJefkO7qHZQ==} cpu: [riscv64] os: [linux] libc: [musl] - '@rollup/rollup-linux-s390x-gnu@4.60.3': - resolution: {integrity: sha512-cJd1X5XhHHlltkaypz1UcWLA8AcoIi1aWhsvaWDskD1oz2eKCypnqvTQ8ykMNI0RSmm7NkTdSqSSD7zM0xa6Ig==} + '@rollup/rollup-linux-s390x-gnu@4.61.1': + resolution: {integrity: sha512-Mlil5G2Jj6a7B3LWGctg+XPL9vdXYuzCtNXfxOQ0nPjc2m6ueUktocPGH9bnAM0bNRKb/bAWTujUU7IJQdQA+g==} cpu: [s390x] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-gnu@4.60.3': - resolution: {integrity: sha512-DAZDBHQfG2oQuhY7mc6I3/qB4LU2fQCjRvxbDwd/Jdvb9fypP4IJ4qmtu6lNjes6B531AI8cg1aKC2di97bUxA==} + '@rollup/rollup-linux-x64-gnu@4.61.1': + resolution: {integrity: sha512-bVWIOIk6pV01p4CdUbPP7CJ/434z+OooYjDuFcR+44N35YvKUC66G8MGnvcWx5mWKW3g61J+t74l3Kj15Kwn2Q==} cpu: [x64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-musl@4.60.3': - resolution: {integrity: sha512-cRxsE8c13mZOh3vP+wLDxpQBRrOHDIGOWyDL93Sy0Ga8y515fBcC2pjUfFwUe5T7tqvTvWbCpg1URM/AXdWIXA==} + '@rollup/rollup-linux-x64-musl@4.61.1': + resolution: {integrity: sha512-qy5pBvZbqNFheBz61R1rzsezjm0J7O2oNGoWtGoY89SZYLUfxAJTBAqDChqAIdB4rCiIbi9nF7yZ83GnNiLwSw==} cpu: [x64] os: [linux] libc: [musl] - '@rollup/rollup-openbsd-x64@4.60.3': - resolution: {integrity: sha512-QaWcIgRxqEdQdhJqW4DJctsH6HCmo5vHxY0krHSX4jMtOqfzC+dqDGuHM87bu4H8JBeibWx7jFz+h6/4C8wA5Q==} + '@rollup/rollup-openbsd-x64@4.61.1': + resolution: {integrity: sha512-E83TXjI4zm0+5f2qO+UOudaCYIhYwpJ5jq6YCZNIZ+6CbfhKrkAGezeiASBL9ElxAxFsRS9ZhESv8mfnj6TKeg==} cpu: [x64] os: [openbsd] - '@rollup/rollup-openharmony-arm64@4.60.3': - resolution: {integrity: sha512-AaXwSvUi3QIPtroAUw1t5yHGIyqKEXwH54WUocFolZhpGDruJcs8c+xPNDRn4XiQsS7MEwnYsHW2l0MBLDMkWg==} + '@rollup/rollup-openharmony-arm64@4.61.1': + resolution: {integrity: sha512-fbWnKqVkjrJN38vNe3ahkbk6iejS/3b0Nt7EEtPpE6RBacZcGXNKbzfHN3GUUlXOPghUg0j6XUGrtjX9z1sIvA==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.60.3': - resolution: {integrity: sha512-65LAKM/bAWDqKNEelHlcHvm2V+Vfb8C6INFxQXRHCvaVN1rJfwr4NvdP4FyzUaLqWfaCGaadf6UbTm8xJeYfEg==} + '@rollup/rollup-win32-arm64-msvc@4.61.1': + resolution: {integrity: sha512-ArMl38iVAbk0New1ogihQNY6iphLi4ZaRsa037gUzv5yeKPY8TD3Dmy4x2RNC1VztU/uqm+G+/RwFrSka3Oy2g==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.60.3': - resolution: {integrity: sha512-EEM2gyhBF5MFnI6vMKdX1LAosE627RGBzIoGMdLloPZkXrUN0Ckqgr2Qi8+J3zip/8NVVro3/FjB+tjhZUgUHA==} + '@rollup/rollup-win32-ia32-msvc@4.61.1': + resolution: {integrity: sha512-0mYtjHS9ucAbcATycCNK9IGBk/cCe/ma7EmSLGZdsxnOA8cjRIyU04wDpVAD9NiOfLUR9KTxdiO53uOkherqjQ==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.60.3': - resolution: {integrity: sha512-E5Eb5H/DpxaoXH++Qkv28RcUJboMopmdDUALBczvHMf7hNIxaDZqwY5lK12UK1BHacSmvupoEWGu+n993Z0y1A==} + '@rollup/rollup-win32-x64-gnu@4.61.1': + resolution: {integrity: sha512-gK1iCEPfpoSG9wfBihXxvBMi8ZfcWffYkEsC/Eih+iFENTaewvNcrEQ69lIOWYO5pePHKLHHO7nq5AILGO/HQQ==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.60.3': - resolution: {integrity: sha512-hPt/bgL5cE+Qp+/TPHBqptcAgPzgj46mPcg/16zNUmbQk0j+mOEQV/+Lqu8QRtDV3Ek95Q6FeFITpuhl6OTsAA==} + '@rollup/rollup-win32-x64-msvc@4.61.1': + resolution: {integrity: sha512-X+zaP2x+j4RXGfbp/seSoRHWnPxzApilDszisZxbYH5C/jTxFhCtDNdPGZb9lJyYPs24wGxruPF7Y+sIXt9Gzw==} cpu: [x64] os: [win32] @@ -1566,26 +1344,10 @@ packages: resolution: {integrity: sha512-cvGzxbba6sav2zZkH8GPf2oGk9yYoD5qrNWdu9fRehifgnFZJMV+nuy2nON2roRO4yQQ+v7MK/Pktl/HgfsUXg==} engines: {node: '>=v14.0.0', npm: '>=7.0.0'} - '@sapphire/bitfield@1.2.4': - resolution: {integrity: sha512-x0Zvb5jbn8A9fOdWksvxPuXdHGzk6v0Z5ogcYKKg06Az/Ih2WupKZ88CIX1/pZWk6vBWqH5LAU0lOVtEaw7D/A==} - engines: {node: '>=v14.0.0', npm: '>=7.0.0'} - - '@sapphire/cron@1.2.1': - resolution: {integrity: sha512-K96GX4UkzgC/Y2VHXVjhM2Bl4D04552nr/fDiOj9bOACW1+wqeFfLJ3eV6jleTSXmzPIwDvkPIUJLf8A5KSD+w==} - engines: {node: '>=v14.0.0', npm: '>=7.0.0'} - - '@sapphire/decorators@6.2.0': - resolution: {integrity: sha512-st1DNDCNoZaZYz3fgCA99W87Bhe6XqM8y0G+Z9NBOBEqvOYkVNGcPMDrMiaZrPD9Z471k8fpLqJVUNSuWUx8Hg==} - engines: {node: '>=v14.0.0', npm: '>=7.0.0'} - '@sapphire/discord-utilities@3.5.0': resolution: {integrity: sha512-H4SY5KTVDZrqA5QG7ob6etwqhdOb3TRSY2wv56f0tiobUdIr0irlrYvdmr8Kg/FRxWU+aiHDIISWGG5vBuxOGw==} engines: {node: '>=v14.0.0', npm: '>=7.0.0'} - '@sapphire/discord-utilities@4.0.0': - resolution: {integrity: sha512-QAvrKNHgswz+ZX48WqSYpRiRzQcugNXXB1C3fR1qbpTJGd7Ckr2OWyFK88TyOksi3U2isrk8sMriTcAgaIe7Qg==} - engines: {node: '>=v14.0.0', npm: '>=7.0.0'} - '@sapphire/discord.js-utilities@7.3.3': resolution: {integrity: sha512-WDj+zjWgNCUSvzYDD0wY3TVeTUseHq0Nhk0wVWxSDjY8z2gFEVcpY7wF8/fbTDWP44LUG5sUQ4haIrIj2OjmkQ==} engines: {node: '>=16.6.0', npm: '>=7.0.0'} @@ -1594,50 +1356,22 @@ packages: resolution: {integrity: sha512-LxjOAFXz81WmrI8XX9YaVcAZDjQj/1p78lZCvkAWZB1nphOwz/D0dU3CBejmhOWx5dO5CszTkLJMNR0xuCK+Zg==} engines: {node: '>=v14.0.0', npm: '>=7.0.0'} - '@sapphire/fetch@3.0.5': - resolution: {integrity: sha512-YfH5iFFL+n21dEWfdNpSlN1Q4RH+84I9ZFLxtdlbqyWljkh1IwMU6UmHjnroiRJx9TwdFSQ0krHm4v0fV/VqiA==} - engines: {node: '>=v18'} - - '@sapphire/framework@5.5.0': - resolution: {integrity: sha512-jC+zS8yR/MtJaTFEQutBBWj7Scuvny4d0adtQ3s0OCFWe3rUqNfENomBG3P4tsQ/kRF7L3WCqucyLV8ywG24hw==} + '@sapphire/framework@4.8.5': + resolution: {integrity: sha512-RvXh3/Mn11D9ZCATG9LxC8LmgDp2zS/ML7rk1vcBKmv57p/X4UaAry4ZRG/CPq23yja/AWNMVn/osZzMtIKGbw==} engines: {node: '>=v18', npm: '>=7'} - '@sapphire/iana-mime-types@1.15.0': - resolution: {integrity: sha512-+9qRT7aKJmxmqV5nXjchJP85AlOXybAasT3ki4c2VrFXRek2gJqNkszJ0kGsLAItXXyRQpDOdvQIQapvbzCBUA==} - engines: {node: '>=v20'} - - '@sapphire/iterator-utilities@2.0.1': - resolution: {integrity: sha512-SqH2MFaUbmxPoijdYiFdzHM185PWR2m4cNPEUyJTpQqKU7/EPtFh7Nari3ZFoQ0IbPgwn/a7l+kRFf2twUV1+g==} - engines: {node: '>=v18', npm: '>=9'} - '@sapphire/lexure@1.1.12': resolution: {integrity: sha512-F7Z3QzRnAZGunRl24/qQMhzRogZU/foumu2EBBunRnQi/o/DLTCwdAbLgJATyPlvJa8N6FrJq0JJwvzM/vXoXg==} engines: {node: '>=v14.0.0', npm: '>=7.0.0'} + '@sapphire/pieces@3.10.0': + resolution: {integrity: sha512-iBaux50dA+VYjtBqmaceWcskdmw7ua51ojEPkyaSJyg2t9ln/Wc9NqYoQheRCWltZeDTERCUBIYYMqDuCs1Okw==} + engines: {node: '>=v14.0.0', npm: '>=7.0.0'} + '@sapphire/pieces@4.4.1': resolution: {integrity: sha512-2v49P++RzHGb23bdjSa9u7flkdvhrq94IUO9PneY538TILN5QiMxfaXVK+pDR2YR7jpQYBy9APwtFDes2Svykg==} engines: {node: '>=v14.0.0', npm: '>=7.0.0'} - '@sapphire/plugin-api@8.3.1': - resolution: {integrity: sha512-hDOT/o6UZYhHePFQ9yVNtXqwuW81sxObxEp47w0plqTgRPaAP0mqygG5+DRIaY36WRrSD8YGeLJWxA40rifLmQ==} - engines: {node: '>=v18', npm: '>=7'} - - '@sapphire/plugin-editable-commands@4.0.4': - resolution: {integrity: sha512-1Dd04IjZxYjPWupMJPAyOupWUvYNkhOAUdWhoIBRDRjy6eytOHYYD5TpH8QLXsfgbQNV/ETdWDG0IBVH/Vg/EA==} - engines: {node: '>=v18', npm: '>=7'} - - '@sapphire/plugin-i18next@8.0.0': - resolution: {integrity: sha512-oZoQQGqcFLmPHFQ470lOG2tankvNyxaDP1SRBgdVzO+1PKUcs7oC23DWsA0zJiP/XsVe9Q12qSObAwpobANc3Q==} - engines: {node: '>=v18', npm: '>=7'} - - '@sapphire/plugin-logger@4.1.0': - resolution: {integrity: sha512-+vLTITQw3DI8+kfDPNJ0yhIK/LrfM/Gro/UFcxgYWLLm+lwNmSpLZxdWe9v7ESXprody7rTp8JXPNBK7UWyE8w==} - engines: {node: '>=v18', npm: '>=7'} - - '@sapphire/plugin-subcommands@7.0.1': - resolution: {integrity: sha512-3ngUpfKfcMX4zIlJ4SHLe10N79XU72H+Wdfcnd9ueMf6FOSMJFvVUfqDIp1rb7/iXi7C5dfx0pQqSwqu3UG0KQ==} - engines: {node: '>=v18', npm: '>=7'} - '@sapphire/prettier-config@2.0.0': resolution: {integrity: sha512-Vie8KR5zQ6sbEP4+biW/IR7k55saGfZkTSuRlgvxCBKb4SBJdRWcOBI80i+JxMVIDDZKgXlgYnXEST+FgZiWXA==} engines: {node: '>=v14.0.0', npm: '>=7.0.0'} @@ -1666,18 +1400,6 @@ packages: resolution: {integrity: sha512-IVI48D2yAz411bSttXyTkBH0p2vhrXoqWLn5loDDSAAEUGkM1r5KNCX2027ifQ8svdoMkUfIGjFueR+satLeWw==} engines: {node: '>=v14.0.0', npm: '>=7.0.0'} - '@sapphire/time-utilities@1.7.14': - resolution: {integrity: sha512-UVJQ9oyzXcmJVVf9Y9ucGzRmKoPxe6SehpQlBNTX7CTVu0aj1lrEGL+bBa0Mu7hxF5DYXYjDYeO1e5BR0eg90Q==} - engines: {node: '>=v14.0.0', npm: '>=7.0.0'} - - '@sapphire/timer-manager@1.0.4': - resolution: {integrity: sha512-gc1JW8oui86f2l0T/1Iwd7hZTgus8b46slitTR2y0+wiMAEYxdp6vVTHvMAEHOqX8drkxK70aGfZmQKbAcgFqQ==} - engines: {node: '>=v14.0.0', npm: '>=7.0.0'} - - '@sapphire/timestamp@1.0.5': - resolution: {integrity: sha512-oNwWyNdbt5wm4aYZvlHl1+64U3g0xrFmRIHsnER7RgMxNnp/wmAE4yTK2oUHeadg3t4V9iYctPAQCF+aINke4g==} - engines: {node: '>=v14.0.0', npm: '>=7.0.0'} - '@sapphire/ts-config@5.0.3': resolution: {integrity: sha512-bFyGYHFT3TpOf5Sg2P+zY2ad0t5IA2epc5HtewlghhL7MYvbZvxtKsdaNaMwAdNObBx7hpiQm5OcOhyzEwQvbQ==} engines: {node: '>=v16.0.0', npm: '>=8.0.0'} @@ -1686,145 +1408,77 @@ packages: resolution: {integrity: sha512-QGLdC9+pT74Zd7aaObqn0EUfq40c4dyTL65pFnkM6WO1QYN7Yg/s4CdH+CXmx0Zcu6wcfCWILSftXPMosJHP5A==} engines: {node: '>=v14.0.0'} - '@sentry/core@10.53.1': - resolution: {integrity: sha512-XG4ezlkyuAPjBC5+9kXC94rXXuqYTw9NRhfaDHssbTFaGnqBR8vQX2UUgZfY7ucbeelRDGfBu1sywoU+mB04uA==} - engines: {node: '>=18'} - - '@sentry/node-core@10.53.1': - resolution: {integrity: sha512-iH7SMcM/7jPbN+t7+7ussQOiIqI4BMOGt4VYWlV71/z7k0pY+YPaSvlfVkNXfISiDzFAKv0ecCY3BmsLMu1xDQ==} - engines: {node: '>=18'} - peerDependencies: - '@opentelemetry/api': ^1.9.0 - '@opentelemetry/core': ^1.30.1 || ^2.1.0 - '@opentelemetry/exporter-trace-otlp-http': '>=0.57.0 <1' - '@opentelemetry/instrumentation': '>=0.57.1 <1' - '@opentelemetry/sdk-trace-base': ^1.30.1 || ^2.1.0 - '@opentelemetry/semantic-conventions': ^1.39.0 - peerDependenciesMeta: - '@opentelemetry/api': - optional: true - '@opentelemetry/core': - optional: true - '@opentelemetry/exporter-trace-otlp-http': - optional: true - '@opentelemetry/instrumentation': - optional: true - '@opentelemetry/sdk-trace-base': - optional: true - '@opentelemetry/semantic-conventions': - optional: true - - '@sentry/node@10.53.1': - resolution: {integrity: sha512-rxHVil0tJAmz+keFcZCj1LaUdgdkK66E/l0gqh2p1209PNCGoD3lnClFr6vusy1aF3zF8O9JPtuMEJzXOKhs+w==} - engines: {node: '>=18'} - - '@sentry/opentelemetry@10.53.1': - resolution: {integrity: sha512-Zok6UXla0mFOjd1YnVb1TZtQNOry9v93fXUqx8jmDaygwWM2BwvP8rBQabLz0/OZXo8+35oge+Vmw+QY5aesnA==} - engines: {node: '>=18'} - peerDependencies: - '@opentelemetry/api': ^1.9.0 - '@opentelemetry/core': ^1.30.1 || ^2.1.0 - '@opentelemetry/sdk-trace-base': ^1.30.1 || ^2.1.0 - '@opentelemetry/semantic-conventions': ^1.39.0 - - '@simple-libs/child-process-utils@1.0.2': - resolution: {integrity: sha512-/4R8QKnd/8agJynkNdJmNw2MBxuFTRcNFnE5Sg/G+jkSsV8/UBgULMzhizWWW42p8L5H7flImV2ATi79Ove2Tw==} - engines: {node: '>=18'} + '@sentry-internal/tracing@7.120.4': + resolution: {integrity: sha512-Fz5+4XCg3akeoFK+K7g+d7HqGMjmnLoY2eJlpONJmaeT9pXY7yfUyXKZMmMajdE2LxxKJgQ2YKvSCaGVamTjHw==} + engines: {node: '>=8'} - '@simple-libs/stream-utils@1.2.0': - resolution: {integrity: sha512-KxXvfapcixpz6rVEB6HPjOUZT22yN6v0vI0urQSk1L8MlEWPDFCZkhw2xmkyoTGYeFw7tWTZd7e3lVzRZRN/EA==} - engines: {node: '>=18'} + '@sentry/core@7.114.0': + resolution: {integrity: sha512-YnanVlmulkjgZiVZ9BfY9k6I082n+C+LbZo52MTvx3FY6RE5iyiPMpaOh67oXEZRWcYQEGm+bKruRxLVP6RlbA==} + engines: {node: '>=8'} - '@skyra/ai-android-arm-eabi@2.0.1': - resolution: {integrity: sha512-aAvUAi+SQzNVMUcGLRsF1C3HyoMLxhzC5OkWeGkvsHJpfyHygVPlZxzsd0PDD7JXNspE/VyAxbrPf+XIUX2Q9A==} - engines: {node: '>= 16'} - cpu: [arm] - os: [android] + '@sentry/core@7.120.4': + resolution: {integrity: sha512-TXu3Q5kKiq8db9OXGkWyXUbIxMMuttB5vJ031yolOl5T/B69JRyAoKuojLBjRv1XX583gS1rSSoX8YXX7ATFGA==} + engines: {node: '>=8'} - '@skyra/ai-android-arm64@2.0.1': - resolution: {integrity: sha512-Ts4tu99xNhptFSncmOIqRGaaQ6m7fst8O/XJG0RXYTaAKjjFP1qjuSOq5/0HdABQKqiUhd5s5hi/ywuzE8aBPw==} - engines: {node: '>= 16'} - cpu: [arm64] - os: [android] + '@sentry/core@8.55.2': + resolution: {integrity: sha512-YlEBwybUcOQ/KjMHDmof1vwweVnBtBxYlQp7DE3fOdtW4pqqdHWTnTntQs4VgYfxzjJYgtkd9LHlGtg8qy+JVQ==} + engines: {node: '>=14.18'} - '@skyra/ai-darwin-arm64@2.0.1': - resolution: {integrity: sha512-dtD6cOLUcn76El1SiUgL/Rio+c/nh+TYILXrBs10PqNOMVek5U3QFBiAUZau/QujsyPLPLrtszQIBvefBqFUoQ==} - engines: {node: '>= 16'} - cpu: [arm64] - os: [darwin] + '@sentry/integrations@7.114.0': + resolution: {integrity: sha512-BJIBWXGKeIH0ifd7goxOS29fBA8BkEgVVCahs6xIOXBjX1IRS6PmX0zYx/GP23nQTfhJiubv2XPzoYOlZZmDxg==} + engines: {node: '>=8'} - '@skyra/ai-darwin-x64@2.0.1': - resolution: {integrity: sha512-zyBz2tbnnEFT+yXAyPA4TmDgEfQ9Lzp5fuuF/BmslAcyKolyTQ4UXTetATgKjgfzBHeLpKzRGTM9srykyOgLTg==} - engines: {node: '>= 16'} - cpu: [x64] - os: [darwin] + '@sentry/integrations@7.120.4': + resolution: {integrity: sha512-kkBTLk053XlhDCg7OkBQTIMF4puqFibeRO3E3YiVc4PGLnocXMaVpOSCkMqAc1k1kZ09UgGi8DxfQhnFEjUkpA==} + engines: {node: '>=8'} - '@skyra/ai-linux-arm-gnueabihf@2.0.1': - resolution: {integrity: sha512-IvFInoDF9sVHhV4+Xy3tO8TIHamNsXybWBIybE3OZ3Bz/1NCLPCB1pPF2UWFUmP27Ws41qUF/UMHzTh7H0PH2A==} - engines: {node: '>= 16'} - cpu: [arm] - os: [linux] + '@sentry/node@7.120.4': + resolution: {integrity: sha512-qq3wZAXXj2SRWhqErnGCSJKUhPSlZ+RGnCZjhfjHpP49KNpcd9YdPTIUsFMgeyjdh6Ew6aVCv23g1hTP0CHpYw==} + engines: {node: '>=8'} - '@skyra/ai-linux-arm64-gnu@2.0.1': - resolution: {integrity: sha512-I03FHzXc6p1qRQkJG+/DfRRsZvK8ljDwigiIfuRo2UjyDf1dkTOfQjTxAD7lx7cm7rsGDXioL+hrAY+n082J8w==} - engines: {node: '>= 16'} - cpu: [arm64] - os: [linux] - libc: [glibc] + '@sentry/node@8.55.2': + resolution: {integrity: sha512-x3Whryb4TytiIhH9ABLVuASfBvwA50v6PpJYvq0Y9dUMi9Eb0cfuqvRCB3e+oVntZHQpnXor2U/gRBIdG2jp4w==} + engines: {node: '>=14.18'} - '@skyra/ai-linux-arm64-musl@2.0.1': - resolution: {integrity: sha512-7xJGY3kEEaRk+n9nDgWUMnRsA5sLwWpvRh94fKeVr9uhdL1LbTiOJp1rVRGpnMHUbIbMrkR14N4MReEvla8RDg==} - engines: {node: '>= 16'} - cpu: [arm64] - os: [linux] - libc: [musl] + '@sentry/opentelemetry@8.55.2': + resolution: {integrity: sha512-pbhXi4cS1W4l392yEfIx3UD28OYAl9JkYOmh/Cpm6cPTtRMPxi3hWeujGbcXV9T/RkWYjqd+JdUDJjqsWSww9A==} + engines: {node: '>=14.18'} + peerDependencies: + '@opentelemetry/api': ^1.9.0 + '@opentelemetry/context-async-hooks': ^1.30.1 + '@opentelemetry/core': ^1.30.1 + '@opentelemetry/instrumentation': ^0.57.1 + '@opentelemetry/sdk-trace-base': ^1.30.1 + '@opentelemetry/semantic-conventions': ^1.28.0 + + '@sentry/types@7.114.0': + resolution: {integrity: sha512-tsqkkyL3eJtptmPtT0m9W/bPLkU7ILY7nvwpi1hahA5jrM7ppoU0IMaQWAgTD+U3rzFH40IdXNBFb8Gnqcva4w==} + engines: {node: '>=8'} - '@skyra/ai-linux-x64-gnu@2.0.1': - resolution: {integrity: sha512-BPPAuSqZdN9lpa/mE76yKgXFddHUK0KqYxuU7bZA8+cpn21U96n9EVahZC+fibLbONy6RhNmSGuBXbb+Keiypw==} - engines: {node: '>= 16'} - cpu: [x64] - os: [linux] - libc: [glibc] + '@sentry/types@7.120.4': + resolution: {integrity: sha512-cUq2hSSe6/qrU6oZsEP4InMI5VVdD86aypE+ENrQ6eZEVLTCYm1w6XhW1NvIu3UuWh7gZec4a9J7AFpYxki88Q==} + engines: {node: '>=8'} - '@skyra/ai-linux-x64-musl@2.0.1': - resolution: {integrity: sha512-/pTBco6a4J12Jo8oOiyQUOpknwuCOD4gvcfH4ImD/2a1upFcYa/LFMgSgpczOGUqI4mJ7Os4m+2DzUw4a4jiyg==} - engines: {node: '>= 16'} - cpu: [x64] - os: [linux] - libc: [musl] + '@sentry/utils@7.114.0': + resolution: {integrity: sha512-319N90McVpupQ6vws4+tfCy/03AdtsU0MurIE4+W5cubHME08HtiEWlfacvAxX+yuKFhvdsO4K4BB/dj54ideg==} + engines: {node: '>=8'} - '@skyra/ai-win32-arm64-msvc@2.0.1': - resolution: {integrity: sha512-LoaYTh96ks9vXZf4Oo0DIBEX13ZbqHrSmXcAbxjSVayLaYHqSFC3OXg4HZXfpsYQ+OeMvC58zRE7mj6MZ7XHTw==} - engines: {node: '>= 16'} - cpu: [arm64] - os: [win32] + '@sentry/utils@7.120.4': + resolution: {integrity: sha512-zCKpyDIWKHwtervNK2ZlaK8mMV7gVUijAgFeJStH+CU/imcdquizV3pFLlSQYRswG+Lbyd6CT/LGRh3IbtkCFw==} + engines: {node: '>=8'} - '@skyra/ai-win32-x64-msvc@2.0.1': - resolution: {integrity: sha512-Jj/ewJn7akF/snfY7kFbM65Ete1JYQQcuZ0MK7y7McBdkOqcDbhHot/gWUKUFySLRby7m5tJEPOJH82iwDfgUw==} - engines: {node: '>= 16'} - cpu: [x64] - os: [win32] + '@simple-libs/child-process-utils@1.0.2': + resolution: {integrity: sha512-/4R8QKnd/8agJynkNdJmNw2MBxuFTRcNFnE5Sg/G+jkSsV8/UBgULMzhizWWW42p8L5H7flImV2ATi79Ove2Tw==} + engines: {node: '>=18'} - '@skyra/ai@2.0.1': - resolution: {integrity: sha512-wmPSyXc+bU2yOqLz/amZhROwOdkOEdz3jGggIL99MqJepgOPM7f5ddM4GKBtk5jcI4za/NgZt2Nphe7OnUt9ng==} - engines: {node: '>= v16'} + '@simple-libs/stream-utils@1.2.0': + resolution: {integrity: sha512-KxXvfapcixpz6rVEB6HPjOUZT22yN6v0vI0urQSk1L8MlEWPDFCZkhw2xmkyoTGYeFw7tWTZd7e3lVzRZRN/EA==} + engines: {node: '>=18'} '@skyra/char@1.0.3': resolution: {integrity: sha512-qe9yAiFuiRn1TSpEdL+hKdycRvAfajhi1qiJmJlfhGpiR9LE3abL8QryhETDy4tr5DFvVTwf3XrH6QJUxDOQKg==} engines: {node: '>=v14'} - '@skyra/editable-commands@3.0.4': - resolution: {integrity: sha512-wQQqOt/GVnKTY0yfL9AmBCvoNIRa/4COxMDYS/TcQexabdZlIfxG4up2zKz8A1or5+73meDZ/D/SvUav36/V2w==} - engines: {node: '>=16.6', npm: '>=7.24.2'} - - '@skyra/env-utilities@2.0.1': - resolution: {integrity: sha512-WEWKE0Acud4nll6pcOxDxmLBG6Zjusd9V2xCfOJsYF2NlmaWjiaiKL3ofS+9ZjMinR+QXRxaJAZ1LXh/1des3w==} - engines: {node: '>=18'} - - '@skyra/i18next-backend@2.0.6': - resolution: {integrity: sha512-emMWpgHVsycYUobAcylJhBrVAOg/C8huAflam3xGtFSzeVGtjQ1jcEbBzmzDj5c0E+AUcz/QDI1JCnKsXHL1HQ==} - engines: {node: '>=18'} - '@skyra/jaro-winkler@1.1.1': resolution: {integrity: sha512-jT2OWwpajtXTb6opnaIwmBTMpQtKUwl2Ro1zApxIIrpZJon71kZIv6GZSc08LzKO2lpTqUjvD+i7Z2hGuG42KQ==} engines: {node: '>=v18'} @@ -1832,151 +1486,149 @@ packages: '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} - '@tybys/wasm-util@0.10.1': - resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + '@tokenizer/token@0.3.0': + resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} - '@types/backoff@2.5.5': - resolution: {integrity: sha512-4gv8BiXZMG4yxwn9Jii6ooCBVo+DXYq8kcKg6OvoHiWNh8rSjbYwQANTbUBx0c7ZKFv8aSYg9yDO6fOX2GkkAQ==} + '@tybys/wasm-util@0.10.2': + resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} '@types/chai@5.2.3': resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} - '@types/connect@3.4.38': - resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} - - '@types/conventional-commits-parser@5.0.2': - resolution: {integrity: sha512-BgT2szDXnVypgpNxOK8aL5SGjUdaQbC++WZNjF1Qge3Og2+zhHj+RWhmehLhYyvQwqAmvezruVfOf8+3m74W+g==} + '@types/connect@3.4.36': + resolution: {integrity: sha512-P63Zd/JUGq+PdrM1lv0Wv5SBYeA2+CORvbrXbngriYY0jzLUWfQMQQxOhjONEz/wlHOAxOdY7CY65rgQdTjq2w==} '@types/deep-eql@4.0.2': resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} - '@types/diff@6.0.0': - resolution: {integrity: sha512-dhVCYGv3ZSbzmQaBSagrv1WJ6rXCdkyTcDyoNu1MD8JohI7pR7k8wdZEm+mvdxRKXyHVwckFzWU1vJc+Z29MlA==} - - '@types/estree@1.0.8': - resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - - '@types/he@1.2.3': - resolution: {integrity: sha512-q67/qwlxblDzEDvzHhVkwc1gzVWxaNxeyHUBF4xElrvjL11O+Ytze+1fGpBHlr/H9myiBUaUXNnNPmBHxxfAcA==} + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} '@types/jsesc@2.5.1': resolution: {integrity: sha512-9VN+6yxLOPLOav+7PwjZbxiID2bVaeq0ED4qSQmdQTdjnXJSaCVKTR58t15oqH1H5t8Ng2ZX1SabJVoN9Q34bw==} - '@types/mysql@2.15.27': - resolution: {integrity: sha512-YfWiV16IY0OeBfBCk8+hXKmdTKrKlwKN1MNKAPBu5JYxLwBEZl7QzeEpGnlZb3VMGJrrGmB84gXiH+ofs/TezA==} + '@types/mysql@2.15.26': + resolution: {integrity: sha512-DSLCOXhkvfS5WNNPbfn2KdICAmk8lLc+/PNvnPnF7gOdMZCxopXduqv0OQ13y/yA/zXTSikZZqVgybUxOEg6YQ==} - '@types/node@22.19.1': - resolution: {integrity: sha512-LCCV0HdSZZZb34qifBsyWlUmok6W7ouER+oQIGBScS8EsZsQbrtFTUrDX4hOl+CS6p7cnNC4td+qrSVGSCTUfQ==} + '@types/node@13.13.52': + resolution: {integrity: sha512-s3nugnZumCC//n4moGGe6tkNMyYEdaDBitVjwPxXmR5lnMG5dHePinH2EdxkG3Rh1ghFHHixAG4NJhpJW1rthQ==} - '@types/pg-pool@2.0.7': - resolution: {integrity: sha512-U4CwmGVQcbEuqpyju8/ptOKg6gEC+Tqsvj2xS9o1g71bUh8twxnC6ZL5rZKCsGN0iyH0CwgUyc9VR5owNQF9Ng==} + '@types/node@22.19.21': + resolution: {integrity: sha512-VMeFBSCKQKmm2swI2kW51SFusDqekC6q9trBCvJ/JliDchFSuoYYKN7yVNjPthP1HKZcx3U1gI/wTcEBjEFKTA==} - '@types/pg@8.15.6': - resolution: {integrity: sha512-NoaMtzhxOrubeL/7UZuNTrejB4MPAJ0RpxZqXQf2qXuVlTPuG6Y8p4u9dKRaue4yjmC7ZhzVO2/Yyyn25znrPQ==} + '@types/pg-pool@2.0.6': + resolution: {integrity: sha512-TaAUE5rq2VQYxab5Ts7WZhKNmuN78Q6PiFonTDdpbx8a1H0M1vhy3rhiMjl+e2iHmogyMw7jZF4FrE6eJUy5HQ==} - '@types/pg@8.20.0': - resolution: {integrity: sha512-bEPFOaMAHTEP1EzpvHTbmwR8UsFyHSKsRisLIHVMXnpNefSbGA1bD6CVy+qKjGSqmZqNqBDV2azOBo8TgkcVow==} + '@types/pg@8.6.1': + resolution: {integrity: sha512-1Kc4oAGzAl7uqUStZCDvaLFqZrW9qWSjXOmBfdgyBP5La7Us6Mg4GBvRlSoaZMhQF/zSj1C8CtKMBkoiT8eL8w==} - '@types/react@19.2.14': - resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} + '@types/shimmer@1.2.0': + resolution: {integrity: sha512-UE7oxhQLLd9gub6JKIAhDq06T0F6FnztwMNRvYgjeQSBeMc1ZG/tA47EwfduvkuQS8apbkM/lpLpWsaCeYsXVg==} '@types/tedious@4.0.14': resolution: {integrity: sha512-KHPsfX/FoVbUGbyYvk1q9MMQHLPeRZhRJZdO45Q4YjvFkv4hMNghCWTvy7rdKessBsmtz4euWCWAB6/tVpI1Iw==} + '@types/tinycolor2@1.4.6': + resolution: {integrity: sha512-iEN8J0BoMnsWBqjVbWH/c0G0Hh7O21lpR2/+PrvAVgWdzL7eexIFm4JN/Wn10PTcmNdtS6U67r499mlWMXOxNw==} + '@types/ws@8.18.1': resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} - '@vitest/coverage-v8@4.1.7': - resolution: {integrity: sha512-qsYPeXc5Q9dFLd1i8Ap+Bx8sQgcp+rFVQo4R0dDsWNBzl26ldVF1qOO+RL24K7FDrR6pA+50XedRLSoSG24bVQ==} + '@vitest/coverage-v8@4.1.8': + resolution: {integrity: sha512-lt3kovsyHwYe00wq4D1ti0Z974fWj4NLp6siqiyEufUpyFwK9Yhi7rBhac9JL5aA0zoMrJqc4vYPZRUnI7l7nw==} peerDependencies: - '@vitest/browser': 4.1.7 - vitest: 4.1.7 + '@vitest/browser': 4.1.8 + vitest: 4.1.8 peerDependenciesMeta: '@vitest/browser': optional: true - '@vitest/expect@4.1.7': - resolution: {integrity: sha512-1R+tw0ortHEbZDGMymm+pN7/AFQ/RkFFdtd7EN+VBpynKmLbP8A3rpEXdshBJ7+8hQ9zBJh/i1s0yKNtxAnU7w==} + '@vitest/expect@4.1.8': + resolution: {integrity: sha512-h3nDO677RDLEGlBxyQ5CW8RlMThSKSRLUePLOx09gNIWRL40edgA1GCZSZgf1W55MFAG6/Sw14KeaAnqv0NKdQ==} - '@vitest/mocker@4.1.7': - resolution: {integrity: sha512-vY7nuamKgfvpA1Koa3oYIw/k7D6kZnpGyNMZW8loow2bsBYla1TFdqTaXncWdRn4pgwNs+90RhnXhJScDwQeJA==} + '@vitest/mocker@4.1.8': + resolution: {integrity: sha512-LEiN/xe4OSIbKe9HQIp5OC24agGD9J5CnmMgsLohVVoOPWL9a2sBoR6VBx43jQZb7Kr1l4RCuyCJzcAa0+dojw==} peerDependencies: msw: ^2.4.9 - vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + vite: ^6.3.5 peerDependenciesMeta: msw: optional: true vite: optional: true - '@vitest/pretty-format@4.1.7': - resolution: {integrity: sha512-umgCarTOYQWIaDMvGDRZij+6b9oVeLIyJzfN+AS88e0ZOU3QTgNNSTtjQOpcvWr3np1N0j4WgZj+sb3oYBDscw==} + '@vitest/pretty-format@4.1.8': + resolution: {integrity: sha512-9GasEBxpZ1VYIpqHf/0+YGg121uSNwCKOJqIrTwWP/TB7DmFCiaBpNl3aPZzoLWfWkuqhbH8vJIVobZkvdo2cA==} - '@vitest/runner@4.1.7': - resolution: {integrity: sha512-BapjmAQ2aI78WdMEfeUWivnfVzB+VPGwWRQcJE0OUq7qEeEcBsCSf+0T5iREBNE5nBb4wA5Ya0W6IA+sghdEFw==} + '@vitest/runner@4.1.8': + resolution: {integrity: sha512-EmVxeBAfMJvycdjd6Hm+RbFBbA9fKvo0Kx37hNpBYoYeavH3RNsBXWDooR1mgD52dCrxIIuP7UotpfiwOikvcg==} - '@vitest/snapshot@4.1.7': - resolution: {integrity: sha512-ZacLzja+TmJeZ1h14xW2FB/WpeimUD3haBXQPyJqxvo8jQTmfeA8zv58mtjN2C7EHXZDYVcVYdYmAxjkWVvKCw==} + '@vitest/snapshot@4.1.8': + resolution: {integrity: sha512-acfZboRmAIf05DEKcBQy33VXojFJjtUdLyo7oOmV9kebb2xdU01UknNiPuPZoJZQyO7DF0gZdTGTpeAzET9QPQ==} - '@vitest/spy@4.1.7': - resolution: {integrity: sha512-kbkI5LMWakyuTIvs6fUJ5qdIVb1XVKsYJAT4OJ938cHMROYMSfmoQdZy0aaAnjbbc8F61vkoTqz/Az+/HiIu5Q==} + '@vitest/spy@4.1.8': + resolution: {integrity: sha512-6EevtBp6OZOPF7bmz36HrGMeP3txgVSrgebWxHOafDXGkhIzfXK14f8KF6MuFfgXXUeHxmpD3BQxkV00/3s5mA==} - '@vitest/utils@4.1.7': - resolution: {integrity: sha512-T532WBu791cBxJlCl6SO+J14l81DQx6uQHm1bQbmCDY7nqlEIgkza/UFnSBNaUtSf41unldDFjdOBYEQC4b5Hw==} - - '@vladfrangu/async_event_emitter@2.4.6': - resolution: {integrity: sha512-RaI5qZo6D2CVS6sTHFKg1v5Ohq/+Bo2LZ5gzUEwZ/WkHhwtGTCB/sVLw8ijOkAUxasZ+WshN/Rzj4ywsABJ5ZA==} - engines: {node: '>=v14.0.0', npm: '>=7.0.0'} + '@vitest/utils@4.1.8': + resolution: {integrity: sha512-uOJamYALNhfJ6iolExyQM40yIQwDqYnkKtQ5VCiSe17E33H0aQ/u+1GlRuz4LZBk6Mm3sg90G9hEbmEt37C1Zg==} '@vladfrangu/async_event_emitter@2.4.7': resolution: {integrity: sha512-Xfe6rpCTxSxfbswi/W/Pz7zp1WWSNn4A0eW4mLkQUewCrXXtMj31lCg+iQyTkh/CkusZSq9eDflu7tjEDXUY6g==} engines: {node: '>=v14.0.0', npm: '>=7.0.0'} - JSONStream@1.3.5: - resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} - hasBin: true + '@wolfstar/env-utilities@3.0.1': + resolution: {integrity: sha512-kUI0oNN62Snp1WvaIyeXGXZ2kQcjmurmKr6xYiu2E71ocJly73GacLdikoDRqn44bOJtUOyJnwtg3dBVkifQwQ==} + engines: {node: '>=18'} + + '@wolfstar/http-framework-i18n@3.0.1': + resolution: {integrity: sha512-wSxWgFvgKviKfnalSUduG6cSQ0F0i9GCHemxyp1AZepQsvtu5nHQfHj8F9y+SblQ/0K+xp8I/xVYczRmYWjSKA==} + engines: {node: '>=18'} + + '@wolfstar/http-framework@3.0.1': + resolution: {integrity: sha512-0kumXat6pWt8bsZK/RB5srRK+YuZAZBxRDs9wOQYexq1gmQWmIKY6izsR1bmidY7TvTVS732USNGlynsR4sXpw==} + engines: {node: '>=18'} + + '@wolfstar/i18next-backend@3.0.1': + resolution: {integrity: sha512-z5AHBJj7p6lLYth/bMRqzfuQEY9BXVKW/HMC8mcnrvRKmDmbXgXIrg9u+WiZyQEjXn7OoYTMA5HYiJRe68zgnQ==} + engines: {node: '>=18'} + + '@wolfstar/shared-http-pieces@3.0.1': + resolution: {integrity: sha512-shwMvnmBt1WnfLAPC2ZbOr5zeITap4SPWOsN8KbxFOu1w1QIsgPIOd/0gYVLi5IoafFovUwZuB59CQxE+t5OsQ==} + engines: {node: '>=16.9.0', npm: '>=8.0.0'} + + '@wolfstar/start-banner@3.0.1': + resolution: {integrity: sha512-Q1mRxbRMrHoVn6EOuxT4AzoR9fmknt7XkgqeF7yGVvcBxwaQmm5J6e63f+++JMbjsttfXcrRLqRVWHQ+WhvDLQ==} + engines: {node: '>=18'} + + abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} acorn-import-attributes@1.9.5: resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} peerDependencies: acorn: ^8 - acorn-node@1.8.2: - resolution: {integrity: sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==} - - acorn-walk@7.2.0: - resolution: {integrity: sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==} - engines: {node: '>=0.4.0'} - - acorn@7.4.1: - resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==} - engines: {node: '>=0.4.0'} - hasBin: true - - acorn@8.15.0: - resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + acorn@8.17.0: + resolution: {integrity: sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==} engines: {node: '>=0.4.0'} hasBin: true - ajv@8.17.1: - resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + ajv@8.20.0: + resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} ansi-escapes@4.3.2: resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} engines: {node: '>=8'} - ansi-escapes@7.2.0: - resolution: {integrity: sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw==} + ansi-escapes@7.3.0: + resolution: {integrity: sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==} engines: {node: '>=18'} ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} - ansi-styles@2.2.1: - resolution: {integrity: sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==} - engines: {node: '>=0.10.0'} - ansi-styles@3.2.1: resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} engines: {node: '>=4'} @@ -1989,8 +1641,8 @@ packages: resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} - ansis@4.2.0: - resolution: {integrity: sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==} + ansis@4.3.1: + resolution: {integrity: sha512-BJ8/l4R5LRE7hW9WdSuGYrLSHi2ynxeFpDFbH0K/CgNeY/tyhk+vO6TYxXC5r5CpUhNVX310xzPsN/H9lCdfOA==} engines: {node: '>=14'} argparse@2.0.1: @@ -1999,12 +1651,6 @@ packages: array-ify@1.0.0: resolution: {integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==} - asn1.js@4.10.1: - resolution: {integrity: sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==} - - assert@1.5.1: - resolution: {integrity: sha512-zzw1uCAgLbsKwBfFc8CX78DDg+xZeBksSO3vwVIDDN5i94eOrPsSSyiVhmsSABFDM/OcpE2aagCat9dnWQLG1A==} - assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} @@ -2013,160 +1659,54 @@ packages: resolution: {integrity: sha512-trmleAnZ2PxN/loHWVhhx1qeOHSRXq4TDsBBxq3GqeJitfk3+jTQ+v/C1km/KYq9M7wKqCewMh+/NAvVH7m+bw==} engines: {node: '>=20.19.0'} - ast-v8-to-istanbul@1.0.0: - resolution: {integrity: sha512-1fSfIwuDICFA4LKkCzRPO7F0hzFf0B7+Xqrl27ynQaa+Rh0e1Es0v6kWHPott3lU10AyAr7oKHa65OppjLn3Rg==} + ast-v8-to-istanbul@1.0.4: + resolution: {integrity: sha512-0bC0/4bTSrnwdhU3IsZDwEdojvuPrSg59OYZfKsLRtJZ0u8VBx9DebfqqG8bRdCC0I7vjgxmPi41P0lpkhJHtA==} at-least-node@1.0.0: resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} engines: {node: '>= 4.0.0'} - available-typed-arrays@1.0.7: - resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} - engines: {node: '>= 0.4'} - - aws-ssl-profiles@1.1.2: - resolution: {integrity: sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==} - engines: {node: '>= 6.0.0'} - balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - balanced-match@4.0.4: - resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} - engines: {node: 18 || 20 || >=22} - base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - better-result@2.8.2: - resolution: {integrity: sha512-YOf0VSj5nUPI27doTtXF+BBnsiRq3qY7avHqfIWnppxTLGyvkLq1QV2RTxkwoZwJ60ywLfZ0raFF4J/G886i7A==} - birpc@4.0.0: resolution: {integrity: sha512-LShSxJP0KTmd101b6DRyGBj57LZxSDYWKitQNW/mi8GRMvZb078Uf9+pveax1DrVL89vm7mWe+TovdI/UDOuPw==} bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} - bn.js@4.12.2: - resolution: {integrity: sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==} - - bn.js@5.2.2: - resolution: {integrity: sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==} - - brace-expansion@1.1.12: - resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} - - brace-expansion@5.0.5: - resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} - engines: {node: 18 || 20 || >=22} + brace-expansion@1.1.15: + resolution: {integrity: sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==} braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} - brorand@1.1.0: - resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} - - browser-pack@6.1.0: - resolution: {integrity: sha512-erYug8XoqzU3IfcU8fUgyHqyOXqIE4tUTTQ+7mqUjQlvnXkOO6OlT9c/ZoJVHYoAaqGxr09CN53G7XIsO4KtWA==} - hasBin: true - - browser-process-hrtime@0.1.3: - resolution: {integrity: sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw==} - - browser-resolve@2.0.0: - resolution: {integrity: sha512-7sWsQlYL2rGLy2IWm8WL8DCTJvYLc/qlOnsakDac87SOoCd16WLsaAMdCiAqsTNHIe+SXfaqyxyo6THoWqs8WQ==} - - browserify-aes@1.2.0: - resolution: {integrity: sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==} - - browserify-cipher@1.0.1: - resolution: {integrity: sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==} - - browserify-des@1.0.2: - resolution: {integrity: sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==} - - browserify-rsa@4.1.1: - resolution: {integrity: sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==} - engines: {node: '>= 0.10'} - - browserify-sign@4.2.5: - resolution: {integrity: sha512-C2AUdAJg6rlM2W5QMp2Q4KGQMVBwR1lIimTsUnutJ8bMpW5B52pGpR2gEnNBNwijumDo5FojQ0L9JrXA8m4YEw==} - engines: {node: '>= 0.10'} - - browserify-zlib@0.2.0: - resolution: {integrity: sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==} - - browserify@17.0.1: - resolution: {integrity: sha512-pxhT00W3ylMhCHwG5yfqtZjNnFuX5h2IJdaBfSo4ChaaBsIp9VLrEMQ1bHV+Xr1uLPXuNDDM1GlJkjli0qkRsw==} - engines: {node: '>= 0.8'} - hasBin: true - - buffer-from@1.1.2: - resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - - buffer-xor@1.0.3: - resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==} - - buffer@5.2.1: - resolution: {integrity: sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==} - buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} - bufferutil@4.1.0: - resolution: {integrity: sha512-ZMANVnAixE6AWWnPzlW2KpUrxhm9woycYvPOo67jWHyFowASTEd9s+QN1EIMsSDtwhIxN4sWE1jotpuDUIgyIw==} - engines: {node: '>=6.14.2'} - - builtin-status-codes@3.0.0: - resolution: {integrity: sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==} - - c12@3.3.4: - resolution: {integrity: sha512-cM0ApFQSBXuourJejzwv/AuPRvAxordTyParRVcHjjtXirtkzM0uK2L9TTn9s0cXZbG7E55jCivRQzoxYmRAlA==} - peerDependencies: - magicast: '*' - peerDependenciesMeta: - magicast: - optional: true + buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} cac@7.0.0: resolution: {integrity: sha512-tixWYgm5ZoOD+3g6UTea91eow5z6AAHaho3g0V9CNSNb45gM8SmflpAc+GRd1InC4AqN/07Unrgp56Y94N9hJQ==} engines: {node: '>=20.19.0'} - cached-path-relative@1.1.0: - resolution: {integrity: sha512-WF0LihfemtesFcJgO7xfOoOcnWzY/QHR4qeDqV44jPU3HTI54+LnfXK3SA27AVVGCdZFgjjFFaqUA9Jx7dMJZA==} - cachedir@2.3.0: resolution: {integrity: sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==} engines: {node: '>=6'} - call-bind-apply-helpers@1.0.2: - resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} - engines: {node: '>= 0.4'} - - call-bind@1.0.8: - resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} - engines: {node: '>= 0.4'} - - call-bound@1.0.4: - resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} - engines: {node: '>= 0.4'} - callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - camel-case@3.0.0: - resolution: {integrity: sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==} - chai@6.2.2: resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} engines: {node: '>=18'} - chalk@1.1.3: - resolution: {integrity: sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==} - engines: {node: '>=0.10.0'} - chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} @@ -2175,31 +1715,11 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} - chalk@5.6.2: - resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} - engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - chardet@0.7.0: resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} - chart.js@4.5.1: - resolution: {integrity: sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw==} - engines: {pnpm: '>=8'} - - chokidar@4.0.3: - resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} - engines: {node: '>= 14.16.0'} - - chokidar@5.0.0: - resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} - engines: {node: '>= 20.19.0'} - - cipher-base@1.0.7: - resolution: {integrity: sha512-Mz9QMT5fJe7bKI7MH31UilT5cEK5EHHRCccw/YRFsRY47AuNgaV6HY3rscp0/I4Q+tTW/5zoqpSeRRI54TkDWA==} - engines: {node: '>= 0.10'} - - cjs-module-lexer@2.2.0: - resolution: {integrity: sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==} + cjs-module-lexer@1.4.3: + resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==} cli-cursor@3.1.0: resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} @@ -2213,8 +1733,8 @@ packages: resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} engines: {node: '>=6'} - cli-truncate@5.1.1: - resolution: {integrity: sha512-SroPvNHxUnk+vIW/dOSfNqdy1sPEFkrTk6TUtqLCnBlo3N7TNYYkzzN7uSD6+jVjrdO4+p8nH7JzH6cIvUem6A==} + cli-truncate@5.2.0: + resolution: {integrity: sha512-xRwvIOMGrfOAnM1JYtqQImuaNtDEv9v6oIYAs4LIHwTiKee8uwvIi363igssOC0O5U04i4AlENs79LQLu9tEMw==} engines: {node: '>=20'} cli-width@3.0.0: @@ -2229,8 +1749,8 @@ packages: resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} engines: {node: '>=0.8'} - code-point-at@1.1.0: - resolution: {integrity: sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==} + cluster-key-slot@1.1.1: + resolution: {integrity: sha512-rwHwUfXL40Chm1r08yrhU3qpUvdVlgkKNeyeGPOxnW8/SyVDvgRaed/Uz54AqWNaTCAThlj6QAs3TZcKI0xDEw==} engines: {node: '>=0.10.0'} color-convert@1.9.3: @@ -2249,9 +1769,6 @@ packages: colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} - combine-source-map@0.8.0: - resolution: {integrity: sha512-UlxQ9Vw0b/Bt/KYwCFqdEwsQ1eL8d1gibiFb7lxQJFdvTgc2hIZi6ugsg+kyhzhPV+QEpUiEIwInIAIrgoEkrg==} - commander@14.0.3: resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==} engines: {node: '>=20'} @@ -2267,27 +1784,6 @@ packages: concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - concat-stream@1.6.2: - resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==} - engines: {'0': node >= 0.8} - - concat-stream@2.0.0: - resolution: {integrity: sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==} - engines: {'0': node >= 6.0} - - confbox@0.2.4: - resolution: {integrity: sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==} - - confusables@1.1.1: - resolution: {integrity: sha512-BzFtzUrufackm00Wb2zvrZV0ItRqPdWaUprU5FXHeZiJRrOWxGmXmQl/muGTF9EQl+MdBXz+Irk99meskGZmXw==} - engines: {node: '>=10', npm: '>=6'} - - console-browserify@1.2.0: - resolution: {integrity: sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==} - - constants-browserify@1.0.0: - resolution: {integrity: sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==} - conventional-changelog-angular@8.3.1: resolution: {integrity: sha512-6gfI3otXK5Ph5DfCOI1dblr+kN3FAm5a97hYoQkqNZxOaYa5WKfXH+AnpsmS+iUH2mgVC2Cg2Qw9m5OKcmNrIg==} engines: {node: '>=18'} @@ -2304,40 +1800,19 @@ packages: engines: {node: '>=18'} hasBin: true - convert-source-map@1.1.3: - resolution: {integrity: sha512-Y8L5rp6jo+g9VEPgvqNfEopjTR4OTYct8lXlS8iVQdmnjDvbdbzYe9rjtFCB9egC86JoNCU61WRY+ScjkZpnIg==} - - convert-source-map@1.9.0: - resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} - convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - cookie-es@1.2.2: - resolution: {integrity: sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==} - - core-util-is@1.0.3: - resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} - - cosmiconfig-typescript-loader@6.2.0: - resolution: {integrity: sha512-GEN39v7TgdxgIoNcdkRE3uiAzQt3UXLyHbRHD6YoL048XAeOomyxaP+Hh/+2C6C2wYjxJ2onhJcsQp+L4YEkVQ==} + cosmiconfig-typescript-loader@6.3.0: + resolution: {integrity: sha512-Akr82WH1Wfqatyiqpj8HDkO2o2KmJRu1FhKfSNJP3K4IdXwHfEyL7MOb62i1AGQVLtIQM+iCE9CGOtrfhR+mmA==} engines: {node: '>=v18'} peerDependencies: '@types/node': '*' cosmiconfig: '>=9' typescript: '>=5' - cosmiconfig@9.0.0: - resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==} - engines: {node: '>=14'} - peerDependencies: - typescript: '>=4.9.5' - peerDependenciesMeta: - typescript: - optional: true - - cosmiconfig@9.0.1: - resolution: {integrity: sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ==} + cosmiconfig@9.0.2: + resolution: {integrity: sha512-gtTZxTDau1wL7Y7zifc2dd8jHSK/k6BTx/2Xp/BpdlAdnlYWFVt7qhJqgwi7637yRwRQ3qL4ZidbB4I8tA5VOg==} engines: {node: '>=14'} peerDependencies: typescript: '>=4.9.5' @@ -2345,90 +1820,10 @@ packages: typescript: optional: true - create-ecdh@4.0.4: - resolution: {integrity: sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==} - - create-hash@1.2.0: - resolution: {integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==} - - create-hmac@1.1.7: - resolution: {integrity: sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==} - - cross-spawn@7.0.6: - resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} - engines: {node: '>= 8'} - - crypto-browserify@3.12.1: - resolution: {integrity: sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==} - engines: {node: '>= 0.10'} - - csstype@3.2.3: - resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - cz-conventional-changelog@3.3.0: resolution: {integrity: sha512-U466fIzU5U22eES5lTNiNbZ+d8dfcHcssH4o7QsdWaCcRs/feIPCxKYSWkYBNs5mny7MvEfwpTLWjvbm94hecw==} engines: {node: '>= 10'} - d3-array@2.12.1: - resolution: {integrity: sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==} - - d3-color@1.4.1: - resolution: {integrity: sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q==} - - d3-color@2.0.0: - resolution: {integrity: sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ==} - - d3-dispatch@1.0.6: - resolution: {integrity: sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA==} - - d3-drag@1.2.5: - resolution: {integrity: sha512-rD1ohlkKQwMZYkQlYVCrSFxsWPzI97+W+PaEIBNTMxRuxz9RF0Hi5nJWHGVJ3Om9d2fRTe1yOBINJyy/ahV95w==} - - d3-ease@1.0.7: - resolution: {integrity: sha512-lx14ZPYkhNx0s/2HX5sLFUI3mbasHjSSpwO/KaaNACweVwxUruKyWVcb293wMv1RqTPZyZ8kSZ2NogUZNcLOFQ==} - - d3-fg@6.14.0: - resolution: {integrity: sha512-M4QpFZOEvAq4ZDzwabJp2inL+KXS85T2SQl00zWwjnolaCJR+gHxUbT7Ha4GxTeW1NXwzbykhv/38I1fxQqbyg==} - - d3-format@2.0.0: - resolution: {integrity: sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA==} - - d3-hierarchy@1.1.9: - resolution: {integrity: sha512-j8tPxlqh1srJHAtxfvOUwKNYJkQuBFdM1+JAUfq6xqH5eAqf93L7oG1NVqDa4CpFZNvnNKtCYEUC8KY9yEn9lQ==} - - d3-interpolate@1.4.0: - resolution: {integrity: sha512-V9znK0zc3jOPV4VD2zZn0sDhZU3WAE2bmlxdIwwQPPzPjvyLkd8B3JUVdS1IDUFDkWZ72c9qnv1GK2ZagTZ8EA==} - - d3-interpolate@2.0.1: - resolution: {integrity: sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ==} - - d3-scale@3.3.0: - resolution: {integrity: sha512-1JGp44NQCt5d1g+Yy+GeOnZP7xHo0ii8zsQp6PGzd+C1/dl0KGsp9A7Mxwp+1D1o4unbTTxVdU/ZOIEBoeZPbQ==} - - d3-selection@1.4.2: - resolution: {integrity: sha512-SJ0BqYihzOjDnnlfyeHT0e30k0K1+5sR3d5fNueCNeuhZTnGw4M4o8mqJchSwgKMXCNFo+e2VTChiSJ0vYtXkg==} - - d3-time-format@3.0.0: - resolution: {integrity: sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag==} - - d3-time@2.1.1: - resolution: {integrity: sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ==} - - d3-timer@1.0.10: - resolution: {integrity: sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw==} - - d3-transition@1.3.2: - resolution: {integrity: sha512-sc0gRU4PFqZ47lPVHloMn9tlPcv8jxgOQg+0zjhfZXMQuvppjG6YuwdMBE0TuqCZjeJkLecku/l9R0JPcRhaDA==} - - d3-zoom@1.8.3: - resolution: {integrity: sha512-VoLXTK4wvy1a0JpH2Il+F2CiOhVu7VRXWF5M/LroMIh3/zBAC3WAt7QoIvPibOavVo20hN6/37vwAsdBejLyKQ==} - - dash-ast@1.0.0: - resolution: {integrity: sha512-Vy4dx7gquTeMcQR/hDkYLGUnwVil6vk4FOOct+djUnHOUWt+zJPJAaRIXaAFkPXtJjvlY7o3rfRu0/3hpnwoUA==} - - debounce@1.2.1: - resolution: {integrity: sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==} - debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -2441,24 +1836,9 @@ packages: dedent@0.7.0: resolution: {integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==} - deepmerge-ts@7.1.5: - resolution: {integrity: sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==} - engines: {node: '>=16.0.0'} - defaults@1.0.4: resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} - define-data-property@1.1.4: - resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} - engines: {node: '>= 0.4'} - - define-properties@1.2.1: - resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} - engines: {node: '>= 0.4'} - - defined@1.0.1: - resolution: {integrity: sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==} - defu@6.1.7: resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} @@ -2466,13 +1846,6 @@ packages: resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} engines: {node: '>=0.10'} - deps-sort@2.0.1: - resolution: {integrity: sha512-1orqXQr5po+3KI6kQb9A4jnXT1PBwggGl2d7Sq2xsnOeI9GPcE/tGcF9UiSZtZBM7MukY4cAh7MemS6tZYipfw==} - hasBin: true - - des.js@1.1.0: - resolution: {integrity: sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==} - destr@2.0.5: resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} @@ -2484,29 +1857,13 @@ packages: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} - detective@5.2.1: - resolution: {integrity: sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==} - engines: {node: '>=0.8.0'} - hasBin: true - - diff@9.0.0: - resolution: {integrity: sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw==} - engines: {node: '>=0.3.1'} - - diffie-hellman@5.0.3: - resolution: {integrity: sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==} - - discord-api-types@0.38.34: - resolution: {integrity: sha512-muq7xKGznj5MSFCzuIm/2TO7DpttuomUTemVM82fRqgnMl70YRzEyY24jlbiV6R9tzOTq6A6UnZ0bsfZeKD38Q==} + discord-api-types@0.38.48: + resolution: {integrity: sha512-WFUE/2o0lBlLeCQonQ+Pu2RqHAqbytBJ2RlXR91gzk05InSS6k9ShzzLYoymrA4c2oRgRKGE7/VqQJNNdGWSxQ==} discord.js@14.26.4: resolution: {integrity: sha512-4oBp8tc6Kf8IDBwAHhbsMaAqx1b5fob9SNasZT7V6yyyUydoO5i5fGuX7TmvRtR+q/WgKRnRViRoAWnG7fNyvA==} engines: {node: '>=18'} - domain-browser@1.2.0: - resolution: {integrity: sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==} - engines: {node: '>=0.4', npm: '>=1.2'} - dot-prop@5.3.0: resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} engines: {node: '>=8'} @@ -2532,46 +1889,20 @@ packages: oxc-resolver: optional: true - dunder-proto@1.0.1: - resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} - engines: {node: '>= 0.4'} - - duplexer2@0.1.4: - resolution: {integrity: sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==} - - duplexify@4.1.3: - resolution: {integrity: sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==} - - effect@3.20.0: - resolution: {integrity: sha512-qMLfDJscrNG8p/aw+IkT9W7fgj50Z4wG5bLBy0Txsxz8iUHjDIkOgO3SV0WZfnQbNG2VJYb0b+rDLMrhM4+Krw==} - - elliptic@6.6.1: - resolution: {integrity: sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==} - emoji-regex@10.6.0: resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - empathic@2.0.0: - resolution: {integrity: sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==} + empathic@2.0.1: + resolution: {integrity: sha512-YGRs8knHhKHVShLkFET/rWAU8kmHbOV5LwN938RHI0pljAJ1Gf6SzXsSmRaEzcXTtOOmVqJ5+WtQPL5uigY50Q==} engines: {node: '>=14'} - end-of-stream@1.4.5: - resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} - env-paths@2.2.1: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} - env-paths@3.0.0: - resolution: {integrity: sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - env-string@1.0.1: - resolution: {integrity: sha512-/DhCJDf5DSFK32joQiWRpWrT0h7p3hVQfMKxiBb7Nt8C8IF8BYyPtclDnuGGLOoj16d/8udKeiE7JbkotDmorQ==} - environment@1.1.0: resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} engines: {node: '>=18'} @@ -2579,10 +1910,6 @@ packages: error-ex@1.3.4: resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} - es-define-property@1.0.1: - resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} - engines: {node: '>= 0.4'} - es-errors@1.3.0: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} @@ -2590,12 +1917,8 @@ packages: es-module-lexer@2.1.0: resolution: {integrity: sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==} - es-object-atoms@1.1.1: - resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} - engines: {node: '>= 0.4'} - - es-toolkit@1.46.1: - resolution: {integrity: sha512-5eNtXOs3tbfxXOj04tjjseeWkRWaoCjdEI+96DgwzZoe6c9juL49pXlzAFTI72aWC9Y8p7168g6XIKjh7k6pyQ==} + es-toolkit@1.47.0: + resolution: {integrity: sha512-n1GuoD0WEQZMBk5tttoZSqwgyLx01oqa5XsBmCHwPyNe1S9jPBEmtR2pSgp2kJuWE3ciFZ6yRHmY4pM4C3OOkw==} esbuild@0.25.12: resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} @@ -2610,82 +1933,20 @@ packages: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} - escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - - estree-is-member-expression@1.0.0: - resolution: {integrity: sha512-Ec+X44CapIGExvSZN+pGkmr5p7HwUVQoPQSd458Lqwvaf4/61k/invHSh4BYK8OXnCkfEhWuIoG5hayKLQStIg==} - estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} - eventemitter3@5.0.1: - resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + event-target-shim@5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} + + eventemitter3@5.0.4: + resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} events@3.3.0: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} - evlog@2.16.0: - resolution: {integrity: sha512-qpIt+5+5hY8hxpca4vFTxR3x5jcnEC5DQh9OffR1mZWFfX2wui7ksh9I0AUUxRNP8ttlU/QN/JPVbSj5nepJ9w==} - peerDependencies: - '@nestjs/common': '>=11.1.19' - '@nuxt/kit': ^4.4.2 - '@tanstack/start-client-core': ^1.167.20 - ai: '>=6.0.168' - elysia: '>=1.4.28' - express: '>=5.2.1' - fastify: '>=5.8.5' - h3: ^1.15.11 - hono: '' - next: '>=16.2.4' - nitro: ^3.0.260311-beta - nitropack: ^2.13.3 - ofetch: ^1.5.1 - react: '>=19.2.5' - react-router: '>=7.14.2' - vite: ^7.0.0 || ^8.0.0 - peerDependenciesMeta: - '@nestjs/common': - optional: true - '@nuxt/kit': - optional: true - '@tanstack/start-client-core': - optional: true - ai: - optional: true - elysia: - optional: true - express: - optional: true - fastify: - optional: true - h3: - optional: true - hono: - optional: true - next: - optional: true - nitro: - optional: true - nitropack: - optional: true - ofetch: - optional: true - react: - optional: true - react-router: - optional: true - vite: - optional: true - - evp_bytestokey@1.0.3: - resolution: {integrity: sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==} - - execspawn@1.0.1: - resolution: {integrity: sha512-s2k06Jy9i8CUkYe0+DxRlvtkZoOkwwfhB+Xxo5HGUtrISVW2m98jO2tr67DGRFxZwkjQqloA3v/tNtjhBRBieg==} - expand-tilde@2.0.2: resolution: {integrity: sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==} engines: {node: '>=0.10.0'} @@ -2694,25 +1955,15 @@ packages: resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} - exsolve@1.0.8: - resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} - external-editor@3.1.0: resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} engines: {node: '>=4'} - fast-check@3.23.2: - resolution: {integrity: sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==} - engines: {node: '>=8.0.0'} - fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - fast-safe-stringify@2.1.1: - resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} - - fast-uri@3.1.0: - resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + fast-uri@3.1.2: + resolution: {integrity: sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==} fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} @@ -2727,6 +1978,10 @@ packages: resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} engines: {node: '>=8'} + file-type@18.7.0: + resolution: {integrity: sha512-ihHtXRzXEziMrQ56VSgU7wkxh55iNchFkosu7Y9/S+tXHdKyrGjVK0ujbqNnsxzea+78MaLhN6PGmfYSAv1ACw==} + engines: {node: '>=14.16'} + fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} @@ -2737,29 +1992,13 @@ packages: find-root@1.1.0: resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==} - find-up-simple@1.0.1: - resolution: {integrity: sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==} - engines: {node: '>=18'} - findup-sync@4.0.0: resolution: {integrity: sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==} engines: {node: '>= 8'} - for-each@0.3.5: - resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} - engines: {node: '>= 0.4'} - - foreground-child@3.3.1: - resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} - engines: {node: '>=14'} - forwarded-parse@2.1.2: resolution: {integrity: sha512-alTFZZQDKMporBH77856pXgzhEzaUVmLCDk+egLgIgHst3Tpndzz8MnKe+GzRJRfvVdn69HhpW7cmXzvtLvJAw==} - fs-extra@10.1.0: - resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} - engines: {node: '>=12'} - fs-extra@9.1.0: resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} engines: {node: '>=10'} @@ -2778,43 +2017,18 @@ packages: fzf@0.5.2: resolution: {integrity: sha512-Tt4kuxLXFKHy8KT40zwsUPUkg1CrsgY25FxA2U/j/0WgEDCk3ddc/zLTCCcbSHX9FcKtLuVaDGtGE/STWC+j3Q==} - generate-function@2.3.1: - resolution: {integrity: sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==} - - generator-function@2.0.1: - resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} - engines: {node: '>= 0.4'} - - get-assigned-identifiers@1.2.0: - resolution: {integrity: sha512-mBBwmeGTrxEMO4pMaaf/uUEFHnYtwr8FTe8Y/mer4rcV/bye0qGm6pw1bGZFGStxC5O76c5ZAVBGnqHmOaJpdQ==} - get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} - get-east-asian-width@1.4.0: - resolution: {integrity: sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==} + get-east-asian-width@1.6.0: + resolution: {integrity: sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==} engines: {node: '>=18'} - get-intrinsic@1.3.0: - resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} - engines: {node: '>= 0.4'} - - get-port-please@3.2.0: - resolution: {integrity: sha512-I9QVvBw5U/hw3RmWpYKRumUeaDgxTPd401x364rLmWBJcOQ753eov1eTgzDqRG9bqFIfDc7gfzcQEWrUri3o1A==} - - get-proto@1.0.1: - resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} - engines: {node: '>= 0.4'} - get-tsconfig@5.0.0-beta.5: resolution: {integrity: sha512-/6gFNr0N04nob252sTQxyFLi3eKFRqIg1I87YcqAMT1i6SQrSF6KujUEQrtrjMV0H/eejTCltLdDSTEMzHbnsQ==} engines: {node: '>=20.20.0'} - giget@3.2.0: - resolution: {integrity: sha512-GvHTWcykIR/fP8cj8dMpuMMkvaeJfPvYnhq0oW+chSeIr+ldX21ifU2Ms6KBoyKZQZmVaUAAhQ2EZ68KJF8a7A==} - hasBin: true - git-raw-commits@5.0.1: resolution: {integrity: sha512-Y+csSm2GD/PCSh6Isd/WiMjNAydu0VBiG9J7EdQsNA5P9uXvLayqjmTsNlK5Gs9IhblFZqOU0yid5Il5JPoLiQ==} engines: {node: '>=18'} @@ -2824,10 +2038,6 @@ packages: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - global-directory@4.0.1: - resolution: {integrity: sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==} - engines: {node: '>=18'} - global-directory@5.0.0: resolution: {integrity: sha512-1pgFdhK3J2LeM+dVf2Pd424yHx2ou338lC0ErNP2hPx4j8eW1Sp0XqSjNxtk6Tc4Kr5wlWtSvz8cn2yb7/SG/w==} engines: {node: '>=20'} @@ -2840,22 +2050,12 @@ packages: resolution: {integrity: sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==} engines: {node: '>=0.10.0'} - gopd@1.2.0: - resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} - engines: {node: '>= 0.4'} - graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - grammex@3.1.12: - resolution: {integrity: sha512-6ufJOsSA7LcQehIJNCO7HIBykfM7DXQual0Ny780/DEcJIpBlHRvcqEBWGPYd7hrXL2GJ3oJI1MIhaXjWmLQOQ==} - - graphmatch@1.1.1: - resolution: {integrity: sha512-5ykVn/EXM1hF0XCaWh05VbYvEiOL2lY1kBxZtaYsyvjp7cmWOU1XsAdfQBwClraEofXDT197lFbXOEVMHpvQOg==} - - has-ansi@2.0.0: - resolution: {integrity: sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==} - engines: {node: '>=0.10.0'} + gradient-string@2.0.2: + resolution: {integrity: sha512-rEDCuqUQ4tbD78TpzsMtt5OIf0cBCSDWSJtUDaF6JsAh+k0v9r++NzxNEG87oDZx9ZwGhD8DaezR2L/yrw0Jdw==} + engines: {node: '>=10'} has-flag@3.0.0: resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} @@ -2865,109 +2065,44 @@ packages: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} - has-property-descriptors@1.0.2: - resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} - - has-symbols@1.1.0: - resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} - engines: {node: '>= 0.4'} - - has-tostringtag@1.0.2: - resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} - engines: {node: '>= 0.4'} - - has-unicode@2.0.1: - resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} - - hash-base@3.0.5: - resolution: {integrity: sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==} - engines: {node: '>= 0.10'} - - hash-base@3.1.2: - resolution: {integrity: sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg==} - engines: {node: '>= 0.8'} - - hash.js@1.1.7: - resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} - - hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + hasown@2.0.4: + resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} engines: {node: '>= 0.4'} - he@1.2.0: - resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} - hasBin: true - - hmac-drbg@1.0.1: - resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} - homedir-polyfill@1.0.3: resolution: {integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==} engines: {node: '>=0.10.0'} - hono@4.12.12: - resolution: {integrity: sha512-p1JfQMKaceuCbpJKAPKVqyqviZdS0eUxH9v82oWo1kb9xjQ5wA6iP3FNVAPDFlz5/p7d45lO+BpSk1tuSZMF4Q==} - engines: {node: '>=16.9.0'} - hookable@6.1.1: resolution: {integrity: sha512-U9LYDy1CwhMCnprUfeAZWZGByVbhd54hwepegYTK7Pi5NvqEj63ifz5z+xukznehT7i6NIZRu89Ay1AZmRsLEQ==} - hsl-to-rgb-for-reals@1.1.1: - resolution: {integrity: sha512-LgOWAkrN0rFaQpfdWBQlv/VhkOxb5AsBjk6NQVx4yEzWS923T07X0M1Y0VNko2H52HeSpZrZNNMJ0aFqsdVzQg==} - html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} - htmlescape@1.1.1: - resolution: {integrity: sha512-eVcrzgbR4tim7c7soKQKtxa/kQM4TzjnlU83rcZ9bHU6t31ehfV7SktN6McWgwPWg+JYMA/O3qpGxBvFq1z2Jg==} - engines: {node: '>=0.10'} - - http-status-codes@2.3.0: - resolution: {integrity: sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA==} - - https-browserify@1.0.0: - resolution: {integrity: sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==} - husky@9.1.7: resolution: {integrity: sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==} engines: {node: '>=18'} hasBin: true - hyperscript-attribute-to-property@1.0.2: - resolution: {integrity: sha512-oerMul16jZCmrbNsUw8QgrtDzF8lKgFri1bKQjReLw1IhiiNkI59CWuzZjJDGT79UQ1YiWqXhJMv/tRMVqgtkA==} - - hyperx@2.5.4: - resolution: {integrity: sha512-iOkSh7Yse7lsN/B9y7OsevLWjeXPqGuHQ5SbwaiJM5xAhWFqhoN6erpK1dQsS12OFU36lyai1pnx1mmzWLQqcA==} - - i18next@25.6.3: - resolution: {integrity: sha512-AEQvoPDljhp67a1+NsnG/Wb1Nh6YoSvtrmeEd24sfGn3uujCtXCF3cXpr7ulhMywKNFF7p3TX1u2j7y+caLOJg==} - peerDependencies: - typescript: ^5 - peerDependenciesMeta: - typescript: - optional: true + i18next@22.5.1: + resolution: {integrity: sha512-8TGPgM3pAD+VRsMtUMNknRz3kzqwp/gPALrWMsDnmC1mKqJwpWyooQRLMcbTwq8z8YwSmuj+ZYvc+xCuEpkssA==} iconv-lite@0.4.24: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} - iconv-lite@0.7.2: - resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} - engines: {node: '>=0.10.0'} - ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + immediate@3.0.6: + resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} + import-fresh@3.3.1: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} - import-in-the-middle@2.0.6: - resolution: {integrity: sha512-3vZV3jX0XRFW3EJDTwzWoZa+RH1b8eTTx6YOCjglrLyPuepwoBti1k3L2dKwdCUrnVEfc5CuRuGstaC/uQJJaw==} - - import-in-the-middle@3.0.1: - resolution: {integrity: sha512-pYkiyXVL2Mf3pozdlDGV6NAObxQx13Ae8knZk1UJRJ6uRW/ZRmTGHlQYtrsSl7ubuE5F8CD1z+s1n4RHNuTtuA==} - engines: {node: '>=18'} + import-in-the-middle@1.15.0: + resolution: {integrity: sha512-bpQy+CrsRmYmoPMAE/0G33iwRqwW4ouqdRg8jgbH3aKuCtOc8lxgmYXg2dMM92CRiGP660EtBcymH/eVUpCSaA==} import-meta-resolve@4.2.0: resolution: {integrity: sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==} @@ -2980,70 +2115,35 @@ packages: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. - inherits@2.0.3: - resolution: {integrity: sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==} - inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} ini@1.3.8: resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} - ini@4.1.1: - resolution: {integrity: sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - ini@6.0.0: resolution: {integrity: sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==} engines: {node: ^20.17.0 || >=22.9.0} - inline-source-map@0.6.3: - resolution: {integrity: sha512-1aVsPEsJWMJq/pdMU61CDlm1URcW702MTB4w9/zUjMus6H/Py8o7g68Pr9D4I6QluWGt/KdmswuRhaA05xVR1w==} - inquirer@8.2.5: resolution: {integrity: sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==} engines: {node: '>=12.0.0'} - insert-module-globals@7.2.1: - resolution: {integrity: sha512-ufS5Qq9RZN+Bu899eA9QCAYThY+gGW7oRkmb0vC93Vlyu/CFGcH0OYPEjVkDXA5FEbTt1+VWzdoOD3Ny9N+8tg==} - hasBin: true - - internmap@1.0.1: - resolution: {integrity: sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==} - - is-arguments@1.2.0: - resolution: {integrity: sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==} - engines: {node: '>= 0.4'} - - is-arrayish@0.2.1: - resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - - is-boolean-attribute@0.0.1: - resolution: {integrity: sha512-0kXT52Scokg2Miscvsn5UVqg6y1691vcLJcagie1YHJB4zOEuAhMERLX992jtvaStGy2xQTqOtJhvmG/MK1T5w==} - - is-buffer@1.1.6: - resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} - - is-buffer@2.0.5: - resolution: {integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==} - engines: {node: '>=4'} + ioredis@5.11.1: + resolution: {integrity: sha512-ehuGcf94bQXhfagULNXrJdfnWO38v070jxSx/qE87Kjzmu2fU7ro5EFAb+OPituLqgfyuQaym5DlrNydW2sJ9A==} + engines: {node: '>=12.22.0'} - is-callable@1.2.7: - resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} - engines: {node: '>= 0.4'} + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - is-core-module@2.16.1: - resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + is-core-module@2.16.2: + resolution: {integrity: sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==} engines: {node: '>= 0.4'} is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} - is-fullwidth-code-point@1.0.0: - resolution: {integrity: sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==} - engines: {node: '>=0.10.0'} - is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} @@ -3052,10 +2152,6 @@ packages: resolution: {integrity: sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==} engines: {node: '>=18'} - is-generator-function@1.1.2: - resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} - engines: {node: '>= 0.4'} - is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} @@ -3076,17 +2172,6 @@ packages: resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} engines: {node: '>=12'} - is-property@1.0.2: - resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==} - - is-regex@1.2.1: - resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} - engines: {node: '>= 0.4'} - - is-typed-array@1.1.15: - resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} - engines: {node: '>= 0.4'} - is-unicode-supported@0.1.0: resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} engines: {node: '>=10'} @@ -3098,16 +2183,6 @@ packages: resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} engines: {node: '>=0.10.0'} - is-wsl@1.1.0: - resolution: {integrity: sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==} - engines: {node: '>=4'} - - isarray@1.0.0: - resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} - - isarray@2.0.5: - resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} - isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} @@ -3123,6 +2198,9 @@ packages: resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} engines: {node: '>=8'} + ix@5.0.0: + resolution: {integrity: sha512-6LyyrHnvNrSy5pKtW/KA+KKusHrB223aBJCJlIGPN7QBfDkEEtNrAkAz9lLLShIcdJntq6BiPCHuKaCM/9wwXw==} + jiti@2.6.1: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true @@ -3133,8 +2211,8 @@ packages: js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - js-yaml@4.1.1: - resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} + js-yaml@4.2.0: + resolution: {integrity: sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==} hasBin: true jsesc@3.1.0: @@ -3148,20 +2226,11 @@ packages: json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - jsonfile@6.2.0: - resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} - - jsonparse@1.3.1: - resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} - engines: {'0': node >= 0.2.0} - - jsonstream2@3.0.0: - resolution: {integrity: sha512-8ngq2XB8NjYrpe3+Xtl9lFJl6RoV2dNT4I7iyaHwxUpTBwsj0AlAR7epGfeYVP0z4Z7KxMoSxRgJWrd2jmBT/Q==} - engines: {node: '>=5.10.0'} - hasBin: true + jsonfile@6.2.1: + resolution: {integrity: sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==} - labeled-stream-splicer@2.0.2: - resolution: {integrity: sha512-Ca4LSXFFZUjPScRaqOcFxneA0VpKZr4MMYCljyQr4LIewTLb3Y0IUTIsnBBsVubIeEfxeSZpSjSsRM8APEQaAw==} + lie@3.1.1: + resolution: {integrity: sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==} lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} @@ -3175,30 +2244,21 @@ packages: resolution: {integrity: sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==} engines: {node: '>=20.0.0'} - lodash.isplainobject@4.0.6: - resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + localforage@1.10.0: + resolution: {integrity: sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==} lodash.map@4.6.0: resolution: {integrity: sha512-worNHGKLDetmcEYDvh2stPCrrQRkP20E4l0iIS7F8EvzMqBBi7ltvFN5m1HvTf1P7Jk1txKhvFcmYsCr8O2F1Q==} - lodash.memoize@3.0.4: - resolution: {integrity: sha512-eDn9kqrAmVUC1wmZvlQ6Uhde44n+tXpqPrN8olQJbttgh0oKclk+SF54P47VEGE9CEiMeRwAP8BaM7UHvBkz2A==} - - lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - - lodash.mergewith@4.6.2: - resolution: {integrity: sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==} - lodash.snakecase@4.1.1: resolution: {integrity: sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==} - lodash.uniq@4.5.0: - resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} - lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + lodash@4.18.1: + resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==} + log-symbols@4.1.0: resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} engines: {node: '>=10'} @@ -3207,57 +2267,27 @@ packages: resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} engines: {node: '>=18'} - long@5.3.2: - resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} - longest@2.0.1: resolution: {integrity: sha512-Ajzxb8CM6WAnFjgiloPsI3bF+WCxcvhdIG3KNA2KN962+tdBsHcuQ4k4qX/EcS/2CRkcc0iAkR956Nib6aXU/Q==} engines: {node: '>=0.10.0'} - lower-case@1.1.4: - resolution: {integrity: sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==} - - lru.min@1.1.4: - resolution: {integrity: sha512-DqC6n3QQ77zdFpCMASA1a3Jlb64Hv2N2DciFGkO/4L9+q/IpIAuRlKOvCXabtRW6cQf8usbmM6BE/TOPysCdIA==} - engines: {bun: '>=1.0.0', deno: '>=1.30.0', node: '>=8.0.0'} - - magic-bytes.js@1.12.1: - resolution: {integrity: sha512-ThQLOhN86ZkJ7qemtVRGYM+gRgR8GEXNli9H/PMvpnZsE44Xfh3wx9kGJaldg314v85m+bFW6WBMaVHJc/c3zA==} - magic-bytes.js@1.13.0: resolution: {integrity: sha512-afO2mnxW7GDTXMm5/AoN1WuOcdoKhtgXjIvHmobqTD1grNplhGdv3PFOyjCVmrnOZBIT/gD/koDKpYG+0mvHcg==} - magic-string@0.23.2: - resolution: {integrity: sha512-oIUZaAxbcxYIp4AyLafV6OVKoB3YouZs0UTCJ8mOKBHNyJgGDaMJ4TgA+VylJh6fx7EQCC52XkbURxxG9IoJXA==} - magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - magicast@0.5.2: - resolution: {integrity: sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==} - - make-dir@3.1.0: - resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} - engines: {node: '>=8'} + magicast@0.5.3: + resolution: {integrity: sha512-pVKE4UdSQ7DvHzivsCIFx2BJn1mHG6KsyrFcaxFx6tONdneEuThrDx0Cj3AMg58KyN4pzYT+LHOotxDQDjNvkw==} make-dir@4.0.0: resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} engines: {node: '>=10'} - math-intrinsics@1.1.0: - resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} - engines: {node: '>= 0.4'} - - md5.js@1.3.5: - resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==} - meow@13.2.0: resolution: {integrity: sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==} engines: {node: '>=18'} - merge-source-map@1.0.4: - resolution: {integrity: sha512-PGSmS0kfnTnMJCzJ16BLLCEe6oeYCamKFFdQKshi4BmM6FUwipjVOcBFGxqtQtirtAG4iZvHlqST9CpZKqlRjA==} - merge@2.1.1: resolution: {integrity: sha512-jz+Cfrg9GWOZbQAnDQ4hlVnQky+341Yk5ru8bZSe6sIDTCIg8n9i/u7hSQGSVOF3C7lH6mGtqjkiT9G4wFLL0w==} @@ -3265,10 +2295,6 @@ packages: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} - miller-rabin@4.0.1: - resolution: {integrity: sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==} - hasBin: true - mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} @@ -3277,114 +2303,36 @@ packages: resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} engines: {node: '>=18'} - minimalistic-assert@1.0.1: - resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} - - minimalistic-crypto-utils@1.0.1: - resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} - - minimatch@10.2.5: - resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} - engines: {node: 18 || 20 || >=22} - - minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + minimatch@3.1.5: + resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - mkdirp-classic@0.5.3: - resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} - - module-deps@6.2.3: - resolution: {integrity: sha512-fg7OZaQBcL4/L+AK5f4iVqf9OMbCclXfy/znXRxTVhJSeW5AIlS9AwheYwDaXM3lVW7OBeaeUEY3gbaC6cLlSA==} - engines: {node: '>= 0.8.0'} - hasBin: true - module-details-from-path@1.0.4: resolution: {integrity: sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==} - morphdom@2.7.7: - resolution: {integrity: sha512-04GmsiBcalrSCNmzfo+UjU8tt3PhZJKzcOy+r1FlGA7/zri8wre3I1WkYN9PT3sIeIKfW9bpyElA+VzOg2E24g==} - ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} mute-stream@0.0.8: resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} - mutexify@1.4.0: - resolution: {integrity: sha512-pbYSsOrSB/AKN5h/WzzLRMFgZhClWccf2XIB4RSMC8JbquiB0e0/SH5AIfdQMdyHmYtv4seU7yV/TvAwPLJ1Yg==} - - mysql2@3.15.3: - resolution: {integrity: sha512-FBrGau0IXmuqg4haEZRBfHNWB5mUARw6hNwPDXXGg0XzVJ50mr/9hb267lvpVMnhZ1FON3qNd4Xfcez1rbFwSg==} - engines: {node: '>= 8.0'} - - named-placeholders@1.1.6: - resolution: {integrity: sha512-Tz09sEL2EEuv5fFowm419c1+a/jSMiBjI9gHxVLrVdbUkkNUUfjsVYs9pVZu5oCon/kmRh9TfLEObFtkVxmY0w==} - engines: {node: '>=8.0.0'} - - nan@2.23.1: - resolution: {integrity: sha512-r7bBUGKzlqk8oPBDYxt6Z0aEdF1G1rwlMcLk8LCOMbOzf0mG+JUfUzG4fIMWwHWP0iyaLWEQZJmtB7nOHEm/qw==} - - nanoassert@1.1.0: - resolution: {integrity: sha512-C40jQ3NzfkP53NsO8kEOFd79p4b9kDXQMwgiY1z8ZwrDZgUyom0AHwGegF4Dm99L+YoYhuaB0ceerUcXmqr1rQ==} - - nanobench@2.1.1: - resolution: {integrity: sha512-z+Vv7zElcjN+OpzAxAquUayFLGK3JI/ubCl0Oh64YQqsTGG09CGqieJVQw4ui8huDnnAgrvTv93qi5UaOoNj8A==} - hasBin: true - - nanohtml@1.10.0: - resolution: {integrity: sha512-r/3AQl+jxAxUIJRiKExUjBtFcE1cm4yTOsTIdVqqlxPNtBxJh522ANrcQYzdNHhPzbPgb7j6qujq6eGehBX0kg==} - nanoid@3.3.12: resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - no-case@2.3.2: - resolution: {integrity: sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==} - node-fetch-native@1.6.7: resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} - node-gyp-build@4.8.4: - resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} - hasBin: true - - normalize-html-whitespace@0.2.0: - resolution: {integrity: sha512-5CZAEQ4bQi8Msqw0GAT6rrkrjNN4ZKqAG3+jJMwms4O6XoMvh6ekwOueG4mRS1LbPUR1r9EdnhxxfpzMTOdzKw==} - engines: {node: '>= 0.10'} - - number-is-nan@1.0.1: - resolution: {integrity: sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==} - engines: {node: '>=0.10.0'} - - object-inspect@1.13.4: - resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} - engines: {node: '>= 0.4'} - - object-keys@1.1.1: - resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} - engines: {node: '>= 0.4'} - - object.assign@4.1.7: - resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} - engines: {node: '>= 0.4'} - - obug@2.1.1: - resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + obug@2.1.2: + resolution: {integrity: sha512-AWGB9WFcRXOQs48Z/udjI5ZcZMHXwX8XPByNpOydgcGsDLIzjGizhoMWJyKAWze7AVW/2W1i+/gPX4YtKe5cyg==} + engines: {node: '>=12.20.0'} ofetch@1.5.1: resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==} - ohash@2.0.11: - resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} - - on-net-listen@1.1.2: - resolution: {integrity: sha512-y1HRYy8s/RlcBvDUwKXSmkODMdx4KSuIvloCnQYJ2LdBBC1asY4HtfhXwe3UWknLakATZDnbzht2Ijw3M1EqFg==} - engines: {node: '>=9.4.0 || ^8.9.4'} - once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -3396,17 +2344,10 @@ packages: resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} engines: {node: '>=18'} - opn@5.5.0: - resolution: {integrity: sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==} - engines: {node: '>=4'} - ora@5.4.1: resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} engines: {node: '>=10'} - os-browserify@0.3.0: - resolution: {integrity: sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==} - os-tmpdir@1.0.2: resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} engines: {node: '>=0.10.0'} @@ -3421,33 +2362,26 @@ packages: svelte: optional: true - oxlint@1.66.0: - resolution: {integrity: sha512-N4LLxYLd94KEBqXDMDM5f+2PUpItTjDLreXe2Gn5KhjhCK4Qp2YUXaBi8Yu325ryOgKwt22m45fpD7nPOn69Yw==} + oxlint@1.69.0: + resolution: {integrity: sha512-ypZkK/aDc5NQV8zIR6s2H2Tl3aNW8FmJ1m9+2qsaYuRenl8vgnHNCGwTHviWJdUQzglOlHFchgopdtGhSy17Rw==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: oxlint-tsgolint: '>=0.22.1' + vite-plus: '*' peerDependenciesMeta: oxlint-tsgolint: optional: true + vite-plus: + optional: true package-manager-detector@1.6.0: resolution: {integrity: sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==} - pako@1.0.11: - resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} - parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} - parents@1.0.1: - resolution: {integrity: sha512-mXKF3xkoUt5td2DoxpLmtOmZvko9VfFpwRwkKDHSNvgmpLAeBo18YDhcPbBzJq+QLCHMbGOfzia2cX4U+0v9Mg==} - - parse-asn1@5.1.9: - resolution: {integrity: sha512-fIYNuZ/HastSb80baGOuPRo1O9cf4baWw5WsAp7dBuUzeTD/BoaG8sVTdlPFksBE2lF21dN+A1AnrpIjSWqHHg==} - engines: {node: '>= 0.10'} - parse-json@5.2.0: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} @@ -3456,52 +2390,24 @@ packages: resolution: {integrity: sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==} engines: {node: '>=0.10.0'} - path-browserify@1.0.1: - resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} - path-is-absolute@1.0.1: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} - path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - path-platform@0.11.15: - resolution: {integrity: sha512-Y30dB6rab1A/nfEKsZxmr01nUotHX0c/ZiIAsCTatEe1CmS5Pm5He7fZ195bPT7RdquoaL8lLxFCMQi/bS7IJg==} - engines: {node: '>= 0.8.0'} - pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - pbkdf2@3.1.5: - resolution: {integrity: sha512-Q3CG/cYvCO1ye4QKkuH7EXxs3VC/rI1/trd+qX2+PolbaKG0H+bgcZzrTt96mMyRtejk+JMCiLUn3y29W8qmFQ==} - engines: {node: '>= 0.10'} - - perfect-debounce@2.1.0: - resolution: {integrity: sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==} - - pg-cloudflare@1.4.0: - resolution: {integrity: sha512-Vo7z/6rrQYxpNRylp4Tlob2elzbh+N/MOQbxFVWCxS7oEx6jF53GTJFxK2WWpKuBRkmiin4Mt+xofFDjx09R0A==} - - pg-connection-string@2.13.0: - resolution: {integrity: sha512-EMnU9E2fSULdsbErBbMaXJvFeD9B4+nPcM3f+4lsiCR0BHLPrLVjv3DbyM2hgQQviKJaTWIRRTjKjWlHg3p2ig==} + peek-readable@5.4.2: + resolution: {integrity: sha512-peBp3qZyuS6cNIJ2akRNG1uo1WJ1d0wTxg/fxMdZ0BqCVhx242bSFHM9eNqflfJVS9SsgkzgT/1UgnsurBOTMg==} + engines: {node: '>=14.16'} pg-int8@1.0.1: resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} engines: {node: '>=4.0.0'} - pg-pool@3.14.0: - resolution: {integrity: sha512-gKtPkFdQPU3DksooVLi9LsjZxrsBUZIpa+7aVx+LV5pNh0KzP4Zleud2po+ConrxbuXGBJ6Hfer6hdgpIBpBaw==} - peerDependencies: - pg: '>=8.0' - - pg-protocol@1.13.0: - resolution: {integrity: sha512-zzdvXfS6v89r6v7OcFCHfHlyG/wvry1ALxZo4LqgUoy7W9xhBDMaqOuMiF3qEV45VqsN6rdlcehHrfDtlCPc8w==} - pg-protocol@1.14.0: resolution: {integrity: sha512-n5taZ1kO3s9ngDTVxsEznOqCyToTgz0FLuPq0B33COy5pPpuWJpY3/2oRBVETuOgzdqRXfWpM9HIhp2LBBT1BA==} @@ -3509,53 +2415,30 @@ packages: resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} engines: {node: '>=4'} - pg@8.21.0: - resolution: {integrity: sha512-AUP1EYJuHraQGsVoCQVIcM7TEJVGtDzxWtGFZd8rds9d+CCXlU5Js1rYgfLNvxy9iJrpHjGrRjoi/3BT9fRyiA==} - engines: {node: '>= 16.0.0'} - peerDependencies: - pg-native: '>=3.0.1' - peerDependenciesMeta: - pg-native: - optional: true - - pgpass@1.0.5: - resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} - picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + picomatch@2.3.2: + resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} engines: {node: '>=8.6'} picomatch@4.0.4: resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} engines: {node: '>=12'} - pkg-types@2.3.0: - resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==} - - pnpm-workspace-yaml@1.6.0: - resolution: {integrity: sha512-uUy4dK3E11sp7nK+hnT7uAWfkBMe00KaUw8OG3NuNlYQoTk4sc9pcdIy1+XIP85v9Tvr02mK3JPaNNrP0QyRaw==} - - possible-typed-array-names@1.1.0: - resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} - engines: {node: '>= 0.4'} + pnpm-workspace-yaml@1.6.1: + resolution: {integrity: sha512-yTeZntGWi8m9WNuhoVsP0DpFc4sC1U0+rr/qR6Zi9n2g3sxXY+JfccjXjjruNz96tM8I09yaJUA86doRnNLkbg==} - postcss@8.5.14: - resolution: {integrity: sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==} + postcss@8.5.15: + resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} engines: {node: ^10 || ^12 || >=14} postgres-array@2.0.0: resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} engines: {node: '>=4'} - postgres-array@3.0.4: - resolution: {integrity: sha512-nAUSGfSDGOaOAEGwqsRY27GPOea7CNipJPOA7lPbdEpx5Kg3qzdP0AaWC5MlhTWV9s4hFX39nomVZ+C4tnGOJQ==} - engines: {node: '>=12'} - - postgres-bytea@1.0.0: - resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==} + postgres-bytea@1.0.1: + resolution: {integrity: sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==} engines: {node: '>=0.10.0'} postgres-date@1.0.7: @@ -3566,118 +2449,42 @@ packages: resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} engines: {node: '>=0.10.0'} - postgres@3.4.7: - resolution: {integrity: sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw==} - engines: {node: '>=12'} - - prettier@3.8.3: - resolution: {integrity: sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==} + prettier@3.8.4: + resolution: {integrity: sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q==} engines: {node: '>=14'} hasBin: true - pretty-hrtime@1.0.3: - resolution: {integrity: sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==} - engines: {node: '>= 0.8'} - - prisma-json-types-generator@5.0.0: - resolution: {integrity: sha512-w1TKsvgSCIg8ThqD2lvsuEs8y9qIMiz4vPW+o+781TuSJiVwRJcd8doTEM+DxsEhSfEoZbogeS5GqraGgfV3CQ==} - engines: {node: '>=14.0'} - hasBin: true - peerDependencies: - '@prisma/client': ^7.8.0 - prisma: ^7.8.0 - typescript: ^6.0.3 - - prisma@7.8.0: - resolution: {integrity: sha512-yfN4yrw7HV9kEJhoy1+jgah0jafEIQsf7uWouSsM8MvJtlubsk+kM7AIBWZ8+GJl74Yj3c+nbYqBkMOxtsZ3Lw==} - engines: {node: ^20.19 || ^22.12 || >=24.0} + prisma@4.16.2: + resolution: {integrity: sha512-SYCsBvDf0/7XSJyf2cHTLjLeTLVXYfqp7pG5eEVafFLeT0u/hLFz/9W196nDRGUOo1JfPatAEb+uEnTQImQC1g==} + engines: {node: '>=14.17'} hasBin: true - peerDependencies: - better-sqlite3: '>=9.0.0' - typescript: '>=5.4.0' - peerDependenciesMeta: - better-sqlite3: - optional: true - typescript: - optional: true - - process-nextick-args@2.0.1: - resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} process@0.11.10: resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} engines: {node: '>= 0.6.0'} - proper-lockfile@4.1.2: - resolution: {integrity: sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==} - - public-encrypt@4.0.3: - resolution: {integrity: sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==} - - pump@3.0.3: - resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} - - pumpify@2.0.1: - resolution: {integrity: sha512-m7KOje7jZxrmutanlkS1daj1dS6z6BgslzOXmcSEpIlCxM3VJH7lG5QLeck/6hgF6F4crFf01UtQmNsJfweTAw==} - - punycode@1.4.1: - resolution: {integrity: sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==} - - pure-rand@6.1.0: - resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} - - qs@6.14.0: - resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} - engines: {node: '>=0.6'} - quansync@1.0.0: resolution: {integrity: sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA==} - querystring-es3@0.2.1: - resolution: {integrity: sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==} - engines: {node: '>=0.4.x'} - - queue-tick@1.0.1: - resolution: {integrity: sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==} - - randombytes@2.1.0: - resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} - - randomfill@1.0.4: - resolution: {integrity: sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==} - - rc9@3.0.1: - resolution: {integrity: sha512-gMDyleLWVE+i6Sgtc0QbbY6pEKqYs97NGi6isHQPqYlLemPoO8dxQ3uGi0f4NiP98c+jMW6cG1Kx9dDwfvqARQ==} - - react-dom@19.2.5: - resolution: {integrity: sha512-J5bAZz+DXMMwW/wV3xzKke59Af6CHY7G4uYLN1OvBcKEsWOs4pQExj86BBKamxl/Ik5bx9whOrvBlSDfWzgSag==} - peerDependencies: - react: ^19.2.5 - - react@19.2.5: - resolution: {integrity: sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==} - engines: {node: '>=0.10.0'} - - read-only-stream@2.0.0: - resolution: {integrity: sha512-3ALe0bjBVZtkdWKIcThYpQCLbBMd/+Tbh2CDSrAIDO3UsZ4Xs+tnyjv2MjCOMMgBG+AsUOeuP1cgtY1INISc8w==} - - readable-stream@2.3.8: - resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} - readable-stream@3.6.2: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} - readdirp@4.1.2: - resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} - engines: {node: '>= 14.18.0'} + readable-stream@4.7.0: + resolution: {integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + readable-web-to-node-stream@3.0.4: + resolution: {integrity: sha512-9nX56alTf5bwXQ3ZDipHJhusu9NTQJ/CVPtb/XHAJCXihZeitfJvIRS4GqQ/mfIoOE3IelHMrpayVrosdHBuLw==} + engines: {node: '>=8'} - readdirp@5.0.0: - resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} - engines: {node: '>= 20.19.0'} + redis-errors@1.2.0: + resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==} + engines: {node: '>=4'} - remeda@2.33.4: - resolution: {integrity: sha512-ygHswjlc/opg2VrtiYvUOPLjxjtdKvjGz1/plDhkG66hjNjFr1xmfrs2ClNFo/E6TyUFiwYNh53bKV26oBoMGQ==} + redis-parser@3.0.0: + resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==} + engines: {node: '>=4'} require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} @@ -3687,9 +2494,9 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} - require-in-the-middle@8.0.1: - resolution: {integrity: sha512-QT7FVMXfWOYFbeRBF6nu+I6tr2Tf3u0q8RIEjNob/heKY/nh7drD/k7eeMFmSQgnTtCzLDcCu/XEnpW2wk4xCQ==} - engines: {node: '>=9.3.0 || >=8.10.0 <9.0.0'} + require-in-the-middle@7.5.2: + resolution: {integrity: sha512-gAZ+kLqBdHarXB64XpAe2VCjB7rIRv+mU8tfRWziHRJ5umKsIHN2tLLv6EtMw7WCdP19S0ERVMldNvxYCHnhSQ==} + engines: {node: '>=8.6.0'} resolve-dir@1.0.1: resolution: {integrity: sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==} @@ -3706,8 +2513,8 @@ packages: resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - resolve@1.22.11: - resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} + resolve@1.22.12: + resolution: {integrity: sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==} engines: {node: '>= 0.4'} hasBin: true @@ -3719,19 +2526,11 @@ packages: resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} engines: {node: '>=18'} - retry@0.12.0: - resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} - engines: {node: '>= 4'} - rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} - ripemd160@2.0.3: - resolution: {integrity: sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==} - engines: {node: '>= 0.8'} - - rolldown-plugin-dts@0.25.1: - resolution: {integrity: sha512-zK82aC/8z1iVW+g0bCnlQZq04Y5bNeL/RcRwTYBwsnU6wH0N+6vpIFkN7JC0kYRS5qKA+pxQyfIPvXJ6Q5xSpQ==} + rolldown-plugin-dts@0.25.2: + resolution: {integrity: sha512-nMhN/R+vmR8GM45ZW1FWMSjRTSDDn/6w4GTf8RNrEFCBdl8B1kySWrU1ixPtbwzXoRlcO+R/S88VgXuJQwfdDg==} engines: {node: ^22.18.0 || >=24.0.0} peerDependencies: '@ts-macro/tsc': ^0.3.6 @@ -3749,18 +2548,13 @@ packages: vue-tsc: optional: true - rolldown@1.0.0-rc.17: - resolution: {integrity: sha512-ZrT53oAKrtA4+YtBWPQbtPOxIbVDbxT0orcYERKd63VJTF13zPcgXTvD4843L8pcsI7M6MErt8QtON6lrB9tyA==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - - rolldown@1.0.2: - resolution: {integrity: sha512-oZx5zVDtVB44AW3eaifgDml1gWRDZGvjcfdxonE4swNPG98PrrXjaO/KrnUjzlMnztCCRVlUueA1kCXhARGk6g==} + rolldown@1.1.1: + resolution: {integrity: sha512-IN750c0p+s3jqJIsFLRZrQazmbAB1kkQDTtQjSt/gbS2ywLhlv4R5Shazer0FZKmuo/BsO3/w2UoYnUjuOZqHg==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true - rollup@4.60.3: - resolution: {integrity: sha512-pAQK9HalE84QSm4Po3EmWIZPd3FnjkShVkiMlz1iligWYkWQ7wHYd1PF/T7QZ5TVSD6uSTon5gBVMSM4JfBV+A==} + rollup@4.61.1: + resolution: {integrity: sha512-I4KW6iuRpuu2uHBLraZ1wNZe0DP7lnRha+VJ9tNaYVaVgKhW0aI3h4RYnoRPeql0flHm/Co55b7snEDcOfOJrA==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -3771,79 +2565,19 @@ packages: rxjs@7.8.2: resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} - safe-buffer@5.1.2: - resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} - safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - safe-regex-test@1.1.0: - resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} - engines: {node: '>= 0.4'} - safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - scheduler@0.27.0: - resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} - - semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - - semver@7.7.3: - resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} - engines: {node: '>=10'} - hasBin: true - - semver@7.7.4: - resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} + semver@7.8.4: + resolution: {integrity: sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==} engines: {node: '>=10'} hasBin: true - seq-queue@0.0.5: - resolution: {integrity: sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==} - - set-function-length@1.2.2: - resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} - engines: {node: '>= 0.4'} - - sha.js@2.4.12: - resolution: {integrity: sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==} - engines: {node: '>= 0.10'} - hasBin: true - - shasum-object@1.0.1: - resolution: {integrity: sha512-SsC+1tW7XKQ/94D4k1JhLmjDFpVGET/Nf54jVDtbavbALf8Zhp0Td9zTlxScjMW6nbEIrpADtPWfLk9iCXzHDQ==} - hasBin: true - - shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - - shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - - shell-quote@1.8.3: - resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==} - engines: {node: '>= 0.4'} - - side-channel-list@1.0.0: - resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} - engines: {node: '>= 0.4'} - - side-channel-map@1.0.1: - resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} - engines: {node: '>= 0.4'} - - side-channel-weakmap@1.0.2: - resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} - engines: {node: '>= 0.4'} - - side-channel@1.1.0: - resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} - engines: {node: '>= 0.4'} + shimmer@1.2.1: + resolution: {integrity: sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==} siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} @@ -3855,68 +2589,31 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} - simple-concat@1.0.1: - resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} - - single-line-log@1.1.2: - resolution: {integrity: sha512-awzaaIPtYFdexLr6TBpcZSGPB6D1RInNO/qNetgaJloPDF/D0GkVtLvGEp8InfmLV7CyLyQ5fIRP+tVN/JmWQA==} - slice-ansi@7.1.2: resolution: {integrity: sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==} engines: {node: '>=18'} + slice-ansi@8.0.0: + resolution: {integrity: sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg==} + engines: {node: '>=20'} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} - source-map@0.5.7: - resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} - engines: {node: '>=0.10.0'} - - sourcemap-codec@1.4.8: - resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} - deprecated: Please use @jridgewell/sourcemap-codec instead - - split2@4.2.0: - resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} - engines: {node: '>= 10.x'} - - sqlstring@2.3.3: - resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==} - engines: {node: '>= 0.6'} - stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - std-env@3.10.0: - resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + standard-as-callback@2.1.0: + resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==} std-env@4.1.0: resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==} - stream-browserify@3.0.0: - resolution: {integrity: sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==} - - stream-combiner2@1.1.1: - resolution: {integrity: sha512-3PnJbYgS56AeWgtKF5jtJRT6uFJe56Z0Hc5Ngg/6sI6rIt8iiMBTa9cvdyFfpMQjaVHr8dusbNeFGIIonxOvKw==} - - stream-http@3.2.0: - resolution: {integrity: sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A==} - - stream-shift@1.0.3: - resolution: {integrity: sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==} - - stream-splicer@2.0.1: - resolution: {integrity: sha512-Xizh4/NPuYSyAXyT7g8IvdJ9HJpxIGL9PjyhtywCZvvP0OPIdqyrr4dMikeuvY8xahpdKEBlBTySe583totajg==} - string-argv@0.3.2: resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} engines: {node: '>=0.6.19'} - string-width@1.0.2: - resolution: {integrity: sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==} - engines: {node: '>=0.10.0'} - string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -3925,26 +2622,19 @@ packages: resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} engines: {node: '>=18'} - string-width@8.1.0: - resolution: {integrity: sha512-Kxl3KJGb/gxkaUMOjRsQ8IrXiGW75O4E3RPjFIINOVH8AMl2SQ/yWdTzWwF3FevIX9LcMAjJW+GRwAlAbTSXdg==} + string-width@8.2.1: + resolution: {integrity: sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA==} engines: {node: '>=20'} - string_decoder@1.1.1: - resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} - string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} - strip-ansi@3.0.1: - resolution: {integrity: sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==} - engines: {node: '>=0.10.0'} - strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} - strip-ansi@7.1.2: - resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==} + strip-ansi@7.2.0: + resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} engines: {node: '>=12'} strip-bom@4.0.0: @@ -3955,12 +2645,9 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} - subarg@1.0.0: - resolution: {integrity: sha512-RIrIdRY0X1xojthNcVtgT9sjpOGagEUKpZdgBUi054OEPFo282yg+zE+t1Rj3+RqKq2xStL7uUHhY+AjbC4BXg==} - - supports-color@2.0.0: - resolution: {integrity: sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==} - engines: {node: '>=0.8.0'} + strtok3@7.1.1: + resolution: {integrity: sha512-mKX8HA/cdBqMKUr0MMZAFssCkIGoZeSCMXgnt79yKxNFguMLVFgRe6wB+fsL0NmoHDbeyZXczy7vEPSoo3rkzg==} + engines: {node: '>=16'} supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} @@ -3974,51 +2661,30 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - synckit@0.11.11: - resolution: {integrity: sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==} - engines: {node: ^14.18.0 || >=16.0.0} - - syntax-error@1.4.0: - resolution: {integrity: sha512-YPPlu67mdnHGTup2A8ff7BC2Pjq0e0Yp/IyTFN03zWO0RcK07uLcbi7C2KpGR2FvWbaB0+bfE27a+sBKebSo7w==} - - tachyons@4.12.0: - resolution: {integrity: sha512-2nA2IrYFy3raCM9fxJ2KODRGHVSZNTW3BR0YnlGsLUf1DA3pk3YfWZ/DdfbnZK6zLZS+jUenlUGJsKcA5fUiZg==} - - taze@19.13.0: - resolution: {integrity: sha512-c292FM06B4zyWl9Tas5pRvv+e8Che9LCxT6U95SyhUwqbEo7Bc+BRTvLKldkVwcAmZySYwA7atveuqSS9QYzcw==} + taze@19.14.1: + resolution: {integrity: sha512-+wf/IqGReU68vBE/iJ7JCuV5QeD6zQBp9MI6YphN7bT2vf/YIHd0oVA4AJiX3uANI1hQY58MrVmDwLv0x/q3BA==} hasBin: true - through2@2.0.5: - resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} - - through2@3.0.2: - resolution: {integrity: sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==} - - through2@4.0.2: - resolution: {integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==} - through@2.3.8: resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} - timers-browserify@1.4.2: - resolution: {integrity: sha512-PIxwAupJZiYU4JmVZYwXp9FKsHMXb5h0ZEFyuXTAn8WLHOlcij+FEcbrvDsom1o5dr1YggEtFbECvGCW2sT53Q==} - engines: {node: '>=0.6.0'} - tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - tinyexec@1.0.4: - resolution: {integrity: sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw==} - engines: {node: '>=18'} + tinycolor2@1.6.0: + resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==} - tinyexec@1.1.2: - resolution: {integrity: sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA==} + tinyexec@1.2.4: + resolution: {integrity: sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==} engines: {node: '>=18'} - tinyglobby@0.2.16: - resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} engines: {node: '>=12.0.0'} + tinygradient@1.1.5: + resolution: {integrity: sha512-8nIfc2vgQ4TeLnk2lFj4tRLvvJwEfQuabdsmvDdQPT0xlk9TaNtpGd6nNRxXoK6vQhN6RSzj+Cnp5tTQmpxmbw==} + tinypool@2.1.0: resolution: {integrity: sha512-Pugqs6M0m7Lv1I7FtxN4aoyToKg1C4tu+/381vH35y8oENM/Ai7f7C4StcoK4/+BSw9ebcS8jRiVrORFKCALLw==} engines: {node: ^20.0.0 || >=22.0.0} @@ -4027,46 +2693,33 @@ packages: resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} engines: {node: '>=14.0.0'} - tldts-core@7.0.17: - resolution: {integrity: sha512-DieYoGrP78PWKsrXr8MZwtQ7GLCUeLxihtjC1jZsW1DnvSMdKPitJSe8OSYDM2u5H6g3kWJZpePqkp43TfLh0g==} - - tldts@7.0.17: - resolution: {integrity: sha512-Y1KQBgDd/NUc+LfOtKS6mNsC9CCaH+m2P1RoIZy7RAPo3C3/t8X45+zgut31cRZtZ3xKPjfn3TkGTrctC2TQIQ==} - hasBin: true - tmp@0.0.33: resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} engines: {node: '>=0.6.0'} - to-buffer@1.2.2: - resolution: {integrity: sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==} - engines: {node: '>= 0.4'} - to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} - transform-ast@2.4.4: - resolution: {integrity: sha512-AxjeZAcIOUO2lev2GDe3/xZ1Q0cVGjIMk5IsriTy8zbWlsEnjeB025AhkhBJHoy997mXpLd4R+kRbvnnQVuQHQ==} + token-types@5.0.1: + resolution: {integrity: sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==} + engines: {node: '>=14.16'} tree-kill@1.2.2: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true - try@1.0.3: - resolution: {integrity: sha512-AHA8khVCII6zKyRkyPo6pRwoR9v5jb7QFw6e5avtaVSkxVfaEucYIo06xnwB+pJaEarfYNbs7W3Vq+LZLZiWyA==} - ts-mixer@6.0.4: resolution: {integrity: sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA==} - tsdown@0.22.0: - resolution: {integrity: sha512-FgW0hHb27nGQA/+F3d5+U9wKXkfilk9DVkc5+7x/ZqF03g+Hoz/eeApT32jqxATt9eRoR+1jxk7MUMON+O4CXw==} + tsdown@0.22.2: + resolution: {integrity: sha512-VX9gsyKXsTnBZjnIM4jsHl9aRv+GfgkE/k1hQslilaBfZMlaw3JuGR+6yhiU0QxWBtOCDnTjwOSoXzgB7Rr50g==} engines: {node: ^22.18.0 || >=24.0.0} hasBin: true peerDependencies: '@arethetypeswrong/core': ^0.18.1 - '@tsdown/css': 0.22.0 - '@tsdown/exe': 0.22.0 + '@tsdown/css': 0.22.2 + '@tsdown/exe': 0.22.2 '@vitejs/devtools': '*' publint: ^0.3.8 tsx: '*' @@ -4096,22 +2749,14 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - tty-browserify@0.0.1: - resolution: {integrity: sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==} - - type-component@0.0.1: - resolution: {integrity: sha512-mDZRBQS2yZkwRQKfjJvQ8UIYJeBNNWCq+HBNstl9N5s9jZ4dkVYXEGkVPsSCEh5Ld4JM1kmrZTzjnrqSAIQ7dw==} - type-fest@0.21.3: resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} engines: {node: '>=10'} - typed-array-buffer@1.0.3: - resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} - engines: {node: '>= 0.4'} - - typedarray@0.0.6: - resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} + typescript@4.9.5: + resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} + engines: {node: '>=4.2.0'} + hasBin: true typescript@5.4.5: resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} @@ -4123,12 +2768,8 @@ packages: engines: {node: '>=14.17'} hasBin: true - ufo@1.6.1: - resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} - - umd@3.0.3: - resolution: {integrity: sha512-4IcGSufhFshvLNcMCV80UnQVlZ5pMOC8mvNPForqwA4+lzYQuetTESLDQkeLmihq8bRcnpbQa48Wb8Lh16/xow==} - hasBin: true + ufo@1.6.4: + resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==} unconfig-core@7.5.0: resolution: {integrity: sha512-Su3FauozOGP44ZmKdHy2oE6LPjk51M/TRRjHv2HNCWiDvfvCoxC2lno6jevMA91MYAdCdwP05QnWdWpSbncX/w==} @@ -4136,79 +2777,37 @@ packages: unconfig@7.5.0: resolution: {integrity: sha512-oi8Qy2JV4D3UQ0PsopR28CzdQ3S/5A1zwsUwp/rosSbfhJ5z7b90bIyTwi/F7hCLD4SGcZVjDzd4XoUQcEanvA==} - undeclared-identifiers@1.1.3: - resolution: {integrity: sha512-pJOW4nxjlmfwKApE4zvxLScM/njmwj/DiUBv7EabwE4O8kRUy+HIwxQtZLBPll/jx1LJyBcqNfB3/cpv9EZwOw==} - hasBin: true - undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - undici@6.21.3: - resolution: {integrity: sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw==} - engines: {node: '>=18.17'} + undici@5.29.0: + resolution: {integrity: sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==} + engines: {node: '>=14.0'} undici@6.24.1: resolution: {integrity: sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA==} engines: {node: '>=18.17'} - undici@7.16.0: - resolution: {integrity: sha512-QEg3HPMll0o3t2ourKwOeUAZ159Kn9mx5pnzHRQO8+Wixmh88YdZRiIwat0iNzNNXn0yoEtXJqFpyW7eM8BV7g==} - engines: {node: '>=20.18.1'} - universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} - unrun@0.2.37: - resolution: {integrity: sha512-AA7vDuYsgeSYVzJMm16UKA+aXFKhy7nFqW9z5l7q44K4ppFWZAMqYS58ePRZbugMLPH0fwwMzD5A8nP0avxwZQ==} - engines: {node: '>=20.19.0'} - hasBin: true - peerDependencies: - synckit: ^0.11.11 - peerDependenciesMeta: - synckit: - optional: true - - upper-case@1.1.3: - resolution: {integrity: sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA==} - - url@0.11.4: - resolution: {integrity: sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==} - engines: {node: '>= 0.4'} - util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - util-extend@1.0.3: - resolution: {integrity: sha512-mLs5zAK+ctllYBj+iAQvlDCwoxU/WDOUaJkcFudeiAX6OajC6BKXJUa9a+tbtkC11dz2Ufb7h0lyvIOVn4LADA==} - - util@0.10.4: - resolution: {integrity: sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==} - - util@0.12.5: - resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==} - - valibot@1.2.0: - resolution: {integrity: sha512-mm1rxUsmOxzrwnX5arGS+U4T25RdvpPjPN4yR0u9pUBov9+zGVtO84tif1eY4r6zWxVxu3KzIyknJy3rxfRZZg==} - peerDependencies: - typescript: '>=5' - peerDependenciesMeta: - typescript: - optional: true - - vite@7.2.4: - resolution: {integrity: sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w==} - engines: {node: ^20.19.0 || >=22.12.0} + vite@6.4.3: + resolution: {integrity: sha512-NTKlcQjlAK7MlQoyb6LgaqHc8sso/pVyUJYWMws3jg21uTJw/LddqIFPcPqP6PzpgbIcZyKI85sFE4HBrQDA8A==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true peerDependencies: - '@types/node': ^20.19.0 || >=22.12.0 + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 jiti: '>=1.21.0' - less: ^4.0.0 + less: '*' lightningcss: ^1.21.0 - sass: ^1.70.0 - sass-embedded: ^1.70.0 - stylus: '>=0.54.8' - sugarss: ^5.0.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' terser: ^5.16.0 tsx: ^4.8.1 yaml: ^2.4.2 @@ -4236,23 +2835,23 @@ packages: yaml: optional: true - vitest@4.1.7: - resolution: {integrity: sha512-flYyaFd2CgoCoU+0UKt3pxksgC+S02iTDN0n3LtqaMeXsI9SBcdNujc2k0DeFLzUn/0k538yNjOSdwgCqcrwJA==} + vitest@4.1.8: + resolution: {integrity: sha512-flY6ScbCIt9HThs+C5HS7jvGOB560DJtk/Z15IQROTA6zEy49Nh8T/dofWTQL+n3vswqn87sbJNiuqw1SDp5Ig==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.1.7 - '@vitest/browser-preview': 4.1.7 - '@vitest/browser-webdriverio': 4.1.7 - '@vitest/coverage-istanbul': 4.1.7 - '@vitest/coverage-v8': 4.1.7 - '@vitest/ui': 4.1.7 + '@vitest/browser-playwright': 4.1.8 + '@vitest/browser-preview': 4.1.8 + '@vitest/browser-webdriverio': 4.1.8 + '@vitest/coverage-istanbul': 4.1.8 + '@vitest/coverage-v8': 4.1.8 + '@vitest/ui': 4.1.8 happy-dom: '*' jsdom: '*' - vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + vite: ^6.3.5 peerDependenciesMeta: '@edge-runtime/vm': optional: true @@ -4277,25 +2876,13 @@ packages: jsdom: optional: true - vm-browserify@1.1.2: - resolution: {integrity: sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==} - wcwidth@1.0.1: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} - which-typed-array@1.1.19: - resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==} - engines: {node: '>= 0.4'} - which@1.3.1: resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} hasBin: true - which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - why-is-node-running@2.3.0: resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} engines: {node: '>=8'} @@ -4316,8 +2903,8 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - ws@8.18.3: - resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} + ws@8.21.0: + resolution: {integrity: sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -4336,11 +2923,6 @@ packages: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} - yaml@2.8.2: - resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} - engines: {node: '>= 14.6'} - hasBin: true - yaml@2.9.0: resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} engines: {node: '>= 14.6'} @@ -4354,111 +2936,68 @@ packages: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} - zeptomatch@2.1.0: - resolution: {integrity: sha512-KiGErG2J0G82LSpniV0CtIzjlJ10E04j02VOudJsPyPwNZgGnRKQy7I1R7GMyg/QswnE4l7ohSGrQbQbjXPPDA==} - - zlib-sync@0.1.10: - resolution: {integrity: sha512-t7/pYg5tLBznL1RuhmbAt8rNp5tbhr+TSrJFnMkRtrGIaPJZ6Dc0uR4u3OoQI2d6cGlVI62E3Gy6gwkxyIqr/w==} - snapshots: - 0x@6.0.0: - dependencies: - ajv: 8.17.1 - browserify: 17.0.1 - concat-stream: 2.0.0 - d3-fg: 6.14.0 - debounce: 1.2.1 - debug: 4.4.3 - end-of-stream: 1.4.5 - env-string: 1.0.1 - escape-string-regexp: 4.0.0 - execspawn: 1.0.1 - fs-extra: 10.1.0 - has-unicode: 2.0.1 - hsl-to-rgb-for-reals: 1.1.1 - jsonstream2: 3.0.0 - make-dir: 3.1.0 - minimist: 1.2.8 - morphdom: 2.7.7 - nanohtml: 1.10.0 - on-net-listen: 1.1.2 - opn: 5.5.0 - pump: 3.0.3 - pumpify: 2.0.1 - semver: 7.7.3 - single-line-log: 1.1.2 - split2: 4.2.0 - tachyons: 4.12.0 - through2: 4.0.2 - which: 2.0.2 - transitivePeerDependencies: - - supports-color - '@antfu/ni@30.1.0': dependencies: fzf: 0.5.2 package-manager-detector: 1.6.0 - tinyexec: 1.1.2 - tinyglobby: 0.2.16 + tinyexec: 1.2.4 + tinyglobby: 0.2.17 - '@babel/code-frame@7.27.1': + '@babel/code-frame@7.29.7': dependencies: - '@babel/helper-validator-identifier': 7.28.5 + '@babel/helper-validator-identifier': 7.29.7 js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/generator@8.0.0-rc.5': + '@babel/generator@8.0.0-rc.6': dependencies: - '@babel/parser': 8.0.0-rc.5 - '@babel/types': 8.0.0-rc.5 + '@babel/parser': 8.0.0-rc.6 + '@babel/types': 8.0.0-rc.6 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 '@types/jsesc': 2.5.1 jsesc: 3.1.0 - '@babel/helper-string-parser@7.27.1': {} + '@babel/helper-string-parser@7.29.7': {} - '@babel/helper-string-parser@8.0.0-rc.5': {} + '@babel/helper-string-parser@8.0.0-rc.6': {} - '@babel/helper-validator-identifier@7.28.5': {} + '@babel/helper-validator-identifier@7.29.7': {} - '@babel/helper-validator-identifier@8.0.0-rc.5': {} - - '@babel/parser@7.29.3': - dependencies: - '@babel/types': 7.29.0 + '@babel/helper-validator-identifier@8.0.0-rc.6': {} - '@babel/parser@8.0.0-rc.4': + '@babel/parser@7.29.7': dependencies: - '@babel/types': 8.0.0-rc.5 + '@babel/types': 7.29.7 - '@babel/parser@8.0.0-rc.5': + '@babel/parser@8.0.0-rc.6': dependencies: - '@babel/types': 8.0.0-rc.5 + '@babel/types': 8.0.0-rc.6 - '@babel/runtime@7.28.4': {} + '@babel/runtime@7.29.7': {} - '@babel/types@7.29.0': + '@babel/types@7.29.7': dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 - '@babel/types@8.0.0-rc.5': + '@babel/types@8.0.0-rc.6': dependencies: - '@babel/helper-string-parser': 8.0.0-rc.5 - '@babel/helper-validator-identifier': 8.0.0-rc.5 + '@babel/helper-string-parser': 8.0.0-rc.6 + '@babel/helper-validator-identifier': 8.0.0-rc.6 '@bcoe/v8-coverage@1.0.2': {} - '@commitlint/cli@20.5.3(@types/node@22.19.1)(conventional-commits-parser@6.4.0)(typescript@6.0.3)': + '@commitlint/cli@20.5.3(@types/node@22.19.21)(conventional-commits-parser@6.4.0)(typescript@4.9.5)': dependencies: '@commitlint/format': 20.5.0 '@commitlint/lint': 20.5.3 - '@commitlint/load': 20.5.3(@types/node@22.19.1)(typescript@6.0.3) + '@commitlint/load': 20.5.3(@types/node@22.19.21)(typescript@4.9.5) '@commitlint/read': 20.5.0(conventional-commits-parser@6.4.0) '@commitlint/types': 20.5.0 - tinyexec: 1.0.4 + tinyexec: 1.2.4 yargs: 17.7.2 transitivePeerDependencies: - '@types/node' @@ -4471,24 +3010,27 @@ snapshots: '@commitlint/types': 20.5.0 conventional-changelog-conventionalcommits: 9.3.1 - '@commitlint/config-validator@20.0.0': + '@commitlint/config-validator@20.5.0': dependencies: - '@commitlint/types': 20.0.0 - ajv: 8.17.1 - optional: true + '@commitlint/types': 20.5.0 + ajv: 8.20.0 - '@commitlint/config-validator@20.5.0': + '@commitlint/config-validator@21.0.1': dependencies: - '@commitlint/types': 20.5.0 - ajv: 8.17.1 + '@commitlint/types': 21.0.1 + ajv: 8.20.0 + optional: true '@commitlint/ensure@20.5.3': dependencies: '@commitlint/types': 20.5.0 - es-toolkit: 1.46.1 + es-toolkit: 1.47.0 '@commitlint/execute-rule@20.0.0': {} + '@commitlint/execute-rule@21.0.1': + optional: true + '@commitlint/format@20.5.0': dependencies: '@commitlint/types': 20.5.0 @@ -4497,7 +3039,7 @@ snapshots: '@commitlint/is-ignored@20.5.0': dependencies: '@commitlint/types': 20.5.0 - semver: 7.7.4 + semver: 7.8.4 '@commitlint/lint@20.5.3': dependencies: @@ -4506,37 +3048,36 @@ snapshots: '@commitlint/rules': 20.5.3 '@commitlint/types': 20.5.0 - '@commitlint/load@20.1.0(@types/node@22.19.1)(typescript@6.0.3)': + '@commitlint/load@20.5.3(@types/node@22.19.21)(typescript@4.9.5)': dependencies: - '@commitlint/config-validator': 20.0.0 + '@commitlint/config-validator': 20.5.0 '@commitlint/execute-rule': 20.0.0 - '@commitlint/resolve-extends': 20.1.0 - '@commitlint/types': 20.0.0 - chalk: 5.6.2 - cosmiconfig: 9.0.0(typescript@6.0.3) - cosmiconfig-typescript-loader: 6.2.0(@types/node@22.19.1)(cosmiconfig@9.0.0)(typescript@6.0.3) - lodash.isplainobject: 4.0.6 - lodash.merge: 4.6.2 - lodash.uniq: 4.5.0 + '@commitlint/resolve-extends': 20.5.3 + '@commitlint/types': 20.5.0 + cosmiconfig: 9.0.2(typescript@4.9.5) + cosmiconfig-typescript-loader: 6.3.0(@types/node@22.19.21)(cosmiconfig@9.0.2)(typescript@4.9.5) + es-toolkit: 1.47.0 + is-plain-obj: 4.1.0 + picocolors: 1.1.1 transitivePeerDependencies: - '@types/node' - typescript - optional: true - '@commitlint/load@20.5.3(@types/node@22.19.1)(typescript@6.0.3)': + '@commitlint/load@21.0.2(@types/node@22.19.21)(typescript@4.9.5)': dependencies: - '@commitlint/config-validator': 20.5.0 - '@commitlint/execute-rule': 20.0.0 - '@commitlint/resolve-extends': 20.5.3 - '@commitlint/types': 20.5.0 - cosmiconfig: 9.0.1(typescript@6.0.3) - cosmiconfig-typescript-loader: 6.2.0(@types/node@22.19.1)(cosmiconfig@9.0.1)(typescript@6.0.3) - es-toolkit: 1.46.1 + '@commitlint/config-validator': 21.0.1 + '@commitlint/execute-rule': 21.0.1 + '@commitlint/resolve-extends': 21.0.1 + '@commitlint/types': 21.0.1 + cosmiconfig: 9.0.2(typescript@4.9.5) + cosmiconfig-typescript-loader: 6.3.0(@types/node@22.19.21)(cosmiconfig@9.0.2)(typescript@4.9.5) + es-toolkit: 1.47.0 is-plain-obj: 4.1.0 picocolors: 1.1.1 transitivePeerDependencies: - '@types/node' - typescript + optional: true '@commitlint/message@20.4.3': {} @@ -4552,30 +3093,29 @@ snapshots: '@commitlint/types': 20.5.0 git-raw-commits: 5.0.1(conventional-commits-parser@6.4.0) minimist: 1.2.8 - tinyexec: 1.1.2 + tinyexec: 1.2.4 transitivePeerDependencies: - conventional-commits-filter - conventional-commits-parser - '@commitlint/resolve-extends@20.1.0': - dependencies: - '@commitlint/config-validator': 20.0.0 - '@commitlint/types': 20.0.0 - global-directory: 4.0.1 - import-meta-resolve: 4.2.0 - lodash.mergewith: 4.6.2 - resolve-from: 5.0.0 - optional: true - '@commitlint/resolve-extends@20.5.3': dependencies: '@commitlint/config-validator': 20.5.0 '@commitlint/types': 20.5.0 - es-toolkit: 1.46.1 + es-toolkit: 1.47.0 global-directory: 5.0.0 import-meta-resolve: 4.2.0 resolve-from: 5.0.0 + '@commitlint/resolve-extends@21.0.1': + dependencies: + '@commitlint/config-validator': 21.0.1 + '@commitlint/types': 21.0.1 + es-toolkit: 1.47.0 + global-directory: 5.0.0 + resolve-from: 5.0.0 + optional: true + '@commitlint/rules@20.5.3': dependencies: '@commitlint/ensure': 20.5.3 @@ -4589,22 +3129,22 @@ snapshots: dependencies: escalade: 3.2.0 - '@commitlint/types@20.0.0': + '@commitlint/types@20.5.0': dependencies: - '@types/conventional-commits-parser': 5.0.2 - chalk: 5.6.2 - optional: true + conventional-commits-parser: 6.4.0 + picocolors: 1.1.1 - '@commitlint/types@20.5.0': + '@commitlint/types@21.0.1': dependencies: conventional-commits-parser: 6.4.0 picocolors: 1.1.1 + optional: true '@conventional-changelog/git-client@2.7.0(conventional-commits-parser@6.4.0)': dependencies: '@simple-libs/child-process-utils': 1.0.2 '@simple-libs/stream-utils': 1.2.0 - semver: 7.7.4 + semver: 7.8.4 optionalDependencies: conventional-commits-parser: 6.4.0 @@ -4613,7 +3153,7 @@ snapshots: '@discordjs/formatters': 0.6.2 '@discordjs/util': 1.2.0 '@sapphire/shapeshift': 4.0.0 - discord-api-types: 0.38.34 + discord-api-types: 0.38.48 fast-deep-equal: 3.1.3 ts-mixer: 6.0.4 tslib: 2.8.1 @@ -4622,33 +3162,20 @@ snapshots: '@discordjs/collection@2.1.1': {} - '@discordjs/core@1.2.0(bufferutil@4.1.0)': - dependencies: - '@discordjs/rest': 2.6.0 - '@discordjs/util': 1.1.1 - '@discordjs/ws': 1.2.3(bufferutil@4.1.0) - '@sapphire/snowflake': 3.5.5 - '@vladfrangu/async_event_emitter': 2.4.7 - discord-api-types: 0.38.34 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - '@discordjs/formatters@0.6.2': dependencies: - discord-api-types: 0.38.34 + discord-api-types: 0.38.48 - '@discordjs/rest@2.6.0': + '@discordjs/rest@1.7.1': dependencies: - '@discordjs/collection': 2.1.1 - '@discordjs/util': 1.2.0 + '@discordjs/collection': 1.5.3 + '@discordjs/util': 0.3.1 '@sapphire/async-queue': 1.5.5 '@sapphire/snowflake': 3.5.5 - '@vladfrangu/async_event_emitter': 2.4.7 - discord-api-types: 0.38.34 - magic-bytes.js: 1.12.1 + discord-api-types: 0.38.48 + file-type: 18.7.0 tslib: 2.8.1 - undici: 6.21.3 + undici: 5.29.0 '@discordjs/rest@2.6.1': dependencies: @@ -4657,18 +3184,32 @@ snapshots: '@sapphire/async-queue': 1.5.5 '@sapphire/snowflake': 3.5.5 '@vladfrangu/async_event_emitter': 2.4.7 - discord-api-types: 0.38.34 + discord-api-types: 0.38.48 magic-bytes.js: 1.13.0 tslib: 2.8.1 undici: 6.24.1 - '@discordjs/util@1.1.1': {} + '@discordjs/util@0.3.1': {} '@discordjs/util@1.2.0': dependencies: - discord-api-types: 0.38.34 + discord-api-types: 0.38.48 + + '@discordjs/ws@0.2.0': + dependencies: + '@discordjs/collection': 1.5.3 + '@discordjs/rest': 1.7.1 + '@sapphire/async-queue': 1.5.5 + '@types/ws': 8.18.1 + '@vladfrangu/async_event_emitter': 2.4.7 + discord-api-types: 0.38.48 + tslib: 2.8.1 + ws: 8.21.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate - '@discordjs/ws@1.2.3(bufferutil@4.1.0)': + '@discordjs/ws@1.2.3': dependencies: '@discordjs/collection': 2.1.1 '@discordjs/rest': 2.6.1 @@ -4676,35 +3217,25 @@ snapshots: '@sapphire/async-queue': 1.5.5 '@types/ws': 8.18.1 '@vladfrangu/async_event_emitter': 2.4.7 - discord-api-types: 0.38.34 + discord-api-types: 0.38.48 tslib: 2.8.1 - ws: 8.18.3(bufferutil@4.1.0) + ws: 8.21.0 transitivePeerDependencies: - bufferutil - utf-8-validate - '@electric-sql/pglite-socket@0.1.1(@electric-sql/pglite@0.4.1)': - dependencies: - '@electric-sql/pglite': 0.4.1 - - '@electric-sql/pglite-tools@0.3.1(@electric-sql/pglite@0.4.1)': - dependencies: - '@electric-sql/pglite': 0.4.1 - - '@electric-sql/pglite@0.4.1': {} - - '@emnapi/core@1.10.0': + '@emnapi/core@1.11.0': dependencies: - '@emnapi/wasi-threads': 1.2.1 + '@emnapi/wasi-threads': 1.2.2 tslib: 2.8.1 optional: true - '@emnapi/runtime@1.10.0': + '@emnapi/runtime@1.11.0': dependencies: tslib: 2.8.1 optional: true - '@emnapi/wasi-threads@1.2.1': + '@emnapi/wasi-threads@1.2.2': dependencies: tslib: 2.8.1 optional: true @@ -4787,27 +3318,11 @@ snapshots: '@esbuild/win32-x64@0.25.12': optional: true - '@fastify/otel@0.18.0(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation': 0.212.0(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.40.0 - minimatch: 10.2.5 - transitivePeerDependencies: - - supports-color + '@fastify/busboy@2.1.1': {} '@henrygd/queue@1.2.0': {} - '@hono/node-server@1.19.11(hono@4.12.12)': - dependencies: - hono: 4.12.12 - - '@influxdata/influxdb-client-apis@1.35.0(@influxdata/influxdb-client@1.35.0)': - dependencies: - '@influxdata/influxdb-client': 1.35.0 - - '@influxdata/influxdb-client@1.35.0': {} + '@ioredis/commands@1.10.0': {} '@jridgewell/gen-mapping@0.3.13': dependencies: @@ -4823,245 +3338,307 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 - '@kurkle/color@0.3.4': {} - - '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': + '@napi-rs/wasm-runtime@1.1.5(@emnapi/core@1.11.0)(@emnapi/runtime@1.11.0)': dependencies: - '@emnapi/core': 1.10.0 - '@emnapi/runtime': 1.10.0 - '@tybys/wasm-util': 0.10.1 + '@emnapi/core': 1.11.0 + '@emnapi/runtime': 1.11.0 + '@tybys/wasm-util': 0.10.2 optional: true - '@opentelemetry/api-logs@0.207.0': + '@opentelemetry/api-logs@0.53.0': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/api-logs@0.212.0': + '@opentelemetry/api-logs@0.57.1': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/api-logs@0.214.0': + '@opentelemetry/api-logs@0.57.2': dependencies: '@opentelemetry/api': 1.9.1 '@opentelemetry/api@1.9.1': {} - '@opentelemetry/core@2.6.1(@opentelemetry/api@1.9.1)': + '@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + + '@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/semantic-conventions': 1.28.0 + + '@opentelemetry/instrumentation-amqplib@0.46.1(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/semantic-conventions': 1.40.0 + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + transitivePeerDependencies: + - supports-color - '@opentelemetry/core@2.7.1(@opentelemetry/api@1.9.1)': + '@opentelemetry/instrumentation-connect@0.43.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/semantic-conventions': 1.40.0 + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + '@types/connect': 3.4.36 + transitivePeerDependencies: + - supports-color - '@opentelemetry/instrumentation-amqplib@0.61.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/instrumentation-dataloader@0.16.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.40.0 + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-connect@0.57.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/instrumentation-express@0.47.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.40.0 - '@types/connect': 3.4.38 + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-dataloader@0.31.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/instrumentation-fastify@0.44.1(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-fs@0.33.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/instrumentation-fs@0.19.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-generic-pool@0.57.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/instrumentation-generic-pool@0.43.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-graphql@0.62.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/instrumentation-graphql@0.47.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-hapi@0.60.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/instrumentation-hapi@0.45.1(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.40.0 + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-http@0.214.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/instrumentation-http@0.57.1(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.40.0 + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation': 0.57.1(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.28.0 forwarded-parse: 2.1.2 + semver: 7.8.4 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-kafkajs@0.23.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/instrumentation-ioredis@0.47.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.40.0 + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) + '@opentelemetry/redis-common': 0.36.2 + '@opentelemetry/semantic-conventions': 1.41.1 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-knex@0.58.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/instrumentation-kafkajs@0.7.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.40.0 + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-koa@0.62.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/instrumentation-knex@0.44.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.40.0 + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-lru-memoizer@0.58.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/instrumentation-koa@0.47.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-mongodb@0.67.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/instrumentation-lru-memoizer@0.44.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.40.0 + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-mongoose@0.60.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/instrumentation-mongodb@0.51.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.40.0 + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-mysql2@0.60.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/instrumentation-mongoose@0.46.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.40.0 - '@opentelemetry/sql-common': 0.41.2(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-mysql@0.60.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/instrumentation-mysql2@0.45.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.40.0 - '@types/mysql': 2.15.27 + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + '@opentelemetry/sql-common': 0.40.1(@opentelemetry/api@1.9.1) transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-pg@0.66.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/instrumentation-mysql@0.45.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.40.0 - '@opentelemetry/sql-common': 0.41.2(@opentelemetry/api@1.9.1) - '@types/pg': 8.15.6 - '@types/pg-pool': 2.0.7 + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + '@types/mysql': 2.15.26 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-tedious@0.33.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/instrumentation-nestjs-core@0.44.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.40.0 - '@types/tedious': 4.0.14 + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + transitivePeerDependencies: + - supports-color + + '@opentelemetry/instrumentation-pg@0.50.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.27.0 + '@opentelemetry/sql-common': 0.40.1(@opentelemetry/api@1.9.1) + '@types/pg': 8.6.1 + '@types/pg-pool': 2.0.6 + transitivePeerDependencies: + - supports-color + + '@opentelemetry/instrumentation-redis-4@0.46.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) + '@opentelemetry/redis-common': 0.36.2 + '@opentelemetry/semantic-conventions': 1.41.1 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation@0.207.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/instrumentation-tedious@0.18.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/api-logs': 0.207.0 - import-in-the-middle: 2.0.6 - require-in-the-middle: 8.0.1 + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + '@types/tedious': 4.0.14 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation@0.212.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/instrumentation-undici@0.10.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/api-logs': 0.212.0 - import-in-the-middle: 2.0.6 - require-in-the-middle: 8.0.1 + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation@0.214.0(@opentelemetry/api@1.9.1)': + '@opentelemetry/instrumentation@0.53.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/api-logs': 0.214.0 - import-in-the-middle: 3.0.1 - require-in-the-middle: 8.0.1 + '@opentelemetry/api-logs': 0.53.0 + '@types/shimmer': 1.2.0 + import-in-the-middle: 1.15.0 + require-in-the-middle: 7.5.2 + semver: 7.8.4 + shimmer: 1.2.1 transitivePeerDependencies: - supports-color - '@opentelemetry/resources@2.7.1(@opentelemetry/api@1.9.1)': + '@opentelemetry/instrumentation@0.57.1(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.40.0 + '@opentelemetry/api-logs': 0.57.1 + '@types/shimmer': 1.2.0 + import-in-the-middle: 1.15.0 + require-in-the-middle: 7.5.2 + semver: 7.8.4 + shimmer: 1.2.1 + transitivePeerDependencies: + - supports-color - '@opentelemetry/sdk-trace-base@2.7.1(@opentelemetry/api@1.9.1)': + '@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) - '@opentelemetry/resources': 2.7.1(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.40.0 + '@opentelemetry/api-logs': 0.57.2 + '@types/shimmer': 1.2.0 + import-in-the-middle: 1.15.0 + require-in-the-middle: 7.5.2 + semver: 7.8.4 + shimmer: 1.2.1 + transitivePeerDependencies: + - supports-color - '@opentelemetry/semantic-conventions@1.40.0': {} + '@opentelemetry/redis-common@0.36.2': {} - '@opentelemetry/sql-common@0.41.2(@opentelemetry/api@1.9.1)': + '@opentelemetry/resources@1.30.1(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.28.0 - '@oxc-project/types@0.127.0': - optional: true + '@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.28.0 - '@oxc-project/types@0.132.0': {} + '@opentelemetry/semantic-conventions@1.27.0': {} + + '@opentelemetry/semantic-conventions@1.28.0': {} + + '@opentelemetry/semantic-conventions@1.41.1': {} + + '@opentelemetry/sql-common@0.40.1(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) + + '@oxc-project/types@0.135.0': {} '@oxfmt/binding-android-arm-eabi@0.51.0': optional: true @@ -5120,441 +3697,220 @@ snapshots: '@oxfmt/binding-win32-x64-msvc@0.51.0': optional: true - '@oxlint/binding-android-arm-eabi@1.66.0': - optional: true - - '@oxlint/binding-android-arm64@1.66.0': + '@oxlint/binding-android-arm-eabi@1.69.0': optional: true - '@oxlint/binding-darwin-arm64@1.66.0': + '@oxlint/binding-android-arm64@1.69.0': optional: true - '@oxlint/binding-darwin-x64@1.66.0': + '@oxlint/binding-darwin-arm64@1.69.0': optional: true - '@oxlint/binding-freebsd-x64@1.66.0': + '@oxlint/binding-darwin-x64@1.69.0': optional: true - '@oxlint/binding-linux-arm-gnueabihf@1.66.0': + '@oxlint/binding-freebsd-x64@1.69.0': optional: true - '@oxlint/binding-linux-arm-musleabihf@1.66.0': + '@oxlint/binding-linux-arm-gnueabihf@1.69.0': optional: true - '@oxlint/binding-linux-arm64-gnu@1.66.0': + '@oxlint/binding-linux-arm-musleabihf@1.69.0': optional: true - '@oxlint/binding-linux-arm64-musl@1.66.0': + '@oxlint/binding-linux-arm64-gnu@1.69.0': optional: true - '@oxlint/binding-linux-ppc64-gnu@1.66.0': + '@oxlint/binding-linux-arm64-musl@1.69.0': optional: true - '@oxlint/binding-linux-riscv64-gnu@1.66.0': + '@oxlint/binding-linux-ppc64-gnu@1.69.0': optional: true - '@oxlint/binding-linux-riscv64-musl@1.66.0': + '@oxlint/binding-linux-riscv64-gnu@1.69.0': optional: true - '@oxlint/binding-linux-s390x-gnu@1.66.0': + '@oxlint/binding-linux-riscv64-musl@1.69.0': optional: true - '@oxlint/binding-linux-x64-gnu@1.66.0': + '@oxlint/binding-linux-s390x-gnu@1.69.0': optional: true - '@oxlint/binding-linux-x64-musl@1.66.0': + '@oxlint/binding-linux-x64-gnu@1.69.0': optional: true - '@oxlint/binding-openharmony-arm64@1.66.0': + '@oxlint/binding-linux-x64-musl@1.69.0': optional: true - '@oxlint/binding-win32-arm64-msvc@1.66.0': + '@oxlint/binding-openharmony-arm64@1.69.0': optional: true - '@oxlint/binding-win32-ia32-msvc@1.66.0': + '@oxlint/binding-win32-arm64-msvc@1.69.0': optional: true - '@oxlint/binding-win32-x64-msvc@1.66.0': + '@oxlint/binding-win32-ia32-msvc@1.69.0': optional: true - '@pkgr/core@0.2.9': + '@oxlint/binding-win32-x64-msvc@1.69.0': optional: true - '@prisma/adapter-pg@7.8.0': + '@prisma/client@4.16.2(prisma@4.16.2)': dependencies: - '@prisma/driver-adapter-utils': 7.8.0 - '@types/pg': 8.20.0 - pg: 8.21.0 - postgres-array: 3.0.4 - transitivePeerDependencies: - - pg-native - - '@prisma/client-runtime-utils@7.8.0': {} - - '@prisma/client@7.8.0(prisma@7.8.0)(typescript@6.0.3)': - dependencies: - '@prisma/client-runtime-utils': 7.8.0 + '@prisma/engines-version': 4.16.1-1.4bc8b6e1b66cb932731fb1bdbbc550d1e010de81 optionalDependencies: - prisma: 7.8.0(@types/react@19.2.14)(magicast@0.5.2)(react-dom@19.2.5)(react@19.2.5)(typescript@6.0.3) - typescript: 6.0.3 - - '@prisma/config@7.8.0(magicast@0.5.2)': - dependencies: - c12: 3.3.4(magicast@0.5.2) - deepmerge-ts: 7.1.5 - effect: 3.20.0 - empathic: 2.0.0 - transitivePeerDependencies: - - magicast - - '@prisma/debug@7.2.0': {} - - '@prisma/debug@7.8.0': {} - - '@prisma/dev@0.24.3(typescript@6.0.3)': - dependencies: - '@electric-sql/pglite': 0.4.1 - '@electric-sql/pglite-socket': 0.1.1(@electric-sql/pglite@0.4.1) - '@electric-sql/pglite-tools': 0.3.1(@electric-sql/pglite@0.4.1) - '@hono/node-server': 1.19.11(hono@4.12.12) - '@prisma/get-platform': 7.2.0 - '@prisma/query-plan-executor': 7.2.0 - '@prisma/streams-local': 0.1.2 - foreground-child: 3.3.1 - get-port-please: 3.2.0 - hono: 4.12.12 - http-status-codes: 2.3.0 - pathe: 2.0.3 - proper-lockfile: 4.1.2 - remeda: 2.33.4 - std-env: 3.10.0 - valibot: 1.2.0(typescript@6.0.3) - zeptomatch: 2.1.0 - transitivePeerDependencies: - - typescript - - '@prisma/dmmf@7.8.0': {} - - '@prisma/driver-adapter-utils@7.8.0': - dependencies: - '@prisma/debug': 7.8.0 - - '@prisma/engines-version@7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a': {} - - '@prisma/engines@7.8.0': - dependencies: - '@prisma/debug': 7.8.0 - '@prisma/engines-version': 7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a - '@prisma/fetch-engine': 7.8.0 - '@prisma/get-platform': 7.8.0 - - '@prisma/fetch-engine@7.8.0': - dependencies: - '@prisma/debug': 7.8.0 - '@prisma/engines-version': 7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a - '@prisma/get-platform': 7.8.0 - - '@prisma/generator-helper@7.8.0': - dependencies: - '@prisma/debug': 7.8.0 - '@prisma/dmmf': 7.8.0 - '@prisma/generator': 7.8.0 - - '@prisma/generator@7.8.0': {} + prisma: 4.16.2 - '@prisma/get-platform@7.2.0': - dependencies: - '@prisma/debug': 7.2.0 + '@prisma/engines-version@4.16.1-1.4bc8b6e1b66cb932731fb1bdbbc550d1e010de81': {} - '@prisma/get-platform@7.8.0': - dependencies: - '@prisma/debug': 7.8.0 + '@prisma/engines@4.16.2': {} - '@prisma/instrumentation@7.6.0(@opentelemetry/api@1.9.1)': + '@prisma/instrumentation@5.22.0': dependencies: '@opentelemetry/api': 1.9.1 - '@opentelemetry/instrumentation': 0.207.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation': 0.53.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': 1.30.1(@opentelemetry/api@1.9.1) transitivePeerDependencies: - supports-color - '@prisma/query-plan-executor@7.2.0': {} - - '@prisma/streams-local@0.1.2': - dependencies: - ajv: 8.17.1 - better-result: 2.8.2 - env-paths: 3.0.0 - proper-lockfile: 4.1.2 - - '@prisma/studio-core@0.27.3(@types/react@19.2.14)(react-dom@19.2.5)(react@19.2.5)': - dependencies: - '@radix-ui/react-toggle': 1.1.10(@types/react@19.2.14)(react-dom@19.2.5)(react@19.2.5) - '@types/react': 19.2.14 - chart.js: 4.5.1 - react: 19.2.5 - react-dom: 19.2.5(react@19.2.5) - transitivePeerDependencies: - - '@types/react-dom' - '@quansync/fs@1.0.0': dependencies: quansync: 1.0.0 - '@radix-ui/primitive@1.1.3': {} - - '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.14)(react@19.2.5)': - dependencies: - react: 19.2.5 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-primitive@2.1.3(@types/react@19.2.14)(react-dom@19.2.5)(react@19.2.5)': - dependencies: - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.5) - react: 19.2.5 - react-dom: 19.2.5(react@19.2.5) - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-slot@1.2.3(@types/react@19.2.14)(react@19.2.5)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.5) - react: 19.2.5 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-toggle@1.1.10(@types/react@19.2.14)(react-dom@19.2.5)(react@19.2.5)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-primitive': 2.1.3(@types/react@19.2.14)(react-dom@19.2.5)(react@19.2.5) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.5) - react: 19.2.5 - react-dom: 19.2.5(react@19.2.5) - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.14)(react@19.2.5)': - dependencies: - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.14)(react@19.2.5) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.5) - react: 19.2.5 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.14)(react@19.2.5)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.5) - react: 19.2.5 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.14)(react@19.2.5)': - dependencies: - react: 19.2.5 - optionalDependencies: - '@types/react': 19.2.14 - - '@rolldown/binding-android-arm64@1.0.0-rc.17': + '@rolldown/binding-android-arm64@1.1.1': optional: true - '@rolldown/binding-android-arm64@1.0.2': + '@rolldown/binding-darwin-arm64@1.1.1': optional: true - '@rolldown/binding-darwin-arm64@1.0.0-rc.17': + '@rolldown/binding-darwin-x64@1.1.1': optional: true - '@rolldown/binding-darwin-arm64@1.0.2': + '@rolldown/binding-freebsd-x64@1.1.1': optional: true - '@rolldown/binding-darwin-x64@1.0.0-rc.17': + '@rolldown/binding-linux-arm-gnueabihf@1.1.1': optional: true - '@rolldown/binding-darwin-x64@1.0.2': + '@rolldown/binding-linux-arm64-gnu@1.1.1': optional: true - '@rolldown/binding-freebsd-x64@1.0.0-rc.17': + '@rolldown/binding-linux-arm64-musl@1.1.1': optional: true - '@rolldown/binding-freebsd-x64@1.0.2': + '@rolldown/binding-linux-ppc64-gnu@1.1.1': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.17': + '@rolldown/binding-linux-s390x-gnu@1.1.1': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.0.2': + '@rolldown/binding-linux-x64-gnu@1.1.1': optional: true - '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.17': + '@rolldown/binding-linux-x64-musl@1.1.1': optional: true - '@rolldown/binding-linux-arm64-gnu@1.0.2': + '@rolldown/binding-openharmony-arm64@1.1.1': optional: true - '@rolldown/binding-linux-arm64-musl@1.0.0-rc.17': - optional: true - - '@rolldown/binding-linux-arm64-musl@1.0.2': - optional: true - - '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.17': - optional: true - - '@rolldown/binding-linux-ppc64-gnu@1.0.2': - optional: true - - '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.17': - optional: true - - '@rolldown/binding-linux-s390x-gnu@1.0.2': - optional: true - - '@rolldown/binding-linux-x64-gnu@1.0.0-rc.17': - optional: true - - '@rolldown/binding-linux-x64-gnu@1.0.2': - optional: true - - '@rolldown/binding-linux-x64-musl@1.0.0-rc.17': - optional: true - - '@rolldown/binding-linux-x64-musl@1.0.2': - optional: true - - '@rolldown/binding-openharmony-arm64@1.0.0-rc.17': - optional: true - - '@rolldown/binding-openharmony-arm64@1.0.2': - optional: true - - '@rolldown/binding-wasm32-wasi@1.0.0-rc.17': + '@rolldown/binding-wasm32-wasi@1.1.1': dependencies: - '@emnapi/core': 1.10.0 - '@emnapi/runtime': 1.10.0 - '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) - optional: true - - '@rolldown/binding-wasm32-wasi@1.0.2': - dependencies: - '@emnapi/core': 1.10.0 - '@emnapi/runtime': 1.10.0 - '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) - optional: true - - '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.17': - optional: true - - '@rolldown/binding-win32-arm64-msvc@1.0.2': - optional: true - - '@rolldown/binding-win32-x64-msvc@1.0.0-rc.17': + '@emnapi/core': 1.11.0 + '@emnapi/runtime': 1.11.0 + '@napi-rs/wasm-runtime': 1.1.5(@emnapi/core@1.11.0)(@emnapi/runtime@1.11.0) optional: true - '@rolldown/binding-win32-x64-msvc@1.0.2': + '@rolldown/binding-win32-arm64-msvc@1.1.1': optional: true - '@rolldown/pluginutils@1.0.0-rc.17': + '@rolldown/binding-win32-x64-msvc@1.1.1': optional: true '@rolldown/pluginutils@1.0.1': {} - '@rollup/plugin-alias@6.0.0(rollup@4.60.3)': + '@rollup/plugin-alias@6.0.0(rollup@4.61.1)': optionalDependencies: - rollup: 4.60.3 + rollup: 4.61.1 - '@rollup/rollup-android-arm-eabi@4.60.3': + '@rollup/rollup-android-arm-eabi@4.61.1': optional: true - '@rollup/rollup-android-arm64@4.60.3': + '@rollup/rollup-android-arm64@4.61.1': optional: true - '@rollup/rollup-darwin-arm64@4.60.3': + '@rollup/rollup-darwin-arm64@4.61.1': optional: true - '@rollup/rollup-darwin-x64@4.60.3': + '@rollup/rollup-darwin-x64@4.61.1': optional: true - '@rollup/rollup-freebsd-arm64@4.60.3': + '@rollup/rollup-freebsd-arm64@4.61.1': optional: true - '@rollup/rollup-freebsd-x64@4.60.3': + '@rollup/rollup-freebsd-x64@4.61.1': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.60.3': + '@rollup/rollup-linux-arm-gnueabihf@4.61.1': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.60.3': + '@rollup/rollup-linux-arm-musleabihf@4.61.1': optional: true - '@rollup/rollup-linux-arm64-gnu@4.60.3': + '@rollup/rollup-linux-arm64-gnu@4.61.1': optional: true - '@rollup/rollup-linux-arm64-musl@4.60.3': + '@rollup/rollup-linux-arm64-musl@4.61.1': optional: true - '@rollup/rollup-linux-loong64-gnu@4.60.3': + '@rollup/rollup-linux-loong64-gnu@4.61.1': optional: true - '@rollup/rollup-linux-loong64-musl@4.60.3': + '@rollup/rollup-linux-loong64-musl@4.61.1': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.60.3': + '@rollup/rollup-linux-ppc64-gnu@4.61.1': optional: true - '@rollup/rollup-linux-ppc64-musl@4.60.3': + '@rollup/rollup-linux-ppc64-musl@4.61.1': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.60.3': + '@rollup/rollup-linux-riscv64-gnu@4.61.1': optional: true - '@rollup/rollup-linux-riscv64-musl@4.60.3': + '@rollup/rollup-linux-riscv64-musl@4.61.1': optional: true - '@rollup/rollup-linux-s390x-gnu@4.60.3': + '@rollup/rollup-linux-s390x-gnu@4.61.1': optional: true - '@rollup/rollup-linux-x64-gnu@4.60.3': + '@rollup/rollup-linux-x64-gnu@4.61.1': optional: true - '@rollup/rollup-linux-x64-musl@4.60.3': + '@rollup/rollup-linux-x64-musl@4.61.1': optional: true - '@rollup/rollup-openbsd-x64@4.60.3': + '@rollup/rollup-openbsd-x64@4.61.1': optional: true - '@rollup/rollup-openharmony-arm64@4.60.3': + '@rollup/rollup-openharmony-arm64@4.61.1': optional: true - '@rollup/rollup-win32-arm64-msvc@4.60.3': + '@rollup/rollup-win32-arm64-msvc@4.61.1': optional: true - '@rollup/rollup-win32-ia32-msvc@4.60.3': + '@rollup/rollup-win32-ia32-msvc@4.61.1': optional: true - '@rollup/rollup-win32-x64-gnu@4.60.3': + '@rollup/rollup-win32-x64-gnu@4.61.1': optional: true - '@rollup/rollup-win32-x64-msvc@4.60.3': + '@rollup/rollup-win32-x64-msvc@4.61.1': optional: true '@sapphire/async-queue@1.5.5': {} - '@sapphire/bitfield@1.2.4': {} - - '@sapphire/cron@1.2.1': - dependencies: - '@sapphire/utilities': 3.18.2 - - '@sapphire/decorators@6.2.0': - dependencies: - tslib: 2.8.1 - '@sapphire/discord-utilities@3.5.0': dependencies: - discord-api-types: 0.38.34 - - '@sapphire/discord-utilities@4.0.0': - dependencies: - discord-api-types: 0.38.34 + discord-api-types: 0.38.48 '@sapphire/discord.js-utilities@7.3.3': dependencies: @@ -5565,68 +3921,37 @@ snapshots: '@sapphire/duration@1.2.0': {} - '@sapphire/fetch@3.0.5': {} - - '@sapphire/framework@5.5.0': + '@sapphire/framework@4.8.5': dependencies: '@discordjs/builders': 1.14.1 - '@sapphire/discord-utilities': 4.0.0 + '@sapphire/discord-utilities': 3.5.0 '@sapphire/discord.js-utilities': 7.3.3 '@sapphire/lexure': 1.1.12 - '@sapphire/pieces': 4.4.1 + '@sapphire/pieces': 3.10.0 '@sapphire/ratelimits': 2.4.11 '@sapphire/result': 2.8.0 '@sapphire/stopwatch': 1.5.4 '@sapphire/utilities': 3.18.2 - '@sapphire/iana-mime-types@1.15.0': {} - - '@sapphire/iterator-utilities@2.0.1': {} - '@sapphire/lexure@1.1.12': dependencies: '@sapphire/result': 2.8.0 - '@sapphire/pieces@4.4.1': + '@sapphire/pieces@3.10.0': dependencies: - '@discordjs/collection': 2.1.1 + '@discordjs/collection': 1.5.3 '@sapphire/utilities': 3.18.2 tslib: 2.8.1 - '@sapphire/plugin-api@8.3.1': - dependencies: - '@sapphire/iana-mime-types': 1.15.0 - '@types/ws': 8.18.1 - '@vladfrangu/async_event_emitter': 2.4.6 - cookie-es: 1.2.2 - tldts: 7.0.17 - undici: 7.16.0 - - '@sapphire/plugin-editable-commands@4.0.4': - dependencies: - '@skyra/editable-commands': 3.0.4 - - '@sapphire/plugin-i18next@8.0.0(typescript@6.0.3)': - dependencies: - '@sapphire/utilities': 3.18.2 - '@skyra/i18next-backend': 2.0.6 - chokidar: 4.0.3 - i18next: 25.6.3(typescript@6.0.3) - transitivePeerDependencies: - - typescript - - '@sapphire/plugin-logger@4.1.0': - dependencies: - '@sapphire/timestamp': 1.0.5 - colorette: 2.0.20 - - '@sapphire/plugin-subcommands@7.0.1': + '@sapphire/pieces@4.4.1': dependencies: + '@discordjs/collection': 2.1.1 '@sapphire/utilities': 3.18.2 + tslib: 2.8.1 '@sapphire/prettier-config@2.0.0': dependencies: - prettier: 3.8.3 + prettier: 3.8.4 '@sapphire/ratelimits@2.4.11': {} @@ -5635,7 +3960,7 @@ snapshots: '@sapphire/shapeshift@4.0.0': dependencies: fast-deep-equal: 3.1.3 - lodash: 4.17.21 + lodash: 4.18.1 '@sapphire/snowflake@3.5.3': {} @@ -5645,17 +3970,6 @@ snapshots: dependencies: tslib: 2.8.1 - '@sapphire/time-utilities@1.7.14': - dependencies: - '@sapphire/cron': 1.2.1 - '@sapphire/duration': 1.2.0 - '@sapphire/timer-manager': 1.0.4 - '@sapphire/timestamp': 1.0.5 - - '@sapphire/timer-manager@1.0.4': {} - - '@sapphire/timestamp@1.0.5': {} - '@sapphire/ts-config@5.0.3': dependencies: tslib: 2.8.1 @@ -5663,286 +3977,290 @@ snapshots: '@sapphire/utilities@3.18.2': {} - '@sentry/core@10.53.1': {} - - '@sentry/node-core@10.53.1(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.7.1)(@opentelemetry/instrumentation@0.214.0)(@opentelemetry/sdk-trace-base@2.7.1)(@opentelemetry/semantic-conventions@1.40.0)': - dependencies: - '@sentry/core': 10.53.1 - '@sentry/opentelemetry': 10.53.1(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.7.1)(@opentelemetry/sdk-trace-base@2.7.1)(@opentelemetry/semantic-conventions@1.40.0) - import-in-the-middle: 3.0.1 - optionalDependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-trace-base': 2.7.1(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.40.0 - - '@sentry/node@10.53.1': + '@sentry-internal/tracing@7.120.4': dependencies: - '@fastify/otel': 0.18.0(@opentelemetry/api@1.9.1) - '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-amqplib': 0.61.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-connect': 0.57.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-dataloader': 0.31.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-fs': 0.33.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-generic-pool': 0.57.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-graphql': 0.62.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-hapi': 0.60.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-http': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-kafkajs': 0.23.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-knex': 0.58.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-koa': 0.62.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-lru-memoizer': 0.58.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-mongodb': 0.67.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-mongoose': 0.60.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-mysql': 0.60.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-mysql2': 0.60.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-pg': 0.66.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-tedious': 0.33.0(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-trace-base': 2.7.1(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.40.0 - '@prisma/instrumentation': 7.6.0(@opentelemetry/api@1.9.1) - '@sentry/core': 10.53.1 - '@sentry/node-core': 10.53.1(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.7.1)(@opentelemetry/instrumentation@0.214.0)(@opentelemetry/sdk-trace-base@2.7.1)(@opentelemetry/semantic-conventions@1.40.0) - '@sentry/opentelemetry': 10.53.1(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.7.1)(@opentelemetry/sdk-trace-base@2.7.1)(@opentelemetry/semantic-conventions@1.40.0) - import-in-the-middle: 3.0.1 - transitivePeerDependencies: - - '@opentelemetry/exporter-trace-otlp-http' - - supports-color + '@sentry/core': 7.120.4 + '@sentry/types': 7.120.4 + '@sentry/utils': 7.120.4 - '@sentry/opentelemetry@10.53.1(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.7.1)(@opentelemetry/sdk-trace-base@2.7.1)(@opentelemetry/semantic-conventions@1.40.0)': + '@sentry/core@7.114.0': dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-trace-base': 2.7.1(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.40.0 - '@sentry/core': 10.53.1 + '@sentry/types': 7.114.0 + '@sentry/utils': 7.114.0 - '@simple-libs/child-process-utils@1.0.2': + '@sentry/core@7.120.4': dependencies: - '@simple-libs/stream-utils': 1.2.0 - - '@simple-libs/stream-utils@1.2.0': {} - - '@skyra/ai-android-arm-eabi@2.0.1': - optional: true - - '@skyra/ai-android-arm64@2.0.1': - optional: true - - '@skyra/ai-darwin-arm64@2.0.1': - optional: true - - '@skyra/ai-darwin-x64@2.0.1': - optional: true - - '@skyra/ai-linux-arm-gnueabihf@2.0.1': - optional: true + '@sentry/types': 7.120.4 + '@sentry/utils': 7.120.4 - '@skyra/ai-linux-arm64-gnu@2.0.1': - optional: true + '@sentry/core@8.55.2': {} - '@skyra/ai-linux-arm64-musl@2.0.1': - optional: true + '@sentry/integrations@7.114.0': + dependencies: + '@sentry/core': 7.114.0 + '@sentry/types': 7.114.0 + '@sentry/utils': 7.114.0 + localforage: 1.10.0 - '@skyra/ai-linux-x64-gnu@2.0.1': - optional: true + '@sentry/integrations@7.120.4': + dependencies: + '@sentry/core': 7.120.4 + '@sentry/types': 7.120.4 + '@sentry/utils': 7.120.4 + localforage: 1.10.0 - '@skyra/ai-linux-x64-musl@2.0.1': - optional: true + '@sentry/node@7.120.4': + dependencies: + '@sentry-internal/tracing': 7.120.4 + '@sentry/core': 7.120.4 + '@sentry/integrations': 7.120.4 + '@sentry/types': 7.120.4 + '@sentry/utils': 7.120.4 - '@skyra/ai-win32-arm64-msvc@2.0.1': - optional: true + '@sentry/node@8.55.2': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/context-async-hooks': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-amqplib': 0.46.1(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-connect': 0.43.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-dataloader': 0.16.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-express': 0.47.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-fastify': 0.44.1(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-fs': 0.19.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-generic-pool': 0.43.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-graphql': 0.47.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-hapi': 0.45.1(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-http': 0.57.1(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-ioredis': 0.47.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-kafkajs': 0.7.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-knex': 0.44.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-koa': 0.47.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-lru-memoizer': 0.44.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-mongodb': 0.51.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-mongoose': 0.46.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-mysql': 0.45.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-mysql2': 0.45.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-nestjs-core': 0.44.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-pg': 0.50.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-redis-4': 0.46.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-tedious': 0.18.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-undici': 0.10.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + '@prisma/instrumentation': 5.22.0 + '@sentry/core': 8.55.2 + '@sentry/opentelemetry': 8.55.2(@opentelemetry/api@1.9.1)(@opentelemetry/context-async-hooks@1.30.1)(@opentelemetry/core@1.30.1)(@opentelemetry/instrumentation@0.57.2)(@opentelemetry/sdk-trace-base@1.30.1)(@opentelemetry/semantic-conventions@1.41.1) + import-in-the-middle: 1.15.0 + transitivePeerDependencies: + - supports-color - '@skyra/ai-win32-x64-msvc@2.0.1': - optional: true + '@sentry/opentelemetry@8.55.2(@opentelemetry/api@1.9.1)(@opentelemetry/context-async-hooks@1.30.1)(@opentelemetry/core@1.30.1)(@opentelemetry/instrumentation@0.57.2)(@opentelemetry/sdk-trace-base@1.30.1)(@opentelemetry/semantic-conventions@1.41.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/context-async-hooks': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': 1.30.1(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + '@sentry/core': 8.55.2 - '@skyra/ai@2.0.1': - optionalDependencies: - '@skyra/ai-android-arm-eabi': 2.0.1 - '@skyra/ai-android-arm64': 2.0.1 - '@skyra/ai-darwin-arm64': 2.0.1 - '@skyra/ai-darwin-x64': 2.0.1 - '@skyra/ai-linux-arm-gnueabihf': 2.0.1 - '@skyra/ai-linux-arm64-gnu': 2.0.1 - '@skyra/ai-linux-arm64-musl': 2.0.1 - '@skyra/ai-linux-x64-gnu': 2.0.1 - '@skyra/ai-linux-x64-musl': 2.0.1 - '@skyra/ai-win32-arm64-msvc': 2.0.1 - '@skyra/ai-win32-x64-msvc': 2.0.1 + '@sentry/types@7.114.0': {} - '@skyra/char@1.0.3': {} + '@sentry/types@7.120.4': {} - '@skyra/editable-commands@3.0.4': {} + '@sentry/utils@7.114.0': + dependencies: + '@sentry/types': 7.114.0 - '@skyra/env-utilities@2.0.1': + '@sentry/utils@7.120.4': dependencies: - dotenv: 16.6.1 - dotenv-expand: 12.0.3 + '@sentry/types': 7.120.4 - '@skyra/i18next-backend@2.0.6': + '@simple-libs/child-process-utils@1.0.2': dependencies: - tslib: 2.8.1 + '@simple-libs/stream-utils': 1.2.0 + + '@simple-libs/stream-utils@1.2.0': {} + + '@skyra/char@1.0.3': {} '@skyra/jaro-winkler@1.1.1': {} '@standard-schema/spec@1.1.0': {} - '@tybys/wasm-util@0.10.1': + '@tokenizer/token@0.3.0': {} + + '@tybys/wasm-util@0.10.2': dependencies: tslib: 2.8.1 optional: true - '@types/backoff@2.5.5': - dependencies: - '@types/node': 22.19.1 - '@types/chai@5.2.3': dependencies: '@types/deep-eql': 4.0.2 assertion-error: 2.0.1 - '@types/connect@3.4.38': - dependencies: - '@types/node': 22.19.1 - - '@types/conventional-commits-parser@5.0.2': + '@types/connect@3.4.36': dependencies: - '@types/node': 22.19.1 - optional: true + '@types/node': 22.19.21 '@types/deep-eql@4.0.2': {} - '@types/diff@6.0.0': {} - - '@types/estree@1.0.8': {} - - '@types/he@1.2.3': {} + '@types/estree@1.0.9': {} '@types/jsesc@2.5.1': {} - '@types/mysql@2.15.27': + '@types/mysql@2.15.26': dependencies: - '@types/node': 22.19.1 + '@types/node': 22.19.21 - '@types/node@22.19.1': - dependencies: - undici-types: 6.21.0 + '@types/node@13.13.52': {} - '@types/pg-pool@2.0.7': + '@types/node@22.19.21': dependencies: - '@types/pg': 8.20.0 + undici-types: 6.21.0 - '@types/pg@8.15.6': + '@types/pg-pool@2.0.6': dependencies: - '@types/node': 22.19.1 - pg-protocol: 1.13.0 - pg-types: 2.2.0 + '@types/pg': 8.6.1 - '@types/pg@8.20.0': + '@types/pg@8.6.1': dependencies: - '@types/node': 22.19.1 - pg-protocol: 1.13.0 + '@types/node': 22.19.21 + pg-protocol: 1.14.0 pg-types: 2.2.0 - '@types/react@19.2.14': - dependencies: - csstype: 3.2.3 + '@types/shimmer@1.2.0': {} '@types/tedious@4.0.14': dependencies: - '@types/node': 22.19.1 + '@types/node': 22.19.21 + + '@types/tinycolor2@1.4.6': {} '@types/ws@8.18.1': dependencies: - '@types/node': 22.19.1 + '@types/node': 22.19.21 - '@vitest/coverage-v8@4.1.7(vitest@4.1.7)': + '@vitest/coverage-v8@4.1.8(vitest@4.1.8)': dependencies: '@bcoe/v8-coverage': 1.0.2 - '@vitest/utils': 4.1.7 - ast-v8-to-istanbul: 1.0.0 + '@vitest/utils': 4.1.8 + ast-v8-to-istanbul: 1.0.4 istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 istanbul-reports: 3.2.0 - magicast: 0.5.2 - obug: 2.1.1 + magicast: 0.5.3 + obug: 2.1.2 std-env: 4.1.0 tinyrainbow: 3.1.0 - vitest: 4.1.7(@opentelemetry/api@1.9.1)(@types/node@22.19.1)(@vitest/coverage-v8@4.1.7)(vite@7.2.4) + vitest: 4.1.8(@opentelemetry/api@1.9.1)(@types/node@22.19.21)(@vitest/coverage-v8@4.1.8)(vite@6.4.3) - '@vitest/expect@4.1.7': + '@vitest/expect@4.1.8': dependencies: '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 - '@vitest/spy': 4.1.7 - '@vitest/utils': 4.1.7 + '@vitest/spy': 4.1.8 + '@vitest/utils': 4.1.8 chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.7(vite@7.2.4)': + '@vitest/mocker@4.1.8(vite@6.4.3)': dependencies: - '@vitest/spy': 4.1.7 + '@vitest/spy': 4.1.8 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.2.4(@types/node@22.19.1)(jiti@2.6.1)(yaml@2.9.0) + vite: 6.4.3(@types/node@22.19.21)(jiti@2.6.1)(yaml@2.9.0) - '@vitest/pretty-format@4.1.7': + '@vitest/pretty-format@4.1.8': dependencies: tinyrainbow: 3.1.0 - '@vitest/runner@4.1.7': + '@vitest/runner@4.1.8': dependencies: - '@vitest/utils': 4.1.7 + '@vitest/utils': 4.1.8 pathe: 2.0.3 - '@vitest/snapshot@4.1.7': + '@vitest/snapshot@4.1.8': dependencies: - '@vitest/pretty-format': 4.1.7 - '@vitest/utils': 4.1.7 + '@vitest/pretty-format': 4.1.8 + '@vitest/utils': 4.1.8 magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@4.1.7': {} + '@vitest/spy@4.1.8': {} - '@vitest/utils@4.1.7': + '@vitest/utils@4.1.8': dependencies: - '@vitest/pretty-format': 4.1.7 + '@vitest/pretty-format': 4.1.8 convert-source-map: 2.0.0 tinyrainbow: 3.1.0 - '@vladfrangu/async_event_emitter@2.4.6': {} - '@vladfrangu/async_event_emitter@2.4.7': {} - JSONStream@1.3.5: + '@wolfstar/env-utilities@3.0.1': dependencies: - jsonparse: 1.3.1 - through: 2.3.8 + dotenv: 17.4.2 + dotenv-expand: 12.0.3 + + '@wolfstar/http-framework-i18n@3.0.1': + dependencies: + '@discordjs/collection': 2.1.1 + '@sapphire/utilities': 3.18.2 + '@wolfstar/i18next-backend': 3.0.1 + discord-api-types: 0.38.48 + i18next: 22.5.1 + tslib: 2.8.1 + + '@wolfstar/http-framework@3.0.1': + dependencies: + '@discordjs/builders': 1.14.1 + '@discordjs/collection': 2.1.1 + '@discordjs/rest': 2.6.1 + '@discordjs/util': 1.2.0 + '@sapphire/pieces': 4.4.1 + '@sapphire/result': 2.8.0 + '@sapphire/utilities': 3.18.2 + '@vladfrangu/async_event_emitter': 2.4.7 + discord-api-types: 0.38.48 - acorn-import-attributes@1.9.5(acorn@8.15.0): + '@wolfstar/i18next-backend@3.0.1': dependencies: - acorn: 8.15.0 + tslib: 2.8.1 - acorn-node@1.8.2: + '@wolfstar/shared-http-pieces@3.0.1': dependencies: - acorn: 7.4.1 - acorn-walk: 7.2.0 - xtend: 4.0.2 + '@discordjs/builders': 1.14.1 + '@discordjs/collection': 2.1.1 + '@sentry/node': 8.55.2 + '@wolfstar/env-utilities': 3.0.1 + '@wolfstar/http-framework': 3.0.1 + '@wolfstar/http-framework-i18n': 3.0.1 + discord-api-types: 0.38.48 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@wolfstar/start-banner@3.0.1': {} - acorn-walk@7.2.0: {} + abort-controller@3.0.0: + dependencies: + event-target-shim: 5.0.1 - acorn@7.4.1: {} + acorn-import-attributes@1.9.5(acorn@8.17.0): + dependencies: + acorn: 8.17.0 - acorn@8.15.0: {} + acorn@8.17.0: {} - ajv@8.17.1: + ajv@8.20.0: dependencies: fast-deep-equal: 3.1.3 - fast-uri: 3.1.0 + fast-uri: 3.1.2 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 @@ -5950,14 +4268,12 @@ snapshots: dependencies: type-fest: 0.21.3 - ansi-escapes@7.2.0: + ansi-escapes@7.3.0: dependencies: environment: 1.1.0 ansi-regex@5.0.1: {} - ansi-styles@2.2.1: {} - ansi-styles@3.2.1: dependencies: color-convert: 1.9.3 @@ -5968,32 +4284,21 @@ snapshots: ansi-styles@6.2.3: {} - ansis@4.2.0: {} + ansis@4.3.1: {} argparse@2.0.1: {} array-ify@1.0.0: {} - asn1.js@4.10.1: - dependencies: - bn.js: 4.12.2 - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - - assert@1.5.1: - dependencies: - object.assign: 4.1.7 - util: 0.10.4 - assertion-error@2.0.1: {} ast-kit@3.0.0-beta.1: dependencies: - '@babel/parser': 8.0.0-rc.4 + '@babel/parser': 8.0.0-rc.6 estree-walker: 3.0.3 pathe: 2.0.3 - ast-v8-to-istanbul@1.0.0: + ast-v8-to-istanbul@1.0.4: dependencies: '@jridgewell/trace-mapping': 0.3.31 estree-walker: 3.0.3 @@ -6001,20 +4306,10 @@ snapshots: at-least-node@1.0.0: {} - available-typed-arrays@1.0.7: - dependencies: - possible-typed-array-names: 1.1.0 - - aws-ssl-profiles@1.1.2: {} - balanced-match@1.0.2: {} - balanced-match@4.0.4: {} - base64-js@1.5.1: {} - better-result@2.8.2: {} - birpc@4.0.0: {} bl@4.1.0: @@ -6023,212 +4318,33 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 - bn.js@4.12.2: {} - - bn.js@5.2.2: {} - - brace-expansion@1.1.12: + brace-expansion@1.1.15: dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 - brace-expansion@5.0.5: - dependencies: - balanced-match: 4.0.4 - braces@3.0.3: dependencies: fill-range: 7.1.1 - brorand@1.1.0: {} - - browser-pack@6.1.0: - dependencies: - JSONStream: 1.3.5 - combine-source-map: 0.8.0 - defined: 1.0.1 - safe-buffer: 5.2.1 - through2: 2.0.5 - umd: 3.0.3 - - browser-process-hrtime@0.1.3: {} - - browser-resolve@2.0.0: - dependencies: - resolve: 1.22.11 - - browserify-aes@1.2.0: - dependencies: - buffer-xor: 1.0.3 - cipher-base: 1.0.7 - create-hash: 1.2.0 - evp_bytestokey: 1.0.3 - inherits: 2.0.4 - safe-buffer: 5.2.1 - - browserify-cipher@1.0.1: - dependencies: - browserify-aes: 1.2.0 - browserify-des: 1.0.2 - evp_bytestokey: 1.0.3 - - browserify-des@1.0.2: - dependencies: - cipher-base: 1.0.7 - des.js: 1.1.0 - inherits: 2.0.4 - safe-buffer: 5.2.1 - - browserify-rsa@4.1.1: - dependencies: - bn.js: 5.2.2 - randombytes: 2.1.0 - safe-buffer: 5.2.1 - - browserify-sign@4.2.5: - dependencies: - bn.js: 5.2.2 - browserify-rsa: 4.1.1 - create-hash: 1.2.0 - create-hmac: 1.1.7 - elliptic: 6.6.1 - inherits: 2.0.4 - parse-asn1: 5.1.9 - readable-stream: 2.3.8 - safe-buffer: 5.2.1 - - browserify-zlib@0.2.0: - dependencies: - pako: 1.0.11 - - browserify@17.0.1: - dependencies: - JSONStream: 1.3.5 - assert: 1.5.1 - browser-pack: 6.1.0 - browser-resolve: 2.0.0 - browserify-zlib: 0.2.0 - buffer: 5.2.1 - cached-path-relative: 1.1.0 - concat-stream: 1.6.2 - console-browserify: 1.2.0 - constants-browserify: 1.0.0 - crypto-browserify: 3.12.1 - defined: 1.0.1 - deps-sort: 2.0.1 - domain-browser: 1.2.0 - duplexer2: 0.1.4 - events: 3.3.0 - glob: 7.2.3 - hasown: 2.0.2 - htmlescape: 1.1.1 - https-browserify: 1.0.0 - inherits: 2.0.4 - insert-module-globals: 7.2.1 - labeled-stream-splicer: 2.0.2 - mkdirp-classic: 0.5.3 - module-deps: 6.2.3 - os-browserify: 0.3.0 - parents: 1.0.1 - path-browserify: 1.0.1 - process: 0.11.10 - punycode: 1.4.1 - querystring-es3: 0.2.1 - read-only-stream: 2.0.0 - readable-stream: 2.3.8 - resolve: 1.22.11 - shasum-object: 1.0.1 - shell-quote: 1.8.3 - stream-browserify: 3.0.0 - stream-http: 3.2.0 - string_decoder: 1.3.0 - subarg: 1.0.0 - syntax-error: 1.4.0 - through2: 2.0.5 - timers-browserify: 1.4.2 - tty-browserify: 0.0.1 - url: 0.11.4 - util: 0.12.5 - vm-browserify: 1.1.2 - xtend: 4.0.2 - - buffer-from@1.1.2: {} - - buffer-xor@1.0.3: {} - - buffer@5.2.1: + buffer@5.7.1: dependencies: base64-js: 1.5.1 ieee754: 1.2.1 - buffer@5.7.1: + buffer@6.0.3: dependencies: base64-js: 1.5.1 ieee754: 1.2.1 - bufferutil@4.1.0: - dependencies: - node-gyp-build: 4.8.4 - - builtin-status-codes@3.0.0: {} - - c12@3.3.4(magicast@0.5.2): - dependencies: - chokidar: 5.0.0 - confbox: 0.2.4 - defu: 6.1.7 - dotenv: 17.4.2 - exsolve: 1.0.8 - giget: 3.2.0 - jiti: 2.6.1 - ohash: 2.0.11 - pathe: 2.0.3 - perfect-debounce: 2.1.0 - pkg-types: 2.3.0 - rc9: 3.0.1 - optionalDependencies: - magicast: 0.5.2 - cac@7.0.0: {} - cached-path-relative@1.1.0: {} - cachedir@2.3.0: {} - call-bind-apply-helpers@1.0.2: - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - - call-bind@1.0.8: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - get-intrinsic: 1.3.0 - set-function-length: 1.2.2 - - call-bound@1.0.4: - dependencies: - call-bind-apply-helpers: 1.0.2 - get-intrinsic: 1.3.0 - callsites@3.1.0: {} - camel-case@3.0.0: - dependencies: - no-case: 2.3.2 - upper-case: 1.1.3 - chai@6.2.2: {} - chalk@1.1.3: - dependencies: - ansi-styles: 2.2.1 - escape-string-regexp: 1.0.5 - has-ansi: 2.0.0 - strip-ansi: 3.0.1 - supports-color: 2.0.0 - chalk@2.4.2: dependencies: ansi-styles: 3.2.1 @@ -6240,30 +4356,9 @@ snapshots: ansi-styles: 4.3.0 supports-color: 7.2.0 - chalk@5.6.2: - optional: true - chardet@0.7.0: {} - chart.js@4.5.1: - dependencies: - '@kurkle/color': 0.3.4 - - chokidar@4.0.3: - dependencies: - readdirp: 4.1.2 - - chokidar@5.0.0: - dependencies: - readdirp: 5.0.0 - - cipher-base@1.0.7: - dependencies: - inherits: 2.0.4 - safe-buffer: 5.2.1 - to-buffer: 1.2.2 - - cjs-module-lexer@2.2.0: {} + cjs-module-lexer@1.4.3: {} cli-cursor@3.1.0: dependencies: @@ -6275,10 +4370,10 @@ snapshots: cli-spinners@2.9.2: {} - cli-truncate@5.1.1: + cli-truncate@5.2.0: dependencies: - slice-ansi: 7.1.2 - string-width: 8.1.0 + slice-ansi: 8.0.0 + string-width: 8.2.1 cli-width@3.0.0: {} @@ -6290,7 +4385,7 @@ snapshots: clone@1.0.4: {} - code-point-at@1.1.0: {} + cluster-key-slot@1.1.1: {} color-convert@1.9.3: dependencies: @@ -6306,19 +4401,12 @@ snapshots: colorette@2.0.20: {} - combine-source-map@0.8.0: - dependencies: - convert-source-map: 1.1.3 - inline-source-map: 0.6.3 - lodash.memoize: 3.0.4 - source-map: 0.5.7 - commander@14.0.3: {} - commitizen@4.3.1(@types/node@22.19.1)(typescript@6.0.3): + commitizen@4.3.1(@types/node@22.19.21)(typescript@4.9.5): dependencies: cachedir: 2.3.0 - cz-conventional-changelog: 3.3.0(@types/node@22.19.1)(typescript@6.0.3) + cz-conventional-changelog: 3.3.0(@types/node@22.19.21)(typescript@4.9.5) dedent: 0.7.0 detect-indent: 6.1.0 find-node-modules: 2.1.3 @@ -6342,227 +4430,52 @@ snapshots: concat-map@0.0.1: {} - concat-stream@1.6.2: - dependencies: - buffer-from: 1.1.2 - inherits: 2.0.4 - readable-stream: 2.3.8 - typedarray: 0.0.6 - - concat-stream@2.0.0: - dependencies: - buffer-from: 1.1.2 - inherits: 2.0.4 - readable-stream: 3.6.2 - typedarray: 0.0.6 - - confbox@0.2.4: {} - - confusables@1.1.1: {} - - console-browserify@1.2.0: {} - - constants-browserify@1.0.0: {} - - conventional-changelog-angular@8.3.1: - dependencies: - compare-func: 2.0.0 - - conventional-changelog-conventionalcommits@9.3.1: - dependencies: - compare-func: 2.0.0 - - conventional-commit-types@3.0.0: {} - - conventional-commits-parser@6.4.0: - dependencies: - '@simple-libs/stream-utils': 1.2.0 - meow: 13.2.0 - - convert-source-map@1.1.3: {} - - convert-source-map@1.9.0: {} - - convert-source-map@2.0.0: {} - - cookie-es@1.2.2: {} - - core-util-is@1.0.3: {} - - cosmiconfig-typescript-loader@6.2.0(@types/node@22.19.1)(cosmiconfig@9.0.0)(typescript@6.0.3): - dependencies: - '@types/node': 22.19.1 - cosmiconfig: 9.0.0(typescript@6.0.3) - jiti: 2.6.1 - typescript: 6.0.3 - optional: true - - cosmiconfig-typescript-loader@6.2.0(@types/node@22.19.1)(cosmiconfig@9.0.1)(typescript@6.0.3): - dependencies: - '@types/node': 22.19.1 - cosmiconfig: 9.0.1(typescript@6.0.3) - jiti: 2.6.1 - typescript: 6.0.3 - - cosmiconfig@9.0.0(typescript@6.0.3): - dependencies: - env-paths: 2.2.1 - import-fresh: 3.3.1 - js-yaml: 4.1.1 - parse-json: 5.2.0 - optionalDependencies: - typescript: 6.0.3 - optional: true - - cosmiconfig@9.0.1(typescript@6.0.3): - dependencies: - env-paths: 2.2.1 - import-fresh: 3.3.1 - js-yaml: 4.1.1 - parse-json: 5.2.0 - optionalDependencies: - typescript: 6.0.3 - - create-ecdh@4.0.4: - dependencies: - bn.js: 4.12.2 - elliptic: 6.6.1 - - create-hash@1.2.0: - dependencies: - cipher-base: 1.0.7 - inherits: 2.0.4 - md5.js: 1.3.5 - ripemd160: 2.0.3 - sha.js: 2.4.12 - - create-hmac@1.1.7: - dependencies: - cipher-base: 1.0.7 - create-hash: 1.2.0 - inherits: 2.0.4 - ripemd160: 2.0.3 - safe-buffer: 5.2.1 - sha.js: 2.4.12 - - cross-spawn@7.0.6: - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - - crypto-browserify@3.12.1: - dependencies: - browserify-cipher: 1.0.1 - browserify-sign: 4.2.5 - create-ecdh: 4.0.4 - create-hash: 1.2.0 - create-hmac: 1.1.7 - diffie-hellman: 5.0.3 - hash-base: 3.0.5 - inherits: 2.0.4 - pbkdf2: 3.1.5 - public-encrypt: 4.0.3 - randombytes: 2.1.0 - randomfill: 1.0.4 - - csstype@3.2.3: {} - - cz-conventional-changelog@3.3.0(@types/node@22.19.1)(typescript@6.0.3): - dependencies: - chalk: 2.4.2 - commitizen: 4.3.1(@types/node@22.19.1)(typescript@6.0.3) - conventional-commit-types: 3.0.0 - lodash.map: 4.6.0 - longest: 2.0.1 - word-wrap: 1.2.5 - optionalDependencies: - '@commitlint/load': 20.1.0(@types/node@22.19.1)(typescript@6.0.3) - transitivePeerDependencies: - - '@types/node' - - typescript - - d3-array@2.12.1: - dependencies: - internmap: 1.0.1 - - d3-color@1.4.1: {} - - d3-color@2.0.0: {} - - d3-dispatch@1.0.6: {} - - d3-drag@1.2.5: - dependencies: - d3-dispatch: 1.0.6 - d3-selection: 1.4.2 - - d3-ease@1.0.7: {} - - d3-fg@6.14.0: - dependencies: - d3-array: 2.12.1 - d3-dispatch: 1.0.6 - d3-ease: 1.0.7 - d3-hierarchy: 1.1.9 - d3-scale: 3.3.0 - d3-selection: 1.4.2 - d3-zoom: 1.8.3 - escape-string-regexp: 1.0.5 - hsl-to-rgb-for-reals: 1.1.1 - - d3-format@2.0.0: {} - - d3-hierarchy@1.1.9: {} - - d3-interpolate@1.4.0: - dependencies: - d3-color: 1.4.1 - - d3-interpolate@2.0.1: + conventional-changelog-angular@8.3.1: dependencies: - d3-color: 2.0.0 + compare-func: 2.0.0 - d3-scale@3.3.0: + conventional-changelog-conventionalcommits@9.3.1: dependencies: - d3-array: 2.12.1 - d3-format: 2.0.0 - d3-interpolate: 2.0.1 - d3-time: 2.1.1 - d3-time-format: 3.0.0 - - d3-selection@1.4.2: {} + compare-func: 2.0.0 - d3-time-format@3.0.0: - dependencies: - d3-time: 2.1.1 + conventional-commit-types@3.0.0: {} - d3-time@2.1.1: + conventional-commits-parser@6.4.0: dependencies: - d3-array: 2.12.1 + '@simple-libs/stream-utils': 1.2.0 + meow: 13.2.0 - d3-timer@1.0.10: {} + convert-source-map@2.0.0: {} - d3-transition@1.3.2: + cosmiconfig-typescript-loader@6.3.0(@types/node@22.19.21)(cosmiconfig@9.0.2)(typescript@4.9.5): dependencies: - d3-color: 1.4.1 - d3-dispatch: 1.0.6 - d3-ease: 1.0.7 - d3-interpolate: 1.4.0 - d3-selection: 1.4.2 - d3-timer: 1.0.10 + '@types/node': 22.19.21 + cosmiconfig: 9.0.2(typescript@4.9.5) + jiti: 2.6.1 + typescript: 4.9.5 - d3-zoom@1.8.3: + cosmiconfig@9.0.2(typescript@4.9.5): dependencies: - d3-dispatch: 1.0.6 - d3-drag: 1.2.5 - d3-interpolate: 1.4.0 - d3-selection: 1.4.2 - d3-transition: 1.3.2 - - dash-ast@1.0.0: {} + env-paths: 2.2.1 + import-fresh: 3.3.1 + js-yaml: 4.2.0 + parse-json: 5.2.0 + optionalDependencies: + typescript: 4.9.5 - debounce@1.2.1: {} + cz-conventional-changelog@3.3.0(@types/node@22.19.21)(typescript@4.9.5): + dependencies: + chalk: 2.4.2 + commitizen: 4.3.1(@types/node@22.19.21)(typescript@4.9.5) + conventional-commit-types: 3.0.0 + lodash.map: 4.6.0 + longest: 2.0.1 + word-wrap: 1.2.5 + optionalDependencies: + '@commitlint/load': 21.0.2(@types/node@22.19.21)(typescript@4.9.5) + transitivePeerDependencies: + - '@types/node' + - typescript debug@4.4.3: dependencies: @@ -6570,74 +4483,32 @@ snapshots: dedent@0.7.0: {} - deepmerge-ts@7.1.5: {} - defaults@1.0.4: dependencies: clone: 1.0.4 - define-data-property@1.1.4: - dependencies: - es-define-property: 1.0.1 - es-errors: 1.3.0 - gopd: 1.2.0 - - define-properties@1.2.1: - dependencies: - define-data-property: 1.1.4 - has-property-descriptors: 1.0.2 - object-keys: 1.1.1 - - defined@1.0.1: {} - defu@6.1.7: {} denque@2.1.0: {} - deps-sort@2.0.1: - dependencies: - JSONStream: 1.3.5 - shasum-object: 1.0.1 - subarg: 1.0.0 - through2: 2.0.5 - - des.js@1.1.0: - dependencies: - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - destr@2.0.5: {} detect-file@1.0.0: {} detect-indent@6.1.0: {} - detective@5.2.1: - dependencies: - acorn-node: 1.8.2 - defined: 1.0.1 - minimist: 1.2.8 - - diff@9.0.0: {} - - diffie-hellman@5.0.3: - dependencies: - bn.js: 4.12.2 - miller-rabin: 4.0.1 - randombytes: 2.1.0 - - discord-api-types@0.38.34: {} + discord-api-types@0.38.48: {} - discord.js@14.26.4(bufferutil@4.1.0): + discord.js@14.26.4: dependencies: '@discordjs/builders': 1.14.1 '@discordjs/collection': 1.5.3 '@discordjs/formatters': 0.6.2 '@discordjs/rest': 2.6.1 '@discordjs/util': 1.2.0 - '@discordjs/ws': 1.2.3(bufferutil@4.1.0) + '@discordjs/ws': 1.2.3 '@sapphire/snowflake': 3.5.3 - discord-api-types: 0.38.34 + discord-api-types: 0.38.48 fast-deep-equal: 3.1.3 lodash.snakecase: 4.1.1 magic-bytes.js: 1.13.0 @@ -6647,8 +4518,6 @@ snapshots: - bufferutil - utf-8-validate - domain-browser@1.2.0: {} - dot-prop@5.3.0: dependencies: is-obj: 2.0.0 @@ -6663,71 +4532,25 @@ snapshots: dts-resolver@3.0.0: {} - dunder-proto@1.0.1: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-errors: 1.3.0 - gopd: 1.2.0 - - duplexer2@0.1.4: - dependencies: - readable-stream: 2.3.8 - - duplexify@4.1.3: - dependencies: - end-of-stream: 1.4.5 - inherits: 2.0.4 - readable-stream: 3.6.2 - stream-shift: 1.0.3 - - effect@3.20.0: - dependencies: - '@standard-schema/spec': 1.1.0 - fast-check: 3.23.2 - - elliptic@6.6.1: - dependencies: - bn.js: 4.12.2 - brorand: 1.1.0 - hash.js: 1.1.7 - hmac-drbg: 1.0.1 - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - minimalistic-crypto-utils: 1.0.1 - emoji-regex@10.6.0: {} emoji-regex@8.0.0: {} - empathic@2.0.0: {} - - end-of-stream@1.4.5: - dependencies: - once: 1.4.0 + empathic@2.0.1: {} env-paths@2.2.1: {} - env-paths@3.0.0: {} - - env-string@1.0.1: {} - environment@1.1.0: {} error-ex@1.3.4: dependencies: is-arrayish: 0.2.1 - es-define-property@1.0.1: {} - es-errors@1.3.0: {} es-module-lexer@2.1.0: {} - es-object-atoms@1.1.1: - dependencies: - es-errors: 1.3.0 - - es-toolkit@1.46.1: {} + es-toolkit@1.47.0: {} esbuild@0.25.12: optionalDependencies: @@ -6762,33 +4585,15 @@ snapshots: escape-string-regexp@1.0.5: {} - escape-string-regexp@4.0.0: {} - - estree-is-member-expression@1.0.0: {} - estree-walker@3.0.3: dependencies: - '@types/estree': 1.0.8 - - eventemitter3@5.0.1: {} - - events@3.3.0: {} + '@types/estree': 1.0.9 - evlog@2.16.0(hono@4.12.12)(ofetch@1.5.1)(react@19.2.5)(vite@7.2.4): - optionalDependencies: - hono: 4.12.12 - ofetch: 1.5.1 - react: 19.2.5 - vite: 7.2.4(@types/node@22.19.1)(jiti@2.6.1)(yaml@2.9.0) + event-target-shim@5.0.1: {} - evp_bytestokey@1.0.3: - dependencies: - md5.js: 1.3.5 - safe-buffer: 5.2.1 + eventemitter3@5.0.4: {} - execspawn@1.0.1: - dependencies: - util-extend: 1.0.3 + events@3.3.0: {} expand-tilde@2.0.2: dependencies: @@ -6796,23 +4601,15 @@ snapshots: expect-type@1.3.0: {} - exsolve@1.0.8: {} - external-editor@3.1.0: dependencies: chardet: 0.7.0 iconv-lite: 0.4.24 tmp: 0.0.33 - fast-check@3.23.2: - dependencies: - pure-rand: 6.1.0 - fast-deep-equal@3.1.3: {} - fast-safe-stringify@2.1.1: {} - - fast-uri@3.1.0: {} + fast-uri@3.1.2: {} fdir@6.5.0(picomatch@4.0.4): optionalDependencies: @@ -6822,6 +4619,12 @@ snapshots: dependencies: escape-string-regexp: 1.0.5 + file-type@18.7.0: + dependencies: + readable-web-to-node-stream: 3.0.4 + strtok3: 7.1.1 + token-types: 5.0.1 + fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 @@ -6833,8 +4636,6 @@ snapshots: find-root@1.1.0: {} - find-up-simple@1.0.1: {} - findup-sync@4.0.0: dependencies: detect-file: 1.0.0 @@ -6842,28 +4643,13 @@ snapshots: micromatch: 4.0.8 resolve-dir: 1.0.1 - for-each@0.3.5: - dependencies: - is-callable: 1.2.7 - - foreground-child@3.3.1: - dependencies: - cross-spawn: 7.0.6 - signal-exit: 4.1.0 - forwarded-parse@2.1.2: {} - fs-extra@10.1.0: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 6.2.0 - universalify: 2.0.1 - fs-extra@9.1.0: dependencies: at-least-node: 1.0.0 graceful-fs: 4.2.11 - jsonfile: 6.2.0 + jsonfile: 6.2.1 universalify: 2.0.1 fs.realpath@1.0.0: {} @@ -6875,44 +4661,14 @@ snapshots: fzf@0.5.2: {} - generate-function@2.3.1: - dependencies: - is-property: 1.0.2 - - generator-function@2.0.1: {} - - get-assigned-identifiers@1.2.0: {} - get-caller-file@2.0.5: {} - get-east-asian-width@1.4.0: {} - - get-intrinsic@1.3.0: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - function-bind: 1.1.2 - get-proto: 1.0.1 - gopd: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.2 - math-intrinsics: 1.1.0 - - get-port-please@3.2.0: {} - - get-proto@1.0.1: - dependencies: - dunder-proto: 1.0.1 - es-object-atoms: 1.1.1 + get-east-asian-width@1.6.0: {} get-tsconfig@5.0.0-beta.5: dependencies: resolve-pkg-maps: 1.0.0 - giget@3.2.0: {} - git-raw-commits@5.0.1(conventional-commits-parser@6.4.0): dependencies: '@conventional-changelog/git-client': 2.7.0(conventional-commits-parser@6.4.0) @@ -6926,15 +4682,10 @@ snapshots: fs.realpath: 1.0.0 inflight: 1.0.6 inherits: 2.0.4 - minimatch: 3.1.2 + minimatch: 3.1.5 once: 1.4.0 path-is-absolute: 1.0.1 - global-directory@4.0.1: - dependencies: - ini: 4.1.1 - optional: true - global-directory@5.0.0: dependencies: ini: 6.0.0 @@ -6953,122 +4704,53 @@ snapshots: is-windows: 1.0.2 which: 1.3.1 - gopd@1.2.0: {} - graceful-fs@4.2.11: {} - grammex@3.1.12: {} - - graphmatch@1.1.1: {} - - has-ansi@2.0.0: + gradient-string@2.0.2: dependencies: - ansi-regex: 5.0.1 + chalk: 4.1.2 + tinygradient: 1.1.5 has-flag@3.0.0: {} has-flag@4.0.0: {} - has-property-descriptors@1.0.2: - dependencies: - es-define-property: 1.0.1 - - has-symbols@1.1.0: {} - - has-tostringtag@1.0.2: - dependencies: - has-symbols: 1.1.0 - - has-unicode@2.0.1: {} - - hash-base@3.0.5: - dependencies: - inherits: 2.0.4 - safe-buffer: 5.2.1 - - hash-base@3.1.2: - dependencies: - inherits: 2.0.4 - readable-stream: 2.3.8 - safe-buffer: 5.2.1 - to-buffer: 1.2.2 - - hash.js@1.1.7: - dependencies: - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - - hasown@2.0.2: + hasown@2.0.4: dependencies: function-bind: 1.1.2 - he@1.2.0: {} - - hmac-drbg@1.0.1: - dependencies: - hash.js: 1.1.7 - minimalistic-assert: 1.0.1 - minimalistic-crypto-utils: 1.0.1 - homedir-polyfill@1.0.3: dependencies: parse-passwd: 1.0.0 - hono@4.12.12: {} - hookable@6.1.1: {} - hsl-to-rgb-for-reals@1.1.1: {} - html-escaper@2.0.2: {} - htmlescape@1.1.1: {} - - http-status-codes@2.3.0: {} - - https-browserify@1.0.0: {} - husky@9.1.7: {} - hyperscript-attribute-to-property@1.0.2: {} - - hyperx@2.5.4: + i18next@22.5.1: dependencies: - hyperscript-attribute-to-property: 1.0.2 - - i18next@25.6.3(typescript@6.0.3): - dependencies: - '@babel/runtime': 7.28.4 - optionalDependencies: - typescript: 6.0.3 + '@babel/runtime': 7.29.7 iconv-lite@0.4.24: dependencies: safer-buffer: 2.1.2 - iconv-lite@0.7.2: - dependencies: - safer-buffer: 2.1.2 - ieee754@1.2.1: {} + immediate@3.0.6: {} + import-fresh@3.3.1: dependencies: parent-module: 1.0.1 resolve-from: 4.0.0 - import-in-the-middle@2.0.6: + import-in-the-middle@1.15.0: dependencies: - acorn: 8.15.0 - acorn-import-attributes: 1.9.5(acorn@8.15.0) - cjs-module-lexer: 2.2.0 - module-details-from-path: 1.0.4 - - import-in-the-middle@3.0.1: - dependencies: - acorn: 8.15.0 - acorn-import-attributes: 1.9.5(acorn@8.15.0) - cjs-module-lexer: 2.2.0 + acorn: 8.17.0 + acorn-import-attributes: 1.9.5(acorn@8.17.0) + cjs-module-lexer: 1.4.3 module-details-from-path: 1.0.4 import-meta-resolve@4.2.0: {} @@ -7080,21 +4762,12 @@ snapshots: once: 1.4.0 wrappy: 1.0.2 - inherits@2.0.3: {} - inherits@2.0.4: {} ini@1.3.8: {} - ini@4.1.1: - optional: true - ini@6.0.0: {} - inline-source-map@0.6.3: - dependencies: - source-map: 0.5.7 - inquirer@8.2.5: dependencies: ansi-escapes: 4.3.2 @@ -7113,59 +4786,31 @@ snapshots: through: 2.3.8 wrap-ansi: 7.0.0 - insert-module-globals@7.2.1: + ioredis@5.11.1: dependencies: - JSONStream: 1.3.5 - acorn-node: 1.8.2 - combine-source-map: 0.8.0 - concat-stream: 1.6.2 - is-buffer: 1.1.6 - path-is-absolute: 1.0.1 - process: 0.11.10 - through2: 2.0.5 - undeclared-identifiers: 1.1.3 - xtend: 4.0.2 - - internmap@1.0.1: {} - - is-arguments@1.2.0: - dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 + '@ioredis/commands': 1.10.0 + cluster-key-slot: 1.1.1 + debug: 4.4.3 + denque: 2.1.0 + redis-errors: 1.2.0 + redis-parser: 3.0.0 + standard-as-callback: 2.1.0 + transitivePeerDependencies: + - supports-color is-arrayish@0.2.1: {} - is-boolean-attribute@0.0.1: {} - - is-buffer@1.1.6: {} - - is-buffer@2.0.5: {} - - is-callable@1.2.7: {} - - is-core-module@2.16.1: + is-core-module@2.16.2: dependencies: - hasown: 2.0.2 + hasown: 2.0.4 is-extglob@2.1.1: {} - is-fullwidth-code-point@1.0.0: - dependencies: - number-is-nan: 1.0.1 - is-fullwidth-code-point@3.0.0: {} is-fullwidth-code-point@5.1.0: dependencies: - get-east-asian-width: 1.4.0 - - is-generator-function@1.1.2: - dependencies: - call-bound: 1.0.4 - generator-function: 2.0.1 - get-proto: 1.0.1 - has-tostringtag: 1.0.2 - safe-regex-test: 1.1.0 + get-east-asian-width: 1.6.0 is-glob@4.0.3: dependencies: @@ -7179,31 +4824,12 @@ snapshots: is-plain-obj@4.1.0: {} - is-property@1.0.2: {} - - is-regex@1.2.1: - dependencies: - call-bound: 1.0.4 - gopd: 1.2.0 - has-tostringtag: 1.0.2 - hasown: 2.0.2 - - is-typed-array@1.1.15: - dependencies: - which-typed-array: 1.1.19 - is-unicode-supported@0.1.0: {} is-utf8@0.2.1: {} is-windows@1.0.2: {} - is-wsl@1.1.0: {} - - isarray@1.0.0: {} - - isarray@2.0.5: {} - isexe@2.0.0: {} istanbul-lib-coverage@3.2.2: {} @@ -7219,13 +4845,18 @@ snapshots: html-escaper: 2.0.2 istanbul-lib-report: 3.0.1 + ix@5.0.0: + dependencies: + '@types/node': 13.13.52 + tslib: 2.8.1 + jiti@2.6.1: {} js-tokens@10.0.0: {} js-tokens@4.0.0: {} - js-yaml@4.1.1: + js-yaml@4.2.0: dependencies: argparse: 2.0.1 @@ -7235,24 +4866,15 @@ snapshots: json-schema-traverse@1.0.0: {} - jsonfile@6.2.0: + jsonfile@6.2.1: dependencies: universalify: 2.0.1 optionalDependencies: graceful-fs: 4.2.11 - jsonparse@1.3.1: {} - - jsonstream2@3.0.0: - dependencies: - jsonparse: 1.3.1 - through2: 3.0.2 - type-component: 0.0.1 - - labeled-stream-splicer@2.0.2: + lie@3.1.1: dependencies: - inherits: 2.0.4 - stream-splicer: 2.0.1 + immediate: 3.0.6 lines-and-columns@1.2.4: {} @@ -7262,38 +4884,30 @@ snapshots: listr2: 9.0.5 picomatch: 4.0.4 string-argv: 0.3.2 - tinyexec: 1.0.4 - yaml: 2.8.2 + tinyexec: 1.2.4 + yaml: 2.9.0 listr2@9.0.5: dependencies: - cli-truncate: 5.1.1 + cli-truncate: 5.2.0 colorette: 2.0.20 - eventemitter3: 5.0.1 + eventemitter3: 5.0.4 log-update: 6.1.0 rfdc: 1.4.1 wrap-ansi: 9.0.2 - lodash.isplainobject@4.0.6: - optional: true + localforage@1.10.0: + dependencies: + lie: 3.1.1 lodash.map@4.6.0: {} - lodash.memoize@3.0.4: {} - - lodash.merge@4.6.2: - optional: true - - lodash.mergewith@4.6.2: - optional: true - lodash.snakecase@4.1.1: {} - lodash.uniq@4.5.0: - optional: true - lodash@4.17.21: {} + lodash@4.18.1: {} + log-symbols@4.1.0: dependencies: chalk: 4.1.2 @@ -7301,201 +4915,66 @@ snapshots: log-update@6.1.0: dependencies: - ansi-escapes: 7.2.0 + ansi-escapes: 7.3.0 cli-cursor: 5.0.0 slice-ansi: 7.1.2 - strip-ansi: 7.1.2 + strip-ansi: 7.2.0 wrap-ansi: 9.0.2 - long@5.3.2: {} - longest@2.0.1: {} - lower-case@1.1.4: {} - - lru.min@1.1.4: {} - - magic-bytes.js@1.12.1: {} - magic-bytes.js@1.13.0: {} - magic-string@0.23.2: - dependencies: - sourcemap-codec: 1.4.8 - magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 - magicast@0.5.2: + magicast@0.5.3: dependencies: - '@babel/parser': 7.29.3 - '@babel/types': 7.29.0 + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 source-map-js: 1.2.1 - make-dir@3.1.0: - dependencies: - semver: 6.3.1 - make-dir@4.0.0: dependencies: - semver: 7.7.4 - - math-intrinsics@1.1.0: {} - - md5.js@1.3.5: - dependencies: - hash-base: 3.1.2 - inherits: 2.0.4 - safe-buffer: 5.2.1 + semver: 7.8.4 meow@13.2.0: {} - merge-source-map@1.0.4: - dependencies: - source-map: 0.5.7 - merge@2.1.1: {} micromatch@4.0.8: dependencies: braces: 3.0.3 - picomatch: 2.3.1 - - miller-rabin@4.0.1: - dependencies: - bn.js: 4.12.2 - brorand: 1.1.0 + picomatch: 2.3.2 mimic-fn@2.1.0: {} mimic-function@5.0.1: {} - minimalistic-assert@1.0.1: {} - - minimalistic-crypto-utils@1.0.1: {} - - minimatch@10.2.5: - dependencies: - brace-expansion: 5.0.5 - - minimatch@3.1.2: + minimatch@3.1.5: dependencies: - brace-expansion: 1.1.12 + brace-expansion: 1.1.15 minimist@1.2.8: {} - mkdirp-classic@0.5.3: {} - - module-deps@6.2.3: - dependencies: - JSONStream: 1.3.5 - browser-resolve: 2.0.0 - cached-path-relative: 1.1.0 - concat-stream: 1.6.2 - defined: 1.0.1 - detective: 5.2.1 - duplexer2: 0.1.4 - inherits: 2.0.4 - parents: 1.0.1 - readable-stream: 2.3.8 - resolve: 1.22.11 - stream-combiner2: 1.1.1 - subarg: 1.0.0 - through2: 2.0.5 - xtend: 4.0.2 - module-details-from-path@1.0.4: {} - morphdom@2.7.7: {} - - ms@2.1.3: {} - - mute-stream@0.0.8: {} - - mutexify@1.4.0: - dependencies: - queue-tick: 1.0.1 - - mysql2@3.15.3: - dependencies: - aws-ssl-profiles: 1.1.2 - denque: 2.1.0 - generate-function: 2.3.1 - iconv-lite: 0.7.2 - long: 5.3.2 - lru.min: 1.1.4 - named-placeholders: 1.1.6 - seq-queue: 0.0.5 - sqlstring: 2.3.3 - - named-placeholders@1.1.6: - dependencies: - lru.min: 1.1.4 - - nan@2.23.1: {} - - nanoassert@1.1.0: {} - - nanobench@2.1.1: - dependencies: - browser-process-hrtime: 0.1.3 - chalk: 1.1.3 - mutexify: 1.4.0 - pretty-hrtime: 1.0.3 - - nanohtml@1.10.0: - dependencies: - acorn-node: 1.8.2 - camel-case: 3.0.0 - convert-source-map: 1.9.0 - estree-is-member-expression: 1.0.0 - hyperx: 2.5.4 - is-boolean-attribute: 0.0.1 - nanoassert: 1.1.0 - nanobench: 2.1.1 - normalize-html-whitespace: 0.2.0 - through2: 2.0.5 - transform-ast: 2.4.4 - - nanoid@3.3.12: {} - - no-case@2.3.2: - dependencies: - lower-case: 1.1.4 - - node-fetch-native@1.6.7: {} - - node-gyp-build@4.8.4: {} - - normalize-html-whitespace@0.2.0: {} - - number-is-nan@1.0.1: {} + ms@2.1.3: {} - object-inspect@1.13.4: {} + mute-stream@0.0.8: {} - object-keys@1.1.1: {} + nanoid@3.3.12: {} - object.assign@4.1.7: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-object-atoms: 1.1.1 - has-symbols: 1.1.0 - object-keys: 1.1.1 + node-fetch-native@1.6.7: {} - obug@2.1.1: {} + obug@2.1.2: {} ofetch@1.5.1: dependencies: destr: 2.0.5 node-fetch-native: 1.6.7 - ufo: 1.6.1 - - ohash@2.0.11: {} - - on-net-listen@1.1.2: {} + ufo: 1.6.4 once@1.4.0: dependencies: @@ -7509,10 +4988,6 @@ snapshots: dependencies: mimic-function: 5.0.1 - opn@5.5.0: - dependencies: - is-wsl: 1.1.0 - ora@5.4.1: dependencies: bl: 4.1.0 @@ -7525,8 +5000,6 @@ snapshots: strip-ansi: 6.0.1 wcwidth: 1.0.1 - os-browserify@0.3.0: {} - os-tmpdir@1.0.2: {} oxfmt@0.51.0: @@ -7553,136 +5026,74 @@ snapshots: '@oxfmt/binding-win32-ia32-msvc': 0.51.0 '@oxfmt/binding-win32-x64-msvc': 0.51.0 - oxlint@1.66.0: + oxlint@1.69.0: optionalDependencies: - '@oxlint/binding-android-arm-eabi': 1.66.0 - '@oxlint/binding-android-arm64': 1.66.0 - '@oxlint/binding-darwin-arm64': 1.66.0 - '@oxlint/binding-darwin-x64': 1.66.0 - '@oxlint/binding-freebsd-x64': 1.66.0 - '@oxlint/binding-linux-arm-gnueabihf': 1.66.0 - '@oxlint/binding-linux-arm-musleabihf': 1.66.0 - '@oxlint/binding-linux-arm64-gnu': 1.66.0 - '@oxlint/binding-linux-arm64-musl': 1.66.0 - '@oxlint/binding-linux-ppc64-gnu': 1.66.0 - '@oxlint/binding-linux-riscv64-gnu': 1.66.0 - '@oxlint/binding-linux-riscv64-musl': 1.66.0 - '@oxlint/binding-linux-s390x-gnu': 1.66.0 - '@oxlint/binding-linux-x64-gnu': 1.66.0 - '@oxlint/binding-linux-x64-musl': 1.66.0 - '@oxlint/binding-openharmony-arm64': 1.66.0 - '@oxlint/binding-win32-arm64-msvc': 1.66.0 - '@oxlint/binding-win32-ia32-msvc': 1.66.0 - '@oxlint/binding-win32-x64-msvc': 1.66.0 + '@oxlint/binding-android-arm-eabi': 1.69.0 + '@oxlint/binding-android-arm64': 1.69.0 + '@oxlint/binding-darwin-arm64': 1.69.0 + '@oxlint/binding-darwin-x64': 1.69.0 + '@oxlint/binding-freebsd-x64': 1.69.0 + '@oxlint/binding-linux-arm-gnueabihf': 1.69.0 + '@oxlint/binding-linux-arm-musleabihf': 1.69.0 + '@oxlint/binding-linux-arm64-gnu': 1.69.0 + '@oxlint/binding-linux-arm64-musl': 1.69.0 + '@oxlint/binding-linux-ppc64-gnu': 1.69.0 + '@oxlint/binding-linux-riscv64-gnu': 1.69.0 + '@oxlint/binding-linux-riscv64-musl': 1.69.0 + '@oxlint/binding-linux-s390x-gnu': 1.69.0 + '@oxlint/binding-linux-x64-gnu': 1.69.0 + '@oxlint/binding-linux-x64-musl': 1.69.0 + '@oxlint/binding-openharmony-arm64': 1.69.0 + '@oxlint/binding-win32-arm64-msvc': 1.69.0 + '@oxlint/binding-win32-ia32-msvc': 1.69.0 + '@oxlint/binding-win32-x64-msvc': 1.69.0 package-manager-detector@1.6.0: {} - pako@1.0.11: {} - parent-module@1.0.1: dependencies: callsites: 3.1.0 - parents@1.0.1: - dependencies: - path-platform: 0.11.15 - - parse-asn1@5.1.9: - dependencies: - asn1.js: 4.10.1 - browserify-aes: 1.2.0 - evp_bytestokey: 1.0.3 - pbkdf2: 3.1.5 - safe-buffer: 5.2.1 - parse-json@5.2.0: dependencies: - '@babel/code-frame': 7.27.1 + '@babel/code-frame': 7.29.7 error-ex: 1.3.4 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 parse-passwd@1.0.0: {} - path-browserify@1.0.1: {} - path-is-absolute@1.0.1: {} - path-key@3.1.1: {} - path-parse@1.0.7: {} - path-platform@0.11.15: {} - pathe@2.0.3: {} - pbkdf2@3.1.5: - dependencies: - create-hash: 1.2.0 - create-hmac: 1.1.7 - ripemd160: 2.0.3 - safe-buffer: 5.2.1 - sha.js: 2.4.12 - to-buffer: 1.2.2 - - perfect-debounce@2.1.0: {} - - pg-cloudflare@1.4.0: - optional: true - - pg-connection-string@2.13.0: {} + peek-readable@5.4.2: {} pg-int8@1.0.1: {} - pg-pool@3.14.0(pg@8.21.0): - dependencies: - pg: 8.21.0 - - pg-protocol@1.13.0: {} - pg-protocol@1.14.0: {} pg-types@2.2.0: dependencies: pg-int8: 1.0.1 postgres-array: 2.0.0 - postgres-bytea: 1.0.0 + postgres-bytea: 1.0.1 postgres-date: 1.0.7 postgres-interval: 1.2.0 - pg@8.21.0: - dependencies: - pg-connection-string: 2.13.0 - pg-pool: 3.14.0(pg@8.21.0) - pg-protocol: 1.14.0 - pg-types: 2.2.0 - pgpass: 1.0.5 - optionalDependencies: - pg-cloudflare: 1.4.0 - - pgpass@1.0.5: - dependencies: - split2: 4.2.0 - picocolors@1.1.1: {} - picomatch@2.3.1: {} + picomatch@2.3.2: {} picomatch@4.0.4: {} - pkg-types@2.3.0: - dependencies: - confbox: 0.2.4 - exsolve: 1.0.8 - pathe: 2.0.3 - - pnpm-workspace-yaml@1.6.0: + pnpm-workspace-yaml@1.6.1: dependencies: yaml: 2.9.0 - possible-typed-array-names@1.1.0: {} - - postcss@8.5.14: + postcss@8.5.15: dependencies: nanoid: 3.3.12 picocolors: 1.1.1 @@ -7690,9 +5101,7 @@ snapshots: postgres-array@2.0.0: {} - postgres-array@3.0.4: {} - - postgres-bytea@1.0.0: {} + postgres-bytea@1.0.1: {} postgres-date@1.0.7: {} @@ -7700,138 +5109,49 @@ snapshots: dependencies: xtend: 4.0.2 - postgres@3.4.7: {} + prettier@3.8.4: {} - prettier@3.8.3: {} - - pretty-hrtime@1.0.3: {} - - prisma-json-types-generator@5.0.0(@prisma/client@7.8.0)(prisma@7.8.0)(typescript@6.0.3): - dependencies: - '@prisma/client': 7.8.0(prisma@7.8.0)(typescript@6.0.3) - '@prisma/generator-helper': 7.8.0 - prisma: 7.8.0(@types/react@19.2.14)(magicast@0.5.2)(react-dom@19.2.5)(react@19.2.5)(typescript@6.0.3) - semver: 7.7.4 - try: 1.0.3 - tslib: 2.8.1 - typescript: 6.0.3 - - prisma@7.8.0(@types/react@19.2.14)(magicast@0.5.2)(react-dom@19.2.5)(react@19.2.5)(typescript@6.0.3): + prisma@4.16.2: dependencies: - '@prisma/config': 7.8.0(magicast@0.5.2) - '@prisma/dev': 0.24.3(typescript@6.0.3) - '@prisma/engines': 7.8.0 - '@prisma/studio-core': 0.27.3(@types/react@19.2.14)(react-dom@19.2.5)(react@19.2.5) - mysql2: 3.15.3 - postgres: 3.4.7 - optionalDependencies: - typescript: 6.0.3 - transitivePeerDependencies: - - '@types/react' - - '@types/react-dom' - - magicast - - react - - react-dom - - process-nextick-args@2.0.1: {} + '@prisma/engines': 4.16.2 process@0.11.10: {} - proper-lockfile@4.1.2: - dependencies: - graceful-fs: 4.2.11 - retry: 0.12.0 - signal-exit: 3.0.7 - - public-encrypt@4.0.3: - dependencies: - bn.js: 4.12.2 - browserify-rsa: 4.1.1 - create-hash: 1.2.0 - parse-asn1: 5.1.9 - randombytes: 2.1.0 - safe-buffer: 5.2.1 - - pump@3.0.3: - dependencies: - end-of-stream: 1.4.5 - once: 1.4.0 - - pumpify@2.0.1: - dependencies: - duplexify: 4.1.3 - inherits: 2.0.4 - pump: 3.0.3 - - punycode@1.4.1: {} - - pure-rand@6.1.0: {} - - qs@6.14.0: - dependencies: - side-channel: 1.1.0 - quansync@1.0.0: {} - querystring-es3@0.2.1: {} - - queue-tick@1.0.1: {} - - randombytes@2.1.0: - dependencies: - safe-buffer: 5.2.1 - - randomfill@1.0.4: - dependencies: - randombytes: 2.1.0 - safe-buffer: 5.2.1 - - rc9@3.0.1: - dependencies: - defu: 6.1.7 - destr: 2.0.5 - - react-dom@19.2.5(react@19.2.5): - dependencies: - react: 19.2.5 - scheduler: 0.27.0 - - react@19.2.5: {} - - read-only-stream@2.0.0: - dependencies: - readable-stream: 2.3.8 - - readable-stream@2.3.8: + readable-stream@3.6.2: dependencies: - core-util-is: 1.0.3 inherits: 2.0.4 - isarray: 1.0.0 - process-nextick-args: 2.0.1 - safe-buffer: 5.1.2 - string_decoder: 1.1.1 + string_decoder: 1.3.0 util-deprecate: 1.0.2 - readable-stream@3.6.2: + readable-stream@4.7.0: dependencies: - inherits: 2.0.4 + abort-controller: 3.0.0 + buffer: 6.0.3 + events: 3.3.0 + process: 0.11.10 string_decoder: 1.3.0 - util-deprecate: 1.0.2 - readdirp@4.1.2: {} + readable-web-to-node-stream@3.0.4: + dependencies: + readable-stream: 4.7.0 - readdirp@5.0.0: {} + redis-errors@1.2.0: {} - remeda@2.33.4: {} + redis-parser@3.0.0: + dependencies: + redis-errors: 1.2.0 require-directory@2.1.1: {} require-from-string@2.0.2: {} - require-in-the-middle@8.0.1: + require-in-the-middle@7.5.2: dependencies: debug: 4.4.3 module-details-from-path: 1.0.4 + resolve: 1.22.12 transitivePeerDependencies: - supports-color @@ -7846,9 +5166,10 @@ snapshots: resolve-pkg-maps@1.0.0: {} - resolve@1.22.11: + resolve@1.22.12: dependencies: - is-core-module: 2.16.1 + es-errors: 1.3.0 + is-core-module: 2.16.2 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 @@ -7862,103 +5183,90 @@ snapshots: onetime: 7.0.0 signal-exit: 4.1.0 - retry@0.12.0: {} - rfdc@1.4.1: {} - ripemd160@2.0.3: - dependencies: - hash-base: 3.1.2 - inherits: 2.0.4 - - rolldown-plugin-dts@0.25.1(rolldown@1.0.2)(typescript@6.0.3): + rolldown-plugin-dts@0.25.2(rolldown@1.1.1)(typescript@4.9.5): dependencies: - '@babel/generator': 8.0.0-rc.5 - '@babel/helper-validator-identifier': 8.0.0-rc.5 - '@babel/parser': 8.0.0-rc.4 + '@babel/generator': 8.0.0-rc.6 + '@babel/helper-validator-identifier': 8.0.0-rc.6 + '@babel/parser': 8.0.0-rc.6 ast-kit: 3.0.0-beta.1 birpc: 4.0.0 dts-resolver: 3.0.0 get-tsconfig: 5.0.0-beta.5 - obug: 2.1.1 - rolldown: 1.0.2 + obug: 2.1.2 + rolldown: 1.1.1 optionalDependencies: - typescript: 6.0.3 + typescript: 4.9.5 transitivePeerDependencies: - oxc-resolver - rolldown@1.0.0-rc.17: + rolldown-plugin-dts@0.25.2(rolldown@1.1.1)(typescript@6.0.3): dependencies: - '@oxc-project/types': 0.127.0 - '@rolldown/pluginutils': 1.0.0-rc.17 + '@babel/generator': 8.0.0-rc.6 + '@babel/helper-validator-identifier': 8.0.0-rc.6 + '@babel/parser': 8.0.0-rc.6 + ast-kit: 3.0.0-beta.1 + birpc: 4.0.0 + dts-resolver: 3.0.0 + get-tsconfig: 5.0.0-beta.5 + obug: 2.1.2 + rolldown: 1.1.1 optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.0-rc.17 - '@rolldown/binding-darwin-arm64': 1.0.0-rc.17 - '@rolldown/binding-darwin-x64': 1.0.0-rc.17 - '@rolldown/binding-freebsd-x64': 1.0.0-rc.17 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.17 - '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.17 - '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.17 - '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.17 - '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.17 - '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.17 - '@rolldown/binding-linux-x64-musl': 1.0.0-rc.17 - '@rolldown/binding-openharmony-arm64': 1.0.0-rc.17 - '@rolldown/binding-wasm32-wasi': 1.0.0-rc.17 - '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.17 - '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.17 - optional: true + typescript: 6.0.3 + transitivePeerDependencies: + - oxc-resolver - rolldown@1.0.2: + rolldown@1.1.1: dependencies: - '@oxc-project/types': 0.132.0 + '@oxc-project/types': 0.135.0 '@rolldown/pluginutils': 1.0.1 optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.2 - '@rolldown/binding-darwin-arm64': 1.0.2 - '@rolldown/binding-darwin-x64': 1.0.2 - '@rolldown/binding-freebsd-x64': 1.0.2 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.2 - '@rolldown/binding-linux-arm64-gnu': 1.0.2 - '@rolldown/binding-linux-arm64-musl': 1.0.2 - '@rolldown/binding-linux-ppc64-gnu': 1.0.2 - '@rolldown/binding-linux-s390x-gnu': 1.0.2 - '@rolldown/binding-linux-x64-gnu': 1.0.2 - '@rolldown/binding-linux-x64-musl': 1.0.2 - '@rolldown/binding-openharmony-arm64': 1.0.2 - '@rolldown/binding-wasm32-wasi': 1.0.2 - '@rolldown/binding-win32-arm64-msvc': 1.0.2 - '@rolldown/binding-win32-x64-msvc': 1.0.2 - - rollup@4.60.3: - dependencies: - '@types/estree': 1.0.8 + '@rolldown/binding-android-arm64': 1.1.1 + '@rolldown/binding-darwin-arm64': 1.1.1 + '@rolldown/binding-darwin-x64': 1.1.1 + '@rolldown/binding-freebsd-x64': 1.1.1 + '@rolldown/binding-linux-arm-gnueabihf': 1.1.1 + '@rolldown/binding-linux-arm64-gnu': 1.1.1 + '@rolldown/binding-linux-arm64-musl': 1.1.1 + '@rolldown/binding-linux-ppc64-gnu': 1.1.1 + '@rolldown/binding-linux-s390x-gnu': 1.1.1 + '@rolldown/binding-linux-x64-gnu': 1.1.1 + '@rolldown/binding-linux-x64-musl': 1.1.1 + '@rolldown/binding-openharmony-arm64': 1.1.1 + '@rolldown/binding-wasm32-wasi': 1.1.1 + '@rolldown/binding-win32-arm64-msvc': 1.1.1 + '@rolldown/binding-win32-x64-msvc': 1.1.1 + + rollup@4.61.1: + dependencies: + '@types/estree': 1.0.9 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.60.3 - '@rollup/rollup-android-arm64': 4.60.3 - '@rollup/rollup-darwin-arm64': 4.60.3 - '@rollup/rollup-darwin-x64': 4.60.3 - '@rollup/rollup-freebsd-arm64': 4.60.3 - '@rollup/rollup-freebsd-x64': 4.60.3 - '@rollup/rollup-linux-arm-gnueabihf': 4.60.3 - '@rollup/rollup-linux-arm-musleabihf': 4.60.3 - '@rollup/rollup-linux-arm64-gnu': 4.60.3 - '@rollup/rollup-linux-arm64-musl': 4.60.3 - '@rollup/rollup-linux-loong64-gnu': 4.60.3 - '@rollup/rollup-linux-loong64-musl': 4.60.3 - '@rollup/rollup-linux-ppc64-gnu': 4.60.3 - '@rollup/rollup-linux-ppc64-musl': 4.60.3 - '@rollup/rollup-linux-riscv64-gnu': 4.60.3 - '@rollup/rollup-linux-riscv64-musl': 4.60.3 - '@rollup/rollup-linux-s390x-gnu': 4.60.3 - '@rollup/rollup-linux-x64-gnu': 4.60.3 - '@rollup/rollup-linux-x64-musl': 4.60.3 - '@rollup/rollup-openbsd-x64': 4.60.3 - '@rollup/rollup-openharmony-arm64': 4.60.3 - '@rollup/rollup-win32-arm64-msvc': 4.60.3 - '@rollup/rollup-win32-ia32-msvc': 4.60.3 - '@rollup/rollup-win32-x64-gnu': 4.60.3 - '@rollup/rollup-win32-x64-msvc': 4.60.3 + '@rollup/rollup-android-arm-eabi': 4.61.1 + '@rollup/rollup-android-arm64': 4.61.1 + '@rollup/rollup-darwin-arm64': 4.61.1 + '@rollup/rollup-darwin-x64': 4.61.1 + '@rollup/rollup-freebsd-arm64': 4.61.1 + '@rollup/rollup-freebsd-x64': 4.61.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.61.1 + '@rollup/rollup-linux-arm-musleabihf': 4.61.1 + '@rollup/rollup-linux-arm64-gnu': 4.61.1 + '@rollup/rollup-linux-arm64-musl': 4.61.1 + '@rollup/rollup-linux-loong64-gnu': 4.61.1 + '@rollup/rollup-linux-loong64-musl': 4.61.1 + '@rollup/rollup-linux-ppc64-gnu': 4.61.1 + '@rollup/rollup-linux-ppc64-musl': 4.61.1 + '@rollup/rollup-linux-riscv64-gnu': 4.61.1 + '@rollup/rollup-linux-riscv64-musl': 4.61.1 + '@rollup/rollup-linux-s390x-gnu': 4.61.1 + '@rollup/rollup-linux-x64-gnu': 4.61.1 + '@rollup/rollup-linux-x64-musl': 4.61.1 + '@rollup/rollup-openbsd-x64': 4.61.1 + '@rollup/rollup-openharmony-arm64': 4.61.1 + '@rollup/rollup-win32-arm64-msvc': 4.61.1 + '@rollup/rollup-win32-ia32-msvc': 4.61.1 + '@rollup/rollup-win32-x64-gnu': 4.61.1 + '@rollup/rollup-win32-x64-msvc': 4.61.1 fsevents: 2.3.3 run-async@2.4.1: {} @@ -7967,82 +5275,13 @@ snapshots: dependencies: tslib: 2.8.1 - safe-buffer@5.1.2: {} - safe-buffer@5.2.1: {} - safe-regex-test@1.1.0: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-regex: 1.2.1 - safer-buffer@2.1.2: {} - scheduler@0.27.0: {} - - semver@6.3.1: {} - - semver@7.7.3: {} - - semver@7.7.4: {} - - seq-queue@0.0.5: {} - - set-function-length@1.2.2: - dependencies: - define-data-property: 1.1.4 - es-errors: 1.3.0 - function-bind: 1.1.2 - get-intrinsic: 1.3.0 - gopd: 1.2.0 - has-property-descriptors: 1.0.2 - - sha.js@2.4.12: - dependencies: - inherits: 2.0.4 - safe-buffer: 5.2.1 - to-buffer: 1.2.2 - - shasum-object@1.0.1: - dependencies: - fast-safe-stringify: 2.1.1 - - shebang-command@2.0.0: - dependencies: - shebang-regex: 3.0.0 - - shebang-regex@3.0.0: {} + semver@7.8.4: {} - shell-quote@1.8.3: {} - - side-channel-list@1.0.0: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - - side-channel-map@1.0.1: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - - side-channel-weakmap@1.0.2: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - side-channel-map: 1.0.1 - - side-channel@1.1.0: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - side-channel-list: 1.0.0 - side-channel-map: 1.0.1 - side-channel-weakmap: 1.0.2 + shimmer@1.2.1: {} siginfo@2.0.0: {} @@ -8050,65 +5289,26 @@ snapshots: signal-exit@4.1.0: {} - simple-concat@1.0.1: {} - - single-line-log@1.1.2: + slice-ansi@7.1.2: dependencies: - string-width: 1.0.2 + ansi-styles: 6.2.3 + is-fullwidth-code-point: 5.1.0 - slice-ansi@7.1.2: + slice-ansi@8.0.0: dependencies: ansi-styles: 6.2.3 is-fullwidth-code-point: 5.1.0 source-map-js@1.2.1: {} - source-map@0.5.7: {} - - sourcemap-codec@1.4.8: {} - - split2@4.2.0: {} - - sqlstring@2.3.3: {} - stackback@0.0.2: {} - std-env@3.10.0: {} + standard-as-callback@2.1.0: {} std-env@4.1.0: {} - stream-browserify@3.0.0: - dependencies: - inherits: 2.0.4 - readable-stream: 3.6.2 - - stream-combiner2@1.1.1: - dependencies: - duplexer2: 0.1.4 - readable-stream: 2.3.8 - - stream-http@3.2.0: - dependencies: - builtin-status-codes: 3.0.0 - inherits: 2.0.4 - readable-stream: 3.6.2 - xtend: 4.0.2 - - stream-shift@1.0.3: {} - - stream-splicer@2.0.1: - dependencies: - inherits: 2.0.4 - readable-stream: 2.3.8 - string-argv@0.3.2: {} - string-width@1.0.2: - dependencies: - code-point-at: 1.1.0 - is-fullwidth-code-point: 1.0.0 - strip-ansi: 3.0.1 - string-width@4.2.3: dependencies: emoji-regex: 8.0.0 @@ -8118,31 +5318,23 @@ snapshots: string-width@7.2.0: dependencies: emoji-regex: 10.6.0 - get-east-asian-width: 1.4.0 - strip-ansi: 7.1.2 - - string-width@8.1.0: - dependencies: - get-east-asian-width: 1.4.0 - strip-ansi: 7.1.2 + get-east-asian-width: 1.6.0 + strip-ansi: 7.2.0 - string_decoder@1.1.1: + string-width@8.2.1: dependencies: - safe-buffer: 5.1.2 + get-east-asian-width: 1.6.0 + strip-ansi: 7.2.0 string_decoder@1.3.0: dependencies: safe-buffer: 5.2.1 - strip-ansi@3.0.1: - dependencies: - ansi-regex: 5.0.1 - strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 - strip-ansi@7.1.2: + strip-ansi@7.2.0: dependencies: ansi-regex: 5.0.1 @@ -8150,11 +5342,10 @@ snapshots: strip-json-comments@3.1.1: {} - subarg@1.0.0: + strtok3@7.1.1: dependencies: - minimist: 1.2.8 - - supports-color@2.0.0: {} + '@tokenizer/token': 0.3.0 + peek-readable: 5.4.2 supports-color@5.5.0: dependencies: @@ -8166,124 +5357,104 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - synckit@0.11.11: - dependencies: - '@pkgr/core': 0.2.9 - optional: true - - syntax-error@1.4.0: - dependencies: - acorn-node: 1.8.2 - - tachyons@4.12.0: {} - - taze@19.13.0: + taze@19.14.1: dependencies: '@antfu/ni': 30.1.0 '@henrygd/queue': 1.2.0 cac: 7.0.0 - find-up-simple: 1.0.1 ofetch: 1.5.1 package-manager-detector: 1.6.0 pathe: 2.0.3 - pnpm-workspace-yaml: 1.6.0 + pnpm-workspace-yaml: 1.6.1 restore-cursor: 5.1.0 - tinyexec: 1.1.2 - tinyglobby: 0.2.16 + tinyexec: 1.2.4 + tinyglobby: 0.2.17 unconfig: 7.5.0 yaml: 2.9.0 - through2@2.0.5: - dependencies: - readable-stream: 2.3.8 - xtend: 4.0.2 - - through2@3.0.2: - dependencies: - inherits: 2.0.4 - readable-stream: 3.6.2 - - through2@4.0.2: - dependencies: - readable-stream: 3.6.2 - through@2.3.8: {} - timers-browserify@1.4.2: - dependencies: - process: 0.11.10 - tinybench@2.9.0: {} - tinyexec@1.0.4: {} + tinycolor2@1.6.0: {} - tinyexec@1.1.2: {} + tinyexec@1.2.4: {} - tinyglobby@0.2.16: + tinyglobby@0.2.17: dependencies: fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 + tinygradient@1.1.5: + dependencies: + '@types/tinycolor2': 1.4.6 + tinycolor2: 1.6.0 + tinypool@2.1.0: {} tinyrainbow@3.1.0: {} - tldts-core@7.0.17: {} - - tldts@7.0.17: - dependencies: - tldts-core: 7.0.17 - tmp@0.0.33: dependencies: os-tmpdir: 1.0.2 - to-buffer@1.2.2: - dependencies: - isarray: 2.0.5 - safe-buffer: 5.2.1 - typed-array-buffer: 1.0.3 - to-regex-range@5.0.1: dependencies: is-number: 7.0.0 - transform-ast@2.4.4: + token-types@5.0.1: dependencies: - acorn-node: 1.8.2 - convert-source-map: 1.9.0 - dash-ast: 1.0.0 - is-buffer: 2.0.5 - magic-string: 0.23.2 - merge-source-map: 1.0.4 - nanobench: 2.1.1 + '@tokenizer/token': 0.3.0 + ieee754: 1.2.1 tree-kill@1.2.2: {} - try@1.0.3: {} - ts-mixer@6.0.4: {} - tsdown@0.22.0(typescript@6.0.3)(unrun@0.2.37): + tsdown@0.22.2(typescript@4.9.5): + dependencies: + ansis: 4.3.1 + cac: 7.0.0 + defu: 6.1.7 + empathic: 2.0.1 + hookable: 6.1.1 + import-without-cache: 0.4.0 + obug: 2.1.2 + picomatch: 4.0.4 + rolldown: 1.1.1 + rolldown-plugin-dts: 0.25.2(rolldown@1.1.1)(typescript@4.9.5) + semver: 7.8.4 + tinyexec: 1.2.4 + tinyglobby: 0.2.17 + tree-kill: 1.2.2 + unconfig-core: 7.5.0 + optionalDependencies: + typescript: 4.9.5 + transitivePeerDependencies: + - '@ts-macro/tsc' + - '@typescript/native-preview' + - oxc-resolver + - vue-tsc + + tsdown@0.22.2(typescript@6.0.3): dependencies: - ansis: 4.2.0 + ansis: 4.3.1 cac: 7.0.0 defu: 6.1.7 - empathic: 2.0.0 + empathic: 2.0.1 hookable: 6.1.1 import-without-cache: 0.4.0 - obug: 2.1.1 + obug: 2.1.2 picomatch: 4.0.4 - rolldown: 1.0.2 - rolldown-plugin-dts: 0.25.1(rolldown@1.0.2)(typescript@6.0.3) - semver: 7.7.4 - tinyexec: 1.1.2 - tinyglobby: 0.2.16 + rolldown: 1.1.1 + rolldown-plugin-dts: 0.25.2(rolldown@1.1.1)(typescript@6.0.3) + semver: 7.8.4 + tinyexec: 1.2.4 + tinyglobby: 0.2.17 tree-kill: 1.2.2 unconfig-core: 7.5.0 optionalDependencies: typescript: 6.0.3 - unrun: 0.2.37(synckit@0.11.11) transitivePeerDependencies: - '@ts-macro/tsc' - '@typescript/native-preview' @@ -8292,27 +5463,15 @@ snapshots: tslib@2.8.1: {} - tty-browserify@0.0.1: {} - - type-component@0.0.1: {} - type-fest@0.21.3: {} - typed-array-buffer@1.0.3: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-typed-array: 1.1.15 - - typedarray@0.0.6: {} + typescript@4.9.5: {} typescript@5.4.5: {} typescript@6.0.3: {} - ufo@1.6.1: {} - - umd@3.0.3: {} + ufo@1.6.4: {} unconfig-core@7.5.0: dependencies: @@ -8327,125 +5486,69 @@ snapshots: quansync: 1.0.0 unconfig-core: 7.5.0 - undeclared-identifiers@1.1.3: - dependencies: - acorn-node: 1.8.2 - dash-ast: 1.0.0 - get-assigned-identifiers: 1.2.0 - simple-concat: 1.0.1 - xtend: 4.0.2 - undici-types@6.21.0: {} - undici@6.21.3: {} + undici@5.29.0: + dependencies: + '@fastify/busboy': 2.1.1 undici@6.24.1: {} - undici@7.16.0: {} - universalify@2.0.1: {} - unrun@0.2.37(synckit@0.11.11): - dependencies: - rolldown: 1.0.0-rc.17 - optionalDependencies: - synckit: 0.11.11 - optional: true - - upper-case@1.1.3: {} - - url@0.11.4: - dependencies: - punycode: 1.4.1 - qs: 6.14.0 - util-deprecate@1.0.2: {} - util-extend@1.0.3: {} - - util@0.10.4: - dependencies: - inherits: 2.0.3 - - util@0.12.5: - dependencies: - inherits: 2.0.4 - is-arguments: 1.2.0 - is-generator-function: 1.1.2 - is-typed-array: 1.1.15 - which-typed-array: 1.1.19 - - valibot@1.2.0(typescript@6.0.3): - optionalDependencies: - typescript: 6.0.3 - - vite@7.2.4(@types/node@22.19.1)(jiti@2.6.1)(yaml@2.9.0): + vite@6.4.3(@types/node@22.19.21)(jiti@2.6.1)(yaml@2.9.0): dependencies: esbuild: 0.25.12 fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 - postcss: 8.5.14 - rollup: 4.60.3 - tinyglobby: 0.2.16 + postcss: 8.5.15 + rollup: 4.61.1 + tinyglobby: 0.2.17 optionalDependencies: - '@types/node': 22.19.1 + '@types/node': 22.19.21 fsevents: 2.3.3 jiti: 2.6.1 yaml: 2.9.0 - vitest@4.1.7(@opentelemetry/api@1.9.1)(@types/node@22.19.1)(@vitest/coverage-v8@4.1.7)(vite@7.2.4): + vitest@4.1.8(@opentelemetry/api@1.9.1)(@types/node@22.19.21)(@vitest/coverage-v8@4.1.8)(vite@6.4.3): dependencies: - '@vitest/expect': 4.1.7 - '@vitest/mocker': 4.1.7(vite@7.2.4) - '@vitest/pretty-format': 4.1.7 - '@vitest/runner': 4.1.7 - '@vitest/snapshot': 4.1.7 - '@vitest/spy': 4.1.7 - '@vitest/utils': 4.1.7 + '@vitest/expect': 4.1.8 + '@vitest/mocker': 4.1.8(vite@6.4.3) + '@vitest/pretty-format': 4.1.8 + '@vitest/runner': 4.1.8 + '@vitest/snapshot': 4.1.8 + '@vitest/spy': 4.1.8 + '@vitest/utils': 4.1.8 es-module-lexer: 2.1.0 expect-type: 1.3.0 magic-string: 0.30.21 - obug: 2.1.1 + obug: 2.1.2 pathe: 2.0.3 picomatch: 4.0.4 std-env: 4.1.0 tinybench: 2.9.0 - tinyexec: 1.1.2 - tinyglobby: 0.2.16 + tinyexec: 1.2.4 + tinyglobby: 0.2.17 tinyrainbow: 3.1.0 - vite: 7.2.4(@types/node@22.19.1)(jiti@2.6.1)(yaml@2.9.0) + vite: 6.4.3(@types/node@22.19.21)(jiti@2.6.1)(yaml@2.9.0) why-is-node-running: 2.3.0 optionalDependencies: '@opentelemetry/api': 1.9.1 - '@types/node': 22.19.1 - '@vitest/coverage-v8': 4.1.7(vitest@4.1.7) + '@types/node': 22.19.21 + '@vitest/coverage-v8': 4.1.8(vitest@4.1.8) transitivePeerDependencies: - msw - vm-browserify@1.1.2: {} - wcwidth@1.0.1: dependencies: defaults: 1.0.4 - which-typed-array@1.1.19: - dependencies: - available-typed-arrays: 1.0.7 - call-bind: 1.0.8 - call-bound: 1.0.4 - for-each: 0.3.5 - get-proto: 1.0.1 - gopd: 1.2.0 - has-tostringtag: 1.0.2 - which@1.3.1: dependencies: isexe: 2.0.0 - which@2.0.2: - dependencies: - isexe: 2.0.0 - why-is-node-running@2.3.0: dependencies: siginfo: 2.0.0 @@ -8463,20 +5566,16 @@ snapshots: dependencies: ansi-styles: 6.2.3 string-width: 7.2.0 - strip-ansi: 7.1.2 + strip-ansi: 7.2.0 wrappy@1.0.2: {} - ws@8.18.3(bufferutil@4.1.0): - optionalDependencies: - bufferutil: 4.1.0 + ws@8.21.0: {} xtend@4.0.2: {} y18n@5.0.8: {} - yaml@2.8.2: {} - yaml@2.9.0: {} yargs-parser@21.1.1: {} @@ -8490,12 +5589,3 @@ snapshots: string-width: 4.2.3 y18n: 5.0.8 yargs-parser: 21.1.1 - - zeptomatch@2.1.0: - dependencies: - grammex: 3.1.12 - graphmatch: 1.1.1 - - zlib-sync@0.1.10: - dependencies: - nan: 2.23.1 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 28ea15518..da4af6852 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,3 +1,6 @@ +packages: + - 'projects/*' + ignoredBuiltDependencies: - bufferutil - zlib-sync @@ -5,16 +8,13 @@ ignoredBuiltDependencies: onlyBuiltDependencies: - '@prisma/client' - '@prisma/engines' - - '@tailwindcss/oxide' - prisma - - sharp@0.34.5 - - workerd - - better-sqlite3 overrides: ansi-regex: ^5.0.1 discord-api-types: ^0.38.34 - minimist: ^1.2.8 + minimist: ^1.2.6 + vite: ^6.3.5 dedupePeers: true diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 3af4944f0..a5241a17f 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -1,11 +1,5 @@ generator client { - provider = "prisma-client" - output = "../src/generated/prisma" -} - -generator json { - provider = "prisma-json-types-generator" - output = "../src/generated/prisma" + provider = "prisma-client-js" } datasource db { @@ -13,263 +7,572 @@ datasource db { } model Guild { - id String @id(map: "PK_e7e7f2a51bd6d96a9ac2aa560f9") @db.VarChar(19) - prefix String @db.VarChar(10) - language String @default("en-US") @db.VarChar - disableNaturalPrefix Boolean @default(false) @map("disable-natural-prefix") - disabledCommands String[] @default([]) @map("disabled-commands") @db.VarChar(32) - /// [PermissionNodeEntries] - permissionsUsers Json @default("[]") @map("permissions.users") - /// [PermissionNodeEntries] - permissionsRoles Json @default("[]") @map("permissions.roles") - channelsMediaOnly String[] @default([]) @map("channels.media-only") @db.VarChar(19) - channelsLogsModeration String? @map("channels.logs.moderation") @db.VarChar(19) - channelsLogsImage String? @map("channels.logs.image") @db.VarChar(19) - channelsLogsMemberAdd String? @map("channels.logs.member-add") @db.VarChar(19) - channelsLogsMemberRemove String? @map("channels.logs.member-remove") @db.VarChar(19) - channelsLogsMemberNicknameUpdate String? @map("channels.logs.member-nickname-update") @db.VarChar(19) - channelsLogsMemberUsernameUpdate String? @map("channels.logs.member-username-update") @db.VarChar(19) - channelsLogsMemberRolesUpdate String? @map("channels.logs.member-roles-update") @db.VarChar(19) - channelsLogsMessageDelete String? @map("channels.logs.message-delete") @db.VarChar(19) - channelsLogsMessageDeleteNsfw String? @map("channels.logs.message-delete-nsfw") @db.VarChar(19) - channelsLogsMessageUpdate String? @map("channels.logs.message-update") @db.VarChar(19) - channelsLogsMessageUpdateNsfw String? @map("channels.logs.message-update-nsfw") @db.VarChar(19) - channelsLogsPrune String? @map("channels.logs.prune") @db.VarChar(19) - channelsLogsReaction String? @map("channels.logs.reaction") @db.VarChar(19) - channelsLogsRoleCreate String? @map("channels.logs.role-create") @db.VarChar(19) - channelsLogsRoleUpdate String? @map("channels.logs.role-update") @db.VarChar(19) - channelsLogsRoleDelete String? @map("channels.logs.role-delete") @db.VarChar(19) - channelsLogsChannelCreate String? @map("channels.logs.channel-create") @db.VarChar(19) - channelsLogsChannelUpdate String? @map("channels.logs.channel-update") @db.VarChar(19) - channelsLogsChannelDelete String? @map("channels.logs.channel-delete") @db.VarChar(19) - channelsLogsEmojiCreate String? @map("channels.logs.emoji-create") @db.VarChar(19) - channelsLogsEmojiUpdate String? @map("channels.logs.emoji-update") @db.VarChar(19) - channelsLogsEmojiDelete String? @map("channels.logs.emoji-delete") @db.VarChar(19) - channelsLogsServerUpdate String? @map("channels.logs.server-update") @db.VarChar(19) - channelsLogsVoiceChannel String? @map("channels.logs.voice-activity") @db.VarChar(19) - channelsLogsCommand String? @map("channels.logs.command") @db.VarChar(19) - channelsLogsSettings String? @map("channels.logs.settings") @db.VarChar(19) - channelsIgnoreAll String[] @default([]) @map("channels.ignore.all") @db.VarChar(19) - channelsIgnoreMessageEdit String[] @default([]) @map("channels.ignore.message-edit") @db.VarChar(19) - channelsIgnoreMessageDelete String[] @default([]) @map("channels.ignore.message-delete") @db.VarChar(19) - channelsIgnoreReactionAdd String[] @default([]) @map("channels.ignore.reaction-add") @db.VarChar(19) - /// [CommandAutoDeleteEntries] - commandAutoDelete Json @default("[]") @map("command-auto-delete") - disabledChannels String[] @default([]) @map("disabled-channels") @db.VarChar(19) - /// [DisabledCommandChannelEntries] - disabledCommandsChannels Json @default("[]") @map("disabled-commands-channels") - eventsBanAdd Boolean @default(false) @map("events.ban-add") - eventsBanRemove Boolean @default(false) @map("events.ban-remove") - eventsTwemojiReactions Boolean @default(false) @map("events.twemoji-reactions") - messagesIgnoreChannels String[] @default([]) @map("messages.ignore-channels") @db.VarChar(19) - messagesModerationDm Boolean @default(false) @map("messages.moderation-dm") - messagesModerationReasonDisplay Boolean @default(true) @map("messages.moderation-reason-display") - messagesModerationMessageDisplay Boolean @default(true) @map("messages.moderation-message-display") - messagesModerationAutoDelete Boolean @default(false) @map("messages.moderation-auto-delete") - messagesModeratorNameDisplay Boolean @default(true) @map("messages.moderator-name-display") - messagesAutoDeleteIgnoredAll Boolean @default(false) @map("messages.auto-delete.ignored-all") - messagesAutoDeleteIgnoredRoles String[] @default([]) @map("messages.auto-delete.ignored-roles") @db.VarChar(19) - messagesAutoDeleteIgnoredChannels String[] @default([]) @map("messages.auto-delete.ignored-channels") @db.VarChar(19) - messagesAutoDeleteIgnoredCommands String[] @default([]) @map("messages.auto-delete.ignored-commands") @db.VarChar(32) - /// [StickyRoleEntries] - stickyRoles Json @default("[]") @map("sticky-roles") - /// [ReactionRoleEntries] - reactionRoles Json @default("[]") @map("reaction-roles") - rolesAdmin String[] @default([]) @map("roles.admin") @db.VarChar(19) - rolesInitial String? @map("roles.initial") @db.VarChar(19) - rolesInitialHumans String? @map("roles.initial-humans") @db.VarChar(19) - rolesInitialBots String? @map("roles.initial-bots") @db.VarChar(19) - rolesModerator String[] @default([]) @map("roles.moderator") @db.VarChar(19) - rolesMuted String? @map("roles.muted") @db.VarChar(19) - rolesRestrictedReaction String? @map("roles.restricted-reaction") @db.VarChar(19) - rolesRestrictedEmbed String? @map("roles.restricted-embed") @db.VarChar(19) - rolesRestrictedEmoji String? @map("roles.restricted-emoji") @db.VarChar(19) - rolesRestrictedAttachment String? @map("roles.restricted-attachment") @db.VarChar(19) - rolesRestrictedVoice String? @map("roles.restricted-voice") @db.VarChar(19) - rolesPublic String[] @default([]) @map("roles.public") @db.VarChar(19) - rolesRemoveInitial Boolean @default(false) @map("roles.remove-initial") - /// [UniqueRoleSetEntries] - rolesUniqueRoleSets Json @default("[]") @map("roles.unique-role-sets") - selfmodAttachmentsEnabled Boolean @default(false) @map("selfmod.attachments.enabled") - selfmodAttachmentsIgnoredRoles String[] @default([]) @map("selfmod.attachments.ignored-roles") @db.VarChar(19) - selfmodAttachmentsIgnoredChannels String[] @default([]) @map("selfmod.attachments.ignored-channels") @db.VarChar(19) - selfmodAttachmentsSoftAction Int @default(0) @map("selfmod.attachments.soft-action") @db.SmallInt - selfmodAttachmentsHardAction Int @default(0) @map("selfmod.attachments.hard-action") @db.SmallInt - selfmodAttachmentsHardActionDuration BigInt? @map("selfmod.attachments.hard-action-duration") - selfmodAttachmentsThresholdMaximum Int @default(10) @map("selfmod.attachments.threshold-maximum") @db.SmallInt - selfmodAttachmentsThresholdDuration Int @default(60000) @map("selfmod.attachments.threshold-duration") - selfmodCapitalsEnabled Boolean @default(false) @map("selfmod.capitals.enabled") - selfmodCapitalsIgnoredRoles String[] @default([]) @map("selfmod.capitals.ignored-roles") @db.VarChar(19) - selfmodCapitalsIgnoredChannels String[] @default([]) @map("selfmod.capitals.ignored-channels") @db.VarChar(19) - selfmodCapitalsMinimum Int @default(15) @map("selfmod.capitals.minimum") @db.SmallInt - selfmodCapitalsMaximum Int @default(50) @map("selfmod.capitals.maximum") @db.SmallInt - selfmodCapitalsSoftAction Int @default(0) @map("selfmod.capitals.soft-action") @db.SmallInt - selfmodCapitalsHardAction Int @default(0) @map("selfmod.capitals.hard-action") @db.SmallInt - selfmodCapitalsHardActionDuration BigInt? @map("selfmod.capitals.hard-action-duration") - selfmodCapitalsThresholdMaximum Int @default(10) @map("selfmod.capitals.threshold-maximum") @db.SmallInt - selfmodCapitalsThresholdDuration Int @default(60000) @map("selfmod.capitals.threshold-duration") - selfmodLinksEnabled Boolean @default(false) @map("selfmod.links.enabled") - selfmodLinksAllowed String[] @default([]) @map("selfmod.links.allowed") @db.VarChar(128) - selfmodLinksIgnoredRoles String[] @default([]) @map("selfmod.links.ignored-roles") @db.VarChar(19) - selfmodLinksIgnoredChannels String[] @default([]) @map("selfmod.links.ignored-channels") @db.VarChar(19) - selfmodLinksSoftAction Int @default(0) @map("selfmod.links.soft-action") @db.SmallInt - selfmodLinksHardAction Int @default(0) @map("selfmod.links.hard-action") @db.SmallInt - selfmodLinksHardActionDuration BigInt? @map("selfmod.links.hard-action-duration") - selfmodLinksThresholdMaximum Int @default(10) @map("selfmod.links.threshold-maximum") @db.SmallInt - selfmodLinksThresholdDuration Int @default(60000) @map("selfmod.links.threshold-duration") - selfmodMessagesEnabled Boolean @default(false) @map("selfmod.messages.enabled") - selfmodMessagesIgnoredRoles String[] @default([]) @map("selfmod.messages.ignored-roles") @db.VarChar(19) - selfmodMessagesIgnoredChannels String[] @default([]) @map("selfmod.messages.ignored-channels") @db.VarChar(19) - selfmodMessagesMaximum Int @default(5) @map("selfmod.messages.maximum") @db.SmallInt - selfmodMessagesQueueSize Int @default(50) @map("selfmod.messages.queue-size") @db.SmallInt - selfmodMessagesSoftAction Int @default(0) @map("selfmod.messages.soft-action") @db.SmallInt - selfmodMessagesHardAction Int @default(0) @map("selfmod.messages.hard-action") @db.SmallInt - selfmodMessagesHardActionDuration BigInt? @map("selfmod.messages.hard-action-duration") - selfmodMessagesThresholdMaximum Int @default(10) @map("selfmod.messages.threshold-maximum") @db.SmallInt - selfmodMessagesThresholdDuration Int @default(60000) @map("selfmod.messages.threshold-duration") - selfmodNewlinesEnabled Boolean @default(false) @map("selfmod.newlines.enabled") - selfmodNewlinesIgnoredRoles String[] @default([]) @map("selfmod.newlines.ignored-roles") @db.VarChar(19) - selfmodNewlinesIgnoredChannels String[] @default([]) @map("selfmod.newlines.ignored-channels") @db.VarChar(19) - selfmodNewlinesMaximum Int @default(20) @map("selfmod.newlines.maximum") @db.SmallInt - selfmodNewlinesSoftAction Int @default(0) @map("selfmod.newlines.soft-action") @db.SmallInt - selfmodNewlinesHardAction Int @default(0) @map("selfmod.newlines.hard-action") @db.SmallInt - selfmodNewlinesHardActionDuration BigInt? @map("selfmod.newlines.hard-action-duration") - selfmodNewlinesThresholdMaximum Int @default(10) @map("selfmod.newlines.threshold-maximum") @db.SmallInt - selfmodNewlinesThresholdDuration Int @default(60000) @map("selfmod.newlines.threshold-duration") - selfmodInvitesEnabled Boolean @default(false) @map("selfmod.invites.enabled") - selfmodInvitesIgnoredCodes String[] @default([]) @map("selfmod.invites.ignored-codes") @db.VarChar - selfmodInvitesIgnoredGuilds String[] @default([]) @map("selfmod.invites.ignored-guilds") @db.VarChar(19) - selfmodInvitesIgnoredRoles String[] @default([]) @map("selfmod.invites.ignored-roles") @db.VarChar(19) - selfmodInvitesIgnoredChannels String[] @default([]) @map("selfmod.invites.ignored-channels") @db.VarChar(19) - selfmodInvitesSoftAction Int @default(0) @map("selfmod.invites.soft-action") @db.SmallInt - selfmodInvitesHardAction Int @default(0) @map("selfmod.invites.hard-action") @db.SmallInt - selfmodInvitesHardActionDuration BigInt? @map("selfmod.invites.hard-action-duration") - selfmodInvitesThresholdMaximum Int @default(10) @map("selfmod.invites.threshold-maximum") @db.SmallInt - selfmodInvitesThresholdDuration Int @default(60000) @map("selfmod.invites.threshold-duration") - selfmodFilterEnabled Boolean @default(false) @map("selfmod.filter.enabled") - selfmodFilterRaw String[] @default([]) @map("selfmod.filter.raw") @db.VarChar(32) - selfmodFilterIgnoredRoles String[] @default([]) @map("selfmod.filter.ignored-roles") @db.VarChar(19) - selfmodFilterIgnoredChannels String[] @default([]) @map("selfmod.filter.ignored-channels") @db.VarChar(19) - selfmodFilterSoftAction Int @default(0) @map("selfmod.filter.soft-action") @db.SmallInt - selfmodFilterHardAction Int @default(0) @map("selfmod.filter.hard-action") @db.SmallInt - selfmodFilterHardActionDuration BigInt? @map("selfmod.filter.hard-action-duration") - selfmodFilterThresholdMaximum Int @default(10) @map("selfmod.filter.threshold-maximum") @db.SmallInt - selfmodFilterThresholdDuration Int @default(60000) @map("selfmod.filter.threshold-duration") - selfmodReactionsEnabled Boolean @default(false) @map("selfmod.reactions.enabled") - selfmodReactionsIgnoredRoles String[] @default([]) @map("selfmod.reactions.ignored-roles") @db.VarChar(19) - selfmodReactionsIgnoredChannels String[] @default([]) @map("selfmod.reactions.ignored-channels") @db.VarChar(19) - selfmodReactionsMaximum Int @default(10) @map("selfmod.reactions.maximum") @db.SmallInt - selfmodReactionsAllowed String[] @default([]) @map("selfmod.reactions.allowed") @db.VarChar(128) - selfmodReactionsBlocked String[] @default([]) @map("selfmod.reactions.blocked") @db.VarChar(128) - selfmodReactionsSoftAction Int @default(0) @map("selfmod.reactions.soft-action") @db.SmallInt - selfmodReactionsHardAction Int @default(0) @map("selfmod.reactions.hard-action") @db.SmallInt - selfmodReactionsHardActionDuration BigInt? @map("selfmod.reactions.hard-action-duration") - selfmodReactionsThresholdMaximum Int @default(10) @map("selfmod.reactions.threshold-maximum") @db.SmallInt - selfmodReactionsThresholdDuration Int @default(60000) @map("selfmod.reactions.threshold-duration") - selfmodIgnoredChannels String[] @default([]) @map("selfmod.ignored-channels") @db.VarChar(19) - noMentionSpamEnabled Boolean @default(false) @map("no-mention-spam.enabled") - noMentionSpamAlerts Boolean @default(false) @map("no-mention-spam.alerts") - noMentionSpamMentionsAllowed Int @default(20) @map("no-mention-spam.mentions-allowed") @db.SmallInt - noMentionSpamTimePeriod Int @default(8) @map("no-mention-spam.time-period") - eventsUnknownMessages Boolean @default(false) @map("events.unknown-messages") - eventsIncludeBots Boolean @default(false) @map("events.include-bots") - channelsIgnoreVoiceActivity String[] @default([]) @map("channels.ignore.voice-activity") @db.VarChar(19) - eventsTimeout Boolean @default(false) @map("events.timeout") - - @@map("guilds") + id BigInt @id @map("id") + + log GuildLogs? + moderation GuildModeration? + autoModeration GuildAutoModeration? + roles GuildRoles? + + cases ModerationAction[] + stickyRoles StickyRole[] +} + +model GuildModeration { + id BigInt @id @map("id") + /// The guild entry is from. + guild Guild @relation(fields: [id], references: [id], onDelete: Cascade) + + /// The moderation logs channel. + channelId BigInt? @map("channel_id") + /// Whether or not bans issued manually should be logged. + trackBans Boolean @default(false) @map("track_bans") + /// Whether or not timeouts issued manually should be included. + trackTimeouts Boolean @default(false) @map("track_timeouts") } -model Migration { - id Int @id(map: "PK_Migrations") @default(autoincrement()) - timestamp BigInt - name String @db.VarChar +model GuildAutoModeration { + id BigInt @id @map("id") + /// The guild entry is from. + guild Guild @relation(fields: [id], references: [id], onDelete: Cascade) + + /// The moderation logs channel. + channelId BigInt? @map("channel_id") + /// Whether or not to track Discord's native automod actions. + trackNative Boolean @default(false) @map("track_native") - @@map("migrations") + attachments GuildAutoModerationAttachments? + capitals GuildAutoModerationCapitals? + invites GuildAutoModerationInvites? + links GuildAutoModerationLinks? + mentions GuildAutoModerationMentions? + newlines GuildAutoModerationNewlines? + words GuildAutoModerationWords? } -model Moderation { - caseId Int @map("case_id") - createdAt DateTime? @map("created_at") @db.Timestamp(6) - duration BigInt? - extraData Json? @map("extra_data") @db.Json - guildId String @map("guild_id") @db.VarChar(19) - moderatorId String @map("moderator_id") @db.VarChar(19) - reason String? @db.VarChar(2000) - imageURL String? @map("image_url") @db.VarChar(2000) - userId String? @map("user_id") @db.VarChar(19) - type Int @db.SmallInt - metadata Int @default(0) @db.SmallInt - - @@id([caseId, guildId], map: "PK_4054ed22fc0434ba8d5647e07cc") - @@map("moderation") +enum GuildAutoModerationHardAction { + VoiceKick + Warning + Timeout + Kick + Softban + Ban } -model Schedule { - id Int @id(map: "PK_1c05e42aec7371641193e180046") @default(autoincrement()) - taskId String @map("task_id") @db.VarChar - time DateTime @db.Timestamp(6) - recurring String? @db.VarChar - catchUp Boolean @default(true) @map("catch_up") - data Json +model GuildAutoModerationAttachments { + id BigInt @id @map("id") + /// The parent where all automod information is at. + parent GuildAutoModeration @relation(fields: [id], references: [id], onDelete: Cascade) + + /// Whether or not the subsystem is enabled. + enabled Boolean? @map("enabled") + + /// The action to do in each infraction. Holds a bitfield value, where: + /// + /// - 1st bit (0b00X): Whether or not to delete the message. + /// - 2nd bit (0b0X0): Whether or not to send an alert to the channel. + /// - 3rd bit (0bX00): Whether or not to log the infraction. + softAction Int @map("soft_action") + + /// The action to do in each infraction. Holds a bitfield value, where: + /// + /// - 1st bit (0b00X): Whether or not to delete the message. + /// - 2nd bit (0b0X0): Whether or not to send an alert to the channel. + /// - 3rd bit (0bX00): Whether or not to log the infraction. + hardAction GuildAutoModerationHardAction @map("hard_action") + /// The duration in seconds of the hard action. Only applicable to Warning, Timeout, and Ban. + /// + /// In the case of Timeout, if none is given, the action will be ignored. + hardActionDuration Int? @map("hard_action_duration") + + /// The amount of infractions a user can do before triggering the hard action. + thresholdMaximum Int @map("threshold_maximum") + /// The amount of time in seconds to pool the amount of infractions. + thresholdDuration Int @map("threshold_duration") - @@map("schedule") + /// The roles that are ignored by this subsystem. + ignoredRoles BigInt[] @default([]) @map("ignored_roles") + /// The channels that are ignored by this subsystem. + ignoredChannels BigInt[] @default([]) @map("ignored_channels") } -model User { - id String @id(map: "PK_cace4a159ff9f2512dd42373760") @db.VarChar(19) - moderationDM Boolean @default(true) @map("moderation_dm") +model GuildAutoModerationCapitals { + id BigInt @id @map("id") + /// The parent where all automod information is at. + parent GuildAutoModeration @relation(fields: [id], references: [id], onDelete: Cascade) + + /// Whether or not the subsystem is enabled. + enabled Boolean? @map("enabled") + + /// The action to do in each infraction. Holds a bitfield value, where: + /// + /// - 1st bit (0b00X): Whether or not to delete the message. + /// - 2nd bit (0b0X0): Whether or not to send an alert to the channel. + /// - 3rd bit (0bX00): Whether or not to log the infraction. + softAction Int @map("soft_action") + + /// The action to do in each infraction. Holds a bitfield value, where: + /// + /// - 1st bit (0b00X): Whether or not to delete the message. + /// - 2nd bit (0b0X0): Whether or not to send an alert to the channel. + /// - 3rd bit (0bX00): Whether or not to log the infraction. + hardAction GuildAutoModerationHardAction @map("hard_action") + /// The duration in seconds of the hard action. Only applicable to Warning, Timeout, and Ban. + /// + /// In the case of Timeout, if none is given, the action will be ignored. + hardActionDuration Int? @map("hard_action_duration") + + /// The amount of infractions a user can do before triggering the hard action. + thresholdMaximum Int @map("threshold_maximum") + /// The amount of time in seconds to pool the amount of infractions. + thresholdDuration Int @map("threshold_duration") + + /// The amount of characters at which the message won't be ignored by this subsystem. + minimum Int @map("minimum") + /// The percentage of uppercase characters a message may have for an infraction. + maximum Int @map("maximum") + + /// The roles that are ignored by this subsystem. + ignoredRoles BigInt[] @default([]) @map("ignored_roles") + /// The channels that are ignored by this subsystem. + ignoredChannels BigInt[] @default([]) @map("ignored_channels") +} + +model GuildAutoModerationLinks { + id BigInt @id @map("id") + /// The parent where all automod information is at. + parent GuildAutoModeration @relation(fields: [id], references: [id], onDelete: Cascade) + + /// Whether or not the subsystem is enabled. + enabled Boolean? @map("enabled") + + /// The action to do in each infraction. Holds a bitfield value, where: + /// + /// - 1st bit (0b00X): Whether or not to delete the message. + /// - 2nd bit (0b0X0): Whether or not to send an alert to the channel. + /// - 3rd bit (0bX00): Whether or not to log the infraction. + softAction Int @map("soft_action") - @@map("user") + /// The action to do in each infraction. Holds a bitfield value, where: + /// + /// - 1st bit (0b00X): Whether or not to delete the message. + /// - 2nd bit (0b0X0): Whether or not to send an alert to the channel. + /// - 3rd bit (0bX00): Whether or not to log the infraction. + hardAction GuildAutoModerationHardAction @map("hard_action") + /// The duration in seconds of the hard action. Only applicable to Warning, Timeout, and Ban. + /// + /// In the case of Timeout, if none is given, the action will be ignored. + hardActionDuration Int? @map("hard_action_duration") + + /// The amount of infractions a user can do before triggering the hard action. + thresholdMaximum Int @map("threshold_maximum") + /// The amount of time in seconds to pool the amount of infractions. + thresholdDuration Int @map("threshold_duration") + + /// The allowed domain links. + allowed String[] @default([]) + + /// The roles that are ignored by this subsystem. + ignoredRoles BigInt[] @default([]) @map("ignored_roles") + /// The channels that are ignored by this subsystem. + ignoredChannels BigInt[] @default([]) @map("ignored_channels") +} + +model GuildAutoModerationNewlines { + id BigInt @id @map("id") + /// The parent where all automod information is at. + parent GuildAutoModeration @relation(fields: [id], references: [id], onDelete: Cascade) + + /// Whether or not the subsystem is enabled. + enabled Boolean? @map("enabled") + + /// The action to do in each infraction. Holds a bitfield value, where: + /// + /// - 1st bit (0b00X): Whether or not to delete the message. + /// - 2nd bit (0b0X0): Whether or not to send an alert to the channel. + /// - 3rd bit (0bX00): Whether or not to log the infraction. + softAction Int @map("soft_action") + + /// The action to do in each infraction. Holds a bitfield value, where: + /// + /// - 1st bit (0b00X): Whether or not to delete the message. + /// - 2nd bit (0b0X0): Whether or not to send an alert to the channel. + /// - 3rd bit (0bX00): Whether or not to log the infraction. + hardAction GuildAutoModerationHardAction @map("hard_action") + /// The duration in seconds of the hard action. Only applicable to Warning, Timeout, and Ban. + /// + /// In the case of Timeout, if none is given, the action will be ignored. + hardActionDuration Int? @map("hard_action_duration") + + /// The amount of infractions a user can do before triggering the hard action. + thresholdMaximum Int @map("threshold_maximum") + /// The amount of time in seconds to pool the amount of infractions. + thresholdDuration Int @map("threshold_duration") + + /// The amount of newlines characters a message may have for an infraction. + maximum Int @map("maximum") + + /// The roles that are ignored by this subsystem. + ignoredRoles BigInt[] @default([]) @map("ignored_roles") + /// The channels that are ignored by this subsystem. + ignoredChannels BigInt[] @default([]) @map("ignored_channels") +} + +model GuildAutoModerationInvites { + id BigInt @id @map("id") + /// The parent where all automod information is at. + parent GuildAutoModeration @relation(fields: [id], references: [id], onDelete: Cascade) + + /// Whether or not the subsystem is enabled. + enabled Boolean? @map("enabled") + + /// The action to do in each infraction. Holds a bitfield value, where: + /// + /// - 1st bit (0b00X): Whether or not to delete the message. + /// - 2nd bit (0b0X0): Whether or not to send an alert to the channel. + /// - 3rd bit (0bX00): Whether or not to log the infraction. + softAction Int @map("soft_action") + + /// The action to do in each infraction. Holds a bitfield value, where: + /// + /// - 1st bit (0b00X): Whether or not to delete the message. + /// - 2nd bit (0b0X0): Whether or not to send an alert to the channel. + /// - 3rd bit (0bX00): Whether or not to log the infraction. + hardAction GuildAutoModerationHardAction @map("hard_action") + /// The duration in seconds of the hard action. Only applicable to Warning, Timeout, and Ban. + /// + /// In the case of Timeout, if none is given, the action will be ignored. + hardActionDuration Int? @map("hard_action_duration") + + /// The amount of infractions a user can do before triggering the hard action. + thresholdMaximum Int @map("threshold_maximum") + /// The amount of time in seconds to pool the amount of infractions. + thresholdDuration Int @map("threshold_duration") + + /// The allowed invite codes. + allowedCodes String[] @default([]) @map("allowed_codes") + /// The allowed invite codes. + allowedGuilds BigInt[] @default([]) @map("allowed_guilds") + + /// The roles that are ignored by this subsystem. + ignoredRoles BigInt[] @default([]) @map("ignored_roles") + /// The channels that are ignored by this subsystem. + ignoredChannels BigInt[] @default([]) @map("ignored_channels") +} + +model GuildAutoModerationWords { + id BigInt @id @map("id") + /// The parent where all automod information is at. + parent GuildAutoModeration @relation(fields: [id], references: [id], onDelete: Cascade) + + /// Whether or not the subsystem is enabled. + enabled Boolean? @map("enabled") + + /// The action to do in each infraction. Holds a bitfield value, where: + /// + /// - 1st bit (0b00X): Whether or not to delete the message. + /// - 2nd bit (0b0X0): Whether or not to send an alert to the channel. + /// - 3rd bit (0bX00): Whether or not to log the infraction. + softAction Int @map("soft_action") + + /// The action to do in each infraction. Holds a bitfield value, where: + /// + /// - 1st bit (0b00X): Whether or not to delete the message. + /// - 2nd bit (0b0X0): Whether or not to send an alert to the channel. + /// - 3rd bit (0bX00): Whether or not to log the infraction. + hardAction GuildAutoModerationHardAction @map("hard_action") + /// The duration in seconds of the hard action. Only applicable to Warning, Timeout, and Ban. + /// + /// In the case of Timeout, if none is given, the action will be ignored. + hardActionDuration Int? @map("hard_action_duration") + + /// The amount of infractions a user can do before triggering the hard action. + thresholdMaximum Int @map("threshold_maximum") + /// The amount of time in seconds to pool the amount of infractions. + thresholdDuration Int @map("threshold_duration") + + /// The filtered words. + words String[] @default([]) @map("words") + + /// The roles that are ignored by this subsystem. + ignoredRoles BigInt[] @default([]) @map("ignored_roles") + /// The channels that are ignored by this subsystem. + ignoredChannels BigInt[] @default([]) @map("ignored_channels") +} + +model GuildAutoModerationMentions { + id BigInt @id @map("id") + /// The parent where all automod information is at. + parent GuildAutoModeration @relation(fields: [id], references: [id], onDelete: Cascade) + + /// Whether or not the subsystem is enabled. + enabled Boolean? @map("enabled") + + /// The action to do in each infraction. Holds a bitfield value, where: + /// + /// - 1st bit (0b00X): Whether or not to delete the message. + /// - 2nd bit (0b0X0): Whether or not to send an alert to the channel. + /// - 3rd bit (0bX00): Whether or not to log the infraction. + softAction Int @map("soft_action") + + /// The action to do in each infraction. Holds a bitfield value, where: + /// + /// - 1st bit (0b00X): Whether or not to delete the message. + /// - 2nd bit (0b0X0): Whether or not to send an alert to the channel. + /// - 3rd bit (0bX00): Whether or not to log the infraction. + hardAction GuildAutoModerationHardAction @map("hard_action") + /// The duration in seconds of the hard action. Only applicable to Warning, Timeout, and Ban. + /// + /// In the case of Timeout, if none is given, the action will be ignored. + hardActionDuration Int? @map("hard_action_duration") + + /// The amount of infractions a user can do before triggering the hard action. + thresholdMaximum Int @map("threshold_maximum") + /// The amount of time in seconds to pool the amount of infractions. + thresholdDuration Int @map("threshold_duration") + + /// The overrides for the point system. + overrides GuildAutoModerationMentionsOverrides[] + + /// The roles that are ignored by this subsystem. + ignoredRoles BigInt[] @default([]) @map("ignored_roles") + /// The channels that are ignored by this subsystem. + ignoredChannels BigInt[] @default([]) @map("ignored_channels") +} + +model GuildAutoModerationMentionsOverrides { + id BigInt @id @default(autoincrement()) @map("id") + + parentId BigInt @map("parent_id") + /// The parent where all automod information is at. + parent GuildAutoModerationMentions @relation(fields: [parentId], references: [id], onDelete: Cascade) + + /// The roles affected by this override. + roles BigInt[] @map("roles") + /// The users affected by this override. + users BigInt[] @map("users") + + points Int @map("points") +} + +model GuildLogs { + id BigInt @id @map("id") + /// The guild entry is from. + guild Guild @relation(fields: [id], references: [id], onDelete: Cascade) + + /// The member add logs channel. + memberAdd BigInt? @map("member_add") + /// The member remove logs channel. + memberRemove BigInt? @map("member_remove") + /// The member nickname update logs channel. + memberNickNameUpdate BigInt? @map("member_nickname_update") + /// The member username update logs channel. + memberUserNameUpdate BigInt? @map("member_username_update") + + /// The message delete logs channel. + messageDelete BigInt? @map("message_delete") + /// The message delete logs NSFW channel. + messageDeleteNsfw BigInt? @map("message_delete_nsfw") + /// The message update logs channel. + messageUpdate BigInt? @map("message_update") + /// The message update logs NSFW channel. + messageUpdateNsfw BigInt? @map("message_update_nsfw") + + /// The message prune logs channel. + prune BigInt? @map("prune") + /// The message reaction logs channel. + reaction BigInt? @map("reaction") + + /// The role create logs channel. + roleCreate BigInt? @map("role_create") + /// The role update logs channel. + roleUpdate BigInt? @map("role_update") + /// The role delete logs channel. + roleDelete BigInt? @map("role_delete") + + /// The channel create logs channel. + channelCreate BigInt? @map("channel_create") + /// The channel update logs channel. + channelUpdate BigInt? @map("channel_update") + /// The channel delete logs channel. + channelDelete BigInt? @map("channel_delete") + + /// The emoji create logs channel. + emojiCreate BigInt? @map("emoji_create") + /// The emoji update logs channel. + emojiUpdate BigInt? @map("emoji_update") + /// The emoji delete logs channel. + emojiDelete BigInt? @map("emoji_delete") + + /// The emoji reaction add logs channel. + emojiAdd BigInt? @map("emoji_add") + /// Whether or not twemoji reactions should be logged. + emojiAddIncludeTwemoji Boolean @default(false) @map("emoji_add_include_twemoji") + + /// The server update logs channel. + serverUpdate BigInt? @map("server_update") + /// The command execution logs channel. + command BigInt? @map("command") + /// The settings change logs channel. + settings BigInt? @map("settings") + + /// The channels to ignore logs from. + ignoreAll BigInt[] @default([]) @map("ignore_all") + /// The channels to ignore message updates from. + ignoreMessages BigInt[] @default([]) @map("ignore_messages") + /// The channels to ignore reaction updates from. + ignoreReactions BigInt[] @default([]) @map("ignore_reactions") +} + +model GuildRoles { + id BigInt @id @map("id") + /// The guild entry is from. + guild Guild @relation(fields: [id], references: [id], onDelete: Cascade) + + /// The roles to be given to any new user. + initial BigInt[] @default([]) @map("initial") + /// The roles to be given to any new human user. + initialHumans BigInt[] @default([]) @map("initial_humans") + /// The roles to be given to any new bot user. + initialRobots BigInt[] @default([]) @map("initial_robots") +} + +model StickyRole { + /// The entry's case number ID. + userId BigInt @map("user_id") + /// The guild this entry was issued at. + guild Guild @relation(fields: [guildId], references: [id]) + /// The ID of the guild this entry was issued at. + guildId BigInt @map("guild_id") + + /// The sticky role IDs + roleIds BigInt[] @map("role_ids") + + @@id([userId, guildId]) +} + +enum ModerationActionType { + AddRole + RemoveRole + Nickname + AddWarning + RemoveWarning + Timeout + TimeoutEnd + Kick + Softban + Ban + Unban +} + +model ModerationAction { + /// The entry's case number ID. + id Int @map("id") + /// The guild this entry was issued at. + guild Guild @relation(fields: [guildId], references: [id]) + /// The ID of the guild this entry was issued at. + guildId BigInt @map("guild_id") + /// The moderation action type. + action ModerationActionType @map("action") + /// Holds a bitfield value, where: + /// + /// - 1st bit (0b000X): Whether or not the entry is hidden. + metadata Int @map("metadata") + /// The creation time of this entry. + createdAt DateTime @default(now()) @map("created_at") + /// The duration in seconds of this action, `0` is considered no duration. + duration Int @map("duration") + /// The target user. + targetId BigInt @map("target_id") + /// The moderator who issued this action. + moderatorId BigInt @map("moderator_id") + /// The moderation log this entry refers to, if any. + referenceId Int? @map("reference_id") + + @@id([id, guildId]) +} + +model User { + /// The ID of the user. + id BigInt @id @map("id") + /// Whether or not moderation actions should DM the user. + report Boolean @default(true) @map("report") } model AuditEvent { - id String @id @default(uuid()) @db.Uuid - action String @db.VarChar(64) - actorType String @map("actor_type") @db.VarChar(32) - actorId String @map("actor_id") + id String @id @default(uuid()) + + /// The action identifier (e.g. `guild.settings.update`). + action String + /// The type of actor that performed the action. + actorType String @map("actor_type") + /// The ID of the actor that performed the action. + actorId BigInt @map("actor_id") + /// The display name of the actor, if known. actorName String? @map("actor_name") - targetType String? @map("target_type") @db.VarChar(32) - targetId String? @map("target_id") - outcome String @db.VarChar(32) - tenantId String? @map("tenant_id") - reason String? @db.VarChar(500) - timestamp DateTime @db.Timestamp(6) + /// The type of the action target, if any. + targetType String? @map("target_type") + /// The ID of the action target, if any. + targetId BigInt? @map("target_id") + /// The outcome of the action (e.g. `success`, `denied`). + outcome String + /// The tenant (guild) this event belongs to. + tenantId BigInt? @map("tenant_id") + /// An optional reason for the action. + reason String? + /// When the event occurred. + timestamp DateTime + /// The before/after changes for settings updates. changes Json? + /// Additional contextual metadata. context Json? - prevHash String? @map("prev_hash") @db.VarChar(64) - hash String @unique @db.VarChar(64) + /// The hash of the previous event in the chain. + prevHash String? @map("prev_hash") + /// The SHA-256 envelope hash of this event. + hash String @unique @@index([action, timestamp]) @@index([actorId, timestamp]) @@index([tenantId, timestamp]) - @@map("audit_event") } model AuditChainHead { - id String @id @default("default") - hash String? @db.VarChar(64) - updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamp(6) + id String @id @default("default") - @@map("audit_chain_head") + /// The hash of the latest event in the audit chain. + hash String? + updatedAt DateTime @updatedAt @map("updated_at") } model CommandLog { - id String @id @default(uuid()) @db.Uuid - guildId String @map("guild_id") @db.VarChar(19) - userId String @map("user_id") @db.VarChar(19) - commandName String @map("command_name") @db.VarChar(64) - commandType String @map("command_type") @db.VarChar(32) - commandId String? @map("command_id") @db.VarChar(19) - subcommand String? @db.VarChar(64) - channelId String? @map("channel_id") @db.VarChar(19) + id String @id @default(uuid()) + + /// The guild where the command was executed. + guildId BigInt @map("guild_id") + /// The user who executed the command. + userId BigInt @map("user_id") + /// The command name. + commandName String @map("command_name") + /// The command type (`chat-input`, `message`, or `context-menu`). + commandType String @map("command_type") + /// The Discord application command ID, if applicable. + commandId BigInt? @map("command_id") + /// The subcommand name, if applicable. + subcommand String? + /// The channel where the command was executed. + channelId BigInt? @map("channel_id") + /// Whether the command executed successfully. success Boolean @default(true) - errorReason String? @map("error_reason") @db.VarChar(2000) - executedAt DateTime @map("executed_at") @db.Timestamp(6) + /// The error reason, if the command failed. + errorReason String? @map("error_reason") + /// When the command was executed. + executedAt DateTime @map("executed_at") + /// The execution latency in milliseconds. latencyMs Int? @map("latency_ms") - metadata Json? @db.Json + /// Additional metadata about the execution. + metadata Json? @@index([guildId, executedAt(sort: Desc)]) @@index([guildId, userId, executedAt]) @@index([guildId, commandName, executedAt]) - @@map("command_log") } diff --git a/projects/bot/Dockerfile b/projects/bot/Dockerfile new file mode 100644 index 000000000..950f7ef78 --- /dev/null +++ b/projects/bot/Dockerfile @@ -0,0 +1,62 @@ +# ================ # +# Base Stage # +# ================ # + +FROM node:16-buster-slim as base + +WORKDIR /usr/src/app + +ENV HUSKY=0 +ENV CI=true + +RUN apt-get update && \ + apt-get upgrade -y --no-install-recommends && \ + apt-get install -y --no-install-recommends build-essential python3 libfontconfig1 dumb-init && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +COPY --chown=node:node yarn.lock . +COPY --chown=node:node package.json . +COPY --chown=node:node projects/bot/package.json projects/bot/package.json +COPY --chown=node:node .yarnrc.yml . +COPY --chown=node:node .yarn/ .yarn/ + +ENTRYPOINT ["dumb-init", "--"] + +# ================ # +# Builder Stage # +# ================ # + +FROM base as builder + +ENV NODE_ENV="development" + +COPY --chown=node:node tsconfig.base.json tsconfig.base.json +COPY --chown=node:node scripts/ scripts/ +COPY --chown=node:node projects/bot/scripts/ projects/bot/scripts/ +COPY --chown=node:node projects/bot/src/ projects/bot/src/ + +RUN yarn install --immutable +RUN cd projects/bot/ && yarn run build + +# ================ # +# Runner Stage # +# ================ # + +FROM base AS runner + +ENV NODE_ENV="production" +ENV NODE_OPTIONS="--enable-source-maps --max_old_space_size=4096" + +COPY --chown=node:node projects/bot/scripts/workerTsLoader.js projects/bot/scripts/workerTsLoader.js +COPY --chown=node:node projects/bot/src/.env projects/bot/src/.env +COPY --chown=node:node --from=builder /usr/src/app/projects/bot/dist projects/bot/dist + +RUN yarn workspaces focus --all --production +RUN chown node:node /usr/src/app/ + +USER node + +WORKDIR /usr/src/app/projects/bot + +CMD [ "yarn", "run", "start" ] diff --git a/projects/bot/package.json b/projects/bot/package.json new file mode 100644 index 000000000..d4bf5081d --- /dev/null +++ b/projects/bot/package.json @@ -0,0 +1,51 @@ +{ + "name": "wolfstar-bot", + "version": "7.0.0", + "description": "Multipurpose Discord Bot built on Sapphire Framework", + "author": "WolfStar Project", + "license": "Apache-2.0", + "private": true, + "main": "dist/main.js", + "type": "module", + "imports": { + "#lib/*": "./dist/lib/*.js" + }, + "scripts": { + "build": "tsdown", + "dev": "pnpm build && pnpm start", + "watch": "tsdown --watch", + "prisma:generate": "pnpm prisma generate", + "clean": "node scripts/clean.mjs", + "start": "node --enable-source-maps dist/main.js", + "test": "vitest run --config ../../vitest.config.ts" + }, + "dependencies": { + "@discordjs/builders": "^1.1.0", + "@discordjs/collection": "^1.0.1", + "@prisma/client": "^4.1.1", + "@sapphire/async-queue": "^1.3.2", + "@sapphire/result": "^2.1.1", + "@sapphire/utilities": "^3.8.0", + "@sentry/integrations": "^7.8.0", + "@sentry/node": "^7.8.0", + "@wolfstar/env-utilities": "^3.0.1", + "@wolfstar/http-framework": "^3.0.1", + "@wolfstar/http-framework-i18n": "^3.0.1", + "@wolfstar/shared-http-pieces": "^3.0.1", + "@wolfstar/start-banner": "^3.0.1", + "@skyra/char": "^1.0.3", + "@skyra/jaro-winkler": "^1.1.1", + "colorette": "^2.0.19", + "discord-api-types": "^0.37.0", + "gradient-string": "^2.0.1", + "wolfstar-shared": "workspace:^", + "tslib": "^2.4.0" + }, + "devDependencies": { + "@rollup/plugin-alias": "latest", + "@sapphire/framework": "^4.5.0", + "discord.js": "^14.14.1", + "tsdown": "latest", + "typescript": "^6.0.0" + } +} diff --git a/scripts/build/clean.mjs b/projects/bot/scripts/clean.mjs similarity index 75% rename from scripts/build/clean.mjs rename to projects/bot/scripts/clean.mjs index ff68751f4..1bd25ff10 100644 --- a/scripts/build/clean.mjs +++ b/projects/bot/scripts/clean.mjs @@ -1,6 +1,6 @@ import { rm } from 'node:fs/promises'; -const rootFolder = new URL('../../', import.meta.url); +const rootFolder = new URL('../', import.meta.url); const distFolder = new URL('dist/', rootFolder); const options = { recursive: true, force: true }; diff --git a/projects/bot/src/.env b/projects/bot/src/.env new file mode 100644 index 000000000..18982227f --- /dev/null +++ b/projects/bot/src/.env @@ -0,0 +1,38 @@ +CLIENT_NAME='WolfStar' +CLIENT_VERSION='7.0.0 [Testa Edition]' +CLIENT_OWNERS='242043489611808769 268792781713965056' +CLIENT_ID='266624760782258186' +SHARDS='"auto"' + +PGSQL_DATABASE_NAME='postgres' +PGSQL_DATABASE_PASSWORD='postgres' +PGSQL_DATABASE_USER='postgres' +PGSQL_DATABASE_PORT=5432 +PGSQL_DATABASE_HOST='localhost' + +REDIS_ENABLED=true +REDIS_HOST='localhost' +REDIS_PORT=8287 +REDIS_DB=1 +REDIS_PASSWORD='redis' + +INFLUX_ENABLED=true +INFLUX_URL='http://localhost:8285' +INFLUX_TOKEN='' +INFLUX_ORG='WolfStar-Project' +INFLUX_ORG_ANALYTICS_BUCKET='analytics' + +WEBHOOK_ERROR_ID='648663047615021058' +WEBHOOK_ERROR_TOKEN='' + +WORKER_COUNT=2 + +# Tokens +DISCORD_TOKEN='' +BOTLIST_SPACE_TOKEN='' +BOTS_FOR_DISCORD_TOKEN='' +BOTS_ON_DISCORD_TOKEN='' +CRYPTOCOMPARE_TOKEN='' +DISCORD_BOT_LIST_TOKEN='' +DISCORD_BOTS_TOKEN='' +SENTRY_URL='' diff --git a/projects/bot/src/.env.development b/projects/bot/src/.env.development new file mode 100644 index 000000000..b3970ef38 --- /dev/null +++ b/projects/bot/src/.env.development @@ -0,0 +1,35 @@ +CLIENT_VERSION='7.0.0-dev [Testa Edition]' +CLIENT_OWNERS='' +CLIENT_ID='' + +OAUTH_SECRET='' + +PGSQL_DATABASE_NAME='skyra' +PGSQL_DATABASE_PASSWORD='postgres' +PGSQL_DATABASE_USER='postgres' +PGSQL_DATABASE_PORT=5432 +PGSQL_DATABASE_HOST='localhost' + +REDIS_ENABLED=true +REDIS_HOST='localhost' +REDIS_PORT=8287 +REDIS_DB=1 +REDIS_PASSWORD='redis' + +INFLUX_ENABLED=true +INFLUX_URL='http://localhost:8285' +INFLUX_TOKEN='' +INFLUX_ORG='Skyra-Project' +INFLUX_ORG_ANALYTICS_BUCKET='analytics' + +HASTEBIN_POST_URL='https://hastebin.skyra.pw' +HASTEBIN_GET_URL='https://hastebin.skyra.pw' + +WEBHOOK_ERROR_ID='648663047615021058' +WEBHOOK_ERROR_TOKEN='' + +WORKER_COUNT=2 + +# Tokens +DISCORD_TOKEN='' +SENTRY_URL='' diff --git a/src/.env.test b/projects/bot/src/.env.test similarity index 100% rename from src/.env.test rename to projects/bot/src/.env.test diff --git a/projects/bot/src/commands/Admin/eval.ts b/projects/bot/src/commands/Admin/eval.ts new file mode 100644 index 000000000..01598f618 --- /dev/null +++ b/projects/bot/src/commands/Admin/eval.ts @@ -0,0 +1,158 @@ +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { WolfCommand } from '#lib/structures'; +import { PermissionLevels } from '#lib/types/Enums'; +import { seconds } from '#utils/common'; +import { EvalExtraData, handleMessage } from '#utils/Parsers/ExceededLength'; +import { clean } from '#utils/Sanitizer/clean'; +import { cast } from '#utils/util'; +import { ApplyOptions } from '@sapphire/decorators'; +import { Stopwatch } from '@sapphire/stopwatch'; +import { Type } from '@sapphire/type'; +import { codeBlock, isThenable } from '@sapphire/utilities'; +import type { Message } from 'discord.js'; +import { setTimeout as sleep } from 'node:timers/promises'; +import { inspect } from 'node:util'; + +@ApplyOptions({ + aliases: ['ev'], + description: LanguageKeys.Commands.System.EvalDescription, + detailedDescription: LanguageKeys.Commands.System.EvalExtended, + flags: ['async', 'no-timeout', 'json', 'silent', 'log', 'showHidden', 'hidden', 'sql'], + options: ['wait', 'lang', 'language', 'output', 'output-to', 'depth'], + permissionLevel: PermissionLevels.BotOwner, + quotes: [] +}) +export class UserCommand extends WolfCommand { + private readonly kTimeout = 60000; + + public async messageRun(message: Message, args: WolfCommand.Args) { + const code = await args.rest('string'); + + const wait = args.getOption('wait'); + const flagTime = args.getFlags('no-timeout') ? (wait === null ? this.kTimeout : Number(wait)) : Infinity; + const language = args.getOption('lang', 'language') ?? (args.getFlags('json') ? 'json' : 'js'); + const executeSql = args.getFlags('sql'); + const { success, result, time, type } = executeSql ? await this.sql(code) : await this.timedEval(message, args, code, flagTime); + + if (args.getFlags('silent')) { + if (!success && result && cast(result).stack) this.container.logger.fatal(cast(result).stack); + return null; + } + + const footer = executeSql ? undefined : codeBlock('ts', type); + const sendAs = args.getOption('output', 'output-to') ?? (args.getFlags('log') ? 'log' : null); + + return handleMessage>(message, { + sendAs, + hastebinUnavailable: false, + url: null, + canLogToConsole: true, + success, + result, + time, + footer, + language + }); + } + + private async timedEval(message: Message, args: WolfCommand.Args, code: string, flagTime: number) { + if (flagTime === Infinity || flagTime === 0) return this.eval(message, args, code); + return Promise.race([ + sleep(flagTime).then(() => ({ + result: args.t(LanguageKeys.Commands.System.EvalTimeout, { seconds: seconds.fromMilliseconds(flagTime) }), + success: false, + time: '⏱ ...', + type: 'EvalTimeoutError' + })), + this.eval(message, args, code) + ]); + } + + // Eval the input + private async eval(message: Message, args: WolfCommand.Args, code: string) { + const stopwatch = new Stopwatch(); + let success: boolean; + let syncTime = ''; + let asyncTime = ''; + let result: unknown; + let thenable = false; + let type: Type; + + try { + if (args.getFlags('async')) code = `(async () => {\n${code}\n})();`; + + // @ts-expect-error value is never read, this is so `msg` is possible as an alias when sending the eval. + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const msg = message; + // eslint-disable-next-line no-eval + result = eval(code); + syncTime = stopwatch.toString(); + type = new Type(result); + if (isThenable(result)) { + thenable = true; + stopwatch.restart(); + result = await result; + asyncTime = stopwatch.toString(); + } + success = true; + } catch (error) { + if (!syncTime.length) syncTime = stopwatch.toString(); + if (thenable && !asyncTime.length) asyncTime = stopwatch.toString(); + if (!type!) type = new Type(error); + result = error; + success = false; + } + + stopwatch.stop(); + if (typeof result !== 'string') { + result = + result instanceof Error + ? result.stack + : args.getFlags('json') + ? JSON.stringify(result, null, 4) + : inspect(result, { + depth: Number(args.getOption('depth') ?? 0) || 0, + showHidden: args.getFlags('showHidden', 'hidden') + }); + } + return { + success, + type: type!, + time: this.formatTime(syncTime, asyncTime ?? ''), + result: clean(result as string) + }; + } + + private async sql(sql: string) { + const stopwatch = new Stopwatch(); + let success: boolean; + let time: string; + let result: unknown; + let type: Type; + + try { + result = await this.container.db.connection.query(sql); + time = stopwatch.toString(); + type = new Type(result); + success = true; + } catch (error) { + time = stopwatch.toString(); + type = new Type(error); + result = error; + success = false; + } + + stopwatch.stop(); + + return { + success, + type: type!, + time: this.formatTime(time), + result: JSON.stringify(result, null, 2) + }; + } + + private formatTime(syncTime: string, asyncTime?: string) { + return asyncTime ? `⏱ ${asyncTime}<${syncTime}>` : `⏱ ${syncTime}`; + } +} diff --git a/src/commands/Management/Helpers/guild-info.ts b/projects/bot/src/commands/Management/Helpers/guild-info.ts similarity index 67% rename from src/commands/Management/Helpers/guild-info.ts rename to projects/bot/src/commands/Management/Helpers/guild-info.ts index b7edba5f4..ddc0821fd 100644 --- a/src/commands/Management/Helpers/guild-info.ts +++ b/projects/bot/src/commands/Management/Helpers/guild-info.ts @@ -1,22 +1,22 @@ import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { WolfCommand } from '#lib/structures'; +import { WolfCommand, SkyraPaginatedMessage } from '#lib/structures'; import type { GuildMessage } from '#lib/types'; -import { minutes, seconds } from '#utils/common'; +import { seconds } from '#utils/common'; import { ZeroWidthSpace } from '#utils/constants'; -import { getColor, getTag } from '#utils/util'; import { time, TimestampStyles } from '@discordjs/builders'; import { ApplyOptions } from '@sapphire/decorators'; -import { isCategoryChannel, isNewsChannel, isStageChannel, isTextChannel, isVoiceChannel, PaginatedMessage } from '@sapphire/discord.js-utilities'; +import { isCategoryChannel, isNewsChannel, isStageChannel, isTextChannel, isVoiceChannel } from '@sapphire/discord.js-utilities'; import { CommandOptionsRunTypeEnum } from '@sapphire/framework'; import { send } from '@sapphire/plugin-editable-commands'; import { chunk } from '@sapphire/utilities'; -import { EmbedBuilder, PermissionFlagsBits, type Role } from 'discord.js'; +import { PermissionFlagsBits } from 'discord-api-types/v9'; +import { MessageEmbed, Permissions, Role } from 'discord.js'; const SORT = (x: Role, y: Role) => Number(y.position > x.position) || Number(x.position === y.position) - 1; const roleMention = (role: Role): string => role.toString(); const roleLimit = 15; -const paginatedMessagePermissions = PermissionFlagsBits.AddReactions | PermissionFlagsBits.ManageMessages; +const paginatedMessagePermissions = new Permissions([Permissions.FLAGS.ADD_REACTIONS, Permissions.FLAGS.MANAGE_MESSAGES]); @ApplyOptions({ aliases: ['server-info'], @@ -26,11 +26,11 @@ const paginatedMessagePermissions = PermissionFlagsBits.AddReactions | Permissio runIn: [CommandOptionsRunTypeEnum.GuildAny] }) export class UserCommand extends WolfCommand { - public override async messageRun(message: GuildMessage, args: WolfCommand.Args) { - const color = getColor(message); + public async messageRun(message: GuildMessage, args: WolfCommand.Args) { + const color = await this.container.db.fetchColor(message); const roles = this.getRoles(args); - if (message.channel.permissionsFor(message.guild.members.me!)!.has(paginatedMessagePermissions)) { + if (message.channel.permissionsFor(message.guild.me!)!.has(paginatedMessagePermissions)) { const display = await this.buildDisplay(args, roles, color); return display.run(message); } @@ -39,16 +39,15 @@ export class UserCommand extends WolfCommand { return send(message, { embeds: [embed] }); } - private async buildDisplay(args: WolfCommand.Args, roles: Role[], color: number): Promise { + private async buildDisplay(args: WolfCommand.Args, roles: Role[], color: number): Promise { const guild = args.message.guild!; - const display = new PaginatedMessage({ - template: new EmbedBuilder() // + const display = new SkyraPaginatedMessage({ + template: new MessageEmbed() // .setColor(color) - .setThumbnail(guild.iconURL({ size: 256, extension: 'png' })!) + .setThumbnail(guild.iconURL({ size: 256, format: 'png', dynamic: true })!) .setTitle(`${guild.name} [${guild.id}]`) }); - display.setIdle(minutes(5)); display.addPageEmbed(await this.getSummary(args, roles, color)); if (guild.icon) display.addPageEmbed(this.getIcon(args, color)); if (guild.banner) display.addPageEmbed(this.getBanner(args, color)); @@ -58,15 +57,14 @@ export class UserCommand extends WolfCommand { if (roles.length > roleLimit) { for (const batch of chunk(roles, 20)) { if (batch.length <= 10) { - display.addPageEmbed((embed) => embed.addFields({ name: ZeroWidthSpace, value: batch.map(roleMention).join('\n') })); + display.addPageEmbed((embed) => embed.addField(ZeroWidthSpace, batch.map(roleMention).join('\n'))); } else { const left = batch.slice(0, 10); const right = batch.slice(10); display.addPageEmbed((embed) => - embed.addFields( - { name: ZeroWidthSpace, value: left.map(roleMention).join('\n'), inline: true }, - { name: ZeroWidthSpace, value: right.map(roleMention).join('\n'), inline: true } - ) + embed + .addField(ZeroWidthSpace, left.map(roleMention).join('\n'), true) + .addField(ZeroWidthSpace, right.map(roleMention).join('\n'), true) ); } } @@ -75,49 +73,51 @@ export class UserCommand extends WolfCommand { return display; } - private async getSummary(args: WolfCommand.Args, roles: Role[], color: number): Promise { + private async getSummary(args: WolfCommand.Args, roles: Role[], color: number): Promise { const guild = args.message.guild!; const serverInfoTitles = args.t(LanguageKeys.Commands.Management.GuildInfoTitles); const roleCount = guild.roles.cache.size - 1; - return new EmbedBuilder() + return new MessageEmbed() .setColor(color) - .setThumbnail(guild.iconURL({ size: 256, extension: 'png' })!) + .setThumbnail(guild.iconURL({ size: 256, format: 'png', dynamic: true })!) .setTitle(`${guild.name} [${guild.id}]`) - .addFields( - { name: args.t(LanguageKeys.Commands.Whois.RolesTitle, { count: roleCount }), value: this.getSummaryRoles(args, roles) }, - { name: serverInfoTitles.MEMBERS, value: await this.getSummaryMembers(args), inline: true }, - { name: serverInfoTitles.CHANNELS, value: this.getSummaryChannels(args), inline: true }, - { name: serverInfoTitles.OTHER, value: this.getSummaryOther(args) } - ); + .addField(args.t(LanguageKeys.Commands.Tools.WhoisMemberRoles, { count: roleCount }), this.getSummaryRoles(args, roles)) + .addField(serverInfoTitles.MEMBERS, await this.getSummaryMembers(args), true) + .addField(serverInfoTitles.CHANNELS, this.getSummaryChannels(args), true) + .addField(serverInfoTitles.OTHER, this.getSummaryOther(args)); } - private getBanner(args: WolfCommand.Args, color: number): EmbedBuilder { + private getBanner(args: WolfCommand.Args, color: number): MessageEmbed { const guild = args.message.guild!; - return this.getImage(args.t(LanguageKeys.Commands.Management.GuildInfoBanner), guild.bannerURL({ size: 4096, extension: 'png' })!, color); + return this.getImage(args.t(LanguageKeys.Commands.Management.GuildInfoBanner), guild.bannerURL({ size: 4096, format: 'png' })!, color); } - private getIcon(args: WolfCommand.Args, color: number): EmbedBuilder { + private getIcon(args: WolfCommand.Args, color: number): MessageEmbed { const guild = args.message.guild!; - return this.getImage(args.t(LanguageKeys.Commands.Management.GuildInfoIcon), guild.iconURL({ size: 4096, extension: 'png' })!, color); + return this.getImage( + args.t(LanguageKeys.Commands.Management.GuildInfoIcon), + guild.iconURL({ size: 4096, format: 'png', dynamic: true })!, + color + ); } - private getSplash(args: WolfCommand.Args, color: number): EmbedBuilder { + private getSplash(args: WolfCommand.Args, color: number): MessageEmbed { const guild = args.message.guild!; - return this.getImage(args.t(LanguageKeys.Commands.Management.GuildInfoSplash), guild.splashURL({ size: 4096, extension: 'png' })!, color); + return this.getImage(args.t(LanguageKeys.Commands.Management.GuildInfoSplash), guild.splashURL({ size: 4096, format: 'png' })!, color); } - private getDiscoverySplash(args: WolfCommand.Args, color: number): EmbedBuilder { + private getDiscoverySplash(args: WolfCommand.Args, color: number): MessageEmbed { const guild = args.message.guild!; return this.getImage( args.t(LanguageKeys.Commands.Management.GuildInfoDiscoverySplash), - guild.discoverySplashURL({ size: 4096, extension: 'png' })!, + guild.discoverySplashURL({ size: 4096, format: 'png' })!, color ); } - private getImage(description: string, url: string, color: number): EmbedBuilder { - return new EmbedBuilder().setColor(color).setDescription(`${description} [→](${url})`).setImage(url).setThumbnail(null!); + private getImage(description: string, url: string, color: number): MessageEmbed { + return new MessageEmbed().setColor(color).setDescription(`${description} [→](${url})`).setImage(url).setThumbnail(null!); } private getRoles(args: WolfCommand.Args): Role[] { @@ -142,11 +142,7 @@ export class UserCommand extends WolfCommand { const guild = args.message.guild!; const owner = await this.container.client.users.fetch(guild.ownerId); - return args.t(LanguageKeys.Commands.Management.GuildInfoMembers, { - memberCount: guild.memberCount, - ownerId: owner.id, - ownerTag: getTag(owner) - }); + return args.t(LanguageKeys.Commands.Management.GuildInfoMembers, { memberCount: guild.memberCount, owner }); } private getSummaryChannels(args: WolfCommand.Args): string { @@ -169,7 +165,7 @@ export class UserCommand extends WolfCommand { ? args.t(LanguageKeys.Commands.Management.GuildInfoChannelsAfkChannelText, { afkChannel: guild.afkChannelId, afkTime: guild.afkTimeout / 60 - }) + }) : `**${args.t(LanguageKeys.Globals.None)}**` }); } diff --git a/src/commands/Management/Helpers/role-info.ts b/projects/bot/src/commands/Management/Helpers/role-info.ts similarity index 64% rename from src/commands/Management/Helpers/role-info.ts rename to projects/bot/src/commands/Management/Helpers/role-info.ts index 7917da321..9e6bfa4d5 100644 --- a/src/commands/Management/Helpers/role-info.ts +++ b/projects/bot/src/commands/Management/Helpers/role-info.ts @@ -1,13 +1,13 @@ import { LanguageKeys } from '#lib/i18n/languageKeys'; import { WolfCommand } from '#lib/structures'; -import { PermissionLevels, type GuildMessage } from '#lib/types'; -import { PermissionsBits } from '#utils/bits'; +import type { GuildMessage } from '#lib/types'; +import { PermissionLevels } from '#lib/types/Enums'; import { BrandingColors } from '#utils/constants'; -import { EmbedBuilder } from '@discordjs/builders'; import { ApplyOptions } from '@sapphire/decorators'; import { CommandOptionsRunTypeEnum } from '@sapphire/framework'; import { send } from '@sapphire/plugin-editable-commands'; -import { PermissionFlagsBits } from 'discord.js'; +import { PermissionFlagsBits } from 'discord-api-types/v9'; +import { MessageEmbed, Permissions } from 'discord.js'; @ApplyOptions({ description: LanguageKeys.Commands.Management.RoleInfoDescription, @@ -17,18 +17,18 @@ import { PermissionFlagsBits } from 'discord.js'; runIn: [CommandOptionsRunTypeEnum.GuildAny] }) export class UserCommand extends WolfCommand { - public override async messageRun(message: GuildMessage, args: WolfCommand.Args) { + public async messageRun(message: GuildMessage, args: WolfCommand.Args) { const role = args.finished ? message.member.roles.highest : await args.pick('roleName'); const roleInfoTitles = args.t(LanguageKeys.Commands.Management.RoleInfoTitles); - const permissions = role.permissions.bitfield; - const permissionsString = PermissionsBits.has(permissions, PermissionFlagsBits.Administrator) + const permissions = role.permissions.has(Permissions.FLAGS.ADMINISTRATOR) ? args.t(LanguageKeys.Commands.Management.RoleInfoAll) - : permissions > 0n - ? PermissionsBits.toArray(permissions) - .map((name) => `+ ${args.t(`permissions:${name}`)}`) - .join('\n') - : args.t(LanguageKeys.Commands.Management.RoleInfoNoPermissions); + : role.permissions.toArray().length > 0 + ? role.permissions + .toArray() + .map((key) => `+ **${args.t(`permissions:${key}`, key)}**`) + .join('\n') + : args.t(LanguageKeys.Commands.Management.RoleInfoNoPermissions); const description = args.t(LanguageKeys.Commands.Management.RoleInfoData, { role, @@ -36,11 +36,11 @@ export class UserCommand extends WolfCommand { mentionable: args.t(role.mentionable ? LanguageKeys.Globals.Yes : LanguageKeys.Globals.No) }); - const embed = new EmbedBuilder() + const embed = new MessageEmbed() .setColor(role.color || BrandingColors.Secondary) .setTitle(`${role.name} [${role.id}]`) .setDescription(description) - .addFields({ name: roleInfoTitles.PERMISSIONS, value: permissionsString }); + .addField(roleInfoTitles.PERMISSIONS, permissions); return send(message, { embeds: [embed] }); } } diff --git a/src/commands/Management/Members/stickyRoles.ts b/projects/bot/src/commands/Management/Members/stickyRoles.ts similarity index 76% rename from src/commands/Management/Members/stickyRoles.ts rename to projects/bot/src/commands/Management/Members/stickyRoles.ts index 65c60588c..8f6fccdff 100644 --- a/src/commands/Management/Members/stickyRoles.ts +++ b/projects/bot/src/commands/Management/Members/stickyRoles.ts @@ -1,27 +1,23 @@ import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { WolfSubcommand } from '#lib/structures'; -import { PermissionLevels, type GuildMessage } from '#lib/types'; +import { WolfCommand } from '#lib/structures'; +import type { GuildMessage } from '#lib/types'; +import { PermissionLevels } from '#lib/types/Enums'; import { getStickyRoles } from '#utils/functions'; import { ApplyOptions } from '@sapphire/decorators'; import { CommandOptionsRunTypeEnum } from '@sapphire/framework'; import { send } from '@sapphire/plugin-editable-commands'; -import { PermissionFlagsBits } from 'discord.js'; +import { PermissionFlagsBits } from 'discord-api-types/v9'; -@ApplyOptions({ +@ApplyOptions({ description: LanguageKeys.Commands.Management.StickyRolesDescription, detailedDescription: LanguageKeys.Commands.Management.StickyRolesExtended, permissionLevel: PermissionLevels.Administrator, requiredClientPermissions: [PermissionFlagsBits.ManageRoles], runIn: [CommandOptionsRunTypeEnum.GuildAny], - subcommands: [ - { name: 'add', messageRun: 'add' }, - { name: 'remove', messageRun: 'remove' }, - { name: 'reset', messageRun: 'reset' }, - { name: 'show', messageRun: 'show', default: true } - ] + subCommands: ['add', 'remove', 'reset', { input: 'show', default: true }] }) -export class UserCommand extends WolfSubcommand { - public async add(message: GuildMessage, args: WolfSubcommand.Args) { +export class UserCommand extends WolfCommand { + public async add(message: GuildMessage, args: WolfCommand.Args) { const user = await args.pick('userName'); const role = await args.pick('roleName'); @@ -32,7 +28,7 @@ export class UserCommand extends WolfSubcommand { return send(message, content); } - public async remove(message: GuildMessage, args: WolfSubcommand.Args) { + public async remove(message: GuildMessage, args: WolfCommand.Args) { const user = await args.pick('userName'); const stickyRoles = getStickyRoles(message.guild); @@ -46,7 +42,7 @@ export class UserCommand extends WolfSubcommand { return send(message, content); } - public async reset(message: GuildMessage, args: WolfSubcommand.Args) { + public async reset(message: GuildMessage, args: WolfCommand.Args) { const user = await args.pick('userName'); const stickyRoles = getStickyRoles(message.guild); @@ -59,7 +55,7 @@ export class UserCommand extends WolfSubcommand { return send(message, content); } - public async show(message: GuildMessage, args: WolfSubcommand.Args) { + public async show(message: GuildMessage, args: WolfCommand.Args) { const user = await args.pick('userName'); const stickyRoles = getStickyRoles(message.guild); diff --git a/projects/bot/src/commands/Management/Message Filters/attachmentMode.ts b/projects/bot/src/commands/Management/Message Filters/attachmentMode.ts new file mode 100644 index 000000000..3036c0a1d --- /dev/null +++ b/projects/bot/src/commands/Management/Message Filters/attachmentMode.ts @@ -0,0 +1,20 @@ +import { AdderKey, GuildEntity, GuildSettings } from '#lib/database'; +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { SelfModerationCommand } from '#lib/moderation'; +import { ApplyOptions } from '@sapphire/decorators'; +import type { PickByValue } from '@sapphire/utilities'; + +@ApplyOptions({ + aliases: ['attachment-mode', 'attachments-mode', 'att-mode', 'manageAttachment', 'manageattachment'], + description: LanguageKeys.Commands.Management.AttachmentsModeDescription, + detailedDescription: LanguageKeys.Commands.Management.AttachmentsModeExtended +}) +export class UserSelfModerationCommand extends SelfModerationCommand { + protected $adder: AdderKey = 'attachments'; + protected keyEnabled: PickByValue = GuildSettings.Selfmod.Attachments.Enabled; + protected keySoftAction: PickByValue = GuildSettings.Selfmod.Attachments.SoftAction; + protected keyHardAction: PickByValue = GuildSettings.Selfmod.Attachments.HardAction; + protected keyHardActionDuration: PickByValue = GuildSettings.Selfmod.Attachments.HardActionDuration; + protected keyThresholdMaximum: PickByValue = GuildSettings.Selfmod.Attachments.ThresholdMaximum; + protected keyThresholdDuration: PickByValue = GuildSettings.Selfmod.Attachments.ThresholdDuration; +} diff --git a/projects/bot/src/commands/Management/Message Filters/capitalsMode.ts b/projects/bot/src/commands/Management/Message Filters/capitalsMode.ts new file mode 100644 index 000000000..429b75649 --- /dev/null +++ b/projects/bot/src/commands/Management/Message Filters/capitalsMode.ts @@ -0,0 +1,20 @@ +import { AdderKey, GuildEntity, GuildSettings } from '#lib/database'; +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { SelfModerationCommand } from '#lib/moderation'; +import { ApplyOptions } from '@sapphire/decorators'; +import type { PickByValue } from '@sapphire/utilities'; + +@ApplyOptions({ + aliases: ['capitals-mode', 'caps-mode'], + description: LanguageKeys.Commands.Management.CapitalsModeDescription, + detailedDescription: LanguageKeys.Commands.Management.CapitalsModeExtended +}) +export class UserSelfModerationCommand extends SelfModerationCommand { + protected $adder: AdderKey = 'capitals'; + protected keyEnabled: PickByValue = GuildSettings.Selfmod.Capitals.Enabled; + protected keySoftAction: PickByValue = GuildSettings.Selfmod.Capitals.SoftAction; + protected keyHardAction: PickByValue = GuildSettings.Selfmod.Capitals.HardAction; + protected keyHardActionDuration: PickByValue = GuildSettings.Selfmod.Capitals.HardActionDuration; + protected keyThresholdMaximum: PickByValue = GuildSettings.Selfmod.Capitals.ThresholdMaximum; + protected keyThresholdDuration: PickByValue = GuildSettings.Selfmod.Capitals.ThresholdDuration; +} diff --git a/projects/bot/src/commands/Management/Message Filters/filter.ts b/projects/bot/src/commands/Management/Message Filters/filter.ts new file mode 100644 index 000000000..3ec9e3c81 --- /dev/null +++ b/projects/bot/src/commands/Management/Message Filters/filter.ts @@ -0,0 +1,90 @@ +import { GuildEntity, GuildSettings, readSettings, writeSettings } from '#lib/database'; +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { IncomingType, OutgoingType } from '#lib/moderation/workers'; +import { WolfCommand } from '#lib/structures'; +import type { GuildMessage } from '#lib/types'; +import { PermissionLevels } from '#lib/types/Enums'; +import { ApplyOptions } from '@sapphire/decorators'; +import { CommandOptionsRunTypeEnum } from '@sapphire/framework'; +import { send } from '@sapphire/plugin-editable-commands'; +import { remove as removeConfusables } from 'confusables'; + +@ApplyOptions({ + description: LanguageKeys.Commands.Management.FilterDescription, + detailedDescription: LanguageKeys.Commands.Management.FilterExtended, + permissionLevel: PermissionLevels.Administrator, + runIn: [CommandOptionsRunTypeEnum.GuildAny], + subCommands: ['add', 'remove', 'reset', { input: 'show', default: true }] +}) +export class UserCommand extends WolfCommand { + public async add(message: GuildMessage, args: WolfCommand.Args) { + const word = await this.getWord(args); + await writeSettings(message.guild, async (settings) => { + // Check if the word is not filtered: + const words = settings[GuildSettings.Selfmod.Filter.Raw]; + if (await this.hasWord(settings, word)) { + this.error(LanguageKeys.Commands.Management.FilterAlreadyFiltered); + } + + // Add the word to the list: + words.push(word); + }); + + const content = args.t(LanguageKeys.Commands.Management.FilterAdded, { word }); + return send(message, content); + } + + public async remove(message: GuildMessage, args: WolfCommand.Args) { + const word = await this.getWord(args); + await writeSettings(message.guild, (settings) => { + // Check if the word is not filtered: + const words = settings[GuildSettings.Selfmod.Filter.Raw]; + const index = words.indexOf(word); + if (index === -1) { + this.error(LanguageKeys.Commands.Management.FilterNotFiltered); + } + + // Remove the word from the list: + words.splice(index, 1); + }); + + const content = args.t(LanguageKeys.Commands.Management.FilterRemoved, { word }); + return send(message, content); + } + + public async reset(message: GuildMessage, args: WolfCommand.Args) { + await writeSettings(message.guild, [[GuildSettings.Selfmod.Filter.Raw, []]]); + + const content = args.t(LanguageKeys.Commands.Management.FilterReset); + return send(message, content); + } + + public async show(message: GuildMessage, args: WolfCommand.Args) { + const raw = await readSettings(message.guild, GuildSettings.Selfmod.Filter.Raw); + + const content = raw.length + ? args.t(LanguageKeys.Commands.Management.FilterShow, { words: `\`${raw.join('`, `')}\`` }) + : args.t(LanguageKeys.Commands.Management.FilterShowEmpty); + return send(message, content); + } + + private async getWord(args: WolfCommand.Args) { + const word = await args.pick('string', { maximum: 32 }); + return removeConfusables(word.toLowerCase()); + } + + private async hasWord(settings: GuildEntity, content: string) { + const words = settings[GuildSettings.Selfmod.Filter.Raw]; + if (words.includes(content)) return true; + + const regExp = settings.wordFilterRegExp; + if (regExp === null) return false; + + try { + const result = await this.container.workers.send({ type: IncomingType.RunRegExp, content, regExp }); + return result.type === OutgoingType.RegExpMatch; + } catch { + return false; + } + } +} diff --git a/projects/bot/src/commands/Management/Message Filters/filterMode.ts b/projects/bot/src/commands/Management/Message Filters/filterMode.ts new file mode 100644 index 000000000..11f6c9b94 --- /dev/null +++ b/projects/bot/src/commands/Management/Message Filters/filterMode.ts @@ -0,0 +1,20 @@ +import { AdderKey, GuildEntity, GuildSettings } from '#lib/database'; +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { SelfModerationCommand } from '#lib/moderation'; +import { ApplyOptions } from '@sapphire/decorators'; +import type { PickByValue } from '@sapphire/utilities'; + +@ApplyOptions({ + aliases: ['word-filter-mode'], + description: LanguageKeys.Commands.Management.FilterModeDescription, + detailedDescription: LanguageKeys.Commands.Management.FilterModeExtended +}) +export class UserSelfModerationCommand extends SelfModerationCommand { + protected $adder: AdderKey = 'words'; + protected keyEnabled: PickByValue = GuildSettings.Selfmod.Filter.Enabled; + protected keySoftAction: PickByValue = GuildSettings.Selfmod.Filter.SoftAction; + protected keyHardAction: PickByValue = GuildSettings.Selfmod.Filter.HardAction; + protected keyHardActionDuration: PickByValue = GuildSettings.Selfmod.Filter.HardActionDuration; + protected keyThresholdMaximum: PickByValue = GuildSettings.Selfmod.Filter.ThresholdMaximum; + protected keyThresholdDuration: PickByValue = GuildSettings.Selfmod.Filter.ThresholdDuration; +} diff --git a/projects/bot/src/commands/Management/Message Filters/inviteMode.ts b/projects/bot/src/commands/Management/Message Filters/inviteMode.ts new file mode 100644 index 000000000..071537696 --- /dev/null +++ b/projects/bot/src/commands/Management/Message Filters/inviteMode.ts @@ -0,0 +1,20 @@ +import { AdderKey, GuildEntity, GuildSettings } from '#lib/database'; +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { SelfModerationCommand } from '#lib/moderation'; +import { ApplyOptions } from '@sapphire/decorators'; +import type { PickByValue } from '@sapphire/utilities'; + +@ApplyOptions({ + aliases: ['invites-mode', 'inv-mode'], + description: LanguageKeys.Commands.Management.InviteModeDescription, + detailedDescription: LanguageKeys.Commands.Management.InviteModeExtended +}) +export class UserSelfModerationCommand extends SelfModerationCommand { + protected $adder: AdderKey = 'invites'; + protected keyEnabled: PickByValue = GuildSettings.Selfmod.Invites.Enabled; + protected keySoftAction: PickByValue = GuildSettings.Selfmod.Invites.SoftAction; + protected keyHardAction: PickByValue = GuildSettings.Selfmod.Invites.HardAction; + protected keyHardActionDuration: PickByValue = GuildSettings.Selfmod.Invites.HardActionDuration; + protected keyThresholdMaximum: PickByValue = GuildSettings.Selfmod.Invites.ThresholdMaximum; + protected keyThresholdDuration: PickByValue = GuildSettings.Selfmod.Invites.ThresholdDuration; +} diff --git a/projects/bot/src/commands/Management/Message Filters/linkMode.ts b/projects/bot/src/commands/Management/Message Filters/linkMode.ts new file mode 100644 index 000000000..961e4e64d --- /dev/null +++ b/projects/bot/src/commands/Management/Message Filters/linkMode.ts @@ -0,0 +1,20 @@ +import { AdderKey, GuildEntity, GuildSettings } from '#lib/database'; +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { SelfModerationCommand } from '#lib/moderation'; +import { ApplyOptions } from '@sapphire/decorators'; +import type { PickByValue } from '@sapphire/utilities'; + +@ApplyOptions({ + aliases: ['link-mode', 'lmode', 'linkfilter', 'extlinks', 'externallinks'], + description: LanguageKeys.Commands.Management.LinkModeDescription, + detailedDescription: LanguageKeys.Commands.Management.LinkModeExtended +}) +export class UserSelfModerationCommand extends SelfModerationCommand { + protected $adder: AdderKey = 'links'; + protected keyEnabled: PickByValue = GuildSettings.Selfmod.Links.Enabled; + protected keySoftAction: PickByValue = GuildSettings.Selfmod.Links.SoftAction; + protected keyHardAction: PickByValue = GuildSettings.Selfmod.Links.HardAction; + protected keyHardActionDuration: PickByValue = GuildSettings.Selfmod.Links.HardActionDuration; + protected keyThresholdMaximum: PickByValue = GuildSettings.Selfmod.Links.ThresholdMaximum; + protected keyThresholdDuration: PickByValue = GuildSettings.Selfmod.Links.ThresholdDuration; +} diff --git a/projects/bot/src/commands/Management/Message Filters/messageMode.ts b/projects/bot/src/commands/Management/Message Filters/messageMode.ts new file mode 100644 index 000000000..ae39cbde3 --- /dev/null +++ b/projects/bot/src/commands/Management/Message Filters/messageMode.ts @@ -0,0 +1,20 @@ +import { AdderKey, GuildEntity, GuildSettings } from '#lib/database'; +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { SelfModerationCommand } from '#lib/moderation'; +import { ApplyOptions } from '@sapphire/decorators'; +import type { PickByValue } from '@sapphire/utilities'; + +@ApplyOptions({ + aliases: ['message-mode', 'msg-mode', 'm-mode'], + description: LanguageKeys.Commands.Management.MessageModeDescription, + detailedDescription: LanguageKeys.Commands.Management.MessageModeExtended +}) +export class UserSelfModerationCommand extends SelfModerationCommand { + protected $adder: AdderKey = 'messages'; + protected keyEnabled: PickByValue = GuildSettings.Selfmod.Messages.Enabled; + protected keySoftAction: PickByValue = GuildSettings.Selfmod.Messages.SoftAction; + protected keyHardAction: PickByValue = GuildSettings.Selfmod.Messages.HardAction; + protected keyHardActionDuration: PickByValue = GuildSettings.Selfmod.Messages.HardActionDuration; + protected keyThresholdMaximum: PickByValue = GuildSettings.Selfmod.Messages.ThresholdMaximum; + protected keyThresholdDuration: PickByValue = GuildSettings.Selfmod.Messages.ThresholdDuration; +} diff --git a/projects/bot/src/commands/Management/Message Filters/newlineMode.ts b/projects/bot/src/commands/Management/Message Filters/newlineMode.ts new file mode 100644 index 000000000..422582447 --- /dev/null +++ b/projects/bot/src/commands/Management/Message Filters/newlineMode.ts @@ -0,0 +1,20 @@ +import { AdderKey, GuildEntity, GuildSettings } from '#lib/database'; +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { SelfModerationCommand } from '#lib/moderation'; +import { ApplyOptions } from '@sapphire/decorators'; +import type { PickByValue } from '@sapphire/utilities'; + +@ApplyOptions({ + aliases: ['newline-mode', 'nl-mode'], + description: LanguageKeys.Commands.Management.NewlineModeDescription, + detailedDescription: LanguageKeys.Commands.Management.NewlineModeExtended +}) +export class UserSelfModerationCommand extends SelfModerationCommand { + protected $adder: AdderKey = 'newlines'; + protected keyEnabled: PickByValue = GuildSettings.Selfmod.NewLines.Enabled; + protected keySoftAction: PickByValue = GuildSettings.Selfmod.NewLines.SoftAction; + protected keyHardAction: PickByValue = GuildSettings.Selfmod.NewLines.HardAction; + protected keyHardActionDuration: PickByValue = GuildSettings.Selfmod.NewLines.HardActionDuration; + protected keyThresholdMaximum: PickByValue = GuildSettings.Selfmod.NewLines.ThresholdMaximum; + protected keyThresholdDuration: PickByValue = GuildSettings.Selfmod.NewLines.ThresholdDuration; +} diff --git a/projects/bot/src/commands/Management/Reaction Filters/reactionMode.ts b/projects/bot/src/commands/Management/Reaction Filters/reactionMode.ts new file mode 100644 index 000000000..d7b9df737 --- /dev/null +++ b/projects/bot/src/commands/Management/Reaction Filters/reactionMode.ts @@ -0,0 +1,20 @@ +import { AdderKey, GuildEntity, GuildSettings } from '#lib/database'; +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { SelfModerationCommand } from '#lib/moderation'; +import { ApplyOptions } from '@sapphire/decorators'; +import type { PickByValue } from '@sapphire/utilities'; + +@ApplyOptions({ + aliases: ['reaction-mode', 'r-mode'], + description: LanguageKeys.Commands.Management.ReactionModeDescription, + detailedDescription: LanguageKeys.Commands.Management.ReactionModeExtended +}) +export class UserSelfModerationCommand extends SelfModerationCommand { + protected $adder: AdderKey = 'reactions'; + protected keyEnabled: PickByValue = GuildSettings.Selfmod.Reactions.Enabled; + protected keySoftAction: PickByValue = GuildSettings.Selfmod.Reactions.SoftAction; + protected keyHardAction: PickByValue = GuildSettings.Selfmod.Reactions.HardAction; + protected keyHardActionDuration: PickByValue = GuildSettings.Selfmod.Reactions.HardActionDuration; + protected keyThresholdMaximum: PickByValue = GuildSettings.Selfmod.Reactions.ThresholdMaximum; + protected keyThresholdDuration: PickByValue = GuildSettings.Selfmod.Reactions.ThresholdDuration; +} diff --git a/projects/bot/src/commands/Moderation/Management/history.ts b/projects/bot/src/commands/Moderation/Management/history.ts new file mode 100644 index 000000000..c8702c397 --- /dev/null +++ b/projects/bot/src/commands/Moderation/Management/history.ts @@ -0,0 +1,145 @@ +import type { ModerationEntity } from '#lib/database'; +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { WolfCommand, SkyraPaginatedMessage } from '#lib/structures'; +import type { GuildMessage } from '#lib/types'; +import { PermissionLevels } from '#lib/types/Enums'; +import { seconds } from '#utils/common'; +import { getModeration } from '#utils/functions'; +import { TypeVariation } from '#utils/moderationConstants'; +import { sendLoadingMessage } from '#utils/util'; +import { time, TimestampStyles } from '@discordjs/builders'; +import type { Collection } from '@discordjs/collection'; +import { ApplyOptions, RequiresClientPermissions } from '@sapphire/decorators'; +import { CommandOptionsRunTypeEnum } from '@sapphire/framework'; +import { send } from '@sapphire/plugin-editable-commands'; +import { chunk, cutText } from '@sapphire/utilities'; +import { PermissionFlagsBits } from 'discord-api-types/v9'; +import { MessageEmbed } from 'discord.js'; + +const COLORS = [0x80f31f, 0xa5de0b, 0xc7c101, 0xe39e03, 0xf6780f, 0xfe5326, 0xfb3244]; + +@ApplyOptions({ + aliases: ['hd', 'ho'], + description: LanguageKeys.Commands.Moderation.HistoryDescription, + detailedDescription: LanguageKeys.Commands.Moderation.HistoryExtended, + permissionLevel: PermissionLevels.Moderator, + runIn: [CommandOptionsRunTypeEnum.GuildAny], + subCommands: ['details', { input: 'overview', default: true }] +}) +export class UserCommand extends WolfCommand { + public messageRun(message: GuildMessage, args: WolfCommand.Args, context: WolfCommand.Context) { + if (context.commandName === 'hd') return this.details(message, args); + if (context.commandName === 'ho') return this.overview(message, args); + return super.messageRun(message, args, context); + } + + public async overview(message: GuildMessage, args: WolfCommand.Args) { + const target = args.finished ? message.author : await args.pick('userName'); + const logs = await getModeration(message.guild).fetch(target.id); + let warnings = 0; + let mutes = 0; + let kicks = 0; + let bans = 0; + + for (const log of logs.values()) { + if (log.invalidated || log.appealType) continue; + switch (log.typeVariation) { + case TypeVariation.Ban: + case TypeVariation.SoftBan: + ++bans; + break; + case TypeVariation.Mute: + ++mutes; + break; + case TypeVariation.Kick: + ++kicks; + break; + case TypeVariation.Warning: + ++warnings; + } + } + + const index = Math.min(COLORS.length - 1, warnings + mutes + kicks + bans); + const footer = args.t(LanguageKeys.Commands.Moderation.HistoryFooterNew, { + warnings, + mutes, + kicks, + bans, + warningsText: args.t(LanguageKeys.Commands.Moderation.HistoryFooterWarning, { count: warnings }), + mutesText: args.t(LanguageKeys.Commands.Moderation.HistoryFooterMutes, { count: mutes }), + kicksText: args.t(LanguageKeys.Commands.Moderation.HistoryFooterKicks, { count: kicks }), + bansText: args.t(LanguageKeys.Commands.Moderation.HistoryFooterBans, { count: bans }) + }); + + const embed = new MessageEmbed() + .setColor(COLORS[index]) + .setAuthor({ name: target.username, iconURL: target.displayAvatarURL({ size: 128, format: 'png', dynamic: true }) }) + .setFooter({ text: footer }); + return send(message, { embeds: [embed] }); + } + + @RequiresClientPermissions(PermissionFlagsBits.EmbedLinks) + public async details(message: GuildMessage, args: WolfCommand.Args) { + const target = args.finished ? message.author : await args.pick('userName'); + const response = await sendLoadingMessage(message, args.t); + + const entries = (await getModeration(message.guild).fetch(target.id)).filter((log) => !log.invalidated && !log.appealType); + if (!entries.size) this.error(LanguageKeys.Commands.Moderation.ModerationsEmpty); + + const user = this.container.client.user!; + const display = new SkyraPaginatedMessage({ + template: new MessageEmbed() + .setColor(await this.container.db.fetchColor(message)) + .setAuthor({ name: user.username, iconURL: user.displayAvatarURL({ size: 128, format: 'png', dynamic: true }) }) + .setTitle(args.t(LanguageKeys.Commands.Moderation.ModerationsAmount, { count: entries.size })) + }); + + // Fetch usernames + const usernames = await this.fetchAllModerators(entries); + + // Lock in the current time + const now = Date.now(); + + for (const page of chunk([...entries.values()], 10)) { + display.addPageEmbed((embed) => { + for (const entry of page) { + const { name, value } = this.displayModerationLogFromModerators(usernames, now, entry); + embed.addField(name, value); + } + + return embed; + }); + } + + await display.run(response, message.author); + return response; + } + + private displayModerationLogFromModerators(users: Map, now: number, entry: ModerationEntity) { + const appealOrInvalidated = entry.appealType || entry.invalidated; + const remainingTime = + appealOrInvalidated || entry.duration === null || entry.createdAt === null ? null : entry.createdTimestamp + entry.duration! - Date.now(); + const expiredTime = remainingTime !== null && remainingTime <= 0; + const formattedModerator = users.get(entry.moderatorId!); + const formattedReason = entry.reason ? cutText(entry.reason, 800) : 'None'; + const formattedDuration = + remainingTime === null || expiredTime + ? '' + : `\nExpires: ${time(seconds.fromMilliseconds(now + remainingTime), TimestampStyles.RelativeTime)}`; + const formatter = expiredTime || appealOrInvalidated ? '~~' : ''; + + return { + name: `\`${entry.caseId}\` | ${entry.title}`, + value: `${formatter}Moderator: **${formattedModerator}**.\n${formattedReason}${formattedDuration}${formatter}` + }; + } + + private async fetchAllModerators(entries: Collection) { + const moderators = new Map() as Map; + for (const entry of entries.values()) { + const id = entry.moderatorId!; + if (!moderators.has(id)) moderators.set(id, (await entry.fetchModerator()).username); + } + return moderators; + } +} diff --git a/projects/bot/src/commands/Moderation/Management/moderations.ts b/projects/bot/src/commands/Moderation/Management/moderations.ts new file mode 100644 index 000000000..9561b4dab --- /dev/null +++ b/projects/bot/src/commands/Moderation/Management/moderations.ts @@ -0,0 +1,169 @@ +import type { ModerationEntity } from '#lib/database'; +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { PaginatedMessageCommand, SkyraPaginatedMessage } from '#lib/structures'; +import type { GuildMessage } from '#lib/types'; +import { PermissionLevels } from '#lib/types/Enums'; +import { seconds } from '#utils/common'; +import { getModeration } from '#utils/functions'; +import { TypeCodes } from '#utils/moderationConstants'; +import { sendLoadingMessage } from '#utils/util'; +import { time, TimestampStyles } from '@discordjs/builders'; +import type { Collection } from '@discordjs/collection'; +import { ApplyOptions } from '@sapphire/decorators'; +import { CommandOptionsRunTypeEnum } from '@sapphire/framework'; +import { chunk, cutText } from '@sapphire/utilities'; +import { MessageEmbed, User } from 'discord.js'; + +const enum Type { + Mute, + Warning, + All +} + +@ApplyOptions({ + aliases: ['moderation'], + description: LanguageKeys.Commands.Moderation.ModerationsDescription, + detailedDescription: LanguageKeys.Commands.Moderation.ModerationsExtended, + permissionLevel: PermissionLevels.Moderator, + runIn: [CommandOptionsRunTypeEnum.GuildAny], + subCommands: [ + { input: 'mute', output: 'mutes' }, + 'mutes', + { input: 'warning', output: 'warnings' }, + 'warnings', + { input: 'warn', output: 'warnings' }, + { input: 'warns', output: 'warnings' }, + { input: 'all', default: true } + ] +}) +export class UserPaginatedMessageCommand extends PaginatedMessageCommand { + public mutes(message: GuildMessage, args: PaginatedMessageCommand.Args, { commandPrefix }: PaginatedMessageCommand.Context) { + return this.handle(message, args, Type.Mute, commandPrefix); + } + + public warnings(message: GuildMessage, args: PaginatedMessageCommand.Args, { commandPrefix }: PaginatedMessageCommand.Context) { + return this.handle(message, args, Type.Warning, commandPrefix); + } + + public all(message: GuildMessage, args: PaginatedMessageCommand.Args, { commandPrefix }: PaginatedMessageCommand.Context) { + return this.handle(message, args, Type.All, commandPrefix); + } + + private async handle(message: GuildMessage, args: PaginatedMessageCommand.Args, action: Type, prefix: string) { + const target = args.finished ? null : await args.pick('userName'); + + const response = await sendLoadingMessage(message, args.t); + const moderation = getModeration(message.guild); + const entries = (await (target ? moderation.fetch(target.id) : moderation.fetch())).filter(this.getFilter(action, target)); + + if (!entries.size) this.error(LanguageKeys.Commands.Moderation.ModerationsEmpty, { prefix }); + + const user = this.container.client.user!; + const display = new SkyraPaginatedMessage({ + template: new MessageEmbed() + .setColor(await this.container.db.fetchColor(message)) + .setAuthor({ name: user.username, iconURL: user.displayAvatarURL({ size: 128, format: 'png', dynamic: true }) }) + .setTitle(args.t(LanguageKeys.Commands.Moderation.ModerationsAmount, { count: entries.size })) + }); + + // Fetch usernames + const usernames = await (target ? this.fetchAllModerators(entries) : this.fetchAllUsers(entries)); + + // Lock in the current time + const now = Date.now(); + + const displayName = action === Type.All; + const format = target + ? this.displayModerationLogFromModerators.bind(this, usernames, now, displayName) + : this.displayModerationLogFromUsers.bind(this, usernames, now, displayName); + + for (const page of chunk([...entries.values()], 10)) { + display.addPageEmbed((embed) => { + for (const entry of page) { + const { name, value } = format(entry); + embed.addField(name, value); + } + + return embed; + }); + } + + await display.run(response, message.author); + return response; + } + + private displayModerationLogFromModerators(users: Map, now: number, displayName: boolean, entry: ModerationEntity) { + const appealOrInvalidated = entry.appealType || entry.invalidated; + const remainingTime = + appealOrInvalidated || entry.duration === null || entry.createdAt === null ? null : entry.createdTimestamp + entry.duration! - Date.now(); + const expiredTime = remainingTime !== null && remainingTime <= 0; + const formattedModerator = users.get(entry.moderatorId!); + const formattedReason = entry.reason ? cutText(entry.reason, 800) : 'None'; + const formattedDuration = + remainingTime === null || expiredTime + ? '' + : `\nExpires: ${time(seconds.fromMilliseconds(now + remainingTime), TimestampStyles.RelativeTime)}`; + const formatter = appealOrInvalidated || expiredTime ? '~~' : ''; + + return { + name: `\`${entry.caseId}\`${displayName ? ` | ${entry.title}` : ''}`, + value: `${formatter}Moderator: **${formattedModerator}**.\n${formattedReason}${formattedDuration}${formatter}` + }; + } + + private displayModerationLogFromUsers(users: Map, now: number, displayName: boolean, entry: ModerationEntity) { + const appealOrInvalidated = entry.appealType || entry.invalidated; + const remainingTime = + appealOrInvalidated || entry.duration === null || entry.createdAt === null ? null : entry.createdTimestamp + entry.duration! - Date.now(); + const expiredTime = remainingTime !== null && remainingTime <= 0; + const formattedUser = users.get(entry.userId!); + const formattedReason = entry.reason ? cutText(entry.reason, 800) : 'None'; + const formattedDuration = + remainingTime === null || expiredTime + ? '' + : `\nExpires: ${time(seconds.fromMilliseconds(now + remainingTime), TimestampStyles.RelativeTime)}`; + const formatter = appealOrInvalidated || expiredTime ? '~~' : ''; + + return { + name: `\`${entry.caseId}\`${displayName ? ` | ${entry.title}` : ''}`, + value: `${formatter}Moderator: **${formattedUser}**.\n${formattedReason}${formattedDuration}${formatter}` + }; + } + + private async fetchAllUsers(entries: Collection) { + const users = new Map() as Map; + for (const entry of entries.values()) { + const id = entry.userId!; + if (!users.has(id)) users.set(id, (await entry.fetchUser()).username); + } + return users; + } + + private async fetchAllModerators(entries: Collection) { + const moderators = new Map() as Map; + for (const entry of entries.values()) { + const id = entry.moderatorId!; + if (!moderators.has(id)) moderators.set(id, (await entry.fetchModerator()).username); + } + return moderators; + } + + private getFilter(type: Type, target: User | null) { + switch (type) { + case Type.Mute: + return target + ? (entry: ModerationEntity) => + entry.isType(TypeCodes.Mute) && !entry.invalidated && !entry.appealType && entry.userId === target.id + : (entry: ModerationEntity) => entry.isType(TypeCodes.Mute) && !entry.invalidated && !entry.appealType; + case Type.Warning: + return target + ? (entry: ModerationEntity) => + entry.isType(TypeCodes.Warning) && !entry.invalidated && !entry.appealType && entry.userId === target.id + : (entry: ModerationEntity) => entry.isType(TypeCodes.Warning) && !entry.invalidated && !entry.appealType; + case Type.All: + return target + ? (entry: ModerationEntity) => entry.duration !== null && !entry.invalidated && !entry.appealType && entry.userId === target.id + : (entry: ModerationEntity) => entry.duration !== null && !entry.invalidated && !entry.appealType; + } + } +} diff --git a/projects/bot/src/commands/Moderation/Utilities/case.ts b/projects/bot/src/commands/Moderation/Utilities/case.ts new file mode 100644 index 000000000..ba6aa3667 --- /dev/null +++ b/projects/bot/src/commands/Moderation/Utilities/case.ts @@ -0,0 +1,45 @@ +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { WolfCommand } from '#lib/structures'; +import type { GuildMessage } from '#lib/types'; +import { PermissionLevels } from '#lib/types/Enums'; +import { getModeration } from '#utils/functions'; +import { ApplyOptions } from '@sapphire/decorators'; +import { CommandOptionsRunTypeEnum } from '@sapphire/framework'; +import { send } from '@sapphire/plugin-editable-commands'; +import { PermissionFlagsBits } from 'discord-api-types/v9'; + +@ApplyOptions({ + description: LanguageKeys.Commands.Moderation.CaseDescription, + detailedDescription: LanguageKeys.Commands.Moderation.CaseExtended, + permissionLevel: PermissionLevels.Moderator, + requiredClientPermissions: [PermissionFlagsBits.EmbedLinks], + runIn: [CommandOptionsRunTypeEnum.GuildAny], + subCommands: ['delete', { input: 'show', default: true }] +}) +export class UserCommand extends WolfCommand { + public async show(message: GuildMessage, args: WolfCommand.Args) { + const caseId = await args.pick('case'); + + const moderation = getModeration(message.guild); + const entry = await moderation.fetch(caseId); + if (entry) { + const embed = await entry.prepareEmbed(); + return send(message, { embeds: [embed] }); + } + this.error(LanguageKeys.Commands.Moderation.ReasonNotExists); + } + + public async delete(message: GuildMessage, args: WolfCommand.Args) { + const caseId = await args.pick('case'); + + const moderation = getModeration(message.guild); + const entry = await moderation.fetch(caseId); + if (!entry) this.error(LanguageKeys.Commands.Moderation.ReasonNotExists); + + entry.remove(); + moderation.delete(entry.caseId); + + const content = args.t(LanguageKeys.Commands.Moderation.CaseDeleted, { case: entry.caseId }); + return send(message, content); + } +} diff --git a/projects/bot/src/commands/Moderation/Utilities/permissions.ts b/projects/bot/src/commands/Moderation/Utilities/permissions.ts new file mode 100644 index 000000000..4d9ab23bf --- /dev/null +++ b/projects/bot/src/commands/Moderation/Utilities/permissions.ts @@ -0,0 +1,45 @@ +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { WolfCommand } from '#lib/structures'; +import type { GuildMessage } from '#lib/types'; +import { PermissionLevels } from '#lib/types/Enums'; +import { ZeroWidthSpace } from '#utils/constants'; +import { ApplyOptions } from '@sapphire/decorators'; +import { CommandOptionsRunTypeEnum } from '@sapphire/framework'; +import { send } from '@sapphire/plugin-editable-commands'; +import { PermissionFlagsBits } from 'discord-api-types/v9'; +import { MessageEmbed, Permissions, PermissionString } from 'discord.js'; + +const PERMISSION_FLAGS = Object.keys(Permissions.FLAGS) as PermissionString[]; + +@ApplyOptions({ + description: LanguageKeys.Commands.Moderation.PermissionsDescription, + detailedDescription: LanguageKeys.Commands.Moderation.PermissionsExtended, + permissionLevel: PermissionLevels.Administrator, + requiredClientPermissions: [PermissionFlagsBits.EmbedLinks], + runIn: [CommandOptionsRunTypeEnum.GuildAny] +}) +export class UserCommand extends WolfCommand { + public async messageRun(message: GuildMessage, args: WolfCommand.Args) { + const user = args.finished ? message.author : await args.pick('userName'); + const member = await message.guild.members.fetch(user.id).catch(() => { + this.error(LanguageKeys.Misc.UserNotInGuild); + }); + + const { permissions } = member; + const list = [ZeroWidthSpace]; + + if (permissions.has(Permissions.FLAGS.ADMINISTRATOR)) { + list.push(args.t(LanguageKeys.Commands.Moderation.PermissionsAll)); + } else { + for (const flag of PERMISSION_FLAGS) { + list.push(`${permissions.has(flag) ? '🔹' : '🔸'} ${args.t(`permissions:${flag}`, flag)}`); + } + } + + const embed = new MessageEmbed() + .setColor(await this.container.db.fetchColor(message)) + .setTitle(args.t(LanguageKeys.Commands.Moderation.Permissions, { username: user.tag, id: user.id })) + .setDescription(list.join('\n')); + return send(message, { embeds: [embed] }); + } +} diff --git a/projects/bot/src/commands/Moderation/Utilities/reason.ts b/projects/bot/src/commands/Moderation/Utilities/reason.ts new file mode 100644 index 000000000..ea8c210ea --- /dev/null +++ b/projects/bot/src/commands/Moderation/Utilities/reason.ts @@ -0,0 +1,57 @@ +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { WolfCommand } from '#lib/structures'; +import type { GuildMessage } from '#lib/types'; +import { Events, PermissionLevels } from '#lib/types/Enums'; +import { getModeration, sendTemporaryMessage } from '#utils/functions'; +import { getImage } from '#utils/util'; +import { ApplyOptions } from '@sapphire/decorators'; +import { CommandOptionsRunTypeEnum } from '@sapphire/framework'; +import { PermissionFlagsBits } from 'discord-api-types/v9'; + +@ApplyOptions({ + description: LanguageKeys.Commands.Moderation.ReasonDescription, + detailedDescription: LanguageKeys.Commands.Moderation.ReasonExtended, + permissionLevel: PermissionLevels.Moderator, + requiredClientPermissions: [PermissionFlagsBits.EmbedLinks], + runIn: [CommandOptionsRunTypeEnum.GuildAny] +}) +export class UserCommand extends WolfCommand { + public async messageRun(message: GuildMessage, args: WolfCommand.Args) { + const cases = await args + .pick('case') + .then((value) => [value]) + .catch(() => args.pick('range', { maximum: 50 })); + + const moderation = getModeration(message.guild); + const entries = await moderation.fetch(cases); + if (!entries.size) { + this.error(LanguageKeys.Commands.Moderation.ModerationCaseNotExists, { count: cases.length }); + } + + const reason = await args.rest('string'); + const imageURL = getImage(message); + const { moderations } = this.container.db; + await moderations + .createQueryBuilder() + .update() + .where('guild_id = :guild', { guild: message.guild.id }) + .andWhere('case_id IN (:...ids)', { ids: [...entries.keys()] }) + .set({ reason, imageURL }) + .execute(); + await moderation.fetchChannelMessages(); + for (const entry of entries.values()) { + const clone = entry.clone(); + entry.setReason(reason).setImageURL(imageURL); + this.container.client.emit(Events.ModerationEntryEdit, clone, entry); + } + + return sendTemporaryMessage( + message, + args.t(LanguageKeys.Commands.Moderation.ReasonUpdated, { + entries: cases, + newReason: reason, + count: cases.length + }) + ); + } +} diff --git a/src/commands/Moderation/Utilities/slowmode.ts b/projects/bot/src/commands/Moderation/Utilities/slowmode.ts similarity index 81% rename from src/commands/Moderation/Utilities/slowmode.ts rename to projects/bot/src/commands/Moderation/Utilities/slowmode.ts index 21fbc6cbd..cdcc14d7d 100644 --- a/src/commands/Moderation/Utilities/slowmode.ts +++ b/projects/bot/src/commands/Moderation/Utilities/slowmode.ts @@ -1,11 +1,13 @@ import { LanguageKeys } from '#lib/i18n/languageKeys'; import { WolfCommand } from '#lib/structures'; -import { PermissionLevels, type GuildMessage } from '#lib/types'; +import type { GuildMessage } from '#lib/types/Discord'; +import { PermissionLevels } from '#lib/types/Enums'; import { hours, seconds } from '#utils/common'; import { ApplyOptions } from '@sapphire/decorators'; import { CommandOptionsRunTypeEnum } from '@sapphire/framework'; import { send } from '@sapphire/plugin-editable-commands'; -import { PermissionFlagsBits, type TextChannel } from 'discord.js'; +import { PermissionFlagsBits } from 'discord-api-types/v9'; +import type { TextChannel } from 'discord.js'; const MAXIMUM_DURATION = hours(6); @@ -18,7 +20,7 @@ const MAXIMUM_DURATION = hours(6); runIn: [CommandOptionsRunTypeEnum.GuildText] }) export class UserCommand extends WolfCommand { - public override async messageRun(message: GuildMessage, args: WolfCommand.Args) { + public async messageRun(message: GuildMessage, args: WolfCommand.Args) { const cooldown = await args .pick('reset') .then(() => 0) diff --git a/projects/bot/src/commands/Moderation/Utilities/time.ts b/projects/bot/src/commands/Moderation/Utilities/time.ts new file mode 100644 index 000000000..3fb0b0647 --- /dev/null +++ b/projects/bot/src/commands/Moderation/Utilities/time.ts @@ -0,0 +1,142 @@ +import type { ModerationEntity } from '#lib/database'; +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { WolfCommand } from '#lib/structures'; +import type { GuildMessage } from '#lib/types'; +import { PermissionLevels } from '#lib/types/Enums'; +import { seconds, years } from '#utils/common'; +import { getModeration, getSecurity } from '#utils/functions'; +import { SchemaKeys, TypeCodes } from '#utils/moderationConstants'; +import { ApplyOptions } from '@sapphire/decorators'; +import { Args, CommandOptionsRunTypeEnum } from '@sapphire/framework'; +import { send } from '@sapphire/plugin-editable-commands'; +import { Permissions, User } from 'discord.js'; + +@ApplyOptions({ + description: LanguageKeys.Commands.Moderation.TimeDescription, + detailedDescription: LanguageKeys.Commands.Moderation.TimeExtended, + permissionLevel: PermissionLevels.Moderator, + runIn: [CommandOptionsRunTypeEnum.GuildAny] +}) +export class UserCommand extends WolfCommand { + public async messageRun(message: GuildMessage, args: WolfCommand.Args) { + const cancel = await args.pick(UserCommand.cancel).catch(() => false); + const caseId = await args.pick('case'); + + const moderation = getModeration(message.guild); + const entry = await moderation.fetch(caseId); + if (!entry) this.error(LanguageKeys.Commands.Moderation.ModerationCaseNotExists, { count: 1 }); + if (!cancel && entry.temporaryType) this.error(LanguageKeys.Commands.Moderation.TimeTimed); + + const user = await entry.fetchUser(); + await this.validateAction(message, entry, user); + const task = this.container.schedule.queue.find( + (tk) => tk.data && tk.data[SchemaKeys.Case] === entry.caseId && tk.data[SchemaKeys.Guild] === entry.guild.id + )!; + + if (cancel) { + if (!task) this.error(LanguageKeys.Commands.Moderation.TimeNotScheduled); + + await moderation.fetchChannelMessages(); + await entry.edit({ + duration: null, + moderatorId: message.author.id + }); + + this.error(LanguageKeys.Commands.Moderation.TimeAborted, { title: entry.title }); + } + + if (entry.appealType || entry.invalidated) { + this.error(LanguageKeys.Commands.Moderation.ModerationLogAppealed); + } + + if (task) { + this.error(LanguageKeys.Commands.Moderation.ModerationTimed, { + remaining: (task.data.timestamp as number) - Date.now() + }); + } + + const duration = await args.rest('timespan', { minimum: seconds(1), maximum: years(5) }); + await moderation.fetchChannelMessages(); + await entry.edit({ + duration, + moderatorId: message.author.id + }); + + const content = args.t(LanguageKeys.Commands.Moderation.TimeScheduled, { title: entry.title, user, time: duration! }); + return send(message, content); + } + + private async validateAction(message: GuildMessage, modlog: ModerationEntity, user: User) { + switch (modlog.type) { + case TypeCodes.FastTemporaryBan: + case TypeCodes.TemporaryBan: + case TypeCodes.Ban: + return this.checkBan(message, user); + case TypeCodes.FastTemporaryMute: + case TypeCodes.TemporaryMute: + case TypeCodes.Mute: + return this.checkMute(message, user); + case TypeCodes.FastTemporaryVoiceMute: + case TypeCodes.TemporaryVoiceMute: + case TypeCodes.VoiceMute: + return this.checkVMute(message, user); + case TypeCodes.Warning: + case TypeCodes.FastTemporaryWarning: + case TypeCodes.TemporaryWarning: + // TODO(kyranet): Add checks for restrictions + case TypeCodes.RestrictionAttachment: + case TypeCodes.FastTemporaryRestrictionAttachment: + case TypeCodes.TemporaryRestrictionAttachment: + case TypeCodes.RestrictionEmbed: + case TypeCodes.FastTemporaryRestrictionEmbed: + case TypeCodes.TemporaryRestrictionEmbed: + case TypeCodes.RestrictionEmoji: + case TypeCodes.FastTemporaryRestrictionEmoji: + case TypeCodes.TemporaryRestrictionEmoji: + case TypeCodes.RestrictionReaction: + case TypeCodes.FastTemporaryRestrictionReaction: + case TypeCodes.TemporaryRestrictionReaction: + case TypeCodes.RestrictionVoice: + case TypeCodes.FastTemporaryRestrictionVoice: + case TypeCodes.TemporaryRestrictionVoice: + return; + default: + this.error(LanguageKeys.Commands.Moderation.TimeUnsupportedType); + } + } + + private async checkBan(message: GuildMessage, user: User) { + if (!message.guild.me!.permissions.has(Permissions.FLAGS.BAN_MEMBERS)) { + this.error(LanguageKeys.Commands.Moderation.UnbanMissingPermission); + } + + if (!(await getSecurity(message.guild).actions.userIsBanned(user))) { + this.error(LanguageKeys.Commands.Moderation.GuildBansNotFound); + } + } + + private async checkMute(message: GuildMessage, user: User) { + if (!message.guild.me!.permissions.has(Permissions.FLAGS.MANAGE_ROLES)) { + this.error(LanguageKeys.Commands.Moderation.UnmuteMissingPermission); + } + + if (!(await getSecurity(message.guild).actions.userIsMuted(user))) { + this.error(LanguageKeys.Commands.Moderation.MuteUserNotMuted); + } + } + + private async checkVMute(message: GuildMessage, user: User) { + if (!message.guild.me!.permissions.has(Permissions.FLAGS.MUTE_MEMBERS)) { + this.error(LanguageKeys.Commands.Moderation.VmuteMissingPermission); + } + + if (!(await getSecurity(message.guild).actions.userIsVoiceMuted(user))) { + this.error(LanguageKeys.Commands.Moderation.VmuteUserNotMuted); + } + } + + private static cancel = Args.make((parameter, { argument }) => { + if (parameter.toLowerCase() === 'cancel') return Args.ok(true); + return Args.error({ argument, parameter }); + }); +} diff --git a/projects/bot/src/commands/Moderation/addrole.ts b/projects/bot/src/commands/Moderation/addrole.ts new file mode 100644 index 000000000..f17cf4b09 --- /dev/null +++ b/projects/bot/src/commands/Moderation/addrole.ts @@ -0,0 +1,44 @@ +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { HandledCommandContext, ModerationCommand } from '#lib/moderation'; +import type { GuildMessage } from '#lib/types'; +import { PermissionLevels } from '#lib/types/Enums'; +import { years } from '#utils/common'; +import { getSecurity } from '#utils/functions'; +import { getImage } from '#utils/util'; +import { ApplyOptions } from '@sapphire/decorators'; +import { PermissionFlagsBits } from 'discord-api-types/v9'; +import type { Role } from 'discord.js'; + +@ApplyOptions({ + aliases: ['ar'], + description: LanguageKeys.Commands.Moderation.AddRoleDescription, + detailedDescription: LanguageKeys.Commands.Moderation.AddRoleExtended, + optionalDuration: true, + permissionLevel: PermissionLevels.Administrator, + requiredClientPermissions: [PermissionFlagsBits.ManageRoles], + requiredMember: true +}) +export class UserModerationCommand extends ModerationCommand { + protected async resolveOverloads(args: ModerationCommand.Args) { + return { + targets: await args.repeat('user', { times: 10 }), + role: await args.pick('roleName'), + duration: this.optionalDuration ? await args.pick('timespan', { minimum: 0, maximum: years(5) }).catch(() => null) : null, + reason: args.finished ? null : await args.rest('string') + }; + } + + protected async handle(message: GuildMessage, context: HandledCommandContext & { role: Role }) { + return getSecurity(message.guild).actions.addRole( + { + userId: context.target.id, + moderatorId: message.author.id, + reason: context.reason, + imageURL: getImage(message), + duration: context.duration + }, + context.role, + await this.getTargetDM(message, context.args, context.target) + ); + } +} diff --git a/projects/bot/src/commands/Moderation/ban.ts b/projects/bot/src/commands/Moderation/ban.ts new file mode 100644 index 000000000..16858e68b --- /dev/null +++ b/projects/bot/src/commands/Moderation/ban.ts @@ -0,0 +1,57 @@ +import { GuildSettings, readSettings } from '#lib/database'; +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { ModerationCommand } from '#lib/moderation'; +import { getModeration, getSecurity } from '#utils/functions'; +import type { Unlock } from '#utils/moderationConstants'; +import { getImage } from '#utils/util'; +import { ApplyOptions } from '@sapphire/decorators'; +import type { ArgumentTypes } from '@sapphire/utilities'; +import { PermissionFlagsBits } from 'discord-api-types/v9'; + +@ApplyOptions({ + aliases: ['b'], + description: LanguageKeys.Commands.Moderation.BanDescription, + detailedDescription: LanguageKeys.Commands.Moderation.BanExtended, + optionalDuration: true, + options: ['d', 'day', 'days'], + requiredClientPermissions: [PermissionFlagsBits.BanMembers], + requiredMember: false +}) +export class UserModerationCommand extends ModerationCommand { + public async prehandle(...[message]: ArgumentTypes) { + return (await readSettings(message.guild, GuildSettings.Events.BanAdd)) ? { unlock: getModeration(message.guild).createLock() } : null; + } + + public async handle(...[message, context]: ArgumentTypes) { + return getSecurity(message.guild).actions.ban( + { + userId: context.target.id, + moderatorId: message.author.id, + duration: context.duration, + imageURL: getImage(message), + reason: context.reason + }, + await this.getDays(context.args), + await this.getTargetDM(message, context.args, context.target) + ); + } + + public posthandle(...[, { preHandled }]: ArgumentTypes['posthandle']>) { + if (preHandled) preHandled.unlock(); + } + + public async checkModeratable(...[message, context]: ArgumentTypes['checkModeratable']>) { + const member = await super.checkModeratable(message, context); + if (member && !member.bannable) throw context.args.t(LanguageKeys.Commands.Moderation.BanNotBannable); + return member; + } + + private async getDays(args: ModerationCommand.Args) { + const value = args.getOption('d', 'day', 'days'); + if (value === null) return 0; + + const parsed = Number(value); + if (Number.isInteger(parsed) && parsed >= 0 && parsed <= 7) return parsed; + return 0; + } +} diff --git a/src/commands/Moderation/dehoist.ts b/projects/bot/src/commands/Moderation/dehoist.ts similarity index 82% rename from src/commands/Moderation/dehoist.ts rename to projects/bot/src/commands/Moderation/dehoist.ts index 19bee6888..304d8a03a 100644 --- a/src/commands/Moderation/dehoist.ts +++ b/projects/bot/src/commands/Moderation/dehoist.ts @@ -1,14 +1,15 @@ import { LanguageKeys } from '#lib/i18n/languageKeys'; import { WolfCommand } from '#lib/structures'; -import { PermissionLevels, type GuildMessage } from '#lib/types'; -import { getColor, sendLoadingMessage } from '#utils/util'; -import { EmbedBuilder } from '@discordjs/builders'; +import type { GuildMessage } from '#lib/types'; +import { PermissionLevels } from '#lib/types/Enums'; +import { sendLoadingMessage } from '#utils/util'; import { ApplyOptions } from '@sapphire/decorators'; import { CommandOptionsRunTypeEnum } from '@sapphire/framework'; import { send } from '@sapphire/plugin-editable-commands'; -import type { TFunction } from '@sapphire/plugin-i18next'; import { codeBlock } from '@sapphire/utilities'; -import { PermissionFlagsBits, type GuildMember } from 'discord.js'; +import { PermissionFlagsBits } from 'discord-api-types/v9'; +import { GuildMember, MessageEmbed } from 'discord.js'; +import type { TFunction } from 'i18next'; const [kLowestNumberCode, kHighestNumberCode] = ['0'.charCodeAt(0), '9'.charCodeAt(0)]; @@ -23,7 +24,7 @@ const [kLowestNumberCode, kHighestNumberCode] = ['0'.charCodeAt(0), '9'.charCode export class UserCommand extends WolfCommand { private kLowestCode = 'A'.charCodeAt(0); - public override async messageRun(message: GuildMessage, args: WolfCommand.Args) { + public async messageRun(message: GuildMessage, args: WolfCommand.Args) { if (message.guild.members.cache.size !== message.guild.memberCount) { await sendLoadingMessage(message, args.t); await message.guild.members.fetch(); @@ -66,7 +67,7 @@ export class UserCommand extends WolfCommand { } // We're done! - const embed = this.prepareFinalEmbed(message, args.t, counter, errored); + const embed = await this.prepareFinalEmbed(message, args.t, counter, errored); return send(message, { embeds: [embed] }); } @@ -80,14 +81,14 @@ export class UserCommand extends WolfCommand { return char < this.kLowestCode && (char < kLowestNumberCode || char > kHighestNumberCode); } - private prepareFinalEmbed(message: GuildMessage, t: TFunction, deHoistedMembers: number, erroredChanges: ErroredChange[]) { + private async prepareFinalEmbed(message: GuildMessage, t: TFunction, deHoistedMembers: number, erroredChanges: ErroredChange[]) { const embedLanguage = t(LanguageKeys.Commands.Moderation.DehoistEmbed, { dehoistedMemberCount: deHoistedMembers, dehoistedWithErrorsCount: deHoistedMembers - erroredChanges.length, errored: erroredChanges.length, users: message.guild.members.cache.size }); - const embed = new EmbedBuilder().setColor(getColor(message)).setTitle(embedLanguage.title); + const embed = new MessageEmbed().setColor(await this.container.db.fetchColor(message)).setTitle(embedLanguage.title); let { description } = embedLanguage; if (deHoistedMembers <= 0) description = embedLanguage.descriptionNoone; @@ -96,7 +97,7 @@ export class UserCommand extends WolfCommand { description = erroredChanges.length > 1 ? embedLanguage.descriptionWithMultipleErrors : embedLanguage.descriptionWithError; const erroredNicknames = erroredChanges.map((entry) => `${entry.oldNick} => ${entry.newNick}`).join('\n'); const codeblock = codeBlock('js', erroredNicknames); - embed.addFields({ name: embedLanguage.fieldErrorTitle, value: codeblock }); + embed.addField(embedLanguage.fieldErrorTitle, codeblock); } return embed.setDescription(description); diff --git a/projects/bot/src/commands/Moderation/kick.ts b/projects/bot/src/commands/Moderation/kick.ts new file mode 100644 index 000000000..0e797c9c5 --- /dev/null +++ b/projects/bot/src/commands/Moderation/kick.ts @@ -0,0 +1,46 @@ +import { GuildSettings, readSettings } from '#lib/database'; +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { ModerationCommand } from '#lib/moderation'; +import { getModeration, getSecurity } from '#utils/functions'; +import type { Unlock } from '#utils/moderationConstants'; +import { getImage } from '#utils/util'; +import { ApplyOptions } from '@sapphire/decorators'; +import type { ArgumentTypes } from '@sapphire/utilities'; +import { PermissionFlagsBits } from 'discord-api-types/v9'; + +@ApplyOptions({ + aliases: ['k'], + description: LanguageKeys.Commands.Moderation.KickDescription, + detailedDescription: LanguageKeys.Commands.Moderation.KickExtended, + requiredClientPermissions: [PermissionFlagsBits.KickMembers], + requiredMember: true +}) +export class UserModerationCommand extends ModerationCommand { + public async prehandle(...[message]: ArgumentTypes) { + return (await readSettings(message.guild, GuildSettings.Channels.Logs.MemberRemove)) + ? { unlock: getModeration(message.guild).createLock() } + : null; + } + + public async handle(...[message, context]: ArgumentTypes) { + return getSecurity(message.guild).actions.kick( + { + userId: context.target.id, + moderatorId: message.author.id, + reason: context.reason, + imageURL: getImage(message) + }, + await this.getTargetDM(message, context.args, context.target) + ); + } + + public posthandle(...[, { preHandled }]: ArgumentTypes['posthandle']>) { + if (preHandled) preHandled.unlock(); + } + + public async checkModeratable(...[message, context]: ArgumentTypes) { + const member = await super.checkModeratable(message, context); + if (member && !member.kickable) throw context.args.t(LanguageKeys.Commands.Moderation.KickNotKickable); + return member; + } +} diff --git a/src/commands/Moderation/lockdown.ts b/projects/bot/src/commands/Moderation/lockdown.ts similarity index 77% rename from src/commands/Moderation/lockdown.ts rename to projects/bot/src/commands/Moderation/lockdown.ts index 7c50f61c3..0e27a3bfb 100644 --- a/src/commands/Moderation/lockdown.ts +++ b/projects/bot/src/commands/Moderation/lockdown.ts @@ -1,37 +1,35 @@ import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { LockdownManager, WolfSubcommand } from '#lib/structures'; -import { PermissionLevels, type GuildMessage } from '#lib/types'; -import { clearAccurateTimeout, setAccurateTimeout } from '#utils/Timers'; +import { LockdownManager, WolfCommand } from '#lib/structures'; +import type { GuildMessage } from '#lib/types'; +import { PermissionLevels } from '#lib/types/Enums'; import { floatPromise } from '#utils/common'; import { assertNonThread, getSecurity } from '#utils/functions'; +import { clearAccurateTimeout, setAccurateTimeout } from '#utils/Timers'; import { ApplyOptions } from '@sapphire/decorators'; -import { canSendMessages, type NonThreadGuildTextBasedChannelTypes } from '@sapphire/discord.js-utilities'; +import { canSendMessages, NonThreadGuildTextBasedChannelTypes } from '@sapphire/discord.js-utilities'; import { CommandOptionsRunTypeEnum } from '@sapphire/framework'; import { send } from '@sapphire/plugin-editable-commands'; -import type { TFunction } from '@sapphire/plugin-i18next'; -import { PermissionFlagsBits, type Role } from 'discord.js'; +import { PermissionFlagsBits } from 'discord-api-types/v9'; +import { Permissions, Role } from 'discord.js'; +import type { TFunction } from 'i18next'; -@ApplyOptions({ +@ApplyOptions({ aliases: ['lock', 'unlock'], description: LanguageKeys.Commands.Moderation.LockdownDescription, detailedDescription: LanguageKeys.Commands.Moderation.LockdownExtended, permissionLevel: PermissionLevels.Moderator, requiredClientPermissions: [PermissionFlagsBits.ManageChannels, PermissionFlagsBits.ManageRoles], runIn: [CommandOptionsRunTypeEnum.GuildAny], - subcommands: [ - { name: 'lock', messageRun: 'lock' }, - { name: 'unlock', messageRun: 'unlock' }, - { name: 'auto', messageRun: 'auto', default: true } - ] + subCommands: ['lock', 'unlock', { input: 'auto', default: true }] }) -export class UserCommand extends WolfSubcommand { - public override messageRun(message: GuildMessage, args: WolfSubcommand.Args, context: WolfSubcommand.RunContext) { +export class UserCommand extends WolfCommand { + public messageRun(message: GuildMessage, args: WolfCommand.Args, context: WolfCommand.Context) { if (context.commandName === 'lock') return this.lock(message, args); if (context.commandName === 'unlock') return this.unlock(message, args); return super.messageRun(message, args, context); } - public async auto(message: GuildMessage, args: WolfSubcommand.Args) { + public async auto(message: GuildMessage, args: WolfCommand.Args) { const role = await args.pick('roleName').catch(() => message.guild.roles.everyone); const channel = args.finished ? assertNonThread(message.channel) : await args.pick('textChannelName'); if (this.getLock(role, channel)) return this.handleUnlock(message, args, role, channel); @@ -40,13 +38,13 @@ export class UserCommand extends WolfSubcommand { return this.handleLock(message, args, role, channel, duration); } - public async unlock(message: GuildMessage, args: WolfSubcommand.Args) { + public async unlock(message: GuildMessage, args: WolfCommand.Args) { const role = await args.pick('roleName').catch(() => message.guild.roles.everyone); const channel = args.finished ? assertNonThread(message.channel) : await args.pick('textChannelName'); return this.handleUnlock(message, args, role, channel); } - public async lock(message: GuildMessage, args: WolfSubcommand.Args) { + public async lock(message: GuildMessage, args: WolfCommand.Args) { const role = await args.pick('roleName').catch(() => message.guild.roles.everyone); const channel = args.finished ? assertNonThread(message.channel) : await args.pick('textChannelName'); const duration = args.finished ? null : await args.pick('timespan', { minimum: 0 }); @@ -55,7 +53,7 @@ export class UserCommand extends WolfSubcommand { private async handleLock( message: GuildMessage, - args: WolfSubcommand.Args, + args: WolfCommand.Args, role: Role, channel: NonThreadGuildTextBasedChannelTypes, duration: number | null @@ -70,7 +68,7 @@ export class UserCommand extends WolfSubcommand { // If they can send, begin locking const response = await send(message, args.t(LanguageKeys.Commands.Moderation.LockdownLocking, { channel: channel.toString() })); - await channel.permissionOverwrites.edit(role, { SendMessages: false }); + await channel.permissionOverwrites.edit(role, { SEND_MESSAGES: false }); if (canSendMessages(message.channel)) { await response.edit(args.t(LanguageKeys.Commands.Moderation.LockdownLock, { channel: channel.toString() })).catch(() => null); } @@ -83,10 +81,10 @@ export class UserCommand extends WolfSubcommand { } private isAllowed(role: Role, channel: NonThreadGuildTextBasedChannelTypes): boolean | null { - return channel.permissionOverwrites.cache.get(role.id)?.allow.has(PermissionFlagsBits.SendMessages, false) ?? null; + return channel.permissionOverwrites.cache.get(role.id)?.allow.has(Permissions.FLAGS.SEND_MESSAGES, false) ?? null; } - private async handleUnlock(message: GuildMessage, args: WolfSubcommand.Args, role: Role, channel: NonThreadGuildTextBasedChannelTypes) { + private async handleUnlock(message: GuildMessage, args: WolfCommand.Args, role: Role, channel: NonThreadGuildTextBasedChannelTypes) { const entry = this.getLock(role, channel); if (entry === null) this.error(LanguageKeys.Commands.Moderation.LockdownUnlocked, { channel: channel.toString() }); if (entry.timeout) clearAccurateTimeout(entry.timeout); @@ -107,10 +105,10 @@ export class UserCommand extends WolfSubcommand { // If the only permission overwrite is the denied SEND_MESSAGES, clean up the entire permission; if the permission // was denied, reset it to the default state, otherwise don't run an extra query - if (overwrites.allow.bitfield === 0n && overwrites.deny.bitfield === PermissionFlagsBits.SendMessages) { + if (overwrites.allow.bitfield === 0n && overwrites.deny.bitfield === Permissions.FLAGS.SEND_MESSAGES) { await overwrites.delete(); - } else if (overwrites.deny.has(PermissionFlagsBits.SendMessages)) { - await overwrites.edit({ SendMessages: allowed }); + } else if (overwrites.deny.has(Permissions.FLAGS.SEND_MESSAGES)) { + await overwrites.edit({ SEND_MESSAGES: allowed }); } if (canSendMessages(message.channel)) { @@ -123,7 +121,7 @@ export class UserCommand extends WolfSubcommand { const entry = getSecurity(channel.guild).lockdowns.get(channel.id)?.get(role.id); if (entry) return entry; - const permissions = channel.permissionOverwrites.cache.get(role.id)?.deny.has(PermissionFlagsBits.SendMessages); + const permissions = channel.permissionOverwrites.cache.get(role.id)?.deny.has(Permissions.FLAGS.SEND_MESSAGES); return permissions === true ? { allowed: null, timeout: null } : null; } } diff --git a/projects/bot/src/commands/Moderation/mute.ts b/projects/bot/src/commands/Moderation/mute.ts new file mode 100644 index 000000000..d63b5b06b --- /dev/null +++ b/projects/bot/src/commands/Moderation/mute.ts @@ -0,0 +1,34 @@ +import { GuildSettings } from '#lib/database'; +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { SetUpModerationCommand } from '#lib/moderation'; +import { getSecurity } from '#utils/functions'; +import { ModerationSetupRestriction } from '#utils/Security/ModerationActions'; +import { getImage } from '#utils/util'; +import { ApplyOptions } from '@sapphire/decorators'; +import type { ArgumentTypes } from '@sapphire/utilities'; +import { PermissionFlagsBits } from 'discord-api-types/v9'; + +@ApplyOptions({ + aliases: ['m'], + description: LanguageKeys.Commands.Moderation.MuteDescription, + detailedDescription: LanguageKeys.Commands.Moderation.MuteExtended, + optionalDuration: true, + requiredClientPermissions: [PermissionFlagsBits.ManageRoles], + requiredMember: true, + roleKey: GuildSettings.Roles.Muted, + setUpKey: ModerationSetupRestriction.All +}) +export class UserSetUpModerationCommand extends SetUpModerationCommand { + public async handle(...[message, context]: ArgumentTypes) { + return getSecurity(message.guild).actions.mute( + { + userId: context.target.id, + moderatorId: message.author.id, + reason: context.reason, + imageURL: getImage(message), + duration: context.duration + }, + await this.getTargetDM(message, context.args, context.target) + ); + } +} diff --git a/projects/bot/src/commands/Moderation/prune.ts b/projects/bot/src/commands/Moderation/prune.ts new file mode 100644 index 000000000..b21fa45c2 --- /dev/null +++ b/projects/bot/src/commands/Moderation/prune.ts @@ -0,0 +1,212 @@ +import { GuildSettings, readSettings, writeSettings } from '#lib/database'; +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { WolfCommand } from '#lib/structures'; +import type { GuildMessage } from '#lib/types'; +import { PermissionLevels } from '#lib/types/Enums'; +import { days, floatPromise, seconds } from '#utils/common'; +import { andMix, BooleanFn } from '#utils/common/comparators'; +import { formatMessage } from '#utils/formatters'; +import { sendTemporaryMessage } from '#utils/functions'; +import { urlRegex } from '#utils/Links/UrlRegex'; +import { metadata, TypeCodes } from '#utils/moderationConstants'; +import { getImageUrl } from '#utils/util'; +import { ApplyOptions } from '@sapphire/decorators'; +import { canSendAttachments } from '@sapphire/discord.js-utilities'; +import { Args, CommandOptionsRunTypeEnum, IArgument } from '@sapphire/framework'; +import { isNullish, isNullishOrEmpty } from '@sapphire/utilities'; +import { PermissionFlagsBits, RESTJSONErrorCodes } from 'discord-api-types/v9'; +import { Collection, MessageAttachment, MessageEmbed, TextChannel } from 'discord.js'; +import type { TFunction } from 'i18next'; + +const enum Position { + Before, + After +} + +const attachmentsFlags = ['f', 'file', 'files', 'upload', 'uploads'] as const; +const imageFlags = ['img', 'image', 'images'] as const; +const authorFlags = ['a', 'author', 'me'] as const; +const botsFlags = ['b', 'bot', 'bots'] as const; +const humansFlags = ['h', 'human', 'humans'] as const; +const invitesFlags = ['i', 'inv', 'invite', 'invites'] as const; +const linksFlags = ['l', 'link', 'links'] as const; +const youFlags = ['y', 'you', 'skyra'] as const; +const pinsFlags = ['p', 'pin', 'pins'] as const; +const silentFlags = ['s', 'silent'] as const; +const ageOptions = ['age'] as const; +const includesOptions = ['include', 'includes', 'contain', 'contains'] as const; + +@ApplyOptions({ + aliases: ['purge', 'nuke', 'sweep'], + description: LanguageKeys.Commands.Moderation.PruneDescription, + detailedDescription: LanguageKeys.Commands.Moderation.PruneExtended, + flags: [ + ...attachmentsFlags, + ...imageFlags, + ...authorFlags, + ...botsFlags, + ...humansFlags, + ...invitesFlags, + ...linksFlags, + ...youFlags, + ...pinsFlags, + ...silentFlags + ], + options: [...ageOptions, ...includesOptions], + permissionLevel: PermissionLevels.Moderator, + requiredClientPermissions: [PermissionFlagsBits.ManageMessages, PermissionFlagsBits.ReadMessageHistory, PermissionFlagsBits.EmbedLinks], + runIn: [CommandOptionsRunTypeEnum.GuildAny] +}) +export class UserCommand extends WolfCommand { + private get timespan(): IArgument { + return this.container.stores.get('arguments').get('timespan') as IArgument; + } + + public async messageRun(message: GuildMessage, args: WolfCommand.Args) { + const limit = await args.pick('integer', { minimum: 1, maximum: 100 }); + const filter = await this.getFilters(args); + const rawPosition = args.finished ? null : await args.pick(UserCommand.position); + const targetMessage = args.finished && rawPosition === null ? message : await args.pick('message'); + + const position = this.resolvePosition(rawPosition); + + // Fetch the messages + const messages = (await message.channel.messages.fetch({ limit: 100, [position]: targetMessage.id })) as Collection; + + // Filter the messages by their age + const filtered = messages.filter(filter); + if (filtered.size === 0) this.error(LanguageKeys.Commands.Moderation.PruneNoDeletes); + + const silent = args.getFlags(...silentFlags); + if (silent && filtered.size !== 100) { + filtered.set(message.id, message); + } + + // Perform a bulk delete, throw if it returns unknown message. + const filteredKeys = this.resolveKeys([...filtered.keys()], position, limit); + await (message.channel as TextChannel).bulkDelete(filteredKeys).catch((error) => { + if (error.code !== RESTJSONErrorCodes.UnknownMessage) throw error; + }); + + // Send prune logs and reply to the channel + floatPromise(this.sendPruneLogs(message, args.t, filtered, filteredKeys)); + if (silent) return null; + + const content = args.t(LanguageKeys.Commands.Moderation.PruneAlert, { count: filteredKeys.length, total: limit }); + return sendTemporaryMessage(message, content, seconds(10)); + } + + private resolveKeys(messages: readonly string[], position: 'before' | 'after', limit: number) { + return position === 'before' ? messages.slice(0, limit) : messages.slice(messages.length - limit, messages.length); + } + + private async getFilters(args: WolfCommand.Args) { + const fns: BooleanFn<[GuildMessage]>[] = []; + + const user = args.finished ? null : await args.pick('user').catch(() => null); + if (user !== null) fns.push((mes: GuildMessage) => mes.author.id === user.id); + + const maximumAge = await this.getAge(args); + const oldestMessageTimestamp = Date.now() - maximumAge; + fns.push((mes: GuildMessage) => mes.createdTimestamp > oldestMessageTimestamp); + + if (args.getFlags(...attachmentsFlags)) fns.push((mes: GuildMessage) => mes.attachments.size > 0); + else if (args.getFlags(...imageFlags)) fns.push((mes: GuildMessage) => mes.attachments.some((at) => !isNullish(getImageUrl(at.url)))); + if (args.getFlags(...authorFlags)) fns.push((mes: GuildMessage) => mes.author.id === args.message.author.id); + if (args.getFlags(...botsFlags)) fns.push((mes: GuildMessage) => mes.author.bot); + if (args.getFlags(...humansFlags)) fns.push((mes: GuildMessage) => !mes.author.bot); + if (args.getFlags(...invitesFlags)) fns.push((mes: GuildMessage) => UserCommand.kInviteRegExp.test(mes.content)); + if (args.getFlags(...linksFlags)) fns.push((mes: GuildMessage) => UserCommand.kLinkRegExp.test(mes.content)); + if (args.getFlags(...youFlags)) fns.push((mes: GuildMessage) => mes.author.id === process.env.CLIENT_ID); + if (!args.getFlags(...pinsFlags)) fns.push((mes: GuildMessage) => !mes.pinned); + + const includes = args.getOption(...includesOptions)?.toLowerCase(); + if (!isNullishOrEmpty(includes)) fns.push((mes: GuildMessage) => mes.content.toLowerCase().includes(includes)); + + return andMix(...fns); + } + + private resolvePosition(position: Position | null) { + return position === Position.After ? 'after' : 'before'; + } + + private async getAge(args: WolfCommand.Args) { + const parameter = args.getOption(...ageOptions); + if (parameter === null) return days(14); + + const argument = this.timespan; + const optionResult = await argument.run(parameter, { + args, + argument, + command: this, + commandContext: args.commandContext, + message: args.message, + minimum: 0, + maximum: days(14) + }); + if (optionResult.success) return optionResult.value; + throw optionResult.error; + } + + private async sendPruneLogs(message: GuildMessage, t: TFunction, messages: Collection, rawMessages: readonly string[]) { + const channelId = await readSettings(message.guild, GuildSettings.Channels.Logs.Prune); + if (isNullish(channelId)) return; + + const channel = message.guild.channels.cache.get(channelId) as TextChannel | undefined; + if (typeof channel === 'undefined') { + await writeSettings(message.guild, [[GuildSettings.Channels.Logs.Prune, null]]); + return; + } + + if (canSendAttachments(channel)) { + // Filter the messages collection by the deleted messages, so no extras are added. + messages = messages.filter((_, key) => rawMessages.includes(key)); + + const authorName = `${message.author.tag} (${message.author.id})`; + const authorAvatar = message.author.displayAvatarURL({ size: 128, format: 'png', dynamic: true }); + const description = t(LanguageKeys.Commands.Moderation.PruneLogMessage, { + channel: (message.channel as TextChannel).toString(), + author: message.author.toString(), + count: messages.size + }); + + const embed = new MessageEmbed() + .setAuthor({ name: authorName, iconURL: authorAvatar }) + .setDescription(description) + .setColor(UserCommand.kColor) + .setTimestamp(); + + // Send the message to the prune logs channel. + await channel.send({ embeds: [embed], files: [this.generateAttachment(t, messages)] }); + } + } + + private generateAttachment(t: TFunction, messages: Collection) { + const header = t(LanguageKeys.Commands.Moderation.PruneLogHeader); + const processed = messages + .map((message) => formatMessage(t, message)) + .reverse() + .join('\n\n'); + const buffer = Buffer.from(`${header}\n\n${processed}`); + return new MessageAttachment(buffer, 'prune.txt'); + } + + private static position = Args.make((parameter, { argument }) => { + const position = UserCommand.kCommandPrunePositions[parameter.toLowerCase()]; + if (typeof position === 'undefined') { + return Args.error({ parameter, argument, identifier: LanguageKeys.Commands.Moderation.PruneInvalidPosition }); + } + + return Args.ok(position); + }); + + private static readonly kColor = metadata.get(TypeCodes.Prune)!.color; + private static readonly kInviteRegExp = /(?:discord\.(?:gg|io|me|plus|link)|invite\.(?:gg|ink)|discord(?:app)?\.com\/invite)\/(?:[\w-]{2,})/i; + private static readonly kLinkRegExp = urlRegex({ requireProtocol: true, tlds: true }); + private static readonly kCommandPrunePositions: Record = { + before: Position.Before, + b: Position.Before, + after: Position.After, + a: Position.After + }; +} diff --git a/projects/bot/src/commands/Moderation/removerole.ts b/projects/bot/src/commands/Moderation/removerole.ts new file mode 100644 index 000000000..bddeda3f7 --- /dev/null +++ b/projects/bot/src/commands/Moderation/removerole.ts @@ -0,0 +1,44 @@ +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { HandledCommandContext, ModerationCommand } from '#lib/moderation'; +import type { GuildMessage } from '#lib/types'; +import { PermissionLevels } from '#lib/types/Enums'; +import { years } from '#utils/common'; +import { getSecurity } from '#utils/functions'; +import { getImage } from '#utils/util'; +import { ApplyOptions } from '@sapphire/decorators'; +import { PermissionFlagsBits } from 'discord-api-types/v9'; +import type { Role } from 'discord.js'; + +@ApplyOptions({ + aliases: ['rro'], + description: LanguageKeys.Commands.Moderation.RemoveRoleDescription, + detailedDescription: LanguageKeys.Commands.Moderation.RemoveRoleExtended, + optionalDuration: true, + permissionLevel: PermissionLevels.Administrator, + requiredClientPermissions: [PermissionFlagsBits.ManageRoles], + requiredMember: true +}) +export class UserModerationCommand extends ModerationCommand { + protected async resolveOverloads(args: ModerationCommand.Args) { + return { + targets: await args.repeat('user', { times: 10 }), + role: await args.pick('roleName'), + duration: this.optionalDuration ? await args.pick('timespan', { minimum: 0, maximum: years(5) }).catch(() => null) : null, + reason: args.finished ? null : await args.rest('string') + }; + } + + protected async handle(message: GuildMessage, context: HandledCommandContext & { role: Role }) { + return getSecurity(message.guild).actions.removeRole( + { + userId: context.target.id, + moderatorId: message.author.id, + reason: context.reason, + imageURL: getImage(message), + duration: context.duration + }, + context.role, + await this.getTargetDM(message, context.args, context.target) + ); + } +} diff --git a/projects/bot/src/commands/Moderation/setnickname.ts b/projects/bot/src/commands/Moderation/setnickname.ts new file mode 100644 index 000000000..c93cbdd37 --- /dev/null +++ b/projects/bot/src/commands/Moderation/setnickname.ts @@ -0,0 +1,41 @@ +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { HandledCommandContext, ModerationCommand } from '#lib/moderation'; +import type { GuildMessage } from '#lib/types'; +import { years } from '#utils/common'; +import { getSecurity } from '#utils/functions'; +import { getImage } from '#utils/util'; +import { ApplyOptions } from '@sapphire/decorators'; +import { PermissionFlagsBits } from 'discord-api-types/v9'; + +@ApplyOptions({ + aliases: ['sn'], + description: LanguageKeys.Commands.Moderation.SetNicknameDescription, + detailedDescription: LanguageKeys.Commands.Moderation.SetNicknameExtended, + optionalDuration: true, + requiredClientPermissions: [PermissionFlagsBits.ManageNicknames], + requiredMember: true +}) +export class UserModerationCommand extends ModerationCommand { + protected async resolveOverloads(args: ModerationCommand.Args) { + return { + targets: await args.repeat('user', { times: 10 }), + nickname: args.finished ? null : await args.pick('string'), + duration: this.optionalDuration ? await args.pick('timespan', { minimum: 0, maximum: years(5) }).catch(() => null) : null, + reason: args.finished ? null : await args.rest('string') + }; + } + + protected async handle(message: GuildMessage, context: HandledCommandContext & { nickname: string }) { + return getSecurity(message.guild).actions.setNickname( + { + userId: context.target.id, + moderatorId: message.author.id, + reason: context.reason, + imageURL: getImage(message), + duration: context.duration + }, + context.nickname, + await this.getTargetDM(message, context.args, context.target) + ); + } +} diff --git a/projects/bot/src/commands/Moderation/softban.ts b/projects/bot/src/commands/Moderation/softban.ts new file mode 100644 index 000000000..56cda8db3 --- /dev/null +++ b/projects/bot/src/commands/Moderation/softban.ts @@ -0,0 +1,57 @@ +import { GuildSettings, readSettings } from '#lib/database'; +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { ModerationCommand } from '#lib/moderation'; +import { getModeration, getSecurity } from '#utils/functions'; +import type { Unlock } from '#utils/moderationConstants'; +import { getImage } from '#utils/util'; +import { ApplyOptions } from '@sapphire/decorators'; +import type { ArgumentTypes } from '@sapphire/utilities'; +import { PermissionFlagsBits } from 'discord-api-types/v9'; + +@ApplyOptions({ + aliases: ['sb'], + description: LanguageKeys.Commands.Moderation.SoftBanDescription, + detailedDescription: LanguageKeys.Commands.Moderation.SoftBanExtended, + options: ['d', 'day', 'days'], + requiredClientPermissions: [PermissionFlagsBits.BanMembers], + requiredMember: false +}) +export class UserModerationCommand extends ModerationCommand { + public async prehandle(...[message]: ArgumentTypes) { + const [banAdd, banRemove] = await readSettings(message.guild, [GuildSettings.Events.BanAdd, GuildSettings.Events.BanRemove]); + return banAdd || banRemove ? { unlock: getModeration(message.guild).createLock() } : null; + } + + public async handle(...[message, context]: ArgumentTypes) { + return getSecurity(message.guild).actions.softBan( + { + userId: context.target.id, + moderatorId: message.author.id, + duration: context.duration, + reason: context.reason, + imageURL: getImage(message) + }, + await this.getDays(context.args), + await this.getTargetDM(message, context.args, context.target) + ); + } + + public posthandle(...[, { preHandled }]: ArgumentTypes['posthandle']>) { + if (preHandled) preHandled.unlock(); + } + + public async checkModeratable(...[message, context]: ArgumentTypes) { + const member = await super.checkModeratable(message, context); + if (member && !member.bannable) throw context.args.t(LanguageKeys.Commands.Moderation.BanNotBannable); + return member; + } + + private async getDays(args: ModerationCommand.Args) { + const value = args.getOption('d', 'day', 'days'); + if (value === null) return 0; + + const parsed = Number(value); + if (Number.isInteger(parsed) && parsed >= 0 && parsed <= 7) return parsed; + return 0; + } +} diff --git a/src/commands/Moderation/togglemoderationdm.ts b/projects/bot/src/commands/Moderation/togglemoderationdm.ts similarity index 70% rename from src/commands/Moderation/togglemoderationdm.ts rename to projects/bot/src/commands/Moderation/togglemoderationdm.ts index 2cd99b5f5..1ab50ea38 100644 --- a/src/commands/Moderation/togglemoderationdm.ts +++ b/projects/bot/src/commands/Moderation/togglemoderationdm.ts @@ -10,10 +10,17 @@ import { send } from '@sapphire/plugin-editable-commands'; detailedDescription: LanguageKeys.Commands.Moderation.ToggleModerationDmExtended }) export class UserCommand extends WolfCommand { - public override async messageRun(message: GuildMessage, args: WolfCommand.Args) { - const enabled = await this.container.prisma.user.toggleModerationDirectMessageEnabled(message.author.id); + public async messageRun(message: GuildMessage, args: WolfCommand.Args) { + const { users } = this.container.db; + const updated = await users.lock([message.author.id], async (id) => { + const user = await users.ensure(id); + + user.moderationDM = !user.moderationDM; + return user.save(); + }); + const content = args.t( - enabled + updated.moderationDM ? LanguageKeys.Commands.Moderation.ToggleModerationDmToggledEnabled : LanguageKeys.Commands.Moderation.ToggleModerationDmToggledDisabled ); diff --git a/projects/bot/src/commands/Moderation/unban.ts b/projects/bot/src/commands/Moderation/unban.ts new file mode 100644 index 000000000..2647cad81 --- /dev/null +++ b/projects/bot/src/commands/Moderation/unban.ts @@ -0,0 +1,63 @@ +import { GuildSettings, readSettings } from '#lib/database'; +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { ModerationCommand } from '#lib/moderation'; +import type { GuildMessage } from '#lib/types'; +import { getModeration, getSecurity } from '#utils/functions'; +import type { Unlock } from '#utils/moderationConstants'; +import { getImage } from '#utils/util'; +import { ApplyOptions } from '@sapphire/decorators'; +import { fromAsync } from '@sapphire/framework'; +import { resolveKey } from '@sapphire/plugin-i18next'; +import type { ArgumentTypes } from '@sapphire/utilities'; +import { PermissionFlagsBits } from 'discord-api-types/v9'; + +@ApplyOptions({ + aliases: ['ub'], + description: LanguageKeys.Commands.Moderation.UnbanDescription, + detailedDescription: LanguageKeys.Commands.Moderation.UnbanExtended, + requiredClientPermissions: [PermissionFlagsBits.BanMembers], + requiredMember: false +}) +export class UserModerationCommand extends ModerationCommand { + public async prehandle(message: GuildMessage) { + const result = await fromAsync(message.guild.bans.fetch()); + const bans = result.success ? result.value.map((ban) => ban.user.id) : null; + + // If the fetch failed, throw an error saying that the fetch failed: + if (bans === null) { + throw await resolveKey(message, LanguageKeys.System.FetchBansFail); + } + + // If there were no bans, throw an error saying that the ban list is empty: + if (bans.length === 0) { + throw await resolveKey(message, LanguageKeys.Commands.Moderation.GuildBansEmpty); + } + + return { + bans, + unlock: (await readSettings(message.guild, GuildSettings.Events.BanRemove)) ? getModeration(message.guild).createLock() : null + }; + } + + public async handle(...[message, context]: ArgumentTypes) { + return getSecurity(message.guild).actions.unBan( + { + userId: context.target.id, + moderatorId: message.author.id, + reason: context.reason, + imageURL: getImage(message), + duration: context.duration + }, + await this.getTargetDM(message, context.args, context.target) + ); + } + + public posthandle(...[, { preHandled }]: ArgumentTypes['posthandle']>) { + if (preHandled) preHandled.unlock(); + } + + public checkModeratable(...[message, context]: ArgumentTypes['checkModeratable']>) { + if (!context.preHandled.bans.includes(context.target.id)) throw context.args.t(LanguageKeys.Commands.Moderation.GuildBansNotFound); + return super.checkModeratable(message, context); + } +} diff --git a/projects/bot/src/commands/Moderation/unmute.ts b/projects/bot/src/commands/Moderation/unmute.ts new file mode 100644 index 000000000..f27f66c22 --- /dev/null +++ b/projects/bot/src/commands/Moderation/unmute.ts @@ -0,0 +1,31 @@ +import { GuildSettings } from '#lib/database'; +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { ModerationCommand, SetUpModerationCommand } from '#lib/moderation'; +import { getSecurity } from '#utils/functions'; +import { ModerationSetupRestriction } from '#utils/Security/ModerationActions'; +import { getImage } from '#utils/util'; +import { ApplyOptions } from '@sapphire/decorators'; +import type { ArgumentTypes } from '@sapphire/utilities'; +import { PermissionFlagsBits } from 'discord-api-types/v9'; + +@ApplyOptions({ + aliases: ['um'], + description: LanguageKeys.Commands.Moderation.UnmuteDescription, + detailedDescription: LanguageKeys.Commands.Moderation.UnmuteExtended, + requiredClientPermissions: [PermissionFlagsBits.ManageRoles], + roleKey: GuildSettings.Roles.Muted, + setUpKey: ModerationSetupRestriction.All +}) +export class UserSetUpModerationCommand extends SetUpModerationCommand { + public async handle(...[message, context]: ArgumentTypes) { + return getSecurity(message.guild).actions.unMute( + { + userId: context.target.id, + moderatorId: message.author.id, + reason: context.reason, + imageURL: getImage(message) + }, + await this.getTargetDM(message, context.args, context.target) + ); + } +} diff --git a/projects/bot/src/commands/Moderation/unwarn.ts b/projects/bot/src/commands/Moderation/unwarn.ts new file mode 100644 index 000000000..a072a704a --- /dev/null +++ b/projects/bot/src/commands/Moderation/unwarn.ts @@ -0,0 +1,71 @@ +import { GuildSettings, ModerationEntity, readSettings } from '#lib/database'; +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { HandledCommandContext, ModerationCommand } from '#lib/moderation'; +import type { GuildMessage } from '#lib/types'; +import { floatPromise } from '#utils/common'; +import { deleteMessage, getModeration, getSecurity } from '#utils/functions'; +import { TypeCodes } from '#utils/moderationConstants'; +import { getImage } from '#utils/util'; +import { ApplyOptions } from '@sapphire/decorators'; +import { send } from '@sapphire/plugin-editable-commands'; + +@ApplyOptions({ + aliases: ['uw', 'unwarning'], + description: LanguageKeys.Commands.Moderation.UnwarnDescription, + detailedDescription: LanguageKeys.Commands.Moderation.UnwarnExtended +}) +export class UserModerationCommand extends ModerationCommand { + public async messageRun(message: GuildMessage, args: ModerationCommand.Args) { + const caseId = await args.pick('case'); + const reason = await args.rest('string'); + + const [autoDelete, messageDisplay, reasonDisplay] = await readSettings(message.guild, [ + GuildSettings.Messages.ModerationAutoDelete, + GuildSettings.Messages.ModerationMessageDisplay, + GuildSettings.Messages.ModerationReasonDisplay + ]); + + const modlog = await getModeration(message.guild).fetch(caseId); + if (!modlog || !modlog.isType(TypeCodes.Warning)) { + this.error(LanguageKeys.Commands.Moderation.GuildWarnNotFound); + } + + const user = await modlog.fetchUser(); + const unwarnLog = await this.handle(message, { args, target: user, reason, modlog, duration: null, preHandled: null }); + + // If the server was configured to automatically delete messages, delete the command and return null. + if (autoDelete) { + if (message.deletable) floatPromise(deleteMessage(message)); + } + + if (messageDisplay) { + const originalReason = reasonDisplay ? unwarnLog.reason : null; + const content = args.t( + originalReason ? LanguageKeys.Commands.Moderation.ModerationOutputWithReason : LanguageKeys.Commands.Moderation.ModerationOutput, + { + count: 1, + range: unwarnLog.caseId, + users: [`\`${user.tag}\``], + reason: originalReason + } + ); + + return send(message, content) as Promise; + } + + return null; + } + + public async handle(message: GuildMessage, context: HandledCommandContext & { modlog: ModerationEntity }) { + return getSecurity(message.guild).actions.unWarning( + { + userId: context.target.id, + moderatorId: message.author.id, + reason: context.reason, + imageURL: getImage(message) + }, + context.modlog.caseId, + await this.getTargetDM(message, context.args, context.target) + ); + } +} diff --git a/projects/bot/src/commands/Moderation/voicekick.ts b/projects/bot/src/commands/Moderation/voicekick.ts new file mode 100644 index 000000000..0815b08e4 --- /dev/null +++ b/projects/bot/src/commands/Moderation/voicekick.ts @@ -0,0 +1,34 @@ +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { ModerationCommand } from '#lib/moderation'; +import { getSecurity } from '#utils/functions'; +import { getImage } from '#utils/util'; +import { ApplyOptions } from '@sapphire/decorators'; +import type { ArgumentTypes } from '@sapphire/utilities'; +import { PermissionFlagsBits } from 'discord-api-types/v9'; + +@ApplyOptions({ + aliases: ['vk', 'vkick'], + description: LanguageKeys.Commands.Moderation.VoiceKickDescription, + detailedDescription: LanguageKeys.Commands.Moderation.VoiceKickExtended, + requiredClientPermissions: [PermissionFlagsBits.ManageChannels, PermissionFlagsBits.MoveMembers], + requiredMember: true +}) +export class UserModerationCommand extends ModerationCommand { + public async handle(...[message, context]: ArgumentTypes) { + return getSecurity(message.guild).actions.voiceKick( + { + userId: context.target.id, + moderatorId: message.author.id, + reason: context.reason, + imageURL: getImage(message) + }, + await this.getTargetDM(message, context.args, context.target) + ); + } + + public async checkModeratable(...[message, context]: ArgumentTypes) { + const member = await super.checkModeratable(message, context); + if (member && !member.voice.channelId) throw context.args.t(LanguageKeys.Commands.Moderation.GuildMemberNotVoicechannel); + return member; + } +} diff --git a/projects/bot/src/commands/Moderation/warn.ts b/projects/bot/src/commands/Moderation/warn.ts new file mode 100644 index 000000000..a5537b49c --- /dev/null +++ b/projects/bot/src/commands/Moderation/warn.ts @@ -0,0 +1,28 @@ +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { ModerationCommand } from '#lib/moderation'; +import { getSecurity } from '#utils/functions'; +import { getImage } from '#utils/util'; +import { ApplyOptions } from '@sapphire/decorators'; +import type { ArgumentTypes } from '@sapphire/utilities'; + +@ApplyOptions({ + aliases: ['w', 'warning'], + description: LanguageKeys.Commands.Moderation.WarnDescription, + detailedDescription: LanguageKeys.Commands.Moderation.WarnExtended, + optionalDuration: true, + requiredMember: true +}) +export class UserModerationCommand extends ModerationCommand { + public async handle(...[message, context]: ArgumentTypes) { + return getSecurity(message.guild).actions.warning( + { + userId: context.target.id, + moderatorId: message.author.id, + reason: context.reason, + imageURL: getImage(message), + duration: context.duration + }, + await this.getTargetDM(message, context.args, context.target) + ); + } +} diff --git a/projects/bot/src/commands/Tools/whois.ts b/projects/bot/src/commands/Tools/whois.ts new file mode 100644 index 000000000..5791665f1 --- /dev/null +++ b/projects/bot/src/commands/Tools/whois.ts @@ -0,0 +1,149 @@ +import { SkyraEmbed } from '#lib/discord'; +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import type { GuildMessage } from '#lib/types'; +import { months, seconds } from '#utils/common'; +import { Colors, Emojis } from '#utils/constants'; +import { time, TimestampStyles } from '@discordjs/builders'; +import { Command, RegisterCommand, RegisterSubCommand } from '@wolfstar/http-framework'; +import { applyLocalizedBuilder } from '@wolfstar/http-framework-i18n'; +import type { TFunction } from 'i18next'; + +const sortRanks = (x: Role, y: Role) => Number(y.position > x.position) || Number(x.position === y.position) - 1; +const { FLAGS } = Permissions; + +@RegisterCommand((builder) => + applyLocalizedBuilder(builder, LanguageKeys.Commands.Whois.RootName, LanguageKeys.Commands.Whois.RootDescription).setDMPermission(false) +) +export class UserCommand extends Command { + private readonly kAdministratorPermission = FLAGS.ADMINISTRATOR; + private readonly kKeyPermissions: [PermissionString, bigint][] = [ + ['BAN_MEMBERS', FLAGS.BAN_MEMBERS], + ['KICK_MEMBERS', FLAGS.KICK_MEMBERS], + ['MANAGE_CHANNELS', FLAGS.MANAGE_CHANNELS], + ['MANAGE_EMOJIS_AND_STICKERS', FLAGS.MANAGE_EMOJIS_AND_STICKERS], + ['MANAGE_GUILD', FLAGS.MANAGE_GUILD], + ['MANAGE_MESSAGES', FLAGS.MANAGE_MESSAGES], + ['MANAGE_NICKNAMES', FLAGS.MANAGE_NICKNAMES], + ['MANAGE_ROLES', FLAGS.MANAGE_ROLES], + ['MANAGE_WEBHOOKS', FLAGS.MANAGE_WEBHOOKS], + ['MENTION_EVERYONE', FLAGS.MENTION_EVERYONE] + ]; + + @RegisterSubCommand((builder) => + applyLocalizedBuilder(builder, LanguageKeys.Commands.Whois.User) // + .addUserOption((builder) => applyLocalizedBuilder(builder, LanguageKeys.Commands.Whois.OptionsUser)) + ) + public async handleUser(interaction: Command.Interaction) {} + + @RegisterSubCommand((builder) => + applyLocalizedBuilder(builder, LanguageKeys.Commands.Whois.Role) // + .addRoleOption((builder) => applyLocalizedBuilder(builder, LanguageKeys.Commands.Whois.OptionsRole)) + ) + public async handleRole(interaction: Command.Interaction) {} + + @RegisterSubCommand((builder) => applyLocalizedBuilder(builder, LanguageKeys.Commands.Whois.Server)) + public async handleServer(interaction: Command.Interaction) { + this.container.client + } + + public async messageRun(message: GuildMessage, args: WolfCommand.Args) { + const user = args.finished ? message.author : await args.pick('userName'); + const member = await message.guild.members.fetch(user.id).catch(() => null); + + const embed = member ? this.member(args.t, member) : this.user(args.t, user); + return send(message, { embeds: [embed] }); + } + + private user(t: TFunction, user: User) { + const userCreatedAtTimestampSeconds = seconds.fromMilliseconds(user.createdTimestamp); + + const titles = t(LanguageKeys.Commands.Tools.WhoisUserTitles); + const fields = t(LanguageKeys.Commands.Tools.WhoisUserFields, { + user, + userCreatedAt: time(userCreatedAtTimestampSeconds, TimestampStyles.ShortDateTime), + userCreatedAtOffset: time(userCreatedAtTimestampSeconds, TimestampStyles.RelativeTime) + }); + + return new SkyraEmbed() + .setColor(Colors.White) + .setThumbnail(user.displayAvatarURL({ size: 256, format: 'png', dynamic: true })) + .setDescription(this.getUserInformation(user)) + .addField(titles.createdAt, fields.createdAt) + .setFooter({ text: fields.footer, iconURL: this.container.client.user!.displayAvatarURL({ size: 128, format: 'png', dynamic: true }) }) + .setTimestamp(); + } + + private member(t: TFunction, member: GuildMember) { + const userCreatedAtTimestampSeconds = seconds.fromMilliseconds(member.user.createdTimestamp); + const memberJoinedAtTimestampSeconds = seconds.fromMilliseconds(member.joinedTimestamp!); + + const titles = t(LanguageKeys.Commands.Tools.WhoisMemberTitles); + const fields = t(LanguageKeys.Commands.Tools.WhoisMemberFields, { + member, + memberCreatedAt: time(userCreatedAtTimestampSeconds, TimestampStyles.ShortDateTime), + memberCreatedAtOffset: time(userCreatedAtTimestampSeconds, TimestampStyles.RelativeTime), + memberJoinedAt: time(memberJoinedAtTimestampSeconds, TimestampStyles.ShortDateTime), + memberJoinedAtOffset: time(memberJoinedAtTimestampSeconds, TimestampStyles.RelativeTime) + }); + + const embed = new SkyraEmbed() + .setColor(member.displayColor || Colors.White) + .setThumbnail(member.user.displayAvatarURL({ size: 256, format: 'png', dynamic: true })) + .setDescription(this.getUserInformation(member.user, this.getBoostIcon(member.premiumSinceTimestamp))) + .addField(titles.joined, member.joinedTimestamp ? fields.joinedWithTimestamp : fields.joinedUnknown, true) + .addField(titles.createdAt, fields.createdAt, true) + .setFooter({ text: fields.footer, iconURL: this.container.client.user!.displayAvatarURL({ size: 128, format: 'png', dynamic: true }) }) + .setTimestamp(); + + this.applyMemberRoles(t, member, embed); + this.applyMemberKeyPermissions(t, member, embed); + return embed; + } + + private getUserInformation(user: User, extras = ''): string { + const bot = user.bot ? ` ${Emojis.Bot}` : ''; + const avatar = `[Avatar ${Emojis.Frame}](${user.displayAvatarURL({ size: 4096, format: 'png', dynamic: true })})`; + return `**${user.tag}**${bot} - ${user.toString()}${extras} - ${avatar}`; + } + + private applyMemberRoles(t: TFunction, member: GuildMember, embed: SkyraEmbed) { + if (member.roles.cache.size <= 1) return; + + const roles = member.roles.cache.sorted(sortRanks); + roles.delete(member.guild.id); + embed.splitFields(t(LanguageKeys.Commands.Tools.WhoisMemberRoles, { count: roles.size }), [...roles.values()].join(' ')); + } + + private applyMemberKeyPermissions(t: TFunction, member: GuildMember, embed: SkyraEmbed) { + if (member.permissions.has(this.kAdministratorPermission)) { + embed.addField(t(LanguageKeys.Commands.Tools.WhoisMemberPermissions), t(LanguageKeys.Commands.Tools.WhoisMemberPermissionsAll)); + return; + } + + const permissions: string[] = []; + for (const [name, bit] of this.kKeyPermissions) { + if (member.permissions.has(bit)) permissions.push(t(`permissions:${name}`)); + } + + if (permissions.length > 0) { + embed.addField(t(LanguageKeys.Commands.Tools.WhoisMemberPermissions), permissions.join(', ')); + } + } + + private getBoostIcon(boostingSince: number | null): string { + if (boostingSince === null || boostingSince <= 0) return ''; + return ` ${this.getBoostEmoji(Date.now() - boostingSince)}`; + } + + private getBoostEmoji(duration: number): string { + if (duration >= months(24)) return Emojis.BoostLevel9; + if (duration >= months(18)) return Emojis.BoostLevel8; + if (duration >= months(15)) return Emojis.BoostLevel7; + if (duration >= months(12)) return Emojis.BoostLevel6; + if (duration >= months(9)) return Emojis.BoostLevel5; + if (duration >= months(6)) return Emojis.BoostLevel4; + if (duration >= months(3)) return Emojis.BoostLevel3; + if (duration >= months(2)) return Emojis.BoostLevel2; + return Emojis.BoostLevel1; + } +} diff --git a/projects/bot/src/config.ts b/projects/bot/src/config.ts new file mode 100644 index 000000000..19436123e --- /dev/null +++ b/projects/bot/src/config.ts @@ -0,0 +1,7 @@ +import { GatewayIntentBits, type ClientOptions } from 'discord.js'; + +export const OWNERS: string[] = ['242043489611808769']; + +export const CLIENT_OPTIONS: ClientOptions = { + intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages] +}; diff --git a/projects/bot/src/lib/Client.ts b/projects/bot/src/lib/Client.ts new file mode 100644 index 000000000..5d4bfb187 --- /dev/null +++ b/projects/bot/src/lib/Client.ts @@ -0,0 +1,73 @@ +import { envParseInteger, envParseString } from '@wolfstar/env-utilities'; +import { Client, container } from '@wolfstar/http-framework'; +import { MessageBroker, Redis, Cache, RedisOptions } from 'wolfstar-shared'; +import * as Sentry from '@sentry/node'; +import { RewriteFrames } from '@sentry/integrations'; +import { fileURLToPath } from 'node:url'; + +export function createClient(options: ClientOptions = {}) { + new Client({ + discordToken: envParseString('DISCORD_TOKEN'), + discordPublicKey: envParseString('DISCORD_PUBLIC_KEY') + }); + + container.redis = new Redis({ + ...options.redis, + lazyConnect: true, + host: envParseString('REDIS_HOST'), + port: envParseInteger('REDIS_PORT'), + db: envParseInteger('REDIS_DB'), + password: envParseString('REDIS_PASSWORD') + }); + container.cache = new Cache({ + client: container.redis, + prefix: 's7' + }); + container.broker = new MessageBroker({ + redis: container.redis, + stream: envParseString('BROKER_STREAM_NAME'), + block: envParseInteger('BROKER_BLOCK', 5000), + max: envParseInteger('BROKER_MAX', 10) + }); + + const srcFolderURL = new URL('..', import.meta.url); + container.stores.registerPath(fileURLToPath(srcFolderURL)); + + // Load in Sentry for error logging + if (process.env.SENTRY_URL) { + Sentry.init({ + dsn: process.env.SENTRY_URL, + integrations: [ + new Sentry.Integrations.Modules(), + new Sentry.Integrations.FunctionToString(), + new Sentry.Integrations.LinkedErrors(), + new Sentry.Integrations.Console(), + new Sentry.Integrations.Http({ breadcrumbs: true, tracing: true }), + new RewriteFrames({ root: fileURLToPath(new URL('..', srcFolderURL)) }) + ] + }); + } +} + +export async function loadAll() { + await container.redis.connect(); + await container.stores.load(); + await container.client.load(); +} + +export interface ClientOptions { + redis?: Omit; +} + +declare module '@sapphire/pieces' { + interface Container { + broker: MessageBroker; + cache: Cache; + redis: Redis; + + // db: DbSet; + // schedule: ScheduleManager; + // settings: SettingsManager; + // workers: WorkerManager; + } +} diff --git a/projects/bot/src/lib/augments.d.ts b/projects/bot/src/lib/augments.d.ts new file mode 100644 index 000000000..2193c3d86 --- /dev/null +++ b/projects/bot/src/lib/augments.d.ts @@ -0,0 +1,21 @@ +import type { IntegerString } from '@wolfstar/env-utilities'; + +declare module '@wolfstar/env-utilities' { + interface Env { + CLIENT_VERSION: string; + + SENTRY_URL?: string; + + DISCORD_TOKEN: string; + DISCORD_PUBLIC_KEY: string; + + REDIS_HOST: string; + REDIS_PORT: IntegerString; + REDIS_DB: IntegerString; + REDIS_PASSWORD: string; + + BROKER_STREAM_NAME: string; + BROKER_BLOCK?: IntegerString; + BROKER_MAX?: IntegerString; + } +} diff --git a/src/lib/discord/GuildMemberFetchQueue.ts b/projects/bot/src/lib/discord/GuildMemberFetchQueue.ts similarity index 98% rename from src/lib/discord/GuildMemberFetchQueue.ts rename to projects/bot/src/lib/discord/GuildMemberFetchQueue.ts index 63a9b42c4..334e41996 100644 --- a/src/lib/discord/GuildMemberFetchQueue.ts +++ b/projects/bot/src/lib/discord/GuildMemberFetchQueue.ts @@ -1,6 +1,8 @@ import { container } from '@sapphire/framework'; import { Time } from '@sapphire/time-utilities'; +// TODO: Move this to /gateway + /** * Represents a {@link GuildMemberFetchQueue.shards} entry. */ diff --git a/projects/bot/src/lib/i18n/languageKeys/index.ts b/projects/bot/src/lib/i18n/languageKeys/index.ts new file mode 100644 index 000000000..b90c43db3 --- /dev/null +++ b/projects/bot/src/lib/i18n/languageKeys/index.ts @@ -0,0 +1 @@ +export * as LanguageKeys from './keys/All'; diff --git a/projects/bot/src/lib/i18n/languageKeys/keys/All.ts b/projects/bot/src/lib/i18n/languageKeys/keys/All.ts new file mode 100644 index 000000000..1a5723dca --- /dev/null +++ b/projects/bot/src/lib/i18n/languageKeys/keys/All.ts @@ -0,0 +1,14 @@ +export * as Arguments from './Arguments'; +export * as Assertions from './Assertions'; +export * as Colors from './Colors'; +export * as Commands from './Commands'; +export * as Events from './events/All'; +export * as FuzzySearch from './FuzzySearch'; +export * as Globals from './Globals'; +export * as Guilds from './Guilds'; +export * as Misc from './Misc'; +export * as Preconditions from './Preconditions'; +export * as PromptList from './PromptList'; +export * as Serializers from './Serializers'; +export * as Settings from './Settings'; +export * as System from './System'; diff --git a/src/lib/i18n/languageKeys/keys/Arguments.ts b/projects/bot/src/lib/i18n/languageKeys/keys/Arguments.ts similarity index 88% rename from src/lib/i18n/languageKeys/keys/Arguments.ts rename to projects/bot/src/lib/i18n/languageKeys/keys/Arguments.ts index aab263b22..a37572ff5 100644 --- a/src/lib/i18n/languageKeys/keys/Arguments.ts +++ b/projects/bot/src/lib/i18n/languageKeys/keys/Arguments.ts @@ -1,16 +1,19 @@ import { FT, T } from '#lib/types'; +export const RangeInvalid = FT<{ value: string }>('arguments/range:invalid'); +export const RangeMax = FT<{ value: string; maximum: number; count: number }>('arguments/range:max'); +export const ImageNotFound = FT<{ value: string }>('arguments/image:notFound'); + +export const All = T('arguments:all'); export const BooleanDisabled = T('arguments:booleanDisabled'); export const BooleanError = FT<{ parameter: string; possibles: string[]; count: number }>('arguments:booleanError'); export const BooleanEnabled = T('arguments:booleanEnabled'); export const BooleanFalseOptions = T('arguments:booleanFalseOptions'); export const BooleanTrueOptions = T('arguments:booleanTrueOptions'); -export const CaseNoEntries = FT<{ parameter: string }>('arguments:caseNoEntries'); -export const CaseUnknownEntry = FT<{ parameter: string }>('arguments:caseUnknownEntry'); -export const CaseNotInThisGuild = FT<{ parameter: string }>('arguments:caseNotInThisGuild'); export const CaseLatestOptions = T('arguments:caseLatestOptions'); export const CategoryChannelError = FT<{ parameter: string }>('arguments:categoryChannelError'); export const ChannelError = FT<{ parameter: string }>('arguments:channelError'); +export const Color = FT<{ parameter: string }>('arguments:color'); export const Command = FT<{ parameter: string }>('arguments:command'); export const CommandMatch = FT<{ parameter: string }>('arguments:commandMatch'); export const DateError = FT<{ parameter: string }>('arguments:dateError'); @@ -18,12 +21,11 @@ export const DateTooFar = FT<{ parameter: string; maximum: number }>('arguments: export const DateTooEarly = FT<{ parameter: string; minimum: number }>('arguments:dateTooEarly'); export const DmChannelError = FT<{ parameter: string }>('arguments:dmChannelError'); export const Duration = FT<{ parameter: string }>('arguments:duration'); -export const EmojiError = FT<{ parameter: string }>('arguments:emojiError'); +export const Emoji = FT<{ parameter: string }>('arguments:emoji'); export const FloatError = FT<{ parameter: string }>('arguments:floatError'); export const FloatTooLarge = FT<{ parameter: string; maximum: number }>('arguments:floatTooLarge'); export const FloatTooSmall = FT<{ parameter: string; minimum: number }>('arguments:floatTooSmall'); export const GuildChannelError = FT<{ parameter: string }>('arguments:guildChannelError'); -export const GuildChannelMismatchingError = FT<{ parameter: string }>('arguments:guildChannelMismatchingError'); export const GuildChannelMissingGuildError = FT<{ parameter: string }>('arguments:guildChannelMissingGuildError'); export const GuildPrivateThreadChannelError = FT<{ parameter: string }>('arguments:guildPrivateThreadChannelError'); export const GuildPublicThreadChannelError = FT<{ parameter: string }>('arguments:guildPublicThreadChannelError'); @@ -46,11 +48,11 @@ export const NumberError = FT<{ parameter: string }>('arguments:numberError'); export const NumberTooLarge = FT<{ parameter: string; maximum: number }>('arguments:numberTooLarge'); export const NumberTooSmall = FT<{ parameter: string; minimum: number }>('arguments:numberTooSmall'); export const Piece = FT<{ parameter: string; piece: string }>('arguments:piece'); -export const RangeInvalid = FT<{ value: string }>('arguments:rangeInvalid'); -export const RangeMax = FT<{ value: string; maximum: number; count: number }>('arguments:rangeMax'); export const ResetPossibles = T('arguments:resetPossibles'); export const RoleError = FT<{ parameter: string }>('arguments:roleError'); export const RoleMissingGuild = FT<{ parameter: string }>('arguments:roleMissingGuild'); +export const ScopeGlobal = T('arguments:scopeGlobal'); +export const ScopeLocal = T('arguments:scopeLocal'); export const Snowflake = FT<{ parameter: string }>('arguments:snowflake'); export const Store = FT<{ parameter: string }>('arguments:store'); export const StringTooLong = FT<{ parameter: string; maximum: number }>('arguments:stringTooLong'); @@ -63,3 +65,5 @@ export const TooFewWinners = FT<{ parameter: string }>('arguments:tooFewWinners' export const TooManyWinners = FT<{ parameter: string }>('arguments:tooManyWinners'); export const Unavailable = T('arguments:unavailable'); export const UserError = FT<{ parameter: string }>('arguments:userError'); +export const Wager = FT<{ parameter: number; possibles: readonly string[] }>('arguments:wager'); +export const Winners = FT<{ parameter: string }>('arguments:winners'); diff --git a/src/lib/i18n/languageKeys/keys/Assertions.ts b/projects/bot/src/lib/i18n/languageKeys/keys/Assertions.ts similarity index 100% rename from src/lib/i18n/languageKeys/keys/Assertions.ts rename to projects/bot/src/lib/i18n/languageKeys/keys/Assertions.ts diff --git a/projects/bot/src/lib/i18n/languageKeys/keys/Colors.ts b/projects/bot/src/lib/i18n/languageKeys/keys/Colors.ts new file mode 100644 index 000000000..753cd2708 --- /dev/null +++ b/projects/bot/src/lib/i18n/languageKeys/keys/Colors.ts @@ -0,0 +1,12 @@ +import { FT } from '#lib/types'; + +export const InvalidBase10 = FT<{ value: number }>('colors:invalidBase10'); +export const InvalidHexRed = FT<{ value: string }>('colors:invalidHexRed'); +export const InvalidHexGreen = FT<{ value: string }>('colors:invalidHexGreen'); +export const InvalidHexBlue = FT<{ value: string }>('colors:invalidHexBlue'); +export const InvalidHslHue = FT<{ value: number }>('colors:invalidHslHue'); +export const InvalidHslSaturation = FT<{ value: number }>('colors:invalidHslSaturation'); +export const InvalidHslLightness = FT<{ value: number }>('colors:invalidHslLightness'); +export const InvalidRgbRed = FT<{ value: number }>('colors:invalidRgbRed'); +export const InvalidRgbGreen = FT<{ value: number }>('colors:invalidRgbGreen'); +export const InvalidRgbBlue = FT<{ value: number }>('colors:invalidRgbBlue'); diff --git a/projects/bot/src/lib/i18n/languageKeys/keys/Commands.ts b/projects/bot/src/lib/i18n/languageKeys/keys/Commands.ts new file mode 100644 index 000000000..c546aeed8 --- /dev/null +++ b/projects/bot/src/lib/i18n/languageKeys/keys/Commands.ts @@ -0,0 +1,4 @@ +export * as Admin from './commands/Admin'; +export * as Management from './commands/Management'; +export * as Moderation from './commands/Moderation'; +export * as Whois from './commands/Whois'; diff --git a/src/lib/i18n/languageKeys/keys/FuzzySearch.ts b/projects/bot/src/lib/i18n/languageKeys/keys/FuzzySearch.ts similarity index 100% rename from src/lib/i18n/languageKeys/keys/FuzzySearch.ts rename to projects/bot/src/lib/i18n/languageKeys/keys/FuzzySearch.ts diff --git a/src/lib/i18n/languageKeys/keys/Globals.ts b/projects/bot/src/lib/i18n/languageKeys/keys/Globals.ts similarity index 72% rename from src/lib/i18n/languageKeys/keys/Globals.ts rename to projects/bot/src/lib/i18n/languageKeys/keys/Globals.ts index d4e3d8ff3..778060f2f 100644 --- a/src/lib/i18n/languageKeys/keys/Globals.ts +++ b/projects/bot/src/lib/i18n/languageKeys/keys/Globals.ts @@ -6,19 +6,12 @@ export const None = T('globals:none'); export const Unknown = T('globals:unknown'); export const PaginatedMessagePage = T('globals:paginatedMessagePage'); export const PaginatedMessageWrongUserInteractionReply = FT<{ user: string }>('globals:paginatedMessageWrongUserInteractionReply'); +export const OrdinalValue = FT<{ value: string }>('globals:ordinalValue'); export const DurationValue = FT<{ value: number }>('globals:durationValue'); export const NumberValue = FT<{ value: number }>('globals:numberValue'); export const NumberCompactValue = FT<{ value: number }>('globals:numberCompactValue'); export const DateTimeValue = FT<{ value: number }>('globals:dateTimeValue'); -export const HumanDateTimeValue = FT<{ value: number }>('globals:humanDateTimeValue'); export const AndListValue = FT<{ value: string[] }>('globals:andListValue'); export const OrListValue = FT<{ value: string[] }>('globals:orListValue'); export const DateFormat = T('globals:dateFormat'); export const DateFormatExplanation = T('globals:dateFormatExplanation'); -export const Back = T('globals:back'); -export const Stop = T('globals:stop'); -export const Set = T('globals:set'); -export const Remove = T('globals:remove'); -export const Reset = T('globals:reset'); -export const Value = T('globals:value'); -export const Cancel = T('globals:cancel'); diff --git a/src/lib/i18n/languageKeys/keys/Guilds.ts b/projects/bot/src/lib/i18n/languageKeys/keys/Guilds.ts similarity index 100% rename from src/lib/i18n/languageKeys/keys/Guilds.ts rename to projects/bot/src/lib/i18n/languageKeys/keys/Guilds.ts diff --git a/src/lib/i18n/languageKeys/keys/Misc.ts b/projects/bot/src/lib/i18n/languageKeys/keys/Misc.ts similarity index 57% rename from src/lib/i18n/languageKeys/keys/Misc.ts rename to projects/bot/src/lib/i18n/languageKeys/keys/Misc.ts index 5411e0bd5..4788516c1 100644 --- a/src/lib/i18n/languageKeys/keys/Misc.ts +++ b/projects/bot/src/lib/i18n/languageKeys/keys/Misc.ts @@ -1,8 +1,12 @@ import { FT, T } from '#lib/types'; +export const ChannelNotReadable = T('errors:channelNotReadable'); export const ConfigurationEquals = T('commands/management:configurationEquals'); export const JumpTo = T('system:jumpTo'); +export const MessagePromptTimeout = T('system:messagePromptTimeout'); export const PrefixReminder = FT<{ prefix: string }, string>('system:prefixReminder'); export const RestrictionNotConfigured = T('moderation:restrictionNotConfigured'); +export const SystemTextTruncated = FT<{ definition: string; url: string }, string>('commands/tools:systemTextTruncated'); +export const TextPromptAbortOptions = T('system:textPromptAbortOptions'); export const UnexpectedIssue = T('errors:unexpectedIssue'); export const UserNotInGuild = T('errors:userNotInGuild'); diff --git a/projects/bot/src/lib/i18n/languageKeys/keys/Preconditions.ts b/projects/bot/src/lib/i18n/languageKeys/keys/Preconditions.ts new file mode 100644 index 000000000..be4779e1d --- /dev/null +++ b/projects/bot/src/lib/i18n/languageKeys/keys/Preconditions.ts @@ -0,0 +1,25 @@ +import { FT, T } from '#lib/types'; + +// Sapphire built-in: +export const ClientPermissions = FT<{ missing: string[] }>('preconditions:clientPermissions'); +export const Cooldown = FT<{ remaining: number }>('preconditions:cooldown'); +export const DisabledGlobal = T('preconditions:disabledGlobal'); +export const DmOnly = T('preconditions:dmOnly'); +export const GuildNewsOnly = T('preconditions:guildNewsOnly'); +export const GuildNewsThreadOnly = T('preconditions:guildNewsThreadOnly'); +export const GuildOnly = T('preconditions:guildOnly'); +export const GuildPrivateThreadOnly = T('preconditions:guildPrivateThreadOnly'); +export const GuildPublicThreadOnly = T('preconditions:guildPublicThreadOnly'); +export const GuildTextOnly = T('preconditions:guildTextOnly'); +export const Nsfw = T('preconditions:nsfw'); +export const ThreadOnly = T('preconditions:threadOnly'); +export const UserPermissions = FT<{ missing: string[] }>('preconditions:userPermissions'); + +// Skyra: +export const Administrator = T('preconditions:administrator'); +export const Moderator = T('preconditions:moderator'); +export const NewsOnly = T('preconditions:newsOnly'); +export const PermissionNodes = T('preconditions:permissionNodes'); +export const ServerOwner = T('preconditions:serverOwner'); +export const SubCommandGuildOnly = T('preconditions:subCommandGuildOnly'); +export const TextOnly = T('preconditions:textOnly'); diff --git a/projects/bot/src/lib/i18n/languageKeys/keys/PromptList.ts b/projects/bot/src/lib/i18n/languageKeys/keys/PromptList.ts new file mode 100644 index 000000000..4de1d39fc --- /dev/null +++ b/projects/bot/src/lib/i18n/languageKeys/keys/PromptList.ts @@ -0,0 +1,5 @@ +import { FT, T } from '#lib/types'; + +export const MultipleChoice = FT<{ list: string; count: number }, string>('promptlist:multipleChoice'); +export const AttemptFailed = FT<{ list: string; attempt: number; maxAttempts: number }, string>('promptlist:attemptFailed'); +export const Aborted = T('promptlist:aborted'); diff --git a/src/lib/i18n/languageKeys/keys/Serializers.ts b/projects/bot/src/lib/i18n/languageKeys/keys/Serializers.ts similarity index 85% rename from src/lib/i18n/languageKeys/keys/Serializers.ts rename to projects/bot/src/lib/i18n/languageKeys/keys/Serializers.ts index 4684f0809..84e5f6981 100644 --- a/src/lib/i18n/languageKeys/keys/Serializers.ts +++ b/projects/bot/src/lib/i18n/languageKeys/keys/Serializers.ts @@ -30,11 +30,16 @@ export const WordIncluded = FT<{ name: string; value: string }>('serializers:wor export const PermissionNodeSecurityOwner = T('serializers:permissionNodeSecurityOwner'); export const ReactionRoleInvalid = T('serializers:reactionRoleInvalid'); export const StickyRoleInvalid = T('serializers:stickyRoleInvalid'); +export const TriggerAliasInvalid = T('serializers:triggerAliasInvalid'); +export const TriggerIncludeInvalid = T('serializers:triggerIncludeInvalid'); +export const TriggerIncludeInvalidAction = T('serializers:triggerIncludeInvalidAction'); +export const TwitchSubscriptionInvalid = T('serializers:twitchSubscriptionInvalid'); +export const TwitchSubscriptionInvalidStreamer = T('serializers:twitchSubscriptionInvalidStreamer'); export const UniqueRoleSetInvalid = T('serializers:uniqueRoleSetInvalid'); export const UnknownChannel = T('serializers:unknownChannel'); export const UnknownRole = T('serializers:unknownRole'); export const UnknownUser = T('serializers:unknownUser'); export const Unsupported = T('serializers:unsupported'); -export * as CustomCommands from '#lib/i18n/languageKeys/keys/CustomCommandSerializer/All'; -export * as DisabledCommandChannels from '#lib/i18n/languageKeys/keys/DisabledCommandChannels/All'; +export * as CustomCommands from './CustomCommandSerializer/All'; +export * as DisabledCommandChannels from './DisabledCommandChannels/All'; diff --git a/src/lib/i18n/languageKeys/keys/Settings.ts b/projects/bot/src/lib/i18n/languageKeys/keys/Settings.ts similarity index 85% rename from src/lib/i18n/languageKeys/keys/Settings.ts rename to projects/bot/src/lib/i18n/languageKeys/keys/Settings.ts index 5c0fada2a..5de702cfe 100644 --- a/src/lib/i18n/languageKeys/keys/Settings.ts +++ b/projects/bot/src/lib/i18n/languageKeys/keys/Settings.ts @@ -7,11 +7,8 @@ export const DisableNaturalPrefix = T('settings:disableNaturalPrefix'); export const DisabledChannels = T('settings:disabledChannels'); export const EventsBanAdd = T('settings:eventsBanAdd'); export const EventsBanRemove = T('settings:eventsBanRemove'); -export const EventsTimeout = T('settings:eventsTimeout'); -export const EventsUnknownMessages = T('settings:eventsUnknownMessages'); export const EventsTwemojiReactions = T('settings:eventsTwemojiReactions'); export const MessagesIgnoreChannels = T('settings:messagesIgnoreChannels'); -export const EventsIncludeBots = T('settings:eventsIncludeBots'); export const MessagesModerationAutoDelete = T('settings:messagesModerationAutoDelete'); export const MessagesModerationDM = T('settings:messagesModerationDm'); export const MessagesModerationMessageDisplay = T('settings:messagesModerationMessageDisplay'); @@ -74,7 +71,19 @@ export const SelfmodReactionsEnabled = T('settings:selfmodReactionsEnabled'); export const SelfmodReactionsIgnoredChannels = T('settings:selfmodReactionsIgnoredChannels'); export const SelfmodReactionsIgnoredRoles = T('settings:selfmodReactionsIgnoredRoles'); export const SelfmodReactionsAllowed = T('settings:selfmodReactionsAllowed'); +export const SocialEnabled = T('settings:socialEnabled'); +export const SocialMultiplier = T('settings:socialMultiplier'); +export const SocialAchieveRole = T('settings:socialAchieveRole'); +export const SocialAchieveLevel = T('settings:socialAchieveLevel'); +export const SocialAchieveChannel = T('settings:socialAchieveChannel'); +export const SocialAchieveMultiple = T('settings:socialAchieveMultiple'); +export const SocialIgnoredChannels = T('settings:socialIgnoredChannels'); +export const SocialIgnoredRoles = T('settings:socialIgnoredRoles'); +export const SuggestionsChannel = T('settings:suggestionsChannel'); +export const SuggestionsOnActionDM = T('settings:suggestionsOnActionDm'); +export const SuggestionsOnActionRePost = T('settings:suggestionsOnActionRePost'); +export const SuggestionsOnActionHideAuthor = T('settings:suggestionsOnActionHideAuthor'); export const DashboardOnlyKey = T('settings:dashboardOnlyKey'); -export * as Channels from '#lib/i18n/languageKeys/keys/settings/Channels'; -export * as Gateway from '#lib/i18n/languageKeys/keys/settings/Gateway'; +export * as Channels from './settings/Channels'; +export * as Gateway from './settings/Gateway'; diff --git a/projects/bot/src/lib/i18n/languageKeys/keys/System.ts b/projects/bot/src/lib/i18n/languageKeys/keys/System.ts new file mode 100644 index 000000000..ed799f32b --- /dev/null +++ b/projects/bot/src/lib/i18n/languageKeys/keys/System.ts @@ -0,0 +1,26 @@ +import { FT, T } from '#lib/types'; + +export const ParseError = T('system:parseError'); +export const FetchBansFail = T('system:fetchBansFail'); +export const Loading = T('system:loading'); +export const DiscordAbortError = T('system:discordAbortError'); +export const QueryFail = T('system:queryFail'); +export const NoResults = T('system:noResults'); +export const ExceededLengthOutput = FT<{ output: string }>('system:exceededLengthOutput'); +export const ExceededLengthOutputConsole = T('system:exceededLengthOutputConsole'); +export const ExceededLengthOutputFile = T('system:exceededLengthOutputFile'); +export const ExceededLengthOutputHastebin = FT<{ url: string }>('system:exceededLengthOutputHastebin'); +export const ExceededLengthChooseOutput = FT<{ output: string[] }>('system:exceededLengthChooseOutput'); +export const ExceededLengthOutputType = FT<{ type: string }>('system:exceededLengthOutputType'); +export const ExceededLengthOutputTime = FT<{ time: string }>('system:exceededLengthOutputTime'); +export const ExternalServerError = T('system:externalServerError'); +export const HelpTitles = T<{ + aliases: string; + usages: string; + extendedHelp: string; + explainedUsage: string; + possibleFormats: string; + examples: string; + reminders: string; +}>('system:helpTitles'); +export const ReminderHeader = FT<{ timestamp: string }>('system:reminderHeader'); diff --git a/projects/bot/src/lib/i18n/languageKeys/keys/commands/Admin.ts b/projects/bot/src/lib/i18n/languageKeys/keys/commands/Admin.ts new file mode 100644 index 000000000..a23cf547e --- /dev/null +++ b/projects/bot/src/lib/i18n/languageKeys/keys/commands/Admin.ts @@ -0,0 +1,37 @@ +import { FT, T } from '#lib/types'; + +export const ConfGet = FT<{ key: string; value: string }, string>('commands/admin:confGet'); +export const ConfGetNoExt = FT<{ key: string }, string>('commands/admin:confGetNoExt'); +export const ConfGuarded = FT<{ name: string }, string>('commands/admin:confGuarded'); +export const ConfMenuInvalidAction = T('commands/admin:confMenuInvalidAction'); +export const ConfMenuInvalidKey = T('commands/admin:confMenuInvalidKey'); +export const ConfMenuRenderAtFolder = FT<{ path: string }, string>('commands/admin:confMenuRenderAtFolder'); +export const ConfMenuRenderAtPiece = FT<{ path: string }, string>('commands/admin:confMenuRenderAtPiece'); +export const ConfMenuRenderBack = T('commands/admin:confMenuRenderBack'); +export const ConfMenuRenderCvalue = FT<{ value: string }, string>('commands/admin:confMenuRenderCvalue'); +export const ConfMenuRenderNokeys = T('commands/admin:confMenuRenderNokeys'); +export const ConfMenuRenderRemove = T('commands/admin:confMenuRenderRemove'); +export const ConfMenuRenderReset = T('commands/admin:confMenuRenderReset'); +export const ConfMenuRenderSelect = T('commands/admin:confMenuRenderSelect'); +export const ConfMenuRenderUndo = T('commands/admin:confMenuRenderUndo'); +export const ConfMenuRenderUpdate = T('commands/admin:confMenuRenderUpdate'); +export const ConfMenuSaved = T('commands/admin:confMenuSaved'); +export const ConfNochange = FT<{ key: string }, string>('commands/admin:confNochange'); +export const ConfReset = FT<{ key: string; value: string }, string>('commands/admin:confReset'); +export const Conf = FT<{ key: string; list: string }, string>('commands/admin:confServer'); +export const ConfDescription = T('commands/admin:confServerDescription'); +export const ConfExtended = T('commands/admin:confServerExtended'); +export const ConfSettingNotSet = T('commands/admin:confSettingNotSet'); +export const ConfUpdated = FT<{ key: string; response: string }, string>('commands/admin:confUpdated'); +export const ConfDashboardOnlyKey = FT<{ key: string }, string>('commands/admin:confDashboardOnlyKey'); +export const RoleSetAdded = FT<{ name: string; roles: string[] }, string>('commands/admin:rolesetAdded'); +export const RoleSetCreated = FT<{ name: string; roles: string[] }, string>('commands/admin:rolesetCreated'); +export const RoleSetDescription = T('commands/admin:rolesetDescription'); +export const RoleSetExtended = T('commands/admin:rolesetExtended'); +export const RoleSetNoRoleSets = T('commands/admin:rolesetNoRolesets'); +export const RoleSetRemoved = FT<{ name: string; roles: string[] }, string>('commands/admin:rolesetRemoved'); +export const RoleSetResetAll = T('commands/admin:rolesetResetAll'); +export const RoleSetResetEmpty = T('commands/admin:rolesetResetEmpty'); +export const RoleSetResetGroup = FT<{ name: string }, string>('commands/admin:rolesetResetGroup'); +export const RoleSetResetNotExists = FT<{ name: string }, string>('commands/admin:rolesetResetNotExists'); +export const RoleSetUpdated = FT<{ name: string }, string>('commands/admin:rolesetUpdated'); diff --git a/src/lib/i18n/languageKeys/keys/commands/Management.ts b/projects/bot/src/lib/i18n/languageKeys/keys/commands/Management.ts similarity index 81% rename from src/lib/i18n/languageKeys/keys/commands/Management.ts rename to projects/bot/src/lib/i18n/languageKeys/keys/commands/Management.ts index 8181660f2..1f4a3b49b 100644 --- a/src/lib/i18n/languageKeys/keys/commands/Management.ts +++ b/projects/bot/src/lib/i18n/languageKeys/keys/commands/Management.ts @@ -1,9 +1,24 @@ import type { LanguageHelpDisplayOptions } from '#lib/i18n/LanguageHelp'; import { FT, T } from '#lib/types'; -import type { GuildVerificationLevel, Role } from 'discord.js'; +import type { Role, User } from 'discord.js'; +export const AttachmentsModeDescription = T('commands/management:attachmentsModeDescription'); +export const AttachmentsModeExtended = T('commands/management:attachmentsModeExtended'); +export const CapitalsModeDescription = T('commands/management:capitalsModeDescription'); +export const CapitalsModeExtended = T('commands/management:capitalsModeExtended'); export const CreateMuteDescription = T('commands/management:createMuteDescription'); export const CreateMuteExtended = T('commands/management:createMuteExtended'); +export const FilterAdded = FT<{ word: string }, string>('commands/management:filterAdded'); +export const FilterAlreadyFiltered = T('commands/management:filterAlreadyFiltered'); +export const FilterDescription = T('commands/management:filterDescription'); +export const FilterExtended = T('commands/management:filterExtended'); +export const FilterModeDescription = T('commands/management:filterModeDescription'); +export const FilterModeExtended = T('commands/management:filterModeExtended'); +export const FilterNotFiltered = T('commands/management:filterNotFiltered'); +export const FilterRemoved = FT<{ word: string }, string>('commands/management:filterRemoved'); +export const FilterReset = T('commands/management:filterReset'); +export const FilterShow = FT<{ words: string }, string>('commands/management:filterShow'); +export const FilterShowEmpty = T('commands/management:filterShowEmpty'); export const GuildInfoChannels = FT<{ text: number; voice: number; categories: number; afkChannelText: string }, string>( 'commands/management:guildInfoChannels' ); @@ -12,12 +27,12 @@ export const GuildInfoChannelsAfkChannelText = FT<{ afkChannel: string; afkTime: ); export const GuildInfoDescription = T('commands/management:guildInfoDescription'); export const GuildInfoExtended = T('commands/management:guildInfoExtended'); -export const GuildInfoMembers = FT<{ memberCount: number; ownerId: string; ownerTag: string }, string>('commands/management:guildInfoMembers'); +export const GuildInfoMembers = FT<{ memberCount: number; owner: User }, string>('commands/management:guildInfoMembers'); export const GuildInfoOther = FT< { size: number; createdAt: string; - verificationLevel: GuildVerificationLevel; + verificationLevel: 'NONE' | 'LOW' | 'MEDIUM' | 'HIGH' | 'VERY_HIGH'; }, string >('commands/management:guildInfoOther'); @@ -26,6 +41,10 @@ export const GuildInfoBanner = T('commands/management:guildInfoBanner'); export const GuildInfoIcon = T('commands/management:guildInfoIcon'); export const GuildInfoSplash = T('commands/management:guildInfoSplash'); export const GuildInfoDiscoverySplash = T('commands/management:guildInfoDiscoverySplash'); +export const InviteModeDescription = T('commands/management:inviteModeDescription'); +export const InviteModeExtended = T('commands/management:inviteModeExtended'); +export const LinkModeDescription = T('commands/management:linkModeDescription'); +export const LinkModeExtended = T('commands/management:linkModeExtended'); export const ManageCommandAutoDeleteAdd = FT<{ channel: string; time: number }, string>('commands/management:manageCommandAutoDeleteAdd'); export const ManageCommandAutoDeleteDescription = T('commands/management:managecommandautodeleteDescription'); export const ManageCommandAutoDeleteExtended = T('commands/management:managecommandautodeleteExtended'); @@ -55,6 +74,10 @@ export const ManageReactionRolesRemoveNotExists = T('commands/management export const ManageReactionRolesReset = T('commands/management:manageReactionRolesReset'); export const ManageReactionRolesResetEmpty = T('commands/management:manageReactionRolesResetEmpty'); export const ManageReactionRolesShowEmpty = T('commands/management:manageReactionRolesShowEmpty'); +export const MessageModeDescription = T('commands/management:messageModeDescription'); +export const MessageModeExtended = T('commands/management:messageModeExtended'); +export const NewlineModeDescription = T('commands/management:newlineModeDescription'); +export const NewlineModeExtended = T('commands/management:newlineModeExtended'); export const PermissionNodesAdd = T('commands/management:permissionNodesAdd'); export const PermissionNodesCommandNotExists = T('commands/management:permissionNodesCommandNotExists'); export const PermissionNodesDescription = T('commands/management:permissionNodesDescription'); @@ -68,6 +91,8 @@ export const PermissionNodesReset = T('commands/management:permissionNod export const PermissionNodesShowAllow = FT<{ allow: string }, string>('commands/management:permissionNodesShowAllow'); export const PermissionNodesShowDeny = FT<{ deny: string }, string>('commands/management:permissionNodesShowDeny'); export const PermissionNodesShowName = FT<{ name: string }, string>('commands/management:permissionNodesShowName'); +export const ReactionModeDescription = T('commands/management:reactionModeDescription'); +export const ReactionModeExtended = T('commands/management:reactionModeExtended'); export const RoleInfoAll = T('commands/management:roleInfoAll'); export const RoleInfoData = FT<{ role: Role; hoisted: string; mentionable: string }, string>('commands/management:roleInfoData'); export const RoleInfoDescription = T('commands/management:roleInfoDescription'); diff --git a/src/lib/i18n/languageKeys/keys/commands/Moderation.ts b/projects/bot/src/lib/i18n/languageKeys/keys/commands/Moderation.ts similarity index 57% rename from src/lib/i18n/languageKeys/keys/commands/Moderation.ts rename to projects/bot/src/lib/i18n/languageKeys/keys/commands/Moderation.ts index c494c0008..09a22a438 100644 --- a/src/lib/i18n/languageKeys/keys/commands/Moderation.ts +++ b/projects/bot/src/lib/i18n/languageKeys/keys/commands/Moderation.ts @@ -1,12 +1,62 @@ import type { LanguageHelpDisplayOptions } from '#lib/i18n/LanguageHelp'; import { FT, T } from '#lib/types'; +import type { ModerationManagerDescriptionData } from '#utils/moderationConstants'; +import type { User } from 'discord.js'; +export interface ModerationAction { + addRole: string; + mute: string; + ban: string; + kick: string; + softban: string; + vkick: string; + vmute: string; + restrictedReact: string; + restrictedEmbed: string; + restrictedAttachment: string; + restrictedVoice: string; + setNickname: string; + removeRole: string; +} + +export const HistoryDescription = T('commands/moderation:historyDescription'); +export const HistoryExtended = T('commands/moderation:historyExtended'); +export const HistoryFooterNew = FT< + { + warnings: number; + mutes: number; + kicks: number; + bans: number; + warningsText: string; + mutesText: string; + kicksText: string; + bansText: string; + }, + string +>('commands/moderation:historyFooterNew'); +export const HistoryFooterWarning = FT<{ count: number }, string>('commands/moderation:historyFooterWarning'); +export const HistoryFooterMutes = FT<{ count: number }, string>('commands/moderation:historyFooterMutes'); +export const HistoryFooterKicks = FT<{ count: number }, string>('commands/moderation:historyFooterKicks'); +export const HistoryFooterBans = FT<{ count: number }, string>('commands/moderation:historyFooterBans'); +export const ModerationsDescription = T('commands/moderation:moderationsDescription'); +export const ModerationsExtended = T('commands/moderation:moderationsExtended'); +export const ModerationsEmpty = FT<{ prefix: string }, string>('commands/moderation:moderationsEmpty'); +export const ModerationsAmount = FT<{ count: number }, string>('commands/moderation:moderationsAmount'); +export const MutesDescription = T('commands/moderation:mutesDescription'); +export const MutesExtended = T('commands/moderation:mutesExtended'); +export const WarningsDescription = T('commands/moderation:warningsDescription'); +export const WarningsExtended = T('commands/moderation:warningsExtended'); export const MuteDescription = T('commands/moderation:muteDescription'); export const MuteExtended = T('commands/moderation:muteExtended'); export const PruneDescription = T('commands/moderation:pruneDescription'); export const PruneExtended = T('commands/moderation:pruneExtended'); +export const CaseDescription = T('commands/moderation:caseDescription'); +export const CaseExtended = T('commands/moderation:caseExtended'); +export const CaseDeleted = FT<{ case: number }, string>('commands/moderation:caseDeleted'); export const PermissionsDescription = T('commands/moderation:permissionsDescription'); export const PermissionsExtended = T('commands/moderation:permissionsExtended'); +export const ReasonDescription = T('commands/moderation:reasonDescription'); +export const ReasonExtended = T('commands/moderation:reasonExtended'); export const RestrictAttachmentDescription = T('commands/moderation:restrictAttachmentDescription'); export const RestrictAttachmentExtended = T('commands/moderation:restrictAttachmentExtended'); export const RestrictEmbedDescription = T('commands/moderation:restrictEmbedDescription'); @@ -19,11 +69,6 @@ export const RestrictVoiceDescription = T('commands/moderation:restrictVoiceDesc export const RestrictVoiceExtended = T('commands/moderation:restrictVoiceExtended'); export const SoftBanDescription = T('commands/moderation:softBanDescription'); export const SoftBanExtended = T('commands/moderation:softBanExtended'); -export const TimeoutApplyDescription = T('commands/moderation:timeoutApplyDescription'); -export const TimeoutApplyExtended = T('commands/moderation:timeoutApplyExtended'); -export const TimeoutUndoDescription = T('commands/moderation:timeoutUndoDescription'); -export const TimeoutUndoExtended = T('commands/moderation:timeoutUndoExtended'); -export const TimeoutNotModeratable = T('commands/moderation:timeoutNotModeratable'); export const ToggleModerationDmDescription = T('commands/moderation:toggleModerationDmDescription'); export const ToggleModerationDmExtended = T('commands/moderation:toggleModerationDmExtended'); export const UnbanDescription = T('commands/moderation:unbanDescription'); @@ -40,6 +85,8 @@ export const UnrestrictReactionDescription = T('commands/moderation:unrestrictRe export const UnrestrictReactionExtended = T('commands/moderation:unrestrictReactionExtended'); export const UnrestrictVoiceDescription = T('commands/moderation:unrestrictVoiceDescription'); export const UnrestrictVoiceExtended = T('commands/moderation:unrestrictVoiceExtended'); +export const UnwarnDescription = T('commands/moderation:unwarnDescription'); +export const UnwarnExtended = T('commands/moderation:unwarnExtended'); export const VmuteDescription = T('commands/moderation:vmuteDescription'); export const VmuteExtended = T('commands/moderation:vmuteExtended'); export const VoiceKickDescription = T('commands/moderation:voiceKickDescription'); @@ -48,11 +95,18 @@ export const VunmuteDescription = T('commands/moderation:vunmuteDescription'); export const VunmuteExtended = T('commands/moderation:vunmuteExtended'); export const WarnDescription = T('commands/moderation:warnDescription'); export const WarnExtended = T('commands/moderation:warnExtended'); -export const SlowmodeSet = FT<{ cooldown: number }>('commands/moderation:slowmodeSet'); +export const TimeTimed = T('commands/moderation:timeTimed'); +export const TimeUnsupportedType = T('commands/moderation:timeUnsupportedType'); +export const TimeNotScheduled = T('commands/moderation:timeNotScheduled'); +export const TimeAborted = FT<{ title: string }, string>('commands/moderation:timeAborted'); +export const TimeScheduled = FT<{ title: string; user: User; time: number }, string>('commands/moderation:timeScheduled'); +export const SlowmodeSet = FT<{ cooldown: number }, string>('commands/moderation:slowmodeSet'); export const SlowmodeReset = T('commands/moderation:slowmodeReset'); +export const TimeDescription = T('commands/moderation:timeDescription'); +export const TimeExtended = T('commands/moderation:timeExtended'); export const BanNotBannable = T('commands/moderation:banNotBannable'); -export const DehoistStarting = FT<{ count: number }>('commands/moderation:dehoistStarting'); -export const DehoistProgress = FT<{ count: number; percentage: number }>('commands/moderation:dehoistProgress'); +export const DehoistStarting = FT<{ count: number }, string>('commands/moderation:dehoistStarting'); +export const DehoistProgress = FT<{ count: number; percentage: number }, string>('commands/moderation:dehoistProgress'); export const DehoistEmbed = FT< { users: number; dehoistedMemberCount: number; dehoistedWithErrorsCount: number; errored: number }, { @@ -66,46 +120,61 @@ export const DehoistEmbed = FT< } >('commands/moderation:dehoistEmbed'); export const KickNotKickable = T('commands/moderation:kickNotKickable'); -export const LockdownLock = FT<{ channel: string }>('commands/moderation:lockdownLock'); -export const LockdownLocking = FT<{ channel: string }>('commands/moderation:lockdownLocking'); -export const LockdownLocked = FT<{ channel: string }>('commands/moderation:lockdownLocked'); -export const LockdownUnlocked = FT<{ channel: string }>('commands/moderation:lockdownUnlocked'); -export const LockdownOpen = FT<{ channel: string }>('commands/moderation:lockdownOpen'); +export const LockdownLock = FT<{ channel: string }, string>('commands/moderation:lockdownLock'); +export const LockdownLocking = FT<{ channel: string }, string>('commands/moderation:lockdownLocking'); +export const LockdownLocked = FT<{ channel: string }, string>('commands/moderation:lockdownLocked'); +export const LockdownUnlocked = FT<{ channel: string }, string>('commands/moderation:lockdownUnlocked'); +export const LockdownOpen = FT<{ channel: string }, string>('commands/moderation:lockdownOpen'); export const MuteMuted = T('commands/moderation:muteMuted'); +export const MuteUserNotMuted = T('commands/moderation:muteUserNotMuted'); export const RestrictLowlevel = T('commands/moderation:restrictLowlevel'); -export const PruneAlert = FT<{ count: number; total: number }>('commands/moderation:pruneAlert'); +export const PruneAlert = FT<{ count: number; total: number }, string>('commands/moderation:pruneAlert'); export const PruneInvalidPosition = T('commands/moderation:pruneInvalidPosition'); export const PruneNoDeletes = T('commands/moderation:pruneNoDeletes'); export const PruneLogHeader = T('commands/moderation:pruneLogHeader'); -export const PruneNotSubcommandSameOFSameFlag = T('commands/moderation:pruneNotSubcommandSameOFSameFlag'); +export const PruneLogMessage = FT<{ channel: string; author: string; count: number }, string>('commands/moderation:pruneLogMessage'); +export const ReasonNotExists = T('commands/moderation:reasonNotExists'); +export const ReasonUpdated = FT<{ entries: readonly number[]; newReason: string; count: number }>('commands/moderation:reasonUpdated'); export const ToggleModerationDmToggledEnabled = T('commands/moderation:toggleModerationDmToggledEnabled'); export const ToggleModerationDmToggledDisabled = T('commands/moderation:toggleModerationDmToggledDisabled'); +export const UnbanMissingPermission = T('commands/moderation:unbanMissingPermission'); +export const UnmuteMissingPermission = T('commands/moderation:unmuteMissingPermission'); +export const VmuteMissingPermission = T('commands/moderation:vmuteMissingPermission'); export const VmuteUserNotMuted = T('commands/moderation:vmuteUserNotMuted'); -export const ModerationOutput = FT<{ count: number; range: string | number; users: string; reason: string | null }>( +export const ModerationOutput = FT<{ count: number; range: string | number; users: string; reason: string | null }, string>( 'commands/moderation:moderationOutput' ); -export const ModerationOutputWithReason = FT<{ count: number; range: string | number; users: string; reason: string | null }>( +export const ModerationOutputWithReason = FT<{ count: number; range: string | number; users: string; reason: string | null }, string>( 'commands/moderation:moderationOutputWithReason' ); +export const ModerationCaseNotExists = FT<{ count: number }, string>('moderation:caseNotExists'); +export const ModerationLogAppealed = T('moderation:logAppealed'); +export const ModerationLogDescriptionTypeAndUser = FT<{ data: ModerationManagerDescriptionData }, string>('moderation:logDescriptionTypeAndUser'); +export const ModerationLogDescriptionWithReason = FT<{ data: ModerationManagerDescriptionData }, string>('moderation:logDescriptionWithReason'); +export const ModerationLogDescriptionWithoutReason = FT<{ data: ModerationManagerDescriptionData }, string>('moderation:logDescriptionWithoutReason'); export const GuildBansEmpty = T('errors:guildBansEmpty'); export const GuildBansNotFound = T('errors:guildBansNotFound'); export const GuildMemberNotVoicechannel = T('errors:guildMemberNotVoicechannel'); -export const ModerationFailed = FT<{ users: string; count: number }>('commands/moderation:moderationFailed'); +export const GuildWarnNotFound = T('errors:guildWarnNotFound'); +export const ModerationLogExpiresIn = FT<{ duration: number }, string>('moderation:logExpiresIn'); +export const ModerationLogFooter = FT<{ caseId: number }, string>('moderation:logFooter'); +export const ModerationTimed = FT<{ remaining: number }, string>('errors:modlogTimed'); +export const ModerationFailed = FT<{ users: string; count: number }, string>('commands/moderation:moderationFailed'); export const ModerationDmFooter = T('commands/moderation:moderationDmFooter'); -export const ModerationDmDescription = FT<{ guild: string; title: string; reason: string | null; duration: number | null }>( +export const ModerationDmDescription = FT<{ guild: string; title: string; reason: string | null; duration: number | null }, string>( 'commands/moderation:moderationDmDescription' ); -export const ModerationDmDescriptionWithReason = FT<{ guild: string; title: string; reason: string | null; duration: number | null }>( +export const ModerationDmDescriptionWithReason = FT<{ guild: string; title: string; reason: string | null; duration: number | null }, string>( 'commands/moderation:moderationDmDescriptionWithReason' ); -export const ModerationDmDescriptionWithDuration = FT<{ guild: string; title: string; reason: string | null; duration: number | null }>( +export const ModerationDmDescriptionWithDuration = FT<{ guild: string; title: string; reason: string | null; duration: number | null }, string>( 'commands/moderation:moderationDmDescriptionWithDuration' ); export const ModerationDmDescriptionWithReasonWithDuration = FT< { guild: string; title: string; reason: string | null; duration: number | null }, string >('commands/moderation:moderationDmDescriptionWithReasonWithDuration'); -export const Permissions = FT<{ username: string; id: string }>('commands/moderation:permissions'); +export const Permissions = FT<{ username: string; id: string }, string>('commands/moderation:permissions'); export const PermissionsAll = T('commands/moderation:permissionsAll'); export const SlowmodeDescription = T('commands/moderation:slowmodeDescription'); export const SlowmodeExtended = T('commands/moderation:slowmodeExtended'); @@ -123,31 +192,39 @@ export const KickDescription = T('commands/moderation:kickDescription'); export const KickExtended = T('commands/moderation:kickExtended'); export const LockdownDescription = T('commands/moderation:lockdownDescription'); export const LockdownExtended = T('commands/moderation:lockdownExtended'); -export const AutomaticParameterInvalidMissingAction = FT<{ name: string }>('selfModeration:commandInvalidMissingAction'); -export const AutomaticParameterInvalidMissingArguments = FT<{ name: string }>('selfModeration:commandInvalidMissingArguments'); -export const AutomaticParameterInvalidSoftAction = FT<{ name: string }>('selfModeration:commandInvalidSoftaction'); -export const AutomaticParameterInvalidHardAction = FT<{ name: string }>('selfModeration:commandInvalidHardaction'); +export const MuteCannotManageRoles = T('moderation:muteCannotManageRoles'); +export const MuteLowHierarchy = T('moderation:muteLowHierarchy'); +export const MuteNotConfigured = T('moderation:muteNotConfigured'); +export const MuteNotExists = T('moderation:muteNotExists'); +export const MuteNotInMember = T('moderation:muteNotInMember'); +export const AutomaticParameterInvalidMissingAction = FT<{ name: string }, string>('selfModeration:commandInvalidMissingAction'); +export const AutomaticParameterInvalidMissingArguments = FT<{ name: string }, string>('selfModeration:commandInvalidMissingArguments'); +export const AutomaticParameterInvalidSoftAction = FT<{ name: string }, string>('selfModeration:commandInvalidSoftaction'); +export const AutomaticParameterInvalidHardAction = FT<{ name: string }, string>('selfModeration:commandInvalidHardaction'); export const AutomaticParameterEnabled = T('selfModeration:commandEnabled'); export const AutomaticParameterDisabled = T('selfModeration:commandDisabled'); export const AutomaticParameterSoftAction = T('selfModeration:commandSoftAction'); -export const AutomaticParameterSoftActionWithValue = FT<{ value: string }>('selfModeration:commandSoftActionWithValue'); -export const AutomaticParameterHardAction = FT<{ value: string }>('selfModeration:commandHardAction'); +export const AutomaticParameterSoftActionWithValue = FT<{ value: string }, string>('selfModeration:commandSoftActionWithValue'); +export const AutomaticParameterHardAction = FT<{ value: string }, string>('selfModeration:commandHardAction'); export const AutomaticParameterHardActionDuration = T('selfModeration:commandHardActionDuration'); -export const AutomaticParameterHardActionDurationWithValue = FT<{ value: number }>('selfModeration:commandHardActionDurationWithValue'); +export const AutomaticParameterHardActionDurationWithValue = FT<{ value: number }, string>('selfModeration:commandHardActionDurationWithValue'); export const AutomaticParameterThresholdMaximum = T('selfModeration:commandThresholdMaximum'); -export const AutomaticParameterThresholdMaximumWithValue = FT<{ value: number }>('selfModeration:commandThresholdMaximumWithValue'); +export const AutomaticParameterThresholdMaximumWithValue = FT<{ value: number }, string>('selfModeration:commandThresholdMaximumWithValue'); export const AutomaticParameterThresholdDuration = T('selfModeration:commandThresholdDuration'); -export const AutomaticParameterThresholdDurationWithValue = FT<{ value: number }>('selfModeration:commandThresholdDurationWithValue'); -export const AutomaticParameterShow = FT<{ - kEnabled: string; - kAlert: string; - kLog: string; - kDelete: string; - kHardAction: string; - hardActionDurationText: string; - thresholdMaximumText: string | number; - thresholdDurationText: string; -}>('selfModeration:commandShow'); +export const AutomaticParameterThresholdDurationWithValue = FT<{ value: number }, string>('selfModeration:commandThresholdDurationWithValue'); +export const AutomaticParameterShow = FT< + { + kEnabled: string; + kAlert: string; + kLog: string; + kDelete: string; + kHardAction: string; + hardActionDurationText: string; + thresholdMaximumText: string | number; + thresholdDurationText: string; + }, + string +>('selfModeration:commandShow'); export const AutomaticParameterShowDurationPermanent = T('selfModeration:commandShowDurationPermanent'); export const AutomaticParameterShowUnset = T('selfModeration:commandShowUnset'); export const AutomaticValueSoftActionAlert = T('selfModeration:softActionAlert'); @@ -159,28 +236,30 @@ export const AutomaticValueHardActionMute = T('selfModeration:hardActionMute'); export const AutomaticValueHardActionSoftBan = T('selfModeration:hardActionSoftban'); export const AutomaticValueHardActionWarning = T('selfModeration:hardActionWarning'); export const AutomaticValueHardActionNone = T('selfModeration:hardActionNone'); -export const ActionApplyReason = FT<{ action: string; reason: string }>('moderationActions:applyReason'); -export const ActionApplyNoReason = FT<{ action: string }>('moderationActions:applyNoReason'); -export const ActionRevokeReason = FT<{ action: string; reason: string }>('moderationActions:revokeReason'); -export const ActionRevokeNoReason = FT<{ action: string }>('moderationActions:revokeNoReason'); -export const ActionSoftBanReason = FT<{ reason: string }>('moderationActions:softbanReason'); -export const ActionUnSoftBanReason = FT<{ reason: string }>('moderationActions:unSoftbanReason'); +export const Actions = T('moderationActions:actions'); +export const ActionApplyReason = FT<{ action: string; reason: string }, string>('moderationActions:applyReason'); +export const ActionApplyNoReason = FT<{ action: string }, string>('moderationActions:applyNoReason'); +export const ActionRevokeReason = FT<{ action: string; reason: string }, string>('moderationActions:revokeReason'); +export const ActionRevokeNoReason = FT<{ action: string }, string>('moderationActions:revokeNoReason'); +export const ActionSoftBanReason = FT<{ reason: string }, string>('moderationActions:softbanReason'); +export const ActionUnSoftBanReason = FT<{ reason: string }, string>('moderationActions:unSoftbanReason'); export const ActionSoftBanNoReason = T('moderationActions:softbanNoReason'); export const ActionUnSoftBanNoReason = T('moderationActions:unSoftbanNoReason'); -export const ActionSetNicknameSet = FT<{ reason: string }>('moderationActions:setNicknameSet'); -export const ActionSetNicknameRemoved = FT<{ reason: string }>('moderationActions:setNicknameRemoved'); +export const ActionSetNicknameSet = FT<{ reason: string }, string>('moderationActions:setNicknameSet'); +export const ActionSetNicknameRemoved = FT<{ reason: string }, string>('moderationActions:setNicknameRemoved'); export const ActionSetNicknameNoReasonSet = T('moderationActions:setNicknameNoReasonSet'); export const ActionSetNicknameNoReasonRemoved = T('moderationActions:setNicknameNoReasonRemoved'); export const ActionSetupMuteExists = T('moderationActions:setupMuteExists'); +export const ActionSetupRestrictionExists = T('moderationActions:setupRestrictionExists'); export const ActionSetupTooManyRoles = T('moderationActions:setupTooManyRoles'); export const ActionSharedRoleSetupExisting = T('moderationActions:sharedRoleSetupExisting'); export const ActionSharedRoleSetupExistingName = T('moderationActions:sharedRoleSetupExistingName'); export const ActionSharedRoleSetupNew = T('moderationActions:sharedRoleSetupNew'); -export const ActionSharedRoleSetupAsk = FT<{ role: string; channels: number; permissions: string }>('moderationActions:sharedRoleSetupAsk'); +export const ActionSharedRoleSetupAsk = FT<{ role: string; channels: number; permissions: string }, string>('moderationActions:sharedRoleSetupAsk'); export const ActionSharedRoleSetupNoMessage = T('moderationActions:sharedRoleSetupNoMessage'); export const ActionRequiredMember = T('moderationActions:requiredMember'); -export const ActionCannotManageRoles = T('moderationActions:actionCannotManageRoles'); -export const ActionRoleNotConfigured = T('moderationActions:actionRoleNotConfigured'); -export const ActionRoleHigherPosition = T('moderationActions:actionRoleHigherPosition'); -export const ActionRoleManaged = T('moderationActions:actionRoleManaged'); +export const RoleHigher = T('moderation:roleHigher'); +export const RoleHigherSkyra = T('moderation:roleHigherSkyra'); export const Success = T('moderation:success'); +export const ToSkyra = T('moderation:toSkyra'); +export const UserSelf = T('moderation:userSelf'); diff --git a/projects/bot/src/lib/i18n/languageKeys/keys/commands/Whois.ts b/projects/bot/src/lib/i18n/languageKeys/keys/commands/Whois.ts new file mode 100644 index 000000000..2e4a61ed6 --- /dev/null +++ b/projects/bot/src/lib/i18n/languageKeys/keys/commands/Whois.ts @@ -0,0 +1,12 @@ +import { T } from '@wolfstar/http-framework-i18n'; + +export const RootName = T('commands/whois:name'); +export const RootDescription = T('commands/whois:description'); + +export const User = 'commands/whois:user'; +export const OptionsUser = 'commands/whois:optionsUser'; + +export const Role = 'commands/whois:role'; +export const OptionsRole = 'commands/whois:optionsRole'; + +export const Server = 'commands/whois:server'; diff --git a/projects/bot/src/lib/i18n/languageKeys/keys/events/All.ts b/projects/bot/src/lib/i18n/languageKeys/keys/events/All.ts new file mode 100644 index 000000000..e0635521e --- /dev/null +++ b/projects/bot/src/lib/i18n/languageKeys/keys/events/All.ts @@ -0,0 +1,7 @@ +export * as Errors from './errors/All'; +export * as Guilds from './guilds/All'; +export * as Messages from './messages/All'; +export * as Moderation from './moderation/All'; +export * as NoMentionSpam from './NoMentionSpam'; +export * as Reactions from './reactions/All'; +export * as Twitch from './twitch/All'; diff --git a/src/lib/i18n/languageKeys/keys/events/NoMentionSpam.ts b/projects/bot/src/lib/i18n/languageKeys/keys/events/NoMentionSpam.ts similarity index 67% rename from src/lib/i18n/languageKeys/keys/events/NoMentionSpam.ts rename to projects/bot/src/lib/i18n/languageKeys/keys/events/NoMentionSpam.ts index c838993cb..53e6d4682 100644 --- a/src/lib/i18n/languageKeys/keys/events/NoMentionSpam.ts +++ b/projects/bot/src/lib/i18n/languageKeys/keys/events/NoMentionSpam.ts @@ -1,6 +1,7 @@ import { FT, T } from '#lib/types'; +import type { User } from 'discord.js'; export const Alert = T('events/noMentionSpam:alert'); export const Footer = T('events/noMentionSpam:footer'); -export const Message = FT<{ userId: string; userTag: string }, string>('events/noMentionSpam:message'); +export const Message = FT<{ user: User }, string>('events/noMentionSpam:message'); export const ModerationLog = FT<{ threshold: number }, string>('events/noMentionSpam:modlog'); diff --git a/src/lib/i18n/languageKeys/keys/events/errors/All.ts b/projects/bot/src/lib/i18n/languageKeys/keys/events/errors/All.ts similarity index 100% rename from src/lib/i18n/languageKeys/keys/events/errors/All.ts rename to projects/bot/src/lib/i18n/languageKeys/keys/events/errors/All.ts diff --git a/projects/bot/src/lib/i18n/languageKeys/keys/events/guilds/All.ts b/projects/bot/src/lib/i18n/languageKeys/keys/events/guilds/All.ts new file mode 100644 index 000000000..d53e86e90 --- /dev/null +++ b/projects/bot/src/lib/i18n/languageKeys/keys/events/guilds/All.ts @@ -0,0 +1,2 @@ +export * as Logs from './Logs'; +export * as Members from './Members'; diff --git a/src/lib/i18n/languageKeys/keys/events/guilds/Logs.ts b/projects/bot/src/lib/i18n/languageKeys/keys/events/guilds/Logs.ts similarity index 87% rename from src/lib/i18n/languageKeys/keys/events/guilds/Logs.ts rename to projects/bot/src/lib/i18n/languageKeys/keys/events/guilds/Logs.ts index 23c5bb49e..79173eedd 100644 --- a/src/lib/i18n/languageKeys/keys/events/guilds/Logs.ts +++ b/projects/bot/src/lib/i18n/languageKeys/keys/events/guilds/Logs.ts @@ -1,7 +1,7 @@ -import { FT, T, type Difference, type Value, type Values } from '#lib/types'; -import type { ChannelMention, GuildDefaultMessageNotifications, GuildExplicitContentFilter, GuildVerificationLevel } from 'discord.js'; +import { Difference, FT, T, Value, Values } from '#lib/types'; +import type { DefaultMessageNotificationLevel, ExplicitContentFilterLevel, VerificationLevel } from 'discord.js'; -type Notifications = GuildDefaultMessageNotifications; +type Notifications = DefaultMessageNotificationLevel | number; export const ChannelCreate = T('events/guilds-logs:channelCreate'); export const ChannelCreateParent = FT('events/guilds-logs:channelCreateParent'); @@ -85,7 +85,7 @@ export const ServerUpdateDescription = FT('events/guilds-logs:server export const ServerUpdateDiscoverySplashAdded = FT('events/guilds-logs:serverUpdateDiscoverySplashAdded'); export const ServerUpdateDiscoverySplashRemoved = FT('events/guilds-logs:serverUpdateDiscoverySplashRemoved'); export const ServerUpdateDiscoverySplash = FT('events/guilds-logs:serverUpdateDiscoverySplash'); -export const ServerUpdateExplicitContentFilter = FT>('events/guilds-logs:serverUpdateExplicitContentFilter'); +export const ServerUpdateExplicitContentFilter = FT>('events/guilds-logs:serverUpdateExplicitContentFilter'); export const ServerUpdateFeaturesAdded = FT('events/guilds-logs:serverUpdateFeaturesAdded'); export const ServerUpdateFeaturesRemoved = FT('events/guilds-logs:serverUpdateFeaturesRemoved'); export const ServerUpdateIconAdded = FT('events/guilds-logs:serverUpdateIconAdded'); @@ -122,24 +122,9 @@ export const ServerUpdateSystemChannel = FT('events/guilds-logs:serv export const ServerUpdateVanityUrlAdded = FT('events/guilds-logs:serverUpdateVanityUrlAdded'); export const ServerUpdateVanityUrlRemoved = FT('events/guilds-logs:serverUpdateVanityUrlRemoved'); export const ServerUpdateVanityUrl = FT('events/guilds-logs:serverUpdateVanityUrl'); -export const ServerUpdateVerificationLevel = FT>('events/guilds-logs:serverUpdateVerificationLevel'); +export const ServerUpdateVerificationLevel = FT>('events/guilds-logs:serverUpdateVerificationLevel'); export const ServerUpdateWidgetChannelAdded = FT('events/guilds-logs:serverUpdateWidgetChannelAdded'); export const ServerUpdateWidgetChannelRemoved = FT('events/guilds-logs:serverUpdateWidgetChannelRemoved'); export const ServerUpdateWidgetChannel = FT('events/guilds-logs:serverUpdateWidgetChannel'); export const ServerUpdateWidgetEnabled = T('events/guilds-logs:serverUpdateWidgetEnabled'); export const ServerUpdateWidgetDisabled = T('events/guilds-logs:serverUpdateWidgetDisabled'); -export const VoiceChannelJoin = FT<{ channel: ChannelMention }>('events/guilds-logs:voiceChannelJoin'); -export const VoiceChannelLeave = FT<{ channel: ChannelMention }>('events/guilds-logs:voiceChannelLeave'); -export const VoiceChannelMove = FT<{ oldChannel: ChannelMention; newChannel: ChannelMention }>('events/guilds-logs:voiceChannelMove'); -export const CommandExecuteTitle = T('events/guilds-logs:commandExecuteTitle'); -export const SettingsUpdateTitle = T('events/guilds-logs:settingsUpdateTitle'); -export const SettingsAccessDeniedTitle = T('events/guilds-logs:settingsAccessDeniedTitle'); -export const LogFieldUser = T('events/guilds-logs:logFieldUser'); -export const LogFieldCommand = T('events/guilds-logs:logFieldCommand'); -export const LogFieldType = T('events/guilds-logs:logFieldType'); -export const LogFieldChannel = T('events/guilds-logs:logFieldChannel'); -export const LogFieldChange = T('events/guilds-logs:logFieldChange'); -export const LogFieldReason = T('events/guilds-logs:logFieldReason'); -export const CommandTypeChatInput = T('events/guilds-logs:commandTypeChatInput'); -export const CommandTypeContextMenu = T('events/guilds-logs:commandTypeContextMenu'); -export const CommandTypeMessage = T('events/guilds-logs:commandTypeMessage'); diff --git a/projects/bot/src/lib/i18n/languageKeys/keys/events/guilds/Members.ts b/projects/bot/src/lib/i18n/languageKeys/keys/events/guilds/Members.ts new file mode 100644 index 000000000..a487d89b0 --- /dev/null +++ b/projects/bot/src/lib/i18n/languageKeys/keys/events/guilds/Members.ts @@ -0,0 +1,23 @@ +import { FT, T } from '#lib/types'; + +export const GuildMemberAdd = T('events/guilds-members:guildMemberAdd'); +export const GuildMemberAddDescription = FT<{ mention: string; time: number }, string>('events/guilds-members:guildMemberAddDescription'); +export const GuildMemberAddedRoles = FT<{ addedRoles: string; count: number }, string>('events/guilds-members:guildMemberAddedRoles'); +export const GuildMemberAddMute = T('events/guilds-members:guildMemberAddMute'); +export const GuildMemberBanned = T('events/guilds-members:guildMemberBanned'); +export const GuildMemberKicked = T('events/guilds-members:guildMemberKicked'); +export const GuildMemberNoUpdate = T('events/guilds-members:guildMemberNoUpdate'); +export const GuildMemberRemove = T('events/guilds-members:guildMemberRemove'); +export const GuildMemberRemoveDescription = FT<{ mention: string; time: number }, string>('events/guilds-members:guildMemberRemoveDescription'); +export const GuildMemberRemoveDescriptionWithJoinedAt = FT<{ mention: string; time: number }, string>( + 'events/guilds-members:guildMemberRemoveDescriptionWithJoinedAt' +); +export const GuildMemberRemovedRoles = FT<{ removedRoles: string; count: number }, string>('events/guilds-members:guildMemberRemovedRoles'); +export const GuildMemberSoftBanned = T('events/guilds-members:guildMemberSoftBanned'); +export const NameUpdateNextWasNotSet = FT<{ nextName: string | null }, string>('events/guilds-members:nameUpdateNextWasNotSet'); +export const NameUpdateNextWasSet = FT<{ nextName: string | null }, string>('events/guilds-members:nameUpdateNextWasSet'); +export const NameUpdatePreviousWasNotSet = FT<{ previousName: string | null }, string>('events/guilds-members:nameUpdatePreviousWasNotSet'); +export const NameUpdatePreviousWasSet = FT<{ previousName: string | null }, string>('events/guilds-members:nameUpdatePreviousWasSet'); +export const NicknameUpdate = T('events/guilds-members:nicknameUpdate'); +export const RoleUpdate = T('events/guilds-members:roleUpdate'); +export const UsernameUpdate = T('events/guilds-members:usernameUpdate'); diff --git a/projects/bot/src/lib/i18n/languageKeys/keys/events/messages/All.ts b/projects/bot/src/lib/i18n/languageKeys/keys/events/messages/All.ts new file mode 100644 index 000000000..b9465381f --- /dev/null +++ b/projects/bot/src/lib/i18n/languageKeys/keys/events/messages/All.ts @@ -0,0 +1,4 @@ +import { FT } from '#lib/types'; + +export const MessageUpdate = FT<{ channel: `#${string}` }>('events/messages:messageUpdate'); +export const MessageDelete = FT<{ channel: `#${string}` }>('events/messages:messageDelete'); diff --git a/projects/bot/src/lib/i18n/languageKeys/keys/events/moderation/All.ts b/projects/bot/src/lib/i18n/languageKeys/keys/events/moderation/All.ts new file mode 100644 index 000000000..b5d4a161f --- /dev/null +++ b/projects/bot/src/lib/i18n/languageKeys/keys/events/moderation/All.ts @@ -0,0 +1 @@ +export * as Messages from './Messages'; diff --git a/src/lib/i18n/languageKeys/keys/events/moderation/Messages.ts b/projects/bot/src/lib/i18n/languageKeys/keys/events/moderation/Messages.ts similarity index 100% rename from src/lib/i18n/languageKeys/keys/events/moderation/Messages.ts rename to projects/bot/src/lib/i18n/languageKeys/keys/events/moderation/Messages.ts diff --git a/projects/bot/src/lib/i18n/languageKeys/keys/events/reactions/All.ts b/projects/bot/src/lib/i18n/languageKeys/keys/events/reactions/All.ts new file mode 100644 index 000000000..d934eb706 --- /dev/null +++ b/projects/bot/src/lib/i18n/languageKeys/keys/events/reactions/All.ts @@ -0,0 +1,6 @@ +import { FT, T } from '#lib/types'; + +export const Reaction = T('events/reactions:reaction'); +export const Filter = FT<{ user: string }, string>('events/reactions:filter'); +export const FilterFooter = T('events/reactions:filterFooter'); +export const SelfRoleHierarchy = T('events/reactions:selfRoleHierarchy'); diff --git a/projects/bot/src/lib/i18n/languageKeys/keys/settings/Channels.ts b/projects/bot/src/lib/i18n/languageKeys/keys/settings/Channels.ts new file mode 100644 index 000000000..fa8405ec4 --- /dev/null +++ b/projects/bot/src/lib/i18n/languageKeys/keys/settings/Channels.ts @@ -0,0 +1,6 @@ +import { T } from '#lib/types'; + +export * as Ignore from './channels/Ignore'; +export * as Logs from './channels/Logs'; + +export const MediaOnly = T('settings:channelsMediaOnly'); diff --git a/src/lib/i18n/languageKeys/keys/settings/Gateway.ts b/projects/bot/src/lib/i18n/languageKeys/keys/settings/Gateway.ts similarity index 100% rename from src/lib/i18n/languageKeys/keys/settings/Gateway.ts rename to projects/bot/src/lib/i18n/languageKeys/keys/settings/Gateway.ts diff --git a/src/lib/i18n/languageKeys/keys/settings/channels/Ignore.ts b/projects/bot/src/lib/i18n/languageKeys/keys/settings/channels/Ignore.ts similarity index 80% rename from src/lib/i18n/languageKeys/keys/settings/channels/Ignore.ts rename to projects/bot/src/lib/i18n/languageKeys/keys/settings/channels/Ignore.ts index e333d08f0..08da0266a 100644 --- a/src/lib/i18n/languageKeys/keys/settings/channels/Ignore.ts +++ b/projects/bot/src/lib/i18n/languageKeys/keys/settings/channels/Ignore.ts @@ -3,5 +3,4 @@ import { T } from '#lib/types'; export const MessageDelete = T('settings:channelsIgnoreMessageDelete'); export const MessageEdit = T('settings:channelsIgnoreMessageEdit'); export const ReactionAdd = T('settings:channelsIgnoreReactionAdd'); -export const VoiceActivity = T('settings:channelsIgnoreVoiceActivity'); export const All = T('settings:channelsIgnoreAll'); diff --git a/src/lib/i18n/languageKeys/keys/settings/channels/Logs.ts b/projects/bot/src/lib/i18n/languageKeys/keys/settings/channels/Logs.ts similarity index 89% rename from src/lib/i18n/languageKeys/keys/settings/channels/Logs.ts rename to projects/bot/src/lib/i18n/languageKeys/keys/settings/channels/Logs.ts index 00dd531b3..8d62a70e3 100644 --- a/src/lib/i18n/languageKeys/keys/settings/channels/Logs.ts +++ b/projects/bot/src/lib/i18n/languageKeys/keys/settings/channels/Logs.ts @@ -23,6 +23,3 @@ export const RoleCreate = T('settings:channelsLogsRoleCreate'); export const RoleDelete = T('settings:channelsLogsRoleDelete'); export const RoleUpdate = T('settings:channelsLogsRoleUpdate'); export const ServerUpdate = T('settings:channelsLogsServerUpdate'); -export const VoiceActivity = T('settings:channelsLogsVoiceChannel'); -export const Command = T('settings:channelsLogsCommand'); -export const Settings = T('settings:channelsLogsSettings'); diff --git a/projects/bot/src/lib/moderation/index.ts b/projects/bot/src/lib/moderation/index.ts new file mode 100644 index 000000000..c1a879f15 --- /dev/null +++ b/projects/bot/src/lib/moderation/index.ts @@ -0,0 +1,2 @@ +export * from './managers'; +export * from './structures'; diff --git a/projects/bot/src/lib/moderation/managers/ModerationManager.ts b/projects/bot/src/lib/moderation/managers/ModerationManager.ts new file mode 100644 index 000000000..7b327ed08 --- /dev/null +++ b/projects/bot/src/lib/moderation/managers/ModerationManager.ts @@ -0,0 +1,208 @@ +import { ModerationEntity } from '#lib/database/entities'; +import { GuildSettings } from '#lib/database/keys'; +import { readSettings } from '#lib/database/settings'; +import { createReferPromise, floatPromise, ReferredPromise, seconds } from '#utils/common'; +import { cast } from '#utils/util'; +import { Collection, type CollectionConstructor } from '@discordjs/collection'; +import type { GuildTextBasedChannelTypes } from '@sapphire/discord.js-utilities'; +import { container } from '@sapphire/framework'; +import { isNullish, StrictRequired } from '@sapphire/utilities'; +import { DiscordAPIError, Guild } from 'discord.js'; +import { In } from 'typeorm'; + +enum CacheActions { + None, + Fetch, + Insert +} + +export class ModerationManager extends Collection { + /** + * The Guild instance that manages this manager + */ + public guild: Guild; + + /** + * The current case count + */ + private _count: number | null = null; + + /** + * The timer that sweeps this manager's entries + */ + private _timer: NodeJS.Timeout | null = null; + + /** + * The promise to wait for tasks to complete + */ + private readonly _locks: ReferredPromise[] = []; + + private get db() { + return container.db; + } + + public constructor(guild: Guild) { + super(); + this.guild = guild; + } + + /** + * The channel where messages have to be sent. + */ + public async fetchChannel() { + const channelId = await readSettings(this.guild, GuildSettings.Channels.Logs.Moderation); + if (isNullish(channelId)) return null; + return (this.guild.channels.cache.get(channelId) ?? null) as GuildTextBasedChannelTypes | null; + } + + /** + * Fetch 100 messages from the modlogs channel + */ + public async fetchChannelMessages(remainingRetries = 5): Promise { + const channel = await this.fetchChannel(); + if (channel === null) return; + try { + await channel.messages.fetch({ limit: 100 }); + } catch (error) { + if (error instanceof DiscordAPIError) throw error; + return this.fetchChannelMessages(--remainingRetries); + } + } + + public getLatestLogForUser(userId: string) { + if (this.size === 0) return null; + + const minimumTime = Date.now() - seconds(15); + return this.reduce( + (prev, curr) => + curr.userId === userId + ? prev === null + ? curr.createdTimestamp >= minimumTime + ? curr + : prev + : curr.createdTimestamp > prev.createdTimestamp + ? curr + : prev + : prev, + null + ); + } + + public create(data: ModerationManagerCreateData) { + return new ModerationEntity(data).setup(this); + } + + public async fetch(id: number): Promise; + public async fetch(id: string | number[]): Promise>; + public async fetch(id?: null): Promise; + public async fetch(id?: string | number | number[] | null): Promise | this | null> { + // Case number + if (typeof id === 'number') { + return ( + super.get(id) || this._cache(await this.db.fetchModerationEntry({ where: { guildId: this.guild.id, caseId: id } }), CacheActions.None) + ); + } + + // User id + if (typeof id === 'string') { + return this._count === super.size + ? super.filter((entry) => entry.userId === id) + : this._cache(await this.db.fetchModerationEntries({ where: { guildId: this.guild.id, userId: id } }), CacheActions.None); + } + + if (Array.isArray(id) && id.length) { + return this._cache(await this.db.fetchModerationEntries({ where: { guildId: this.guild.id, caseId: In(id) } }), CacheActions.None); + } + + if (super.size !== this._count) { + this._cache(await this.db.fetchModerationEntries({ where: { guildId: this.guild.id } }), CacheActions.Fetch); + } + return this; + } + + public async getCurrentId() { + if (this._count === null) { + const { moderations } = this.db; + + const [{ max }] = (await moderations.query( + /* sql */ ` + SELECT max(case_id) + FROM "${moderations.metadata.tableName}" + WHERE guild_id = $1; + `, + [this.guild.id] + )) as [MaxQuery]; + + this._count = max ?? 0; + } + + return this._count; + } + + public insert(data: ModerationEntity): ModerationEntity; + public insert(data: ModerationEntity[]): Collection; + public insert(data: ModerationEntity | ModerationEntity[]) { + // @ts-expect-error TypeScript does not read the overloaded `data` parameter correctly + return this._cache(data, CacheActions.Insert); + } + + public createLock() { + // eslint-disable-next-line @typescript-eslint/no-invalid-void-type + const lock = createReferPromise(); + this._locks.push(lock); + floatPromise( + lock.promise.finally(() => { + this._locks.splice(this._locks.indexOf(lock), 1); + }) + ); + + return lock.resolve; + } + + public releaseLock() { + for (const lock of this._locks) lock.resolve(); + } + + public waitLock() { + return Promise.all(this._locks.map((lock) => lock.promise)); + } + + private _cache(entry: ModerationEntity | null, type: CacheActions): ModerationEntity; + private _cache(entries: ModerationEntity[], type: CacheActions): Collection; + private _cache( + entries: ModerationEntity | ModerationEntity[] | null, + type: CacheActions + ): Collection | ModerationEntity | null { + if (!entries) return null; + + const parsedEntries = Array.isArray(entries) ? entries : [entries]; + + for (const entry of parsedEntries) { + super.set(entry.caseId, entry.setup(this)); + } + + if (type === CacheActions.Insert) this._count! += parsedEntries.length; + + if (!this._timer) { + this._timer = setInterval(() => { + super.sweep((value) => value.cacheExpired); + if (!super.size) this._timer = null; + }, 1000); + } + + return Array.isArray(entries) ? new Collection(entries.map((entry) => [entry.caseId, entry])) : entries; + } + + public static get [Symbol.species]() { + return cast(Collection); + } +} + +interface MaxQuery { + max: number | null; +} + +export type ModerationManagerUpdateData = Partial>; +export type ModerationManagerCreateData = Omit; +export type ModerationManagerInsertData = StrictRequired> & + Partial>; diff --git a/projects/bot/src/lib/moderation/managers/StickyRoleManager.ts b/projects/bot/src/lib/moderation/managers/StickyRoleManager.ts new file mode 100644 index 000000000..29a162e85 --- /dev/null +++ b/projects/bot/src/lib/moderation/managers/StickyRoleManager.ts @@ -0,0 +1,167 @@ +import type { StickyRole } from '#lib/database/entities'; +import { GuildSettings } from '#lib/database/keys'; +import { readSettings, writeSettings } from '#lib/database/settings'; +import { isNullish } from '@sapphire/utilities'; +import type { Guild } from 'discord.js'; + +export interface StickyRoleManagerExtraContext { + author: string; +} + +export class StickyRoleManager { + #guild: Guild; + + public constructor(guild: Guild) { + this.#guild = guild; + } + + public async get(userId: string): Promise { + const entries = await readSettings(this.#guild, GuildSettings.StickyRoles); + return entries.find((entry) => entry.user === userId)?.roles ?? []; + } + + public async has(userId: string, roleId: string): Promise { + const roles = await this.get(userId); + return roles.includes(roleId); + } + + public async fetch(userId: string): Promise { + // 1.0. If the entry does not exist, return empty array + const entries = await readSettings(this.#guild, GuildSettings.StickyRoles); + const entry = entries.find((entry) => entry.user === userId); + if (isNullish(entry)) return []; + + // 2.0. Read the entry and clean the roles: + const roles = [...this.cleanRoles(entry.roles)]; + + // 2.1. If the roles are unchanged (have the same size), return them: + if (entry.roles.length === roles.length) return entry.roles; + + // 2.2. If the roles are changed and leds to an empty array: + if (roles.length === 0) { + // 3.0.a. Then delete the entry from the settings: + await this.clear(userId); + return roles; + } + + // 3.0.b. Make a clone with the userId and the fixed roles array: + return writeSettings(this.#guild, (settings) => { + const index = settings[GuildSettings.StickyRoles].findIndex((entry) => entry.user === userId); + if (index === -1) return []; + + const clone: StickyRole = { user: userId, roles }; + settings[GuildSettings.StickyRoles][index] = clone; + + // 4.0. Return the updated roles: + return clone.roles; + }); + } + + public add(userId: string, roleId: string): Promise { + return writeSettings(this.#guild, (settings) => { + // 0.0 Get all the entries + const entries = settings[GuildSettings.StickyRoles]; + + // 1.0. Get the index for the entry: + const index = entries.findIndex((entry) => entry.user === userId); + + // 2.0. If the entry does not exist: + if (index === -1) { + // 3.0.a. Proceed to create a new sticky roles entry: + const entry: StickyRole = { user: userId, roles: [roleId] }; + entries.push(entry); + return entry.roles; + } + + // 3.0.b. Otherwise read the previous entry and patch it by adding the role: + const entry = entries[index]; + const roles = [...this.addRole(roleId, entry.roles)]; + + // 3.1.b. Otherwise patch it: + entries[index] = { user: entry.user, roles }; + + // 4.0. Return the updated roles: + return entry.roles; + }); + } + + public remove(userId: string, roleId: string): Promise { + return writeSettings(this.#guild, (settings) => { + // 0.0 Get all the entries + const entries = settings[GuildSettings.StickyRoles]; + + // 1.0. Get the index for the entry: + const index = entries.findIndex((entry) => entry.user === userId); + + // 1.1. If the index is negative, return empty array, as the entry does not exist: + if (index === -1) return []; + + // 2.0. Read the previous entry and patch it by removing the role: + const entry = entries[index]; + const roles = [...this.removeRole(roleId, entry.roles)]; + + if (roles.length === 0) { + // 3.1.a. Then delete the entry from the settings: + entries.splice(index, 1); + } else { + // 3.1.b. Otherwise patch it: + entries[index] = { user: entry.user, roles }; + } + + // 4.0. Return the updated roles: + return entry.roles; + }); + } + + public clear(userId: string): Promise { + return writeSettings(this.#guild, (settings) => { + // 0.0 Get all the entries + const entries = settings[GuildSettings.StickyRoles]; + + // 1.0. Get the index for the entry: + const index = entries.findIndex((entry) => entry.user === userId); + + // 1.1. If the index is negative, return empty array, as the entry does not exist: + if (index === -1) return []; + + // 2.0. Read the previous entry: + const entry = entries[index]; + + // 3.0. Remove the entry from the settings: + entries.splice(index, 1); + + // 4.0. Return the previous roles: + return entry.roles; + }); + } + + private *addRole(roleId: string, roleIds: readonly string[]) { + const emitted = new Set(); + for (const role of this.cleanRoles(roleIds)) { + if (emitted.has(role)) continue; + + emitted.add(role); + yield role; + } + + if (!emitted.has(roleId)) yield roleId; + } + + private *removeRole(roleId: string, roleIds: readonly string[]) { + const emitted = new Set(); + for (const role of this.cleanRoles(roleIds)) { + if (role === roleId) continue; + if (emitted.has(role)) continue; + + emitted.add(role); + yield role; + } + } + + private *cleanRoles(roleIds: readonly string[]) { + const { roles } = this.#guild; + for (const roleId of roleIds) { + if (roles.cache.has(roleId)) yield roleId; + } + } +} diff --git a/projects/bot/src/lib/moderation/managers/index.ts b/projects/bot/src/lib/moderation/managers/index.ts new file mode 100644 index 000000000..b34ba2451 --- /dev/null +++ b/projects/bot/src/lib/moderation/managers/index.ts @@ -0,0 +1,2 @@ +export * from './ModerationManager'; +export * from './StickyRoleManager'; diff --git a/projects/bot/src/lib/moderation/structures/ModerationCommand.ts b/projects/bot/src/lib/moderation/structures/ModerationCommand.ts new file mode 100644 index 000000000..40deac78e --- /dev/null +++ b/projects/bot/src/lib/moderation/structures/ModerationCommand.ts @@ -0,0 +1,204 @@ +import { GuildSettings, ModerationEntity, readSettings } from '#lib/database'; +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { WolfCommand } from '#lib/structures/commands/WolfCommand'; +import type { GuildMessage } from '#lib/types'; +import { PermissionLevels } from '#lib/types/Enums'; +import { floatPromise, seconds, years } from '#utils/common'; +import { deleteMessage, isGuildOwner } from '#utils/functions'; +import type { ModerationActionsSendOptions } from '#utils/Security/ModerationActions'; +import { cast } from '#utils/util'; +import { Args, CommandOptionsRunTypeEnum, PieceContext } from '@sapphire/framework'; +import { send } from '@sapphire/plugin-editable-commands'; +import type { User } from 'discord.js'; + +export abstract class ModerationCommand extends WolfCommand { + /** + * Whether a member is required or not. + */ + public requiredMember: boolean; + + /** + * Whether or not this moderation command can create temporary actions. + */ + public optionalDuration: boolean; + + protected constructor(context: PieceContext, options: ModerationCommand.Options) { + super(context, { + cooldownDelay: seconds(5), + flags: ['no-author', 'authored'], + optionalDuration: false, + permissionLevel: PermissionLevels.Moderator, + requiredMember: false, + runIn: [CommandOptionsRunTypeEnum.GuildAny], + ...options + }); + + this.requiredMember = options.requiredMember!; + this.optionalDuration = options.optionalDuration!; + } + + public messageRun(message: GuildMessage, args: ModerationCommand.Args, context: ModerationCommand.Context): Promise; + public async messageRun(message: GuildMessage, args: ModerationCommand.Args) { + const resolved = await this.resolveOverloads(args); + const preHandled = await this.prehandle(message, resolved); + const processed = [] as Array<{ log: ModerationEntity; target: User }>; + const errored = [] as Array<{ error: Error | string; target: User }>; + + const [shouldAutoDelete, shouldDisplayMessage, shouldDisplayReason] = await readSettings(message.guild, [ + GuildSettings.Messages.ModerationAutoDelete, + GuildSettings.Messages.ModerationMessageDisplay, + GuildSettings.Messages.ModerationReasonDisplay + ]); + + const { targets, ...handledRaw } = resolved; + for (const target of new Set(targets)) { + try { + const handled = { ...handledRaw, args, target, preHandled }; + await this.checkModeratable(message, handled); + const log = await this.handle(message, handled); + processed.push({ log, target }); + } catch (error) { + errored.push({ error: error as Error | string, target }); + } + } + + try { + await this.posthandle(message, { ...resolved, preHandled }); + } catch { + // noop + } + + // If the server was configured to automatically delete messages, delete the command and return null. + if (shouldAutoDelete) { + if (message.deletable) floatPromise(deleteMessage(message)); + } + + if (shouldDisplayMessage) { + const output: string[] = []; + if (processed.length) { + const logReason = shouldDisplayReason ? processed[0].log.reason! : null; + const sorted = processed.sort((a, b) => a.log.caseId - b.log.caseId); + const cases = sorted.map(({ log }) => log.caseId); + const users = sorted.map(({ target }) => `\`${target.tag}\``); + const range = cases.length === 1 ? cases[0] : `${cases[0]}..${cases[cases.length - 1]}`; + const langKey = logReason + ? LanguageKeys.Commands.Moderation.ModerationOutputWithReason + : LanguageKeys.Commands.Moderation.ModerationOutput; + output.push(args.t(langKey, { count: cases.length, range, users, reason: logReason })); + } + + if (errored.length) { + const users = errored.map(({ error, target }) => `- ${target.tag} → ${typeof error === 'string' ? error : error.message}`); + output.push(args.t(LanguageKeys.Commands.Moderation.ModerationFailed, { users, count: users.length })); + } + + // Else send the message as usual. + const content = output.join('\n'); + return send(message, content); + } + + return null; + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + protected prehandle(_message: GuildMessage, _context: CommandContext): Promise | T { + return cast(null); + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + protected posthandle(_message: GuildMessage, _context: PostHandledCommandContext): unknown { + return null; + } + + protected async checkModeratable(message: GuildMessage, context: HandledCommandContext) { + if (context.target.id === message.author.id) { + throw context.args.t(LanguageKeys.Commands.Moderation.UserSelf); + } + + if (context.target.id === process.env.CLIENT_ID) { + throw context.args.t(LanguageKeys.Commands.Moderation.ToSkyra); + } + + const member = await message.guild.members.fetch(context.target.id).catch(() => { + if (this.requiredMember) throw context.args.t(LanguageKeys.Misc.UserNotInGuild); + return null; + }); + + if (member) { + const targetHighestRolePosition = member.roles.highest.position; + + // Skyra cannot moderate members with higher role position than her: + if (targetHighestRolePosition >= message.guild.me!.roles.highest.position) { + throw context.args.t(LanguageKeys.Commands.Moderation.RoleHigherSkyra); + } + + // A member who isn't a server owner is not allowed to moderate somebody with higher role than them: + if (!isGuildOwner(message.member) && targetHighestRolePosition >= message.member.roles.highest.position) { + throw context.args.t(LanguageKeys.Commands.Moderation.RoleHigher); + } + } + + return member; + } + + protected async getTargetDM(message: GuildMessage, args: Args, target: User): Promise { + const [nameDisplay, enabledDM] = await readSettings(message.guild, [ + GuildSettings.Messages.ModeratorNameDisplay, + GuildSettings.Messages.ModerationDM + ]); + + return { + moderator: args.getFlags('no-author') ? null : args.getFlags('no-authored') || nameDisplay ? message.author : null, + send: enabledDM && (await this.container.db.fetchModerationDirectMessageEnabled(target.id)) + }; + } + + protected async resolveOverloads(args: ModerationCommand.Args): Promise { + return { + targets: await args.repeat('user', { times: 10 }), + duration: await this.resolveDurationArgument(args), + reason: args.finished ? null : await args.rest('string') + }; + } + + protected abstract handle(message: GuildMessage, context: HandledCommandContext): Promise | ModerationEntity; + + private async resolveDurationArgument(args: ModerationCommand.Args) { + if (args.finished) return null; + if (!this.optionalDuration) return null; + + const result = await args.pickResult('timespan', { minimum: 0, maximum: years(5) }); + if (result.success) return result.value; + if (result.error.identifier === LanguageKeys.Arguments.TimeSpan) return null; + throw result.error; + } +} + +export namespace ModerationCommand { + /** + * The ModerationCommand Options + */ + export interface Options extends WolfCommand.Options { + requiredMember?: boolean; + optionalDuration?: boolean; + } + + export type Args = WolfCommand.Args; + export type Context = WolfCommand.Context; +} + +export interface CommandContext { + targets: User[]; + duration: number | null; + reason: string | null; +} + +export interface HandledCommandContext extends Pick { + args: ModerationCommand.Args; + target: User; + preHandled: T; +} + +export interface PostHandledCommandContext extends CommandContext { + preHandled: T; +} diff --git a/projects/bot/src/lib/moderation/structures/ModerationListener.ts b/projects/bot/src/lib/moderation/structures/ModerationListener.ts new file mode 100644 index 000000000..73e16c9f8 --- /dev/null +++ b/projects/bot/src/lib/moderation/structures/ModerationListener.ts @@ -0,0 +1,117 @@ +import { GuildEntity, readSettings } from '#lib/database'; +import { getModeration, getSecurity } from '#utils/functions'; +import { Listener } from '@sapphire/framework'; +import type { PickByValue } from '@sapphire/utilities'; +import type { Guild, MessageEmbed } from 'discord.js'; +import type { HardPunishment } from './ModerationMessageListener'; +import { SelfModeratorBitField, SelfModeratorHardActionFlags } from './SelfModeratorBitField'; + +export abstract class ModerationListener extends Listener { + public abstract run(...params: V): unknown; + + protected processSoftPunishment(args: Readonly, preProcessed: T, bitField: SelfModeratorBitField) { + if (bitField.has(SelfModeratorBitField.FLAGS.DELETE)) this.onDelete(args, preProcessed); + if (bitField.has(SelfModeratorBitField.FLAGS.ALERT)) this.onAlert(args, preProcessed); + if (bitField.has(SelfModeratorBitField.FLAGS.LOG)) this.onLog(args, preProcessed); + } + + protected async processHardPunishment(guild: Guild, userId: string, action: SelfModeratorHardActionFlags) { + switch (action) { + case SelfModeratorHardActionFlags.Warning: + await this.onWarning(guild, userId); + break; + case SelfModeratorHardActionFlags.Kick: + await this.onKick(guild, userId); + break; + case SelfModeratorHardActionFlags.Mute: + await this.onMute(guild, userId); + break; + case SelfModeratorHardActionFlags.SoftBan: + await this.onSoftBan(guild, userId); + break; + case SelfModeratorHardActionFlags.Ban: + await this.onBan(guild, userId); + break; + case SelfModeratorHardActionFlags.None: + break; + } + } + + protected async onWarning(guild: Guild, userId: string) { + const duration = await readSettings(guild, this.hardPunishmentPath.actionDuration); + await this.createActionAndSend(guild, () => + getSecurity(guild).actions.warning({ + userId, + moderatorId: process.env.CLIENT_ID, + reason: '[Auto-Moderation] Threshold Reached.', + duration + }) + ); + } + + protected async onKick(guild: Guild, userId: string) { + await this.createActionAndSend(guild, () => + getSecurity(guild).actions.kick({ + userId, + moderatorId: process.env.CLIENT_ID, + reason: '[Auto-Moderation] Threshold Reached.' + }) + ); + } + + protected async onMute(guild: Guild, userId: string) { + const duration = await readSettings(guild, this.hardPunishmentPath.actionDuration); + await this.createActionAndSend(guild, () => + getSecurity(guild).actions.mute({ + userId, + moderatorId: process.env.CLIENT_ID, + reason: '[Auto-Moderation] Threshold Reached.', + duration + }) + ); + } + + protected async onSoftBan(guild: Guild, userId: string) { + await this.createActionAndSend(guild, () => + getSecurity(guild).actions.softBan( + { + userId, + moderatorId: process.env.CLIENT_ID, + reason: '[Auto-Moderation] Threshold Reached.' + }, + 1 + ) + ); + } + + protected async onBan(guild: Guild, userId: string) { + const duration = await readSettings(guild, this.hardPunishmentPath.actionDuration); + + await this.createActionAndSend(guild, () => + getSecurity(guild).actions.ban( + { + userId, + moderatorId: process.env.CLIENT_ID, + reason: '[Auto-Moderation] Threshold Reached.', + duration + }, + 0 + ) + ); + } + + protected async createActionAndSend(guild: Guild, performAction: () => unknown): Promise { + const unlock = getModeration(guild).createLock(); + await performAction(); + unlock(); + } + + protected abstract keyEnabled: PickByValue; + protected abstract softPunishmentPath: PickByValue; + protected abstract hardPunishmentPath: HardPunishment; + protected abstract preProcess(args: Readonly): Promise | T | null; + protected abstract onLog(args: Readonly, value: T): unknown; + protected abstract onDelete(args: Readonly, value: T): unknown; + protected abstract onAlert(args: Readonly, value: T): unknown; + protected abstract onLogMessage(args: Readonly, value: T): Promise | MessageEmbed; +} diff --git a/projects/bot/src/lib/moderation/structures/ModerationMessageListener.ts b/projects/bot/src/lib/moderation/structures/ModerationMessageListener.ts new file mode 100644 index 000000000..e7bc53b24 --- /dev/null +++ b/projects/bot/src/lib/moderation/structures/ModerationMessageListener.ts @@ -0,0 +1,231 @@ +import { AdderKey, GuildEntity, GuildSettings, readSettings } from '#lib/database'; +import type { AdderError } from '#lib/database/utils/Adder'; +import type { CustomFunctionGet, CustomGet, GuildMessage } from '#lib/types'; +import { Events } from '#lib/types/Enums'; +import { floatPromise } from '#utils/common'; +import { getModeration, getSecurity, isModerator } from '#utils/functions'; +import { canSendMessages, GuildTextBasedChannelTypes } from '@sapphire/discord.js-utilities'; +import { Listener, ListenerOptions, PieceContext } from '@sapphire/framework'; +import type { Awaitable, Nullish, PickByValue } from '@sapphire/utilities'; +import type { GuildMember, MessageEmbed } from 'discord.js'; +import type { TFunction } from 'i18next'; +import { SelfModeratorBitField, SelfModeratorHardActionFlags } from './SelfModeratorBitField'; + +export abstract class ModerationMessageListener extends Listener { + private readonly keyEnabled: PickByValue; + private readonly ignoredRolesPath: PickByValue; + private readonly ignoredChannelsPath: PickByValue; + private readonly softPunishmentPath: PickByValue; + private readonly hardPunishmentPath: HardPunishment; + private readonly reasonLanguageKey: CustomGet; + private readonly reasonLanguageKeyWithMaximum: CustomFunctionGet; + + public constructor(context: PieceContext, options: ModerationMessageListener.Options) { + super(context, { ...options, event: Events.GuildUserMessage }); + + this.keyEnabled = options.keyEnabled; + this.ignoredRolesPath = options.ignoredRolesPath; + this.ignoredChannelsPath = options.ignoredChannelsPath; + this.softPunishmentPath = options.softPunishmentPath; + this.hardPunishmentPath = options.hardPunishmentPath; + this.reasonLanguageKey = options.reasonLanguageKey; + this.reasonLanguageKeyWithMaximum = options.reasonLanguageKeyWithMaximum; + } + + public async run(message: GuildMessage) { + const shouldRun = await this.checkPreRun(message); + if (!shouldRun) return; + + if (await isModerator(message.member)) return; + + const preProcessed = await this.preProcess(message); + if (preProcessed === null) return; + + const [logChannelId, filter, adder, language] = await readSettings(message.guild, (settings) => [ + settings[GuildSettings.Channels.Logs.Moderation], + settings[this.softPunishmentPath], + settings.adders[this.hardPunishmentPath.adder], + settings.getLanguage() + ]); + const bitField = new SelfModeratorBitField(filter); + this.processSoftPunishment(message, logChannelId, language, bitField, preProcessed); + + if (this.hardPunishmentPath === null) return; + + if (!adder) return this.processHardPunishment(message, language, 0, 0); + + const points = typeof preProcessed === 'number' ? preProcessed : 1; + try { + adder.add(message.author.id, points); + } catch (error) { + await this.processHardPunishment(message, language, (error as AdderError).amount, adder.maximum); + } + } + + protected processSoftPunishment( + message: GuildMessage, + logChannelId: string | Nullish, + language: TFunction, + bitField: SelfModeratorBitField, + preProcessed: T + ) { + if (bitField.has(SelfModeratorBitField.FLAGS.DELETE) && message.deletable) { + floatPromise(this.onDelete(message, language, preProcessed) as any); + } + + if (bitField.has(SelfModeratorBitField.FLAGS.ALERT) && canSendMessages(message.channel)) { + floatPromise(this.onAlert(message, language, preProcessed) as any); + } + + if (bitField.has(SelfModeratorBitField.FLAGS.LOG)) { + floatPromise(this.onLog(message, logChannelId, language, preProcessed) as any); + } + } + + protected async processHardPunishment(message: GuildMessage, language: TFunction, points: number, maximum: number) { + const [action, duration] = await readSettings(message.guild, [this.hardPunishmentPath.action, this.hardPunishmentPath.actionDuration]); + switch (action) { + case SelfModeratorHardActionFlags.Warning: + await this.onWarning(message, language, points, maximum, duration); + break; + case SelfModeratorHardActionFlags.Kick: + await this.onKick(message, language, points, maximum); + break; + case SelfModeratorHardActionFlags.Mute: + await this.onMute(message, language, points, maximum, duration); + break; + case SelfModeratorHardActionFlags.SoftBan: + await this.onSoftBan(message, language, points, maximum); + break; + case SelfModeratorHardActionFlags.Ban: + await this.onBan(message, language, points, maximum, duration); + break; + } + } + + protected async onWarning(message: GuildMessage, t: TFunction, points: number, maximum: number, duration: number | null) { + await this.createActionAndSend(message, () => + getSecurity(message.guild).actions.warning({ + userId: message.author.id, + moderatorId: process.env.CLIENT_ID, + reason: maximum === 0 ? t(this.reasonLanguageKey) : t(this.reasonLanguageKeyWithMaximum, { amount: points, maximum }), + duration + }) + ); + } + + protected async onKick(message: GuildMessage, t: TFunction, points: number, maximum: number) { + await this.createActionAndSend(message, () => + getSecurity(message.guild).actions.kick({ + userId: message.author.id, + moderatorId: process.env.CLIENT_ID, + reason: maximum === 0 ? t(this.reasonLanguageKey) : t(this.reasonLanguageKeyWithMaximum, { amount: points, maximum }) + }) + ); + } + + protected async onMute(message: GuildMessage, t: TFunction, points: number, maximum: number, duration: number | null) { + await this.createActionAndSend(message, () => + getSecurity(message.guild).actions.mute({ + userId: message.author.id, + moderatorId: process.env.CLIENT_ID, + reason: maximum === 0 ? t(this.reasonLanguageKey) : t(this.reasonLanguageKeyWithMaximum, { amount: points, maximum }), + duration + }) + ); + } + + protected async onSoftBan(message: GuildMessage, t: TFunction, points: number, maximum: number) { + await this.createActionAndSend(message, () => + getSecurity(message.guild).actions.softBan( + { + userId: message.author.id, + moderatorId: process.env.CLIENT_ID, + reason: maximum === 0 ? t(this.reasonLanguageKey) : t(this.reasonLanguageKeyWithMaximum, { amount: points, maximum }) + }, + 1 + ) + ); + } + + protected async onBan(message: GuildMessage, t: TFunction, points: number, maximum: number, duration: number | null) { + await this.createActionAndSend(message, () => + getSecurity(message.guild).actions.ban( + { + userId: message.author.id, + moderatorId: process.env.CLIENT_ID, + reason: maximum === 0 ? t(this.reasonLanguageKey) : t(this.reasonLanguageKeyWithMaximum, { amount: points, maximum }), + duration + }, + 0 + ) + ); + } + + protected async createActionAndSend(message: GuildMessage, performAction: () => unknown): Promise { + const unlock = getModeration(message.guild).createLock(); + await performAction(); + unlock(); + } + + protected onLog(message: GuildMessage, logChannelId: string | Nullish, language: TFunction, value: T): Awaitable { + this.container.client.emit( + Events.GuildMessageLog, + message.guild, + logChannelId, + GuildSettings.Channels.Logs.Moderation, + this.onLogMessage.bind(this, message, language, value) + ); + } + + protected abstract preProcess(message: GuildMessage): Promise | T | null; + protected abstract onDelete(message: GuildMessage, language: TFunction, value: T): Awaitable; + protected abstract onAlert(message: GuildMessage, language: TFunction, value: T): Awaitable; + protected abstract onLogMessage(message: GuildMessage, language: TFunction, value: T): Awaitable; + + private checkPreRun(message: GuildMessage) { + return readSettings( + message.guild, + (settings) => + settings[this.keyEnabled] && this.checkMessageChannel(settings, message.channel) && this.checkMemberRoles(settings, message.member) + ); + } + + private checkMessageChannel(settings: GuildEntity, channel: GuildTextBasedChannelTypes) { + const globalIgnore = settings[GuildSettings.Selfmod.IgnoreChannels]; + if (globalIgnore.includes(channel.id)) return false; + + const localIgnore = settings[this.ignoredChannelsPath] as readonly string[]; + if (localIgnore.includes(channel.id)) return false; + + return true; + } + + private checkMemberRoles(settings: GuildEntity, member: GuildMember | null) { + if (member === null) return false; + + const ignoredRoles = settings[this.ignoredRolesPath]; + if (ignoredRoles.length === 0) return true; + + const { roles } = member; + return !ignoredRoles.some((id) => roles.cache.has(id)); + } +} + +export interface HardPunishment { + action: PickByValue; + actionDuration: PickByValue; + adder: AdderKey; +} + +export namespace ModerationMessageListener { + export interface Options extends ListenerOptions { + keyEnabled: PickByValue; + ignoredRolesPath: PickByValue; + ignoredChannelsPath: PickByValue; + softPunishmentPath: PickByValue; + hardPunishmentPath: HardPunishment; + reasonLanguageKey: CustomGet; + reasonLanguageKeyWithMaximum: CustomFunctionGet; + } +} diff --git a/src/lib/moderation/structures/ModerationTask.ts b/projects/bot/src/lib/moderation/structures/ModerationTask.ts similarity index 54% rename from src/lib/moderation/structures/ModerationTask.ts rename to projects/bot/src/lib/moderation/structures/ModerationTask.ts index 722726d61..5978b070a 100644 --- a/src/lib/moderation/structures/ModerationTask.ts +++ b/projects/bot/src/lib/moderation/structures/ModerationTask.ts @@ -1,16 +1,13 @@ -import { readSettings } from '#lib/database'; -import type { ModerationAction } from '#lib/moderation/actions/base/ModerationAction'; -import { ResponseType, Task, type PartialResponseValue } from '#lib/schedule'; -import { getModeration } from '#utils/functions'; +import { GuildSettings, PartialResponseValue, readSettings, ResponseType, Task } from '#lib/database'; import type { SchemaKeys } from '#utils/moderationConstants'; -import { isNullish } from '@sapphire/utilities'; -import type { Guild, Snowflake } from 'discord.js'; +import type { ModerationActionsSendOptions } from '#utils/Security/ModerationActions'; +import type { Guild, User } from 'discord.js'; export abstract class ModerationTask extends Task { public async run(data: ModerationData): Promise { const guild = this.container.client.guilds.cache.get(data.guildID); // If the guild is not available, cancel the task. - if (isNullish(guild)) return { type: ResponseType.Ignore }; + if (typeof guild === 'undefined') return { type: ResponseType.Ignore }; // If the guild is not available, re-schedule the task by creating // another with the same data but happening 20 seconds later. @@ -23,22 +20,15 @@ export abstract class ModerationTask extends Task { /* noop */ } - // Mark the moderation entry as complete. - await getModeration(guild).complete(data.caseID); - return { type: ResponseType.Finished }; } - protected async getActionData( - guild: Guild, - targetId: Snowflake, - context?: ContextType - ): Promise> { - const settings = await readSettings(guild); + protected async getTargetDM(guild: Guild, target: User): Promise { return { moderator: null, - sendDirectMessage: settings.messagesModerationDm && (await this.container.prisma.user.fetchModerationDirectMessageEnabled(targetId)), - context + send: + (await readSettings(guild, GuildSettings.Messages.ModerationDM)) && + (await this.container.db.fetchModerationDirectMessageEnabled(target.id)) }; } diff --git a/projects/bot/src/lib/moderation/structures/SelfModerationCommand.ts b/projects/bot/src/lib/moderation/structures/SelfModerationCommand.ts new file mode 100644 index 000000000..c79025cc2 --- /dev/null +++ b/projects/bot/src/lib/moderation/structures/SelfModerationCommand.ts @@ -0,0 +1,315 @@ +import { AdderKey, configurableKeys, GuildEntity, readSettings, writeSettings } from '#lib/database'; +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { WolfCommand } from '#lib/structures'; +import type { GuildMessage } from '#lib/types'; +import { PermissionLevels } from '#lib/types/Enums'; +import { CommandOptionsRunTypeEnum, PieceContext } from '@sapphire/framework'; +import { send } from '@sapphire/plugin-editable-commands'; +import { codeBlock, PickByValue } from '@sapphire/utilities'; +import type { TFunction } from 'i18next'; +import { SelfModeratorBitField, SelfModeratorHardActionFlags } from './SelfModeratorBitField'; + +export enum AKeys { + Enable, + Disable, + SoftAction, + HardAction, + HardActionDuration, + ThresholdMaximum, + ThresholdDuration, + Show +} + +export const kActions = new Map([ + ['e', AKeys.Enable], + ['enable', AKeys.Enable], + ['on', AKeys.Enable], + ['d', AKeys.Disable], + ['disable', AKeys.Disable], + ['off', AKeys.Disable], + ['a', AKeys.SoftAction], + ['action', AKeys.SoftAction], + ['soft-action', AKeys.SoftAction], + ['p', AKeys.HardAction], + ['punish', AKeys.HardAction], + ['punishment', AKeys.HardAction], + ['pd', AKeys.HardActionDuration], + ['punish-duration', AKeys.HardActionDuration], + ['punishment-duration', AKeys.HardActionDuration], + ['t', AKeys.ThresholdMaximum], + ['tm', AKeys.ThresholdMaximum], + ['threshold', AKeys.ThresholdMaximum], + ['threshold-maximum', AKeys.ThresholdMaximum], + ['td', AKeys.ThresholdDuration], + ['threshold-duration', AKeys.ThresholdDuration], + ['s', AKeys.Show], + ['sh', AKeys.Show], + ['show', AKeys.Show], + ['display', AKeys.Show] +]); + +export enum ASKeys { + Alert = SelfModeratorBitField.FLAGS.ALERT, + Log = SelfModeratorBitField.FLAGS.LOG, + Delete = SelfModeratorBitField.FLAGS.DELETE +} + +export const kSoftActions = new Map([ + ['a', ASKeys.Alert], + ['al', ASKeys.Alert], + ['alert', ASKeys.Alert], + ['l', ASKeys.Log], + ['log', ASKeys.Log], + ['d', ASKeys.Delete], + ['del', ASKeys.Delete], + ['delete', ASKeys.Delete] +]); + +export const kHardActions = new Map([ + ['r', SelfModeratorHardActionFlags.None], + ['reset', SelfModeratorHardActionFlags.None], + ['n', SelfModeratorHardActionFlags.None], + ['none', SelfModeratorHardActionFlags.None], + ['w', SelfModeratorHardActionFlags.Warning], + ['warn', SelfModeratorHardActionFlags.Warning], + ['warning', SelfModeratorHardActionFlags.Warning], + ['m', SelfModeratorHardActionFlags.Mute], + ['mute', SelfModeratorHardActionFlags.Mute], + ['k', SelfModeratorHardActionFlags.Kick], + ['kick', SelfModeratorHardActionFlags.Kick], + ['sb', SelfModeratorHardActionFlags.SoftBan], + ['softban', SelfModeratorHardActionFlags.SoftBan], + ['soft-ban', SelfModeratorHardActionFlags.SoftBan], + ['b', SelfModeratorHardActionFlags.Ban], + ['ban', SelfModeratorHardActionFlags.Ban] +]); + +export abstract class SelfModerationCommand extends WolfCommand { + protected constructor(context: PieceContext, options: SelfModerationCommand.Options) { + super(context, { + permissionLevel: PermissionLevels.Administrator, + runIn: [CommandOptionsRunTypeEnum.GuildAny], + ...options + }); + } + + public async messageRun(message: GuildMessage, args: WolfCommand.Args) { + const type = this.getAction(args); + if (type === AKeys.Show) return this.show(message); + + let value = (await this.getValue(args, type)) as unknown; + + const key = this.getProperty(type)!; + const t = await writeSettings(message.guild, (settings) => { + Reflect.set(settings, key, value); + return settings.getLanguage(); + }); + + switch (type) { + case AKeys.SoftAction: { + value = SelfModerationCommand.displaySoftAction(t, value as number).join('`, `'); + break; + } + case AKeys.HardAction: { + value = t(SelfModerationCommand.displayHardAction(value as SelfModeratorHardActionFlags)); + break; + } + case AKeys.Enable: + case AKeys.Disable: + case AKeys.ThresholdMaximum: + case AKeys.ThresholdDuration: + case AKeys.HardActionDuration: + break; + } + + const content = SelfModerationCommand.getLanguageKey(t, type, value); + return send(message, content); + } + + protected async show(message: GuildMessage) { + const [enabled, softAction, hardAction, hardActionDuration, adder, t] = await readSettings(message.guild, (settings) => [ + settings[this.keyEnabled], + settings[this.keySoftAction], + settings[this.keyHardAction], + settings[this.keyHardActionDuration], + settings.adders[this.$adder], + settings.getLanguage() + ]); + + const [yes, no] = [t(LanguageKeys.Arguments.BooleanEnabled), t(LanguageKeys.Arguments.BooleanDisabled)]; + const codeBlockContent = t(LanguageKeys.Commands.Moderation.AutomaticParameterShow, { + kEnabled: enabled ? yes : no, + kAlert: SelfModerationCommand.has(softAction, ASKeys.Alert) ? yes : no, + kLog: SelfModerationCommand.has(softAction, ASKeys.Log) ? yes : no, + kDelete: SelfModerationCommand.has(softAction, ASKeys.Delete) ? yes : no, + kHardAction: t(SelfModerationCommand.displayHardAction(hardAction)), + hardActionDurationText: hardActionDuration + ? t(LanguageKeys.Globals.DurationValue, { value: hardActionDuration }) + : t(LanguageKeys.Commands.Moderation.AutomaticParameterShowDurationPermanent), + thresholdMaximumText: adder?.maximum ? adder.maximum : t(LanguageKeys.Commands.Moderation.AutomaticParameterShowUnset), + thresholdDurationText: adder?.duration + ? t(LanguageKeys.Globals.DurationValue, { value: adder.duration }) + : t(LanguageKeys.Commands.Moderation.AutomaticParameterShowUnset), + joinArrays: '\n' + }); + const content = codeBlock('prolog', codeBlockContent); + return send(message, content); + } + + private getAction(args: WolfCommand.Args) { + if (args.finished) return AKeys.Show; + + const action = kActions.get(args.next().toLowerCase()); + if (typeof action === 'undefined') { + return this.error(LanguageKeys.Commands.Moderation.AutomaticParameterInvalidMissingAction, { name: this.name }); + } + + return action; + } + + private async getValue(args: WolfCommand.Args, type: AKeys) { + if (type === AKeys.Enable) return true; + if (type === AKeys.Disable) return false; + if (type === AKeys.Show) return null; + if (args.finished) this.error(LanguageKeys.Commands.Moderation.AutomaticParameterInvalidMissingArguments, { name: this.name }); + + if (type === AKeys.SoftAction) { + const softAction = kSoftActions.get(args.next().toLowerCase()); + if (typeof softAction === 'undefined') { + this.error(LanguageKeys.Commands.Moderation.AutomaticParameterInvalidSoftAction, { name: this.name }); + } + + const previousSoftAction = await readSettings(args.message.guild!, this.keySoftAction); + return SelfModerationCommand.toggle(previousSoftAction, softAction); + } + + if (type === AKeys.HardAction) { + const hardAction = kHardActions.get(args.next().toLowerCase()); + if (typeof hardAction === 'undefined') { + this.error(LanguageKeys.Commands.Moderation.AutomaticParameterInvalidHardAction, { name: this.name }); + } + + return hardAction; + } + + if (type === AKeys.HardActionDuration) { + const key = configurableKeys.get(this.keyHardActionDuration)!; + return args.pick('timespan', { minimum: key.minimum, maximum: key.maximum }); + } + + if (type === AKeys.ThresholdMaximum) { + const key = configurableKeys.get(this.keyThresholdMaximum)!; + return args.pick('integer', { minimum: key.minimum, maximum: key.maximum }); + } + + if (type === AKeys.ThresholdDuration) { + const key = configurableKeys.get(this.keyThresholdDuration)!; + return args.pick('timespan', { minimum: key.minimum, maximum: key.maximum }); + } + + throw new Error('Unreachable'); + } + + private getProperty(action: AKeys) { + switch (action) { + case AKeys.Enable: + case AKeys.Disable: + return this.keyEnabled; + case AKeys.SoftAction: + return this.keySoftAction; + case AKeys.HardAction: + return this.keyHardAction; + case AKeys.HardActionDuration: + return this.keyHardActionDuration; + case AKeys.ThresholdMaximum: + return this.keyThresholdMaximum; + case AKeys.ThresholdDuration: + return this.keyThresholdDuration; + default: + throw new Error('Unexpected.'); + } + } + + private static displaySoftAction(t: TFunction, softAction: number) { + const actions: string[] = []; + if (SelfModerationCommand.has(softAction, ASKeys.Alert)) actions.push(t(LanguageKeys.Commands.Moderation.AutomaticValueSoftActionAlert)); + if (SelfModerationCommand.has(softAction, ASKeys.Log)) actions.push(t(LanguageKeys.Commands.Moderation.AutomaticValueSoftActionLog)); + if (SelfModerationCommand.has(softAction, ASKeys.Delete)) actions.push(t(LanguageKeys.Commands.Moderation.AutomaticValueSoftActionDelete)); + return actions; + } + + private static getLanguageKey(t: TFunction, action: AKeys, value: unknown) { + switch (action) { + case AKeys.Enable: + return t(LanguageKeys.Commands.Moderation.AutomaticParameterEnabled); + case AKeys.Disable: + return t(LanguageKeys.Commands.Moderation.AutomaticParameterDisabled); + case AKeys.SoftAction: { + return value + ? t(LanguageKeys.Commands.Moderation.AutomaticParameterSoftActionWithValue, { value: value as string }) + : t(LanguageKeys.Commands.Moderation.AutomaticParameterSoftAction); + } + case AKeys.HardAction: + return t(LanguageKeys.Commands.Moderation.AutomaticParameterHardAction, { value: value as string }); + case AKeys.HardActionDuration: { + return value + ? t(LanguageKeys.Commands.Moderation.AutomaticParameterHardActionDurationWithValue, { value: value as number }) + : t(LanguageKeys.Commands.Moderation.AutomaticParameterHardActionDuration); + } + case AKeys.ThresholdMaximum: { + return value + ? t(LanguageKeys.Commands.Moderation.AutomaticParameterThresholdMaximumWithValue, { value: value as number }) + : t(LanguageKeys.Commands.Moderation.AutomaticParameterThresholdMaximum); + } + case AKeys.ThresholdDuration: { + return value + ? t(LanguageKeys.Commands.Moderation.AutomaticParameterThresholdDurationWithValue, { value: value as number }) + : t(LanguageKeys.Commands.Moderation.AutomaticParameterThresholdDuration); + } + default: + throw new Error('Unexpected.'); + } + } + + private static displayHardAction(hardAction: SelfModeratorHardActionFlags | null) { + switch (hardAction) { + case SelfModeratorHardActionFlags.Ban: + return LanguageKeys.Commands.Moderation.AutomaticValueHardActionBan; + case SelfModeratorHardActionFlags.Kick: + return LanguageKeys.Commands.Moderation.AutomaticValueHardActionKick; + case SelfModeratorHardActionFlags.Mute: + return LanguageKeys.Commands.Moderation.AutomaticValueHardActionMute; + case SelfModeratorHardActionFlags.SoftBan: + return LanguageKeys.Commands.Moderation.AutomaticValueHardActionSoftBan; + case SelfModeratorHardActionFlags.Warning: + return LanguageKeys.Commands.Moderation.AutomaticValueHardActionWarning; + default: + return LanguageKeys.Commands.Moderation.AutomaticValueHardActionNone; + } + } + + private static has(bitfields: number, bitfield: number) { + return (bitfields & bitfield) === bitfield; + } + + private static toggle(bitfields: number, bitfield: number) { + return SelfModerationCommand.has(bitfields, bitfield) ? bitfields & ~bitfield : bitfields | bitfield; + } + + protected abstract $adder: AdderKey; + protected abstract keyEnabled: PickByValue; + protected abstract keySoftAction: PickByValue; + protected abstract keyHardAction: PickByValue; + protected abstract keyHardActionDuration: PickByValue; + protected abstract keyThresholdMaximum: PickByValue; + protected abstract keyThresholdDuration: PickByValue; +} + +export namespace SelfModerationCommand { + /** + * The SelfModerationCommand Options + */ + export type Options = WolfCommand.Options; + + export type Args = WolfCommand.Args; +} diff --git a/projects/bot/src/lib/moderation/structures/SelfModeratorBitField.ts b/projects/bot/src/lib/moderation/structures/SelfModeratorBitField.ts new file mode 100644 index 000000000..b2085f74c --- /dev/null +++ b/projects/bot/src/lib/moderation/structures/SelfModeratorBitField.ts @@ -0,0 +1,25 @@ +import { BitField } from 'discord.js'; + +export class SelfModeratorBitField extends BitField { + public static FLAGS: Record = { + DELETE: 1 << 0, + LOG: 1 << 1, + ALERT: 1 << 2 + }; + + public static ALL = SelfModeratorBitField.FLAGS.ALERT | SelfModeratorBitField.FLAGS.LOG | SelfModeratorBitField.FLAGS.DELETE; +} + +/** + * The bitfields for the SelfModeratorBitField + */ +export type SelfModeratorBitFieldString = 'DELETE' | 'LOG' | 'ALERT'; + +export enum SelfModeratorHardActionFlags { + None, + Warning, + Kick, + Mute, + SoftBan, + Ban +} diff --git a/projects/bot/src/lib/moderation/structures/SetUpModerationCommand.ts b/projects/bot/src/lib/moderation/structures/SetUpModerationCommand.ts new file mode 100644 index 000000000..35d0b5604 --- /dev/null +++ b/projects/bot/src/lib/moderation/structures/SetUpModerationCommand.ts @@ -0,0 +1,80 @@ +import { GuildEntity, readSettings, writeSettings } from '#lib/database'; +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import type { GuildMessage } from '#lib/types'; +import { getSecurity, isAdmin, promptConfirmation, promptForMessage } from '#utils/functions'; +import type { ModerationSetupRestriction } from '#utils/Security/ModerationActions'; +import type { Argument, PieceContext } from '@sapphire/framework'; +import { send } from '@sapphire/plugin-editable-commands'; +import type { PickByValue } from '@sapphire/utilities'; +import type { Role } from 'discord.js'; +import { ModerationCommand } from './ModerationCommand'; + +export abstract class SetUpModerationCommand extends ModerationCommand { + public readonly roleKey: PickByValue; + public readonly setUpKey: ModerationSetupRestriction; + + public constructor(context: PieceContext, options: SetUpModerationCommand.Options) { + super(context, options); + this.roleKey = options.roleKey; + this.setUpKey = options.setUpKey; + } + + private get role() { + return this.container.stores.get('arguments').get('role') as Argument; + } + + public async messageRun(message: GuildMessage, args: ModerationCommand.Args, context: ModerationCommand.Context): Promise { + await this.inhibit(message, args, context); + return super.messageRun(message, args, context); + } + + public async inhibit(message: GuildMessage, args: ModerationCommand.Args, context: ModerationCommand.Context) { + // If the command messageRun is not this one (potentially help command) or the guild is null, return with no error. + const [id, t] = await readSettings(message.guild, (settings) => [settings[this.roleKey], settings.getLanguage()]); + + // Verify for role existence. + const role = (id && message.guild.roles.cache.get(id)) ?? null; + if (role) return undefined; + + // If there + if (!(await isAdmin(message.member!))) { + this.error(LanguageKeys.Commands.Moderation.RestrictLowlevel); + } + + if (await promptConfirmation(message, t(LanguageKeys.Commands.Moderation.ActionSharedRoleSetupExisting))) { + const role = await this.askForRole(message, args, context); + if (!role.success) return this.error(role.error); + await writeSettings(message.guild, [[this.roleKey, role.value.id]]); + } else if (await promptConfirmation(message, t(LanguageKeys.Commands.Moderation.ActionSharedRoleSetupNew))) { + await getSecurity(message.guild).actions.restrictionSetup(message, this.setUpKey); + + const content = t(LanguageKeys.Commands.Moderation.Success); + await send(message, content); + } else { + this.error(LanguageKeys.Commands.Management.CommandHandlerAborted); + } + + return undefined; + } + + protected async askForRole(message: GuildMessage, args: SetUpModerationCommand.Args, context: SetUpModerationCommand.Context) { + const result = await promptForMessage(message, args.t(LanguageKeys.Commands.Moderation.ActionSharedRoleSetupExistingName)); + if (result === null) this.error(LanguageKeys.Commands.Moderation.ActionSharedRoleSetupNoMessage); + + const argument = this.role; + return argument.run(result, { args, argument, command: this, commandContext: context, message }); + } +} + +export namespace SetUpModerationCommand { + /** + * The ModerationCommand Options + */ + export interface Options extends ModerationCommand.Options { + roleKey: PickByValue; + setUpKey: ModerationSetupRestriction; + } + + export type Args = ModerationCommand.Args; + export type Context = ModerationCommand.Context; +} diff --git a/projects/bot/src/lib/moderation/structures/index.ts b/projects/bot/src/lib/moderation/structures/index.ts new file mode 100644 index 000000000..5d52bc183 --- /dev/null +++ b/projects/bot/src/lib/moderation/structures/index.ts @@ -0,0 +1,7 @@ +export * from './ModerationCommand'; +export * from './ModerationListener'; +export * from './ModerationMessageListener'; +export * from './ModerationTask'; +export * from './SelfModerationCommand'; +export * from './SelfModeratorBitField'; +export * from './SetUpModerationCommand'; diff --git a/src/lib/moderation/workers/WorkerHandler.ts b/projects/bot/src/lib/moderation/workers/WorkerHandler.ts similarity index 81% rename from src/lib/moderation/workers/WorkerHandler.ts rename to projects/bot/src/lib/moderation/workers/WorkerHandler.ts index d05acdf17..e903b5741 100644 --- a/src/lib/moderation/workers/WorkerHandler.ts +++ b/projects/bot/src/lib/moderation/workers/WorkerHandler.ts @@ -1,10 +1,13 @@ -import { WorkerResponseHandler } from '#lib/moderation/workers/WorkerResponseHandler'; -import { OutgoingType, type IncomingPayload, type NoId, type OutgoingPayload } from '#lib/moderation/workers/types'; +import { rootFolder } from '#utils/constants'; import { AsyncQueue } from '@sapphire/async-queue'; import { container } from '@sapphire/framework'; +import { envParseString } from '@wolfstar/env-utilities'; import { cyan, green, red, yellow } from 'colorette'; import { once } from 'node:events'; -import { SHARE_ENV, Worker } from 'node:worker_threads'; +import { join } from 'node:path'; +import { Worker } from 'node:worker_threads'; +import { IncomingPayload, NoId, OutgoingPayload, OutgoingType } from './types'; +import { WorkerResponseHandler } from './WorkerResponseHandler'; export class WorkerHandler { public lastHeartBeat!: number; @@ -60,8 +63,12 @@ export class WorkerHandler { public spawn() { this.online = false; this.lastHeartBeat = 0; - this.worker = new Worker(WorkerHandler.filename, { env: SHARE_ENV }); - this.worker.on('message', (message: OutgoingPayload) => this.handleWorkerMessage(message)); + this.worker = new Worker(WorkerHandler.workerTsLoader, { + workerData: { + path: WorkerHandler.filename + } + }); + this.worker.on('message', (message: OutgoingPayload) => this.handleMessage(message)); this.worker.once('online', () => this.handleOnline()); this.worker.once('exit', (code: number) => this.handleExit(code)); return this; @@ -91,16 +98,12 @@ export class WorkerHandler { return this.id++; } - private handleWorkerMessage(message: OutgoingPayload) { + private handleMessage(message: OutgoingPayload) { if (message.type === OutgoingType.Heartbeat) { this.lastHeartBeat = Date.now(); return; } - this.handleMessage(message); - } - - private handleMessage(message: OutgoingPayload) { this.response.resolve(message.id, message); } @@ -129,8 +132,8 @@ export class WorkerHandler { } } + private static readonly workerTsLoader = join(rootFolder, 'scripts', 'workerTsLoader.js'); private static readonly logsEnabled = process.env.NODE_ENV !== 'test'; - private static readonly filename = new URL('worker.mjs', import.meta.url); - + private static readonly filename = join(__dirname, `worker.${envParseString('NODE_ENV') === 'test' ? 't' : 'j'}s`); private static readonly maximumId = Number.MAX_SAFE_INTEGER; } diff --git a/src/lib/moderation/workers/WorkerManager.ts b/projects/bot/src/lib/moderation/workers/WorkerManager.ts similarity index 59% rename from src/lib/moderation/workers/WorkerManager.ts rename to projects/bot/src/lib/moderation/workers/WorkerManager.ts index 5478d632d..b36c6cfaf 100644 --- a/src/lib/moderation/workers/WorkerManager.ts +++ b/projects/bot/src/lib/moderation/workers/WorkerManager.ts @@ -1,13 +1,7 @@ -import { envParseInteger } from '@skyra/env-utilities'; +import { envParseInteger } from '@wolfstar/env-utilities'; import { cpus } from 'node:os'; -import type { - IncomingPayload, - IncomingRunRegExpPayload, - NoId, - OutgoingNoContentPayload, - OutgoingRegExpMatchPayload -} from '#lib/moderation/workers/types'; -import { WorkerHandler } from '#lib/moderation/workers/WorkerHandler'; +import type { IncomingPayload, IncomingRunRegExpPayload, NoId, OutgoingNoContentPayload, OutgoingRegExpMatchPayload } from './types'; +import { WorkerHandler } from './WorkerHandler'; export class WorkerManager { public readonly workers: WorkerHandler[] = []; @@ -25,8 +19,8 @@ export class WorkerManager { await Promise.all(this.workers.map((worker) => worker.start())); } - public send(data: NoId, delay?: number | null): Promise; - public send(data: NoId, delay?: number | null) { + public async send(data: NoId, delay?: number | null): Promise; + public async send(data: NoId, delay?: number | null) { return this.getIdealWorker().send(data, delay); } diff --git a/src/lib/moderation/workers/WorkerResponseHandler.ts b/projects/bot/src/lib/moderation/workers/WorkerResponseHandler.ts similarity index 83% rename from src/lib/moderation/workers/WorkerResponseHandler.ts rename to projects/bot/src/lib/moderation/workers/WorkerResponseHandler.ts index 2fdddf377..505b85e8b 100644 --- a/src/lib/moderation/workers/WorkerResponseHandler.ts +++ b/projects/bot/src/lib/moderation/workers/WorkerResponseHandler.ts @@ -1,6 +1,6 @@ -import { createReferPromise, type ReferredPromise } from '#utils/common'; -import { TimeoutError } from '#lib/moderation/workers/errors/TimeoutError'; -import type { OutgoingPayload } from '#lib/moderation/workers/types'; +import { createReferPromise, ReferredPromise } from '#utils/common'; +import { TimeoutError } from './errors'; +import type { OutgoingPayload } from './types'; export class WorkerResponseHandler { private id = -1; diff --git a/src/lib/moderation/workers/errors/TimeoutError.ts b/projects/bot/src/lib/moderation/workers/errors/TimeoutError.ts similarity index 100% rename from src/lib/moderation/workers/errors/TimeoutError.ts rename to projects/bot/src/lib/moderation/workers/errors/TimeoutError.ts diff --git a/projects/bot/src/lib/moderation/workers/errors/index.ts b/projects/bot/src/lib/moderation/workers/errors/index.ts new file mode 100644 index 000000000..3a1bf590f --- /dev/null +++ b/projects/bot/src/lib/moderation/workers/errors/index.ts @@ -0,0 +1 @@ +export * from './TimeoutError'; diff --git a/projects/bot/src/lib/moderation/workers/index.ts b/projects/bot/src/lib/moderation/workers/index.ts new file mode 100644 index 000000000..609ae5343 --- /dev/null +++ b/projects/bot/src/lib/moderation/workers/index.ts @@ -0,0 +1,5 @@ +export * from './errors'; +export * from './types'; +export * from './WorkerHandler'; +export * from './WorkerManager'; +export * from './WorkerResponseHandler'; diff --git a/src/lib/moderation/workers/types.ts b/projects/bot/src/lib/moderation/workers/types.ts similarity index 100% rename from src/lib/moderation/workers/types.ts rename to projects/bot/src/lib/moderation/workers/types.ts diff --git a/src/lib/moderation/workers/worker.mjs b/projects/bot/src/lib/moderation/workers/worker.ts similarity index 50% rename from src/lib/moderation/workers/worker.mjs rename to projects/bot/src/lib/moderation/workers/worker.ts index 1132b614f..72312190b 100644 --- a/src/lib/moderation/workers/worker.mjs +++ b/projects/bot/src/lib/moderation/workers/worker.ts @@ -1,42 +1,20 @@ import { remove as removeConfusables } from 'confusables'; import { isMainThread, parentPort } from 'node:worker_threads'; +import { IncomingPayload, IncomingRunRegExpPayload, IncomingType, OutgoingPayload, OutgoingType } from './types'; if (isMainThread || parentPort === null) throw new Error('The Worker may only be ran via the worker_threads fork method!'); -/** @typedef {import('./types.js').IncomingType} IncomingType */ -/** @typedef {import('./types.js').IncomingRunRegExpPayload} IncomingRunRegExpPayload */ -/** @typedef {import('./types.js').OutgoingPayload} OutgoingPayload */ -/** @typedef {import('./types.js').OutgoingRegExpMatchPayload} OutgoingRegExpMatchPayload */ - -const IncomingType = { - RunRegExp: 0 -}; - -const OutgoingType = { - Heartbeat: 0, - UnknownCommand: 1, - NoContent: 2, - RegExpMatch: 3 -}; - -/** - * @param {OutgoingPayload} message - */ -function post(message) { - return parentPort.postMessage(message); +function post(message: OutgoingPayload) { + return parentPort!.postMessage(message); } post({ type: OutgoingType.Heartbeat }); setInterval(() => post({ type: OutgoingType.Heartbeat }), 45000).unref(); -parentPort.on('message', (message) => post(handleMessage(message))); +parentPort.on('message', (message: IncomingPayload) => post(handleMessage(message))); -/** - * @param {IncomingPayload} message - * @returns {OutgoingPayload} - */ -function handleMessage(message) { +function handleMessage(message: IncomingPayload): OutgoingPayload { switch (message.type) { case IncomingType.RunRegExp: return handleRunRegExp(message); @@ -45,12 +23,7 @@ function handleMessage(message) { } } -/** - * Handles running a regular expression filter on a message's content after removing confusables. - * @param {IncomingRunRegExpPayload} message - The message object to filter. - * @returns {OutgoingPayload} - The filtered message content, if any. - */ -function handleRunRegExp(message) { +function handleRunRegExp(message: IncomingRunRegExpPayload): OutgoingPayload { // Remove confusables and run filter: const result = filter(removeConfusables(message.content), message.regExp); if (result === null) return { id: message.id, type: OutgoingType.NoContent }; @@ -59,24 +32,15 @@ function handleRunRegExp(message) { return { id: message.id, type: OutgoingType.RegExpMatch, filtered: result.filtered, highlighted: result.highlighted }; } -/** @typedef {Pick} RegExpMatchResult */ - -/** - * Filters a string based on a regular expression, replacing matching sections with asterisks and returning both the filtered and highlighted versions. - * - * @param {string} str - The string to filter. - * @param {RegExp} regex - The regular expression to match against. - * @returns {RegExpMatchResult | null} - */ -function filter(str, regex) { +function filter(str: string, regex: RegExp) { const matches = str.match(regex); if (matches === null) return null; let last = 0; let next = 0; - const filtered = []; - const highlighted = []; + const filtered: string[] = []; + const highlighted: string[] = []; for (const match of matches) { next = str.indexOf(match, last); const section = str.slice(last, next); diff --git a/projects/bot/src/lib/setup.ts b/projects/bot/src/lib/setup.ts new file mode 100644 index 000000000..662b69a28 --- /dev/null +++ b/projects/bot/src/lib/setup.ts @@ -0,0 +1,2 @@ +import '@sapphire/framework/register'; +import '@sapphire/plugin-i18next/register'; diff --git a/src/lib/structures/InviteStore.ts b/projects/bot/src/lib/structures/InviteStore.ts similarity index 80% rename from src/lib/structures/InviteStore.ts rename to projects/bot/src/lib/structures/InviteStore.ts index 15bc0b10a..f8c2c2d71 100644 --- a/src/lib/structures/InviteStore.ts +++ b/projects/bot/src/lib/structures/InviteStore.ts @@ -1,6 +1,7 @@ import { api } from '#lib/discord/Api'; import { minutes, resolveOnErrorCodes } from '#utils/common'; -import { Collection, RESTJSONErrorCodes, type RESTGetAPIInviteResult } from 'discord.js'; +import { Collection } from '@discordjs/collection'; +import { RESTGetAPIInviteResult, RESTJSONErrorCodes } from 'discord-api-types/v9'; export class InviteStore extends Collection { private readonly interval = setInterval(() => { @@ -16,7 +17,7 @@ export class InviteStore extends Collection { const previous = this.get(code); if (typeof previous !== 'undefined') return previous; - const data = (await resolveOnErrorCodes(api().invites.get(code), RESTJSONErrorCodes.UnknownInvite)) as RESTGetAPIInviteResult | null; + const data = (await resolveOnErrorCodes(api().invites(code).get(), RESTJSONErrorCodes.UnknownInvite)) as RESTGetAPIInviteResult | null; if (data === null) { const resolved: InviteCodeEntry = { valid: false, fetchedAt: Date.now() }; this.set(code, resolved); diff --git a/projects/bot/src/lib/structures/commands/SkyraCommand.ts b/projects/bot/src/lib/structures/commands/SkyraCommand.ts new file mode 100644 index 000000000..44a055573 --- /dev/null +++ b/projects/bot/src/lib/structures/commands/SkyraCommand.ts @@ -0,0 +1,23 @@ +import { Command } from '@sapphire/framework'; + +export class WolfCommand extends Command { + public readonly permissionLevel: number; + + public constructor(context: Command.LoaderContext, options: WolfCommand.Options) { + super(context, options); + this.permissionLevel = options.permissionLevel ?? 0; + } + + public get category(): string { + return this.fullCategory.join('.'); + } +} + +export namespace WolfCommand { + export interface Options extends Command.Options { + permissionLevel?: number; + } + + export type Args = Command.Args; + export type Context = Command.Context; +} diff --git a/projects/bot/src/lib/structures/index.ts b/projects/bot/src/lib/structures/index.ts new file mode 100644 index 000000000..57b973ac7 --- /dev/null +++ b/projects/bot/src/lib/structures/index.ts @@ -0,0 +1,3 @@ +export * from './InviteStore'; +export * from './commands/WolfCommand'; +export * from './managers'; diff --git a/src/lib/structures/managers/LockdownManager.ts b/projects/bot/src/lib/structures/managers/LockdownManager.ts similarity index 95% rename from src/lib/structures/managers/LockdownManager.ts rename to projects/bot/src/lib/structures/managers/LockdownManager.ts index f1f8293f5..ca008e7ce 100644 --- a/src/lib/structures/managers/LockdownManager.ts +++ b/projects/bot/src/lib/structures/managers/LockdownManager.ts @@ -1,6 +1,6 @@ import type { AccurateTimeout } from '#utils/Timers'; import type { GuildTextBasedChannelTypes } from '@sapphire/discord.js-utilities'; -import { Collection, type Role } from 'discord.js'; +import { Collection, Role } from 'discord.js'; export class LockdownManager extends Collection> { public add(role: Role, channel: LockdownManager.Channel, value: LockdownManager.Entry) { @@ -30,7 +30,7 @@ export class LockdownManager extends Collection entity.id === entityOrId)!; + if (!entityOrId) return false; + } + + await entityOrId.pause().remove(); + this._remove(entityOrId); + this._checkInterval(); + return true; + } + + public async execute() { + if (this.queue.length) { + // Process the active tasks, they're sorted by the time they end + const now = Date.now(); + const execute: Promise[] = []; + for (const entry of this.queue) { + if (entry.time.getTime() > now) break; + execute.push(entry.run()); + } + + // Check if the Schedule has a task to run and run them if they exist + if (!execute.length) return; + await this._handleResponses(await Promise.all(execute)); + } + + this._checkInterval(); + } + + private _insert(entity: ScheduleEntity) { + const index = this.queue.findIndex((entry) => entry.time > entity.time); + if (index === -1) this.queue.push(entity); + else this.queue.splice(index, 0, entity); + + return entity; + } + + private _remove(entity: ScheduleEntity) { + const index = this.queue.findIndex((entry) => entry === entity); + if (index !== -1) this.queue.splice(index, 1); + } + + private async _handleResponses(responses: readonly ResponseValue[]) { + const { connection } = container.db; + const queryRunner = connection.createQueryRunner(); + await queryRunner.connect(); + await queryRunner.startTransaction(); + + const updated: ScheduleEntity[] = []; + const removed: ScheduleEntity[] = []; + try { + for (const response of responses) { + // Pause so it is not re-run + response.entry.pause(); + + switch (response.type) { + case ResponseType.Delay: { + response.entry.time = new Date(response.entry.time.getTime() + response.value); + updated.push(response.entry); + await queryRunner.manager.save(response.entry); + continue; + } + case ResponseType.Finished: { + removed.push(response.entry); + await queryRunner.manager.remove(response.entry); + continue; + } + case ResponseType.Ignore: { + continue; + } + case ResponseType.Update: { + response.entry.time = response.value; + updated.push(response.entry); + await queryRunner.manager.save(response.entry); + } + } + } + + // Commit transaction + await queryRunner.commitTransaction(); + + // Update cache + // - Remove expired entries + for (const entry of removed) { + this._remove(entry); + } + + // - Update indexes + for (const entry of updated) { + const index = this.queue.findIndex((entity) => entity === entry); + if (index === -1) continue; + + this.queue.splice(index, 1); + this._insert(entry); + + // Resume so it can be run again + entry.resume(); + } + } catch (error) { + container.logger.fatal(error); + + // Rollback transaction + await queryRunner.rollbackTransaction(); + + // Reload all entities + await Promise.all(updated.map((entry) => entry.reload())); + } finally { + // Release transaction + await queryRunner.release(); + } + } + + /** + * Clear the current interval + */ + private _clearInterval(): void { + if (this.interval) { + clearInterval(this.interval); + this.interval = null; + } + } + + /** + * Sets the interval when needed + */ + private _checkInterval(): void { + if (!this.queue.length) { + this._clearInterval(); + } else if (!this.interval) { + this.interval = setInterval(this.execute.bind(this), container.client.options.schedule?.interval ?? 5000).unref(); + } + } + + /** + * Resolve the time and cron + * @param time The time or Cron pattern + */ + private _resolveTime(time: TimeResolvable): [Date, Cron | null] { + if (time instanceof Date) return [time, null]; + if (time instanceof Cron) return [time.next(), time]; + if (typeof time === 'number') return [new Date(time), null]; + if (typeof time === 'string') { + const cron = new Cron(time); + return [cron.next(), cron]; + } + throw new Error('invalid time passed'); + } +} + +export interface ScheduleManagerAddOptions { + /** + * If the task should try to catch up if the bot is down. + */ + catchUp?: boolean; + + /** + * The data to pass to the Task piece when the ScheduledTask is ready for execution. + */ + data?: Record; +} + +export type TimeResolvable = number | Date | string | Cron; diff --git a/projects/bot/src/lib/structures/managers/index.ts b/projects/bot/src/lib/structures/managers/index.ts new file mode 100644 index 000000000..04aa6963c --- /dev/null +++ b/projects/bot/src/lib/structures/managers/index.ts @@ -0,0 +1,2 @@ +export * from './LockdownManager'; +export * from './ScheduleManager'; diff --git a/src/lib/util/Links/TLDs.ts b/projects/bot/src/lib/util/Links/TLDs.ts similarity index 96% rename from src/lib/util/Links/TLDs.ts rename to projects/bot/src/lib/util/Links/TLDs.ts index 727c6fc6c..69e3995ed 100644 --- a/src/lib/util/Links/TLDs.ts +++ b/projects/bot/src/lib/util/Links/TLDs.ts @@ -1,9 +1,10 @@ // Autogenerated file from ICANN, source: -// https://data.iana.org/TLD/tlds-alpha-by-domain.txt +// http://data.iana.org/TLD/tlds-alpha-by-domain.txt export const TLDs = [ 'aaa', 'aarp', + 'abarth', 'abb', 'abbott', 'abbvie', @@ -19,6 +20,7 @@ export const TLDs = [ 'aco', 'actor', 'ad', + 'adac', 'ads', 'adult', 'ae', @@ -38,6 +40,7 @@ export const TLDs = [ 'airtel', 'akdn', 'al', + 'alfaromeo', 'alibaba', 'alipay', 'allfinanz', @@ -88,6 +91,7 @@ export const TLDs = [ 'author', 'auto', 'autos', + 'avianca', 'aw', 'aws', 'ax', @@ -98,6 +102,7 @@ export const TLDs = [ 'baby', 'baidu', 'banamex', + 'bananarepublic', 'band', 'bank', 'bar', @@ -174,6 +179,7 @@ export const TLDs = [ 'brussels', 'bs', 'bt', + 'bugatti', 'build', 'builders', 'business', @@ -193,6 +199,7 @@ export const TLDs = [ 'cam', 'camera', 'camp', + 'cancerresearch', 'canon', 'capetown', 'capital', @@ -214,6 +221,7 @@ export const TLDs = [ 'cba', 'cbn', 'cbre', + 'cbs', 'cc', 'cd', 'center', @@ -242,6 +250,7 @@ export const TLDs = [ 'citi', 'citic', 'city', + 'cityeats', 'ck', 'cl', 'claims', @@ -262,6 +271,7 @@ export const TLDs = [ 'college', 'cologne', 'com', + 'comcast', 'commbank', 'community', 'company', @@ -274,6 +284,7 @@ export const TLDs = [ 'contact', 'contractors', 'cooking', + 'cookingchannel', 'cool', 'coop', 'corsica', @@ -300,6 +311,7 @@ export const TLDs = [ 'cymru', 'cyou', 'cz', + 'dabur', 'dad', 'dance', 'data', @@ -378,6 +390,7 @@ export const TLDs = [ 'esq', 'estate', 'et', + 'etisalat', 'eu', 'eurovision', 'eus', @@ -403,6 +416,7 @@ export const TLDs = [ 'ferrari', 'ferrero', 'fi', + 'fiat', 'fidelity', 'fido', 'film', @@ -428,6 +442,7 @@ export const TLDs = [ 'fo', 'foo', 'food', + 'foodnetwork', 'football', 'ford', 'forex', @@ -440,6 +455,7 @@ export const TLDs = [ 'fresenius', 'frl', 'frogans', + 'frontdoor', 'frontier', 'ftr', 'fujitsu', @@ -511,6 +527,7 @@ export const TLDs = [ 'gs', 'gt', 'gu', + 'guardian', 'gucci', 'guge', 'guide', @@ -531,6 +548,7 @@ export const TLDs = [ 'helsinki', 'here', 'hermes', + 'hgtv', 'hiphop', 'hisamitsu', 'hitachi', @@ -552,6 +570,7 @@ export const TLDs = [ 'host', 'hosting', 'hot', + 'hoteles', 'hotels', 'hotmail', 'house', @@ -630,6 +649,7 @@ export const TLDs = [ 'kddi', 'ke', 'kerryhotels', + 'kerrylogistics', 'kerryproperties', 'kfh', 'kg', @@ -638,6 +658,7 @@ export const TLDs = [ 'kia', 'kids', 'kim', + 'kinder', 'kindle', 'kitchen', 'kiwi', @@ -662,6 +683,7 @@ export const TLDs = [ 'lamborghini', 'lamer', 'lancaster', + 'lancia', 'land', 'landrover', 'lanxess', @@ -692,7 +714,9 @@ export const TLDs = [ 'limited', 'limo', 'lincoln', + 'linde', 'link', + 'lipsy', 'live', 'living', 'lk', @@ -702,6 +726,7 @@ export const TLDs = [ 'loans', 'locker', 'locus', + 'loft', 'lol', 'london', 'lotte', @@ -721,6 +746,7 @@ export const TLDs = [ 'lv', 'ly', 'ma', + 'macys', 'madrid', 'maif', 'maison', @@ -734,6 +760,7 @@ export const TLDs = [ 'markets', 'marriott', 'marshalls', + 'maserati', 'mattel', 'mba', 'mc', @@ -793,6 +820,7 @@ export const TLDs = [ 'mu', 'museum', 'music', + 'mutual', 'mv', 'mw', 'mx', @@ -802,6 +830,7 @@ export const TLDs = [ 'nab', 'nagoya', 'name', + 'natura', 'navy', 'nba', 'nc', @@ -832,6 +861,7 @@ export const TLDs = [ 'nl', 'no', 'nokia', + 'northwesternmutual', 'norton', 'now', 'nowruz', @@ -850,6 +880,7 @@ export const TLDs = [ 'okinawa', 'olayan', 'olayangroup', + 'oldnavy', 'ollo', 'om', 'omega', @@ -876,6 +907,7 @@ export const TLDs = [ 'partners', 'parts', 'party', + 'passagens', 'pay', 'pccw', 'pe', @@ -976,6 +1008,7 @@ export const TLDs = [ 'rio', 'rip', 'ro', + 'rocher', 'rocks', 'rodeo', 'rogers', @@ -1010,6 +1043,7 @@ export const TLDs = [ 'sbi', 'sbs', 'sc', + 'sca', 'scb', 'schaeffler', 'schmidt', @@ -1029,6 +1063,7 @@ export const TLDs = [ 'select', 'sener', 'services', + 'ses', 'seven', 'sew', 'sex', @@ -1038,6 +1073,7 @@ export const TLDs = [ 'sh', 'shangrila', 'sharp', + 'shaw', 'shell', 'shia', 'shiksha', @@ -1046,6 +1082,7 @@ export const TLDs = [ 'shopping', 'shouji', 'show', + 'showtime', 'si', 'silk', 'sina', @@ -1143,6 +1180,7 @@ export const TLDs = [ 'tiaa', 'tickets', 'tienda', + 'tiffany', 'tips', 'tires', 'tirol', @@ -1172,6 +1210,7 @@ export const TLDs = [ 'trading', 'training', 'travel', + 'travelchannel', 'travelers', 'travelersinsurance', 'trust', @@ -1226,12 +1265,14 @@ export const TLDs = [ 'vlaanderen', 'vn', 'vodka', + 'volkswagen', 'volvo', 'vote', 'voting', 'voto', 'voyage', 'vu', + 'vuelos', 'wales', 'walmart', 'walter', @@ -1269,6 +1310,7 @@ export const TLDs = [ 'wtf', 'xbox', 'xerox', + 'xfinity', 'xihuan', 'xin', 'कॉम', // xn--11b4c3d @@ -1348,6 +1390,7 @@ export const TLDs = [ 'укр', // xn--j1amh '香港', // xn--j6w193g '亚马逊', // xn--jlq480n2rg + '诺基亚', // xn--jlq61u9w7b '食品', // xn--jvr189m '飞利浦', // xn--kcrx77d1x4a '台湾', // xn--kprw13d @@ -1359,6 +1402,7 @@ export const TLDs = [ 'ارامكو', // xn--mgba3a3ejt 'ایران', // xn--mgba3a4f16a 'العليان', // xn--mgba7c0bbn0a + 'اتصالات', // xn--mgbaakc7dvf 'امارات', // xn--mgbaam7a8h 'بازار', // xn--mgbab2bd 'موريتانيا', // xn--mgbah1a3hjkrd diff --git a/src/lib/util/Links/UrlRegex.ts b/projects/bot/src/lib/util/Links/UrlRegex.ts similarity index 97% rename from src/lib/util/Links/UrlRegex.ts rename to projects/bot/src/lib/util/Links/UrlRegex.ts index ddb380a05..2359faa9b 100644 --- a/src/lib/util/Links/UrlRegex.ts +++ b/projects/bot/src/lib/util/Links/UrlRegex.ts @@ -22,7 +22,7 @@ * THE SOFTWARE. */ -import { TLDs } from '#lib/util/Links/TLDs'; +import { TLDs } from './TLDs'; export function urlRegex({ requireProtocol = true, exact = false, tlds = false }: UrlRegexOptions = {}) { const protocol = `(?:(?:[a-z]+:)?//)${requireProtocol ? '' : '?'}`; diff --git a/projects/bot/src/lib/util/Parsers/ExceededLength.ts b/projects/bot/src/lib/util/Parsers/ExceededLength.ts new file mode 100644 index 000000000..76db106af --- /dev/null +++ b/projects/bot/src/lib/util/Parsers/ExceededLength.ts @@ -0,0 +1,132 @@ +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { getHaste } from '#utils/APIs/Hastebin'; +import { promptForMessage } from '#utils/functions'; +import { canSendAttachments } from '@sapphire/discord.js-utilities'; +import { container } from '@sapphire/framework'; +import { send } from '@sapphire/plugin-editable-commands'; +import { fetchT } from '@sapphire/plugin-i18next'; +import { codeBlock } from '@sapphire/utilities'; +import type { Message } from 'discord.js'; +import type { TFunction } from 'i18next'; + +export async function handleMessage( + message: Message, + options: HandleMessageData +): Promise { + const t = await fetchT(message); + const typeFooter = options.footer ? t(LanguageKeys.System.ExceededLengthOutputType, { type: options.footer }) : undefined; + const timeTaken = options.time ? t(LanguageKeys.System.ExceededLengthOutputTime, { time: options.time }) : undefined; + + switch (options.sendAs) { + case 'file': { + if (canSendAttachments(message.channel)) { + const output = t(LanguageKeys.System.ExceededLengthOutputFile); + const content = [output, typeFooter, timeTaken].filter(Boolean).join('\n'); + + const fileExtension = options.language ?? 'txt'; + const attachment = Buffer.from(options.content ? options.content : options.result!); + const name = options.targetId ? `${options.targetId}.${fileExtension}` : `output.${fileExtension}`; + return send(message, { content, files: [{ attachment, name }] }); + } + + await getTypeOutput(message, t, options); + return handleMessage(message, options); + } + case 'haste': + case 'hastebin': { + if (!options.url) { + options.url = await getHaste(options.content ? options.content : options.result!, options.language ?? 'md').catch(() => null); + } + + if (options.url) { + const hastebinUrl = t(LanguageKeys.System.ExceededLengthOutputHastebin, { url: options.url }); + + const content = [hastebinUrl, typeFooter, timeTaken].filter(Boolean).join('\n'); + return send(message, content); + } + + options.hastebinUnavailable = true; + + await getTypeOutput(message, t, options); + return handleMessage(message, options); + } + case 'console': + case 'log': { + if (options.canLogToConsole) { + container.logger.info(options.result); + const output = t(LanguageKeys.System.ExceededLengthOutputConsole); + + const content = [output, typeFooter, timeTaken].filter(Boolean).join('\n'); + return send(message, content); + } + await getTypeOutput(message, t, options); + return handleMessage(message, options); + } + case 'abort': + case 'none': + return null; + default: { + if (options.content ? options.content.length > 1950 : options.result!.length > 1950) { + await getTypeOutput(message, t, options); + return handleMessage(message, options); + } + + if (options.content) { + const content = codeBlock('md', options.content); + return send(message, content); + } + + if (options.success) { + const parsedOutput = t(LanguageKeys.System.ExceededLengthOutput, { output: codeBlock(options.language!, options.result!) }); + + const content = [parsedOutput, typeFooter, timeTaken].filter(Boolean).join('\n'); + return send(message, content); + } + + const output = codeBlock(options.language ?? 'ts', options.result!); + const content = t(LanguageKeys.Commands.System.EvalError, { time: options.time!, output, type: options.footer! }); + return send(message, content); + } + } +} + +async function getTypeOutput(message: Message, t: TFunction, options: HandleMessageData) { + const _options = ['none', 'abort']; + if (options.canLogToConsole) _options.push('log'); + + if (canSendAttachments(message.channel)) _options.push('file'); + if (!options.hastebinUnavailable) _options.push('hastebin'); + + let choice: string; + do { + const content = await promptForMessage(message, t(LanguageKeys.System.ExceededLengthChooseOutput, { output: _options })); + choice = content?.toLowerCase() ?? 'none'; + } while (!_options.concat('none', 'abort').includes(choice)); + + options.sendAs = choice; +} + +type HandleMessageData = { + sendAs: string | null; + hastebinUnavailable: boolean; + url: string | null; + canLogToConsole: boolean; +} & ED; + +export interface EvalExtraData extends QueryExtraData { + footer: string; +} + +export interface ContentExtraData { + content: string; + targetId: string; +} + +export interface QueryExtraData { + success: boolean; + result: string; + time: string; + language: string; +} + +type ExtraDataPartial = Partial & Partial & Partial; diff --git a/src/lib/util/Parsers/FuzzySearch.ts b/projects/bot/src/lib/util/Parsers/FuzzySearch.ts similarity index 93% rename from src/lib/util/Parsers/FuzzySearch.ts rename to projects/bot/src/lib/util/Parsers/FuzzySearch.ts index 2aa9962e0..d9de209c8 100644 --- a/src/lib/util/Parsers/FuzzySearch.ts +++ b/projects/bot/src/lib/util/Parsers/FuzzySearch.ts @@ -1,10 +1,10 @@ import { LanguageKeys } from '#lib/i18n/languageKeys'; -import type { NonGroupMessage } from '#lib/types'; import { promptForMessage } from '#utils/functions'; import { UserError } from '@sapphire/framework'; import { fetchT } from '@sapphire/plugin-i18next'; import { codeBlock } from '@sapphire/utilities'; import { decodeUtf8, jaroWinkler } from '@skyra/jaro-winkler'; +import type { Message } from 'discord.js'; type FuzzySearchAccess = (value: V) => string; type FuzzySearchFilter = (value: V) => boolean; @@ -20,7 +20,7 @@ export class FuzzySearch { this.kFilter = filter; } - public run(message: NonGroupMessage, query: string, threshold?: number) { + public run(message: Message, query: string, threshold?: number) { const lowerCaseQuery = query.toLowerCase(); const decodedLowerCaseQuery = decodeUtf8(lowerCaseQuery); const results: [K, V, number][] = []; @@ -75,7 +75,7 @@ export class FuzzySearch { return this.select(message, sorted); } - private async select(message: NonGroupMessage, results: [K, V, number][]) { + private async select(message: Message, results: [K, V, number][]) { if (results.length === 1) return results[0]; if (results.length > 10) results.length = 10; diff --git a/src/lib/util/Sanitizer/clean.ts b/projects/bot/src/lib/util/Sanitizer/clean.ts similarity index 96% rename from src/lib/util/Sanitizer/clean.ts rename to projects/bot/src/lib/util/Sanitizer/clean.ts index 863fc1d54..f668ef3ae 100644 --- a/src/lib/util/Sanitizer/clean.ts +++ b/projects/bot/src/lib/util/Sanitizer/clean.ts @@ -35,7 +35,7 @@ const zws = String.fromCharCode(8203); */ export function clean(text: string) { if (typeof sensitivePattern === 'undefined') { - throw new TypeError('initClean must be called before running this.'); + throw new Error('initClean must be called before running this.'); } return text.replace(sensitivePattern, '「redacted」').replace(/`/g, `\`${zws}`).replace(/@/g, `@${zws}`); } diff --git a/src/lib/util/Sanitizer/initClean.ts b/projects/bot/src/lib/util/Sanitizer/initClean.ts similarity index 83% rename from src/lib/util/Sanitizer/initClean.ts rename to projects/bot/src/lib/util/Sanitizer/initClean.ts index c24de7cb8..3ef5a65e5 100644 --- a/src/lib/util/Sanitizer/initClean.ts +++ b/projects/bot/src/lib/util/Sanitizer/initClean.ts @@ -2,7 +2,7 @@ import { initClean } from '#utils/Sanitizer/clean'; import { isNullishOrEmpty } from '@sapphire/utilities'; const secrets = new Set(); -const suffixes = ['_KEY', '_TOKEN', '_SECRET', '_PASSWORD', 'PGSQL']; +const suffixes = ['_KEY', '_TOKEN', '_SECRET', '_PASSWORD']; for (const [key, value] of Object.entries(process.env)) { if (isNullishOrEmpty(value)) continue; if (suffixes.some((suffix) => key.endsWith(suffix))) secrets.add(value); diff --git a/src/lib/util/Security/GuildSecurity.ts b/projects/bot/src/lib/util/Security/GuildSecurity.ts similarity index 67% rename from src/lib/util/Security/GuildSecurity.ts rename to projects/bot/src/lib/util/Security/GuildSecurity.ts index 28a873a3f..f5c151594 100644 --- a/src/lib/util/Security/GuildSecurity.ts +++ b/projects/bot/src/lib/util/Security/GuildSecurity.ts @@ -1,5 +1,6 @@ import { LockdownManager } from '#lib/structures'; import type { Guild } from 'discord.js'; +import { ModerationActions } from './ModerationActions'; /** * @version 3.0.0 @@ -10,6 +11,11 @@ export class GuildSecurity { */ public guild: Guild; + /** + * The moderation actions + */ + public actions: ModerationActions; + /** * The lockdowns map */ @@ -17,5 +23,6 @@ export class GuildSecurity { public constructor(guild: Guild) { this.guild = guild; + this.actions = new ModerationActions(this.guild); } } diff --git a/projects/bot/src/lib/util/Security/ModerationActions.ts b/projects/bot/src/lib/util/Security/ModerationActions.ts new file mode 100644 index 000000000..c0a5e173c --- /dev/null +++ b/projects/bot/src/lib/util/Security/ModerationActions.ts @@ -0,0 +1,1028 @@ +import type { GuildEntity, ModerationEntity } from '#lib/database/entities'; +import { GuildSettings } from '#lib/database/keys'; +import { readSettings, writeSettings } from '#lib/database/settings'; +import { api } from '#lib/discord/Api'; +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import type { ModerationManagerCreateData } from '#lib/moderation'; +import { resolveOnErrorCodes } from '#utils/common'; +import { getModeration, getStickyRoles, promptConfirmation } from '#utils/functions'; +import { TypeCodes } from '#utils/moderationConstants'; +import { isCategoryChannel, isNewsChannel, isStageChannel, isTextChannel, isVoiceChannel } from '@sapphire/discord.js-utilities'; +import { container, UserError } from '@sapphire/framework'; +import { fetchT, resolveKey } from '@sapphire/plugin-i18next'; +import { isNullish, isNullishOrEmpty, isNullishOrZero, Nullish, PickByValue } from '@sapphire/utilities'; +import { RESTJSONErrorCodes } from 'discord-api-types/v9'; +import { + DiscordAPIError, + Guild, + GuildChannel, + GuildMember, + Message, + MessageEmbed, + PermissionOverwriteOptions, + Permissions, + Role, + RoleData, + User +} from 'discord.js'; +import type { TFunction } from 'i18next'; + +export const enum ModerationSetupRestriction { + All = 'rolesMuted', + Reaction = 'rolesRestrictedReaction', + Embed = 'rolesRestrictedEmbed', + Emoji = 'rolesRestrictedEmoji', + Attachment = 'rolesRestrictedAttachment', + Voice = 'rolesRestrictedVoice' +} + +const enum RoleDataKey { + Muted, + Reaction, + Embed, + Emoji, + Attachment, + Voice +} + +const kRoleDataOptions = new Map([ + [ + RoleDataKey.Muted, + { + color: 0x000000, + hoist: false, + mentionable: false, + name: 'Muted', + permissions: [] + } + ], + [ + RoleDataKey.Attachment, + { + color: 0x000000, + hoist: false, + mentionable: false, + name: 'Restricted Attachment', + permissions: [] + } + ], + [ + RoleDataKey.Embed, + { + color: 0x000000, + hoist: false, + mentionable: false, + name: 'Restricted Embed', + permissions: [] + } + ], + [ + RoleDataKey.Emoji, + { + color: 0x000000, + hoist: false, + mentionable: false, + name: 'Restricted Emoji', + permissions: [] + } + ], + [ + RoleDataKey.Reaction, + { + color: 0x000000, + hoist: false, + mentionable: false, + name: 'Restricted Reaction', + permissions: [] + } + ], + [ + RoleDataKey.Voice, + { + color: 0x000000, + hoist: false, + mentionable: false, + name: 'Restricted Voice', + permissions: [] + } + ] +]); + +const kRoleChannelOverwriteOptions = new Map([ + [ + RoleDataKey.Muted, + { + category: { + options: { + SEND_MESSAGES: false, + ADD_REACTIONS: false, + CONNECT: false + }, + permissions: new Permissions(['SEND_MESSAGES', 'ADD_REACTIONS', 'CONNECT']) + }, + text: { + options: { + SEND_MESSAGES: false, + ADD_REACTIONS: false + }, + permissions: new Permissions(['SEND_MESSAGES', 'ADD_REACTIONS']) + }, + voice: { + options: { + CONNECT: false + }, + permissions: new Permissions(['CONNECT']) + } + } + ], + [ + RoleDataKey.Attachment, + { + category: { + options: { + ATTACH_FILES: false + }, + permissions: new Permissions(['ATTACH_FILES']) + }, + text: { + options: { + ATTACH_FILES: false + }, + permissions: new Permissions(['ATTACH_FILES']) + }, + voice: null + } + ], + [ + RoleDataKey.Embed, + { + category: { + options: { + EMBED_LINKS: false + }, + permissions: new Permissions(['EMBED_LINKS']) + }, + text: { + options: { + EMBED_LINKS: false + }, + permissions: new Permissions(['EMBED_LINKS']) + }, + voice: null + } + ], + [ + RoleDataKey.Emoji, + { + category: { + options: { + USE_EXTERNAL_EMOJIS: false + }, + permissions: new Permissions(['USE_EXTERNAL_EMOJIS']) + }, + text: { + options: { + USE_EXTERNAL_EMOJIS: false + }, + permissions: new Permissions(['USE_EXTERNAL_EMOJIS']) + }, + voice: null + } + ], + [ + RoleDataKey.Reaction, + { + category: { + options: { + ADD_REACTIONS: false + }, + permissions: new Permissions(['ADD_REACTIONS']) + }, + text: { + options: { + ADD_REACTIONS: false + }, + permissions: new Permissions(['ADD_REACTIONS']) + }, + voice: null + } + ], + [ + RoleDataKey.Voice, + { + category: { + options: { + CONNECT: false + }, + permissions: new Permissions(['CONNECT']) + }, + text: null, + voice: { + options: { + CONNECT: false + }, + permissions: new Permissions(['CONNECT']) + } + } + ] +]); + +export interface ModerationAction { + addRole: string; + mute: string; + ban: string; + kick: string; + softban: string; + vkick: string; + vmute: string; + restrictedReact: string; + restrictedEmbed: string; + restrictedAttachment: string; + restrictedVoice: string; + setNickname: string; + removeRole: string; +} + +export class ModerationActions { + public guild: Guild; + + public constructor(guild: Guild) { + this.guild = guild; + } + + private get manageableChannelCount() { + return this.guild.channels.cache.reduce((acc, channel) => (channel.manageable ? acc + 1 : acc), 0); + } + + public async warning(rawOptions: ModerationActionOptions, sendOptions?: ModerationActionsSendOptions) { + const options = ModerationActions.fillOptions(rawOptions, TypeCodes.Warning); + const moderationLog = getModeration(this.guild).create(options); + await this.sendDM(moderationLog, sendOptions); + return (await moderationLog.create())!; + } + + public async unWarning(rawOptions: ModerationActionOptions, caseId: number, sendOptions?: ModerationActionsSendOptions) { + const oldModerationLog = await getModeration(this.guild).fetch(caseId); + if (oldModerationLog === null || !oldModerationLog.isType(TypeCodes.Warning)) + throw await resolveKey(this.guild, LanguageKeys.Commands.Moderation.GuildWarnNotFound); + + await oldModerationLog.invalidate(); + const options = ModerationActions.fillOptions(rawOptions, TypeCodes.UnWarn); + const moderationLog = getModeration(this.guild).create(options); + await this.sendDM(moderationLog, sendOptions); + return (await moderationLog.create())!; + } + + public async setNickname(rawOptions: ModerationActionOptions, nickname: string, sendOptions?: ModerationActionsSendOptions) { + const oldName = this.guild.members.cache.get(rawOptions.userId)?.nickname || ''; + const options = ModerationActions.fillOptions({ ...rawOptions, extraData: { oldName } }, TypeCodes.SetNickname); + const moderationLog = getModeration(this.guild).create(options); + await this.sendDM(moderationLog, sendOptions); + await api() + .guilds(this.guild.id) + .members(rawOptions.userId) + .patch({ + data: { nick: nickname }, + reason: moderationLog.reason + ? await resolveKey( + this.guild, + nickname + ? LanguageKeys.Commands.Moderation.ActionSetNicknameSet + : LanguageKeys.Commands.Moderation.ActionSetNicknameRemoved, + { reason: moderationLog.reason } + ) + : await resolveKey( + this.guild, + nickname + ? LanguageKeys.Commands.Moderation.ActionSetNicknameNoReasonSet + : LanguageKeys.Commands.Moderation.ActionSetNicknameNoReasonRemoved + ) + }); + + await this.cancelLastLogTaskFromUser(options.userId, TypeCodes.SetNickname); + return (await moderationLog.create())!; + } + + public async unSetNickname(rawOptions: ModerationActionOptions, nickname: string, sendOptions?: ModerationActionsSendOptions) { + const options = ModerationActions.fillOptions(rawOptions, TypeCodes.UnSetNickname); + const moderationLog = getModeration(this.guild).create(options); + await this.sendDM(moderationLog, sendOptions); + await api() + .guilds(this.guild.id) + .members(rawOptions.userId) + .patch({ data: { nick: nickname }, reason: rawOptions.reason }); + + await this.cancelLastLogTaskFromUser(options.userId, TypeCodes.SetNickname); + return (await moderationLog.create())!; + } + + public async addRole(rawOptions: ModerationActionOptions, role: Role, sendOptions?: ModerationActionsSendOptions) { + const options = ModerationActions.fillOptions({ ...rawOptions, extraData: { role: role.id } }, TypeCodes.AddRole); + const moderationLog = getModeration(this.guild).create(options); + await this.sendDM(moderationLog, sendOptions); + await api() + .guilds(this.guild.id) + .members(rawOptions.userId) + .roles(role.id) + .put({ + reason: await this.getReason('addRole', moderationLog.reason) + }); + + await this.cancelLastLogTaskFromUser(options.userId, TypeCodes.AddRole, (log) => (log.extraData as { role?: string })?.role === role.id); + return (await moderationLog.create())!; + } + + public async unAddRole(rawOptions: ModerationActionOptions, role: Role, sendOptions?: ModerationActionsSendOptions) { + const options = ModerationActions.fillOptions(rawOptions, TypeCodes.UnAddRole); + const moderationLog = getModeration(this.guild).create(options); + await this.sendDM(moderationLog, sendOptions); + await api().guilds(this.guild.id).members(rawOptions.userId).roles(role.id).delete({ reason: rawOptions.reason! }); + + await this.cancelLastLogTaskFromUser(options.userId, TypeCodes.AddRole, (log) => (log.extraData as { role?: string })?.role === role.id); + return (await moderationLog.create())!; + } + + public async removeRole(rawOptions: ModerationActionOptions, role: Role, sendOptions?: ModerationActionsSendOptions) { + const options = ModerationActions.fillOptions({ ...rawOptions, extraData: { role: role.id } }, TypeCodes.RemoveRole); + const moderationLog = getModeration(this.guild).create(options); + await this.sendDM(moderationLog, sendOptions); + await api() + .guilds(this.guild.id) + .members(rawOptions.userId) + .roles(role.id) + .delete({ reason: await this.getReason('removeRole', moderationLog.reason) }); + + await this.cancelLastLogTaskFromUser(options.userId, TypeCodes.RemoveRole, (log) => (log.extraData as { role?: string })?.role === role.id); + return (await moderationLog.create())!; + } + + public async unRemoveRole(rawOptions: ModerationActionOptions, role: Role, sendOptions?: ModerationActionsSendOptions) { + const options = ModerationActions.fillOptions(rawOptions, TypeCodes.UnRemoveRole); + const moderationLog = getModeration(this.guild).create(options); + await this.sendDM(moderationLog, sendOptions); + await api().guilds(this.guild.id).members(rawOptions.userId).roles(role.id).put({ reason: rawOptions.reason }); + + await this.cancelLastLogTaskFromUser(options.userId, TypeCodes.RemoveRole, (log) => (log.extraData as { role?: string })?.role === role.id); + return (await moderationLog.create())!; + } + + public async mute(rawOptions: ModerationActionOptions, sendOptions?: ModerationActionsSendOptions) { + await this.addStickyMute(rawOptions.userId); + const extraData = await this.muteUser(rawOptions); + const options = ModerationActions.fillOptions({ ...rawOptions, extraData }, TypeCodes.Mute); + const moderationLog = getModeration(this.guild).create(options); + await this.sendDM(moderationLog, sendOptions); + + await this.cancelLastLogTaskFromUser(options.userId, TypeCodes.Mute); + return (await moderationLog.create())!; + } + + public async unMute(rawOptions: ModerationActionOptions, sendOptions?: ModerationActionsSendOptions) { + const options = ModerationActions.fillOptions(rawOptions, TypeCodes.UnMute); + await this.removeStickyMute(options.userId); + const oldModerationLog = await this.cancelLastLogTaskFromUser(options.userId, TypeCodes.Mute); + if (typeof oldModerationLog === 'undefined') { + throw await resolveKey(this.guild, LanguageKeys.Commands.Moderation.MuteNotExists); + } + + // If Skyra does not have permissions to manage permissions, abort. + if (!(await this.fetchMe()).permissions.has(Permissions.FLAGS.MANAGE_ROLES)) { + throw await resolveKey(this.guild, LanguageKeys.Commands.Moderation.MuteCannotManageRoles); + } + + await this.unmuteUser(options, oldModerationLog); + const moderationLog = getModeration(this.guild).create(options); + await this.sendDM(moderationLog, sendOptions); + + return (await moderationLog.create())!; + } + + public async kick(rawOptions: ModerationActionOptions, sendOptions?: ModerationActionsSendOptions) { + const options = ModerationActions.fillOptions(rawOptions, TypeCodes.Kick); + const moderationLog = getModeration(this.guild).create(options); + await this.sendDM(moderationLog, sendOptions); + await api() + .guilds(this.guild.id) + .members(options.userId) + .delete({ + reason: await this.getReason('kick', moderationLog.reason) + }); + return (await moderationLog.create())!; + } + + public async softBan(rawOptions: ModerationActionOptions, days: number, sendOptions?: ModerationActionsSendOptions) { + const options = ModerationActions.fillOptions(rawOptions, TypeCodes.SoftBan); + const moderationLog = getModeration(this.guild).create(options); + await this.sendDM(moderationLog, sendOptions); + + const t = await fetchT(this.guild); + await api() + .guilds(this.guild.id) + .bans(options.userId) + .put({ + data: { + delete_message_days: days + }, + reason: moderationLog.reason + ? t(LanguageKeys.Commands.Moderation.ActionSoftBanReason, { reason: moderationLog.reason! }) + : t(LanguageKeys.Commands.Moderation.ActionSoftBanNoReason) + }); + await api() + .guilds(this.guild.id) + .bans(options.userId) + .delete({ + reason: moderationLog.reason + ? t(LanguageKeys.Commands.Moderation.ActionUnSoftBanReason, { reason: moderationLog.reason! }) + : t(LanguageKeys.Commands.Moderation.ActionUnSoftBanNoReason) + }); + return (await moderationLog.create())!; + } + + public async ban(rawOptions: ModerationActionOptions, days: number, sendOptions?: ModerationActionsSendOptions) { + const options = ModerationActions.fillOptions(rawOptions, TypeCodes.Ban); + const moderationLog = getModeration(this.guild).create(options); + await this.sendDM(moderationLog, sendOptions); + await api() + .guilds(this.guild.id) + .bans(options.userId) + .put({ + data: { + delete_message_days: days + }, + reason: await this.getReason('ban', moderationLog.reason) + }); + + await this.cancelLastLogTaskFromUser(options.userId, TypeCodes.Ban); + return (await moderationLog.create())!; + } + + public async unBan(rawOptions: ModerationActionOptions, sendOptions?: ModerationActionsSendOptions) { + const options = ModerationActions.fillOptions(rawOptions, TypeCodes.UnBan); + const moderationLog = getModeration(this.guild).create(options); + await api() + .guilds(this.guild.id) + .bans(options.userId) + .delete({ reason: await this.getReason('ban', moderationLog.reason, true) }); + await this.sendDM(moderationLog, sendOptions); + + await this.cancelLastLogTaskFromUser(options.userId, TypeCodes.Ban); + return (await moderationLog.create())!; + } + + public async voiceMute(rawOptions: ModerationActionOptions, sendOptions?: ModerationActionsSendOptions) { + const options = ModerationActions.fillOptions(rawOptions, TypeCodes.VoiceMute); + const moderationLog = getModeration(this.guild).create(options); + await api() + .guilds(this.guild.id) + .members(options.userId) + .patch({ data: { mute: true }, reason: await this.getReason('vmute', moderationLog.reason) }); + await this.sendDM(moderationLog, sendOptions); + + await this.cancelLastLogTaskFromUser(options.userId, TypeCodes.VoiceMute); + return (await moderationLog.create())!; + } + + public async unVoiceMute(rawOptions: ModerationActionOptions, sendOptions?: ModerationActionsSendOptions) { + const options = ModerationActions.fillOptions(rawOptions, TypeCodes.UnVoiceMute); + const moderationLog = getModeration(this.guild).create(options); + await api() + .guilds(this.guild.id) + .members(options.userId) + .patch({ data: { mute: false }, reason: await this.getReason('vmute', moderationLog.reason, true) }); + await this.sendDM(moderationLog, sendOptions); + + await this.cancelLastLogTaskFromUser(options.userId, TypeCodes.VoiceMute); + return (await moderationLog.create())!; + } + + public async voiceKick(rawOptions: ModerationActionOptions, sendOptions?: ModerationActionsSendOptions) { + const options = ModerationActions.fillOptions(rawOptions, TypeCodes.VoiceKick); + const moderationLog = getModeration(this.guild).create(options); + await api() + .guilds(this.guild.id) + .members(options.userId) + .patch({ data: { channel_id: null }, reason: await this.getReason('vkick', moderationLog.reason) }); + await this.sendDM(moderationLog, sendOptions); + return (await moderationLog.create())!; + } + + public async restrictAttachment(rawOptions: ModerationActionOptions, sendOptions?: ModerationActionsSendOptions) { + await this.addStickyRestriction(rawOptions.userId, GuildSettings.Roles.RestrictedAttachment); + await this.addRestrictionRole(rawOptions.userId, GuildSettings.Roles.RestrictedAttachment); + const options = ModerationActions.fillOptions(rawOptions, TypeCodes.RestrictionAttachment); + const moderationLog = getModeration(this.guild).create(options); + await this.sendDM(moderationLog, sendOptions); + + await this.cancelLastLogTaskFromUser(options.userId, TypeCodes.RestrictionAttachment); + return (await moderationLog.create())!; + } + + public async unRestrictAttachment(rawOptions: ModerationActionOptions, sendOptions?: ModerationActionsSendOptions) { + await this.removeStickyRestriction(rawOptions.userId, GuildSettings.Roles.RestrictedAttachment); + await this.removeRestrictionRole(rawOptions.userId, GuildSettings.Roles.RestrictedAttachment); + const options = ModerationActions.fillOptions(rawOptions, TypeCodes.UnRestrictionAttachment); + const moderationLog = getModeration(this.guild).create(options); + await this.sendDM(moderationLog, sendOptions); + + await this.cancelLastLogTaskFromUser(options.userId, TypeCodes.RestrictionAttachment); + return (await moderationLog.create())!; + } + + public async restrictReaction(rawOptions: ModerationActionOptions, sendOptions?: ModerationActionsSendOptions) { + await this.addStickyRestriction(rawOptions.userId, GuildSettings.Roles.RestrictedReaction); + await this.addRestrictionRole(rawOptions.userId, GuildSettings.Roles.RestrictedReaction); + const options = ModerationActions.fillOptions(rawOptions, TypeCodes.RestrictionReaction); + const moderationLog = getModeration(this.guild).create(options); + await this.sendDM(moderationLog, sendOptions); + + await this.cancelLastLogTaskFromUser(options.userId, TypeCodes.RestrictionReaction); + return (await moderationLog.create())!; + } + + public async unRestrictReaction(rawOptions: ModerationActionOptions, sendOptions?: ModerationActionsSendOptions) { + await this.removeStickyRestriction(rawOptions.userId, GuildSettings.Roles.RestrictedReaction); + await this.removeRestrictionRole(rawOptions.userId, GuildSettings.Roles.RestrictedReaction); + const options = ModerationActions.fillOptions(rawOptions, TypeCodes.UnRestrictionReaction); + const moderationLog = getModeration(this.guild).create(options); + await this.sendDM(moderationLog, sendOptions); + + await this.cancelLastLogTaskFromUser(options.userId, TypeCodes.RestrictionReaction); + return (await moderationLog.create())!; + } + + public async restrictEmbed(rawOptions: ModerationActionOptions, sendOptions?: ModerationActionsSendOptions) { + await this.addStickyRestriction(rawOptions.userId, GuildSettings.Roles.RestrictedEmbed); + await this.addRestrictionRole(rawOptions.userId, GuildSettings.Roles.RestrictedEmbed); + const options = ModerationActions.fillOptions(rawOptions, TypeCodes.RestrictionEmbed); + const moderationLog = getModeration(this.guild).create(options); + await this.sendDM(moderationLog, sendOptions); + + await this.cancelLastLogTaskFromUser(options.userId, TypeCodes.RestrictionEmbed); + return (await moderationLog.create())!; + } + + public async unRestrictEmbed(rawOptions: ModerationActionOptions, sendOptions?: ModerationActionsSendOptions) { + await this.removeStickyRestriction(rawOptions.userId, GuildSettings.Roles.RestrictedEmbed); + await this.removeRestrictionRole(rawOptions.userId, GuildSettings.Roles.RestrictedEmbed); + const options = ModerationActions.fillOptions(rawOptions, TypeCodes.UnRestrictionEmbed); + const moderationLog = getModeration(this.guild).create(options); + await this.sendDM(moderationLog, sendOptions); + + await this.cancelLastLogTaskFromUser(options.userId, TypeCodes.RestrictionEmbed); + return (await moderationLog.create())!; + } + + public async restrictEmoji(rawOptions: ModerationActionOptions, sendOptions?: ModerationActionsSendOptions) { + await this.addStickyRestriction(rawOptions.userId, GuildSettings.Roles.RestrictedEmoji); + await this.addRestrictionRole(rawOptions.userId, GuildSettings.Roles.RestrictedEmoji); + const options = ModerationActions.fillOptions(rawOptions, TypeCodes.RestrictionEmoji); + const moderationLog = getModeration(this.guild).create(options); + await this.sendDM(moderationLog, sendOptions); + + await this.cancelLastLogTaskFromUser(options.userId, TypeCodes.RestrictionEmoji); + return (await moderationLog.create())!; + } + + public async unRestrictEmoji(rawOptions: ModerationActionOptions, sendOptions?: ModerationActionsSendOptions) { + await this.removeStickyRestriction(rawOptions.userId, GuildSettings.Roles.RestrictedEmoji); + await this.removeRestrictionRole(rawOptions.userId, GuildSettings.Roles.RestrictedEmoji); + const options = ModerationActions.fillOptions(rawOptions, TypeCodes.UnRestrictionEmoji); + const moderationLog = getModeration(this.guild).create(options); + await this.sendDM(moderationLog, sendOptions); + + await this.cancelLastLogTaskFromUser(options.userId, TypeCodes.RestrictionEmoji); + return (await moderationLog.create())!; + } + + public async restrictVoice(rawOptions: ModerationActionOptions, sendOptions?: ModerationActionsSendOptions) { + await this.addStickyRestriction(rawOptions.userId, GuildSettings.Roles.RestrictedVoice); + await this.addRestrictionRole(rawOptions.userId, GuildSettings.Roles.RestrictedVoice); + const options = ModerationActions.fillOptions(rawOptions, TypeCodes.RestrictionVoice); + const moderationLog = getModeration(this.guild).create(options); + await this.sendDM(moderationLog, sendOptions); + + await this.cancelLastLogTaskFromUser(options.userId, TypeCodes.RestrictionVoice); + return (await moderationLog.create())!; + } + + public async unRestrictVoice(rawOptions: ModerationActionOptions, sendOptions?: ModerationActionsSendOptions) { + await this.removeStickyRestriction(rawOptions.userId, GuildSettings.Roles.RestrictedVoice); + await this.removeRestrictionRole(rawOptions.userId, GuildSettings.Roles.RestrictedVoice); + const options = ModerationActions.fillOptions(rawOptions, TypeCodes.UnRestrictionVoice); + const moderationLog = getModeration(this.guild).create(options); + await this.sendDM(moderationLog, sendOptions); + + await this.cancelLastLogTaskFromUser(options.userId, TypeCodes.RestrictionVoice); + return (await moderationLog.create())!; + } + + public async muteSetup(message: Message) { + const [roleId] = await readSettings(this.guild, (settings) => [settings[GuildSettings.Roles.Muted]]); + if (roleId && this.guild.roles.cache.has(roleId)) throw new UserError({ identifier: LanguageKeys.Commands.Moderation.ActionSetupMuteExists }); + if (this.guild.roles.cache.size >= 250) throw new UserError({ identifier: LanguageKeys.Commands.Moderation.ActionSetupTooManyRoles }); + + // Set up the shared role setup + return this.sharedRoleSetup(message, RoleDataKey.Muted, GuildSettings.Roles.Muted); + } + + public async restrictionSetup(message: Message, path: ModerationSetupRestriction) { + const [roleId] = await readSettings(this.guild, (settings) => [settings[path]]); + if (!isNullish(roleId) && this.guild.roles.cache.has(roleId)) { + throw new UserError({ identifier: LanguageKeys.Commands.Moderation.ActionSetupRestrictionExists }); + } + if (this.guild.roles.cache.size >= 250) throw new UserError({ identifier: LanguageKeys.Commands.Moderation.ActionSetupTooManyRoles }); + + // Set up the shared role setup + return this.sharedRoleSetup(message, ModerationActions.getRoleDataKeyFromSchemaKey(path), path); + } + + public async userIsBanned(user: User) { + try { + await api().guilds(this.guild.id).bans(user.id).get(); + return true; + } catch (error) { + if (!(error instanceof DiscordAPIError)) throw await resolveKey(this.guild, LanguageKeys.System.FetchBansFail); + if (error.code === RESTJSONErrorCodes.UnknownBan) return false; + throw error; + } + } + + public async userIsMuted(user: User) { + const roleId = await readSettings(this.guild, GuildSettings.Roles.Muted); + if (isNullish(roleId)) return false; + return getStickyRoles(this.guild).has(user.id, roleId); + } + + public async userIsVoiceMuted(user: User) { + const member = await resolveOnErrorCodes(this.guild.members.fetch(user.id), RESTJSONErrorCodes.UnknownUser); + return member?.voice.serverMute ?? false; + } + + private async sharedRoleSetup(message: Message, key: RoleDataKey, path: PickByValue) { + const roleData = kRoleDataOptions.get(key)!; + const role = await this.guild.roles.create({ + ...roleData, + reason: `[Role Setup] Authorized by ${message.author.username} (${message.author.id}).` + }); + const t = await writeSettings(this.guild, (settings) => { + Reflect.set(settings, path, role.id); + return settings.getLanguage(); + }); + + if ( + await promptConfirmation( + message, + t(LanguageKeys.Commands.Moderation.ActionSharedRoleSetupAsk, { + role: role.name, + channels: this.manageableChannelCount, + permissions: this.displayPermissions(t, key).map((permission) => `\`${permission}\``) + }) + ) + ) { + await this.updatePermissionsForCategoryChannels(role, key); + await this.updatePermissionsForTextOrVoiceChannels(role, key); + } + } + + private displayPermissions(t: TFunction, key: RoleDataKey) { + const options = kRoleChannelOverwriteOptions.get(key)!; + const output: string[] = []; + for (const keyOption of Object.keys(options.category.options)) { + output.push(t(`permissions:${keyOption}`, keyOption)); + } + return output; + } + + private async fetchMe() { + return this.guild.members.fetch(process.env.CLIENT_ID); + } + + private async sendDM(entry: ModerationEntity, sendOptions: ModerationActionsSendOptions = {}) { + if (sendOptions.send) { + try { + const target = await entry.fetchUser(); + const embed = await this.buildEmbed(entry, sendOptions); + await resolveOnErrorCodes(target.send({ embeds: [embed] }), RESTJSONErrorCodes.CannotSendMessagesToThisUser); + } catch (error) { + container.logger.error(error); + } + } + } + + private async buildEmbed(entry: ModerationEntity, sendOptions: ModerationActionsSendOptions) { + const descriptionKey = entry.reason + ? entry.duration + ? LanguageKeys.Commands.Moderation.ModerationDmDescriptionWithReasonWithDuration + : LanguageKeys.Commands.Moderation.ModerationDmDescriptionWithReason + : entry.duration + ? LanguageKeys.Commands.Moderation.ModerationDmDescriptionWithDuration + : LanguageKeys.Commands.Moderation.ModerationDmDescription; + + const t = await fetchT(this.guild); + const description = t(descriptionKey, { + guild: this.guild.name, + title: entry.title, + reason: entry.reason, + duration: entry.duration + }); + const embed = new MessageEmbed() // + .setDescription(description) + .setFooter({ text: t(LanguageKeys.Commands.Moderation.ModerationDmFooter) }); + + if (sendOptions.moderator) { + embed.setAuthor({ + name: sendOptions.moderator.username, + iconURL: sendOptions.moderator.displayAvatarURL({ size: 128, format: 'png', dynamic: true }) + }); + } + + return embed; + } + + private async addStickyMute(id: string) { + const [roleId] = await readSettings(this.guild, (settings) => [settings.rolesMuted]); + if (isNullish(roleId)) throw new UserError({ identifier: LanguageKeys.Commands.Moderation.MuteNotConfigured }); + return getStickyRoles(this.guild).add(id, roleId); + } + + private async removeStickyMute(id: string) { + const [roleId] = await readSettings(this.guild, (settings) => [settings.rolesMuted]); + if (isNullish(roleId)) throw new UserError({ identifier: LanguageKeys.Commands.Moderation.MuteNotConfigured }); + return getStickyRoles(this.guild).remove(id, roleId); + } + + private async muteUser(rawOptions: ModerationActionOptions) { + try { + const member = await this.guild.members.fetch(rawOptions.userId); + return this.muteUserInGuild(member, await this.getReason('mute', rawOptions.reason || null)); + } catch (error) { + if ((error as DiscordAPIError).code === RESTJSONErrorCodes.UnknownMember) + throw await resolveKey(this.guild, LanguageKeys.Commands.Moderation.ActionRequiredMember); + throw error; + } + } + + private async muteUserInGuild(member: GuildMember, reason: string) { + const [roleId] = await readSettings(this.guild, (settings) => [settings.rolesMuted]); + if (isNullish(roleId)) throw new UserError({ identifier: LanguageKeys.Commands.Moderation.MuteNotConfigured }); + + const role = this.guild.roles.cache.get(roleId); + if (typeof role === 'undefined') { + await writeSettings(this.guild, [[GuildSettings.Roles.Muted, null]]); + throw new UserError({ identifier: LanguageKeys.Commands.Moderation.MuteNotConfigured }); + } + + const { position } = (await this.fetchMe()).roles.highest; + const extracted = ModerationActions.muteExtractRoles(member, position); + extracted.keepRoles.push(roleId); + + await member.edit({ roles: extracted.keepRoles }, reason); + return extracted.removedRoles; + } + + private async unmuteUser(options: ModerationManagerCreateData & { reason: string | null }, moderationLog: ModerationEntity | null) { + try { + const member = await this.guild.members.fetch(options.userId); + return moderationLog === null + ? this.unmuteUserInGuildWithoutData(member, await this.getReason('mute', options.reason, true)) + : this.unmuteUserInGuildWithData(member, await this.getReason('mute', options.reason, true), moderationLog); + } catch (error) { + if ((error as DiscordAPIError).code !== RESTJSONErrorCodes.UnknownMember) throw error; + } + } + + /** + * Unmute a user who is in a guild and has a running moderation log. + * @since 5.3.0 + * @param member The member to unmute + * @param reason The reason to send for audit logs when unmuting + * @param moderationLog The moderation manager that defined the formal mute + */ + private async unmuteUserInGuildWithData(member: GuildMember, reason: string, moderationLog: ModerationEntity) { + const roleId = await readSettings(this.guild, GuildSettings.Roles.Muted); + const { position } = (await this.fetchMe()).roles.highest; + const rawRoleIds = Array.isArray(moderationLog.extraData) ? (moderationLog.extraData as string[]) : []; + const roles = this.unmuteExtractRoles(member, roleId, position, rawRoleIds); + await member.edit({ roles }, reason); + + return roles; + } + + /** + * Unmute a user who is in a guild and does not have a running moderation log, e.g. when unmuting somebody who + * merely has the muted role. + * @since 5.3.0 + * @param member The member to unmute + * @param reason The reason to send for audit logs when unmuting + */ + private async unmuteUserInGuildWithoutData(member: GuildMember, reason: string) { + // Retrieve the role ID of the mute role, return false if it does not exist. + const [roleId] = await readSettings(this.guild, (settings) => [settings.rolesMuted]); + if (isNullish(roleId)) throw new UserError({ identifier: LanguageKeys.Commands.Moderation.MuteNotConfigured }); + + // Retrieve the role instance from the role ID, reset and return false if it does not exist. + const role = this.guild.roles.cache.get(roleId); + if (typeof role === 'undefined') { + await writeSettings(this.guild, [[GuildSettings.Roles.Muted, null]]); + throw new UserError({ identifier: LanguageKeys.Commands.Moderation.MuteNotConfigured }); + } + + // If the user has the role, begin processing the data. + if (member.roles.cache.has(roleId)) { + // Fetch self and check if the bot has enough role hierarchy to manage the role, return false when not. + const { position } = (await this.fetchMe()).roles.highest; + if (role.position >= position) throw new UserError({ identifier: LanguageKeys.Commands.Moderation.MuteLowHierarchy }); + + // Remove the role from the member. + await member.roles.remove(roleId, reason); + return; + } + + throw new UserError({ identifier: LanguageKeys.Commands.Moderation.MuteNotInMember }); + } + + private unmuteExtractRoles(member: GuildMember, roleId: string | Nullish, selfPosition: number, rawIdentifiers: readonly string[] | null) { + if (rawIdentifiers === null) rawIdentifiers = []; + + const rawRoles: Role[] = []; + for (const id of rawIdentifiers) { + const role = this.guild.roles.cache.get(id); + if (typeof role !== 'undefined') rawRoles.push(role); + } + + const roles = new Set(member.roles.cache.keys()); + for (const rawRole of rawRoles) { + if (rawRole.position < selfPosition) roles.add(rawRole.id); + } + + if (!isNullish(roleId)) roles.delete(roleId); + + return [...roles]; + } + + private async addStickyRestriction(id: string, key: PickByValue) { + const [roleId] = await readSettings(this.guild, (settings) => [settings[key]]); + if (isNullish(roleId)) throw new UserError({ identifier: LanguageKeys.Misc.RestrictionNotConfigured }); + return getStickyRoles(this.guild).add(id, roleId); + } + + private async addRestrictionRole(id: string, key: PickByValue) { + const [roleId] = await readSettings(this.guild, (settings) => [settings[key]]); + if (isNullish(roleId)) throw new UserError({ identifier: LanguageKeys.Misc.RestrictionNotConfigured }); + await api().guilds(this.guild.id).members(id).roles(roleId).put(); + } + + private async removeStickyRestriction(id: string, key: PickByValue) { + const [roleId] = await readSettings(this.guild, (settings) => [settings[key]]); + if (isNullish(roleId)) throw new UserError({ identifier: LanguageKeys.Misc.RestrictionNotConfigured }); + return getStickyRoles(this.guild).remove(id, roleId); + } + + private async removeRestrictionRole(id: string, key: PickByValue) { + const [roleId] = await readSettings(this.guild, (settings) => [settings[key]]); + if (isNullish(roleId)) throw new UserError({ identifier: LanguageKeys.Misc.RestrictionNotConfigured }); + try { + await api().guilds(this.guild.id).members(id).roles(roleId).delete(); + } catch (error) { + if ((error as DiscordAPIError).code !== RESTJSONErrorCodes.UnknownMember) throw error; + } + } + + private async updatePermissionsForCategoryChannels(role: Role, dataKey: RoleDataKey) { + const options = kRoleChannelOverwriteOptions.get(dataKey)!; + const promises: Promise[] = []; + for (const channel of this.guild.channels.cache.values()) { + if (isCategoryChannel(channel) && channel.manageable) { + promises.push(ModerationActions.updatePermissionsForChannel(role, channel, options.category)); + } + } + + await Promise.all(promises); + } + + private async updatePermissionsForTextOrVoiceChannels(role: Role, dataKey: RoleDataKey) { + const options = kRoleChannelOverwriteOptions.get(dataKey)!; + const promises: Promise[] = []; + for (const channel of this.guild.channels.cache.values()) { + if (!channel.manageable) continue; + if (isTextChannel(channel) || isNewsChannel(channel)) { + promises.push(ModerationActions.updatePermissionsForChannel(role, channel, options.text)); + } else if (isVoiceChannel(channel) || isStageChannel(channel)) { + promises.push(ModerationActions.updatePermissionsForChannel(role, channel, options.voice)); + } + } + + await Promise.all(promises); + } + + /** + * Deletes the task from the last log from a user's cases + * @param userId The user ID to use when fetching + * @param type The type to retrieve for the invalidation + */ + private async cancelLastLogTaskFromUser(userId: string, type: TypeCodes, extra?: (log: ModerationEntity) => boolean) { + const log = await this.retrieveLastLogFromUser(userId, type, extra); + if (!log) return null; + + const { task } = log; + if (task && !task.running) await task.delete(); + return log; + } + + private async getReason(action: keyof ModerationAction, reason: string | null, revoke = false) { + const t = await fetchT(this.guild); + const actions = t(LanguageKeys.Commands.Moderation.Actions); + if (!reason) + return revoke + ? t(LanguageKeys.Commands.Moderation.ActionRevokeNoReason, { action: actions[action] }) + : t(LanguageKeys.Commands.Moderation.ActionApplyNoReason, { action: actions[action] }); + return revoke + ? t(LanguageKeys.Commands.Moderation.ActionRevokeReason, { action: actions[action], reason }) + : t(LanguageKeys.Commands.Moderation.ActionApplyReason, { action: actions[action], reason }); + } + + private async retrieveLastLogFromUser(userId: string, type: TypeCodes, extra: (log: ModerationEntity) => boolean = () => true) { + // Retrieve all moderation logs regarding a user. + const logs = await getModeration(this.guild).fetch(userId); + + // Filter all logs by valid and by type of mute (isType will include temporary and invisible). + return logs.filter((log) => !log.invalidated && log.isType(type) && extra(log)).last(); + } + + private static getRoleDataKeyFromSchemaKey(key: ModerationSetupRestriction): RoleDataKey { + switch (key) { + case ModerationSetupRestriction.All: + return RoleDataKey.Muted; + case ModerationSetupRestriction.Attachment: + return RoleDataKey.Attachment; + case ModerationSetupRestriction.Embed: + return RoleDataKey.Embed; + case ModerationSetupRestriction.Emoji: + return RoleDataKey.Emoji; + case ModerationSetupRestriction.Reaction: + return RoleDataKey.Reaction; + case ModerationSetupRestriction.Voice: + return RoleDataKey.Voice; + } + } + + private static fillOptions(rawOptions: ModerationActionOptions, type: TypeCodes) { + const options = { reason: null, ...rawOptions, type }; + if (isNullishOrEmpty(options.reason)) options.reason = null; + if (isNullishOrEmpty(options.moderatorId)) options.moderatorId = process.env.CLIENT_ID; + if (isNullishOrZero(options.duration)) options.duration = null; + return options; + } + + private static muteExtractRoles(member: GuildMember, selfPosition: number) { + const keepRoles: string[] = []; + const removedRoles: string[] = []; + + // Iterate over all the member's roles. + for (const [id, role] of member.roles.cache.entries()) { + // Managed roles cannot be removed. + if (role.managed) keepRoles.push(id); + // Roles with higher hierarchy position cannot be removed. + else if (role.position >= selfPosition) keepRoles.push(id); + // Else it is fine to remove the role. + else removedRoles.push(id); + } + + return { keepRoles, removedRoles }; + } + + private static async updatePermissionsForChannel(role: Role, channel: GuildChannel, rolePermissions: RolePermissionOverwriteOptionField | null) { + if (rolePermissions === null) return; + + const current = channel.permissionOverwrites.cache.get(role.id); + if (typeof current === 'undefined') { + // If no permissions overwrites exists, create a new one. + await channel.permissionOverwrites.edit(role, rolePermissions.options, { reason: '[Setup] Updated channel for Muted Role.' }); + } else if (!current.deny.has(rolePermissions.permissions)) { + // If one exists and does not have the deny fields, tweak the existing one to keep all the allowed and + // denied, but also add the ones that must be denied for the mute role to work. + const allowed = current.allow.toArray().map((permission) => [permission, true]); + const denied = current.allow.toArray().map((permission) => [permission, false]); + const mixed = Object.fromEntries(allowed.concat(denied)); + await current.edit({ ...mixed, ...rolePermissions.options }); + } + } +} + +export interface ModerationActionsSendOptions { + send?: boolean; + moderator?: User | null; +} + +interface RolePermissionOverwriteOption { + category: RolePermissionOverwriteOptionField; + text: RolePermissionOverwriteOptionField | null; + voice: RolePermissionOverwriteOptionField | null; +} + +interface RolePermissionOverwriteOptionField { + options: PermissionOverwriteOptions; + permissions: Permissions; +} + +export type ModerationActionOptions = Omit; diff --git a/src/lib/util/Security/RegexCreator.ts b/projects/bot/src/lib/util/Security/RegexCreator.ts similarity index 90% rename from src/lib/util/Security/RegexCreator.ts rename to projects/bot/src/lib/util/Security/RegexCreator.ts index 58a60d77c..62268bab1 100644 --- a/src/lib/util/Security/RegexCreator.ts +++ b/projects/bot/src/lib/util/Security/RegexCreator.ts @@ -54,17 +54,17 @@ export function processWordBoundaries(word: string) { return starts ? // Starts and end? - ends + ends ? // Starts and ends - WordBoundary.Both + WordBoundary.Both : // Only starts - WordBoundary.Start + WordBoundary.Start : // Ends? - ends - ? // Ends with wildcard - WordBoundary.End - : // Does not have wildcards - WordBoundary.None; + ends + ? // Ends with wildcard + WordBoundary.End + : // Does not have wildcards + WordBoundary.None; } export function processWordPatternsWithGroups(word: string) { @@ -81,13 +81,13 @@ export function processGroup(group: string) { onMatch: (match) => match[1] === match[2] ? // and a === - - match[1] === '-' + match[1] === '-' ? // then optimize to - - '\\-' + '\\-' : // else optimize to a- - `${processLetter(match[1])}\\-` + `${processLetter(match[1])}\\-` : // otherwise a-b - `${processLetter(match[1])}-${processLetter(match[2])}`, + `${processLetter(match[1])}-${processLetter(match[2])}`, outMatch: (match) => [...match].map(processLetter).join('') }); diff --git a/projects/bot/src/lib/util/bits.ts b/projects/bot/src/lib/util/bits.ts new file mode 100644 index 000000000..e24c5bfd2 --- /dev/null +++ b/projects/bot/src/lib/util/bits.ts @@ -0,0 +1,48 @@ +import type { Constructor } from '@sapphire/utilities'; +import { BitField, Permissions, SystemChannelFlags } from 'discord.js'; +import { max } from './common'; + +function toMap(ctor: Constructor>) { + return new Map(Object.entries(Reflect.get(ctor, 'FLAGS')).map(([key, value]) => [value as N, key as S] as const)); +} + +function toInitialOffset(map: Map) { + let i: number; + let max: number; + for (i = 0, max = Math.max(...map.keys()); max !== 0; ++i, max >>= 1); + return i; +} + +function toInitialBigIntOffset(map: Map) { + let i: bigint; + let maximum: bigint; + for (i = 0n, maximum = max(...map.keys()); maximum !== 0n; ++i, maximum >>= 1n); + return i; +} + +function toArray(map: Map, maxOffset: N, bits: N): S[] { + const output: S[] = []; + + const [zeroValue, bitValue] = (typeof bits == 'bigint' ? [0n, 1n] : [0, 1]) as [N, N]; + for (let i = zeroValue; i <= maxOffset; ++i) { + const offset = (bitValue << i) as N; + if ((bits & offset) === zeroValue) continue; + + const value = map.get(offset); + if (value !== undefined) output.push(value); + } + + return output; +} + +export const permissionsFlags = toMap(Permissions); +export const permissionsOffset = toInitialBigIntOffset(permissionsFlags); +export function toPermissionsArray(bits: bigint) { + return toArray(permissionsFlags, permissionsOffset, bits); +} + +export const channelFlags = toMap(SystemChannelFlags); +export const channelOffset = toInitialOffset(channelFlags); +export function toChannelsArray(bits: number) { + return toArray(channelFlags, channelOffset, bits); +} diff --git a/src/lib/util/common/comparators.ts b/projects/bot/src/lib/util/common/comparators.ts similarity index 81% rename from src/lib/util/common/comparators.ts rename to projects/bot/src/lib/util/common/comparators.ts index e05e39341..7b6264c95 100644 --- a/src/lib/util/common/comparators.ts +++ b/projects/bot/src/lib/util/common/comparators.ts @@ -1,11 +1,3 @@ -export function asc(a: number | string | bigint, b: number | string | bigint): -1 | 0 | 1 { - return a < b ? -1 : a > b ? 1 : 0; -} - -export function desc(a: number | string | bigint, b: number | string | bigint): -1 | 0 | 1 { - return a > b ? -1 : a < b ? 1 : 0; -} - /** * Gets the maximum value. * @param values The values to compare. @@ -84,7 +76,7 @@ export function bidirectionalReplace(regex: RegExp, content: string, options: return results; } -export type BooleanFn = (...args: ArgumentTypes) => ReturnType; +export type BooleanFn = (...args: T) => R; export function andMix(...fns: readonly BooleanFn[]): BooleanFn { if (fns.length === 0) throw new Error('You must input at least one function.'); @@ -98,12 +90,10 @@ export function andMix(...fns: }; } -export function orMix( - ...fns: readonly BooleanFn[] -): BooleanFn { +export function orMix(...fns: readonly BooleanFn[]): BooleanFn { if (fns.length === 0) throw new Error('You must input at least one function.'); return (...args) => { - let ret!: ReturnType; + let ret!: R; for (const fn of fns) { if ((ret = fn(...args))) break; } diff --git a/src/lib/util/common/guards.ts b/projects/bot/src/lib/util/common/guards.ts similarity index 100% rename from src/lib/util/common/guards.ts rename to projects/bot/src/lib/util/common/guards.ts diff --git a/projects/bot/src/lib/util/common/index.ts b/projects/bot/src/lib/util/common/index.ts new file mode 100644 index 000000000..c4f876f72 --- /dev/null +++ b/projects/bot/src/lib/util/common/index.ts @@ -0,0 +1,5 @@ +export * from './comparators'; +export * from './guards'; +export * from './iterators'; +export * from './promises'; +export * from './times'; diff --git a/projects/bot/src/lib/util/common/iterators.ts b/projects/bot/src/lib/util/common/iterators.ts new file mode 100644 index 000000000..b1424ec1e --- /dev/null +++ b/projects/bot/src/lib/util/common/iterators.ts @@ -0,0 +1,51 @@ +export function iteratorRange(iterator: IterableIterator, position: number, offset: number) { + let result: IteratorResult | null = null; + while (position-- > 0) { + result = iterator.next(); + if (result.done) return []; + } + + const results: T[] = []; + while (offset-- > 0) { + result = iterator.next(); + if (result.done) return results; + results.push(result.value); + } + return results; +} + +export function* map(iterator: IterableIterator, cb: (value: T) => R): IterableIterator { + let result: IteratorResult | null = null; + while (!(result = iterator.next()).done) { + yield cb(result.value); + } +} + +export function skip(iterator: IterableIterator, times: number): IterableIterator { + if (times <= 0) return iterator; + + let result: IteratorResult | null = null; + let i = 0; + + do { + result = iterator.next(); + ++i; + } while (i < times && !result.done); + + return iterator; +} + +export function* filter(iterator: IterableIterator, cb: (value: T) => boolean): IterableIterator { + let result: IteratorResult | null = null; + while (!(result = iterator.next()).done) { + if (cb(result.value)) yield result.value; + } +} + +export function* take(iterator: IterableIterator, amount: number): IterableIterator { + let i = 0; + let result: IteratorResult | null = null; + while (i++ < amount && !(result = iterator.next()).done) { + yield result.value; + } +} diff --git a/src/lib/util/common/promises.ts b/projects/bot/src/lib/util/common/promises.ts similarity index 63% rename from src/lib/util/common/promises.ts rename to projects/bot/src/lib/util/common/promises.ts index c9150b27c..a9967edc9 100644 --- a/src/lib/util/common/promises.ts +++ b/projects/bot/src/lib/util/common/promises.ts @@ -1,21 +1,13 @@ -import { Result, container, err, ok } from '@sapphire/framework'; -import { isThenable, type Awaitable } from '@sapphire/utilities'; -import { DiscordAPIError, type RESTJSONErrorCodes } from 'discord.js'; +import { container } from '@sapphire/framework'; +import { Awaitable, isThenable } from '@sapphire/utilities'; +import type { RESTJSONErrorCodes } from 'discord-api-types/v9'; +import { DiscordAPIError } from 'discord.js'; export async function resolveOnErrorCodes(promise: Promise, ...codes: readonly RESTJSONErrorCodes[]) { try { return await promise; } catch (error) { - if (error instanceof DiscordAPIError && codes.includes(error.code as RESTJSONErrorCodes)) return null; - throw error; - } -} - -export async function toErrorCodeResult(promise: Promise): Promise> { - try { - return ok(await promise); - } catch (error) { - if (error instanceof DiscordAPIError) return err(error.code as RESTJSONErrorCodes); + if (error instanceof DiscordAPIError && codes.includes(error.code)) return null; throw error; } } diff --git a/src/lib/util/common/times.ts b/projects/bot/src/lib/util/common/times.ts similarity index 75% rename from src/lib/util/common/times.ts rename to projects/bot/src/lib/util/common/times.ts index f455d9a7c..84f9ea6de 100644 --- a/src/lib/util/common/times.ts +++ b/projects/bot/src/lib/util/common/times.ts @@ -19,33 +19,6 @@ seconds.fromMilliseconds = (milliseconds: number): number => { return roundNumber(milliseconds / Time.Second); }; -/** - * Converts a number of minutes to seconds. - * @param minutes The amount of minutes - * @returns The amount of seconds `minutes` equals to. - */ -seconds.fromMinutes = (minutes: number): number => { - return minutes * 60; -}; - -/** - * Converts a number of hours to seconds. - * @param hours The amount of hours - * @returns The amount of seconds `hours` equals to. - */ -seconds.fromHours = (hours: number): number => { - return hours * 60 * 60; -}; - -/** - * Converts a number of days to seconds. - * @param days The amount of days - * @returns The amount of seconds `days` equals to. - */ -seconds.fromDays = (days: number): number => { - return days * 60 * 60 * 24; -}; - /** * Converts a number of minutes to milliseconds. * @param minutes The amount of minutes diff --git a/projects/bot/src/lib/util/constants.ts b/projects/bot/src/lib/util/constants.ts new file mode 100644 index 000000000..f7963644d --- /dev/null +++ b/projects/bot/src/lib/util/constants.ts @@ -0,0 +1,100 @@ +import { getRootData } from '@sapphire/pieces'; +import { join } from 'node:path'; + +export const mainFolder = getRootData().root; +export const rootFolder = join(mainFolder, '..'); +export const assetsFolder = join(rootFolder, 'assets'); +export const socialFolder = join(assetsFolder, 'images', 'social'); +export const cdnFolder = process.env.NODE_ENV === 'production' ? join('/var', 'www', 'skyra.pw', 'cdn') : join(assetsFolder, 'public'); + +export const ZeroWidthSpace = '\u200B'; +export const LongWidthSpace = '\u3000'; + +export const enum Emojis { + ArrowB = '<:ArrowB:694594285269680179>', + ArrowBL = '<:ArrowBL:694594285118685259>', + ArrowBR = '<:ArrowBR:694594285445578792>', + ArrowL = '<:ArrowL:694594285521207436>', + ArrowR = '<:ArrowR:694594285466812486>', + ArrowT = '<:ArrowT:694594285487652954>', + ArrowTL = '<:ArrowTL:694594285625933854>', + ArrowTR = '<:ArrowTR:694594285412155393>', + BoostLevel1 = '<:boostlvl1:764841388243681322>', + BoostLevel2 = '<:boostlvl2:764841388449071134>', + BoostLevel3 = '<:boostlvl3:764841388029902891>', + BoostLevel4 = '<:boostlvl4:764841388336349225>', + BoostLevel5 = '<:boostlvl5:764841388449202198>', + BoostLevel6 = '<:boostlvl6:764841388445532200>', + BoostLevel7 = '<:boostlvl7:764841388150882305>', + BoostLevel8 = '<:boostlvl8:764841388462178344>', + BoostLevel9 = '<:boostlvl9:764841388470698014>', + Bot = '<:bot:764788923851079702>', + Frame = '<:frame:764845055356698644>', + GreenTick = '<:greenTick:637706251253317669>', + GreenTickSerialized = 's637706251253317669', + Loading = '', + RedCross = '<:redCross:637706251257511973>', + Shiny = '<:shiny:612364146792726539>', + Star = '<:Star:736337719982030910>', + StarEmpty = '<:StarEmpty:736337232738254849>', + StarHalf = '<:StarHalf:736337529900499034>', + /** This is the default Twemoji, uploaded as a custom emoji because iOS and Android do not render the emoji properly */ + MaleSignEmoji = '<:2642:845772713770614874>', + /** This is the default Twemoji, uploaded as a custom emoji because iOS and Android do not render the emoji properly */ + FemaleSignEmoji = '<:2640:845772713729720320>' +} + +export const enum BrandingColors { + Primary = 0x1e88e5, + Secondary = 0xff9d01 +} + +// eslint-disable-next-line @typescript-eslint/ban-types +export type O = object; + +export const enum LanguageFormatters { + AndList = 'andList', + Duration = 'duration', + ExplicitContentFilter = 'explicitContentFilter', + MessageNotifications = 'messageNotifications', + Number = 'number', + NumberCompact = 'numberCompact', + HumanLevels = 'humanLevels', + InlineCodeblock = 'inlineCodeBlock', + CodeBlock = 'codeBlock', + JsCodeBlock = 'jsCodeBlock', + Ordinal = 'ordinal', + OrList = 'orList', + Permissions = 'permissions', + Random = 'random', + DateTime = 'dateTime', + ToTitleCase = 'toTitleCase', + PermissionsAndList = 'permissionsAndList' +} + +export const enum Colors { + White = 0xe7e7e8, + Amber = 0xffc107, + Amber300 = 0xffd54f, + Blue = 0x2196f3, + BlueGrey = 0x607d8b, + Brown = 0x795548, + Cyan = 0x00bcd4, + DeepOrange = 0xff5722, + DeepPurple = 0x673ab7, + Green = 0x4caf50, + Grey = 0x9e9e9e, + Indigo = 0x3f51b5, + LightBlue = 0x03a9f4, + LightGreen = 0x8bc34a, + Lime = 0xcddc39, + Lime300 = 0xdce775, + Orange = 0xff9800, + Pink = 0xe91e63, + Purple = 0x9c27b0, + Red = 0xf44336, + Red300 = 0xe57373, + Teal = 0x009688, + Yellow = 0xffeb3b, + Yellow300 = 0xfff176 +} diff --git a/src/lib/util/formatters.ts b/projects/bot/src/lib/util/formatters.ts similarity index 66% rename from src/lib/util/formatters.ts rename to projects/bot/src/lib/util/formatters.ts index 11c967adc..2bcfd1b80 100644 --- a/src/lib/util/formatters.ts +++ b/projects/bot/src/lib/util/formatters.ts @@ -1,8 +1,8 @@ import { LanguageKeys } from '#lib/i18n/languageKeys'; import type { GuildMessage } from '#lib/types'; -import { cleanMentions, getTag } from '#utils/util'; -import type { TFunction } from '@sapphire/plugin-i18next'; -import type { APIEmbedField, Attachment, Embed, EmbedAssetData, EmbedFooterData, Guild, User } from 'discord.js'; +import type { EmbedField, Guild, MessageAttachment, MessageEmbed, MessageEmbedFooter, MessageEmbedImage, User } from 'discord.js'; +import type { TFunction } from 'i18next'; +import { cleanMentions } from './util'; export function formatMessage(t: TFunction, message: GuildMessage): string { const header = formatHeader(t, message); @@ -20,12 +20,12 @@ function formatHeader(t: TFunction, message: GuildMessage): string { * This **cannot** make use of Discord's timestamp formatting as the result * of this function is placed inside of a codeblock. */ -export function formatTimestamp(t: TFunction, timestamp: number): string { - return `[${t(LanguageKeys.Globals.HumanDateTimeValue, { value: timestamp })}]`; +function formatTimestamp(t: TFunction, timestamp: number): string { + return `[${t(LanguageKeys.Globals.DateTimeValue, { value: timestamp })}]`; } function formatAuthor(author: User): string { - return `${getTag(author)}${author.bot ? ' [BOT]' : ''}`; + return `${author.tag}${author.bot ? ' [BOT]' : ''}`; } function formatContents(message: GuildMessage): string { @@ -43,11 +43,30 @@ function formatContent(guild: Guild, content: string): string { .join('\n'); } -export function formatAttachment(attachment: Attachment): string { +export function formatAttachment(attachment: MessageAttachment): string { return `📂 [${attachment.name}: ${attachment.url}]`; } -function formatEmbed(guild: Guild, embed: Embed): string { +function formatEmbed(guild: Guild, embed: MessageEmbed): string { + switch (embed.type) { + case 'video': + return formatEmbedVideo(embed); + case 'image': + return formatEmbedImage(embed); + default: + return formatEmbedRich(guild, embed); + } +} + +function formatEmbedVideo(embed: MessageEmbed): string { + return `📹 [${embed.url}]${embed.provider ? ` (${embed.provider.name}).` : ''}`; +} + +function formatEmbedImage(embed: MessageEmbed): string { + return `🖼️ [${embed.url}]${embed.provider ? ` (${embed.provider.name}).` : ''}`; +} + +function formatEmbedRich(guild: Guild, embed: MessageEmbed): string { if (embed.provider === null) { const output: string[] = []; if (embed.title) output.push(formatEmbedRichTitle(embed.title)); @@ -71,7 +90,7 @@ function formatEmbedRichUrl(url: string): string { return `> 📎 ${url}`; } -function formatEmbedRichAuthor(author: Exclude): string { +function formatEmbedRichAuthor(author: Exclude): string { return `> 👤 ${author.iconURL ? `[${author.iconURL}] ` : ''}${author.name || '-'}${author.url ? ` <${author.url}>` : ''}`; } @@ -82,21 +101,21 @@ function formatEmbedRichDescription(guild: Guild, description: string): string { .join('\n'); } -function formatEmbedRichField(guild: Guild, field: APIEmbedField): string { +function formatEmbedRichField(guild: Guild, field: EmbedField): string { return `> #> ${field.name}\n${cleanMentions(guild, field.value) .split('\n') .map((line) => `> > ${line}`) .join('\n')}`; } -function formatEmbedRichImage(image: EmbedAssetData): string { +function formatEmbedRichImage(image: MessageEmbedImage): string { return `>🖼️ [${image.url}]`; } -function formatEmbedRichFooter(footer: EmbedFooterData): string { +function formatEmbedRichFooter(footer: MessageEmbedFooter): string { return `>_ ${footer.iconURL ? `[${footer.iconURL}]${footer.text ? ' - ' : ''}` : ''}${footer.text ?? ''}`; } -function formatEmbedRichProvider(embed: Embed): string { +function formatEmbedRichProvider(embed: MessageEmbed): string { return `🔖 [${embed.url}]${embed.provider ? ` (${embed.provider.name}).` : ''}`; } diff --git a/projects/bot/src/lib/util/functions/booleans.ts b/projects/bot/src/lib/util/functions/booleans.ts new file mode 100644 index 000000000..008210364 --- /dev/null +++ b/projects/bot/src/lib/util/functions/booleans.ts @@ -0,0 +1,7 @@ +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { resolveT, TResolvable } from '#lib/i18n/translate'; + +export function formatBoolean(t: TResolvable, value: boolean): string { + const tFunction = resolveT(t); + return tFunction(value ? LanguageKeys.Globals.Yes : LanguageKeys.Globals.No); +} diff --git a/src/lib/util/functions/emojis.ts b/projects/bot/src/lib/util/functions/emojis.ts similarity index 59% rename from src/lib/util/functions/emojis.ts rename to projects/bot/src/lib/util/functions/emojis.ts index 05e0c41a1..e4535a38e 100644 --- a/src/lib/util/functions/emojis.ts +++ b/projects/bot/src/lib/util/functions/emojis.ts @@ -1,41 +1,7 @@ import { formatEmoji } from '@discordjs/builders'; -import { FormattedCustomEmojiWithGroups } from '@sapphire/discord-utilities'; -import { container } from '@sapphire/framework'; +import { FormattedCustomEmojiWithGroups, TwemojiRegex } from '@sapphire/discord-utilities'; import { isNullish } from '@sapphire/utilities'; -// Based on the identifiers at https://cdn.jsdelivr.net/gh/twitter/twemoji/assets/72x72/ -export type EncodedTwemoji = `${1 | 2 | 3}${string}` | 'a9' | 'ae' | 'e50a'; - -// Hacky workaround for codes Discord and Windows use that don't exist on Twemoji's CDN. -const TwemojiExceptions = { - '\u2764\uFE0F': '2764' // (❤️) -} as Record; - -/** - * Transforms the given emoji to a code point string that can be used for the CDN. - * @param emoji The emoji to encode - * @example - * ```typescript - * twemoji('😃'); - * // → '1f603' - * ``` - */ -export function getEncodedTwemoji(emoji: string): EncodedTwemoji { - return TwemojiExceptions[emoji] ?? [...emoji].map((point) => point.codePointAt(0)!.toString(16)).join('-'); -} - -/** - * Gets the CDN URL for a Twemoji. - * @param emoji The encoded Twemoji to use. - */ -export function getTwemojiUrl(emoji: E) { - return `https://cdn.jsdelivr.net/gh/twitter/twemoji/assets/72x72/${emoji}.png` as const; -} - -export function getCustomEmojiUrl(id: string, animated: boolean) { - return container.client.rest.cdn.emoji(id, { extension: animated ? 'gif' : 'png', size: 64 }); -} - interface EmojiObjectPartial { name: string | null; id: string | null; @@ -48,34 +14,13 @@ export interface EmojiObject extends EmojiObjectPartial { export type SerializedEmoji = string & { __TYPE__: 'SerializedEmoji' }; const customEmojiRegExp = /^[as]\d{17,19}$/; -const allowedTwemojiRanges: ReadonlyArray<[number, number]> = [ - [0x1f000, 0x1ffff], // Most emoji blocks including symbols & pictographs - [0x2600, 0x27bf], // Misc symbols / dingbats - [0x2300, 0x23ff] // Misc technical -]; - -function matchesTwemoji(emoji: string) { - const codepoints = [...emoji]; - - if (codepoints.length !== 1) return false; - - const code = emoji.codePointAt(0); - if (code === undefined) return false; - - return allowedTwemojiRanges.some(([start, end]) => code >= start && code <= end); -} /** * Checks whether or not the emoji is a valid twemoji. * @param emoji The emoji to validate. */ export function isValidTwemoji(emoji: string) { - if (emoji.includes('%')) return false; - - if (customEmojiRegExp.test(emoji)) return false; - if (FormattedCustomEmojiWithGroups.test(emoji)) return false; - - return matchesTwemoji(emoji); + return TwemojiRegex.test(emoji); } export function isValidCustomEmoji(emoji: string) { @@ -88,13 +33,7 @@ export function isValidCustomEmoji(emoji: string) { * @param emoji The emoji to validate. */ export function isValidSerializedTwemoji(emoji: string): emoji is SerializedEmoji { - if (!emoji.includes('%')) return false; - - try { - return matchesTwemoji(decodeURIComponent(emoji)); - } catch { - return false; - } + return isValidTwemoji(decodeURIComponent(emoji)); } /** @@ -137,7 +76,7 @@ export function getEmojiTextFormat(emoji: SerializedEmoji): string { * Formats an emoji in the format that we can use to for reactions on Discord messages. */ export function getEmojiReactionFormat(emoji: SerializedEmoji): string { - return isSerializedTwemoji(emoji) ? decodeURIComponent(emoji) : `emoji:${emoji.slice(1)}`; + return isSerializedTwemoji(emoji) ? emoji : `emoji:${emoji.slice(1)}`; } /** @@ -176,5 +115,12 @@ export function getEmojiObject(emoji: string): EmojiObject | null { export function resolveEmojiId(emoji: EmojiObject | SerializedEmoji): string { if (isNullish(emoji)) return ''; - return typeof emoji === 'string' ? getEmojiId(emoji) : (emoji.id ?? encodeURIComponent(emoji.name!)); + return typeof emoji === 'string' ? getEmojiId(emoji) : emoji.id ?? encodeURIComponent(emoji.name!); +} + +/** + * Compared whether the identifiers for both emojis are the same, ignoring name and animated. + */ +export function areEmojisEqual(a: EmojiObject | SerializedEmoji, b: EmojiObject | SerializedEmoji) { + return resolveEmojiId(a) === resolveEmojiId(b); } diff --git a/src/lib/util/functions/guild.ts b/projects/bot/src/lib/util/functions/guild.ts similarity index 66% rename from src/lib/util/functions/guild.ts rename to projects/bot/src/lib/util/functions/guild.ts index ef65ca2a3..42b2c9117 100644 --- a/src/lib/util/functions/guild.ts +++ b/projects/bot/src/lib/util/functions/guild.ts @@ -1,16 +1,15 @@ -import { LoggerManager, ModerationManager, StickyRoleManager } from '#lib/moderation/managers'; -import { resolveGuild } from '#utils/common'; +import { ModerationManager, StickyRoleManager } from '#lib/moderation/managers'; import { GuildSecurity } from '#utils/Security/GuildSecurity'; +import { container } from '@sapphire/framework'; import type { Guild, GuildResolvable } from 'discord.js'; interface GuildUtilities { - readonly logger: LoggerManager; readonly moderation: ModerationManager; readonly security: GuildSecurity; readonly stickyRoles: StickyRoleManager; } -export const cache = new WeakMap(); +const cache = new WeakMap(); export function getGuildUtilities(resolvable: GuildResolvable): GuildUtilities { const guild = resolveGuild(resolvable); @@ -18,7 +17,6 @@ export function getGuildUtilities(resolvable: GuildResolvable): GuildUtilities { if (previous !== undefined) return previous; const entry: GuildUtilities = { - logger: new LoggerManager(guild), moderation: new ModerationManager(guild), security: new GuildSecurity(guild), stickyRoles: new StickyRoleManager(guild) @@ -28,7 +26,10 @@ export function getGuildUtilities(resolvable: GuildResolvable): GuildUtilities { return entry; } -export const getLogger = getProperty('logger'); +export function removeGuildUtilities(resolvable: GuildResolvable): boolean { + return cache.delete(resolveGuild(resolvable)); +} + export const getModeration = getProperty('moderation'); export const getSecurity = getProperty('security'); export const getStickyRoles = getProperty('stickyRoles'); @@ -36,3 +37,10 @@ export const getStickyRoles = getProperty('stickyRoles'); function getProperty(property: K) { return (resolvable: GuildResolvable): GuildUtilities[K] => getGuildUtilities(resolvable)[property]; } + +function resolveGuild(resolvable: GuildResolvable): Guild { + const guild = container.client.guilds.resolve(resolvable); + if (guild === null) throw new TypeError(`${resolvable} resolved to null.`); + + return guild; +} diff --git a/projects/bot/src/lib/util/functions/index.ts b/projects/bot/src/lib/util/functions/index.ts new file mode 100644 index 000000000..28bab5b03 --- /dev/null +++ b/projects/bot/src/lib/util/functions/index.ts @@ -0,0 +1,5 @@ +export * from './booleans'; +export * from './emojis'; +export * from './guild'; +export * from './numbers'; +export * from './permissions'; diff --git a/src/lib/util/functions/numbers.ts b/projects/bot/src/lib/util/functions/numbers.ts similarity index 74% rename from src/lib/util/functions/numbers.ts rename to projects/bot/src/lib/util/functions/numbers.ts index 77021ab6f..9d1f5bc59 100644 --- a/src/lib/util/functions/numbers.ts +++ b/projects/bot/src/lib/util/functions/numbers.ts @@ -1,5 +1,5 @@ import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { resolveT, type TResolvable } from '#lib/i18n/translate'; +import { resolveT, TResolvable } from '#lib/i18n/translate'; export function formatNumber(t: TResolvable, value: number): string { return resolveT(t)(LanguageKeys.Globals.NumberValue, { value }); diff --git a/projects/bot/src/lib/util/functions/permissions.ts b/projects/bot/src/lib/util/functions/permissions.ts new file mode 100644 index 000000000..34c9abca8 --- /dev/null +++ b/projects/bot/src/lib/util/functions/permissions.ts @@ -0,0 +1,32 @@ +import type { GuildEntity } from '#lib/database/entities'; +import { GuildSettings } from '#lib/database/keys'; +import { readSettings } from '#lib/database/settings'; +import { OWNERS } from '#root/config'; +import { hasAtLeastOneKeyInMap } from '@sapphire/utilities'; +import { GuildMember, Permissions } from 'discord.js'; + +export function isModerator(member: GuildMember) { + return isGuildOwner(member) || readSettings(member, (settings) => checkModerator(member, settings) || checkAdministrator(member, settings)); +} + +export function isAdmin(member: GuildMember) { + return isGuildOwner(member) || readSettings(member, (settings) => checkAdministrator(member, settings)); +} + +export function isGuildOwner(member: GuildMember) { + return member.id === member.guild.ownerId; +} + +export function isOwner(member: GuildMember) { + return OWNERS.includes(member.id); +} + +function checkModerator(member: GuildMember, settings: GuildEntity) { + const roles = settings[GuildSettings.Roles.Moderator]; + return roles.length === 0 ? member.permissions.has(Permissions.FLAGS.BAN_MEMBERS) : hasAtLeastOneKeyInMap(member.roles.cache, roles); +} + +function checkAdministrator(member: GuildMember, settings: GuildEntity) { + const roles = settings[GuildSettings.Roles.Admin]; + return roles.length === 0 ? member.permissions.has(Permissions.FLAGS.MANAGE_GUILD) : hasAtLeastOneKeyInMap(member.roles.cache, roles); +} diff --git a/projects/bot/src/lib/util/moderationConstants.ts b/projects/bot/src/lib/util/moderationConstants.ts new file mode 100644 index 000000000..e97649392 --- /dev/null +++ b/projects/bot/src/lib/util/moderationConstants.ts @@ -0,0 +1,192 @@ +import { Colors } from '#utils/constants'; + +/* eslint-disable no-multi-spaces */ +export const enum TypeVariation { + Ban = 0b00000000, + Kick = 0b00000001, + Mute = 0b00000010, + Prune = 0b00000011, + SoftBan = 0b00000100, + VoiceKick = 0b00000101, + VoiceMute = 0b00000110, + Warning = 0b00000111, + RestrictedReaction = 0b00001000, + RestrictedEmbed = 0b00001001, + RestrictedAttachment = 0b00001010, + RestrictedVoice = 0b00001011, + SetNickname = 0b00001100, + AddRole = 0b00001101, + RemoveRole = 0b00001110, + RestrictedEmoji = 0b00001111 +} + +export const enum TypeMetadata { + Appeal = 0b00010000, + Temporary = 0b00100000, + Fast = 0b01000000, + Invalidated = 0b10000000 +} + +export const enum TypeBits { + Variation = 0b00001111, + Metadata = 0b11110000 +} + +export const enum TypeCodes { + Warning = TypeVariation.Warning, + Mute = TypeVariation.Mute, + Kick = TypeVariation.Kick, + SoftBan = TypeVariation.SoftBan, + Ban = TypeVariation.Ban, + VoiceMute = TypeVariation.VoiceMute, + VoiceKick = TypeVariation.VoiceKick, + RestrictionAttachment = TypeVariation.RestrictedAttachment, + RestrictionReaction = TypeVariation.RestrictedReaction, + RestrictionEmbed = TypeVariation.RestrictedEmbed, + RestrictionEmoji = TypeVariation.RestrictedEmoji, + RestrictionVoice = TypeVariation.RestrictedVoice, + UnWarn = TypeVariation.Warning | TypeMetadata.Appeal, + UnMute = TypeVariation.Mute | TypeMetadata.Appeal, + UnBan = TypeVariation.Ban | TypeMetadata.Appeal, + UnVoiceMute = TypeVariation.VoiceMute | TypeMetadata.Appeal, + UnRestrictionReaction = TypeVariation.RestrictedReaction | TypeMetadata.Appeal, + UnRestrictionEmbed = TypeVariation.RestrictedEmbed | TypeMetadata.Appeal, + UnRestrictionEmoji = TypeVariation.RestrictedEmoji | TypeMetadata.Appeal, + UnRestrictionAttachment = TypeVariation.RestrictedAttachment | TypeMetadata.Appeal, + UnRestrictionVoice = TypeVariation.RestrictedVoice | TypeMetadata.Appeal, + UnSetNickname = TypeVariation.SetNickname | TypeMetadata.Appeal, + UnAddRole = TypeVariation.AddRole | TypeMetadata.Appeal, + UnRemoveRole = TypeVariation.RemoveRole | TypeMetadata.Appeal, + TemporaryWarning = TypeVariation.Warning | TypeMetadata.Temporary, + TemporaryMute = TypeVariation.Mute | TypeMetadata.Temporary, + TemporaryBan = TypeVariation.Ban | TypeMetadata.Temporary, + TemporaryVoiceMute = TypeVariation.VoiceMute | TypeMetadata.Temporary, + TemporaryRestrictionAttachment = TypeVariation.RestrictedAttachment | TypeMetadata.Temporary, + TemporaryRestrictionReaction = TypeVariation.RestrictedReaction | TypeMetadata.Temporary, + TemporaryRestrictionEmbed = TypeVariation.RestrictedEmbed | TypeMetadata.Temporary, + TemporaryRestrictionEmoji = TypeVariation.RestrictedEmoji | TypeMetadata.Temporary, + TemporaryRestrictionVoice = TypeVariation.RestrictedVoice | TypeMetadata.Temporary, + TemporarySetNickname = TypeVariation.SetNickname | TypeMetadata.Temporary, + TemporaryAddRole = TypeVariation.AddRole | TypeMetadata.Temporary, + TemporaryRemoveRole = TypeVariation.RemoveRole | TypeMetadata.Temporary, + FastTemporaryWarning = TypeVariation.Warning | TypeMetadata.Temporary | TypeMetadata.Fast, + FastTemporaryMute = TypeVariation.Mute | TypeMetadata.Temporary | TypeMetadata.Fast, + FastTemporaryBan = TypeVariation.Ban | TypeMetadata.Temporary | TypeMetadata.Fast, + FastTemporaryVoiceMute = TypeVariation.VoiceMute | TypeMetadata.Temporary | TypeMetadata.Fast, + FastTemporaryRestrictionAttachment = TypeVariation.RestrictedAttachment | TypeMetadata.Temporary | TypeMetadata.Fast, + FastTemporaryRestrictionReaction = TypeVariation.RestrictedReaction | TypeMetadata.Temporary | TypeMetadata.Fast, + FastTemporaryRestrictionEmbed = TypeVariation.RestrictedEmbed | TypeMetadata.Temporary | TypeMetadata.Fast, + FastTemporaryRestrictionEmoji = TypeVariation.RestrictedEmoji | TypeMetadata.Temporary | TypeMetadata.Fast, + FastTemporaryRestrictionVoice = TypeVariation.RestrictedVoice | TypeMetadata.Temporary | TypeMetadata.Fast, + FastTemporarySetNickname = TypeVariation.SetNickname | TypeMetadata.Temporary | TypeMetadata.Fast, + FastTemporaryAddRole = TypeVariation.AddRole | TypeMetadata.Temporary | TypeMetadata.Fast, + FastTemporaryRemoveRole = TypeVariation.RemoveRole | TypeMetadata.Temporary | TypeMetadata.Fast, + Prune = TypeVariation.Prune, + SetNickname = TypeVariation.SetNickname, + AddRole = TypeVariation.AddRole, + RemoveRole = TypeVariation.RemoveRole +} +/* eslint-enable no-multi-spaces */ + +export const metadata = new Map([ + [TypeCodes.Warning, { color: Colors.Yellow, title: 'Warning' }], + [TypeCodes.Mute, { color: Colors.Amber, title: 'Mute' }], + [TypeCodes.Kick, { color: Colors.Orange, title: 'Kick' }], + [TypeCodes.SoftBan, { color: Colors.DeepOrange, title: 'SoftBan' }], + [TypeCodes.Ban, { color: Colors.Red, title: 'Ban' }], + [TypeCodes.VoiceMute, { color: Colors.Amber, title: 'Voice Mute' }], + [TypeCodes.VoiceKick, { color: Colors.Orange, title: 'Voice Kick' }], + [TypeCodes.RestrictionReaction, { color: Colors.Lime, title: 'Reaction Restriction' }], + [TypeCodes.RestrictionEmbed, { color: Colors.Lime, title: 'Embed Restriction' }], + [TypeCodes.RestrictionEmoji, { color: Colors.Lime, title: 'Emoji Restriction' }], + [TypeCodes.RestrictionAttachment, { color: Colors.Lime, title: 'Attachment Restriction' }], + [TypeCodes.RestrictionVoice, { color: Colors.Lime, title: 'Voice Restriction' }], + [TypeCodes.UnWarn, { color: Colors.LightBlue, title: 'Reverted Warning' }], + [TypeCodes.UnMute, { color: Colors.LightBlue, title: 'Reverted Mute' }], + [TypeCodes.UnBan, { color: Colors.LightBlue, title: 'Reverted Ban' }], + [TypeCodes.UnVoiceMute, { color: Colors.LightBlue, title: 'Reverted Voice Mute' }], + [TypeCodes.UnRestrictionReaction, { color: Colors.LightBlue, title: 'Reverted Reaction Restriction' }], + [TypeCodes.UnRestrictionEmbed, { color: Colors.LightBlue, title: 'Reverted Embed Restriction' }], + [TypeCodes.UnRestrictionEmoji, { color: Colors.LightBlue, title: 'Reverted Emoji Restriction' }], + [TypeCodes.UnRestrictionAttachment, { color: Colors.LightBlue, title: 'Reverted Attachment Restriction' }], + [TypeCodes.UnRestrictionVoice, { color: Colors.LightBlue, title: 'Reverted Voice Restriction' }], + [TypeCodes.UnSetNickname, { color: Colors.LightBlue, title: 'Reverted Set Nickname' }], + [TypeCodes.UnAddRole, { color: Colors.LightBlue, title: 'Reverted Add Role' }], + [TypeCodes.UnRemoveRole, { color: Colors.LightBlue, title: 'Reverted Remove Role' }], + [TypeCodes.TemporaryWarning, { color: Colors.Yellow300, title: 'Temporary Warning' }], + [TypeCodes.TemporaryMute, { color: Colors.Amber300, title: 'Temporary Mute' }], + [TypeCodes.TemporaryBan, { color: Colors.Red300, title: 'Temporary Ban' }], + [TypeCodes.TemporaryVoiceMute, { color: Colors.Amber300, title: 'Temporary Voice Mute' }], + [TypeCodes.TemporaryRestrictionReaction, { color: Colors.Lime300, title: 'Temporary Reaction Restriction' }], + [TypeCodes.TemporaryRestrictionEmbed, { color: Colors.Lime300, title: 'Temporary Embed Restriction' }], + [TypeCodes.TemporaryRestrictionEmoji, { color: Colors.Lime300, title: 'Temporary Emoji Restriction' }], + [TypeCodes.TemporaryRestrictionAttachment, { color: Colors.Lime300, title: 'Temporary Attachment Restriction' }], + [TypeCodes.TemporaryRestrictionVoice, { color: Colors.Lime300, title: 'Temporary Voice Restriction' }], + [TypeCodes.TemporarySetNickname, { color: Colors.Lime300, title: 'Temporary Set Nickname' }], + [TypeCodes.TemporaryAddRole, { color: Colors.Lime300, title: 'Temporarily Added Role' }], + [TypeCodes.TemporaryRemoveRole, { color: Colors.Lime300, title: 'Temporarily Removed Role' }], + [TypeCodes.FastTemporaryWarning, { color: Colors.Yellow300, title: 'Temporary Warning' }], + [TypeCodes.FastTemporaryMute, { color: Colors.Amber300, title: 'Temporary Mute' }], + [TypeCodes.FastTemporaryBan, { color: Colors.Red300, title: 'Temporary Ban' }], + [TypeCodes.FastTemporaryVoiceMute, { color: Colors.Amber300, title: 'Temporary Voice Mute' }], + [TypeCodes.FastTemporaryRestrictionReaction, { color: Colors.Lime300, title: 'Temporary Reaction Restriction' }], + [TypeCodes.FastTemporaryRestrictionEmbed, { color: Colors.Lime300, title: 'Temporary Embed Restriction' }], + [TypeCodes.FastTemporaryRestrictionEmoji, { color: Colors.Lime300, title: 'Temporary Emoji Restriction' }], + [TypeCodes.FastTemporaryRestrictionAttachment, { color: Colors.Lime300, title: 'Temporary Attachment Restriction' }], + [TypeCodes.FastTemporaryRestrictionVoice, { color: Colors.Lime300, title: 'Temporary Voice Restriction' }], + [TypeCodes.FastTemporarySetNickname, { color: Colors.Lime300, title: 'Temporary Set Nickname' }], + [TypeCodes.FastTemporaryAddRole, { color: Colors.Lime300, title: 'Temporarily Added Role' }], + [TypeCodes.FastTemporaryRemoveRole, { color: Colors.Lime300, title: 'Temporarily Removed Role' }], + [TypeCodes.Prune, { color: Colors.Brown, title: 'Prune' }], + [TypeCodes.SetNickname, { color: Colors.Lime, title: 'Set Nickname' }], + [TypeCodes.AddRole, { color: Colors.Lime, title: 'Added Role' }], + [TypeCodes.RemoveRole, { color: Colors.Lime, title: 'Removed Role' }] +]) as ReadonlyMap; + +export const enum TypeVariationAppealNames { + Warning = 'moderationEndWarning', + Mute = 'moderationEndMute', + Ban = 'moderationEndBan', + VoiceMute = 'moderationEndVoiceMute', + RestrictedReaction = 'moderationEndRestrictionReaction', + RestrictedEmbed = 'moderationEndRestrictionEmbed', + RestrictedEmoji = 'moderationEndRestrictionEmoji', + RestrictedAttachment = 'moderationEndRestrictionAttachment', + RestrictedVoice = 'moderationEndRestrictionVoice', + SetNickname = 'moderationEndSetNickname', + AddRole = 'moderationEndAddRole', + RemoveRole = 'moderationEndRemoveRole' +} + +export const enum SchemaKeys { + Case = 'caseID', + CreatedAt = 'createdAt', + Duration = 'duration', + ExtraData = 'extraData', + Guild = 'guildID', + Moderator = 'moderatorID', + Reason = 'reason', + ImageURL = 'imageURL', + Type = 'type', + User = 'userID' +} + +export interface ModerationTypeAssets { + color: number; + title: string; +} + +export interface ModerationManagerDescriptionData { + type: string; + userName: string; + userDiscriminator: string; + userId: string; + reason: string | null; + prefix: string; + caseId: number; + formattedDuration: string; +} + +export interface Unlock { + unlock(): void; +} diff --git a/projects/bot/src/lib/util/util.ts b/projects/bot/src/lib/util/util.ts new file mode 100644 index 000000000..62d2a7945 --- /dev/null +++ b/projects/bot/src/lib/util/util.ts @@ -0,0 +1,216 @@ +import type { ImageURLOptions } from '@discordjs/rest'; +import { DiscordSnowflake } from '@sapphire/snowflake'; +import { parseURL } from '@sapphire/utilities'; +import { container } from '@wolfstar/http-framework'; +import type { APIMessage, APIUser } from 'discord-api-types/v10'; +import type { Guild } from 'wolfstar-shared'; +import { ZeroWidthSpace } from './constants'; + +/** + * Image extensions: + * - bmp + * - jpg + * - jpeg + * - png + * - gif + * - webp + */ +export const IMAGE_EXTENSION = /\.(bmp|jpe?g|png|gif|webp)$/i; + +/** + * Media extensions + * - ...Image extensions + * - ...Audio extensions + * - ...Video extensions + */ +export const MEDIA_EXTENSION = /\.(bmp|jpe?g|png|gifv?|web[pm]|wav|mp[34]|ogg)$/i; + +export function radians(degrees: number) { + return (degrees * Math.PI) / 180; +} + +export function snowflakeAge(snowflake: string | bigint) { + return Math.max(Date.now() - DiscordSnowflake.timestampFrom(snowflake), 0); +} + +export function twemoji(emoji: string) { + const r: string[] = []; + let c = 0; + let p = 0; + let i = 0; + + while (i < emoji.length) { + c = emoji.charCodeAt(i++); + if (p) { + r.push((0x10000 + ((p - 0xd800) << 10) + (c - 0xdc00)).toString(16)); + p = 0; + } else if (c >= 0xd800 && c <= 0xdbff) { + p = c; + } else { + r.push(c.toString(16)); + } + } + return r.join('-'); +} + +/** + * Get the content from a message. + * @param message The Message instance to get the content from + */ +export function getContent(message: APIMessage): string | null { + if (message.content) return message.content; + for (const embed of message.embeds) { + if (embed.description) return embed.description; + if (embed.fields?.length) return embed.fields[0].value; + } + return null; +} + +/** + * Gets all the contents from a message. + * @param message The Message instance to get all contents from + */ +export function getAllContent(message: APIMessage): string { + const output: string[] = []; + if (message.content) output.push(message.content); + for (const embed of message.embeds) { + if (embed.author?.name) output.push(embed.author.name); + if (embed.title) output.push(embed.title); + if (embed.description) output.push(embed.description); + for (const field of embed.fields ?? []) output.push(`${field.name}\n${field.value}`); + if (embed.footer?.text) output.push(embed.footer.text); + } + + return output.join('\n'); +} + +export interface ImageAttachment { + url: string; + proxyURL: string; + height: number; + width: number; +} + +/** + * Get a image attachment from a message. + * @param message The Message instance to get the image url from + */ +export function getAttachment(message: APIMessage): ImageAttachment | null { + if (message.attachments.length) { + const attachment = message.attachments.find((att) => IMAGE_EXTENSION.test(att.url)); + if (attachment) { + return { + url: attachment.url, + proxyURL: attachment.proxy_url, + height: attachment.height!, + width: attachment.width! + }; + } + } + + for (const embed of message.embeds) { + if (embed.image) { + return { + url: embed.image.url, + proxyURL: embed.image.proxy_url!, + height: embed.image.height!, + width: embed.image.width! + }; + } + + if (embed.thumbnail) { + return { + url: embed.thumbnail.url, + proxyURL: embed.thumbnail.proxy_url!, + height: embed.thumbnail.height!, + width: embed.thumbnail.width! + }; + } + } + + return null; +} + +/** + * Get the image url from a message. + * @param message The Message instance to get the image url from + */ +export function getImage(message: APIMessage): string | null { + const attachment = getAttachment(message); + return attachment ? attachment.proxyURL || attachment.url : null; +} + +export function getDisplayAvatar(id: string, user: APIUser, options?: Readonly) { + if (user.avatar === null) return container.rest.cdn.defaultAvatar(Number(user.discriminator) % 5); + return container.rest.cdn.avatar(id, user.avatar, options); +} + +/** + * Parse a range + * @param input The input to parse + * @example + * parseRange('23..25'); + * // -> [23, 24, 25] + * @example + * parseRange('1..3,23..25'); + * // -> [1, 2, 3, 23, 24, 25] + */ +export function parseRange(input: string): number[] { + const set = new Set(); + for (const subset of input.split(',')) { + const [, stringMin, stringMax] = /(\d+) *\.{2,} *(\d+)/.exec(subset) || [subset, subset, subset]; + let min = Number(stringMin); + let max = Number(stringMax); + if (min > max) [max, min] = [min, max]; + + for (let i = Math.max(1, min); i <= max; ++i) set.add(i); + } + + return [...set]; +} + +/** + * Parses an URL and checks if the extension is valid. + * @param url The url to check + */ +export function getImageUrl(url: string): string | undefined { + const parsed = parseURL(url); + return parsed && IMAGE_EXTENSION.test(parsed.pathname) ? parsed.href : undefined; +} + +/** + * Clean all mentions from a body of text + * @param guild The guild for context + * @param input The input to clean + * @returns The input cleaned of mentions + * @license Apache-2.0 + * @copyright 2019 Aura Román + */ +export function cleanMentions(guild: Guild, input: string) { + return input.replace(/@(here|everyone)/g, `@${ZeroWidthSpace}$1`).replace(/<(@[!&]?|#)(\d{17,19})>/g, (match, type, id) => { + switch (type) { + case '@': + case '@!': { + const tag = guild.client.users.cache.get(id); + return tag ? `@${tag.username}` : `<${type}${ZeroWidthSpace}${id}>`; + } + case '@&': { + const role = guild.roles.cache.get(id); + return role ? `@${role.name}` : match; + } + case '#': { + const channel = guild.channels.cache.get(id); + return channel ? `#${channel.name}` : `<${type}${ZeroWidthSpace}${id}>`; + } + default: + return `<${type}${ZeroWidthSpace}${id}>`; + } + }); +} + +export const anyMentionRegExp = /<(@[!&]?|#)(\d{17,19})>/g; +export const hereOrEveryoneMentionRegExp = /@(?:here|everyone)/; + +export function cast(value: unknown): T { + return value as T; +} diff --git a/src/listeners/commands/messageCommandDenied.ts b/projects/bot/src/listeners/commands/commandDenied.ts similarity index 62% rename from src/listeners/commands/messageCommandDenied.ts rename to projects/bot/src/listeners/commands/commandDenied.ts index 93b27e69d..ad4d26361 100644 --- a/src/listeners/commands/messageCommandDenied.ts +++ b/projects/bot/src/listeners/commands/commandDenied.ts @@ -1,17 +1,17 @@ import { translate } from '#lib/i18n/translate'; import { sendTemporaryMessage } from '#utils/functions'; -import { Events, Listener, UserError, type MessageCommandDeniedPayload } from '@sapphire/framework'; +import { CommandDeniedPayload, Events, Listener, UserError } from '@sapphire/framework'; import { resolveKey } from '@sapphire/plugin-i18next'; import type { Message } from 'discord.js'; -export class UserListener extends Listener { - public async run(error: UserError, { message, command }: MessageCommandDeniedPayload) { +export class UserListener extends Listener { + public async run(error: UserError, { message, command }: CommandDeniedPayload) { // `context: { silent: true }` should make UserError silent: // Use cases for this are for example permissions error when running the `eval` command. - if (Reflect.get(new Object(error.context), 'silent')) return; + if (Reflect.get(Object(error.context), 'silent')) return; const identifier = translate(error.identifier); - return this.alert(message, await resolveKey(message, identifier, { message, command, ...(error.context as object) })); + return this.alert(message, await resolveKey(message, identifier, { message, command, ...(error.context as any) })); } private alert(message: Message, content: string) { diff --git a/projects/bot/src/listeners/commands/commandError.ts b/projects/bot/src/listeners/commands/commandError.ts new file mode 100644 index 000000000..67687163f --- /dev/null +++ b/projects/bot/src/listeners/commands/commandError.ts @@ -0,0 +1,184 @@ +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { translate } from '#lib/i18n/translate'; +import type { WolfCommand } from '#lib/structures'; +import { OWNERS } from '#root/config'; +import { Colors, O, rootFolder, ZeroWidthSpace } from '#utils/constants'; +import { sendTemporaryMessage } from '#utils/functions'; +import { Args, ArgumentError, Command, CommandErrorPayload, Events, Listener, UserError } from '@sapphire/framework'; +import { codeBlock, cutText } from '@sapphire/utilities'; +import { captureException } from '@sentry/hub'; +import { envIsDefined } from '@wolfstar/env-utilities'; +import { RESTJSONErrorCodes } from 'discord-api-types/v9'; +import { DiscordAPIError, HTTPError, Message, MessageEmbed } from 'discord.js'; +import type { TFunction } from 'i18next'; + +const ignoredCodes = [RESTJSONErrorCodes.UnknownChannel, RESTJSONErrorCodes.UnknownMessage]; + +export class UserListener extends Listener { + private readonly sentry = envIsDefined('SENTRY_URL'); + + public async run(error: Error, { message, piece, parameters, args }: CommandErrorPayload) { + // If the error was a string or an UserError, send it to the user: + if (typeof error === 'string') return this.stringError(message, args.t, error); + if (error instanceof ArgumentError) return this.argumentError(message, args.t, error); + if (error instanceof UserError) return this.userError(message, args.t, error); + + const { client, logger } = this.container; + // If the error was an AbortError or an Internal Server Error, tell the user to re-try: + if (error.name === 'AbortError' || error.message === 'Internal Server Error') { + logger.warn(`${this.getWarnError(message)} (${message.author.id}) | ${error.constructor.name}`); + return sendTemporaryMessage(message, args.t(LanguageKeys.System.DiscordAbortError)); + } + + // Extract useful information about the DiscordAPIError + if (error instanceof DiscordAPIError || error instanceof HTTPError) { + if (this.isSilencedError(args, error)) return; + client.emit(Events.Error, error); + } else { + logger.warn(`${this.getWarnError(message)} (${message.author.id}) | ${error.constructor.name}`); + } + + // Send a detailed message: + const command = piece as WolfCommand; + await this.sendErrorChannel(message, command, parameters, error); + + // Emit where the error was emitted + logger.fatal(`[COMMAND] ${command.location.full}\n${error.stack || error.message}`); + try { + await sendTemporaryMessage(message, this.generateUnexpectedErrorMessage(args, error)); + } catch (err) { + client.emit(Events.Error, err); + } + + return undefined; + } + + private isSilencedError(args: Args, error: DiscordAPIError | HTTPError) { + return ( + // If it's an unknown channel or an unknown message, ignore: + ignoredCodes.includes(error.code) || + // If it's a DM message reply after a block, ignore: + this.isDirectMessageReplyAfterBlock(args, error) + ); + } + + private isDirectMessageReplyAfterBlock(args: Args, error: DiscordAPIError | HTTPError) { + // When sending a message to a user who has blocked the bot, Discord replies with 50007 "Cannot send messages to this user": + if (error.code !== RESTJSONErrorCodes.CannotSendMessagesToThisUser) return false; + + // If it's not a Direct Message, return false: + if (args.message.guild !== null) return false; + + // If the query was made to the message's channel, then it was a DM response: + return error.path === `/channels/${args.message.channel.id}/messages`; + } + + private generateUnexpectedErrorMessage(args: Args, error: Error) { + if (OWNERS.includes(args.message.author.id)) return codeBlock('js', error.stack!); + if (!this.sentry) return args.t(LanguageKeys.Events.Errors.UnexpectedError); + + try { + const report = captureException(error, { tags: { command: args.command.name } }); + return args.t(LanguageKeys.Events.Errors.UnexpectedErrorWithContext, { report }); + } catch (error) { + this.container.client.emit(Events.Error, error); + return args.t(LanguageKeys.Events.Errors.UnexpectedError); + } + } + + private stringError(message: Message, t: TFunction, error: string) { + return this.alert(message, t(LanguageKeys.Events.Errors.String, { mention: message.author.toString(), message: error })); + } + + private argumentError(message: Message, t: TFunction, error: ArgumentError) { + const argument = error.argument.name; + const identifier = translate(error.identifier); + const parameter = error.parameter.replaceAll('`', '῾'); + return this.alert(message, t(identifier, { ...error, ...(error.context as O), argument, parameter: cutText(parameter, 50) })); + } + + private userError(message: Message, t: TFunction, error: UserError) { + // `context: { silent: true }` should make UserError silent: + // Use cases for this are for example permissions error when running the `eval` command. + if (Reflect.get(Object(error.context), 'silent')) return; + + const identifier = translate(error.identifier); + return this.alert(message, t(identifier, error.context as any)); + } + + private alert(message: Message, content: string) { + return sendTemporaryMessage(message, { content, allowedMentions: { users: [message.author.id], roles: [] } }); + } + + private async sendErrorChannel(message: Message, command: Command, parameters: string, error: Error) { + const webhook = this.container.client.webhookError; + if (webhook === null) return; + + const lines = [this.getLinkLine(message.url), this.getCommandLine(command), this.getArgumentsLine(parameters), this.getErrorLine(error)]; + + // If it's a DiscordAPIError or a HTTPError, add the HTTP path and code lines after the second one. + if (error instanceof DiscordAPIError || error instanceof HTTPError) { + lines.splice(2, 0, this.getPathLine(error), this.getCodeLine(error)); + } + + const embed = new MessageEmbed().setDescription(lines.join('\n')).setColor(Colors.Red).setTimestamp(); + try { + await webhook.send({ embeds: [embed] }); + } catch (err) { + this.container.client.emit(Events.Error, err); + } + } + + /** + * Formats a message url line. + * @param url The url to format. + */ + private getLinkLine(url: string): string { + return `[**Jump to Message!**](${url})`; + } + + /** + * Formats a command line. + * @param command The command to format. + */ + private getCommandLine(command: Command): string { + return `**Command**: ${command.location.full.slice(rootFolder.length)}`; + } + + /** + * Formats an error path line. + * @param error The error to format. + */ + private getPathLine(error: DiscordAPIError | HTTPError): string { + return `**Path**: ${error.method.toUpperCase()} ${error.path}`; + } + + /** + * Formats an error code line. + * @param error The error to format. + */ + private getCodeLine(error: DiscordAPIError | HTTPError): string { + return `**Code**: ${error.code}`; + } + + /** + * Formats an arguments line. + * @param parameters The arguments the user used when running the command. + */ + private getArgumentsLine(parameters: string): string { + if (parameters.length === 0) return '**Parameters**: Not Supplied'; + return `**Parameters**: [\`${parameters.trim().replaceAll('`', '῾') || ZeroWidthSpace}\`]`; + } + + /** + * Formats an error codeblock. + * @param error The error to format. + */ + private getErrorLine(error: Error): string { + return `**Error**: ${codeBlock('js', error.stack || error)}`; + } + + private getWarnError(message: Message) { + return `ERROR: /${message.guild ? `${message.guild.id}/${message.channel.id}` : `DM/${message.author.id}`}/${message.id}`; + } +} diff --git a/src/listeners/commands/messageCommandRunAttach.ts b/projects/bot/src/listeners/commands/commandRunAttach.ts similarity index 58% rename from src/listeners/commands/messageCommandRunAttach.ts rename to projects/bot/src/listeners/commands/commandRunAttach.ts index f97d6c985..dcfa41233 100644 --- a/src/listeners/commands/messageCommandRunAttach.ts +++ b/projects/bot/src/listeners/commands/commandRunAttach.ts @@ -1,11 +1,11 @@ import type { WolfCommand } from '#lib/structures'; import { setCommand } from '#utils/functions'; import { ApplyOptions } from '@sapphire/decorators'; -import { Events, Listener } from '@sapphire/framework'; +import { Events, Listener, ListenerOptions } from '@sapphire/framework'; import type { Message } from 'discord.js'; -@ApplyOptions({ event: Events.MessageCommandRun }) -export class UserListener extends Listener { +@ApplyOptions({ event: Events.CommandRun }) +export class UserListener extends Listener { public run(message: Message, command: WolfCommand) { setCommand(message, command); } diff --git a/projects/bot/src/listeners/commands/commandSuccessAnalytics.ts b/projects/bot/src/listeners/commands/commandSuccessAnalytics.ts new file mode 100644 index 000000000..0ec8a1576 --- /dev/null +++ b/projects/bot/src/listeners/commands/commandSuccessAnalytics.ts @@ -0,0 +1,12 @@ +import type { WolfCommand } from '#lib/structures'; +import { Events } from '#lib/types/Enums'; +import { ApplyOptions } from '@sapphire/decorators'; +import { CommandSuccessPayload, Listener, ListenerOptions } from '@sapphire/framework'; + +@ApplyOptions({ event: Events.CommandSuccess }) +export class UserListener extends Listener { + public run(payload: CommandSuccessPayload) { + const command = payload.command as WolfCommand; + this.container.client.emit(Events.CommandUsageAnalytics, command.name, command.category); + } +} diff --git a/projects/bot/src/listeners/commands/commandSuccessAutoDelete.ts b/projects/bot/src/listeners/commands/commandSuccessAutoDelete.ts new file mode 100644 index 000000000..5a73dc5b0 --- /dev/null +++ b/projects/bot/src/listeners/commands/commandSuccessAutoDelete.ts @@ -0,0 +1,19 @@ +import { GuildSettings, readSettings } from '#lib/database'; +import { Events } from '#lib/types/Enums'; +import { isGuildMessage } from '#utils/common'; +import { deleteMessage } from '#utils/functions'; +import { ApplyOptions } from '@sapphire/decorators'; +import { CommandSuccessPayload, Listener, ListenerOptions } from '@sapphire/framework'; + +@ApplyOptions({ event: Events.CommandSuccess }) +export class UserListener extends Listener { + public async run({ message }: CommandSuccessPayload) { + if (!isGuildMessage(message)) return; + + const commandAutoDelete = await readSettings(message.guild, GuildSettings.CommandAutoDelete); + const commandAutoDeleteEntry = commandAutoDelete.find(([id]) => id === message.channel.id); + if (commandAutoDeleteEntry && message.deletable) { + await deleteMessage(message, commandAutoDeleteEntry[1]); + } + } +} diff --git a/src/listeners/commands/messageCommandSuccessLogger.ts b/projects/bot/src/listeners/commands/commandSuccessLogger.ts similarity index 65% rename from src/listeners/commands/messageCommandSuccessLogger.ts rename to projects/bot/src/listeners/commands/commandSuccessLogger.ts index 5b8bcb6a1..02fecdd61 100644 --- a/src/listeners/commands/messageCommandSuccessLogger.ts +++ b/projects/bot/src/listeners/commands/commandSuccessLogger.ts @@ -1,11 +1,12 @@ import { ApplyOptions } from '@sapphire/decorators'; -import { Command, Events, Listener, LogLevel, type MessageCommandSuccessPayload } from '@sapphire/framework'; +import { Command, CommandSuccessPayload, Events, Listener, ListenerOptions, LogLevel } from '@sapphire/framework'; +import type { Logger } from '@sapphire/plugin-logger'; import { cyan } from 'colorette'; import type { Guild, User } from 'discord.js'; -@ApplyOptions({ event: Events.MessageCommandSuccess }) -export class UserListener extends Listener { - public run({ message, command }: MessageCommandSuccessPayload) { +@ApplyOptions({ event: Events.CommandSuccess }) +export class UserListener extends Listener { + public run({ message, command }: CommandSuccessPayload) { const shard = this.shard(message.guild?.shardId ?? 0); const commandName = this.command(command); const author = this.author(message.author); @@ -13,8 +14,8 @@ export class UserListener extends Listener this.container.logger.debug(`${shard} - ${commandName} ${author} ${sentAt}`); } - public override onLoad() { - this.enabled = this.container.logger.has(LogLevel.Debug); + public onLoad() { + this.enabled = (this.container.logger as Logger).level <= LogLevel.Debug; return super.onLoad(); } diff --git a/projects/bot/src/listeners/commands/unknownCommand.ts b/projects/bot/src/listeners/commands/unknownCommand.ts new file mode 100644 index 000000000..43838f2d9 --- /dev/null +++ b/projects/bot/src/listeners/commands/unknownCommand.ts @@ -0,0 +1,38 @@ +import { getFromId } from '#lib/customCommands'; +import { GuildSettings, readSettings } from '#lib/database'; +import type { GuildMessage } from '#lib/types'; +import { isGuildMessage } from '#utils/common'; +import { isModerator } from '#utils/functions'; +import { Events, Listener, UnknownCommandPayload } from '@sapphire/framework'; + +export class UserListener extends Listener { + public async run({ message, commandPrefix, commandName }: UnknownCommandPayload) { + if (!isGuildMessage(message)) return null; + + const [disabledChannels, tags] = await readSettings(message.guild, [GuildSettings.DisabledChannels, GuildSettings.CustomCommands]); + + if (tags.length === 0) return null; + if (disabledChannels.includes(message.channel.id) && !(await isModerator(message.member))) return null; + + const name = commandName.toLowerCase(); + + const tag = getFromId(name, tags); + if (tag) return this.runCommand(message as GuildMessage, commandPrefix, 'tag', tag.id); + + return null; + } + + private runCommand(message: GuildMessage, commandPrefix: string, commandName: string, suffix: string) { + // Retrieve the command and validate: + const command = this.container.stores.get('commands').get(commandName); + if (!command) return; + + const prefixLess = message.content.slice(commandPrefix.length).trim(); + const spaceIndex = prefixLess.indexOf(' '); + + // Run the last stage before running the command: + const rawParameters = spaceIndex === -1 ? '' : prefixLess.slice(spaceIndex + 1).trim(); + const parameters = rawParameters.length === 0 ? suffix : suffix.length === 0 ? rawParameters : `${suffix} ${rawParameters}`; + message.client.emit(Events.PreCommandRun, { message, command, parameters, context: { commandName, commandPrefix, prefix: commandPrefix } }); + } +} diff --git a/src/listeners/errors/error.ts b/projects/bot/src/listeners/errors/error.ts similarity index 71% rename from src/listeners/errors/error.ts rename to projects/bot/src/listeners/errors/error.ts index 6feab6b3d..9dde7eefc 100644 --- a/src/listeners/errors/error.ts +++ b/projects/bot/src/listeners/errors/error.ts @@ -7,10 +7,10 @@ export class UserListener extends Listener { public run(error: Error) { const { logger } = this.container; if (error instanceof DiscordAPIError) { - logger.warn(`[API ERROR] [CODE: ${error.code}] ${error.message}${NEWLINE} [PATH: ${error.method} ${error.url}]`); + logger.warn(`[API ERROR] [CODE: ${error.code}] ${error.message}${NEWLINE} [PATH: ${error.method} ${error.path}]`); logger.fatal(error.stack); } else if (error instanceof HTTPError) { - logger.warn(`[HTTP ERROR] [CODE: ${error.status}] ${error.message}${NEWLINE} [PATH: ${error.method} ${error.url}]`); + logger.warn(`[HTTP ERROR] [CODE: ${error.code}] ${error.message}${NEWLINE} [PATH: ${error.method} ${error.path}]`); logger.fatal(error.stack); } else { logger.error(error); diff --git a/src/listeners/errors/listenerError.ts b/projects/bot/src/listeners/errors/listenerError.ts similarity index 51% rename from src/listeners/errors/listenerError.ts rename to projects/bot/src/listeners/errors/listenerError.ts index f32dd9d8a..c1e0c73f2 100644 --- a/src/listeners/errors/listenerError.ts +++ b/projects/bot/src/listeners/errors/listenerError.ts @@ -1,10 +1,7 @@ -import { Events, Listener, UserError, type ListenerErrorPayload } from '@sapphire/framework'; +import { Events, Listener, ListenerErrorPayload } from '@sapphire/framework'; export class UserListener extends Listener { public run(error: Error, context: ListenerErrorPayload) { - // We generally do not care about `UserError`s in listeners since they're not bugs. - if (error instanceof UserError) return; - this.container.logger.fatal(`[EVENT] ${context.piece.name}\n${error.stack || error.message}`); } } diff --git a/src/listeners/errors/listenerErrorSentry.ts b/projects/bot/src/listeners/errors/listenerErrorSentry.ts similarity index 56% rename from src/listeners/errors/listenerErrorSentry.ts rename to projects/bot/src/listeners/errors/listenerErrorSentry.ts index 42a8d50eb..226d77f2f 100644 --- a/src/listeners/errors/listenerErrorSentry.ts +++ b/projects/bot/src/listeners/errors/listenerErrorSentry.ts @@ -1,14 +1,11 @@ import { ApplyOptions } from '@sapphire/decorators'; -import { Events, Listener, UserError, type ListenerErrorPayload } from '@sapphire/framework'; +import { Events, Listener, ListenerErrorPayload } from '@sapphire/framework'; import { captureException } from '@sentry/node'; -import { envIsDefined } from '@skyra/env-utilities'; +import { envIsDefined } from '@wolfstar/env-utilities'; @ApplyOptions({ enabled: envIsDefined('SENTRY_URL') }) export class UserListener extends Listener { public run(error: Error, context: ListenerErrorPayload) { - // We generally do not care about `UserError`s in listeners since they're not bugs. - if (error instanceof UserError) return; - captureException(error, { tags: { name: context.piece.name } }); } } diff --git a/src/listeners/errors/taskError.ts b/projects/bot/src/listeners/errors/taskError.ts similarity index 72% rename from src/listeners/errors/taskError.ts rename to projects/bot/src/listeners/errors/taskError.ts index d5b5a91b7..e7043120b 100644 --- a/src/listeners/errors/taskError.ts +++ b/projects/bot/src/listeners/errors/taskError.ts @@ -1,4 +1,5 @@ -import type { Events, TaskErrorPayload } from '#lib/types'; +import type { TaskErrorPayload } from '#lib/types'; +import type { Events } from '#lib/types/Enums'; import { Listener } from '@sapphire/framework'; export class UserListener extends Listener { diff --git a/src/listeners/errors/taskErrorSentry.ts b/projects/bot/src/listeners/errors/taskErrorSentry.ts similarity index 59% rename from src/listeners/errors/taskErrorSentry.ts rename to projects/bot/src/listeners/errors/taskErrorSentry.ts index 5b48da3b8..285975437 100644 --- a/src/listeners/errors/taskErrorSentry.ts +++ b/projects/bot/src/listeners/errors/taskErrorSentry.ts @@ -1,12 +1,13 @@ -import type { Events, TaskErrorPayload } from '#lib/types'; +import type { TaskErrorPayload } from '#lib/types'; +import type { Events } from '#lib/types/Enums'; import { ApplyOptions } from '@sapphire/decorators'; import { Listener } from '@sapphire/framework'; -import { captureException } from '@sentry/node'; -import { envIsDefined } from '@skyra/env-utilities'; +import { captureException } from '@sentry/hub'; +import { envIsDefined } from '@wolfstar/env-utilities'; @ApplyOptions({ enabled: envIsDefined('SENTRY_URL') }) export class UserListener extends Listener { public run(error: Error, context: TaskErrorPayload) { - captureException(error, { tags: { name: context.piece.name, entity: context.entry.id } }); + captureException(error, { tags: { name: context.piece.name, entity: context.entity.id } }); } } diff --git a/projects/bot/src/listeners/guildMessageLog.ts b/projects/bot/src/listeners/guildMessageLog.ts new file mode 100644 index 000000000..0ee35419f --- /dev/null +++ b/projects/bot/src/listeners/guildMessageLog.ts @@ -0,0 +1,37 @@ +import { GuildEntity, writeSettings } from '#lib/database'; +import { canSendEmbeds } from '@sapphire/discord.js-utilities'; +import { Listener } from '@sapphire/framework'; +import { Awaitable, isNullish, Nullish, PickByValue } from '@sapphire/utilities'; +import { DiscordAPIError, Guild, HTTPError, MessageEmbed, MessageOptions, TextChannel } from 'discord.js'; + +export class UserListener extends Listener { + public async run( + guild: Guild, + logChannelId: string | Nullish, + key: PickByValue, + makeMessage: () => Awaitable + ) { + if (isNullish(logChannelId)) return; + + const channel = guild.channels.cache.get(logChannelId) as TextChannel; + if (!channel) { + await writeSettings(guild, [[key, null]]); + return; + } + + // Don't post if it's not possible + if (!canSendEmbeds(channel)) return; + + const processed = await makeMessage(); + const options: MessageOptions = processed instanceof MessageEmbed ? { embeds: [processed] } : processed; + try { + await channel.send(options); + } catch (error) { + this.container.logger.fatal( + error instanceof DiscordAPIError || error instanceof HTTPError + ? `Failed to send '${key}' log for guild ${guild} in channel ${channel.name}. Error: [${error.code} - ${error.method} | ${error.path}] ${error.message}` + : `Failed to send '${key}' log for guild ${guild} in channel ${channel.name}. Error: ${(error as Error).message}` + ); + } + } +} diff --git a/projects/bot/src/listeners/guilds/bans/guildBanAdd.ts b/projects/bot/src/listeners/guilds/bans/guildBanAdd.ts new file mode 100644 index 000000000..70c01b922 --- /dev/null +++ b/projects/bot/src/listeners/guilds/bans/guildBanAdd.ts @@ -0,0 +1,21 @@ +import { GuildSettings, readSettings } from '#lib/database'; +import { getModeration } from '#utils/functions'; +import { TypeCodes } from '#utils/moderationConstants'; +import { Listener } from '@sapphire/framework'; +import type { GuildBan } from 'discord.js'; + +export class UserListener extends Listener { + public async run({ guild, user }: GuildBan) { + if (!guild.available || !(await readSettings(guild, GuildSettings.Events.BanAdd))) return; + + const moderation = getModeration(guild); + await moderation.waitLock(); + await moderation + .create({ + userId: user.id, + moderatorId: process.env.CLIENT_ID, + type: TypeCodes.Ban + }) + .create(); + } +} diff --git a/projects/bot/src/listeners/guilds/bans/guildBanRemove.ts b/projects/bot/src/listeners/guilds/bans/guildBanRemove.ts new file mode 100644 index 000000000..5cd479639 --- /dev/null +++ b/projects/bot/src/listeners/guilds/bans/guildBanRemove.ts @@ -0,0 +1,21 @@ +import { GuildSettings, readSettings } from '#lib/database'; +import { getModeration } from '#utils/functions'; +import { TypeCodes } from '#utils/moderationConstants'; +import { Listener } from '@sapphire/framework'; +import type { GuildBan } from 'discord.js'; + +export class UserListener extends Listener { + public async run({ guild, user }: GuildBan) { + if (!guild.available || !(await readSettings(guild, GuildSettings.Events.BanRemove))) return; + + const moderation = getModeration(guild); + await moderation.waitLock(); + await moderation + .create({ + userId: user.id, + moderatorId: process.env.CLIENT_ID, + type: TypeCodes.UnBan + }) + .create(); + } +} diff --git a/src/listeners/guilds/channels/channelCreateNotify.ts b/projects/bot/src/listeners/guilds/channels/channelCreateNotify.ts similarity index 62% rename from src/listeners/guilds/channels/channelCreateNotify.ts rename to projects/bot/src/listeners/guilds/channels/channelCreateNotify.ts index 14c8f82dd..a5fa1b021 100644 --- a/src/listeners/guilds/channels/channelCreateNotify.ts +++ b/projects/bot/src/listeners/guilds/channels/channelCreateNotify.ts @@ -1,61 +1,57 @@ -import { readSettings } from '#lib/database'; -import { getT } from '#lib/i18n'; +import { GuildSettings, readSettings, writeSettings } from '#lib/database'; import { LanguageKeys } from '#lib/i18n/languageKeys'; import { toPermissionsArray } from '#utils/bits'; import { seconds } from '#utils/common'; import { Colors, LongWidthSpace } from '#utils/constants'; -import { getLogger } from '#utils/functions'; -import { EmbedBuilder } from '@discordjs/builders'; import { ApplyOptions } from '@sapphire/decorators'; import { isNsfwChannel } from '@sapphire/discord.js-utilities'; -import { Events, Listener } from '@sapphire/framework'; -import type { TFunction } from '@sapphire/plugin-i18next'; -import { - ChannelType, - OverwriteType, - type GuildChannel, - type NewsChannel, - type PermissionOverwrites, - type TextChannel, - type VoiceChannel -} from 'discord.js'; - -@ApplyOptions({ event: Events.ChannelCreate }) +import { Events, Listener, ListenerOptions } from '@sapphire/framework'; +import { isNullish } from '@sapphire/utilities'; +import { CategoryChannel, GuildChannel, MessageEmbed, NewsChannel, PermissionOverwrites, StoreChannel, TextChannel, VoiceChannel } from 'discord.js'; +import type { TFunction } from 'i18next'; + +type GuildBasedChannel = TextChannel | VoiceChannel | CategoryChannel | NewsChannel | StoreChannel; + +@ApplyOptions({ event: Events.ChannelCreate }) export class UserListener extends Listener { - public async run(channel: GuildChannel) { - const settings = await readSettings(channel.guild); - await getLogger(channel.guild).send({ - key: 'channelsLogsChannelCreate', - channelId: settings.channelsLogsChannelCreate, - makeMessage: () => { - const t = getT(settings.language); - const changes: string[] = [...this.getChannelInformation(t, channel)]; - return new EmbedBuilder() - .setColor(Colors.Green) - .setAuthor({ - name: `${channel.name} (${channel.id})`, - iconURL: channel.guild.iconURL({ size: 64, extension: 'png' }) ?? undefined - }) - .setDescription(changes.join('\n')) - .setFooter({ text: t(LanguageKeys.Events.Guilds.Logs.ChannelCreate) }) - .setTimestamp(); - } - }); + public async run(next: GuildBasedChannel) { + const [channelId, t] = await readSettings(next.guild, (settings) => [ + settings[GuildSettings.Channels.Logs.ChannelCreate], + settings.getLanguage() + ]); + if (isNullish(channelId)) return; + + const channel = next.guild.channels.cache.get(channelId) as TextChannel | undefined; + if (channel === undefined) { + await writeSettings(next.guild, [[GuildSettings.Channels.Logs.ChannelCreate, null]]); + return; + } + + const changes: string[] = [...this.getChannelInformation(t, next)]; + const embed = new MessageEmbed() + .setColor(Colors.Green) + .setAuthor({ name: `${next.name} (${next.id})`, iconURL: channel.guild.iconURL({ size: 64, format: 'png', dynamic: true }) ?? undefined }) + .setDescription(changes.join('\n')) + .setFooter({ text: t(LanguageKeys.Events.Guilds.Logs.ChannelCreate) }) + .setTimestamp(); + await channel.send({ embeds: [embed] }); } - private *getChannelInformation(t: TFunction, channel: GuildChannel) { + private *getChannelInformation(t: TFunction, channel: GuildBasedChannel) { yield* this.getGuildChannelInformation(t, channel); switch (channel.type) { - case ChannelType.GuildText: - yield* this.getTextChannelInformation(t, channel as TextChannel); + case 'GUILD_TEXT': + yield* this.getTextChannelInformation(t, channel); break; - case ChannelType.GuildStageVoice: - case ChannelType.GuildVoice: - yield* this.getVoiceChannelInformation(t, channel as VoiceChannel); + case 'GUILD_VOICE': + yield* this.getVoiceChannelInformation(t, channel); break; - case ChannelType.GuildAnnouncement: - yield* this.getNewsChannelInformation(t, channel as NewsChannel); + case 'GUILD_NEWS': + yield* this.getNewsChannelInformation(t, channel); + break; + case 'GUILD_STORE': + yield* this.getStoreChannelInformation(t, channel); break; default: // No Op @@ -64,7 +60,7 @@ export class UserListener extends Listener { yield* this.getChannelPermissionOverwrites(t, channel); } - private *getGuildChannelInformation(t: TFunction, channel: GuildChannel) { + private *getGuildChannelInformation(t: TFunction, channel: GuildBasedChannel) { if (channel.parentId) yield t(LanguageKeys.Events.Guilds.Logs.ChannelCreateParent, { value: `<#${channel.parentId}>` }); yield t(LanguageKeys.Events.Guilds.Logs.ChannelCreatePosition, { value: channel.position }); } @@ -105,6 +101,10 @@ export class UserListener extends Listener { if (channel.topic) yield this.displayTopic(t, channel.topic); } + private *getStoreChannelInformation(t: TFunction, channel: StoreChannel) { + if (isNsfwChannel(channel)) yield this.displayNsfw(t); + } + private displayNsfw(t: TFunction) { return t(LanguageKeys.Events.Guilds.Logs.ChannelCreateNsfw); } @@ -126,7 +126,7 @@ export class UserListener extends Listener { } private displayMention(permissions: PermissionOverwrites) { - if (permissions.type === OverwriteType.Member) return `<@${permissions.id}>`; + if (permissions.type === 'member') return `<@${permissions.id}>`; if (permissions.id === permissions.channel.guild.id) return '@everyone'; return `<@&${permissions.id}>`; } diff --git a/projects/bot/src/listeners/guilds/channels/channelDeleteNotify.ts b/projects/bot/src/listeners/guilds/channels/channelDeleteNotify.ts new file mode 100644 index 000000000..0a215bfd0 --- /dev/null +++ b/projects/bot/src/listeners/guilds/channels/channelDeleteNotify.ts @@ -0,0 +1,40 @@ +import { GuildSettings, readSettings, writeSettings } from '#lib/database'; +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { Colors } from '#utils/constants'; +import { ApplyOptions } from '@sapphire/decorators'; +import { Events, Listener, ListenerOptions } from '@sapphire/framework'; +import { isNullish } from '@sapphire/utilities'; +import { CategoryChannel, MessageEmbed, NewsChannel, StoreChannel, TextChannel, VoiceChannel } from 'discord.js'; +import type { TFunction } from 'i18next'; + +type GuildBasedChannel = TextChannel | VoiceChannel | CategoryChannel | NewsChannel | StoreChannel; + +@ApplyOptions({ event: Events.ChannelDelete }) +export class UserListener extends Listener { + public async run(next: GuildBasedChannel) { + const [channelId, t] = await readSettings(next.guild, (settings) => [ + settings[GuildSettings.Channels.Logs.ChannelDelete], + settings.getLanguage() + ]); + if (isNullish(channelId)) return; + + const channel = next.guild.channels.cache.get(channelId) as TextChannel | undefined; + if (channel === undefined) { + await writeSettings(next.guild, [[GuildSettings.Channels.Logs.ChannelDelete, null]]); + return; + } + + const changes = [...this.getChannelInformation(t, next)]; + const embed = new MessageEmbed() + .setColor(Colors.Red) + .setAuthor({ name: `${next.name} (${next.id})`, iconURL: channel.guild.iconURL({ size: 64, format: 'png', dynamic: true }) ?? undefined }) + .setDescription(changes.join('\n')) + .setFooter({ text: t(LanguageKeys.Events.Guilds.Logs.ChannelDelete) }) + .setTimestamp(); + await channel.send({ embeds: [embed] }); + } + + private *getChannelInformation(t: TFunction, channel: GuildBasedChannel) { + if (channel.parentId) yield t(LanguageKeys.Events.Guilds.Logs.ChannelCreateParent, { value: `<#${channel.parentId}>` }); + } +} diff --git a/src/listeners/guilds/channels/channelUpdateNotify.ts b/projects/bot/src/listeners/guilds/channels/channelUpdateNotify.ts similarity index 80% rename from src/listeners/guilds/channels/channelUpdateNotify.ts rename to projects/bot/src/listeners/guilds/channels/channelUpdateNotify.ts index 0cad7c4e2..e0e250020 100644 --- a/src/listeners/guilds/channels/channelUpdateNotify.ts +++ b/projects/bot/src/listeners/guilds/channels/channelUpdateNotify.ts @@ -1,80 +1,76 @@ -import { readSettings } from '#lib/database'; -import { getT } from '#lib/i18n'; +import { GuildSettings, readSettings, writeSettings } from '#lib/database'; import { LanguageKeys } from '#lib/i18n/languageKeys'; import { toPermissionsArray } from '#utils/bits'; import { seconds } from '#utils/common'; import { differenceBitField, differenceMap } from '#utils/common/comparators'; import { Colors, LongWidthSpace } from '#utils/constants'; -import { getLogger } from '#utils/functions'; -import { EmbedBuilder } from '@discordjs/builders'; import { ApplyOptions } from '@sapphire/decorators'; -import { isDMChannel, isNsfwChannel, type GuildBasedChannelTypes, type NonThreadGuildBasedChannelTypes } from '@sapphire/discord.js-utilities'; -import { Events, Listener } from '@sapphire/framework'; -import type { TFunction } from '@sapphire/plugin-i18next'; -import { - ChannelType, - OverwriteType, - type DMChannel, - type GuildChannel, - type NewsChannel, - type PermissionOverwrites, - type TextChannel, - type VoiceChannel -} from 'discord.js'; - -type Channel = DMChannel | GuildChannel; - -@ApplyOptions({ event: Events.ChannelUpdate }) +import { GuildBasedChannelTypes, isDMChannel, isNsfwChannel, NonThreadGuildBasedChannelTypes } from '@sapphire/discord.js-utilities'; +import { Events, Listener, ListenerOptions } from '@sapphire/framework'; +import { isNullish } from '@sapphire/utilities'; +import { DMChannel, GuildChannel, MessageEmbed, NewsChannel, PermissionOverwrites, StoreChannel, TextChannel, VoiceChannel } from 'discord.js'; +import type { TFunction } from 'i18next'; + +type ChannelType = DMChannel | GuildChannel; + +@ApplyOptions({ event: Events.ChannelUpdate }) export class UserListener extends Listener { - public async run(previous: Channel, next: Channel) { + public async run(previous: ChannelType, next: ChannelType) { if (isDMChannel(next)) return; - const settings = await readSettings(next.guild); - await getLogger(next.guild).send({ - key: 'channelsLogsChannelUpdate', - channelId: settings.channelsLogsChannelUpdate, - makeMessage: () => { - const t = getT(settings.language); - const changes: string[] = [...this.differenceChannel(t, previous as GuildBasedChannelTypes, next as GuildBasedChannelTypes)]; - if (changes.length === 0) return null; - - return new EmbedBuilder() - .setColor(Colors.Yellow) - .setAuthor({ name: `${next.name} (${next.id})`, iconURL: next.guild.iconURL({ size: 64, extension: 'png' }) ?? undefined }) - .setDescription(changes.join('\n')) - .setFooter({ text: t(LanguageKeys.Events.Guilds.Logs.ChannelUpdate) }) - .setTimestamp(); - } - }); + const [channelId, t] = await readSettings(next.guild, (settings) => [ + settings[GuildSettings.Channels.Logs.ChannelUpdate], + settings.getLanguage() + ]); + if (isNullish(channelId)) return; + + const channel = next.guild.channels.cache.get(channelId) as TextChannel | undefined; + if (channel === undefined) { + await writeSettings(next.guild, [[GuildSettings.Channels.Logs.ChannelUpdate, null]]); + return; + } + + const changes: string[] = [...this.differenceChannel(t, previous as GuildBasedChannelTypes, next as GuildBasedChannelTypes)]; + if (changes.length === 0) return; + + const embed = new MessageEmbed() + .setColor(Colors.Yellow) + .setAuthor({ name: `${next.name} (${next.id})`, iconURL: channel.guild.iconURL({ size: 64, format: 'png', dynamic: true }) ?? undefined }) + .setDescription(changes.join('\n')) + .setFooter({ text: t(LanguageKeys.Events.Guilds.Logs.ChannelUpdate) }) + .setTimestamp(); + await channel.send({ embeds: [embed] }); } private *differenceChannel(t: TFunction, previous: GuildBasedChannelTypes, next: GuildBasedChannelTypes) { - yield* this.differenceGuildChannel(t, previous, next); - const isThread = next.isThread(); + + yield* this.differenceGuildChannel(t, previous, next); if (!isThread) { - yield* this.differencePositions(t, previous as NonThreadGuildBasedChannelTypes, next as NonThreadGuildBasedChannelTypes); + yield* this.differencePositions(t, previous as NonThreadGuildBasedChannelTypes, next); } if (previous.type !== next.type) return; switch (next.type) { - case ChannelType.GuildText: + case 'GUILD_TEXT': yield* this.differenceTextChannel(t, previous as TextChannel, next as TextChannel); break; - case ChannelType.GuildStageVoice: - case ChannelType.GuildVoice: + case 'GUILD_VOICE': yield* this.differenceVoiceChannel(t, previous as VoiceChannel, next as VoiceChannel); break; - case ChannelType.GuildAnnouncement: + case 'GUILD_NEWS': yield* this.differenceNewsChannel(t, previous as NewsChannel, next as NewsChannel); break; + case 'GUILD_STORE': + yield* this.differenceStoreChannel(t, previous as StoreChannel, next as StoreChannel); + break; default: // No Op } if (!isThread) { - yield* this.differencePermissionOverwrites(t, previous as NonThreadGuildBasedChannelTypes, next as NonThreadGuildBasedChannelTypes); + yield* this.differencePermissionOverwrites(t, previous as NonThreadGuildBasedChannelTypes, next); } } @@ -195,6 +191,10 @@ export class UserListener extends Listener { if (previous.topic !== next.topic) yield this.displayTopic(t, previous.topic, next.topic); } + private *differenceStoreChannel(t: TFunction, previous: StoreChannel, next: StoreChannel) { + if (isNsfwChannel(previous) !== isNsfwChannel(next)) yield this.displayNsfw(t, isNsfwChannel(previous), isNsfwChannel(next)); + } + private displayNsfw(t: TFunction, previous: boolean, next: boolean) { return t(LanguageKeys.Events.Guilds.Logs.ChannelUpdateNsfw, { previous: t(previous ? LanguageKeys.Globals.Yes : LanguageKeys.Globals.No), @@ -225,7 +225,7 @@ export class UserListener extends Listener { } private displayMention(permissions: PermissionOverwrites) { - if (permissions.type === OverwriteType.Member) return `<@${permissions.id}>`; + if (permissions.type === 'member') return `<@${permissions.id}>`; if (permissions.id === permissions.channel.guild.id) return '@everyone'; return `<@&${permissions.id}>`; } diff --git a/projects/bot/src/listeners/guilds/emojis/emojiCreateNotify.ts b/projects/bot/src/listeners/guilds/emojis/emojiCreateNotify.ts new file mode 100644 index 000000000..4b90b5a3a --- /dev/null +++ b/projects/bot/src/listeners/guilds/emojis/emojiCreateNotify.ts @@ -0,0 +1,48 @@ +import { GuildSettings, readSettings, writeSettings } from '#lib/database'; +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { Colors } from '#utils/constants'; +import { ApplyOptions } from '@sapphire/decorators'; +import { Events, Listener, ListenerOptions } from '@sapphire/framework'; +import { isNullish } from '@sapphire/utilities'; +import { GuildEmoji, MessageEmbed, TextChannel } from 'discord.js'; +import type { TFunction } from 'i18next'; + +@ApplyOptions({ event: Events.GuildEmojiCreate }) +export class UserListener extends Listener { + public async run(next: GuildEmoji) { + const [channelId, t] = await readSettings(next.guild, (settings) => [ + settings[GuildSettings.Channels.Logs.EmojiCreate], + settings.getLanguage() + ]); + if (isNullish(channelId)) return; + + const channel = next.guild.channels.cache.get(channelId) as TextChannel | undefined; + if (channel === undefined) { + await writeSettings(next.guild, [[GuildSettings.Channels.Logs.EmojiCreate, null]]); + return; + } + + const changes: string[] = [...this.getEmojiInformation(t, next)]; + const embed = new MessageEmbed() + .setColor(Colors.Green) + .setThumbnail(next.url) + .setAuthor({ name: `${next.name} (${next.id})`, iconURL: channel.guild.iconURL({ size: 64, format: 'png', dynamic: true }) ?? undefined }) + .setDescription(changes.join('\n')) + .setFooter({ text: t(LanguageKeys.Events.Guilds.Logs.EmojiCreate) }) + .setTimestamp(); + await channel.send({ embeds: [embed] }); + } + + private *getEmojiInformation(t: TFunction, next: GuildEmoji) { + if (next.animated) yield t(LanguageKeys.Events.Guilds.Logs.EmojiCreateAnimated); + if (!next.available) yield t(LanguageKeys.Events.Guilds.Logs.EmojiCreateUnAvailable); + if (next.managed) yield t(LanguageKeys.Events.Guilds.Logs.EmojiCreateManaged); + if (next.requiresColons) yield t(LanguageKeys.Events.Guilds.Logs.EmojiCreateRequiresColons); + + const roles = next.roles.cache; + if (roles.size !== 0) { + const values = [...next.roles.cache.values()].map((role) => role.toString()); + yield t(LanguageKeys.Events.Guilds.Logs.EmojiCreateRoles, { values, count: values.length }); + } + } +} diff --git a/projects/bot/src/listeners/guilds/emojis/emojiDeleteNotify.ts b/projects/bot/src/listeners/guilds/emojis/emojiDeleteNotify.ts new file mode 100644 index 000000000..adc0ce4c9 --- /dev/null +++ b/projects/bot/src/listeners/guilds/emojis/emojiDeleteNotify.ts @@ -0,0 +1,32 @@ +import { GuildSettings, readSettings, writeSettings } from '#lib/database'; +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { Colors } from '#utils/constants'; +import { ApplyOptions } from '@sapphire/decorators'; +import { Events, Listener, ListenerOptions } from '@sapphire/framework'; +import { isNullish } from '@sapphire/utilities'; +import { GuildEmoji, MessageEmbed, TextChannel } from 'discord.js'; + +@ApplyOptions({ event: Events.GuildEmojiDelete }) +export class UserListener extends Listener { + public async run(next: GuildEmoji) { + const [channelId, t] = await readSettings(next.guild, (settings) => [ + settings[GuildSettings.Channels.Logs.EmojiDelete], + settings.getLanguage() + ]); + if (isNullish(channelId)) return; + + const channel = next.guild.channels.cache.get(channelId) as TextChannel | undefined; + if (channel === undefined) { + await writeSettings(next.guild, [[GuildSettings.Channels.Logs.EmojiDelete, null]]); + return; + } + + const embed = new MessageEmbed() + .setColor(Colors.Red) + .setThumbnail(next.url) + .setAuthor({ name: `${next.name} (${next.id})`, iconURL: channel.guild.iconURL({ size: 64, format: 'png', dynamic: true }) ?? undefined }) + .setFooter({ text: t(LanguageKeys.Events.Guilds.Logs.EmojiDelete) }) + .setTimestamp(); + await channel.send({ embeds: [embed] }); + } +} diff --git a/src/listeners/guilds/emojis/emojiUpdateNotify.ts b/projects/bot/src/listeners/guilds/emojis/emojiUpdateNotify.ts similarity index 60% rename from src/listeners/guilds/emojis/emojiUpdateNotify.ts rename to projects/bot/src/listeners/guilds/emojis/emojiUpdateNotify.ts index d43ad4814..6e8303754 100644 --- a/src/listeners/guilds/emojis/emojiUpdateNotify.ts +++ b/projects/bot/src/listeners/guilds/emojis/emojiUpdateNotify.ts @@ -1,36 +1,39 @@ -import { readSettings } from '#lib/database'; -import { getT } from '#lib/i18n'; +import { GuildSettings, readSettings, writeSettings } from '#lib/database'; import { LanguageKeys } from '#lib/i18n/languageKeys'; import { differenceMap } from '#utils/common/comparators'; import { Colors } from '#utils/constants'; -import { getLogger } from '#utils/functions'; -import { EmbedBuilder } from '@discordjs/builders'; import { ApplyOptions } from '@sapphire/decorators'; -import { Events, Listener } from '@sapphire/framework'; -import type { TFunction } from '@sapphire/plugin-i18next'; -import type { GuildEmoji } from 'discord.js'; +import { Events, Listener, ListenerOptions } from '@sapphire/framework'; +import { isNullish } from '@sapphire/utilities'; +import { GuildEmoji, MessageEmbed, TextChannel } from 'discord.js'; +import type { TFunction } from 'i18next'; -@ApplyOptions({ event: Events.GuildEmojiUpdate }) +@ApplyOptions({ event: Events.GuildEmojiUpdate }) export class UserListener extends Listener { public async run(previous: GuildEmoji, next: GuildEmoji) { - const settings = await readSettings(next.guild); - await getLogger(next.guild).send({ - key: 'channelsLogsEmojiUpdate', - channelId: settings.channelsLogsEmojiUpdate, - makeMessage: () => { - const t = getT(settings.language); - const changes: string[] = [...this.differenceEmoji(t, previous, next)]; - if (changes.length === 0) return null; + const [channelId, t] = await readSettings(next.guild, (settings) => [ + settings[GuildSettings.Channels.Logs.EmojiUpdate], + settings.getLanguage() + ]); + if (isNullish(channelId)) return; - return new EmbedBuilder() - .setColor(Colors.Yellow) - .setThumbnail(next.imageURL({ size: 256 })) - .setAuthor({ name: `${next.name} (${next.id})`, iconURL: next.guild.iconURL({ size: 64, extension: 'png' }) ?? undefined }) - .setDescription(changes.join('\n')) - .setFooter({ text: t(LanguageKeys.Events.Guilds.Logs.EmojiUpdate) }) - .setTimestamp(); - } - }); + const channel = next.guild.channels.cache.get(channelId) as TextChannel | undefined; + if (channel === undefined) { + await writeSettings(next.guild, [[GuildSettings.Channels.Logs.EmojiUpdate, null]]); + return; + } + + const changes: string[] = [...this.differenceEmoji(t, previous, next)]; + if (changes.length === 0) return; + + const embed = new MessageEmbed() + .setColor(Colors.Yellow) + .setThumbnail(next.url) + .setAuthor({ name: `${next.name} (${next.id})`, iconURL: channel.guild.iconURL({ size: 64, format: 'png', dynamic: true }) ?? undefined }) + .setDescription(changes.join('\n')) + .setFooter({ text: t(LanguageKeys.Events.Guilds.Logs.EmojiUpdate) }) + .setTimestamp(); + await channel.send({ embeds: [embed] }); } private *differenceEmoji(t: TFunction, previous: GuildEmoji, next: GuildEmoji) { diff --git a/src/listeners/guilds/guildUpdateNotify.ts b/projects/bot/src/listeners/guilds/guildUpdateNotify.ts similarity index 84% rename from src/listeners/guilds/guildUpdateNotify.ts rename to projects/bot/src/listeners/guilds/guildUpdateNotify.ts index 52aca8ca4..e08520447 100644 --- a/src/listeners/guilds/guildUpdateNotify.ts +++ b/projects/bot/src/listeners/guilds/guildUpdateNotify.ts @@ -1,48 +1,55 @@ -import { readSettings } from '#lib/database'; -import { getT } from '#lib/i18n'; +import { GuildSettings, readSettings, writeSettings } from '#lib/database'; import { LanguageKeys } from '#lib/i18n/languageKeys'; import { toChannelsArray } from '#utils/bits'; -import { differenceArray, differenceBitField, seconds } from '#utils/common'; +import { seconds } from '#utils/common'; +import { differenceArray, differenceBitField } from '#utils/common/comparators'; import { Colors } from '#utils/constants'; -import { getLogger } from '#utils/functions'; -import { EmbedBuilder } from '@discordjs/builders'; import { ApplyOptions } from '@sapphire/decorators'; -import { Events, Listener } from '@sapphire/framework'; -import type { TFunction } from '@sapphire/plugin-i18next'; +import { Events, Listener, ListenerOptions } from '@sapphire/framework'; +import { isNullish } from '@sapphire/utilities'; import { - GuildMFALevel, - type Guild, - type GuildDefaultMessageNotifications, - type GuildExplicitContentFilter, - type GuildFeature, - type GuildPremiumTier, - type GuildVerificationLevel, - type SystemChannelFlagsBitField + DefaultMessageNotificationLevel, + ExplicitContentFilterLevel, + Guild, + GuildFeatures, + MessageEmbed, + MFALevel, + PremiumTier, + SystemChannelFlags, + TextChannel, + VerificationLevel } from 'discord.js'; +import type { TFunction } from 'i18next'; -type ChannelFlags = Readonly; -type Features = readonly `${GuildFeature}`[]; +type MessageNotifications = DefaultMessageNotificationLevel | number; +type ChannelFlags = Readonly; +type Features = readonly GuildFeatures[]; -@ApplyOptions({ event: Events.GuildUpdate }) +@ApplyOptions({ event: Events.GuildUpdate }) export class UserListener extends Listener { public async run(previous: Guild, next: Guild) { - const settings = await readSettings(next); - await getLogger(next).send({ - key: 'channelsLogsServerUpdate', - channelId: settings.channelsLogsServerUpdate, - makeMessage: () => { - const t = getT(settings.language); - const changes: string[] = [...this.differenceGuild(t, previous, next)]; - if (changes.length === 0) return null; - - return new EmbedBuilder() - .setColor(Colors.Yellow) - .setAuthor({ name: `${next.name} (${next.id})`, iconURL: next.iconURL({ size: 64, extension: 'png' }) ?? undefined }) - .setDescription(changes.join('\n')) - .setFooter({ text: t(LanguageKeys.Events.Guilds.Logs.ServerUpdate) }) - .setTimestamp(); - } - }); + const [channelId, t] = await readSettings(next, (settings) => [ + settings[GuildSettings.Channels.Logs.ServerUpdate], // + settings.getLanguage() + ]); + if (isNullish(channelId)) return; + + const channel = next.channels.cache.get(channelId) as TextChannel | undefined; + if (channel === undefined) { + await writeSettings(next, [[GuildSettings.Channels.Logs.ServerUpdate, null]]); + return; + } + + const changes: string[] = [...this.differenceGuild(t, previous, next)]; + if (changes.length === 0) return; + + const embed = new MessageEmbed() + .setColor(Colors.Yellow) + .setAuthor({ name: `${next.name} (${next.id})`, iconURL: channel.guild.iconURL({ size: 64, format: 'png', dynamic: true }) ?? undefined }) + .setDescription(changes.join('\n')) + .setFooter({ text: t(LanguageKeys.Events.Guilds.Logs.ServerUpdate) }) + .setTimestamp(); + await channel.send({ embeds: [embed] }); } private *differenceGuild(t: TFunction, previous: Guild, next: Guild) { @@ -163,11 +170,7 @@ export class UserListener extends Listener { return t(LanguageKeys.Events.Guilds.Logs.ServerUpdateBanner, { previous, next }); } - private displayDefaultMessageNotifications( - t: TFunction, - previous: GuildDefaultMessageNotifications, - next: GuildDefaultMessageNotifications - ): string { + private displayDefaultMessageNotifications(t: TFunction, previous: MessageNotifications, next: MessageNotifications): string { return t(LanguageKeys.Events.Guilds.Logs.ServerUpdateDefaultMessageNotifications, { previous, next }); } @@ -183,7 +186,7 @@ export class UserListener extends Listener { return t(LanguageKeys.Events.Guilds.Logs.ServerUpdateDiscoverySplash, { previous, next }); } - private displayExplicitContentFilter(t: TFunction, previous: GuildExplicitContentFilter, next: GuildExplicitContentFilter): string { + private displayExplicitContentFilter(t: TFunction, previous: ExplicitContentFilterLevel, next: ExplicitContentFilterLevel): string { return t(LanguageKeys.Events.Guilds.Logs.ServerUpdateExplicitContentFilter, { previous, next }); } @@ -212,12 +215,8 @@ export class UserListener extends Listener { return t(LanguageKeys.Events.Guilds.Logs.ServerUpdateMaximumMembers, { previous, next }); } - private displayMfaLevel(t: TFunction, next: GuildMFALevel): string { - return t( - next === GuildMFALevel.Elevated - ? LanguageKeys.Events.Guilds.Logs.ServerUpdateMfaAdded - : LanguageKeys.Events.Guilds.Logs.ServerUpdateMfaRemoved - ); + private displayMfaLevel(t: TFunction, next: MFALevel): string { + return t(next === 'ELEVATED' ? LanguageKeys.Events.Guilds.Logs.ServerUpdateMfaAdded : LanguageKeys.Events.Guilds.Logs.ServerUpdateMfaRemoved); } private displayName(t: TFunction, previous: string, next: string): string { @@ -240,7 +239,7 @@ export class UserListener extends Listener { return t(LanguageKeys.Events.Guilds.Logs.ServerUpdatePremiumSubscriptionCount, { previous, next }); } - private displayPremiumTier(t: TFunction, previous: GuildPremiumTier, next: GuildPremiumTier): string { + private displayPremiumTier(t: TFunction, previous: PremiumTier, next: PremiumTier): string { return t(LanguageKeys.Events.Guilds.Logs.ServerUpdatePremiumTier, { previous, next }); } @@ -288,7 +287,7 @@ export class UserListener extends Listener { return t(LanguageKeys.Events.Guilds.Logs.ServerUpdateVanityUrl, { previous, next }); } - private displayVerificationLevel(t: TFunction, previous: GuildVerificationLevel, next: GuildVerificationLevel): string { + private displayVerificationLevel(t: TFunction, previous: VerificationLevel, next: VerificationLevel): string { return t(LanguageKeys.Events.Guilds.Logs.ServerUpdateVerificationLevel, { previous, next }); } @@ -300,9 +299,7 @@ export class UserListener extends Listener { private displayWidgetEnabled(t: TFunction, previous: boolean | null, next: boolean | null): string { return t( - (next ?? !previous) - ? LanguageKeys.Events.Guilds.Logs.ServerUpdateWidgetEnabled - : LanguageKeys.Events.Guilds.Logs.ServerUpdateWidgetDisabled + next ?? !previous ? LanguageKeys.Events.Guilds.Logs.ServerUpdateWidgetEnabled : LanguageKeys.Events.Guilds.Logs.ServerUpdateWidgetDisabled ); } } diff --git a/projects/bot/src/listeners/guilds/members/guildMemberAdd.ts b/projects/bot/src/listeners/guilds/members/guildMemberAdd.ts new file mode 100644 index 000000000..49ad14804 --- /dev/null +++ b/projects/bot/src/listeners/guilds/members/guildMemberAdd.ts @@ -0,0 +1,61 @@ +import { GuildSettings, readSettings, writeSettings } from '#lib/database'; +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { Events } from '#lib/types/Enums'; +import { floatPromise } from '#utils/common'; +import { Colors } from '#utils/constants'; +import { getStickyRoles } from '#utils/functions'; +import { Listener } from '@sapphire/framework'; +import { GuildMember, MessageEmbed, Permissions } from 'discord.js'; + +const { FLAGS } = Permissions; + +export class UserListener extends Listener { + public async run(member: GuildMember) { + if (await this.handleStickyRoles(member)) return; + this.container.client.emit(Events.NotMutedMemberAdd, member); + } + + private async handleStickyRoles(member: GuildMember) { + if (!member.guild.me!.permissions.has(FLAGS.MANAGE_ROLES)) return false; + + const stickyRoles = await getStickyRoles(member).fetch(member.id); + if (stickyRoles.length === 0) return false; + + // Handle the case the user is muted + const key = GuildSettings.Channels.Logs.MemberAdd; + const [logChannelId, roleId, t] = await readSettings(member, (settings) => [ + settings[key], + settings[GuildSettings.Roles.Muted], + settings.getLanguage() + ]); + if (roleId && stickyRoles.includes(roleId)) { + // Handle mute + const role = member.guild.roles.cache.get(roleId); + floatPromise(role ? member.roles.add(role) : writeSettings(member, [[GuildSettings.Roles.Muted, null]])); + + // Handle log + this.container.client.emit(Events.GuildMessageLog, member.guild, logChannelId, key, () => + new MessageEmbed() + .setColor(Colors.Amber) + .setAuthor({ + name: `${member.user.tag} (${member.user.id})`, + iconURL: member.user.displayAvatarURL({ size: 128, format: 'png', dynamic: true }) + }) + .setDescription( + t(LanguageKeys.Events.Guilds.Members.GuildMemberAddDescription, { + mention: member.toString(), + time: Date.now() - member.user.createdTimestamp + }) + ) + .setFooter({ text: t(LanguageKeys.Events.Guilds.Members.GuildMemberAddMute) }) + .setTimestamp() + ); + + return true; + } + + floatPromise(member.roles.add(stickyRoles)); + + return false; + } +} diff --git a/src/listeners/guilds/members/guildMemberUpdateNicknameNotify.ts b/projects/bot/src/listeners/guilds/members/guildMemberUpdateNicknameNotify.ts similarity index 63% rename from src/listeners/guilds/members/guildMemberUpdateNicknameNotify.ts rename to projects/bot/src/listeners/guilds/members/guildMemberUpdateNicknameNotify.ts index fb7fafbcc..e5e402065 100644 --- a/src/listeners/guilds/members/guildMemberUpdateNicknameNotify.ts +++ b/projects/bot/src/listeners/guilds/members/guildMemberUpdateNicknameNotify.ts @@ -1,21 +1,18 @@ -import { readSettings } from '#lib/database'; -import { getT } from '#lib/i18n'; +import { GuildSettings, readSettings } from '#lib/database'; import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { Events } from '#lib/types'; +import { Events } from '#lib/types/Enums'; import { Colors } from '#utils/constants'; -import { getFullEmbedAuthor } from '#utils/util'; -import { EmbedBuilder } from '@discordjs/builders'; import { ApplyOptions } from '@sapphire/decorators'; -import { Listener } from '@sapphire/framework'; -import type { TFunction } from '@sapphire/plugin-i18next'; +import { Listener, ListenerOptions } from '@sapphire/framework'; import { isNullish } from '@sapphire/utilities'; -import type { GuildMember } from 'discord.js'; +import { GuildMember, MessageEmbed } from 'discord.js'; +import type { TFunction } from 'i18next'; -@ApplyOptions({ event: Events.GuildMemberUpdate }) +@ApplyOptions({ event: Events.GuildMemberUpdate }) export class UserListener extends Listener { public async run(previous: GuildMember, next: GuildMember) { - const settings = await readSettings(next); - const logChannelId = settings.channelsLogsMemberNicknameUpdate; + const key = GuildSettings.Channels.Logs.MemberNickNameUpdate; + const [logChannelId, t] = await readSettings(next, (settings) => [settings[key], settings.getLanguage()]); if (isNullish(logChannelId)) return; // Send the Nickname log @@ -23,11 +20,10 @@ export class UserListener extends Listener { const nextNickname = next.nickname; const { user } = next; if (prevNickname !== nextNickname) { - const t = getT(settings.language); - this.container.client.emit(Events.GuildMessageLog, next.guild, logChannelId, 'channelsLogsMemberNicknameUpdate', () => - new EmbedBuilder() + this.container.client.emit(Events.GuildMessageLog, next.guild, logChannelId, key, () => + new MessageEmbed() .setColor(Colors.Yellow) - .setAuthor(getFullEmbedAuthor(user)) + .setAuthor({ name: `${user.tag} (${user.id})`, iconURL: user.displayAvatarURL({ size: 128, format: 'png', dynamic: true }) }) .setDescription(this.getNameDescription(t, prevNickname, nextNickname)) .setFooter({ text: t(LanguageKeys.Events.Guilds.Members.NicknameUpdate) }) .setTimestamp() @@ -41,7 +37,9 @@ export class UserListener extends Listener { previousName === null ? LanguageKeys.Events.Guilds.Members.NameUpdatePreviousWasNotSet : LanguageKeys.Events.Guilds.Members.NameUpdatePreviousWasSet, - { previousName } + { + previousName + } ), t( nextName === null diff --git a/src/listeners/guilds/members/guildMemberUpdateRolesNotify.ts b/projects/bot/src/listeners/guilds/members/guildMemberUpdateRolesNotify.ts similarity index 72% rename from src/listeners/guilds/members/guildMemberUpdateRolesNotify.ts rename to projects/bot/src/listeners/guilds/members/guildMemberUpdateRolesNotify.ts index 315e34cff..5d1c56b9a 100644 --- a/src/listeners/guilds/members/guildMemberUpdateRolesNotify.ts +++ b/projects/bot/src/listeners/guilds/members/guildMemberUpdateRolesNotify.ts @@ -1,21 +1,18 @@ -import { readSettings } from '#lib/database'; -import { getT } from '#lib/i18n'; +import { GuildSettings, readSettings } from '#lib/database'; import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { Events } from '#lib/types'; +import { Events } from '#lib/types/Enums'; import { Colors } from '#utils/constants'; -import { getFullEmbedAuthor } from '#utils/util'; -import { EmbedBuilder } from '@discordjs/builders'; import { ApplyOptions } from '@sapphire/decorators'; -import { Listener } from '@sapphire/framework'; -import type { TFunction } from '@sapphire/plugin-i18next'; +import { Listener, ListenerOptions } from '@sapphire/framework'; import { isNullish } from '@sapphire/utilities'; -import type { GuildMember } from 'discord.js'; +import { GuildMember, MessageEmbed } from 'discord.js'; +import type { TFunction } from 'i18next'; -@ApplyOptions({ event: Events.GuildMemberUpdate }) +@ApplyOptions({ event: Events.GuildMemberUpdate }) export class UserListener extends Listener { public async run(previous: GuildMember, next: GuildMember) { - const settings = await readSettings(next); - const logChannelId = settings.channelsLogsMemberRolesUpdate; + const key = GuildSettings.Channels.Logs.MemberRoleUpdate; + const [logChannelId, t] = await readSettings(next, (settings) => [settings[key], settings.getLanguage()]); if (isNullish(logChannelId)) return; // Retrieve whether or not role logs should be sent from Guild Settings and @@ -40,11 +37,10 @@ export class UserListener extends Listener { const { user } = next; // Set the Role change log - const t = getT(settings.language); - this.container.client.emit(Events.GuildMessageLog, next.guild, logChannelId, 'channelsLogsMemberRolesUpdate', () => - new EmbedBuilder() + this.container.client.emit(Events.GuildMessageLog, next.guild, logChannelId, key, () => + new MessageEmbed() .setColor(Colors.Yellow) - .setAuthor(getFullEmbedAuthor(user)) + .setAuthor({ name: `${user.tag} (${user.id})`, iconURL: user.displayAvatarURL({ size: 128, format: 'png', dynamic: true }) }) .setDescription(this.getRoleDescription(t, addedRoles, removedRoles) || t(LanguageKeys.Events.Guilds.Members.GuildMemberNoUpdate)) .setFooter({ text: t(LanguageKeys.Events.Guilds.Members.RoleUpdate) }) .setTimestamp() diff --git a/projects/bot/src/listeners/guilds/members/notMutedMemberAddInitialRole.ts b/projects/bot/src/listeners/guilds/members/notMutedMemberAddInitialRole.ts new file mode 100644 index 000000000..2735c9bb5 --- /dev/null +++ b/projects/bot/src/listeners/guilds/members/notMutedMemberAddInitialRole.ts @@ -0,0 +1,27 @@ +import { GuildSettings, readSettings, writeSettings } from '#lib/database'; +import { Events } from '#lib/types/Enums'; +import { ApplyOptions } from '@sapphire/decorators'; +import { Listener, ListenerOptions } from '@sapphire/framework'; +import type { GuildMember } from 'discord.js'; + +@ApplyOptions({ event: Events.NotMutedMemberAdd }) +export class UserListener extends Listener { + public async run(member: GuildMember) { + const [initial, initialHumans, initialBots] = await readSettings(member, [ + GuildSettings.Roles.Initial, + GuildSettings.Roles.InitialHumans, + GuildSettings.Roles.InitialBots + ]); + if (!initial && !initialHumans && !initialBots) return; + + const roleId = initial ?? (member.user.bot ? initialBots : initialHumans); + if (!roleId) return; + + const role = member.guild.roles.cache.get(roleId); + if (role && role.position < member.guild.me!.roles.highest.position) { + return member.roles.add(role); + } + + return writeSettings(member, [[GuildSettings.Roles.Initial, null]]); + } +} diff --git a/projects/bot/src/listeners/guilds/members/notMutedMemberAddNotify.ts b/projects/bot/src/listeners/guilds/members/notMutedMemberAddNotify.ts new file mode 100644 index 000000000..a59d32df8 --- /dev/null +++ b/projects/bot/src/listeners/guilds/members/notMutedMemberAddNotify.ts @@ -0,0 +1,34 @@ +import { GuildSettings, readSettings } from '#lib/database'; +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { Events } from '#lib/types/Enums'; +import { Colors } from '#utils/constants'; +import { ApplyOptions } from '@sapphire/decorators'; +import { Listener, ListenerOptions } from '@sapphire/framework'; +import { isNullish } from '@sapphire/utilities'; +import { GuildMember, MessageEmbed } from 'discord.js'; + +@ApplyOptions({ event: Events.NotMutedMemberAdd }) +export class UserListener extends Listener { + public async run(member: GuildMember) { + const key = GuildSettings.Channels.Logs.MemberAdd; + const [logChannelId, t] = await readSettings(member, (settings) => [settings[key], settings.getLanguage()]); + if (isNullish(logChannelId)) return; + + this.container.client.emit(Events.GuildMessageLog, member.guild, logChannelId, key, () => + new MessageEmbed() + .setColor(Colors.Green) + .setAuthor({ + name: `${member.user.tag} (${member.user.id})`, + iconURL: member.user.displayAvatarURL({ size: 128, format: 'png', dynamic: true }) + }) + .setDescription( + t(LanguageKeys.Events.Guilds.Members.GuildMemberAddDescription, { + mention: member.toString(), + time: Date.now() - member.user.createdTimestamp + }) + ) + .setFooter({ text: t(LanguageKeys.Events.Guilds.Members.GuildMemberAdd) }) + .setTimestamp() + ); + } +} diff --git a/src/listeners/guilds/members/rawGuildMemberRemove.ts b/projects/bot/src/listeners/guilds/members/rawGuildMemberRemove.ts similarity index 57% rename from src/listeners/guilds/members/rawGuildMemberRemove.ts rename to projects/bot/src/listeners/guilds/members/rawGuildMemberRemove.ts index 35e430b40..92db8b754 100644 --- a/src/listeners/guilds/members/rawGuildMemberRemove.ts +++ b/projects/bot/src/listeners/guilds/members/rawGuildMemberRemove.ts @@ -1,9 +1,9 @@ -import { Events } from '#lib/types'; +import { Events } from '#lib/types/Enums'; import { ApplyOptions } from '@sapphire/decorators'; -import { Listener } from '@sapphire/framework'; -import { GatewayDispatchEvents, type GatewayGuildMemberRemoveDispatch } from 'discord.js'; +import { Listener, ListenerOptions } from '@sapphire/framework'; +import { GatewayDispatchEvents, GatewayGuildMemberRemoveDispatch } from 'discord-api-types/v9'; -@ApplyOptions({ event: GatewayDispatchEvents.GuildMemberRemove, emitter: 'ws' }) +@ApplyOptions({ event: GatewayDispatchEvents.GuildMemberRemove, emitter: 'ws' }) export class UserListener extends Listener { public run(data: GatewayGuildMemberRemoveDispatch['d']) { const guild = this.container.client.guilds.cache.get(data.guild_id); diff --git a/src/listeners/guilds/members/rawGuildMemberUpdate.ts b/projects/bot/src/listeners/guilds/members/rawGuildMemberUpdate.ts similarity index 61% rename from src/listeners/guilds/members/rawGuildMemberUpdate.ts rename to projects/bot/src/listeners/guilds/members/rawGuildMemberUpdate.ts index 14ad2ac1d..6fe1dcb65 100644 --- a/src/listeners/guilds/members/rawGuildMemberUpdate.ts +++ b/projects/bot/src/listeners/guilds/members/rawGuildMemberUpdate.ts @@ -1,41 +1,37 @@ -import { readSettings } from '#lib/database'; +import { GuildSettings, readSettings } from '#lib/database'; import { api } from '#lib/discord/Api'; import { floatPromise } from '#utils/common'; import { ApplyOptions } from '@sapphire/decorators'; -import { Listener } from '@sapphire/framework'; -import { isNullish } from '@sapphire/utilities'; +import { Listener, ListenerOptions } from '@sapphire/framework'; import { AuditLogEvent, GatewayDispatchEvents, - PermissionFlagsBits, - type GatewayGuildMemberUpdateDispatchData, - type Guild, - type RESTGetAPIAuditLogResult -} from 'discord.js'; + GatewayGuildMemberUpdateDispatch, + RESTGetAPIAuditLogQuery, + RESTGetAPIAuditLogResult +} from 'discord-api-types/v9'; +import { Guild, Permissions } from 'discord.js'; -type GatewayData = Readonly; - -@ApplyOptions({ event: GatewayDispatchEvents.GuildMemberUpdate, emitter: 'ws' }) +@ApplyOptions({ event: GatewayDispatchEvents.GuildMemberUpdate, emitter: 'ws' }) export class UserListener extends Listener { - private readonly requiredPermissions = PermissionFlagsBits.ViewAuditLog; + private readonly requiredPermissions = new Permissions(Permissions.FLAGS.VIEW_AUDIT_LOG); - public run(data: GatewayData) { + public run(data: GatewayGuildMemberUpdateDispatch['d']) { const guild = this.container.client.guilds.cache.get(data.guild_id); // If the guild does not exist for some reason, skip: - if (isNullish(guild)) return; + if (typeof guild === 'undefined') return; // If the bot doesn't have the required permissions, skip: - if (!guild.members.me?.permissions.has(this.requiredPermissions)) return; + if (!guild.me?.permissions.has(this.requiredPermissions)) return; floatPromise(this.handleRoleSets(guild, data)); } - private async handleRoleSets(guild: Guild, data: GatewayData) { + private async handleRoleSets(guild: Guild, data: Readonly) { // Handle unique role sets let hasMultipleRolesInOneSet = false; - const settings = await readSettings(guild); - const allRoleSets = settings.rolesUniqueRoleSets; + const allRoleSets = await readSettings(guild, GuildSettings.Roles.UniqueRoleSets); // First check if the user has multiple roles from a set for (const set of allRoleSets) { @@ -57,12 +53,15 @@ export class UserListener extends Listener { // If the user does not have multiple roles from any set cancel if (!hasMultipleRolesInOneSet) return; - const auditLogs = await api().guilds.getAuditLogs(guild.id, { + const query: RESTGetAPIAuditLogQuery = { limit: 10, action_type: AuditLogEvent.MemberRoleUpdate + }; + const auditLogs = await api().guilds(guild.id)['audit-logs'].get({ + query }); - const updatedRoleId = this.getChange(auditLogs, data.user.id); + const updatedRoleId = this.getChange(auditLogs, data.user!.id); if (updatedRoleId === null) return; let memberRoles = data.roles; @@ -70,13 +69,16 @@ export class UserListener extends Listener { if (set.roles.includes(updatedRoleId)) memberRoles = memberRoles.filter((id) => !set.roles.includes(id) || id === updatedRoleId); } - await api().guilds.editMember(guild.id, data.user.id, { roles: memberRoles }, { reason: 'Automatic Role Set Modification' }); + await api() + .guilds(guild.id) + .members(data.user!.id) + .patch({ data: { roles: memberRoles }, reason: 'Automatic Role Group Modification' }); } private getChange(results: RESTGetAPIAuditLogResult, userId: string): string | null { // Scan the audit logs. for (const result of results.audit_log_entries) { - // If it was given by Wolf, continue. + // If it was given by Skyra, continue. if (result.user_id === process.env.CLIENT_ID) continue; // If the target isn't the edited user, continue. diff --git a/projects/bot/src/listeners/guilds/members/rawMemberRemoveNotify.ts b/projects/bot/src/listeners/guilds/members/rawMemberRemoveNotify.ts new file mode 100644 index 000000000..0542dcf52 --- /dev/null +++ b/projects/bot/src/listeners/guilds/members/rawMemberRemoveNotify.ts @@ -0,0 +1,84 @@ +import { GuildSettings, readSettings } from '#lib/database'; +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { Events } from '#lib/types/Enums'; +import { Colors } from '#utils/constants'; +import { getModeration } from '#utils/functions'; +import { TypeCodes } from '#utils/moderationConstants'; +import { getDisplayAvatar } from '#utils/util'; +import { ApplyOptions } from '@sapphire/decorators'; +import { Listener, ListenerOptions } from '@sapphire/framework'; +import { isNullish } from '@sapphire/utilities'; +import type { GatewayGuildMemberRemoveDispatch } from 'discord-api-types/v9'; +import { Guild, GuildMember, MessageEmbed } from 'discord.js'; + +@ApplyOptions({ event: Events.RawMemberRemove }) +export class UserListener extends Listener { + public async run(guild: Guild, member: GuildMember | null, { user }: GatewayGuildMemberRemoveDispatch['d']) { + const key = GuildSettings.Channels.Logs.MemberRemove; + const [logChannelId, t] = await readSettings(guild, (settings) => [settings[key], settings.getLanguage()]); + if (isNullish(logChannelId)) return; + + const isModerationAction = await this.isModerationAction(guild, user); + + const footer = isModerationAction.kicked + ? t(LanguageKeys.Events.Guilds.Members.GuildMemberKicked) + : isModerationAction.banned + ? t(LanguageKeys.Events.Guilds.Members.GuildMemberBanned) + : isModerationAction.softbanned + ? t(LanguageKeys.Events.Guilds.Members.GuildMemberSoftBanned) + : t(LanguageKeys.Events.Guilds.Members.GuildMemberRemove); + + const time = this.processJoinedTimestamp(member); + this.container.client.emit(Events.GuildMessageLog, guild, logChannelId, key, () => + new MessageEmbed() + .setColor(Colors.Red) + .setAuthor({ name: `${user.username}#${user.discriminator} (${user.id})`, iconURL: getDisplayAvatar(user.id, user) }) + .setDescription( + t( + time === -1 + ? LanguageKeys.Events.Guilds.Members.GuildMemberRemoveDescription + : LanguageKeys.Events.Guilds.Members.GuildMemberRemoveDescriptionWithJoinedAt, + { + mention: `<@${user.id}>`, + time + } + ) + ) + .setFooter({ text: footer }) + .setTimestamp() + ); + } + + private async isModerationAction(guild: Guild, user: GatewayGuildMemberRemoveDispatch['d']['user']): Promise { + const moderation = getModeration(guild); + await moderation.waitLock(); + + const latestLogForUser = moderation.getLatestLogForUser(user.id); + + if (latestLogForUser === null) { + return { + kicked: false, + banned: false, + softbanned: false + }; + } + + return { + kicked: latestLogForUser.isType(TypeCodes.Kick), + banned: latestLogForUser.isType(TypeCodes.Ban), + softbanned: latestLogForUser.isType(TypeCodes.SoftBan) + }; + } + + private processJoinedTimestamp(member: GuildMember | null) { + if (member === null) return -1; + if (member.joinedTimestamp === null) return -1; + return Date.now() - member.joinedTimestamp; + } +} + +interface IsModerationAction { + readonly kicked: boolean; + readonly banned: boolean; + readonly softbanned: boolean; +} diff --git a/src/listeners/guilds/messages/guildUserMessageImageNotify.ts b/projects/bot/src/listeners/guilds/messages/guildUserMessageImageNotify.ts similarity index 60% rename from src/listeners/guilds/messages/guildUserMessageImageNotify.ts rename to projects/bot/src/listeners/guilds/messages/guildUserMessageImageNotify.ts index e6265327f..20121bde3 100644 --- a/src/listeners/guilds/messages/guildUserMessageImageNotify.ts +++ b/projects/bot/src/listeners/guilds/messages/guildUserMessageImageNotify.ts @@ -1,27 +1,24 @@ -import { readSettings } from '#lib/database'; -import { getT } from '#lib/i18n'; +import { GuildSettings, readSettings } from '#lib/database'; import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { Events, type GuildMessage } from '#lib/types'; +import type { GuildMessage } from '#lib/types'; +import { Events } from '#lib/types/Enums'; import { Colors } from '#utils/constants'; -import { getLogPrefix } from '#utils/functions'; -import { getFullEmbedAuthor } from '#utils/util'; -import { EmbedBuilder } from '@discordjs/builders'; +import { IMAGE_EXTENSION } from '#utils/util'; import { ApplyOptions } from '@sapphire/decorators'; -import { FetchResultTypes, fetch } from '@sapphire/fetch'; -import { Listener } from '@sapphire/framework'; -import { isNullish, isNullishOrEmpty, isNullishOrZero, isNumber } from '@sapphire/utilities'; -import { AttachmentBuilder, type MessageCreateOptions, type TextChannel } from 'discord.js'; +import { fetch, FetchResultTypes } from '@sapphire/fetch'; +import { Listener, ListenerOptions } from '@sapphire/framework'; +import { isNullish, isNumber } from '@sapphire/utilities'; +import { MessageAttachment, MessageEmbed, MessageOptions, TextChannel } from 'discord.js'; import { extname } from 'node:path'; +import { URL } from 'node:url'; const MAXIMUM_SIZE = 300; // 1024 = 1 kilobyte // 1024 * 1024 = 1 megabyte const MAXIMUM_LENGTH = 1024 * 1024; -@ApplyOptions({ event: Events.GuildUserMessage }) +@ApplyOptions({ event: Events.GuildUserMessage }) export class UserListener extends Listener { - private readonly LogPrefix = getLogPrefix(this); - public async run(message: GuildMessage) { // If there are no attachments, do not post: if (message.attachments.size === 0) return; @@ -29,33 +26,35 @@ export class UserListener extends Listener { // If the message was edited, do not repost: if (message.editedTimestamp) return; - const settings = await readSettings(message.guild); - const logChannelId = settings.channelsLogsImage; - if (isNullish(logChannelId) || settings.channelsIgnoreAll.includes(message.channel.id)) return; + const key = GuildSettings.Channels.Logs.Image; + const [logChannelId, ignoredChannels, t] = await readSettings(message.guild, (settings) => [ + settings[key], + settings[GuildSettings.Channels.Ignore.All], + settings.getLanguage() + ]); + if (isNullish(logChannelId) || ignoredChannels.includes(message.channel.id)) return; - const t = getT(settings.language); - for (const attachment of this.getAttachments(message)) { - const dimensions = this.getDimensions(attachment.width, attachment.height); + for (const image of this.getAttachments(message)) { + const dimensions = this.getDimensions(image.width, image.height); // Create a new image url with search params. - const url = new URL(attachment.proxyURL); + const url = new URL(image.proxyURL); url.searchParams.append('width', dimensions.width.toString()); url.searchParams.append('height', dimensions.height.toString()); - if (attachment.kind === 'video') url.searchParams.append('format', 'webp'); // Fetch the image. const result = await fetch(url, FetchResultTypes.Result).catch((error) => { - this.container.logger.error(`${this.LogPrefix} ${url} ${error}`); + this.container.logger.error(`ImageLogs[${error}] ${url}`); return null; }); if (result === null) continue; // Retrieve the content length. const contentLength = result.headers.get('content-length'); - if (isNullishOrEmpty(contentLength)) continue; + if (contentLength === null) continue; // Parse the content length, validate it, and check if it's lower than the threshold. - const parsedContentLength = Number.parseInt(contentLength, 10); + const parsedContentLength = parseInt(contentLength, 10); if (!isNumber(parsedContentLength)) continue; if (parsedContentLength > MAXIMUM_LENGTH) continue; @@ -64,35 +63,31 @@ export class UserListener extends Listener { const buffer = Buffer.from(await (await result.blob()).arrayBuffer()); const filename = `image${extname(url.pathname)}`; - this.container.client.emit(Events.GuildMessageLog, message.guild, logChannelId, 'channelsLogsImage', (): MessageCreateOptions => { - const embed = new EmbedBuilder() + this.container.client.emit(Events.GuildMessageLog, message.guild, logChannelId, key, (): MessageOptions => { + const embed = new MessageEmbed() .setColor(Colors.Yellow) - .setAuthor(getFullEmbedAuthor(message.author, message.url)) + .setAuthor({ + name: `${message.author.tag} (${message.author.id})`, + iconURL: message.author.displayAvatarURL({ size: 128, format: 'png', dynamic: true }) + }) .setDescription(`[${t(LanguageKeys.Misc.JumpTo)}](${message.url})`) .setFooter({ text: `#${(message.channel as TextChannel).name}` }) .setImage(`attachment://${filename}`) .setTimestamp(); - return { embeds: [embed], files: [new AttachmentBuilder(buffer, { name: filename })] }; + return { embeds: [embed], files: [new MessageAttachment(buffer, filename)] }; }); } catch (error) { - this.container.logger.fatal(`${this.LogPrefix} ${url} ${error}`); + this.container.logger.fatal(`ImageLogs[${error}] ${url}`); } } } private *getAttachments(message: GuildMessage) { for (const attachment of message.attachments.values()) { - // Skip if the attachment doesn't have a content type: - if (isNullishOrEmpty(attachment.contentType)) continue; - // Skip if the attachment doesn't have a size: - if (isNullishOrZero(attachment.width) || isNullishOrZero(attachment.height)) continue; - - const [kind] = attachment.contentType.split('/', 1); - if (kind !== 'image' && kind !== 'video') continue; + if (!IMAGE_EXTENSION.test(attachment.url)) continue; yield { - kind: kind as 'image' | 'video', url: attachment.url, proxyURL: attachment.proxyURL, height: attachment.height!, diff --git a/projects/bot/src/listeners/guilds/messages/guildUserMessagePointsHandler.ts b/projects/bot/src/listeners/guilds/messages/guildUserMessagePointsHandler.ts new file mode 100644 index 000000000..8c4100d7d --- /dev/null +++ b/projects/bot/src/listeners/guilds/messages/guildUserMessagePointsHandler.ts @@ -0,0 +1,59 @@ +import { GuildEntity, GuildSettings, readSettings } from '#lib/database'; +import type { GuildMessage } from '#lib/types'; +import { Events } from '#lib/types/Enums'; +import { minutes } from '#utils/common'; +import { ApplyOptions } from '@sapphire/decorators'; +import { Listener, ListenerOptions } from '@sapphire/framework'; +import { RateLimitManager } from '@sapphire/ratelimits'; +import { hasAtLeastOneKeyInMap } from '@sapphire/utilities'; + +@ApplyOptions({ event: Events.GuildUserMessage }) +export class UserListener extends Listener { + private readonly rateLimits = new RateLimitManager(minutes(1), 1); + + public async run(message: GuildMessage) { + const [enabled, multiplier] = await readSettings(message.guild, (settings) => [ + this.isEnabled(message, settings), + settings[GuildSettings.Social.Multiplier] + ]); + + if (!enabled) return; + if (this.isRateLimited(message.author.id)) return; + + // If boosted guild, increase rewards + const set = this.container.db; + const { guildBoost } = await set.clients.ensure(); + const add = Math.round((Math.random() * 4 + 4) * (guildBoost.includes(message.guild.id) ? 1.5 : 1)); + + this.container.client.emit(Events.GuildUserMessageSocialPointsAddUser, message, Math.round(add)); + this.container.client.emit(Events.GuildUserMessageSocialPointsAddMember, message, Math.round(add * multiplier)); + } + + /** + * Checks whether or not the settings enable running the handler for the specified message. + * @param message The message that ran the event. + * @param settings The settings to check the data from. + * @returns Whether or not the handler should run. + */ + private isEnabled(message: GuildMessage, settings: GuildEntity) { + // If the social module is not enabled, return false: + if (!settings[GuildSettings.Social.Enabled]) return false; + + // If the channel is ignored, return false: + if (settings[GuildSettings.Social.IgnoredChannels].includes(message.channel.id)) return false; + + // If the role is ignored, return false: + if (hasAtLeastOneKeyInMap(message.member.roles.cache, settings[GuildSettings.Social.IgnoredRoles])) return false; + + // Else, it's enabled, return true + return true; + } + + private isRateLimited(userId: string) { + const rateLimit = this.rateLimits.acquire(userId); + if (rateLimit.limited) return true; + + rateLimit.consume(); + return false; + } +} diff --git a/projects/bot/src/listeners/guilds/messages/guildUserMessageSocialPointsAddMember.ts b/projects/bot/src/listeners/guilds/messages/guildUserMessageSocialPointsAddMember.ts new file mode 100644 index 000000000..7f917e1e7 --- /dev/null +++ b/projects/bot/src/listeners/guilds/messages/guildUserMessageSocialPointsAddMember.ts @@ -0,0 +1,24 @@ +import type { Difference, GuildMessage } from '#lib/types'; +import { Events } from '#lib/types/Enums'; +import { ApplyOptions } from '@sapphire/decorators'; +import { Listener, ListenerOptions } from '@sapphire/framework'; + +@ApplyOptions({ event: Events.GuildUserMessageSocialPointsAddMember }) +export class UserListener extends Listener { + public async run(message: GuildMessage, add: number) { + const difference = await this.addPoints(message.author.id, message.guild.id, add); + this.container.client.emit(Events.GuildUserMessageSocialPointsAddMemberReward, message, difference); + } + + private async addPoints(userId: string, guildId: string, points: number): Promise> { + const member = await this.container.db.members.ensure(userId, guildId); + + const previous = member.points ?? 0; + const next = previous + points; + + member.points = next; + await member.save(); + + return { previous, next }; + } +} diff --git a/projects/bot/src/listeners/guilds/messages/guildUserMessageSocialPointsAddMemberRewardLevel.ts b/projects/bot/src/listeners/guilds/messages/guildUserMessageSocialPointsAddMemberRewardLevel.ts new file mode 100644 index 000000000..e5c5e4085 --- /dev/null +++ b/projects/bot/src/listeners/guilds/messages/guildUserMessageSocialPointsAddMemberRewardLevel.ts @@ -0,0 +1,96 @@ +import { GuildEntity, GuildSettings, readSettings, writeSettings } from '#lib/database'; +import type { Difference, GuildMessage } from '#lib/types'; +import { Events } from '#lib/types/Enums'; +import { formatNumber } from '#utils/functions'; +import { ApplyOptions } from '@sapphire/decorators'; +import type { GuildTextBasedChannelTypes } from '@sapphire/discord.js-utilities'; +import { Listener, ListenerOptions } from '@sapphire/framework'; +import { isNullishOrEmpty } from '@sapphire/utilities'; +import type { GuildMember } from 'discord.js'; +import type { TFunction } from 'i18next'; + +@ApplyOptions({ event: Events.GuildUserMessageSocialPointsAddMemberReward }) +export class UserListener extends Listener { + private readonly regExp = /{((?:user|member)(?:\.(?:id|(?:user)?name|discriminator|tag))?|(?:guild|server)(?:\.(?:id|name))?|points|level)}/g; + public async run(message: GuildMessage, difference: Difference) { + const previousLevel = this.getLevelFromPoints(difference.previous); + const nextLevel = this.getLevelFromPoints(difference.next); + + if (previousLevel === nextLevel) return; + + const points = difference.next; + const information = await readSettings(message.guild, (settings) => this.getInformation(settings)); + if (!information.announce) return; + if (nextLevel % information.multiple !== 0) return; + + const channel = await this.ensureChannel(message, information.channel); + if (channel === null) return; + + const content = this.getMessage(information.t, message.member, information.content, points); + await channel.send({ content, allowedMentions: { roles: [], users: [message.author.id] } }); + } + + private getInformation(settings: GuildEntity) { + const content = settings[GuildSettings.Social.AchieveLevel]; + if (isNullishOrEmpty(content)) return { announce: false } as const; + + return { + announce: true, + content, + channel: settings[GuildSettings.Social.AchieveChannel] ?? null, + multiple: settings[GuildSettings.Social.AchieveMultiple] ?? 1, + t: settings.getLanguage() + } as const; + } + + private async ensureChannel(message: GuildMessage, channelId: string | null): Promise { + if (channelId === null) return message.channel; + + const channels = message.guild.channels.cache; + const channel = channels.get(channelId) as GuildTextBasedChannelTypes | undefined; + if (channel !== undefined) return channel; + + await writeSettings(message.guild, [[GuildSettings.Social.AchieveChannel, null]]); + return message.channel; + } + + private getMessage(t: TFunction, member: GuildMember, content: string, points: number) { + return content.replace(this.regExp, (match, value) => { + switch (value) { + case 'user': + case 'member': + return member.toString(); + case 'user.id': + case 'member.id': + return member.id; + case 'user.name': + case 'user.username': + case 'member.username': + return member.user.username; + case 'member.name': + return member.displayName; + case 'user.tag': + case 'member.tag': + return member.user.tag; + case 'server': + case 'server.name': + case 'guild': + case 'guild.name': + return member.guild.name; + case 'server.id': + case 'guild.id': + return member.guild.id; + case 'points': + return formatNumber(t, points); + case 'level': + return formatNumber(t, this.getLevelFromPoints(points)); + default: + return match; + } + }); + } + + private getLevelFromPoints(points: number): number { + return Math.floor(0.2 * Math.sqrt(points)); + } +} diff --git a/projects/bot/src/listeners/guilds/messages/guildUserMessageSocialPointsAddMemberRewardRole.ts b/projects/bot/src/listeners/guilds/messages/guildUserMessageSocialPointsAddMemberRewardRole.ts new file mode 100644 index 000000000..f693011db --- /dev/null +++ b/projects/bot/src/listeners/guilds/messages/guildUserMessageSocialPointsAddMemberRewardRole.ts @@ -0,0 +1,140 @@ +import { GuildEntity, GuildSettings, readSettings, RolesAuto, writeSettings } from '#lib/database'; +import type { Difference, GuildMessage } from '#lib/types'; +import { Events } from '#lib/types/Enums'; +import { formatNumber } from '#utils/functions'; +import { ApplyOptions } from '@sapphire/decorators'; +import type { GuildTextBasedChannelTypes } from '@sapphire/discord.js-utilities'; +import { Listener, ListenerOptions } from '@sapphire/framework'; +import { isNullishOrEmpty } from '@sapphire/utilities'; +import { GuildMember, Permissions, Role } from 'discord.js'; +import type { TFunction } from 'i18next'; + +const { FLAGS } = Permissions; + +@ApplyOptions({ event: Events.GuildUserMessageSocialPointsAddMemberReward }) +export class UserListener extends Listener { + private readonly regExp = + /{(role(?:\.(?:id|name|position|colou?r))?|(?:user|member)(?:\.(?:id|(?:user)?name|discriminator|tag))?|(?:guild|server)(?:\.(?:id|name))?|points|level)}/g; + + public async run(message: GuildMessage, difference: Difference) { + if (!message.guild.me!.permissions.has(FLAGS.MANAGE_ROLES)) return; + + const points = difference.next; + const information = await readSettings(message.guild, (settings) => this.getInformation(settings, points)); + if (information === null) return; + + const role = await this.ensureRole(message, points, information.role); + if (role === null) return; + if (role.position >= message.guild.me!.roles.highest.position) return; + if (message.member.roles.cache.has(role.id)) return; + await message.member.roles.add(role); + + if (!information.announce) return; + const channel = await this.ensureChannel(message, information.channel); + if (channel === null) return; + + const content = this.getMessage(information.t, message.member, role, information.content, points); + await channel.send({ content, allowedMentions: { roles: [], users: [message.author.id] } }); + } + + private getInformation(settings: GuildEntity, points: number) { + const role = this.getNextRole(settings, points); + if (role === null) return null; + + const content = settings[GuildSettings.Social.AchieveRole]; + if (isNullishOrEmpty(content)) return { announce: false, role } as const; + + return { + announce: true, + role, + content, + channel: settings[GuildSettings.Social.AchieveChannel] ?? null, + t: settings.getLanguage() + } as const; + } + + private getNextRole(settings: GuildEntity, points: number): RolesAuto | null { + let latest: RolesAuto | null = null; + for (const role of settings[GuildSettings.Roles.Auto]) { + if (role.points > points) break; + latest = role; + } + + return latest; + } + + private async ensureRole(message: GuildMessage, points: number, autoRole: RolesAuto): Promise { + const roles = message.guild.roles.cache; + const role = roles.get(autoRole.id); + if (role !== undefined) return role; + + const fallbackAutoRole = await writeSettings(message.guild, (settings) => { + settings[GuildSettings.Roles.Auto] = settings[GuildSettings.Roles.Auto].filter((entry) => roles.has(entry.id)); + return this.getNextRole(settings, points); + }); + if (fallbackAutoRole === null) return null; + return roles.get(fallbackAutoRole.id) ?? null; + } + + private async ensureChannel(message: GuildMessage, channelId: string | null): Promise { + if (channelId === null) return message.channel; + + const channels = message.guild.channels.cache; + const channel = channels.get(channelId) as GuildTextBasedChannelTypes | undefined; + if (channel !== undefined) return channel; + + await writeSettings(message.guild, [[GuildSettings.Social.AchieveChannel, null]]); + return message.channel; + } + + private getMessage(t: TFunction, member: GuildMember, role: Role, content: string, points: number) { + return content.replace(this.regExp, (match, value) => { + switch (value) { + case 'role': + return role.toString(); + case 'role.id': + return role.id; + case 'role.name': + return role.name; + case 'role.position': + return formatNumber(t, role.position); + case 'role.color': + case 'role.colour': + return role.hexColor; + case 'user': + case 'member': + return member.toString(); + case 'user.id': + case 'member.id': + return member.id; + case 'user.name': + case 'user.username': + case 'member.username': + return member.user.username; + case 'member.name': + return member.displayName; + case 'user.tag': + case 'member.tag': + return member.user.tag; + case 'server': + case 'server.name': + case 'guild': + case 'guild.name': + return member.guild.name; + case 'server.id': + case 'guild.id': + return member.guild.id; + case 'points': + return formatNumber(t, points); + case 'level': + return formatNumber(t, this.getLevelFromPoints(points)); + default: + return match; + } + }); + } + + private getLevelFromPoints(points: number): number { + return Math.floor(0.2 * Math.sqrt(points)); + } +} diff --git a/projects/bot/src/listeners/guilds/messages/guildUserMessageSocialPointsAddUser.ts b/projects/bot/src/listeners/guilds/messages/guildUserMessageSocialPointsAddUser.ts new file mode 100644 index 000000000..db2c864f7 --- /dev/null +++ b/projects/bot/src/listeners/guilds/messages/guildUserMessageSocialPointsAddUser.ts @@ -0,0 +1,16 @@ +import type { GuildMessage } from '#lib/types'; +import { Events } from '#lib/types/Enums'; +import { ApplyOptions } from '@sapphire/decorators'; +import { Listener, ListenerOptions } from '@sapphire/framework'; + +@ApplyOptions({ event: Events.GuildUserMessageSocialPointsAddUser }) +export class UserListener extends Listener { + public async run(message: GuildMessage, points: number) { + const { users } = this.container.db; + await users.lock([message.author.id], async (id) => { + const user = await users.ensure(id); + user.points += points; + await user.save(); + }); + } +} diff --git a/projects/bot/src/listeners/guilds/rawGuildCreateMemberFetch.ts b/projects/bot/src/listeners/guilds/rawGuildCreateMemberFetch.ts new file mode 100644 index 000000000..65411897f --- /dev/null +++ b/projects/bot/src/listeners/guilds/rawGuildCreateMemberFetch.ts @@ -0,0 +1,10 @@ +import { ApplyOptions } from '@sapphire/decorators'; +import { Listener, ListenerOptions } from '@sapphire/framework'; +import { GatewayDispatchEvents, GatewayGuildCreateDispatch } from 'discord-api-types/v9'; + +@ApplyOptions({ event: GatewayDispatchEvents.GuildCreate, emitter: 'ws' }) +export class UserListener extends Listener { + public run(data: GatewayGuildCreateDispatch['d'], shardId: number) { + this.container.client.guildMemberFetchQueue.add(shardId, data.id); + } +} diff --git a/projects/bot/src/listeners/guilds/rawGuildDelete.ts b/projects/bot/src/listeners/guilds/rawGuildDelete.ts new file mode 100644 index 000000000..5e8b16f5a --- /dev/null +++ b/projects/bot/src/listeners/guilds/rawGuildDelete.ts @@ -0,0 +1,12 @@ +import { ApplyOptions } from '@sapphire/decorators'; +import { Listener, ListenerOptions } from '@sapphire/framework'; +import { GatewayDispatchEvents, GatewayGuildDeleteDispatch } from 'discord-api-types/v9'; + +@ApplyOptions({ event: GatewayDispatchEvents.GuildDelete, emitter: 'ws' }) +export class UserListener extends Listener { + public run(data: GatewayGuildDeleteDispatch['d']) { + if (data.unavailable) return; + + this.container.settings.guilds.delete(data.id); + } +} diff --git a/projects/bot/src/listeners/guilds/rawGuildDeleteMemberFetch.ts b/projects/bot/src/listeners/guilds/rawGuildDeleteMemberFetch.ts new file mode 100644 index 000000000..24d241a00 --- /dev/null +++ b/projects/bot/src/listeners/guilds/rawGuildDeleteMemberFetch.ts @@ -0,0 +1,10 @@ +import { ApplyOptions } from '@sapphire/decorators'; +import { Listener, ListenerOptions } from '@sapphire/framework'; +import { GatewayDispatchEvents, GatewayGuildDeleteDispatch } from 'discord-api-types/v9'; + +@ApplyOptions({ event: GatewayDispatchEvents.GuildDelete, emitter: 'ws' }) +export class UserListener extends Listener { + public run(data: GatewayGuildDeleteDispatch['d'], shardId: number) { + this.container.client.guildMemberFetchQueue.remove(shardId, data.id); + } +} diff --git a/src/listeners/guilds/roles/roleCreateNotify.ts b/projects/bot/src/listeners/guilds/roles/roleCreateNotify.ts similarity index 68% rename from src/listeners/guilds/roles/roleCreateNotify.ts rename to projects/bot/src/listeners/guilds/roles/roleCreateNotify.ts index d65cddd9d..9f6ee4129 100644 --- a/src/listeners/guilds/roles/roleCreateNotify.ts +++ b/projects/bot/src/listeners/guilds/roles/roleCreateNotify.ts @@ -1,33 +1,29 @@ -import { readSettings, writeSettings } from '#lib/database'; -import { getT } from '#lib/i18n'; +import { GuildSettings, readSettings, writeSettings } from '#lib/database'; import { LanguageKeys } from '#lib/i18n/languageKeys'; import { toPermissionsArray } from '#utils/bits'; import { Colors } from '#utils/constants'; -import { EmbedBuilder } from '@discordjs/builders'; import { ApplyOptions } from '@sapphire/decorators'; -import { Events, Listener } from '@sapphire/framework'; -import type { TFunction } from '@sapphire/plugin-i18next'; +import { Events, Listener, ListenerOptions } from '@sapphire/framework'; import { isNullish } from '@sapphire/utilities'; -import type { Role, TextChannel } from 'discord.js'; +import { MessageEmbed, Role, TextChannel } from 'discord.js'; +import type { TFunction } from 'i18next'; -@ApplyOptions({ event: Events.GuildRoleCreate }) +@ApplyOptions({ event: Events.GuildRoleCreate }) export class UserListener extends Listener { public async run(next: Role) { - const settings = await readSettings(next); - const channelId = settings.channelsLogsRoleCreate; + const [channelId, t] = await readSettings(next, (settings) => [settings[GuildSettings.Channels.Logs.RoleCreate], settings.getLanguage()]); if (isNullish(channelId)) return; const channel = next.guild.channels.cache.get(channelId) as TextChannel | undefined; if (channel === undefined) { - await writeSettings(next, { channelsLogsRoleCreate: null }, next.client.user!.id); + await writeSettings(next, [[GuildSettings.Channels.Logs.RoleCreate, null]]); return; } - const t = getT(settings.language); const changes: string[] = [...this.getRoleInformation(t, next)]; - const embed = new EmbedBuilder() + const embed = new MessageEmbed() .setColor(Colors.Green) - .setAuthor({ name: `${next.name} (${next.id})`, iconURL: channel.guild.iconURL({ size: 64, extension: 'png' }) ?? undefined }) + .setAuthor({ name: `${next.name} (${next.id})`, iconURL: channel.guild.iconURL({ size: 64, format: 'png', dynamic: true }) ?? undefined }) .setDescription(changes.join('\n')) .setFooter({ text: t(LanguageKeys.Events.Guilds.Logs.RoleCreate) }) .setTimestamp(); diff --git a/projects/bot/src/listeners/guilds/roles/roleDelete.ts b/projects/bot/src/listeners/guilds/roles/roleDelete.ts new file mode 100644 index 000000000..d02a91cdc --- /dev/null +++ b/projects/bot/src/listeners/guilds/roles/roleDelete.ts @@ -0,0 +1,55 @@ +import { writeSettings } from '#lib/database'; +import { Listener } from '@sapphire/framework'; +import type { Role } from 'discord.js'; + +export class UserListener extends Listener { + public run(role: Role) { + if (!role.guild.available) return; + + return writeSettings(role, (settings) => { + for (const stickyRole of settings.stickyRoles) { + stickyRole.roles = stickyRole.roles.filter((srr) => srr !== role.id); + } + + settings.stickyRoles = settings.stickyRoles.filter((sr) => Boolean(sr.roles.length)); + + for (const uniqueRoleSet of settings.rolesUniqueRoleSets) { + uniqueRoleSet.roles = uniqueRoleSet.roles.filter((urs) => urs !== role.id); + } + + settings.rolesUniqueRoleSets = settings.rolesUniqueRoleSets.filter((sr) => Boolean(sr.roles.length)); + + settings.reactionRoles = settings.reactionRoles.filter((rr) => rr.role !== role.id); + settings.rolesAuto = settings.rolesAuto.filter((ra) => ra.id !== role.id); + settings.rolesModerator = settings.rolesModerator.filter((rm) => rm !== role.id); + settings.rolesAdmin = settings.rolesAdmin.filter((rm) => rm !== role.id); + settings.rolesPublic = settings.rolesPublic.filter((rm) => rm !== role.id); + + settings.selfmodAttachmentsIgnoredRoles = settings.selfmodAttachmentsIgnoredRoles.filter((rm) => rm !== role.id); + settings.selfmodCapitalsIgnoredRoles = settings.selfmodCapitalsIgnoredRoles.filter((rm) => rm !== role.id); + settings.selfmodLinksIgnoredRoles = settings.selfmodLinksIgnoredRoles.filter((rm) => rm !== role.id); + settings.selfmodMessagesIgnoredRoles = settings.selfmodMessagesIgnoredRoles.filter((rm) => rm !== role.id); + settings.selfmodNewlinesIgnoredRoles = settings.selfmodNewlinesIgnoredRoles.filter((rm) => rm !== role.id); + settings.selfmodInvitesIgnoredRoles = settings.selfmodInvitesIgnoredRoles.filter((rm) => rm !== role.id); + settings.selfmodFilterIgnoredRoles = settings.selfmodFilterIgnoredRoles.filter((rm) => rm !== role.id); + settings.selfmodReactionsIgnoredRoles = settings.selfmodReactionsIgnoredRoles.filter((rm) => rm !== role.id); + + if (settings.rolesInitial === role.id) settings.rolesInitial = null; + if (settings.rolesInitialHumans === role.id) settings.rolesInitialHumans = null; + if (settings.rolesInitialBots === role.id) settings.rolesInitialBots = null; + if (settings.rolesMuted === role.id) settings.rolesMuted = null; + + if (settings.rolesRestrictedReaction === role.id) settings.rolesRestrictedReaction = null; + if (settings.rolesRestrictedEmbed === role.id) settings.rolesRestrictedEmbed = null; + + if (settings.rolesRestrictedEmoji === role.id) settings.rolesRestrictedEmoji = null; + if (settings.rolesRestrictedAttachment === role.id) settings.rolesRestrictedAttachment = null; + + if (settings.rolesRestrictedVoice === role.id) settings.rolesRestrictedVoice = null; + + if (this.container.settings.guilds.get(role.guild.id)?.permissionNodes.has(role.id)) { + settings.permissionNodes.refresh(); + } + }); + } +} diff --git a/projects/bot/src/listeners/guilds/roles/roleDeleteNotify.ts b/projects/bot/src/listeners/guilds/roles/roleDeleteNotify.ts new file mode 100644 index 000000000..1931a1eb2 --- /dev/null +++ b/projects/bot/src/listeners/guilds/roles/roleDeleteNotify.ts @@ -0,0 +1,28 @@ +import { GuildSettings, readSettings, writeSettings } from '#lib/database'; +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { Colors } from '#utils/constants'; +import { ApplyOptions } from '@sapphire/decorators'; +import { Events, Listener, ListenerOptions } from '@sapphire/framework'; +import { isNullish } from '@sapphire/utilities'; +import { MessageEmbed, Role, TextChannel } from 'discord.js'; + +@ApplyOptions({ event: Events.GuildRoleDelete }) +export class UserListener extends Listener { + public async run(role: Role) { + const [channelId, t] = await readSettings(role, (settings) => [settings[GuildSettings.Channels.Logs.RoleDelete], settings.getLanguage()]); + if (isNullish(channelId)) return; + + const channel = role.guild.channels.cache.get(channelId) as TextChannel | undefined; + if (channel === undefined) { + await writeSettings(role, [[GuildSettings.Channels.Logs.RoleDelete, null]]); + return; + } + + const embed = new MessageEmbed() + .setColor(Colors.Red) + .setAuthor({ name: `${role.name} (${role.id})`, iconURL: channel.guild.iconURL({ size: 64, format: 'png', dynamic: true }) ?? undefined }) + .setFooter({ text: t(LanguageKeys.Events.Guilds.Logs.RoleDelete) }) + .setTimestamp(); + await channel.send({ embeds: [embed] }); + } +} diff --git a/projects/bot/src/listeners/guilds/roles/roleUpdate.ts b/projects/bot/src/listeners/guilds/roles/roleUpdate.ts new file mode 100644 index 000000000..6f223e249 --- /dev/null +++ b/projects/bot/src/listeners/guilds/roles/roleUpdate.ts @@ -0,0 +1,12 @@ +import { writeSettings } from '#lib/database'; +import { Listener } from '@sapphire/framework'; +import type { Role } from 'discord.js'; + +export class UserListener extends Listener { + public run(previous: Role, next: Role) { + if (!next.guild.available) return; + if (previous.position === next.position) return; + if (!this.container.settings.guilds.get(next.guild.id)?.permissionNodes.has(next.id)) return; + return writeSettings(next, (settings) => settings.adders.refresh()); + } +} diff --git a/src/listeners/guilds/roles/roleUpdateNotify.ts b/projects/bot/src/listeners/guilds/roles/roleUpdateNotify.ts similarity index 62% rename from src/listeners/guilds/roles/roleUpdateNotify.ts rename to projects/bot/src/listeners/guilds/roles/roleUpdateNotify.ts index e45311df9..1ed22bd6e 100644 --- a/src/listeners/guilds/roles/roleUpdateNotify.ts +++ b/projects/bot/src/listeners/guilds/roles/roleUpdateNotify.ts @@ -1,36 +1,36 @@ -import { readSettings } from '#lib/database'; -import { getT } from '#lib/i18n'; +import { GuildSettings, readSettings, writeSettings } from '#lib/database'; import { LanguageKeys } from '#lib/i18n/languageKeys'; import { toPermissionsArray } from '#utils/bits'; import { differenceBitField } from '#utils/common/comparators'; import { Colors } from '#utils/constants'; -import { getLogger } from '#utils/functions'; -import { EmbedBuilder } from '@discordjs/builders'; import { ApplyOptions } from '@sapphire/decorators'; -import { Events, Listener } from '@sapphire/framework'; -import type { TFunction } from '@sapphire/plugin-i18next'; -import type { Role } from 'discord.js'; +import { Events, Listener, ListenerOptions } from '@sapphire/framework'; +import { isNullish } from '@sapphire/utilities'; +import { MessageEmbed, Role, TextChannel } from 'discord.js'; +import type { TFunction } from 'i18next'; -@ApplyOptions({ event: Events.GuildRoleUpdate }) +@ApplyOptions({ event: Events.GuildRoleUpdate }) export class UserListener extends Listener { public async run(previous: Role, next: Role) { - const settings = await readSettings(next); - await getLogger(next.guild).send({ - key: 'channelsLogsRoleUpdate', - channelId: settings.channelsLogsRoleUpdate, - makeMessage: () => { - const t = getT(settings.language); - const changes: string[] = [...this.differenceRole(t, previous, next)]; - if (changes.length === 0) return null; + const [channelId, t] = await readSettings(next, (settings) => [settings[GuildSettings.Channels.Logs.RoleUpdate], settings.getLanguage()]); + if (isNullish(channelId)) return; - return new EmbedBuilder() - .setColor(Colors.Yellow) - .setAuthor({ name: `${next.name} (${next.id})`, iconURL: next.guild.iconURL({ size: 64, extension: 'png' }) ?? undefined }) - .setDescription(changes.join('\n')) - .setFooter({ text: t(LanguageKeys.Events.Guilds.Logs.RoleUpdate) }) - .setTimestamp(); - } - }); + const channel = next.guild.channels.cache.get(channelId) as TextChannel | undefined; + if (channel === undefined) { + await writeSettings(next, [[GuildSettings.Channels.Logs.RoleUpdate, null]]); + return; + } + + const changes: string[] = [...this.differenceRole(t, previous, next)]; + if (changes.length === 0) return; + + const embed = new MessageEmbed() + .setColor(Colors.Yellow) + .setAuthor({ name: `${next.name} (${next.id})`, iconURL: channel.guild.iconURL({ size: 64, format: 'png', dynamic: true }) ?? undefined }) + .setDescription(changes.join('\n')) + .setFooter({ text: t(LanguageKeys.Events.Guilds.Logs.RoleUpdate) }) + .setTimestamp(); + await channel.send({ embeds: [embed] }); } private *differenceRole(t: TFunction, previous: Role, next: Role) { diff --git a/projects/bot/src/listeners/messages/guildMessageDeleteNotify.ts b/projects/bot/src/listeners/messages/guildMessageDeleteNotify.ts new file mode 100644 index 000000000..6ba453462 --- /dev/null +++ b/projects/bot/src/listeners/messages/guildMessageDeleteNotify.ts @@ -0,0 +1,43 @@ +import { GuildSettings, readSettings } from '#lib/database'; +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import type { GuildMessage } from '#lib/types'; +import { Events } from '#lib/types/Enums'; +import { Colors } from '#utils/constants'; +import { getContent, getImage } from '#utils/util'; +import { ApplyOptions } from '@sapphire/decorators'; +import { isNsfwChannel } from '@sapphire/discord.js-utilities'; +import { Listener, ListenerOptions } from '@sapphire/framework'; +import { cutText, isNullish } from '@sapphire/utilities'; +import { MessageEmbed } from 'discord.js'; + +@ApplyOptions({ event: Events.GuildMessageDelete }) +export class UserListener extends Listener { + public async run(message: GuildMessage) { + const key = GuildSettings.Channels.Logs[isNsfwChannel(message.channel) ? 'MessageDeleteNsfw' : 'MessageDelete']; + const [ignoredChannels, logChannelId, ignoredDeletes, ignoredAll, t] = await readSettings(message.guild, (settings) => [ + settings[GuildSettings.Messages.IgnoreChannels], + settings[key], + settings[GuildSettings.Channels.Ignore.MessageDelete], + settings[GuildSettings.Channels.Ignore.All], + settings.getLanguage() + ]); + + if (isNullish(logChannelId)) return; + if (ignoredChannels.some((id) => id === message.channel.id || message.channel.parentId === id)) return; + if (ignoredDeletes.some((id) => id === message.channel.id && message.channel.parentId === id)) return; + if (ignoredAll.some((id) => id === message.channel.id || message.channel.parentId === id)) return; + + this.container.client.emit(Events.GuildMessageLog, message.guild, logChannelId, key, () => + new MessageEmbed() + .setColor(Colors.Red) + .setAuthor({ + name: `${message.author.tag} (${message.author.id})`, + iconURL: message.author.displayAvatarURL({ size: 128, format: 'png', dynamic: true }) + }) + .setDescription(cutText(getContent(message) || '', 1900)) + .setFooter({ text: t(LanguageKeys.Events.Messages.MessageDelete, { channel: `#${message.channel.name}` }) }) + .setImage(getImage(message)!) + .setTimestamp() + ); + } +} diff --git a/projects/bot/src/listeners/messages/guildMessageDeleteRichDisplay.ts b/projects/bot/src/listeners/messages/guildMessageDeleteRichDisplay.ts new file mode 100644 index 000000000..e234a2108 --- /dev/null +++ b/projects/bot/src/listeners/messages/guildMessageDeleteRichDisplay.ts @@ -0,0 +1,13 @@ +import { SkyraLazyPaginatedMessage, SkyraPaginatedMessage } from '#lib/structures'; +import type { GuildMessage } from '#lib/types'; +import { Events } from '#lib/types/Enums'; +import { ApplyOptions } from '@sapphire/decorators'; +import { Listener, ListenerOptions } from '@sapphire/framework'; + +@ApplyOptions({ event: Events.GuildMessageDelete }) +export class UserListener extends Listener { + public run(message: GuildMessage) { + SkyraPaginatedMessage.messages.get(message.id)?.collector?.stop(); + SkyraLazyPaginatedMessage.messages.get(message.id)?.collector?.stop(); + } +} diff --git a/src/listeners/messages/guildMessageDeleteSnipe.ts b/projects/bot/src/listeners/messages/guildMessageDeleteSnipe.ts similarity index 51% rename from src/listeners/messages/guildMessageDeleteSnipe.ts rename to projects/bot/src/listeners/messages/guildMessageDeleteSnipe.ts index da60bbd51..a2b63e932 100644 --- a/src/listeners/messages/guildMessageDeleteSnipe.ts +++ b/projects/bot/src/listeners/messages/guildMessageDeleteSnipe.ts @@ -1,9 +1,10 @@ -import { Events, type GuildMessage } from '#lib/types'; +import type { GuildMessage } from '#lib/types'; +import { Events } from '#lib/types/Enums'; import { setSnipedMessage } from '#utils/functions'; import { ApplyOptions } from '@sapphire/decorators'; -import { Listener } from '@sapphire/framework'; +import { Listener, ListenerOptions } from '@sapphire/framework'; -@ApplyOptions({ event: Events.GuildMessageDelete }) +@ApplyOptions({ event: Events.GuildMessageDelete }) export class UserListener extends Listener { public run(message: GuildMessage) { setSnipedMessage(message.channel, message); diff --git a/src/listeners/messages/guildUserMessageMediaOnly.ts b/projects/bot/src/listeners/messages/guildUserMessageMediaOnly.ts similarity index 63% rename from src/listeners/messages/guildUserMessageMediaOnly.ts rename to projects/bot/src/listeners/messages/guildUserMessageMediaOnly.ts index c80fc1fd9..1c4ede75e 100644 --- a/src/listeners/messages/guildUserMessageMediaOnly.ts +++ b/projects/bot/src/listeners/messages/guildUserMessageMediaOnly.ts @@ -1,15 +1,15 @@ -import { readSettings } from '#lib/database'; -import { Events, type GuildMessage } from '#lib/types'; +import { GuildSettings, readSettings } from '#lib/database'; +import type { GuildMessage } from '#lib/types'; +import { Events } from '#lib/types/Enums'; import { deleteMessage, isModerator } from '#utils/functions'; +import { MEDIA_EXTENSION } from '#utils/util'; import { ApplyOptions } from '@sapphire/decorators'; -import { isMediaAttachment } from '@sapphire/discord.js-utilities'; -import { Listener } from '@sapphire/framework'; +import { Listener, ListenerOptions } from '@sapphire/framework'; -@ApplyOptions({ event: Events.GuildUserMessage }) +@ApplyOptions({ event: Events.GuildUserMessage }) export class UserListener extends Listener { public async run(message: GuildMessage) { - const settings = await readSettings(message.guild); - const channels = settings.channelsMediaOnly; + const channels = await readSettings(message.guild, GuildSettings.Channels.MediaOnly); // If the message is not set up as media-only, skip: if (!channels.includes(message.channel.id)) return; @@ -33,6 +33,6 @@ export class UserListener extends Listener { } private hasMediaAttachments(message: GuildMessage) { - return message.attachments.some((attachment) => isMediaAttachment(attachment)); + return message.attachments.some((att) => MEDIA_EXTENSION.test(att.url)); } } diff --git a/src/listeners/messages/messageCreate.ts b/projects/bot/src/listeners/messages/messageCreate.ts similarity index 92% rename from src/listeners/messages/messageCreate.ts rename to projects/bot/src/listeners/messages/messageCreate.ts index 382d8099d..e4c2cebca 100644 --- a/src/listeners/messages/messageCreate.ts +++ b/projects/bot/src/listeners/messages/messageCreate.ts @@ -1,4 +1,4 @@ -import { Events } from '#lib/types'; +import { Events } from '#lib/types/Enums'; import { Listener } from '@sapphire/framework'; import type { Message } from 'discord.js'; diff --git a/src/listeners/messages/messageDelete.ts b/projects/bot/src/listeners/messages/messageDelete.ts similarity index 89% rename from src/listeners/messages/messageDelete.ts rename to projects/bot/src/listeners/messages/messageDelete.ts index 41d68aeb1..693add809 100644 --- a/src/listeners/messages/messageDelete.ts +++ b/projects/bot/src/listeners/messages/messageDelete.ts @@ -1,4 +1,4 @@ -import { Events } from '#lib/types'; +import { Events } from '#lib/types/Enums'; import { isGuildMessage } from '#utils/common'; import { Listener } from '@sapphire/framework'; import type { Message } from 'discord.js'; diff --git a/src/listeners/messages/messageDeleteBulkRemoveResponses.ts b/projects/bot/src/listeners/messages/messageDeleteBulkRemoveResponses.ts similarity index 68% rename from src/listeners/messages/messageDeleteBulkRemoveResponses.ts rename to projects/bot/src/listeners/messages/messageDeleteBulkRemoveResponses.ts index 40539b8af..673edc89f 100644 --- a/src/listeners/messages/messageDeleteBulkRemoveResponses.ts +++ b/projects/bot/src/listeners/messages/messageDeleteBulkRemoveResponses.ts @@ -1,15 +1,16 @@ -import { CommandMatcher, readSettings } from '#lib/database'; -import { Events, type GuildMessage } from '#lib/types'; +import { CommandMatcher, GuildSettings, readSettings } from '#lib/database'; +import type { GuildMessage } from '#lib/types'; +import { Events } from '#lib/types/Enums'; import { deleteMessage, getCommand } from '#utils/functions'; import { ApplyOptions } from '@sapphire/decorators'; -import { Listener } from '@sapphire/framework'; +import { Listener, ListenerOptions } from '@sapphire/framework'; import { get } from '@sapphire/plugin-editable-commands'; import { hasAtLeastOneKeyInMap } from '@sapphire/utilities'; -import type { Message, OmitPartialGroupDMChannel, ReadonlyCollection } from 'discord.js'; +import type { Collection, Message, Snowflake } from 'discord.js'; -type MessageCollection = ReadonlyCollection>>; +type MessageCollection = Collection; -@ApplyOptions({ event: Events.MessageDeleteBulk }) +@ApplyOptions({ event: Events.MessageDeleteBulk }) export class UserListener extends Listener { public async run(messages: MessageCollection) { // If, for some reason, this was emitted with no messages, skip all: @@ -20,17 +21,20 @@ export class UserListener extends Listener { // If the auto-delete behavior cannot be customized, delete all: if (!this.canBeCustomized(first)) return this.deleteAll(messages); - const settings = await readSettings(first.guild); + const [ignoredAll, ignoredChannels, ignoredCommands, ignoredRoles] = await readSettings(first.guild, [ + GuildSettings.Messages.AutoDelete.IgnoredAll, + GuildSettings.Messages.AutoDelete.IgnoredChannels, + GuildSettings.Messages.AutoDelete.IgnoredCommands, + GuildSettings.Messages.AutoDelete.IgnoredRoles + ]); // If auto-delete is disabled globally, skip all: - if (settings.messagesAutoDeleteIgnoredAll) return; + if (ignoredAll) return; // If the channel is ignored, skip all: - if (settings.messagesAutoDeleteIgnoredChannels.includes(first.channel.id)) return; + if (ignoredChannels.includes(first.channel.id)) return; // If the auto-delete behavior is not changed, delete all: - const ignoredCommands = settings.messagesAutoDeleteIgnoredCommands; - const ignoredRoles = settings.messagesAutoDeleteIgnoredRoles; if (ignoredCommands.length === 0 && ignoredRoles.length === 0) return this.deleteAll(messages); for (const message of messages.values()) { @@ -49,7 +53,7 @@ export class UserListener extends Listener { return message.guild !== null; } - private shouldBeIgnored(message: GuildMessage, ignoredCommands: readonly string[], ignoredRoles: readonly string[]): boolean { + private shouldBeIgnored(message: GuildMessage, ignoredCommands: string[], ignoredRoles: string[]): boolean { // Check for ignored roles: if (hasAtLeastOneKeyInMap(message.member.roles.cache, ignoredRoles)) return true; diff --git a/src/listeners/messages/messageDeleteRemoveResponses.ts b/projects/bot/src/listeners/messages/messageDeleteRemoveResponses.ts similarity index 54% rename from src/listeners/messages/messageDeleteRemoveResponses.ts rename to projects/bot/src/listeners/messages/messageDeleteRemoveResponses.ts index 7ab76250f..f28c2447d 100644 --- a/src/listeners/messages/messageDeleteRemoveResponses.ts +++ b/projects/bot/src/listeners/messages/messageDeleteRemoveResponses.ts @@ -1,13 +1,14 @@ -import { CommandMatcher, readSettings } from '#lib/database'; -import { Events, type GuildMessage } from '#lib/types'; +import { CommandMatcher, GuildSettings, readSettings } from '#lib/database'; +import type { GuildMessage } from '#lib/types'; +import { Events } from '#lib/types/Enums'; import { deleteMessage, getCommand } from '#utils/functions'; import { ApplyOptions } from '@sapphire/decorators'; -import { Listener } from '@sapphire/framework'; +import { Listener, ListenerOptions } from '@sapphire/framework'; import { get } from '@sapphire/plugin-editable-commands'; import { hasAtLeastOneKeyInMap } from '@sapphire/utilities'; import type { Message } from 'discord.js'; -@ApplyOptions({ event: Events.MessageDelete }) +@ApplyOptions({ event: Events.MessageDelete }) export class UserListener extends Listener { public async run(message: Message) { const response = get(message); @@ -29,20 +30,25 @@ export class UserListener extends Listener { private async shouldBeIgnored(message: Message): Promise { if (!this.canBeCustomized(message)) return false; - const settings = await readSettings(message.guild); + const [ignoredAll, ignoredChannels, ignoredCommands, ignoredRoles] = await readSettings(message.guild, [ + GuildSettings.Messages.AutoDelete.IgnoredAll, + GuildSettings.Messages.AutoDelete.IgnoredChannels, + GuildSettings.Messages.AutoDelete.IgnoredCommands, + GuildSettings.Messages.AutoDelete.IgnoredRoles + ]); // Check for ignored all: - if (settings.messagesAutoDeleteIgnoredAll) return true; + if (ignoredAll) return true; // Check for ignored channels: - if (settings.messagesAutoDeleteIgnoredChannels.includes(message.channel.id)) return true; + if (ignoredChannels.includes(message.channel.id)) return true; // Check for ignored roles: - if (hasAtLeastOneKeyInMap(message.member.roles.cache, settings.messagesAutoDeleteIgnoredRoles)) return true; + if (hasAtLeastOneKeyInMap(message.member.roles.cache, ignoredRoles)) return true; // Check for ignored commands: const command = getCommand(message); - if (command !== null && CommandMatcher.matchAny(settings.messagesAutoDeleteIgnoredCommands, command)) return true; + if (command !== null && CommandMatcher.matchAny(ignoredCommands, command)) return true; return false; } diff --git a/projects/bot/src/listeners/messages/messageUpdateNotify.ts b/projects/bot/src/listeners/messages/messageUpdateNotify.ts new file mode 100644 index 000000000..4070f574f --- /dev/null +++ b/projects/bot/src/listeners/messages/messageUpdateNotify.ts @@ -0,0 +1,51 @@ +import { GuildSettings, readSettings } from '#lib/database'; +import { SkyraEmbed } from '#lib/discord'; +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { Events } from '#lib/types/Enums'; +import { isGuildMessage } from '#utils/common'; +import { Colors } from '#utils/constants'; +import { escapeMarkdown } from '#utils/External/escapeMarkdown'; +import { ApplyOptions } from '@sapphire/decorators'; +import { isNsfwChannel } from '@sapphire/discord.js-utilities'; +import { Listener, ListenerOptions } from '@sapphire/framework'; +import { isNullish } from '@sapphire/utilities'; +import { diffWordsWithSpace } from 'diff'; +import type { Message } from 'discord.js'; + +@ApplyOptions({ event: Events.MessageUpdate }) +export class UserListener extends Listener { + public async run(old: Message, message: Message) { + if (!isGuildMessage(message) || old.content === message.content || message.author.bot) return; + + const key = GuildSettings.Channels.Logs[isNsfwChannel(message.channel) ? 'MessageUpdateNsfw' : 'MessageUpdate']; + const [ignoredChannels, logChannelId, ignoredEdits, ignoredAll, t] = await readSettings(message.guild, (settings) => [ + settings[GuildSettings.Messages.IgnoreChannels], + settings[key], + settings[GuildSettings.Channels.Ignore.MessageEdit], + settings[GuildSettings.Channels.Ignore.All], + settings.getLanguage() + ]); + + if (isNullish(logChannelId)) return; + if (ignoredChannels.includes(message.channel.id)) return; + if (ignoredEdits.some((id) => id === message.channel.id || message.channel.parentId === id)) return; + if (ignoredAll.some((id) => id === message.channel.id || message.channel.parentId === id)) return; + + this.container.client.emit(Events.GuildMessageLog, message.guild, logChannelId, key, () => + new SkyraEmbed() + .setColor(Colors.Amber) + .setAuthor({ + name: `${message.author.tag} (${message.author.id})`, + iconURL: message.author.displayAvatarURL({ size: 128, format: 'png', dynamic: true }), + url: message.url + }) + .splitFields( + diffWordsWithSpace(escapeMarkdown(old.content), escapeMarkdown(message.content)) + .map((result) => (result.added ? `**${result.value}**` : result.removed ? `~~${result.value}~~` : result.value)) + .join(' ') + ) + .setFooter({ text: t(LanguageKeys.Events.Messages.MessageUpdate, { channel: `#${message.channel.name}` }) }) + .setTimestamp() + ); + } +} diff --git a/projects/bot/src/listeners/messages/rawMessageDelete.ts b/projects/bot/src/listeners/messages/rawMessageDelete.ts new file mode 100644 index 000000000..fbd678cc3 --- /dev/null +++ b/projects/bot/src/listeners/messages/rawMessageDelete.ts @@ -0,0 +1,16 @@ +import { Events } from '#lib/types/Enums'; +import { ApplyOptions } from '@sapphire/decorators'; +import { Listener, ListenerOptions } from '@sapphire/framework'; +import { GatewayDispatchEvents, GatewayMessageDeleteDispatch } from 'discord-api-types/v9'; + +@ApplyOptions({ event: GatewayDispatchEvents.MessageDelete, emitter: 'ws' }) +export class UserListener extends Listener { + public run(data: GatewayMessageDeleteDispatch['d']): void { + if (!data.guild_id) return; + + const guild = this.container.client.guilds.cache.get(data.guild_id); + if (!guild || !guild.channels.cache.has(data.channel_id)) return; + + this.container.client.emit(Events.RawMessageDelete, guild, data); + } +} diff --git a/projects/bot/src/listeners/messages/rawMessageDeleteBulk.ts b/projects/bot/src/listeners/messages/rawMessageDeleteBulk.ts new file mode 100644 index 000000000..7c4eed5ee --- /dev/null +++ b/projects/bot/src/listeners/messages/rawMessageDeleteBulk.ts @@ -0,0 +1,16 @@ +import { Events } from '#lib/types/Enums'; +import { ApplyOptions } from '@sapphire/decorators'; +import { Listener, ListenerOptions } from '@sapphire/framework'; +import { GatewayDispatchEvents, GatewayMessageDeleteBulkDispatch } from 'discord-api-types/v9'; + +@ApplyOptions({ event: GatewayDispatchEvents.MessageDeleteBulk, emitter: 'ws' }) +export class UserListener extends Listener { + public run(data: GatewayMessageDeleteBulkDispatch['d']): void { + if (!data.guild_id) return; + + const guild = this.container.client.guilds.cache.get(data.guild_id); + if (!guild || !guild.channels.cache.has(data.channel_id)) return; + + this.container.client.emit(Events.RawMessageDeleteBulk, guild, data); + } +} diff --git a/src/listeners/messages/userMessageGuildHandler.ts b/projects/bot/src/listeners/messages/userMessageGuildHandler.ts similarity index 60% rename from src/listeners/messages/userMessageGuildHandler.ts rename to projects/bot/src/listeners/messages/userMessageGuildHandler.ts index 96058383a..a1fc2fda8 100644 --- a/src/listeners/messages/userMessageGuildHandler.ts +++ b/projects/bot/src/listeners/messages/userMessageGuildHandler.ts @@ -1,9 +1,9 @@ -import { Events } from '#lib/types'; +import { Events } from '#lib/types/Enums'; import { ApplyOptions } from '@sapphire/decorators'; -import { Listener } from '@sapphire/framework'; +import { Listener, ListenerOptions } from '@sapphire/framework'; import type { Message } from 'discord.js'; -@ApplyOptions({ event: Events.UserMessage }) +@ApplyOptions({ event: Events.UserMessage }) export class UserListener extends Listener { public run(message: Message) { if (message.guild) this.container.client.emit(Events.GuildUserMessage, message); diff --git a/src/listeners/moderation/messages/guildUserMessageAttachmentsHandler.ts b/projects/bot/src/listeners/moderation/messages/guildUserMessageAttachmentsHandler.ts similarity index 65% rename from src/listeners/moderation/messages/guildUserMessageAttachmentsHandler.ts rename to projects/bot/src/listeners/moderation/messages/guildUserMessageAttachmentsHandler.ts index 6959edc44..51b3ed14e 100644 --- a/src/listeners/moderation/messages/guildUserMessageAttachmentsHandler.ts +++ b/projects/bot/src/listeners/moderation/messages/guildUserMessageAttachmentsHandler.ts @@ -1,24 +1,23 @@ +import { GuildSettings } from '#lib/database'; import { LanguageKeys } from '#lib/i18n/languageKeys'; import { ModerationMessageListener } from '#lib/moderation'; import type { GuildMessage } from '#lib/types'; import { Colors } from '#utils/constants'; import { deleteMessage, sendTemporaryMessage } from '#utils/functions'; -import { getFullEmbedAuthor } from '#utils/util'; -import { EmbedBuilder } from '@discordjs/builders'; import { ApplyOptions } from '@sapphire/decorators'; -import type { TFunction } from '@sapphire/plugin-i18next'; -import type { TextChannel } from 'discord.js'; +import { MessageEmbed, TextChannel } from 'discord.js'; +import type { TFunction } from 'i18next'; @ApplyOptions({ reasonLanguageKey: LanguageKeys.Events.Moderation.Messages.ModerationAttachments, reasonLanguageKeyWithMaximum: LanguageKeys.Events.Moderation.Messages.ModerationAttachmentsWithMaximum, - keyEnabled: 'selfmodAttachmentsEnabled', - ignoredChannelsPath: 'selfmodAttachmentsIgnoredChannels', - ignoredRolesPath: 'selfmodAttachmentsIgnoredRoles', - softPunishmentPath: 'selfmodAttachmentsSoftAction', + keyEnabled: GuildSettings.Selfmod.Attachments.Enabled, + ignoredChannelsPath: GuildSettings.Selfmod.Attachments.IgnoredChannels, + ignoredRolesPath: GuildSettings.Selfmod.Attachments.IgnoredRoles, + softPunishmentPath: GuildSettings.Selfmod.Attachments.SoftAction, hardPunishmentPath: { - action: 'selfmodAttachmentsHardAction', - actionDuration: 'selfmodAttachmentsHardActionDuration', + action: GuildSettings.Selfmod.Attachments.HardAction, + actionDuration: GuildSettings.Selfmod.Attachments.HardActionDuration, adder: 'attachments' } }) @@ -37,10 +36,13 @@ export class UserModerationMessageListener extends ModerationMessageListener { } protected onLogMessage(message: GuildMessage, t: TFunction) { - return new EmbedBuilder() + return new MessageEmbed() .setDescription(message.content) .setColor(Colors.Red) - .setAuthor(getFullEmbedAuthor(message.author, message.url)) + .setAuthor({ + name: `${message.author.tag} (${message.author.id})`, + iconURL: message.author.displayAvatarURL({ size: 128, format: 'png', dynamic: true }) + }) .setFooter({ text: `#${(message.channel as TextChannel).name} | ${t(LanguageKeys.Events.Moderation.Messages.AttachmentFilterFooter)}` }) .setTimestamp(); } diff --git a/src/listeners/moderation/messages/guildUserMessageCapitalsHandler.ts b/projects/bot/src/listeners/moderation/messages/guildUserMessageCapitalsHandler.ts similarity index 63% rename from src/listeners/moderation/messages/guildUserMessageCapitalsHandler.ts rename to projects/bot/src/listeners/moderation/messages/guildUserMessageCapitalsHandler.ts index ffe0f121f..c9d0c2498 100644 --- a/src/listeners/moderation/messages/guildUserMessageCapitalsHandler.ts +++ b/projects/bot/src/listeners/moderation/messages/guildUserMessageCapitalsHandler.ts @@ -1,28 +1,26 @@ -import { readSettings } from '#lib/database'; +import { GuildSettings, readSettings } from '#lib/database'; import { LanguageKeys } from '#lib/i18n/languageKeys'; import { ModerationMessageListener } from '#lib/moderation'; import type { GuildMessage } from '#lib/types'; import { floatPromise } from '#utils/common'; import { Colors } from '#utils/constants'; import { deleteMessage, sendTemporaryMessage } from '#utils/functions'; -import { getFullEmbedAuthor } from '#utils/util'; -import { EmbedBuilder } from '@discordjs/builders'; import { ApplyOptions } from '@sapphire/decorators'; -import type { TFunction } from '@sapphire/plugin-i18next'; import { codeBlock, cutText } from '@sapphire/utilities'; import { getCode, isUpper } from '@skyra/char'; -import type { TextChannel } from 'discord.js'; +import { MessageEmbed, TextChannel } from 'discord.js'; +import type { TFunction } from 'i18next'; @ApplyOptions({ reasonLanguageKey: LanguageKeys.Events.Moderation.Messages.ModerationCapitals, reasonLanguageKeyWithMaximum: LanguageKeys.Events.Moderation.Messages.ModerationCapitalsWithMaximum, - keyEnabled: 'selfmodCapitalsEnabled', - ignoredChannelsPath: 'selfmodCapitalsIgnoredChannels', - ignoredRolesPath: 'selfmodCapitalsIgnoredRoles', - softPunishmentPath: 'selfmodCapitalsSoftAction', + keyEnabled: GuildSettings.Selfmod.Capitals.Enabled, + ignoredChannelsPath: GuildSettings.Selfmod.Capitals.IgnoredChannels, + ignoredRolesPath: GuildSettings.Selfmod.Capitals.IgnoredRoles, + softPunishmentPath: GuildSettings.Selfmod.Capitals.SoftAction, hardPunishmentPath: { - action: 'selfmodCapitalsHardAction', - actionDuration: 'selfmodCapitalsHardActionDuration', + action: GuildSettings.Selfmod.Capitals.HardAction, + actionDuration: GuildSettings.Selfmod.Capitals.HardActionDuration, adder: 'capitals' } }) @@ -30,8 +28,12 @@ export class UserModerationMessageListener extends ModerationMessageListener { protected async preProcess(message: GuildMessage): Promise<1 | null> { if (message.content.length === 0) return null; - const settings = await readSettings(message.guild); - if (message.content.length < settings.selfmodCapitalsMinimum) return null; + const [minimumCapitals, maximumCapitals] = await readSettings(message.guild, [ + GuildSettings.Selfmod.Capitals.Minimum, + GuildSettings.Selfmod.Capitals.Maximum + ]); + + if (message.content.length < minimumCapitals) return null; let length = 0; let count = 0; @@ -43,12 +45,12 @@ export class UserModerationMessageListener extends ModerationMessageListener { } const percentage = (count / length) * 100; - return percentage >= settings.selfmodCapitalsMaximum ? 1 : null; + return percentage >= maximumCapitals ? 1 : null; } protected async onDelete(message: GuildMessage, t: TFunction, value: number) { floatPromise(deleteMessage(message)); - if (value > 25 && (await this.container.prisma.user.fetchModerationDirectMessageEnabled(message.author.id))) { + if (value > 25 && (await this.container.db.fetchModerationDirectMessageEnabled(message.author.id))) { await message.author.send( t(LanguageKeys.Events.Moderation.Messages.CapsFilterDm, { message: codeBlock('md', cutText(message.content, 1900)) }) ); @@ -60,10 +62,13 @@ export class UserModerationMessageListener extends ModerationMessageListener { } protected onLogMessage(message: GuildMessage, t: TFunction) { - return new EmbedBuilder() + return new MessageEmbed() .setDescription(message.content) .setColor(Colors.Red) - .setAuthor(getFullEmbedAuthor(message.author, message.url)) + .setAuthor({ + name: `${message.author.tag} (${message.author.id})`, + iconURL: message.author.displayAvatarURL({ size: 128, format: 'png', dynamic: true }) + }) .setFooter({ text: `#${(message.channel as TextChannel).name} | ${t(LanguageKeys.Events.Moderation.Messages.CapsFilterFooter)}` }) .setTimestamp(); } diff --git a/src/listeners/moderation/messages/guildUserMessageInvitesHandler.ts b/projects/bot/src/listeners/moderation/messages/guildUserMessageInvitesHandler.ts similarity index 76% rename from src/listeners/moderation/messages/guildUserMessageInvitesHandler.ts rename to projects/bot/src/listeners/moderation/messages/guildUserMessageInvitesHandler.ts index 1b972667e..ceb64510a 100644 --- a/src/listeners/moderation/messages/guildUserMessageInvitesHandler.ts +++ b/projects/bot/src/listeners/moderation/messages/guildUserMessageInvitesHandler.ts @@ -1,14 +1,12 @@ -import { readSettings } from '#lib/database'; +import { GuildSettings, readSettings } from '#lib/database'; import { LanguageKeys } from '#lib/i18n/languageKeys'; import { ModerationMessageListener } from '#lib/moderation'; import type { GuildMessage } from '#lib/types'; import { Colors } from '#utils/constants'; import { deleteMessage, sendTemporaryMessage } from '#utils/functions'; -import { getFullEmbedAuthor } from '#utils/util'; -import { EmbedBuilder } from '@discordjs/builders'; import { ApplyOptions } from '@sapphire/decorators'; -import type { TFunction } from '@sapphire/plugin-i18next'; -import type { TextChannel } from 'discord.js'; +import { MessageEmbed, TextChannel } from 'discord.js'; +import type { TFunction } from 'i18next'; const enum CodeType { DiscordGG, @@ -18,13 +16,13 @@ const enum CodeType { @ApplyOptions({ reasonLanguageKey: LanguageKeys.Events.Moderation.Messages.ModerationInvites, reasonLanguageKeyWithMaximum: LanguageKeys.Events.Moderation.Messages.ModerationInvitesWithMaximum, - keyEnabled: 'selfmodInvitesEnabled', - ignoredChannelsPath: 'selfmodInvitesIgnoredChannels', - ignoredRolesPath: 'selfmodInvitesIgnoredRoles', - softPunishmentPath: 'selfmodInvitesSoftAction', + keyEnabled: GuildSettings.Selfmod.Invites.Enabled, + ignoredChannelsPath: GuildSettings.Selfmod.Invites.IgnoredChannels, + ignoredRolesPath: GuildSettings.Selfmod.Invites.IgnoredRoles, + softPunishmentPath: GuildSettings.Selfmod.Invites.SoftAction, hardPunishmentPath: { - action: 'selfmodInvitesHardAction', - actionDuration: 'selfmodInvitesHardActionDuration', + action: GuildSettings.Selfmod.Invites.HardAction, + actionDuration: GuildSettings.Selfmod.Invites.HardActionDuration, adder: 'invites' } }) @@ -45,7 +43,7 @@ export class UserModerationMessageListener extends ModerationMessageListener { const identifier = this.getCodeIdentifier(source); // If it has already been scanned, skip - const key = `${source}/${code}`; + const key = `${source}${code}`; if (scanned.has(key)) continue; scanned.add(key); @@ -65,9 +63,12 @@ export class UserModerationMessageListener extends ModerationMessageListener { } protected onLogMessage(message: GuildMessage, t: TFunction, links: readonly string[]) { - return new EmbedBuilder() + return new MessageEmbed() .setColor(Colors.Red) - .setAuthor(getFullEmbedAuthor(message.author, message.url)) + .setAuthor({ + name: `${message.author.tag} (${message.author.id})`, + iconURL: message.author.displayAvatarURL({ size: 128, format: 'png', dynamic: true }) + }) .setDescription(t(LanguageKeys.Events.Moderation.Messages.InviteFilterLog, { links, count: links.length })) .setFooter({ text: `#${(message.channel as TextChannel).name} | ${t(LanguageKeys.Events.Moderation.Messages.InviteFooter)}` }) .setTimestamp(); @@ -78,10 +79,13 @@ export class UserModerationMessageListener extends ModerationMessageListener { } private async fetchIfAllowedInvite(message: GuildMessage, code: string) { - const settings = await readSettings(message.guild); + const [ignoredCodes, ignoredGuilds] = await readSettings(message.guild, [ + GuildSettings.Selfmod.Invites.IgnoredCodes, + GuildSettings.Selfmod.Invites.IgnoredGuilds + ]); // Ignored codes take short-circuit. - if (settings.selfmodInvitesIgnoredCodes.includes(code)) return true; + if (ignoredCodes.includes(code)) return true; const data = await message.client.invites.fetch(code); @@ -95,7 +99,7 @@ export class UserModerationMessageListener extends ModerationMessageListener { if (data.guildId === message.guild.id) return true; // Invites from white-listed guilds should be allowed. - if (settings.selfmodInvitesIgnoredGuilds.includes(data.guildId)) return true; + if (ignoredGuilds.includes(data.guildId)) return true; // Any other invite should not be allowed. return false; diff --git a/src/listeners/moderation/messages/guildUserMessageLinksHandler.ts b/projects/bot/src/listeners/moderation/messages/guildUserMessageLinksHandler.ts similarity index 69% rename from src/listeners/moderation/messages/guildUserMessageLinksHandler.ts rename to projects/bot/src/listeners/moderation/messages/guildUserMessageLinksHandler.ts index 9035c41b1..71487df9c 100644 --- a/src/listeners/moderation/messages/guildUserMessageLinksHandler.ts +++ b/projects/bot/src/listeners/moderation/messages/guildUserMessageLinksHandler.ts @@ -1,26 +1,24 @@ -import { readSettings } from '#lib/database'; +import { GuildSettings, readSettings } from '#lib/database'; import { LanguageKeys } from '#lib/i18n/languageKeys'; import { ModerationMessageListener } from '#lib/moderation'; import type { GuildMessage } from '#lib/types'; -import { urlRegex } from '#utils/Links/UrlRegex'; import { Colors } from '#utils/constants'; import { deleteMessage, sendTemporaryMessage } from '#utils/functions'; -import { getFullEmbedAuthor } from '#utils/util'; -import { EmbedBuilder } from '@discordjs/builders'; +import { urlRegex } from '#utils/Links/UrlRegex'; import { ApplyOptions } from '@sapphire/decorators'; -import type { TFunction } from '@sapphire/plugin-i18next'; -import type { TextChannel } from 'discord.js'; +import { MessageEmbed, TextChannel } from 'discord.js'; +import type { TFunction } from 'i18next'; @ApplyOptions({ reasonLanguageKey: LanguageKeys.Events.Moderation.Messages.ModerationLinks, reasonLanguageKeyWithMaximum: LanguageKeys.Events.Moderation.Messages.ModerationLinksWithMaximum, - keyEnabled: 'selfmodLinksEnabled', - ignoredChannelsPath: 'selfmodLinksIgnoredChannels', - ignoredRolesPath: 'selfmodLinksIgnoredRoles', - softPunishmentPath: 'selfmodLinksSoftAction', + keyEnabled: GuildSettings.Selfmod.Links.Enabled, + ignoredChannelsPath: GuildSettings.Selfmod.Links.IgnoredChannels, + ignoredRolesPath: GuildSettings.Selfmod.Links.IgnoredRoles, + softPunishmentPath: GuildSettings.Selfmod.Links.SoftAction, hardPunishmentPath: { - action: 'selfmodLinksHardAction', - actionDuration: 'selfmodLinksHardActionDuration', + action: GuildSettings.Selfmod.Links.HardAction, + actionDuration: GuildSettings.Selfmod.Links.HardActionDuration, adder: 'links' } }) @@ -33,8 +31,7 @@ export class UserModerationMessageListener extends ModerationMessageListener { let match: RegExpExecArray | null = null; - const settings = await readSettings(message.guild); - const allowed = settings.selfmodLinksAllowed; + const allowed = await readSettings(message.guild, GuildSettings.Selfmod.Links.Allowed); while ((match = this.kRegExp.exec(message.content)) !== null) { const { hostname } = match.groups!; if (this.kAllowedDomains.test(hostname)) continue; @@ -54,9 +51,12 @@ export class UserModerationMessageListener extends ModerationMessageListener { } protected onLogMessage(message: GuildMessage, t: TFunction) { - return new EmbedBuilder() + return new MessageEmbed() .setColor(Colors.Red) - .setAuthor(getFullEmbedAuthor(message.author, message.url)) + .setAuthor({ + name: `${message.author.tag} (${message.author.id})`, + iconURL: message.author.displayAvatarURL({ size: 128, format: 'png', dynamic: true }) + }) .setFooter({ text: `#${(message.channel as TextChannel).name} | ${t(LanguageKeys.Events.Moderation.Messages.LinkFooter)}` }) .setTimestamp(); } diff --git a/src/listeners/moderation/messages/guildUserMessageMentionsHandler.ts b/projects/bot/src/listeners/moderation/messages/guildUserMessageMentionsHandler.ts similarity index 56% rename from src/listeners/moderation/messages/guildUserMessageMentionsHandler.ts rename to projects/bot/src/listeners/moderation/messages/guildUserMessageMentionsHandler.ts index d58b20a0b..dbbf4283f 100644 --- a/src/listeners/moderation/messages/guildUserMessageMentionsHandler.ts +++ b/projects/bot/src/listeners/moderation/messages/guildUserMessageMentionsHandler.ts @@ -1,19 +1,25 @@ -import { readSettings, readSettingsNoMentionSpam } from '#lib/database'; -import { Events, type GuildMessage } from '#lib/types'; +import { GuildSettings, readSettings } from '#lib/database'; +import type { GuildMessage } from '#lib/types'; +import { Events } from '#lib/types/Enums'; import { isModerator } from '#utils/functions'; import { ApplyOptions } from '@sapphire/decorators'; -import { Listener } from '@sapphire/framework'; +import { Listener, ListenerOptions } from '@sapphire/framework'; import { isNullishOrZero } from '@sapphire/utilities'; -@ApplyOptions({ event: Events.GuildUserMessage }) +@ApplyOptions({ event: Events.GuildUserMessage }) export class UserListener extends Listener { public async run(message: GuildMessage) { if (!isNullishOrZero(message.editedTimestamp)) return; if (await isModerator(message.member)) return; - const settings = await readSettings(message.guild); - if (!settings.noMentionSpamEnabled) return; - if (settings.selfmodIgnoredChannels.includes(message.channel.id)) return; + const [enabled, globalIgnore, alerts, ratelimits] = await readSettings(message.guild, (settings) => [ + settings[GuildSettings.Selfmod.NoMentionSpam.Enabled], + settings[GuildSettings.Selfmod.IgnoreChannels], + settings[GuildSettings.Selfmod.NoMentionSpam.Alerts], + settings.nms + ]); + if (!enabled) return; + if (globalIgnore.includes(message.channel.id)) return; const mentions = message.mentions.users.reduce((acc, user) => (user.bot || user === message.author ? acc : acc + 1), 0) + @@ -22,15 +28,14 @@ export class UserListener extends Listener { if (mentions === 0) return; - const ctx = readSettingsNoMentionSpam(settings); - const rateLimit = ctx.acquire(message.author.id); + const rateLimit = ratelimits.acquire(message.author.id); try { for (let i = 0; i < mentions; i++) rateLimit.consume(); // Reset time, don't let them relax rateLimit.resetTime(); // eslint-disable-next-line @typescript-eslint/dot-notation - if (settings.noMentionSpamAlerts && rateLimit['remaining'] / rateLimit.remaining <= 0.2) { + if (alerts && rateLimit['remaining'] / rateLimit.remaining <= 0.2) { message.client.emit(Events.MentionSpamWarning, message); } } catch (err) { diff --git a/src/listeners/moderation/messages/guildUserMessageMessagesHandler.ts b/projects/bot/src/listeners/moderation/messages/guildUserMessageMessagesHandler.ts similarity index 72% rename from src/listeners/moderation/messages/guildUserMessageMessagesHandler.ts rename to projects/bot/src/listeners/moderation/messages/guildUserMessageMessagesHandler.ts index f4b65cbdd..e5af068a2 100644 --- a/src/listeners/moderation/messages/guildUserMessageMessagesHandler.ts +++ b/projects/bot/src/listeners/moderation/messages/guildUserMessageMessagesHandler.ts @@ -1,25 +1,24 @@ -import { readSettings } from '#lib/database'; +import { GuildSettings, readSettings } from '#lib/database'; import { LanguageKeys } from '#lib/i18n/languageKeys'; import { ModerationMessageListener } from '#lib/moderation'; import type { GuildMessage } from '#lib/types'; import { Colors } from '#utils/constants'; import { deleteMessage, sendTemporaryMessage } from '#utils/functions'; -import { getContent, getFullEmbedAuthor } from '#utils/util'; -import { EmbedBuilder } from '@discordjs/builders'; +import { getContent } from '#utils/util'; import { ApplyOptions } from '@sapphire/decorators'; -import type { TFunction } from '@sapphire/plugin-i18next'; -import type { TextChannel } from 'discord.js'; +import { MessageEmbed, TextChannel } from 'discord.js'; +import type { TFunction } from 'i18next'; @ApplyOptions({ reasonLanguageKey: LanguageKeys.Events.Moderation.Messages.ModerationMessages, reasonLanguageKeyWithMaximum: LanguageKeys.Events.Moderation.Messages.ModerationMessagesWithMaximum, - keyEnabled: 'selfmodMessagesEnabled', - ignoredChannelsPath: 'selfmodMessagesIgnoredChannels', - ignoredRolesPath: 'selfmodMessagesIgnoredRoles', - softPunishmentPath: 'selfmodMessagesSoftAction', + keyEnabled: GuildSettings.Selfmod.Messages.Enabled, + ignoredChannelsPath: GuildSettings.Selfmod.Messages.IgnoredChannels, + ignoredRolesPath: GuildSettings.Selfmod.Messages.IgnoredRoles, + softPunishmentPath: GuildSettings.Selfmod.Messages.SoftAction, hardPunishmentPath: { - action: 'selfmodMessagesHardAction', - actionDuration: 'selfmodMessagesHardActionDuration', + action: GuildSettings.Selfmod.Messages.HardAction, + actionDuration: GuildSettings.Selfmod.Messages.HardActionDuration, adder: 'messages' } }) @@ -28,8 +27,10 @@ export class UserModerationMessageListener extends ModerationMessageListener { protected async preProcess(message: GuildMessage): Promise<1 | null> { // Retrieve the threshold - const settings = await readSettings(message.guild); - const threshold = settings.selfmodMessagesMaximum; + const [threshold, queueSize] = await readSettings(message.guild, [ + GuildSettings.Selfmod.Messages.Maximum, + GuildSettings.Selfmod.Messages.QueueSize + ]); if (threshold === 0) return null; // Retrieve the content @@ -38,7 +39,7 @@ export class UserModerationMessageListener extends ModerationMessageListener { // Retrieve the contents, then update them to add the new content to the FILO queue. const contents = this.getContents(message); - const count = this.updateContents(contents, content.toLowerCase(), settings.selfmodMessagesQueueSize); + const count = this.updateContents(contents, content.toLowerCase(), queueSize); // If count is bigger than threshold // - return `count` @@ -55,10 +56,13 @@ export class UserModerationMessageListener extends ModerationMessageListener { } protected onLogMessage(message: GuildMessage, t: TFunction) { - return new EmbedBuilder() + return new MessageEmbed() .setDescription(message.content) .setColor(Colors.Red) - .setAuthor(getFullEmbedAuthor(message.author, message.url)) + .setAuthor({ + name: `${message.author.tag} (${message.author.id})`, + iconURL: message.author.displayAvatarURL({ size: 128, format: 'png', dynamic: true }) + }) .setFooter({ text: `#${(message.channel as TextChannel).name} | ${t(LanguageKeys.Events.Moderation.Messages.MessageFooter)}` }) .setTimestamp(); } diff --git a/src/listeners/moderation/messages/guildUserMessageNewLinesHandler.ts b/projects/bot/src/listeners/moderation/messages/guildUserMessageNewLinesHandler.ts similarity index 65% rename from src/listeners/moderation/messages/guildUserMessageNewLinesHandler.ts rename to projects/bot/src/listeners/moderation/messages/guildUserMessageNewLinesHandler.ts index 4faa8b0c7..ba5ee776e 100644 --- a/src/listeners/moderation/messages/guildUserMessageNewLinesHandler.ts +++ b/projects/bot/src/listeners/moderation/messages/guildUserMessageNewLinesHandler.ts @@ -1,34 +1,32 @@ -import { readSettings } from '#lib/database'; +import { GuildSettings, readSettings } from '#lib/database'; import { LanguageKeys } from '#lib/i18n/languageKeys'; import { ModerationMessageListener } from '#lib/moderation'; import type { GuildMessage } from '#lib/types'; import { Colors } from '#utils/constants'; import { deleteMessage, sendTemporaryMessage } from '#utils/functions'; -import { getContent, getFullEmbedAuthor } from '#utils/util'; -import { EmbedBuilder } from '@discordjs/builders'; +import { getContent } from '#utils/util'; import { ApplyOptions } from '@sapphire/decorators'; -import type { TFunction } from '@sapphire/plugin-i18next'; -import type { TextChannel } from 'discord.js'; +import { MessageEmbed, TextChannel } from 'discord.js'; +import type { TFunction } from 'i18next'; const NEW_LINE = '\n'; @ApplyOptions({ reasonLanguageKey: LanguageKeys.Events.Moderation.Messages.ModerationNewLine, reasonLanguageKeyWithMaximum: LanguageKeys.Events.Moderation.Messages.ModerationNewLineWithMaximum, - keyEnabled: 'selfmodNewlinesEnabled', - ignoredChannelsPath: 'selfmodNewlinesIgnoredChannels', - ignoredRolesPath: 'selfmodNewlinesIgnoredRoles', - softPunishmentPath: 'selfmodNewlinesSoftAction', + keyEnabled: GuildSettings.Selfmod.NewLines.Enabled, + ignoredChannelsPath: GuildSettings.Selfmod.NewLines.IgnoredChannels, + ignoredRolesPath: GuildSettings.Selfmod.NewLines.IgnoredRoles, + softPunishmentPath: GuildSettings.Selfmod.NewLines.SoftAction, hardPunishmentPath: { - action: 'selfmodNewlinesHardAction', - actionDuration: 'selfmodNewlinesHardActionDuration', + action: GuildSettings.Selfmod.NewLines.HardAction, + actionDuration: GuildSettings.Selfmod.NewLines.HardActionDuration, adder: 'newlines' } }) export class UserModerationMessageListener extends ModerationMessageListener { protected async preProcess(message: GuildMessage): Promise<1 | null> { - const settings = await readSettings(message.guild); - const threshold = settings.selfmodNewlinesMaximum; + const threshold = await readSettings(message.guild, GuildSettings.Selfmod.NewLines.Maximum); if (threshold === 0) return null; const content = getContent(message); @@ -49,10 +47,13 @@ export class UserModerationMessageListener extends ModerationMessageListener { } protected onLogMessage(message: GuildMessage, t: TFunction) { - return new EmbedBuilder() + return new MessageEmbed() .setDescription(message.content) .setColor(Colors.Red) - .setAuthor(getFullEmbedAuthor(message.author, message.url)) + .setAuthor({ + name: `${message.author.tag} (${message.author.id})`, + iconURL: message.author.displayAvatarURL({ size: 128, format: 'png', dynamic: true }) + }) .setFooter({ text: `#${(message.channel as TextChannel).name} | ${t(LanguageKeys.Events.Moderation.Messages.NewLineFooter)}` }) .setTimestamp(); } diff --git a/src/listeners/moderation/messages/guildUserMessageWordsHandler.ts b/projects/bot/src/listeners/moderation/messages/guildUserMessageWordsHandler.ts similarity index 65% rename from src/listeners/moderation/messages/guildUserMessageWordsHandler.ts rename to projects/bot/src/listeners/moderation/messages/guildUserMessageWordsHandler.ts index ad5b0716c..24f24acf2 100644 --- a/src/listeners/moderation/messages/guildUserMessageWordsHandler.ts +++ b/projects/bot/src/listeners/moderation/messages/guildUserMessageWordsHandler.ts @@ -1,28 +1,28 @@ -import { readSettings, readSettingsWordFilterRegExp } from '#lib/database'; +import { GuildSettings, readSettings } from '#lib/database'; +import { SkyraEmbed } from '#lib/discord'; import { LanguageKeys } from '#lib/i18n/languageKeys'; import { ModerationMessageListener } from '#lib/moderation'; import { IncomingType, OutgoingType } from '#lib/moderation/workers'; import type { GuildMessage } from '#lib/types'; import { floatPromise } from '#utils/common'; import { Colors } from '#utils/constants'; -import { addAutomaticFields, deleteMessage, sendTemporaryMessage } from '#utils/functions'; -import { getContent, getFullEmbedAuthor } from '#utils/util'; -import { EmbedBuilder } from '@discordjs/builders'; +import { deleteMessage, sendTemporaryMessage } from '#utils/functions'; +import { getContent } from '#utils/util'; import { ApplyOptions } from '@sapphire/decorators'; -import type { TFunction } from '@sapphire/plugin-i18next'; import { codeBlock, cutText } from '@sapphire/utilities'; import type { TextChannel } from 'discord.js'; +import type { TFunction } from 'i18next'; @ApplyOptions({ reasonLanguageKey: LanguageKeys.Events.Moderation.Messages.ModerationWords, reasonLanguageKeyWithMaximum: LanguageKeys.Events.Moderation.Messages.ModerationWordsWithMaximum, - keyEnabled: 'selfmodFilterEnabled', - ignoredChannelsPath: 'selfmodFilterIgnoredChannels', - ignoredRolesPath: 'selfmodFilterIgnoredRoles', - softPunishmentPath: 'selfmodFilterSoftAction', + keyEnabled: GuildSettings.Selfmod.Filter.Enabled, + ignoredChannelsPath: GuildSettings.Selfmod.Filter.IgnoredChannels, + ignoredRolesPath: GuildSettings.Selfmod.Filter.IgnoredRoles, + softPunishmentPath: GuildSettings.Selfmod.Filter.SoftAction, hardPunishmentPath: { - action: 'selfmodFilterHardAction', - actionDuration: 'selfmodFilterHardActionDuration', + action: GuildSettings.Selfmod.Filter.HardAction, + actionDuration: GuildSettings.Selfmod.Filter.HardActionDuration, adder: 'words' } }) @@ -31,8 +31,7 @@ export class UserModerationMessageListener extends ModerationMessageListener { const content = getContent(message); if (content === null) return null; - const settings = await readSettings(message.guild); - const regExp = readSettingsWordFilterRegExp(settings); + const regExp = await readSettings(message.guild, (settings) => settings.wordFilterRegExp); if (regExp === null) return null; const result = await this.container.workers.send({ type: IncomingType.RunRegExp, regExp, content }, 500); @@ -41,7 +40,7 @@ export class UserModerationMessageListener extends ModerationMessageListener { protected async onDelete(message: GuildMessage, t: TFunction, value: FilterResults) { floatPromise(deleteMessage(message)); - if (message.content.length > 25 && (await this.container.prisma.user.fetchModerationDirectMessageEnabled(message.author.id))) { + if (message.content.length > 25 && (await this.container.db.fetchModerationDirectMessageEnabled(message.author.id))) { await message.author.send( t(LanguageKeys.Events.Moderation.Messages.WordFilterDm, { filtered: codeBlock('md', cutText(value.filtered, 1900)) }) ); @@ -53,9 +52,13 @@ export class UserModerationMessageListener extends ModerationMessageListener { } protected onLogMessage(message: GuildMessage, t: TFunction, results: FilterResults) { - return addAutomaticFields(new EmbedBuilder(), cutText(results.highlighted, 4000)) + return new SkyraEmbed() + .splitFields(cutText(results.highlighted, 4000)) .setColor(Colors.Red) - .setAuthor(getFullEmbedAuthor(message.author, message.url)) + .setAuthor({ + name: `${message.author.tag} (${message.author.id})`, + iconURL: message.author.displayAvatarURL({ size: 128, format: 'png', dynamic: true }) + }) .setFooter({ text: `#${(message.channel as TextChannel).name} | ${t(LanguageKeys.Events.Moderation.Messages.WordFooter)}` }) .setTimestamp(); } diff --git a/projects/bot/src/listeners/moderation/moderationEntryAdd.ts b/projects/bot/src/listeners/moderation/moderationEntryAdd.ts new file mode 100644 index 000000000..5f6205224 --- /dev/null +++ b/projects/bot/src/listeners/moderation/moderationEntryAdd.ts @@ -0,0 +1,44 @@ +import { GuildSettings, ModerationEntity, writeSettings } from '#lib/database'; +import { resolveOnErrorCodes } from '#utils/common'; +import { SchemaKeys } from '#utils/moderationConstants'; +import { canSendEmbeds } from '@sapphire/discord.js-utilities'; +import { Listener } from '@sapphire/framework'; +import { RESTJSONErrorCodes } from 'discord-api-types/v9'; + +export class UserListener extends Listener { + public run(entry: ModerationEntity) { + return Promise.all([this.sendMessage(entry), this.scheduleDuration(entry)]); + } + + private async sendMessage(entry: ModerationEntity) { + const channel = await entry.fetchChannel(); + if (channel === null || !canSendEmbeds(channel)) return; + + const messageEmbed = await entry.prepareEmbed(); + + const options = { embeds: [messageEmbed] }; + try { + await resolveOnErrorCodes(channel.send(options), RESTJSONErrorCodes.MissingAccess, RESTJSONErrorCodes.MissingPermissions); + } catch (error) { + await writeSettings(entry.guild, [[GuildSettings.Channels.Logs.Moderation, null]]); + } + } + + private async scheduleDuration(entry: ModerationEntity) { + const taskName = entry.duration === null ? null : entry.appealTaskName; + if (taskName !== null) { + await this.container.schedule + .add(taskName, entry.duration! + Date.now(), { + catchUp: true, + data: { + [SchemaKeys.Case]: entry.caseId, + [SchemaKeys.User]: entry.userId, + [SchemaKeys.Guild]: entry.guildId, + [SchemaKeys.Duration]: entry.duration, + [SchemaKeys.ExtraData]: entry.extraData + } + }) + .catch((error) => this.container.logger.fatal(error)); + } + } +} diff --git a/projects/bot/src/listeners/moderation/moderationEntryEdit.ts b/projects/bot/src/listeners/moderation/moderationEntryEdit.ts new file mode 100644 index 000000000..89db0e83a --- /dev/null +++ b/projects/bot/src/listeners/moderation/moderationEntryEdit.ts @@ -0,0 +1,128 @@ +import { GuildSettings, ModerationEntity, writeSettings } from '#lib/database'; +import { resolveOnErrorCodes } from '#utils/common'; +import { SchemaKeys } from '#utils/moderationConstants'; +import { canSendEmbeds, GuildTextBasedChannelTypes } from '@sapphire/discord.js-utilities'; +import { Listener } from '@sapphire/framework'; +import { RESTJSONErrorCodes } from 'discord-api-types/v9'; +import type { Message, MessageEmbed } from 'discord.js'; + +export class UserListener extends Listener { + public run(old: ModerationEntity, entry: ModerationEntity) { + return Promise.all([this.cancelTask(old, entry), this.sendMessage(old, entry), this.scheduleDuration(old, entry)]); + } + + private async cancelTask(old: ModerationEntity, entry: ModerationEntity) { + // If the task was invalidated or had its duration set to null, delete any pending task + if ((!old.invalidated && entry.invalidated) || (old.duration !== null && entry.duration === null)) await entry.task?.delete(); + } + + private async sendMessage(old: ModerationEntity, entry: ModerationEntity) { + // Handle invalidation + if (!old.invalidated && entry.invalidated) return; + + // If both logs are equals, skip + if (entry.equals(old)) return; + + const channel = await entry.fetchChannel(); + if (channel === null || !canSendEmbeds(channel)) return; + + const messageEmbed = await entry.prepareEmbed(); + const previous = this.fetchModerationLogMessage(entry, channel); + + const options = { embeds: [messageEmbed] }; + try { + await resolveOnErrorCodes( + previous === null ? channel.send(options) : previous.edit(options), + RESTJSONErrorCodes.MissingAccess, + RESTJSONErrorCodes.MissingPermissions + ); + } catch (error) { + await writeSettings(entry.guild, [[GuildSettings.Channels.Logs.Moderation, null]]); + } + } + + private fetchModerationLogMessage(entry: ModerationEntity, channel: GuildTextBasedChannelTypes) { + if (entry.caseId === -1) throw new TypeError('UNREACHABLE.'); + + for (const message of channel.messages.cache.values()) { + if (this.validateModerationLogMessage(message, entry.caseId)) return message; + } + + return null; + } + + private validateModerationLogMessage(message: Message, caseId: number) { + return ( + message.author.id === process.env.CLIENT_ID && + message.attachments.size === 0 && + message.embeds.length === 1 && + this.validateModerationLogMessageEmbed(message.embeds[0]) && + message.embeds[0].footer!.text === `Case ${caseId}` + ); + } + + private validateModerationLogMessageEmbed(embed: MessageEmbed) { + return ( + embed.type === 'rich' && + this.validateModerationLogMessageEmbedAuthor(embed.author) && + this.validateModerationLogMessageEmbedDescription(embed.description) && + this.validateModerationLogMessageEmbedColor(embed.color) && + this.validateModerationLogMessageEmbedFooter(embed.footer) && + this.validateModerationLogMessageEmbedTimestamp(embed.timestamp) + ); + } + + private validateModerationLogMessageEmbedAuthor(author: MessageEmbed['author']) { + return author !== null && typeof author.name === 'string' && /[^#]{2,32}#\d{4}/.test(author.name) && typeof author.iconURL === 'string'; + } + + private validateModerationLogMessageEmbedDescription(description: MessageEmbed['description']) { + return typeof description === 'string' && description.split('\n').length >= 3; + } + + private validateModerationLogMessageEmbedColor(color: MessageEmbed['color']) { + return typeof color === 'number'; + } + + private validateModerationLogMessageEmbedFooter(footer: MessageEmbed['footer']) { + return footer !== null && typeof footer.text === 'string' && typeof footer.iconURL === 'string'; + } + + private validateModerationLogMessageEmbedTimestamp(timestamp: MessageEmbed['timestamp']) { + return typeof timestamp === 'number'; + } + + private async scheduleDuration(old: ModerationEntity, entry: ModerationEntity) { + if (old.duration === entry.duration) return; + + const previous = this.retrievePreviousSchedule(entry); + if (previous !== null) await previous.delete(); + + const taskName = entry.duration === null ? null : entry.appealTaskName; + if (taskName !== null) { + await this.container.schedule + .add(taskName, entry.duration! + Date.now(), { + catchUp: true, + data: { + [SchemaKeys.Case]: entry.caseId, + [SchemaKeys.User]: entry.userId, + [SchemaKeys.Guild]: entry.guildId, + [SchemaKeys.Duration]: entry.duration + } + }) + .catch((error) => this.container.logger.fatal(error)); + } + } + + private retrievePreviousSchedule(entry: ModerationEntity) { + return ( + this.container.schedule.queue.find( + (task) => + typeof task.data === 'object' && + task.data !== null && + task.data[SchemaKeys.Case] === entry.caseId && + task.data[SchemaKeys.Guild] === entry.guild.id + ) || null + ); + } +} diff --git a/src/listeners/reactions/rawMessageReactionAdd.ts b/projects/bot/src/listeners/reactions/rawMessageReactionAdd.ts similarity index 78% rename from src/listeners/reactions/rawMessageReactionAdd.ts rename to projects/bot/src/listeners/reactions/rawMessageReactionAdd.ts index 7e92cf00b..962526eaf 100644 --- a/src/listeners/reactions/rawMessageReactionAdd.ts +++ b/projects/bot/src/listeners/reactions/rawMessageReactionAdd.ts @@ -1,12 +1,13 @@ -import { Events } from '#lib/types'; +import { Events } from '#lib/types/Enums'; import { getEmojiString } from '#utils/functions'; import type { LLRCData } from '#utils/LongLivingReactionCollector'; import { ApplyOptions } from '@sapphire/decorators'; import { canReadMessages, isGuildBasedChannel } from '@sapphire/discord.js-utilities'; -import { Listener } from '@sapphire/framework'; -import { GatewayDispatchEvents, type GatewayMessageReactionAddDispatch, type TextChannel } from 'discord.js'; +import { Listener, ListenerOptions } from '@sapphire/framework'; +import { GatewayDispatchEvents, GatewayMessageReactionAddDispatch } from 'discord-api-types/v9'; +import type { TextChannel } from 'discord.js'; -@ApplyOptions({ event: GatewayDispatchEvents.MessageReactionAdd, emitter: 'ws' }) +@ApplyOptions({ event: GatewayDispatchEvents.MessageReactionAdd, emitter: 'ws' }) export class UserListener extends Listener { public run(raw: GatewayMessageReactionAddDispatch['d']) { const channel = this.container.client.channels.cache.get(raw.channel_id) as TextChannel | undefined; diff --git a/src/listeners/reactions/rawMessageReactionRemove.ts b/projects/bot/src/listeners/reactions/rawMessageReactionRemove.ts similarity index 58% rename from src/listeners/reactions/rawMessageReactionRemove.ts rename to projects/bot/src/listeners/reactions/rawMessageReactionRemove.ts index 1aa4c3482..7434969a8 100644 --- a/src/listeners/reactions/rawMessageReactionRemove.ts +++ b/projects/bot/src/listeners/reactions/rawMessageReactionRemove.ts @@ -1,10 +1,11 @@ -import { Events } from '#lib/types'; +import { Events } from '#lib/types/Enums'; import { ApplyOptions } from '@sapphire/decorators'; import { canReadMessages, isGuildBasedChannel } from '@sapphire/discord.js-utilities'; -import { Listener } from '@sapphire/framework'; -import { GatewayDispatchEvents, type GatewayMessageReactionRemoveDispatch, type TextChannel } from 'discord.js'; +import { Listener, ListenerOptions } from '@sapphire/framework'; +import { GatewayDispatchEvents, GatewayMessageReactionRemoveDispatch } from 'discord-api-types/v9'; +import type { TextChannel } from 'discord.js'; -@ApplyOptions({ event: GatewayDispatchEvents.MessageReactionRemove, emitter: 'ws' }) +@ApplyOptions({ event: GatewayDispatchEvents.MessageReactionRemove, emitter: 'ws' }) export class UserListener extends Listener { public run(data: GatewayMessageReactionRemoveDispatch['d']) { const channel = this.container.client.channels.cache.get(data.channel_id) as TextChannel; diff --git a/projects/bot/src/listeners/reactions/rawReactionAddBlockList.ts b/projects/bot/src/listeners/reactions/rawReactionAddBlockList.ts new file mode 100644 index 000000000..c5f4a82a0 --- /dev/null +++ b/projects/bot/src/listeners/reactions/rawReactionAddBlockList.ts @@ -0,0 +1,116 @@ +import { GuildEntity, GuildSettings, readSettings } from '#lib/database'; +import { api } from '#lib/discord/Api'; +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { HardPunishment, ModerationListener, SelfModeratorBitField } from '#lib/moderation'; +import { Events } from '#lib/types/Enums'; +import { floatPromise, seconds } from '#utils/common'; +import { Colors } from '#utils/constants'; +import { deleteMessage, getEmojiReactionFormat, SerializedEmoji } from '#utils/functions'; +import type { LLRCData } from '#utils/LongLivingReactionCollector'; +import { twemoji } from '#utils/util'; +import { ApplyOptions } from '@sapphire/decorators'; +import type { ListenerOptions } from '@sapphire/framework'; +import { fetchT, sendLocalized } from '@sapphire/plugin-i18next'; +import { hasAtLeastOneKeyInMap, Nullish, PickByValue } from '@sapphire/utilities'; +import { GuildMember, MessageEmbed, Permissions } from 'discord.js'; + +type ArgumentType = [data: LLRCData, reaction: SerializedEmoji, channelId: string | Nullish, blockedReactions: string[]]; + +@ApplyOptions({ event: Events.RawReactionAdd }) +export class UserModerationEvent extends ModerationListener { + protected keyEnabled: PickByValue = GuildSettings.Selfmod.Reactions.Enabled; + protected softPunishmentPath: PickByValue = GuildSettings.Selfmod.Reactions.SoftAction; + protected hardPunishmentPath: HardPunishment = { + action: GuildSettings.Selfmod.Reactions.HardAction, + actionDuration: GuildSettings.Selfmod.Reactions.HardActionDuration, + adder: 'reactions' + }; + + public async run(data: LLRCData, emoji: SerializedEmoji) { + const [enabled, blockedReactions, logChannelId, ignoredChannels, softAction, hardAction, adder] = await readSettings( + data.guild, + (settings) => [ + settings[GuildSettings.Selfmod.Reactions.Enabled], + settings[GuildSettings.Selfmod.Reactions.Blocked], + settings[GuildSettings.Channels.Logs.Moderation], + settings[GuildSettings.Channels.Ignore.ReactionAdd], + settings[GuildSettings.Selfmod.Reactions.SoftAction], + settings[GuildSettings.Selfmod.Reactions.HardAction], + settings.adders[this.hardPunishmentPath.adder] + ] + ); + + if (!enabled || blockedReactions.length === 0 || ignoredChannels.includes(data.channel.id)) return; + + const member = await data.guild.members.fetch(data.userId); + if (member.user.bot || (await this.hasPermissions(member))) return; + + const args = [data, emoji, logChannelId, blockedReactions] as const; + const preProcessed = this.preProcess(args); + if (preProcessed === null) return; + + this.processSoftPunishment(args, preProcessed, new SelfModeratorBitField(softAction)); + + if (!adder) return this.processHardPunishment(data.guild, data.userId, hardAction); + + try { + const points = typeof preProcessed === 'number' ? preProcessed : 1; + adder.add(data.userId, points); + } catch { + await this.processHardPunishment(data.guild, data.userId, hardAction); + } + } + + protected preProcess([, emoji, , blockedReactions]: Readonly) { + return blockedReactions.includes(emoji) ? 1 : null; + } + + protected onDelete([data, emoji]: Readonly) { + floatPromise( + api() + .channels(data.channel.id) + .messages(data.messageId) + .reactions(getEmojiReactionFormat(emoji), data.userId) + .delete({ reason: '[MODERATION] Automatic Removal of Blocked Emoji.' }) + ); + } + + protected onAlert([data]: Readonly) { + floatPromise( + sendLocalized(data.channel, { keys: LanguageKeys.Events.Reactions.Filter, formatOptions: { user: `<@${data.userId}>` } }).then( + (message) => deleteMessage(message, seconds(15)) + ) + ); + } + + protected async onLogMessage([data]: Readonly) { + const user = await this.container.client.users.fetch(data.userId); + const t = await fetchT(data.guild); + return new MessageEmbed() + .setColor(Colors.Red) + .setAuthor({ name: `${user.tag} (${user.id})`, iconURL: user.displayAvatarURL({ size: 128, format: 'png', dynamic: true }) }) + .setThumbnail( + data.emoji.id === null + ? `https://twemoji.maxcdn.com/72x72/${twemoji(data.emoji.name!)}.png` + : `https://cdn.discordapp.com/emojis/${data.emoji.id}.${data.emoji.animated ? 'gif' : 'png'}?size=64` + ) + .setDescription(`[${t(LanguageKeys.Misc.JumpTo)}](https://discord.com/channels/${data.guild.id}/${data.channel.id}/${data.messageId})`) + .setFooter({ text: `${data.channel.name} | ${t(LanguageKeys.Events.Reactions.FilterFooter)}` }) + .setTimestamp(); + } + + protected onLog(args: Readonly) { + this.container.client.emit( + Events.GuildMessageLog, + args[0].guild, + args[2], + GuildSettings.Channels.Logs.Moderation, + this.onLogMessage.bind(this, args) + ); + } + + private async hasPermissions(member: GuildMember) { + const roles = await readSettings(member, GuildSettings.Roles.Moderator); + return roles.length === 0 ? member.permissions.has(Permissions.FLAGS.BAN_MEMBERS) : hasAtLeastOneKeyInMap(member.roles.cache, roles); + } +} diff --git a/projects/bot/src/listeners/reactions/rawReactionAddNotify.ts b/projects/bot/src/listeners/reactions/rawReactionAddNotify.ts new file mode 100644 index 000000000..0bd13e395 --- /dev/null +++ b/projects/bot/src/listeners/reactions/rawReactionAddNotify.ts @@ -0,0 +1,125 @@ +import { GuildSettings, readSettings } from '#lib/database'; +import { api } from '#lib/discord/Api'; +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { Events } from '#lib/types/Enums'; +import { Colors } from '#utils/constants'; +import { getEmojiId, getEmojiReactionFormat, SerializedEmoji } from '#utils/functions'; +import type { LLRCData } from '#utils/LongLivingReactionCollector'; +import { twemoji } from '#utils/util'; +import { Collection } from '@discordjs/collection'; +import { ApplyOptions } from '@sapphire/decorators'; +import { Listener, ListenerOptions } from '@sapphire/framework'; +import { isNullish } from '@sapphire/utilities'; +import type { APIUser } from 'discord-api-types/v9'; +import { MessageEmbed } from 'discord.js'; + +@ApplyOptions({ event: Events.RawReactionAdd }) +export class UserListener extends Listener { + private readonly kCountCache = new Collection(); + private readonly kSyncCache = new Collection>(); + private kTimerSweeper: NodeJS.Timer | null = null; + + public async run(data: LLRCData, emoji: SerializedEmoji) { + const key = GuildSettings.Channels.Logs.Reaction; + const [allowedEmojis, logChannelId, twemojiEnabled, ignoreChannels, ignoreReactionAdd, ignoreAllEvents, t] = await readSettings( + data.guild, + (settings) => [ + settings[GuildSettings.Selfmod.Reactions.Allowed], + settings[key], + settings[GuildSettings.Events.Twemoji], + settings[GuildSettings.Messages.IgnoreChannels], + settings[GuildSettings.Channels.Ignore.ReactionAdd], + settings[GuildSettings.Channels.Ignore.All], + settings.getLanguage() + ] + ); + + const emojiId = getEmojiId(emoji); + if (allowedEmojis.some((allowedEmoji) => getEmojiId(allowedEmoji) === emojiId)) return; + + this.container.client.emit(Events.ReactionBlocked, data, emoji); + if (isNullish(logChannelId) || (!twemojiEnabled && data.emoji.id === null)) return; + + if (ignoreChannels.includes(data.channel.id)) return; + if (ignoreReactionAdd.some((id) => id === data.channel.id || data.channel.parentId === id)) return; + if (ignoreAllEvents.some((id) => id === data.channel.id || data.channel.parentId === id)) return; + + if ((await this.retrieveCount(data, emoji)) > 1) return; + + const user = await this.container.client.users.fetch(data.userId); + if (user.bot) return; + + this.container.client.emit(Events.GuildMessageLog, data.guild, logChannelId, key, () => + new MessageEmbed() + .setColor(Colors.Green) + .setAuthor({ name: `${user.tag} (${user.id})`, iconURL: user.displayAvatarURL({ size: 128, format: 'png', dynamic: true }) }) + .setThumbnail( + data.emoji.id === null + ? `https://twemoji.maxcdn.com/72x72/${twemoji(data.emoji.name!)}.png` + : `https://cdn.discordapp.com/emojis/${data.emoji.id}.${data.emoji.animated ? 'gif' : 'png'}?size=64` + ) + .setDescription( + [ + `**Emoji**: ${data.emoji.name}${data.emoji.id === null ? '' : ` [${data.emoji.id}]`}`, + `**Channel**: ${data.channel}`, + `**Message**: [${t(LanguageKeys.Misc.JumpTo)}](https://discord.com/channels/${data.guild.id}/${data.channel.id}/${ + data.messageId + })` + ].join('\n') + ) + .setFooter({ text: `${t(LanguageKeys.Events.Reactions.Reaction)} • ${data.channel.name}` }) + .setTimestamp() + ); + } + + public onUnload() { + super.onUnload(); + if (this.kTimerSweeper) clearInterval(this.kTimerSweeper); + } + + protected async retrieveCount(data: LLRCData, emoji: SerializedEmoji) { + const id = `${data.messageId}.${getEmojiId(emoji)}`; + + // Pull from sync queue, and if it exists, await + const sync = this.kSyncCache.get(id); + if (typeof sync !== 'undefined') await sync; + + // Retrieve the reaction count + const previousCount = this.kCountCache.get(id); + if (typeof previousCount !== 'undefined') { + previousCount.count++; + previousCount.sweepAt = Date.now() + 120000; + return previousCount.count; + } + + // Pull the reactions from the API + const promise = this.fetchCount(data, emoji, id); + this.kSyncCache.set(id, promise); + return (await promise).count; + } + + private async fetchCount(data: LLRCData, emoji: SerializedEmoji, id: string) { + const users = (await api().channels(data.channel.id).messages(data.messageId).reactions(getEmojiReactionFormat(emoji)).get()) as APIUser[]; + const count: InternalCacheEntry = { count: users.length, sweepAt: Date.now() + 120000 }; + this.kCountCache.set(id, count); + this.kSyncCache.delete(id); + + if (this.kTimerSweeper === null) { + this.kTimerSweeper = setInterval(() => { + const now = Date.now(); + this.kCountCache.sweep((entry) => entry.sweepAt < now); + if (this.kTimerSweeper !== null && this.kCountCache.size === 0) { + clearInterval(this.kTimerSweeper); + this.kTimerSweeper = null; + } + }, 5000).unref(); + } + + return count; + } +} + +interface InternalCacheEntry { + sweepAt: number; + count: number; +} diff --git a/src/listeners/reactions/rawReactionAddRole.ts b/projects/bot/src/listeners/reactions/rawReactionAddRole.ts similarity index 59% rename from src/listeners/reactions/rawReactionAddRole.ts rename to projects/bot/src/listeners/reactions/rawReactionAddRole.ts index 0d8c89f54..944d5f744 100644 --- a/src/listeners/reactions/rawReactionAddRole.ts +++ b/projects/bot/src/listeners/reactions/rawReactionAddRole.ts @@ -1,37 +1,37 @@ -import { readSettings } from '#lib/database'; +import { GuildSettings, readSettings } from '#lib/database'; import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { Events } from '#lib/types'; +import { Events } from '#lib/types/Enums'; +import { resolveEmojiId, sendTemporaryMessage, SerializedEmoji } from '#utils/functions'; import type { LLRCData } from '#utils/LongLivingReactionCollector'; -import { resolveEmojiId, sendTemporaryMessage, type SerializedEmoji } from '#utils/functions'; import { ApplyOptions } from '@sapphire/decorators'; -import { Listener } from '@sapphire/framework'; +import { Listener, ListenerOptions } from '@sapphire/framework'; import { resolveKey } from '@sapphire/plugin-i18next'; import { DiscordAPIError } from 'discord.js'; -@ApplyOptions({ event: Events.RawReactionAdd }) +@ApplyOptions({ event: Events.RawReactionAdd }) export class UserListener extends Listener { - public async run(data: LLRCData, emoji: SerializedEmoji) { + public async run(parsed: LLRCData, emoji: SerializedEmoji) { const emojiId = resolveEmojiId(emoji); - const settings = await readSettings(data.guild); - const roleEntry = settings.reactionRoles.find( - (entry) => - resolveEmojiId(entry.emoji) === emojiId && - entry.channel === data.channel.id && - (entry.message ? entry.message === data.messageId : true) - ); + const [roleEntry, allRoleSets] = await readSettings(parsed.guild, (settings) => [ + settings[GuildSettings.ReactionRoles].find( + (entry) => + resolveEmojiId(entry.emoji) === emojiId && + entry.channel === parsed.channel.id && + (entry.message ? entry.message === parsed.messageId : true) + ), + settings[GuildSettings.Roles.UniqueRoleSets] + ]); if (!roleEntry) return; - const allRoleSets = settings.rolesUniqueRoleSets; - try { - const member = await data.guild.members.fetch(data.userId); + const member = await parsed.guild.members.fetch(parsed.userId); if (member.roles.cache.has(roleEntry.role)) return; // Convert the array into a set const memberRoles = new Set(member.roles.cache.keys()); // Remove the everyone role from the set - memberRoles.delete(data.guild.id); + memberRoles.delete(parsed.guild.id); for (const set of allRoleSets) { // If the set doesn't have the role being added to the user skip @@ -46,7 +46,7 @@ export class UserListener extends Listener { await member.roles.set([...memberRoles]); } catch (error) { if (error instanceof DiscordAPIError && error.code === 50013) { - const message = await data.channel.messages.fetch(data.messageId); + const message = await parsed.channel.messages.fetch(parsed.messageId); await sendTemporaryMessage(message, await resolveKey(message, LanguageKeys.Events.Reactions.SelfRoleHierarchy)); } else { this.container.client.emit(Events.Error, error); diff --git a/src/listeners/reactions/rawReactionRemoveRole.ts b/projects/bot/src/listeners/reactions/rawReactionRemoveRole.ts similarity index 53% rename from src/listeners/reactions/rawReactionRemoveRole.ts rename to projects/bot/src/listeners/reactions/rawReactionRemoveRole.ts index 44124d1cb..8a34eb1e6 100644 --- a/src/listeners/reactions/rawReactionRemoveRole.ts +++ b/projects/bot/src/listeners/reactions/rawReactionRemoveRole.ts @@ -1,24 +1,26 @@ -import { readSettings } from '#lib/database'; -import { Events } from '#lib/types'; +import { GuildSettings, readSettings } from '#lib/database'; +import { Events } from '#lib/types/Enums'; import { resolveEmojiId } from '#utils/functions'; import { ApplyOptions } from '@sapphire/decorators'; import { isGuildBasedChannel } from '@sapphire/discord.js-utilities'; -import { Listener } from '@sapphire/framework'; -import type { GatewayMessageReactionRemoveDispatch, TextChannel } from 'discord.js'; +import { Listener, ListenerOptions } from '@sapphire/framework'; +import type { GatewayMessageReactionRemoveDispatch } from 'discord-api-types/v9'; +import type { TextChannel } from 'discord.js'; -@ApplyOptions({ event: Events.RawReactionRemove }) +@ApplyOptions({ event: Events.RawReactionRemove }) export class UserListener extends Listener { public async run(channel: TextChannel, data: GatewayMessageReactionRemoveDispatch['d']) { // If the channel is not a text channel then stop processing if (!isGuildBasedChannel(channel)) return; const emojiId = resolveEmojiId(data.emoji); - const settings = await readSettings(channel.guild); - const roleEntry = settings.reactionRoles.find( - (entry) => - resolveEmojiId(entry.emoji) === emojiId && - entry.channel === data.channel_id && - (entry.message ? entry.message === data.message_id : true) + const roleEntry = await readSettings(channel.guild, (settings) => + settings[GuildSettings.ReactionRoles].find( + (entry) => + resolveEmojiId(entry.emoji) === emojiId && + entry.channel === data.channel_id && + (entry.message ? entry.message === data.message_id : true) + ) ); if (!roleEntry) return; diff --git a/src/listeners/userUpdate.ts b/projects/bot/src/listeners/userUpdate.ts similarity index 58% rename from src/listeners/userUpdate.ts rename to projects/bot/src/listeners/userUpdate.ts index 57aa8129a..840464d62 100644 --- a/src/listeners/userUpdate.ts +++ b/projects/bot/src/listeners/userUpdate.ts @@ -1,15 +1,12 @@ -import { readSettings } from '#lib/database'; -import { getT } from '#lib/i18n'; +import { GuildSettings, readSettings } from '#lib/database'; import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { Events, type TypedT } from '#lib/types'; +import type { CustomGet } from '#lib/types'; +import { Events } from '#lib/types/Enums'; +import { filter, map } from '#utils/common'; import { Colors } from '#utils/constants'; -import { getFullEmbedAuthor } from '#utils/util'; -import { EmbedBuilder } from '@discordjs/builders'; import { Listener } from '@sapphire/framework'; -import { filter } from '@sapphire/iterator-utilities/filter'; -import { map } from '@sapphire/iterator-utilities/map'; -import type { TFunction } from '@sapphire/plugin-i18next'; -import type { Guild, User } from 'discord.js'; +import { Guild, MessageEmbed, User } from 'discord.js'; +import type { TFunction } from 'i18next'; export class UserListener extends Listener { public async run(previous: User, user: User) { @@ -27,15 +24,17 @@ export class UserListener extends Listener { } private async processGuild(guild: Guild, user: User, previous: string, next: string) { - const settings = await readSettings(guild); - const logChannelId = settings.channelsLogsMemberUsernameUpdate; - if (!logChannelId) return; + const [logChannelId, language] = await readSettings(guild, (settings) => [ + settings[GuildSettings.Channels.Logs.MemberUserNameUpdate], + settings.getLanguage() + ]); - // Send the Username log - const t = getT(settings.language); - this.container.client.emit(Events.GuildMessageLog, guild, logChannelId, 'channelsLogsMemberUsernameUpdate', () => - this.buildEmbed(user, t, this.getNameDescription(t, previous, next), LanguageKeys.Events.Guilds.Members.UsernameUpdate) - ); + if (logChannelId) { + // Send the Username log + this.container.client.emit(Events.GuildMessageLog, guild, logChannelId, GuildSettings.Channels.Logs.MemberUserNameUpdate, () => + this.buildEmbed(user, language, this.getNameDescription(language, previous, next), LanguageKeys.Events.Guilds.Members.UsernameUpdate) + ); + } } private getNameDescription(t: TFunction, previousName: string | null, nextName: string | null) { @@ -48,10 +47,10 @@ export class UserListener extends Listener { return [t(previous, { previousName }), t(next, { nextName })].join('\n'); } - private buildEmbed(user: User, t: TFunction, description: string, footerKey: TypedT) { - return new EmbedBuilder() + private buildEmbed(user: User, t: TFunction, description: string, footerKey: CustomGet) { + return new MessageEmbed() .setColor(Colors.Yellow) - .setAuthor(getFullEmbedAuthor(user)) + .setAuthor({ name: `${user.tag} (${user.id})`, iconURL: user.displayAvatarURL({ size: 128, format: 'png', dynamic: true }) }) .setDescription(description) .setFooter({ text: t(footerKey) }) .setTimestamp(); diff --git a/projects/bot/src/locales/en-US/commands/management.json b/projects/bot/src/locales/en-US/commands/management.json new file mode 100644 index 000000000..5e22a5b5d --- /dev/null +++ b/projects/bot/src/locales/en-US/commands/management.json @@ -0,0 +1,591 @@ +{ + "commandModeEnable": "Enables the sub-system.", + "commandModeDisable": "Disables the sub-system.", + "commandModeActionAlert": "Toggle message alerts in the channel.", + "commandModeActionLog": "Toggle message logs in the moderation logs channel, if set.", + "commandModeActionDelete": "Toggle message deletions.", + "commandModePunishment": "The moderation action to take.", + "commandModePunishmentDuration": "The duration for the punishment.", + "commandModeThreshold": "The amount of infractions that can be done within `Threshold-Duration` before taking action, instantly if unset.", + "commandModeThresholdDuration": "The time in which infractions will accumulate before taking action, instantly if unset.", + "commandModeReminder": "`Action Log` requires `channel.moderation-logs` to be set up.", + "commandHandlerAborted": "Aborted", + "permissionNodesHigher": "{{REDCROSS}} You cannot modify nor preview the permission nodes for this target.", + "permissionNodesCannotAllowEveryone": "{{REDCROSS}} You cannot allow commands for the `@everyone` role.", + "permissionNodesInvalidType": "{{REDCROSS}} Invalid type, expected either of `allow` or `deny`.", + "permissionNodesAdd": "{{GREENTICK}} Successfully added the command to the permission node.", + "permissionNodesNodeNotExists": "{{REDCROSS}} The selected permission node does not exist.", + "permissionNodesCommandNotExists": "{{REDCROSS}} The selected command does not exist in the permision node.", + "permissionNodesRemove": "{{GREENTICK}} Successfully removed the command from the permission node.", + "permissionNodesReset": "{{GREENTICK}} Successfully removed all commands from the permission node.", + "permissionNodesShowName": "Permissions for: __{{name}}__", + "permissionNodesShowAllow": "**Allow**: {{allow}}", + "permissionNodesShowDeny": "**Deny**: {{deny}}", + "guildInfoTitles": { + "CHANNELS": "Channels", + "MEMBERS": "Members", + "OTHER": "Other" + }, + "guildInfoChannels": "• **{{text}}** Text, **{{voice}}** Voice, **{{categories}}** categories.\n• AFK: {{afkChannelText}}", + "guildInfoChannelsAfkChannelText": "**<#{{afkChannel}}>** after **{{afkTime}}**min", + "guildInfoMembers": "• **{{memberCount, number}}** member(s)\n• Owner: **{{owner.tag}}**\n (ID: **{{owner.id}}**)", + "guildInfoOther": "• Roles: **{{size}}**\n• Created: **{{createdAt}}**\n• Verification Level: **{{verificationLevel, humanLevels}}**", + "guildInfoBanner": "Banner Image", + "guildInfoIcon": "Icon Image", + "guildInfoSplash": "Splash Image", + "guildInfoDiscoverySplash": "Discovery Splash Image", + "roleInfoTitles": { + "PERMISSIONS": "Permissions" + }, + "roleInfoData": "ID: **{{role.id}}**\nName: **{{role.name}}**\nColor: **{{role.hexColor}}**\nHoisted: **{{hoisted}}**\nPosition: **{{role.rawPosition}}**\nMentionable: **{{mentionable}}**", + "roleInfoAll": "All Permissions granted.", + "roleInfoNoPermissions": "Permissions not granted.", + "filterUndefinedWord": "You must write what you want me to filter.", + "filterTooLong": "{{REDCROSS}} **The word you defined is too long**.\n\n**Tip**: if you want to filter links/URLs, use an identifier (for example with YouTube, to filter `https://www.youtube.com/watch?v=dQw4w9WgXcQ`, it's more effective to filter `dQw4w9WgXcQ`).\nIf you want to filter an entire domain (e.g. `youtube.com`) use the link filter system instead.", + "filterAlreadyFiltered": "This word is already filtered.", + "filterNotFiltered": "This word is not filtered.", + "filterAdded": "{{GREENTICK}} Success! Added the word {{word}} to the filter.", + "filterRemoved": "{{GREENTICK}} Success! Removed the word {{word}} from the filter.", + "filterReset": "{{GREENTICK}} Success! The filter has been reset.", + "filterShowEmpty": "The list of filtered words is empty!", + "filterShow": "Filtered words in this server: {{words}}", + "manageCommandAutoDeleteShowEmpty": "There are no command autodelete configured right now.", + "manageCommandAutoDeleteShow": "All command autodeletes configured:{{codeblock}}", + "manageCommandAutoDeleteAdd": "{{GREENTICK}} Success! All successful commands in {{channel}} will be deleted after {{time, duration}}!", + "manageCommandAutoDeleteRemove": "{{GREENTICK}} Success! Commands will not be automatically deleted in {{channel}} anymore!", + "manageCommandAutoDeleteRemoveNotset": "{{REDCROSS}} The channel {{channel}} was not configured to automatically delete messages!", + "manageCommandAutoDeleteReset": "All the command autodeletes have been reset.", + "manageCommandChannelShow": "List of disabled commands in {{channel}}: {{commands}}", + "manageCommandChannelShowEmpty": "The list of disabled commands for the specified channel is empty!", + "manageCommandChannelAddAlreadyset": "The command you are trying to disable is already disabled!", + "manageCommandChannelAdd": "Successfully disabled the command {{command}} for the channel {{channel}}!", + "manageCommandChannelRemoveNotset": "The command you are trying to enable was not disabled for {{channel}}.", + "manageCommandChannelRemove": "Successfully enabled the command {{command}} for the channel {{channel}}!", + "manageCommandChannelResetEmpty": "This channel had no disabled command, so I decided to do nothing.", + "manageCommandChannelReset": "Successfully enabled all disabled commands in {{channel}}, enjoy!", + "manageReactionRolesShowEmpty": "There are no reaction roles set up in this server.", + "manageReactionRolesAddChannel": "{{GREENTICK}} Success! I will now give the role when people react with {{emoji}} to any message from {{channel}}!", + "manageReactionRolesAddPrompt": "Listening now! Please react to a message and I will bind the reaction with the role!", + "manageReactionRolesAddMissing": "I waited, but you did not seem to have reacted to a message.", + "manageReactionRolesAdd": "{{GREENTICK}} Success! I will now give the role when people react with {{emoji}} at {{url}}!", + "manageReactionRolesRemoveNotExists": "The reaction role you specified does not exist.", + "manageReactionRolesRemove": "{{GREENTICK}} Success! I will not longer give the role when people react with {{emoji}} at {{url}}!", + "manageReactionRolesResetEmpty": "There were no reaction roles set up.", + "manageReactionRolesReset": "{{GREENTICK}} Successfully removed all reaction roles.", + "configurationEquals": "Successfully configured: no changes were made.", + "setIgnoreChannelsSet": "Ignoring all command input from {{channel}} now.", + "setIgnoreChannelsRemoved": "Listening all command input from {{channel}} now.", + "setImageLogsSet": "Successfully set the image logs channel to {{channel}}.", + "setMemberAddLogsSet": "Successfully set the member add logs channel to {{channel}}.", + "setMemberRemoveLogsSet": "Successfully set the member remove logs channel to {{channel}}.", + "setMessageUpdateLogsSet": "Successfully set the message update logs channel to {{channel}}.", + "setMessageDeleteLogsSet": "Successfully set the message delete logs channel to {{channel}}.", + "setModLogsSet": "Successfully set the mod logs channel to {{channel}}.", + "setPrefixSet": "Successfully set the prefix to `{{prefix}}`. Use `{{prefix}}setPrefix NewPrefix` to change it again.", + "stickyRolesNotExists": "The user {{user}} does not have any sticky roles or does not have the specified one.", + "stickyRolesReset": "Successfully removed all sticky roles from {{user}}.", + "stickyRolesRemove": "Successfully removed the specified role from {{user}}.", + "stickyRolesAdd": "Successfully added the specified role as sticky to {{user}}.", + "stickyRolesShowEmpty": "There are no sticky roles to show.", + "stickyRolesShowSingle": "Sticky Role(s) for **{{user}}**: {{roles, andList}}.", + "createMuteDescription": "Prepare the mute system.", + "createMuteExtended": { + "extendedHelp": "This command prepares the mute system by creating a role called `muted`, and configuring it to the server settings. This command also modifies all channels (where possible) permissions and disables the permission **{{SEND_MESSAGES, permissions}}** in text channels and **{{CONNECT, permissions}}** in voice channels for said role." + }, + "permissionNodesDescription": "Configure the permission nodes for this server.", + "permissionNodesExtended": { + "usages": [ + "add Role/Member allow/deny Command", + "remove Role/Member allow/deny Command", + "reset Role/Member", + "show Role/Member", + "show", + "Role/Member" + ], + "extendedHelp": "Permission nodes are per-user and per-role overrides. They are used when the built-in permissions system is not enough.\nFor example, in some servers they want to give a staff role the permissions to use mute and warn, but not ban and others (reserved to moderators), and only warn is available for the configurable staff-level permission, so you can tell me to allow the mute command for the staff role now.", + "explainedUsage": [ + ["Action", "Either `add`, `remove`, `reset`, or `show`. Defaults to `show`."], + ["Target", "Either a role name or a user name, allowing IDs and mentions for either."], + ["Type", "Either `allow` or `deny`."], + ["Command", "The name of the command to allow or deny."] + ], + "examples": ["add staff allow warn", "add moderators deny ban", "remove staff allow warn", "reset staff", "show staff"], + "reminder": "The server owner cannot have any actions, nor the `everyone` role can have allowed commands." + }, + "managecommandautodeleteDescription": "Manage per-channel auto-delete timer.", + "managecommandautodeleteExtended": { + "usages": ["add TextChannel Seconds", "remove TextChannel", "reset", "show", ""], + "extendedHelp": "This command manages this server's per-channel command auto-delete timer, it serves well to leave a channel clean from commands.", + "explainedUsage": [ + ["add", "Add an auto-delete timer for the specified channel."], + ["remove", "Remove the auto-timer from the specified channel."], + ["reset", "Clear all auto-delete timers."], + ["show", "Show the auto-delete timer for all channels."] + ], + "reminder": "The channel argument is optional, defaulting to the message's channel, but it uses fuzzy search when possible.", + "examples": ["show", "add #general 4s", "remove #general", "reset"] + }, + "manageCommandChannelDescription": "Manage per-channel blocked command list.", + "manageCommandChannelExtended": { + "usages": ["add TextChannel Command", "remove TextChannel Command", "reset TextChannel", "show TextChannel"], + "extendedHelp": "This command manages this server's per-channel blocked command list, it serves well to disable certain commands you do not want to be used in certain channels (to disable a command globally, use the `disabledCommands` settings key to disable in all channels.", + "explainedUsage": [ + ["show [channel]", "Show the list of commands blocked in the specified channel."], + ["add [channel] ", "Add a command to the specified channel's list of blocked commands."], + ["remove [channel] ", "Remove a command from the specified channel's list of blocked commands."], + ["reset [channel]", "Clear the list of commands blocked in the specified channel."] + ], + "reminder": "The channel argument is optional, but it uses fuzzy search when possible.", + "examples": ["add #general profile", "remove #general profile", "reset #general", "show #general"] + }, + "manageReactionRolesDescription": "Manage the reaction roles for this server.", + "manageReactionRolesExtended": { + "usages": ["add Role", "add Role TextChannel Emoji", "remove Role Message", "reset", "show"], + "extendedHelp": "Seamlessly set up reaction roles in your server! When adding reaction roles, I listen to your reactions for 5 minutes and I bind the first reaction from you alongside the channel and the message, with the specified role.\nOtherwise, if a channel is specified, a prompt will not be created, and the reaction role will be bound to all of the channel's messages.\n\nThe best way to add new reaction roles is by using `add @role`. If you prefer not binding the reaction to a specific message then use `add @role #channel emoji`", + "explainedUsage": [ + ["show", "Retrieve the list of all reaction roles."], + ["add ", "Adds a reaction role binding the first reacted message since the execution with the role."], + ["remove ", "Removes a reaction role, use `show` to get a list of them."], + ["reset", "Removes all reaction roles."] + ], + "examples": ["add @role", "add @role #channel emoji", "remove @role 123456789012345678", "reset", "show"] + }, + "rolesAdded": "The following roles have been added to your profile: `{{roles}}`", + "rolesAuditlog": "Authorized: Public Role Management | 'Roles' Command.", + "rolesListEmpty": "This server does not have a role listed as a public role.", + "rolesListTitle": "List of public roles", + "rolesNotManageable": "The following roles cannot be given by me due to their hierarchy role position: `{{roles}}`", + "rolesNotPublic": "The following roles are not public: `{{roles}}`", + "rolesRemoved": "The following roles have been removed from your profile: `{{roles}}`", + "setIgnoreChannelsDescription": "Set a channel to the ignore channel list.", + "setIgnoreChannelsExtended": { + "usages": ["here/TextChannel"], + "extendedHelp": "This command helps you setting up ignored channels. An ignored channel is a channel where nobody but moderators can use Skyra's commands.\nUnlike removing the **{{SEND_MESSAGES, permissions}}** permission, Skyra is still able to send (and therefore execute commands) messages, which allows moderators to use moderation commands in the channel.\nUse this if you want to ban any command usage from the bot in a specific channel.", + "explainedUsage": [ + [ + "channel", + "A TextChannel. You can either put the name of the channel, tag it, or type in \"here\" to select the channel the message was sent." + ] + ], + "reminder": "You cannot set the same channel twice, instead, Skyra will remove it.", + "examples": ["#general", "here"] + }, + "setImageLogsDescription": "Set the image logs channel.", + "setImageLogsExtended": { + "usages": ["here/TextChannel"], + "extendedHelp": "This command helps you setting up the image log channel. Whenever a member sends an image attachment, it will send an embed message with the attachment re-uploaded.\nAll messages are in embeds so you will need to enable the permission **{{EMBED_LINKS, permissions}}** for Skyra.", + "explainedUsage": [ + [ + "channel", + "A TextChannel. You can either put the name of the channel, tag it, or type in \"here\" to select the channel the message was sent." + ] + ], + "examples": ["#image-logs", "here"] + }, + "setMemberAddLogsDescription": "Set the member add logs channel.", + "setMemberAddLogsExtended": { + "usages": ["here/TextChannel"], + "extendedHelp": "This command helps you setting up the member add log channel, which will receive a message each time a user joins.\nIf a muted user joins, it will send a special \"Muted Member Joined\" event.", + "explainedUsage": [ + [ + "channel", + "A TextChannel. You can either put the name of the channel, tag it, or type in \"here\" to select the channel the message was sent." + ] + ], + "examples": ["#member-logs", "here"], + "reminder": "All messages are in embeds so you will need to enable the permission **{{EMBED_LINKS, permissions}}** for Skyra." + }, + "setMemberRemoveLogsDescription": "Set the member remove logs channel.", + "setMemberRemoveLogsExtended": { + "usages": ["here/TextChannel"], + "extendedHelp": "This command helps you setting up the member remove log channel, which will receive a message each time a user leaves, is kicked, or is banned.\nIn the case of the last two, it will send a special \"User Kicked\" or \"User Banned\" event.", + "explainedUsage": [ + [ + "channel", + "A TextChannel. You can either put the name of the channel, tag it, or type in \"here\" to configure the channel this command was used in." + ] + ], + "examples": ["#member-logs", "here"], + "reminder": "All messages are in embeds so you will need to enable the permission **{{EMBED_LINKS, permissions}}** for Skyra." + }, + "setMessageUpdateLogsDescription": "Set the message update logs channel.", + "setMessageUpdateLogsExtended": { + "usages": ["here/TextChannel"], + "extendedHelp": "This command helps you setting up the message update log channel, which will receive a message each time a message is edited.", + "explainedUsage": [ + [ + "channel", + "A TextChannel. You can either put the name of the channel, tag it, or type in \"here\" to configure the channel this command was used in." + ] + ], + "reminder": "All messages are in embeds so you will need to enable the permission **{{EMBED_LINKS, permissions}}** for Skyra.", + "examples": ["#message-logs", "here"] + }, + "setMessageDeleteLogsDescription": "Set the message delete logs channel.", + "setMessageDeleteLogsExtended": { + "usages": ["here/TextChannel"], + "extendedHelp": "This command helps you setting up the message delete log channel, which will receive a message each time a message is deleted.", + "explainedUsage": [ + [ + "channel", + "A TextChannel. You can either put the name of the channel, tag it, or type in \"here\" to configure the channel this command was used in." + ] + ], + "reminder": "All messages are in embeds so you will need to enable the permission **{{EMBED_LINKS, permissions}}** for Skyra.\nDue to Discord limitations, Skyra cannot know who deleted a message.", + "examples": ["#message-logs", "here"] + }, + "setmodlogsDescription": "Set the mod logs channel.", + "setmodlogsExtended": { + "usages": ["here/TextChannel"], + "extendedHelp": "This command helps you setting up the mod log channel. A mod log channel only sends case reports indexed by a number case and with \"claimable\" reasons and moderators.\nThis channel is not a must and you can always retrieve specific modlogs with the `case` command.\nAll messages are in embeds so you will need to enable the permission **{{EMBED_LINKS, permissions}}** for Skyra.\nFor auto-detection, you need to individually set the \"events\" you want to listen: `events.ban-add`, `events.ban-remove` via the `config` command.", + "explainedUsage": [ + [ + "channel", + "A TextChannel. You can either put the name of the channel, tag it, or type in \"here\" to select the channel the message was sent." + ] + ], + "reminder": "Due to Discord limitations, the auto-detection does not detect kicks. You need to use the `kick` command if you want to document them as a formal moderation log case.", + "examples": ["#mod-logs", "here"] + }, + "setprefixDescription": "Set Skyra's prefix.", + "setprefixExtended": { + "usages": ["Prefix"], + "extendedHelp": "This command helps you setting up Skyra's prefix. A prefix is an affix that is added in front of the word, in this case, the message.\nIt allows bots to distinguish between a regular message and a command. By nature, the prefix between should be different to avoid conflicts.\nIf you forget Skyra's prefix, simply mention her with nothing else and she will tell you the current prefix.\nAlternatively, you can prefix the commands with her name and a comma (for example `Skyra, ping`).", + "explainedUsage": [["Prefix", "The prefix to set. Default one in Skyra is `{{DEFAULT_PREFIX}}`."]], + "reminder": "Your prefix should only contain characters everyone can write and type.", + "examples": ["&", "="] + }, + "guildInfoDescription": "Check the information of the server.", + "guildInfoExtended": { + "extendedHelp": "The serverinfo command displays information for the server the message got sent.\nIt shows the amount of channels, with the count for each category, the amount of members (given from the API), the owner with their user id, the amount of roles, region, creation date, verification level... between others." + }, + "roleInfoDescription": "Check the information for a role.", + "roleInfoExtended": { + "usages": ["Role", ""], + "extendedHelp": "The roleinfo command displays information for a role, such as its id, name, color, whether it's hoisted (displays separately) or not, it's role hierarchy position, whether it's mentionable or not, how many members have said role, and its permissions.\nIt sends an embedded message with the color of the role.", + "explainedUsage": [["Role", "The role name, name, mention or id."]], + "examples": ["Administrator", "Moderator", ""] + }, + "stickyRolesDescription": "Manage sticky roles for users.", + "stickyRolesExtended": { + "usages": ["add User Role", "remove User Role", "reset User", "show User", "User"], + "extendedHelp": "The stickyRoles command allows you to manage per-member's sticky roles, they are roles that are kept even when you leave, and are applied back as soon as they join.", + "explainedUsage": [ + ["Action", "Either you want to check the sticky roles, add one, remove one, or remove all of them."], + ["User", "The user target for all the actions."], + ["Role", "The role to add or remove."] + ], + "examples": ["add Skyra Goddess", "show Skyra", "remove Skyra Goddess", "reset Skyra"], + "reminder": "The member's roles will not be modified by this command, you need to add or remove them." + }, + "attachmentsModeDescription": "Manage this server's flags for the attachments filter.", + "attachmentsModeExtended": { + "usages": [ + "on/e/enable", + "off/d/disable", + "action/soft-action alert/log/delete", + "punish/punishment none/warn/mute/kick/softban/ban", + "pd/punish-duration/punishment-duration Timespan", + "tm/threshold Integer", + "td/threshold-duration Timespan", + "sh/show", + "" + ], + "extendedHelp": "The attachmentsMode command manages the behavior of the attachments system.", + "explainedUsage": [ + ["Enable", "$t(commands/management:commandModeEnable)"], + ["Disable", "$t(commands/management:commandModeDisable)"], + ["Action Alert", "$t(commands/management:commandModeActionAlert)"], + ["Action Log", "$t(commands/management:commandModeActionLog)"], + ["Action Delete", "$t(commands/management:commandModeActionDelete)"], + ["Punishment", "$t(commands/management:commandModePunishment)"], + ["Punishment-Duration", "$t(commands/management:commandModePunishmentDuration)"], + ["Threshold-Maximum", "$t(commands/management:commandModeThreshold)"], + ["Threshold-Duration", "$t(commands/management:commandModeThresholdDuration)"] + ], + "reminder": "$t(commands/management:commandModeReminder)", + "examples": [ + "enable", + "disable", + "action alert", + "punishment ban", + "punishment mute", + "punishment-duration 1m", + "threshold-maximum 5", + "threshold-duration 30s" + ] + }, + "capitalsModeDescription": "Manage this server's flags for the caps filter.", + "capitalsModeExtended": { + "usages": [ + "on/e/enable", + "off/d/disable", + "action/soft-action alert/log/delete", + "punish/punishment none/warn/mute/kick/softban/ban", + "pd/punish-duration/punishment-duration Timespan", + "tm/threshold-maximum Integer", + "td/threshold-duration Timespan", + "sh/show", + "" + ], + "extendedHelp": "The capitalsMode command manages the behavior of the caps system.\nThe minimum amount of characters before filtering can be set with `Skyra, settings set selfmod.capitals.minimum `.\nThe percentage of uppercase letters can be set with `Skyra, settings set selfmod.capitals.maximum `.", + "explainedUsage": [ + ["Enable", "$t(commands/management:commandModeEnable)"], + ["Disable", "$t(commands/management:commandModeDisable)"], + ["Action Alert", "$t(commands/management:commandModeActionAlert)"], + ["Action Log", "$t(commands/management:commandModeActionLog)"], + ["Action Delete", "$t(commands/management:commandModeActionDelete)"], + ["Punishment", "$t(commands/management:commandModePunishment)"], + ["Punishment-Duration", "$t(commands/management:commandModePunishmentDuration)"], + ["Threshold-Maximum", "$t(commands/management:commandModeThreshold)"], + ["Threshold-Duration", "$t(commands/management:commandModeThresholdDuration)"] + ], + "reminder": "$t(commands/management:commandModeReminder)", + "examples": [ + "enable", + "disable", + "action alert", + "punishment ban", + "punishment mute", + "punishment-duration 1m", + "threshold-maximum 5", + "threshold-duration 30s" + ] + }, + "filterDescription": "Manage this server's list of blocked words.", + "filterExtended": { + "usages": ["add Word", "remove Word", "reset", "show", ""], + "extendedHelp": "The filter command manages the list of blocked words for this server and must have a filter mode set up (see: `Skyra, help filterMode`).\n\nSkyra's word filter can find matches even with special characters or spaces between the letters of a blocked word, as well as duplicated characters for enhanced filtering.", + "examples": ["add darn", "remove darn", "reset", "show", ""] + }, + "filterModeDescription": "Manage this server's word filter modes.", + "filterModeExtended": { + "usages": [ + "on/e/enable", + "off/d/disable", + "action/soft-action alert/log/delete", + "punish/punishment none/warn/mute/kick/softban/ban", + "pd/punish-duration/punishment-duration Timespan", + "tm/threshold-maximum Integer", + "td/threshold-duration Timespan", + "sh/show", + "" + ], + "extendedHelp": "The filterMode command manages the behavior of the word filter system. Run `Skyra, help filter` for how to add words.", + "explainedUsage": [ + ["Enable", "$t(commands/management:commandModeEnable)"], + ["Disable", "$t(commands/management:commandModeDisable)"], + ["Action Alert", "$t(commands/management:commandModeActionAlert)"], + ["Action Log", "$t(commands/management:commandModeActionLog)"], + ["Action Delete", "$t(commands/management:commandModeActionDelete)"], + ["Punishment", "$t(commands/management:commandModePunishment)"], + ["Punishment-Duration", "$t(commands/management:commandModePunishmentDuration)"], + ["Threshold-Maximum", "$t(commands/management:commandModeThreshold)"], + ["Threshold-Duration", "$t(commands/management:commandModeThresholdDuration)"] + ], + "reminder": "$t(commands/management:commandModeReminder)", + "examples": [ + "enable", + "disable", + "action alert", + "punishment ban", + "punishment mute", + "punishment-duration 1m", + "threshold-maximum 5", + "threshold-duration 30s" + ] + }, + "inviteModeDescription": "Manage the behavior for the invite link filter.", + "inviteModeExtended": { + "usages": [ + "on/e/enable", + "off/d/disable", + "action/soft-action alert/log/delete", + "punish/punishment none/warn/mute/kick/softban/ban", + "pd/punish-duration/punishment-duration Timespan", + "tm/threshold-maximum Integer", + "td/threshold-duration Timespan", + "sh/show", + "" + ], + "extendedHelp": "The inviteMode command manages the behavior of the invite filter system.", + "explainedUsage": [ + ["Enable", "$t(commands/management:commandModeEnable)"], + ["Disable", "$t(commands/management:commandModeDisable)"], + ["Action Alert", "$t(commands/management:commandModeActionAlert)"], + ["Action Log", "$t(commands/management:commandModeActionLog)"], + ["Action Delete", "$t(commands/management:commandModeActionDelete)"], + ["Punishment", "$t(commands/management:commandModePunishment)"], + ["Punishment-Duration", "$t(commands/management:commandModePunishmentDuration)"], + ["Threshold-Maximum", "$t(commands/management:commandModeThreshold)"], + ["Threshold-Duration", "$t(commands/management:commandModeThresholdDuration)"] + ], + "reminder": "$t(commands/management:commandModeReminder)", + "examples": [ + "enable", + "disable", + "action alert", + "punishment ban", + "punishment mute", + "punishment-duration 1m", + "threshold-maximum 5", + "threshold-duration 30s" + ] + }, + "linkModeDescription": "Manage the behavior for the link filter.", + "linkModeExtended": { + "usages": [ + "on/e/enable", + "off/d/disable", + "action/soft-action alert/log/delete", + "punish/punishment none/warn/mute/kick/softban/ban", + "pd/punish-duration/punishment-duration Timespan", + "tm/threshold-maximum Integer", + "td/threshold-duration Timespan", + "sh/show", + "" + ], + "extendedHelp": "The linkMode command manages the behavior of the link system.", + "explainedUsage": [ + ["Enable", "$t(commands/management:commandModeEnable)"], + ["Disable", "$t(commands/management:commandModeDisable)"], + ["Action Alert", "$t(commands/management:commandModeActionAlert)"], + ["Action Log", "$t(commands/management:commandModeActionLog)"], + ["Action Delete", "$t(commands/management:commandModeActionDelete)"], + ["Punishment", "$t(commands/management:commandModePunishment)"], + ["Punishment-Duration", "$t(commands/management:commandModePunishmentDuration)"], + ["Threshold-Maximum", "$t(commands/management:commandModeThreshold)"], + ["Threshold-Duration", "$t(commands/management:commandModeThresholdDuration)"] + ], + "reminder": "$t(commands/management:commandModeReminder)", + "examples": [ + "enable", + "disable", + "action alert", + "punishment ban", + "punishment mute", + "punishment-duration 1m", + "threshold-maximum 5", + "threshold-duration 30s" + ] + }, + "messageModeDescription": "Manage the behavior for the message filter system.", + "messageModeExtended": { + "usages": [ + "on/e/enable", + "off/d/disable", + "action/soft-action alert/log/delete", + "punish/punishment none/warn/mute/kick/softban/ban", + "pd/punish-duration/punishment-duration Timespan", + "tm/threshold-maximum Integer", + "td/threshold-duration Timespan", + "sh/show", + "" + ], + "extendedHelp": "The messageMode command manages the behavior of the message filter system.", + "explainedUsage": [ + ["Enable", "$t(commands/management:commandModeEnable)"], + ["Disable", "$t(commands/management:commandModeDisable)"], + ["Action Alert", "$t(commands/management:commandModeActionAlert)"], + ["Action Log", "$t(commands/management:commandModeActionLog)"], + ["Action Delete", "$t(commands/management:commandModeActionDelete)"], + ["Punishment", "$t(commands/management:commandModePunishment)"], + ["Punishment-Duration", "$t(commands/management:commandModePunishmentDuration)"], + ["Threshold-Maximum", "$t(commands/management:commandModeThreshold)"], + ["Threshold-Duration", "$t(commands/management:commandModeThresholdDuration)"] + ], + "reminder": "$t(commands/management:commandModeReminder)", + "examples": [ + "enable", + "disable", + "action alert", + "punishment ban", + "punishment mute", + "punishment-duration 1m", + "threshold-maximum 5", + "threshold-duration 30s" + ] + }, + "newlineModeDescription": "Manage the behavior for the new line filter system.", + "newlineModeExtended": { + "usages": [ + "on/e/enable", + "off/d/disable", + "action/soft-action alert/log/delete", + "punish/punishment none/warn/mute/kick/softban/ban", + "pd/punish-duration/punishment-duration Timespan", + "tm/threshold-maximum Integer", + "td/threshold-duration Timespan", + "sh/show", + "" + ], + "extendedHelp": "The newLineMode command manages the behavior of the new line filter system.\nThe maximum amount of lines allowed can be set with `Skyra, settings set selfmod.newlines.maximum `", + "explainedUsage": [ + ["Enable", "$t(commands/management:commandModeEnable)"], + ["Disable", "$t(commands/management:commandModeDisable)"], + ["Action Alert", "$t(commands/management:commandModeActionAlert)"], + ["Action Log", "$t(commands/management:commandModeActionLog)"], + ["Action Delete", "$t(commands/management:commandModeActionDelete)"], + ["Punishment", "$t(commands/management:commandModePunishment)"], + ["Punishment-Duration", "$t(commands/management:commandModePunishmentDuration)"], + ["Threshold-Maximum", "$t(commands/management:commandModeThreshold)"], + ["Threshold-Duration", "$t(commands/management:commandModeThresholdDuration)"] + ], + "reminder": "$t(commands/management:commandModeReminder)", + "examples": [ + "enable", + "disable", + "action alert", + "punishment ban", + "punishment mute", + "punishment-duration 1m", + "threshold-maximum 5", + "threshold-duration 30s" + ] + }, + "reactionModeDescription": "Manage the behavior for the reaction filter system.", + "reactionModeExtended": { + "usages": [ + "on/e/enable", + "off/d/disable", + "action/soft-action alert/log/delete", + "punish/punishment none/warn/mute/kick/softban/ban", + "pd/punish-duration/punishment-duration Timespan", + "tm/threshold-maximum Integer", + "td/threshold-duration Timespan", + "sh/show", + "" + ], + "extendedHelp": "The reactionMode command manages the behavior of the reaction filter system.", + "explainedUsage": [ + ["Enable", "$t(commands/management:commandModeEnable)"], + ["Disable", "$t(commands/management:commandModeDisable)"], + ["Action Alert", "$t(commands/management:commandModeActionAlert)"], + ["Action Log", "$t(commands/management:commandModeActionLog)"], + ["Action Delete", "$t(commands/management:commandModeActionDelete)"], + ["Punishment", "$t(commands/management:commandModePunishment)"], + ["Punishment-Duration", "$t(commands/management:commandModePunishmentDuration)"], + ["Threshold-Maximum", "$t(commands/management:commandModeThreshold)"], + ["Threshold-Duration", "$t(commands/management:commandModeThresholdDuration)"] + ], + "reminder": "$t(commands/management:commandModeReminder)", + "examples": [ + "enable", + "disable", + "action alert", + "punishment ban", + "punishment mute", + "punishment-duration 1m", + "threshold-maximum 5", + "threshold-duration 30s" + ] + }, + "rolesDescription": "List, claim or unclaim public roles in this server.", + "rolesExtended": { + "usages": ["Role", ""], + "extendedHelp": "Public roles are roles that are available for everyone.\nAn administrator must configure them with the configuration command.", + "explainedUsage": [["roles", "The list of roles to claim or unclaim. Leave this empty to get a list of available roles."]], + "reminder": "When claiming or unclaiming roles you can provide a single or multiple role(s).\nTo claim multiple roles, you must separate them by a comma, for example `red,green`.\nYou can specify which roles you want by providing the role ID, name, or a sub-section of the name.\n\nAdministrators can add public roles using `{{prefix}}conf set roles.public ExamplePublicRole`.", + "examples": ["Designer Programmer", "Designer"] + } +} diff --git a/src/languages/en-US/commands/moderation.json b/projects/bot/src/locales/en-US/commands/moderation.json similarity index 50% rename from src/languages/en-US/commands/moderation.json rename to projects/bot/src/locales/en-US/commands/moderation.json index 67f31d014..b2137827a 100644 --- a/src/languages/en-US/commands/moderation.json +++ b/projects/bot/src/locales/en-US/commands/moderation.json @@ -1,8 +1,24 @@ { "permissions": "Permissions for {{username}} ({{id}})", "permissionsAll": "All Permissions", + "timeTimed": "The selected moderation case has already been timed.", + "timeUnsupportedType": "The type of action for the selected case cannot be reverse, therefore this action is unsupported.", + "timeNotScheduled": "This task is not scheduled.", + "timeAborted": "Successfully aborted the schedule for {{title}}", + "timeScheduled": "{{GREENTICK}} Successfully scheduled a moderation action type **{{title}}** for the user {{user.tag}} ({{user.id}}) with a duration of {{time, duration}}", "slowmodeSet": "The cooldown for this channel has been set to {{cooldown, duration}}.", "slowmodeReset": "The cooldown for this channel has been reset.", + "timeDescription": "Set the timer.", + "timeExtended": { + "usages": ["Case Duration", "cancel Case Duration"], + "extendedHelp": "Updates the timer for a moderation case..", + "explainedUsage": [ + ["Cancel", "Whether or not you want to cancel the timer. Defaults to \"no\"."], + ["Case", "The case you want to update"], + ["Duration", "The timer, ignored if `cancel` was defined."] + ], + "examples": ["cancel 1234", "1234 6h"] + }, "banNotBannable": "The target is not bannable for me.", "dehoistStarting": "I will start dehoisting {{count}} members...", "dehoistProgress": "Dehoisted {{count}} members so far! ({{percentage}}%)", @@ -27,864 +43,455 @@ "pruneAlert_one": "Successfully deleted {{count}} message from {{total}}.", "pruneAlert_other": "Successfully deleted {{count}} messages from {{total}}.", "pruneInvalidPosition": "{{REDCROSS}} Position must be one of \"before\" or \"after\".", - "pruneNotSubcommandSameOFSameFlag": "{{REDCROSS}} You cannot use the same flag of the same subcommand cannot be used.", "pruneNoDeletes": "No message has been deleted, either no message match the filter or they are over 14 days old.", "pruneLogHeader": "The following messages have been generated by request of a moderator.\nThe date formatting is of \"$t(globals:dateFormat) hh:mm:ss\".", + "pruneLogMessage_one": "{{count}} message deleted in {{channel}} by {{author}}.", + "pruneLogMessage_other": "{{count}} messages deleted in {{channel}} by {{author}}.", + "reasonNotExists": "The selected modlog doesn't seem to exist.", + "reasonUpdated_one": "{{GREENTICK}} Updated {{count}} case\n └─ **Set its reason to:** {{newReason}}", + "reasonUpdated_other": "{{GREENTICK}} Updated {{count}} cases\n └─ **Set their reasons to:** {{newReason}}", "toggleModerationDmToggledEnabled": "{{GREENTICK}} Successfully enabled moderation DMs.", "toggleModerationDmToggledDisabled": "{{GREENTICK}} Successfully disabled moderation DMs", - "moderationOutput_one": "{{GREENTICK}} Created case {{range}} | {{users, list(conjunction)}}.", - "moderationOutput_other": "{{GREENTICK}} Created cases {{range}} | {{users, list(conjunction)}}.", - "moderationOutputWithReason_one": "{{GREENTICK}} Created case {{range}} | {{users, list(conjunction)}}.\nWith the reason of: {{reason}}", - "moderationOutputWithReason_other": "{{GREENTICK}} Created cases {{range}} | {{users, list(conjunction)}}.\nWith the reason of: {{reason}}", - "moderationFailed_one": "{{REDCROSS}} Failed to moderate user:\n{{users}}", - "moderationFailed_other": "{{REDCROSS}} Failed to moderate users:\n{{users}}", + "unbanMissingPermission": "I will need the **{{BAN_MEMBERS, permissions}}** permission to be able to unban.", + "unmuteMissingPermission": "I will need the **{{MANAGE_ROLES, permissions}}** permission to be able to unmute.", + "vmuteMissingPermission": "I will need the **{{MUTE_MEMBERS, permissions}}** permission to be able to voice unmute.", + "vmuteUserNotMuted": "This user is not voice muted.", + "moderationOutput_one": "{{GREENTICK}} Created case {{range}} | {{users, andList}}.", + "moderationOutput_other": "{{GREENTICK}} Created cases {{range}} | {{users, andList}}.", + "moderationOutputWithReason_one": "{{GREENTICK}} Created case {{range}} | {{users, andList}}.\nWith the reason of: {{reason}}", + "moderationOutputWithReason_other": "{{GREENTICK}} Created cases {{range}} | {{users, andList}}.\nWith the reason of: {{reason}}", + "moderationFailed_one": "{{REDCROSS}} Failed to moderate user:\n{{users, andList}}", + "moderationFailed_other": "{{REDCROSS}} Failed to moderate users:\n{{users, andList}}", "moderationDmFooter": "To disable moderation DMs, write `toggleModerationDM`.", "moderationDmDescription": "**❯ Server**: {{guild}}\n**❯ Type**: {{title}}\n**❯ Reason**: None specified", "moderationDmDescriptionWithReason": "**❯ Server**: {{guild}}\n**❯ Type**: {{title}}\n**❯ Reason**: {{reason}}", "moderationDmDescriptionWithDuration": "**❯ Server**: {{guild}}\n**❯ Type**: {{title}}\n**❯ Duration**: {{duration, duration}}\n**❯ Reason**: None specified", "moderationDmDescriptionWithReasonWithDuration": "**❯ Server**: {{guild}}\n**❯ Type**: {{title}}\n**❯ Duration**: {{duration, duration}}\n**❯ Reason**: {{reason}}", + "historyDescription": "Display the count of moderation cases from this server or from a user.", + "historyExtended": { + "usages": ["", "details", "details User", "overview User"], + "extendedHelp": "This command shows the amount of bans, mutes, kicks, and warnings, including temporary, that have not been appealed.", + "explainedUsage": [ + ["details/overview", "Whether to get a detailed view or just a summary. Defaults to \"overview\"."], + ["User", "The user for whom to get the information. Defaults to you yourself."] + ], + "examples": ["", "overview", "details", "@Pete", "details @Pete", "overview Pete"] + }, + "historyFooterNew": "This user has {{warnings}} {{warningsText}}, {{mutes}} {{mutesText}}, {{kicks}} {{kicksText}}, and {{bans}} {{bansText}}", + "historyFooterWarning_one": "warning", + "historyFooterWarning_other": "warnings", + "historyFooterMutes_one": "mute", + "historyFooterMutes_other": "mutes", + "historyFooterKicks_one": "kick", + "historyFooterKicks_other": "kicks", + "historyFooterBans_one": "ban", + "historyFooterBans_other": "bans", + "moderationsDescription": "List all running moderation logs from this server.", + "moderationsExtended": { + "usages": ["", "mutes/warnings/all", "User", "mutes/warnings/all User"], + "extendedHelp": "This command shows you all the temporary moderation actions that are still running. This command uses a reaction-based menu and requires the permission **{{MANAGE_MESSAGES, permissions}}** to execute correctly.", + "explainedUsage": [ + [ + "mutes/warnings/all", + "Whether to get just the mutes, just the warnings or everything. When providing either `mutes` or `warnings` then all moderations of that type are shown, not just the temporary ones." + ], + ["User", "The user for whom to get the information. Defaults to all users."] + ], + "examples": ["", "@Pete", "mutes @Pete", "warnings"] + }, + "moderationsEmpty": "There are no active moderations that will expire at some future date or time. If you want to see all moderations in this server use: `{{prefix}}history`.", + "moderationsAmount_one": "There is 1 entry.", + "moderationsAmount_other": "There are {{count}} entries.", + "mutesDescription": "List all mutes from this server or from a user.", + "mutesExtended": { + "usages": ["", "User"], + "extendedHelp": "This command shows either all mutes filed in this server, or all mutes filed in this server for a specific user.\nThis command uses a reaction-based menu and requires the permission **{{MANAGE_MESSAGES, permissions}}** to execute correctly.", + "examples": ["", "@Pete"] + }, + "warningsDescription": "List all warnings from this server or from a user.", + "warningsExtended": { + "usages": ["", "User"], + "extendedHelp": "This command shows either all warnings filed in this server, or all warnings filed in this server for a specific user.\nThis command uses a reaction-based menu and requires the permission **{{MANAGE_MESSAGES, permissions}}** to execute correctly.", + "examples": ["", "@Pete"] + }, "slowmodeDescription": "Set the channel's slowmode value in seconds.", "slowmodeExtended": { - "usages": [ - "reset/Seconds/Duration" - ], + "usages": ["reset/Seconds/Duration"], "extendedHelp": "This command requires **{{MANAGE_CHANNELS, permissions}}** and will modify the channel's ratelimit per user to any value between 0 and 6 hours.", - "examples": [ - "0", - "reset", - "4m" - ], + "examples": ["0", "reset", "4m"], "reminder": "To reset a channel's ratelimit per user, you can use either 0 or 'reset'." }, "banDescription": "Hit somebody with the ban hammer.", "banExtended": { - "usages": [ - "User", - "User1 User2 User3...User10", - "User1 Duration", - "User1 User2 Duration Reason", - "User --seconds=S --minutes=M --hours=H --days=D" - ], + "usages": ["User", "User1 User2 User3...User10", "User1 Duration", "User1 User2 Duration Reason", "User --days"], "explainedUsage": [ - [ - "User/User1/User2", - "The user(s) to ban. Can be up to a total of 10 users." - ], + ["User/User1/User2", "The user(s) to ban. Can be up to a total of 10 users."], [ "Duration", "The amount of time this ban should last. For example 24h for 24 hours. The user(s) will be automatically unbanned after this time." ], - [ - "Reason", - "The reason for the ban. This will also show in the server's audit logs." - ], - [ - "--seconds=S --minutes=M --hours=H --days=D", - "The amount of time worth of messages to delete, each flag is optional and can be combined. Up to 7 days." - ] + ["Reason", "The reason for the ban. This will also show in the server's audit logs."], + ["--days", "The amount of days of messages to prune. Should be a number between a minimum of 0 and maximum of 7."] ], - "extendedHelp": "This command requires **{{BanMembers, permissions}}**, and only members with lower role hierarchy position can be banned by me.\nNo, the server's owner cannot be banned.\nThis action can be optionally timed to create a temporary ban.", - "examples": [ - "@Pete", - "@Pete Spamming all channels.", - "@Pete @Jack @John 24h Raiding" - ] + "extendedHelp": "This command requires **{{BAN_MEMBERS, permissions}}**, and only members with lower role hierarchy position can be banned by me.\nNo, the server's owner cannot be banned.\nThis action can be optionally timed to create a temporary ban.", + "examples": ["@Pete", "@Pete Spamming all channels.", "@Pete @Jack @John 24h Raiding"] }, "dehoistDescription": "Shoot everyone with the Dehoistinator 3000", "dehoistExtended": { "extendedHelp": "The act of hoisting involves adding special characters in front of your nickname in order to appear higher in the members list.\nThis command replaces any member's nickname that includes those special characters with a special character that drags them to the bottom of the list.", - "reminder": "This command requires **{{ManageNicknames, permissions}}**, and only members with lower role hierarchy position can be dehoisted." + "reminder": "This command requires **{{MANAGE_NICKNAMES, permissions}}**, and only members with lower role hierarchy position can be dehoisted." }, "kickDescription": "Hit somebody with the 👢.", "kickExtended": { - "usages": [ - "User", - "User1 User2 User3...User10", - "User Reason" - ], - "extendedHelp": "This command requires **{{KickMembers, permissions}}**, and only members with lower role hierarchy position can be kicked by me. No, the server's owner cannot be kicked.", + "usages": ["User", "User1 User2 User3...User10", "User Reason"], + "extendedHelp": "This command requires **{{KICK_MEMBERS, permissions}}**, and only members with lower role hierarchy position can be kicked by me. No, the server's owner cannot be kicked.", "explainedUsage": [ - [ - "User/User1/User2", - "The user(s) to kick. Can be up to a total of 10 users." - ], - [ - "Reason", - "The reason for the kick. This will also show in the server's audit logs." - ] + ["User/User1/User2", "The user(s) to kick. Can be up to a total of 10 users."], + ["Reason", "The reason for the kick. This will also show in the server's audit logs."] ], - "examples": [ - "@Sarah", - "@Sarah Spamming general chat." - ] + "examples": ["@Sarah", "@Sarah Spamming general chat."] }, "lockdownDescription": "Close the gates for this channel!", "lockdownExtended": { - "usages": [ - "", - "lock Role TextChannel Duration", - "unlock Role TextChannel", - "Role TextChannel Duration" - ], + "usages": ["", "lock Role TextChannel Duration", "unlock Role TextChannel", "Role TextChannel Duration"], "extendedHelp": "This command requires **{{MANAGE_CHANNELS, permissions}}** in order to be able to manage the permissions for a channel.\nThis command removes the permission **{{SEND_MESSAGES, permissions}}** to the `@everyone` role so nobody but the members with roles that have their own overrides (besides administrators, who bypass channel overrides) can send messages.\nOptionally, you can pass time as second argument.", "explainedUsage": [ [ "lock/unlock", "Whether to lock or unlock the channel. Defaults to \"lock\" if the channel is currently unlocked, or \"unlock\" if it is currently locked." ], - [ - "Role", - "The role to lock. Defaults to the `@everyone` role." - ], - [ - "TextChannel", - "The channel to lock. Defaults to the current channel." - ], - [ - "Duration", - "The amount of time this lock should last. Defaults to infinite." - ] - ], - "examples": [ - "", - "#general", - "lock #general 5m", - "unlock #general", - "lock Members #general" + ["Role", "The role to lock. Defaults to the `@everyone` role."], + ["TextChannel", "The channel to lock. Defaults to the current channel."], + ["Duration", "The amount of time this lock should last. Defaults to infinite."] ], + "examples": ["", "#general", "lock #general 5m", "unlock #general", "lock Members #general"], "reminder": "If your members need a role such as \"member\" to send messages in the channel to begin with then this command will not work. It is in our backlog of work to add make the role that should be locked configurable." }, "muteDescription": "Mute a user in all text and voice channels.", "muteExtended": { - "usages": [ - "User", - "User1 User2 User3...User10", - "User1 Duration", - "User1 User2 Duration Reason" - ], + "usages": ["User", "User1 User2 User3...User10", "User1 Duration", "User1 User2 Duration Reason"], "explainedUsage": [ - [ - "User/User1/User2", - "The user(s) to mute. Can be up to a total of 10 users." - ], + ["User/User1/User2", "The user(s) to mute. Can be up to a total of 10 users."], [ "Duration", "The amount of time this mute should last. For example 24h for 24 hours. The user(s) will be automatically unmuted after this time." ], - [ - "Reason", - "The reason for the mute. This will also show in the server's audit logs." - ] + ["Reason", "The reason for the mute. This will also show in the server's audit logs."] ], "extendedHelp": "This command requires **{{MANAGE_ROLES, permissions}}**, and only members with lower role hierarchy position can be managed by me.\nNo, the server's owner cannot be muted.\nThis action can be optionally timed to create a temporary mute. This action saves a member's roles temporarily and will be granted to the user after the unmute.\nThe muted role is **sticky**, if the user tries to remove it by rejoining the server, it will be added back.", - "examples": [ - "@Alphonse", - "@Alphonse Spamming all channels", - "@Alphonse 24h Spamming all channels" - ] + "examples": ["@Alphonse", "@Alphonse Spamming all channels", "@Alphonse 24h Spamming all channels"] }, "setNicknameDescription": "Change the nickname of a user.", "setNicknameExtended": { - "usages": [ - "User", - "User1 User2 User3...User10", - "User1 Nickname", - "User1 Duration", - "User1 User2 Nickname Duration Reason" - ], + "usages": ["User", "User1 User2 User3...User10", "User1 Nickname", "User1 Duration", "User1 User2 Nickname Duration Reason"], "explainedUsage": [ - [ - "User/User1/User2", - "The user(s) to nickname. Can be up to a total of 10 users." - ], - [ - "Nickname", - "The new nickname to set. Not including this will make this command default to the user's username." - ], + ["User/User1/User2", "The user(s) to nickname. Can be up to a total of 10 users."], + ["Nickname", "The new nickname to set. Not including this will make this command default to the user's username."], [ "Duration", "The amount of time this nickname change should last. For example 24h for 24 hours. The user(s) will automatically get their current name back after this time." ], - [ - "Reason", - "The reason for this nickname change. This will also show in the server's audit logs." - ] + ["Reason", "The reason for this nickname change. This will also show in the server's audit logs."] ], "extendedHelp": "This command requires **{{MANAGE_NICKNAMES, permissions}}**, and only members with lower role hierarchy position can be managed by me.\nNo, the server's owner nickname cannot be changed.", - "examples": [ - "@Pete peeehteeerrr", - "@ꓑ𝗲੮ẻ Pete Unmentionable name" - ], + "examples": ["@Pete peeehteeerrr", "@ꓑ𝗲੮ẻ Pete Unmentionable name"], "reminder": "Leaving out the new nickname will reset it back to the user's username" }, "addRoleDescription": "Adds a role to a user.", "addRoleExtended": { - "usages": [ - "User", - "User1 User2 User3...User10", - "User1 Role", - "User1 Duration", - "User1 User2 role Duration Reason" - ], + "usages": ["User", "User1 User2 User3...User10", "User1 Role", "User1 Duration", "User1 User2 role Duration Reason"], "explainedUsage": [ - [ - "User/User1/User2", - "The user(s) to add a role to. Can be up to a total of 10 users." - ], - [ - "Role", - "The new role to assign" - ], + ["User/User1/User2", "The user(s) to add a role to. Can be up to a total of 10 users."], + ["Role", "The new role to assign"], [ "Duration", "The amount of time this role should be on this user. For example 24h for 24 hours. The user(s) will automatically have the role removed after this time." ], - [ - "Reason", - "The reason for adding this role. This will also show in the server's audit logs." - ] + ["Reason", "The reason for adding this role. This will also show in the server's audit logs."] ], "extendedHelp": "This command requires **{{MANAGE_ROLES, permissions}}**, and only members with lower role hierarchy position can be managed by me.\nNo, the server's owner roles cannot be changed.", - "examples": [ - "@John member", - "@John member Make John a member" - ] + "examples": ["@John member", "@John member Make John a member"] }, "removeroleDescription": "Removes a role from a user", "removeroleExtended": { - "usages": [ - "User", - "User1 User2 User3...User10", - "User1 Role", - "User1 Duration", - "User1 User2 role Duration Reason" - ], + "usages": ["User", "User1 User2 User3...User10", "User1 Role", "User1 Duration", "User1 User2 role Duration Reason"], "explainedUsage": [ - [ - "User/User1/User2", - "The user(s) to remove a role from. Can be up to a total of 10 users." - ], - [ - "Role", - "The role to remove" - ], + ["User/User1/User2", "The user(s) to remove a role from. Can be up to a total of 10 users."], + ["Role", "The role to remove"], [ "Duration", "The amount of time this role should be removed from this user. For example 24h for 24 hours. The user(s) will automatically regain the role after this time." ], - [ - "Reason", - "The reason for removing this role. This will also show in the server's audit logs." - ] + ["Reason", "The reason for removing this role. This will also show in the server's audit logs."] ], "extendedHelp": "This command requires **{{MANAGE_ROLES, permissions}}**, and only members with lower role hierarchy position can be managed by me.\nNo, the server's owner roles cannot be changed.", - "examples": [ - "@Paula member", - "@Paula member Remove member permissions from Paula" - ] + "examples": ["@Paula member", "@Paula member Remove member permissions from Paula"] }, "pruneDescription": "Prunes a certain amount of messages w/o filter.", "pruneExtended": { - "usages": [ - "Amount Flags User", - "Amount Flags after/before Message", - "Amount User", - "Amount User after/before Message", - "Amount --silent" - ], - "extendedHelp": "This command deletes the given amount of messages given a filter within the last 100 messages sent in the channel the command has been run.\nOptionally, you can add `--silent` to tell WolfStar not to send a response message.", + "usages": ["Amount Flags User", "Amount Flags after/before Message", "Amount User", "Amount User after/before Message", "Amount --silent"], + "extendedHelp": "This command deletes the given amount of messages given a filter within the last 100 messages sent in the channel the command has been run.\nOptionally, you can add `--silent` to tell Skyra not to send a response message.", "explainedUsage": [ - [ - "Amount", - "The amount of messages to delete." - ], - [ - "--f/file/files", - "Deletes messages with attachments." - ], - [ - "--a/author", - "Deletes your messages." - ], - [ - "--b/bot/bots", - "Deletes messages sent by bots." - ], - [ - "--h/human/humans", - "Deletes messages sent by users." - ], - [ - "--i/invite/invites", - "Deletes messages that contain invite links." - ], - [ - "--l/link/links", - "Deletes messages that contain any link." - ], - [ - "--y/you", - "Deletes my messages." - ], - [ - "--age=Duration", - "Deletes any message newer than Duration." - ], - [ - "--include/contain=Word", - "Deletes messages that contain Word." - ], - [ - "--p/pin/pins", - "Deletes pinned messages, unless specified, no other filter deletes pins." - ], - [ - "User", - "Deletes messages sent by the specified user." - ], - [ - "Position: after", - "Deletes messages sent after the specified message." - ], - [ - "Position: before", - "Deletes messages sent before the specified message." - ], + ["Amount", "The amount of messages to delete."], + ["--f/file/files", "Deletes messages with attachments."], + ["--a/author", "Deletes your messages."], + ["--b/bot/bots", "Deletes messages sent by bots."], + ["--h/human/humans", "Deletes messages sent by users."], + ["--i/invite/invites", "Deletes messages that contain invite links."], + ["--l/link/links", "Deletes messages that contain any link."], + ["--y/you", "Deletes my messages."], + ["--age=Duration", "Deletes any message newer than Duration."], + ["--include/contain=Word", "Deletes messages that contain Word."], + ["--p/pin/pins", "Deletes pinned messages, unless specified, no other filter deletes pins."], + ["User", "Deletes messages sent by the specified user."], + ["Position: after", "Deletes messages sent after the specified message."], + ["Position: before", "Deletes messages sent before the specified message."], [ "--s/silent", "Whether or not a response message should be sent, this will also delete your command message if there were less than 100 messages filtered." ] ], - "examples": [ - "50 --a", - "75 @kyra", - "20 --bots", - "60 --humans --files before 629992398700675082", - "30 --age=5m --contain=lol", - "100 --silent" - ], + "examples": ["50 --a", "75 @kyra", "20 --bots", "60 --humans --files before 629992398700675082", "30 --age=5m --contain=lol", "100 --silent"], "reminder": "Due to a Discord limitation, bots cannot delete messages older than 14 days." }, - "permissionsDescription": "Check the permission for a member, or yours.", - "permissionsExtended": { - "usages": [ - "", - "User" - ], + "caseDescription": "Get the information from a case by its index.", + "caseExtended": { + "usages": ["Case", "Show Case", "Delete Case"], + "extendedHelp": "You can also get the latest moderation case by specifying the case ID as `latest`", "explainedUsage": [ - [ - "User", - "The user for whom you want to check the permissions. Defaults to you yourself." - ] + ["Show/Delete", "Whether to show or delete a case. Defaults to show."], + ["Case", "Number of the case ID to show or delete, or `latest` for the latest created case."] ], + "examples": ["5", "latest", "delete 6", "delete latest"] + }, + "caseDeleted": "{{GREENTICK}} Case {{case}} has been successfully deleted.", + "permissionsDescription": "Check the permission for a member, or yours.", + "permissionsExtended": { + "usages": ["", "User"], + "explainedUsage": [["User", "The user for whom you want to check the permissions. Defaults to you yourself."]], "extendedHelp": "Ideal if you want to know the what permissions are granted to a member when they have a certain set of roles." }, + "reasonDescription": "Edit the reason field from a moderation log case.", + "reasonExtended": { + "usages": ["Case/Range Reason"], + "extendedHelp": "This command allows moderation log case management, it allows moderators to update the reason.\nIf you want to modify multiple cases at once you provide a range.\nFor example `1..3` for the `` will edit cases 1, 2, and 3.\nAlternatively you can also give ranges with commas:\n`1,3..6` will result in cases 1, 3, 4, 5, and 6\n`1,2,3` will result in cases 1, 2, and 3", + "examples": ["420 Spamming all channels", "419..421 Bad memes", "1..3,4,7..9 Posting NSFW", "latest Woops, I did a mistake!"] + }, "restrictAttachmentDescription": "Restrict a user from sending attachments in all channels.", "restrictAttachmentExtended": { - "usages": [ - "User", - "User1 User2 User3...User10", - "User1 Duration", - "User1 User2 Duration Reason" - ], + "usages": ["User", "User1 User2 User3...User10", "User1 Duration", "User1 User2 Duration Reason"], "explainedUsage": [ - [ - "User/User1/User2", - "The user(s) to restrict attachments for. Can be up to a total of 10 users." - ], + ["User/User1/User2", "The user(s) to restrict attachments for. Can be up to a total of 10 users."], [ "Duration", "The amount of time this restriction should be on this user. For example 24h for 24 hours. The user(s) will automatically have the restriction lifted after this time." ], - [ - "Reason", - "The reason for adding this restriction. This will also show in the server's audit logs." - ] + ["Reason", "The reason for adding this restriction. This will also show in the server's audit logs."] ], "extendedHelp": "This command requires **{{MANAGE_ROLES, permissions}}**, and only members with lower role hierarchy position can be managed by me.\nNo, the server's owner cannot be restricted.\nThis action can be optionally timed to create a temporary restriction.\nThe restricted role is **sticky**, if the user tries to remove it by rejoining the server, it will be added back.", - "examples": [ - "@Pete", - "@Pete Sending weird images", - "@Pete 24h Sending NSFW images" - ] + "examples": ["@Pete", "@Pete Sending weird images", "@Pete 24h Sending NSFW images"] }, "restrictEmbedDescription": "Restrict a user from attaching embeds in all channels.", "restrictEmbedExtended": { - "usages": [ - "User", - "User1 User2 User3...User10", - "User1 Duration", - "User1 User2 Duration Reason" - ], + "usages": ["User", "User1 User2 User3...User10", "User1 Duration", "User1 User2 Duration Reason"], "explainedUsage": [ - [ - "User/User1/User2", - "The user(s) to restrict embeds for. Can be up to a total of 10 users." - ], + ["User/User1/User2", "The user(s) to restrict embeds for. Can be up to a total of 10 users."], [ "Duration", "The amount of time this restriction should be on this user. For example 24h for 24 hours. The user(s) will automatically have the restriction lifted after this time." ], - [ - "Reason", - "The reason for adding this restriction. This will also show in the server's audit logs." - ] + ["Reason", "The reason for adding this restriction. This will also show in the server's audit logs."] ], "extendedHelp": "This command requires **{{MANAGE_ROLES, permissions}}**, and only members with lower role hierarchy position can be managed by me.\nNo, the server's owner cannot be restricted.\nThis action can be optionally timed to create a temporary restriction.\nThe restricted role is **sticky**, if the user tries to remove it by rejoining the server, it will be added back.", - "examples": [ - "@Pete", - "@Pete Sending weird links", - "@Pete 24h Posted a spam link" - ], + "examples": ["@Pete", "@Pete Sending weird links", "@Pete 24h Posted a spam link"], "reminder": "Embeds are, for example, when a user sends a video it gets embedded in the chat." }, "restrictEmojiDescription": "Restrict a user from using external emojis in all channels.", "restrictEmojiExtended": { - "usages": [ - "User", - "User1 User2 User3...User10", - "User1 Duration", - "User1 User2 Duration Reason" - ], + "usages": ["User", "User1 User2 User3...User10", "User1 Duration", "User1 User2 Duration Reason"], "explainedUsage": [ - [ - "User/User1/User2", - "The user(s) to restrict external emojis for. Can be up to a total of 10 users." - ], + ["User/User1/User2", "The user(s) to restrict external emojis for. Can be up to a total of 10 users."], [ "Duration", "The amount of time this restriction should be on this user. For example 24h for 24 hours. The user(s) will automatically have the restriction lifted after this time." ], - [ - "Reason", - "The reason for adding this restriction. This will also show in the server's audit logs." - ] + ["Reason", "The reason for adding this restriction. This will also show in the server's audit logs."] ], "extendedHelp": "This command requires **{{MANAGE_ROLES, permissions}}**, and only members with lower role hierarchy position can be managed by me.\nNo, the server's owner cannot be restricted.\nThis action can be optionally timed to create a temporary restriction.\nThe restricted role is **sticky**, if the user tries to remove it by rejoining the server, it will be added back.", - "examples": [ - "@Pete", - "@Pete Spamming external emojis", - "@Pete 24h Posted cringe" - ], + "examples": ["@Pete", "@Pete Spamming external emojis", "@Pete 24h Posted cringe"], "reminder": "This will only prevent the usage of external emojis and so will have no effect for non-nitro users, your own server's emojis and regular build in twemojis can still be used by members with this role." }, "restrictReactionDescription": "Restrict a user from reacting to messages in all channels.", "restrictReactionExtended": { - "usages": [ - "User", - "User1 User2 User3...User10", - "User1 Duration", - "User1 User2 Duration Reason" - ], + "usages": ["User", "User1 User2 User3...User10", "User1 Duration", "User1 User2 Duration Reason"], "explainedUsage": [ - [ - "User/User1/User2", - "The user(s) to restrict reacting to messages for. Can be up to a total of 10 users." - ], + ["User/User1/User2", "The user(s) to restrict reacting to messages for. Can be up to a total of 10 users."], [ "Duration", "The amount of time this restriction should be on this user. For example 24h for 24 hours. The user(s) will automatically have the restriction lifted after this time." ], - [ - "Reason", - "The reason for adding this restriction. This will also show in the server's audit logs." - ] + ["Reason", "The reason for adding this restriction. This will also show in the server's audit logs."] ], "extendedHelp": "This command requires **{{MANAGE_ROLES, permissions}}**, and only members with lower role hierarchy position can be managed by me.\nNo, the server's owner cannot be restricted.\nThis action can be optionally timed to create a temporary restriction.\nThe restricted role is **sticky**, if the user tries to remove it by rejoining the server, it will be added back.", - "examples": [ - "@Pete", - "@Pete Spamming reactions", - "@Pete 24h Posting weird reactions" - ] + "examples": ["@Pete", "@Pete Spamming reactions", "@Pete 24h Posting weird reactions"] }, "restrictVoiceDescription": "Restrict a user from joining any voice channel.", "restrictVoiceExtended": { - "usages": [ - "User", - "User1 User2 User3...User10", - "User1 Duration", - "User1 User2 Duration Reason" - ], + "usages": ["User", "User1 User2 User3...User10", "User1 Duration", "User1 User2 Duration Reason"], "explainedUsage": [ - [ - "User/User1/User2", - "The user(s) to restrict voice channel interaction for. Can be up to a total of 10 users." - ], + ["User/User1/User2", "The user(s) to restrict voice channel interaction for. Can be up to a total of 10 users."], [ "Duration", "The amount of time this restriction should be on this user. For example 24h for 24 hours. The user(s) will automatically have the restriction lifted after this time." ], - [ - "Reason", - "The reason for adding this restriction. This will also show in the server's audit logs." - ] + ["Reason", "The reason for adding this restriction. This will also show in the server's audit logs."] ], "extendedHelp": "This command requires **{{MANAGE_ROLES, permissions}}**, and only members with lower role hierarchy position can be managed by me.\nNo, the server's owner cannot be restricted.\nThis action can be optionally timed to create a temporary restriction.\nThe restricted role is **sticky**, if the user tries to remove it by rejoining the server, it will be added back.", - "examples": [ - "@Pete", - "@Pete Earraping in general voice channels", - "@Pete 24h Making weird noises" - ] + "examples": ["@Pete", "@Pete Earraping in general voice channels", "@Pete 24h Making weird noises"] }, "softBanDescription": "Hit somebody with the ban hammer, destroying all their messages for some days, and unban it.", "softBanExtended": { - "usages": [ - "User", - "User1 User2 User3...User10", - "User1 Reason", - "User --seconds=S --minutes=M --hours=H --days=D" - ], - "explainedUsage": [ - [ - "User/User1/User2", - "The user(s) to softban. Can be up to a total of 10 users." - ], - [ - "Reason", - "The reason for the softban. This will also show in the server's audit logs." - ], - [ - "--seconds=S --minutes=M --hours=H --days=D", - "The amount of time worth of messages to delete, each flag is optional and can be combined. Up to 7 days." - ] - ], - "extendedHelp": "This command requires **{{BanMembers, permissions}}**, and only members with lower role hierarchy position can be banned by me.\nNo, the server's owner cannot be banned.\nThe ban feature from Discord has a feature that allows the moderator to remove all messages from all channels that have been sent in the last 'x' days, being a number between 0 (no days) and 7.\nThe user gets unbanned right after the ban, so it is like a kick, but that can prune many many messages.", - "examples": [ - "@Pete", - "@Pete Spamming all channels", - "@Pete 7 All messages sent in 7 are gone now, YEE HAH!" - ] - }, - "timeoutApplyDescription": "Time out a user.", - "timeoutApplyExtended": { - "usages": [ - "Duration User", - "Duration User Reason" - ], - "explainedUsage": [ - [ - "Duration", - "The duration of the timeout. For example 24h for 24 hours." - ], - [ - "User", - "The user to time out." - ], - [ - "Reason", - "The reason for the timeout. This will also show in the server's audit logs." - ] - ], - "examples": [ - "30s @Pete", - "2h @Pete Spamming all channels" - ] - }, - "timeoutUndoDescription": "Remove a time out from a user.", - "timeoutUndoExtended": { - "usages": [ - "User", - "User Reason" - ], + "usages": ["User", "User1 User2 User3...User10", "User1 Reason"], "explainedUsage": [ - [ - "User", - "The user to time out." - ], - [ - "Reason", - "The reason for the timeout. This will also show in the server's audit logs." - ] + ["User/User1/User2", "The user(s) to softban. Can be up to a total of 10 users."], + ["Reason", "The reason for the softban. This will also show in the server's audit logs."] ], - "examples": [ - "@Pete", - "@Pete Turns out he was not the one who spammed all channels 🤷" - ] + "extendedHelp": "This command requires **{{BAN_MEMBERS, permissions}}**, and only members with lower role hierarchy position can be banned by me.\nNo, the server's owner cannot be banned.\nThe ban feature from Discord has a feature that allows the moderator to remove all messages from all channels that have been sent in the last 'x' days, being a number between 0 (no days) and 7.\nThe user gets unbanned right after the ban, so it is like a kick, but that can prune many many messages.", + "examples": ["@Pete", "@Pete Spamming all channels", "@Pete 7 All messages sent in 7 are gone now, YEE HAH!"] }, - "timeoutNotModeratable": "The target cannot be timed out by me.", "toggleModerationDmDescription": "Toggle moderation DMs.", "toggleModerationDmExtended": { "extendedHelp": "This command allows you to toggle moderation DMs. By default, they are on, meaning that any moderation action (automatic or manual) will DM you, but you can disable them with this command." }, "unbanDescription": "Unban somebody from this server.", "unbanExtended": { - "usages": [ - "User", - "User1 User2 User3...User10", - "User1 Reason" - ], + "usages": ["User", "User1 User2 User3...User10", "User1 Reason"], "explainedUsage": [ - [ - "User/User1/User2", - "The user(s) to unban. Can be up to a total of 10 users." - ], - [ - "Reason", - "The reason for the ban removal. This will also show in the server's audit logs." - ] + ["User/User1/User2", "The user(s) to unban. Can be up to a total of 10 users."], + ["Reason", "The reason for the ban removal. This will also show in the server's audit logs."] ], - "extendedHelp": "This command requires **{{BanMembers, permissions}}**. It literally gets somebody from the rubbish bin, cleans them up, and allows the pass to this server's gates.", - "examples": [ - "@Pete", - "@Pete Turns out he was not the one who spammed all channels 🤷" - ] + "extendedHelp": "This command requires **{{BAN_MEMBERS, permissions}}**. It literally gets somebody from the rubbish bin, cleans them up, and allows the pass to this server's gates.", + "examples": ["@Pete", "@Pete Turns out he was not the one who spammed all channels 🤷"] }, "unmuteDescription": "Remove the scotch tape from a user.", "unmuteExtended": { - "usages": [ - "User", - "User1 User2 User3...User10", - "User1 Reason" - ], + "usages": ["User", "User1 User2 User3...User10", "User1 Reason"], "explainedUsage": [ - [ - "User/User1/User2", - "The user(s) to unmute. Can be up to a total of 10 users." - ], - [ - "Reason", - "The reason for the mute removal. This will also show in the server's audit logs." - ] + ["User/User1/User2", "The user(s) to unmute. Can be up to a total of 10 users."], + ["Reason", "The reason for the mute removal. This will also show in the server's audit logs."] ], "extendedHelp": "This command requires **{{MANAGE_ROLES, permissions}}** and removes a user from the muted people's list, and gives the old roles back if the user had them.", - "examples": [ - "@Pete", - "@Pete (Insert random joke here)." - ] + "examples": ["@Pete", "@Pete (Insert random joke here)."] }, "unrestrictAttachmentDescription": "Remove the attachment restriction from one or more users.", "unrestrictAttachmentExtended": { - "usages": [ - "User", - "User1 User2 User3...User10", - "User1 Reason" - ], + "usages": ["User", "User1 User2 User3...User10", "User1 Reason"], "explainedUsage": [ - [ - "User/User1/User2", - "The user(s) to remove attachment restrictions from. Can be up to a total of 10 users." - ], - [ - "Reason", - "The reason for the removal of the attachment restriction. This will also show in the server's audit logs." - ] + ["User/User1/User2", "The user(s) to remove attachment restrictions from. Can be up to a total of 10 users."], + ["Reason", "The reason for the removal of the attachment restriction. This will also show in the server's audit logs."] ], "extendedHelp": "This command requires **{{MANAGE_ROLES, permissions}}** and removes a user from the restricted people's list.", - "examples": [ - "@Pete" - ] + "examples": ["@Pete"] }, "unrestrictEmbedDescription": "Remove the embed restriction from one or more users.", "unrestrictEmbedExtended": { - "usages": [ - "User", - "User1 User2 User3...User10", - "User1 Reason" - ], + "usages": ["User", "User1 User2 User3...User10", "User1 Reason"], "explainedUsage": [ - [ - "User/User1/User2", - "The user(s) to remove embed restrictions from. Can be up to a total of 10 users." - ], - [ - "Reason", - "The reason for the removal of the embed restriction. This will also show in the server's audit logs." - ] + ["User/User1/User2", "The user(s) to remove embed restrictions from. Can be up to a total of 10 users."], + ["Reason", "The reason for the removal of the embed restriction. This will also show in the server's audit logs."] ], "extendedHelp": "This command requires **{{MANAGE_ROLES, permissions}}** and removes a user from the restricted people's list.", - "examples": [ - "@Pete" - ] + "examples": ["@Pete"] }, "unrestrictEmojiDescription": "Remove the external emoji restriction from one or more users.", "unrestrictEmojiExtended": { - "usages": [ - "User", - "User1 User2 User3...User10", - "User1 Reason" - ], + "usages": ["User", "User1 User2 User3...User10", "User1 Reason"], "explainedUsage": [ - [ - "User/User1/User2", - "The user(s) to remove emoji restrictions from. Can be up to a total of 10 users." - ], - [ - "Reason", - "The reason for the removal of the emoji restriction. This will also show in the server's audit logs." - ] + ["User/User1/User2", "The user(s) to remove emoji restrictions from. Can be up to a total of 10 users."], + ["Reason", "The reason for the removal of the emoji restriction. This will also show in the server's audit logs."] ], "extendedHelp": "This command requires **{{MANAGE_ROLES, permissions}}** and removes a user from the restricted people's list.", - "examples": [ - "@Pete" - ] + "examples": ["@Pete"] }, "unrestrictReactionDescription": "Remove the reaction restriction from one or more users.", "unrestrictReactionExtended": { - "usages": [ - "User", - "User1 User2 User3...User10", - "User1 Reason" - ], + "usages": ["User", "User1 User2 User3...User10", "User1 Reason"], "explainedUsage": [ - [ - "User/User1/User2", - "The user(s) to remove reaction restrictions from. Can be up to a total of 10 users." - ], - [ - "Reason", - "The reason for the removal of the reaction restriction. This will also show in the server's audit logs." - ] + ["User/User1/User2", "The user(s) to remove reaction restrictions from. Can be up to a total of 10 users."], + ["Reason", "The reason for the removal of the reaction restriction. This will also show in the server's audit logs."] ], "extendedHelp": "This command requires **{{MANAGE_ROLES, permissions}}** and removes a user from the restricted people's list.", - "examples": [ - "@Pete" - ] + "examples": ["@Pete"] }, "unrestrictVoiceDescription": "Remove the voice restriction from one or more users.", "unrestrictVoiceExtended": { - "usages": [ - "User", - "User1 User2 User3...User10", - "User1 Reason" - ], + "usages": ["User", "User1 User2 User3...User10", "User1 Reason"], "explainedUsage": [ - [ - "User/User1/User2", - "The user(s) to remove voice restrictions from. Can be up to a total of 10 users." - ], - [ - "Reason", - "The reason for the removal of the voice restriction. This will also show in the server's audit logs." - ] + ["User/User1/User2", "The user(s) to remove voice restrictions from. Can be up to a total of 10 users."], + ["Reason", "The reason for the removal of the voice restriction. This will also show in the server's audit logs."] ], "extendedHelp": "This command requires **{{MANAGE_ROLES, permissions}}** and removes a user from the restricted people's list.", - "examples": [ - "@Pete" - ] + "examples": ["@Pete"] }, "unwarnDescription": "Appeal a warning moderation log case.", "unwarnExtended": { - "usages": [ - "Case", - "Case Reason" - ], + "usages": ["Case", "Case Reason"], "explainedUsage": [ [ "Case", "The case number to modify. You can find the case numbers through the `history` command or by looking in your moderation logs channel" ], - [ - "Reason", - "The reason for removing this warning." - ] + ["Reason", "The reason for removing this warning."] ], "extendedHelp": "This command appeals a warning, it requires no permissions, you only give me the moderation log case to appeal and the reason.", - "examples": [ - "0 Whoops, wrong dude.", - "42 Turns out this was the definition of life." - ] + "examples": ["0 Whoops, wrong dude.", "42 Turns out this was the definition of life."] }, "vmuteDescription": "Throw somebody's microphone out the window.", "vmuteExtended": { - "usages": [ - "User", - "User1 User2 User3...User10", - "User1 Duration", - "User1 User2 Duration Reason" - ], + "usages": ["User", "User1 User2 User3...User10", "User1 Duration", "User1 User2 Duration Reason"], "explainedUsage": [ - [ - "User/User1/User2", - "The user(s) to mute in voice channels. Can be up to a total of 10 users." - ], + ["User/User1/User2", "The user(s) to mute in voice channels. Can be up to a total of 10 users."], [ "Duration", "The amount of time this voice mute should apply for. For example 24h for 24 hours. The user(s) will automatically have the voice mute lifted after this time." ], - [ - "Reason", - "The reason for adding this voice mute. This will also show in the server's audit logs." - ] + ["Reason", "The reason for adding this voice mute. This will also show in the server's audit logs."] ], "extendedHelp": "This command requires **{{MUTE_MEMBERS, permissions}}**, and only members with lower role hierarchy position can be silenced by me.\nNo, the server's owner cannot be silenced.\nThis action can be optionally timed to create a temporary voice mute.", - "examples": [ - "@Pete", - "@Pete Singing too loud", - "@Pete 24h Literally sang ear rape" - ] + "examples": ["@Pete", "@Pete Singing too loud", "@Pete 24h Literally sang ear rape"] }, "voiceKickDescription": "Hit somebody with the 👢 for singing so bad and loud.", "voiceKickExtended": { - "usages": [ - "User", - "User1 User2 User3...User10", - "User1 Reason", - "User1 User2 Reason" - ], + "usages": ["User", "User1 User2 User3...User10", "User1 Reason", "User1 User2 Reason"], "explainedUsage": [ - [ - "User/User1/User2", - "The user(s) to kick from their current voice channel. Can be up to a total of 10 users." - ], - [ - "Reason", - "The reason for kicking the user(s) from the voice channel. This will also show in the server's audit logs." - ] + ["User/User1/User2", "The user(s) to kick from their current voice channel. Can be up to a total of 10 users."], + ["Reason", "The reason for kicking the user(s) from the voice channel. This will also show in the server's audit logs."] ], "extendedHelp": "This command requires the permissions **{{MANAGE_CHANNELS, permissions}}** to create a temporary (hidden) voice channel, and **{{MOVE_MEMBERS, permissions}}** to move the user to the temporary channel.\nAfter this, the channel is quickly deleted, making the user leave the voice channel.\nFor scared moderators, this command has almost no impact in the average user, as the channel is created in a way only me and the selected user can see and join, then quickly deleted.", - "examples": [ - "@Pete", - "@Pete Spamming all channels" - ] + "examples": ["@Pete", "@Pete Spamming all channels"] }, "vunmuteDescription": "Get somebody's microphone back so they can talk.", "vunmuteExtended": { - "usages": [ - "User", - "User1 User2 User3...User10", - "User1 Reason" - ], + "usages": ["User", "User1 User2 User3...User10", "User1 Reason"], "explainedUsage": [ - [ - "User/User1/User2", - "The user(s) to unmute in voice channels. Can be up to a total of 10 users." - ], - [ - "Reason", - "The reason for removing the voice mute. This will also show in the server's audit logs." - ] + ["User/User1/User2", "The user(s) to unmute in voice channels. Can be up to a total of 10 users."], + ["Reason", "The reason for removing the voice mute. This will also show in the server's audit logs."] ], "extendedHelp": "This command requires **{{MUTE_MEMBERS, permissions}}**, and only members with lower role hierarchy position can be un-silenced by me.\nNo, the server's owner cannot be un-silenced.", - "examples": [ - "@Pete", - "@Pete Appealed his times signing hear rape." - ] + "examples": ["@Pete", "@Pete Appealed his times signing hear rape."] }, "warnDescription": "File a warning to somebody.", "warnExtended": { - "usages": [ - "User", - "User1 User2 User3...User10", - "User1 Duration", - "User1 User2 Duration Reason" - ], + "usages": ["User", "User1 User2 User3...User10", "User1 Duration", "User1 User2 Duration Reason"], "explainedUsage": [ - [ - "User/User1/User2", - "The user(s) to warn. Can be up to a total of 10 users." - ], + ["User/User1/User2", "The user(s) to warn. Can be up to a total of 10 users."], [ "Duration", "The amount of time this warn apply for. For example 24h for 24 hours. The user(s) will automatically have the warning removed after this time." ], - [ - "Reason", - "The reason for this warning." - ] + ["Reason", "The reason for this warning."] ], "extendedHelp": "This command files a warning to a user.\nThis kind of warning is meant to be **formal warnings**, as they will be shown in the 'warnings' command.\nIt is a good practise to do an informal warning before using this command.", - "examples": [ - "@Pete Attempted to mention everyone." - ] + "examples": ["@Pete Attempted to mention everyone."] } } diff --git a/projects/bot/src/locales/en-US/commands/system.json b/projects/bot/src/locales/en-US/commands/system.json new file mode 100644 index 000000000..3ad5abf57 --- /dev/null +++ b/projects/bot/src/locales/en-US/commands/system.json @@ -0,0 +1,47 @@ +{ + "evalDescription": "Evaluates arbitrary Javascript.", + "evalExtended": { + "usages": ["Expression"], + "extendedHelp": "The eval command evaluates code as-in, any error thrown from it will be handled.\nIt also uses the flags feature. Write --silent, --depth=number or --async to customize the output.\nThe --wait flag changes the time the eval will run. Defaults to 10 seconds. Accepts time in milliseconds.\nThe --output and --output-to flag accept either `file`, `log`, `haste` or `hastebin`.\nThe --delete flag makes the command delete the message that executed the message after evaluation.\nThe --silent flag will make it output nothing.\nThe --depth flag accepts a number, for example, --depth=2, to customize util.inspect's depth.\nThe --async flag will wrap the code into an async function where you can enjoy the use of await, however, if you want to return something, you will need the return keyword\nThe --showHidden flag will enable the showHidden option in util.inspect.\nThe --lang and --language flags allow different syntax highlight for the output.\nThe --json flag converts the output to json\nThe --no-timeout flag disables the timeout\nIf the output is too large, it'll send the output as a file, or in the console if the bot does not have the {{ATTACH_FILES, permissions}} permission.", + "explainedUsage": [["Expression", "The expression to evaluate"]], + "examples": ["msg.author.username;", "1 + 1;"], + "reminder": "Reserved for bot owners." + }, + "donateDescription": "Get information about how to donate to keep Skyra alive longer.", + "donateExtended": { + "extendedHelp": "Skyra Project started on 24th October 2016, if you are reading this, you are using version {{VERSION}}. The development team improves a lot in every iteration of Skyra.\n\nHowever, not everything is free and we need your help to keep Skyra alive.\nWe will be very thankful if you help us.\nWe have been working on a lot of things, and Skyra is precious to us. Take care of her ❤\n\nDo you want to support this amazing project? Feel free to do so! https://donate.skyra.pw/patreon or https://donate.skyra.pw/kofi" + }, + "evalTimeout": "TIMEOUT: Took longer than {{seconds}} seconds.", + "evalError": "**Error**:{{output}}\n**Type**:{{type}}\n{{time}}", + "disable": "+ Successfully disabled {{type}}: {{name}}", + "disableDescription": "Re-disables or temporarily disables a command/preconditions/event. Default state restored on reboot.", + "disableExtended": { + "usages": ["Piece"], + "extendedHelp": "Disable a piece that was previously enabled", + "explainedUsage": [["Piece", "The piece to disable"]], + "reminder": "Reserved for bot owners." + }, + "disableWarn": "You probably don't want to disable that, since you wouldn't be able to run any command to enable it again", + "dmNotSent": "I cannot send you a message in DMs, did you block me?", + "dmSent": "I have sent you the message in DMs.", + "enable": "+ Successfully enabled {{type}}: {{name}}", + "enableDescription": "Re-enables or temporarily enables a command/preconditions. Default state restored on reboot.", + "enableExtended": { + "usages": ["Piece"], + "extendedHelp": "Enables a piece that was previously disabled", + "explainedUsage": [["Piece", "The piece to enable"]], + "reminder": "Reserved for bot owners." + }, + "reboot": "{{LOADING}} Rebooting...", + "rebootDescription": "Reboots the bot.", + "rebootExtended": { + "extendedHelp": "The bot goes boom, then the bot goes revive.", + "reminder": "Reserved for bot owners." + }, + "supportDescription": "Show support instructions", + "supportEmbedDescription": "Then you should probably join [Skyra's Lounge](https://join.skyra.pw)! There, you can receive support by the developers and other members of the community!", + "supportEmbedTitle": "Looking for help, {{username}}?", + "supportExtended": { + "extendedHelp": "This command gives you a link to *Skyra's Lounge*, the best place for everything related to me." + } +} diff --git a/projects/bot/src/locales/en-US/commands/tools.json b/projects/bot/src/locales/en-US/commands/tools.json new file mode 100644 index 000000000..178f4d31e --- /dev/null +++ b/projects/bot/src/locales/en-US/commands/tools.json @@ -0,0 +1,309 @@ +{ + "avatarDescription": "View somebody's avatar in full size.", + "avatarExtended": { + "usages": ["", "User"], + "extendedHelp": "As this command's name says, it shows somebody's avatar.", + "explainedUsage": [["User", "The user to get the avatar for. Defaults to you yourself."]], + "reminder": "Use the --size flag to change the avatar's size." + }, + "avatarNone": "The user does not have an avatar set.", + "color": "HEX: **{{hex}}**\nRGB: **{{rgb}}**\nHSL: **{{hsl}}**", + "colorDescription": "Display some awesome colours.", + "colorExtended": { + "usages": ["Color", "Color Difference"], + "extendedHelp": "The color command displays a set of colours with nearest tones given a difference between 1 and 255.", + "explainedUsage": [ + ["Color", "The color to check. Can be in the RGB, HSL, B10 (Base 10) or HEX format."], + [ + "Difference", + "A numeric difference between each shade of the color. Defaults to 10. If you don't know what this is, then you probably don't need it." + ] + ], + "examples": ["#dfdfdf 25", "rgb(200, 130, 75)"], + "possibleFormats": [ + ["HEX", "#dfdfdf"], + ["RGB", "rgb(200, 200, 200)"], + ["HSL", "hsl(350, 100, 100)"], + ["B10", "14671839"] + ] + }, + "contentDescription": "Get messages' raw content.", + "contentExtended": { + "usages": ["Message", "Channel Message", "Channel Message --all/--format"], + "extendedHelp": "Raw content will help you better copy-paste message content as you will not have to reproduce all the formatting.", + "explainedUsage": [ + ["Channel", "The channel in which the message is to get the content from. Defaults to the current channel"], + ["Message", "ID of the message to get the content from."], + ["--all", "Gets all content including embeds and formats them separated by lines."], + ["--format", "Gets all content including embeds and formats them in a more readable format."] + ], + "examples": ["810103450544767026", "#announcement 810103450544767026"] + }, + "contentEmpty": "The message does not contain any content I can source.", + "countryDescription": "Shows information about a country.", + "countryExtended": { + "usages": ["Country"], + "extendedHelp": "This command uses https://restcountries.eu to get information on the provided country.", + "explainedUsage": [["Country", "The name of the country."]], + "examples": ["United Kingdom"] + }, + "countryFields": { + "other": { + "area": "Area", + "currencies": "Currencies", + "demonym": "Demonym" + }, + "overview": { + "capital": "Capital", + "officialName": "Official Name", + "population": "Population" + } + }, + "countryTimezone_one": "Timezone: {{timezone.0}}", + "countryTimezone_other": "Timezones: {{timezone, andList}}", + "countryTitles": { + "LANGUAGES": "Languages", + "OTHER": "Other", + "OVERVIEW": "Overview" + }, + "createEmojiDescription": "Adds a custom emoji to your Discord server.", + "createEmojiExtended": { + "usages": ["Emoji"], + "extendedHelp": "Using a custom emoji on another server, I can re-upload that emoji to the current server.", + "explainedUsage": [["Emoji", "A custom emoji on Discord."]], + "examples": ["<:Skyra:638508279357767680>", ""], + "reminder": "Make sure the bot has {{MANAGE_EMOJIS_AND_STICKERS, permissions}} permissions in this server!" + }, + "createEmojiInvalidDiscordEmoji": "I could not resolve `{{parameter}}` to a valid Discord emoji. Make sure it is from a Discord server, and not a default emoji.", + "createEmojiDuplicate": "An emoji named `{{name}}` already exists!", + "createEmojiInvalidEmoji": "{{REDCROSS}} Failed to download that emoji.", + "createEmojiSuccess": "{{GREENTICK}} Success: {{emoji}} was created", + "defineDescription": "Check the definition of a word.", + "defineExtended": { + "usages": ["Word"], + "extendedHelp": "What does \"heel\" mean?", + "explainedUsage": [["Word", "The word or phrase you want to get the definition from."]], + "examples": ["heel"] + }, + "defineNotfound": "I could not find a definition for this word.", + "definePronounciation": "Pronunciation", + "defineUnknown": "Unknown", + "emojiCustom": "→ `Emoji ::` **{{emoji}}**\n→ `Type ::` **Custom**\n→ `ID ::` **{{id}}**", + "emojiDescription": "Get info on an emoji.", + "emojiExtended": { + "usages": ["Emoji"], + "extendedHelp": "I'll give you the emoji name, whether it is a custom emoji or not, the emoji ID and a large image preview of the emoji.", + "explainedUsage": [["Emoji", "The emoji to get information about"]], + "reminder": "It doesn't matter whether I share a server with a custom emoji or not!" + }, + "emojiInvalid": "The argument you provided is not a valid emoji.", + "emojiTooLarge": "'{{emoji}}' is so heavy the hamsters couldn't keep with its size. Maybe try one that is smaller?", + "emojiTwemoji": "→ `Emoji ::` `{{emoji}}`\n→ `Type ::` **Twemoji**\n→ `ID ::` **{{id}}**", + "eshopDescription": "Request information for any American Nintendo Digital Store", + "eshopExtended": { + "usages": ["Query"], + "extendedHelp": "This command queries Nintendo of America to show data for the game you request.", + "explainedUsage": [["Query", "The name of the game you're looking for."]], + "examples": ["Breath of the Wild", "Pokemon", "Splatoon"] + }, + "eshopNotInDatabase": "None available", + "eshopPriceFree": "Free", + "eshopPricePaid": "${{price}} USD", + "eshopTitles": { + "availability": "Availability", + "genres": "Genres", + "esrb": "ESRB", + "noGenres": "This game has not been sorted into any genres", + "nsuid": "NSUID", + "numberOfPlayers": "Number of Players", + "platform": "Platform", + "price": "Price", + "releaseDate": "Release Date" + }, + "horoscopeDescription": "Get your latest horoscope", + "horoscopeExtended": { + "usages": ["Sunsign", "Sunsign today/tomorrow/yesterday"], + "extendedHelp": "Gets the horoscope for a given sun sign from Kelli Fox's The Astrologer.", + "explainedUsage": [ + ["Sunsign", "The sun sign you want to get the horoscope for"], + ["today/tomorrow/yesterday", "If you want to get the horoscope of another day you can specify that Defaults to \"today\"."] + ], + "examples": ["pisces", "virgo tomorrow", "gemini yesterday", "aries today"] + }, + "horoscopeInvalidSunsign": "I was not able to resolve `{{parameter}}` to a valid sign, maybe try `{{maybe}}`?", + "horoscopeTitles": { + "dailyHoroscope": "Daily horoscope for {{sign}}", + "metadata": ["**Intensity:** {{intensity}}", "**Keywords:** {{keywords, andList}}", "**Mood:** {{mood}}", "**Rating:** {{rating}}"], + "metadataTitle": "Metadata" + }, + "igdbData": { + "noAgeRatings": "No age ratings available", + "noDevelopers": "Developer(s) unknown", + "noGenres": "No known genres", + "noPlatforms": "Platform(s) unknown", + "noRating": "No user rating", + "noReleaseDate": "Release date unknown", + "noSummary": "No game summary available" + }, + "igdbDescription": "Searches IGDB (Internet Game Database) for your favourite games", + "igdbExtended": { + "usages": ["Query"], + "extendedHelp": "This command queries the IGDB API to show data on your favourite games.", + "explainedUsage": [["Query", "The name of the game to look up"]], + "examples": ["Breath of the Wild", "Borderlands 3"] + }, + "igdbTitles": { + "ageRating": "Age rating(s)", + "developers": "Developer(s)", + "genres": "Genre(s)", + "platform": "Platform(s)", + "releaseDate": "Release date", + "userScore": "User score" + }, + "itunesDescription": "Searches iTunes API for music tracks", + "itunesExtended": { + "usages": ["Query"], + "extendedHelp": "This command queries the Apple iTunes API to show data on a music you request.", + "explainedUsage": [["Query", "The name of the song to look up"]], + "examples": ["Apocalyptica feat. Brent Smith", "You're Gonna Go Far, Kid"] + }, + "itunesTitles": { + "artist": "Artist", + "collection": "Collection", + "collectionPrice": "Collection price (USD)", + "numberOfTracksInCollection": "# Tracks in collection", + "preview": "Preview", + "previewLabel": "Click here", + "primaryGenre": "Primary genre", + "trackPrice": "Track price (USD)", + "trackReleaseDate": "Track Release Date" + }, + "moviesData": { + "linkClickHere": "Click here", + "movieInProduction": "Movie in production", + "noGenres": "None on TheMovieDB", + "none": "None", + "notPartOfCollection": "Not part of a collection", + "variableRuntime": "Variable" + }, + "moviesDescription": "Searches TheMovieDatabase for any movie", + "moviesExtended": { + "usages": ["Query"], + "extendedHelp": "This command queries TheMovieDatabase API for data on your favourite movies.\nTip: You can use the 'y:' filter to narrow your results by year. Example: \"star wars y:1977\".", + "explainedUsage": [["Query", "The name of the movie to look up"]], + "examples": ["Ocean's Eleven y:2001", "Star Wars Revenge of the Sith", "Spirited Away"] + }, + "moviesTitles": { + "collection": "Collection", + "genres": "Genres", + "homePage": "Home Page", + "imdbPage": "IMDB Page", + "releaseDate": "Release date", + "runtime": "Runtime", + "status": "Status", + "userScore": "User score" + }, + "pollDescription": "Simplifies reaction-based polls.", + "pollExtended": { + "usages": ["Option1 Option2", "Option1 Option2 Option3...Option20"], + "extendedHelp": "Separate your options using commas.", + "explainedUsage": [["Option1/Option2/Option3/Option20", "The options to poll. Minimum of 2, maximum of 20"]], + "examples": ["Make an anime channel, Make a gaming channel, Make a serious-discussion channel"] + }, + "pollReactionLimit": "Please don't add emojis while I am reacting!", + "priceCurrency": "**{{fromAmount}}** {{fromCurrency}} is worth {{worths, andList}}.", + "priceCurrencyNotFound": "There was an error, please make sure you specified an appropriate coin and currency.", + "priceDescription": "Convert between currencies with this command.", + "priceExtended": { + "usages": ["Amount FromCurrency ToCurrency", "Amount FromCurrency ToCurrency1 ToCurrency2 ToCurrency3...ToCurrencyX"], + "extendedHelp": "Convert between any two currencies, even if they are cryptocurrencies.", + "explainedUsage": [ + ["Amount", "The amount to convert. Default is 1."], + ["FromCurrency", "The currency to convert from"], + ["ToCurrency", "The currency to convert to, you can give multiple currencies to get results in each."] + ], + "examples": ["EUR USD", "5 USD EUR", "10 USD BAT"] + }, + "showsData": { + "noGenres": "None on TheMovieDB", + "unknownUserScore": "No user score", + "variableRuntime": "Variable" + }, + "showsDescription": "Searches The Movie Database for any show", + "showsExtended": { + "usages": ["Query"], + "extendedHelp": "This command queries TheMovieDatabase for data on your favorite shows", + "explainedUsage": [["Query", "The name of the show to search"]], + "examples": ["Final Space", "Gravity Falls", "Rick and Morty"] + }, + "showsTitles": { + "episodeRuntime": "Episode runtime", + "firstAirDate": "First air date", + "genres": "Genres", + "status": "Status", + "userScore": "User score" + }, + "systemTextTruncated": "{{definition}}... [continue reading]({{url}})", + "urbanDescription": "Check the definition of a word on UrbanDictionary.", + "urbanExtended": { + "usages": ["Word", "Word Page"], + "extendedHelp": "What does \"spam\" mean?", + "explainedUsage": [ + ["Word", "The word or phrase you want to get the definition for."], + ["Page", "The page you wish to read. Defaults to 1."] + ], + "examples": ["spam"] + }, + "urbanNoDefinition": "There are no definitions for the query `{{parameter}}`!", + "voteDescription": "Simplified reaction-based vote.", + "voteExtended": { + "usages": ["Question"], + "examples": ["Should I implement the #anime channel?"], + "explainedUsage": [["Question", "The question to vote on."]] + }, + "voteContentNeeded": "{{REDCROSS}} You must give a topic for the poll.", + "voteReactionBlocked": "{{REDCROSS}} I was not able to add the reactions necessary for this command to work because you have me blocked! 😢", + "whoisDescription": "Who are you?", + "whoisExtended": { + "usages": ["", "User"], + "extendedHelp": "Gets information on any server member. Also known as `userinfo` in many other bots.", + "explainedUsage": [["User", "The user to get information about. Defaults to you yourself."]] + }, + "whoisMemberFields": { + "createdAt": "{{memberCreatedAt}}\n{{memberCreatedAtOffset}}", + "footer": "ID: {{member.id}}", + "joinedUnknown": "Unknown", + "joinedWithTimestamp": "{{memberJoinedAt}}\n{{memberJoinedAtOffset}}" + }, + "whoisMemberPermissions": "Key Permissions", + "whoisMemberPermissionsAll": "All Permissions", + "whoisMemberRoles_one": "Role [1]", + "whoisMemberRoles_other": "Roles [{{count}}]", + "whoisMemberRoleListAndMore": "{{count}} more.", + "whoisMemberTitles": { + "createdAt": "Created At", + "joined": "Joined" + }, + "whoisUserFields": { + "createdAt": "{{userCreatedAt}}\n{{userCreatedAtOffset}}", + "footer": "ID: {{user.id}}" + }, + "whoisUserTitles": { + "createdAt": "Created At" + }, + "wikipediaDescription": "Search something through Wikipedia.", + "wikipediaExtended": { + "usages": ["Page"], + "extendedHelp": "In NSFW channels I will also add the page image, if available. This restriction is in place because Wikipedia has NSFW images for NSFW pages as they have to be accurate (i.e. diseases or human body parts).", + "explainedUsage": [["Page", "The Wikipedia page to view"]], + "reminder": "Most Wikipedia page titles are case sensitive. Some celebrities will have lowercase redirects, but not many." + }, + "wikipediaNotfound": "I am sorry, I could not find something that could match your input in Wikipedia.", + "youtubeDescription": "Search something through YouTube.", + "youtubeExtended": { + "usages": ["Query"], + "extendedHelp": "If I have the {{MANAGE_MESSAGES, permissions}} {{ADD_REACTIONS, permissions}} permissions then I will provide the option to navigate through the top 10 results.", + "explainedUsage": [["Query", "The video(s) to look up through YouTube"]] + }, + "youtubeNotfound": "I am sorry, I could not find something that could match your input in YouTube." +} diff --git a/projects/bot/src/locales/en-US/errors.json b/projects/bot/src/locales/en-US/errors.json new file mode 100644 index 000000000..048896880 --- /dev/null +++ b/projects/bot/src/locales/en-US/errors.json @@ -0,0 +1,10 @@ +{ + "channelNotReadable": "I am sorry, but I need the permissions **{{VIEW_CHANNEL, permissions}}** and **{{READ_MESSAGE_HISTORY, permissions}}**", + "guildBansEmpty": "There are no bans registered in this server.", + "guildBansNotFound": "I tried and failed to find this user from the ban list. Are you certain this user is banned?", + "guildMemberNotVoicechannel": "I cannot execute this action in a member that is not connected to a voice channel.", + "guildWarnNotFound": "I failed to fetch that warning. Either it does not exist, is not of type warning, or it has been appealed.", + "modlogTimed": "This moderation log is already timed. Expires in {{remaining, duration}}", + "unexpectedIssue": "An unexpected error popped up! Safely aborting this command...", + "userNotInGuild": "This user is not in this server." +} diff --git a/src/languages/en-US/events/errors.json b/projects/bot/src/locales/en-US/events/errors.json similarity index 99% rename from src/languages/en-US/events/errors.json rename to projects/bot/src/locales/en-US/events/errors.json index 7159d88c7..cc32ab669 100644 --- a/src/languages/en-US/events/errors.json +++ b/projects/bot/src/locales/en-US/events/errors.json @@ -2,4 +2,4 @@ "string": "{{REDCROSS}} Dear {{mention}}, {{message}}", "unexpectedError": "{{REDCROSS}} I found an unexpected error, please report the steps you have taken to my developers!", "unexpectedErrorWithContext": "$t(events/errors:unexpectedError)\nYou may add `{{report}}` to the report so they can look what error was triggered." -} \ No newline at end of file +} diff --git a/src/languages/en-US/events/guilds-logs.json b/projects/bot/src/locales/en-US/events/guilds-logs.json similarity index 89% rename from src/languages/en-US/events/guilds-logs.json rename to projects/bot/src/locales/en-US/events/guilds-logs.json index 0504961ee..3f0671b94 100644 --- a/src/languages/en-US/events/guilds-logs.json +++ b/projects/bot/src/locales/en-US/events/guilds-logs.json @@ -4,9 +4,9 @@ "channelCreatePosition": "• **Position**: `{{value, number}}`", "channelCreatePermissionsTitle": "• **Permissions for {{value}}**", "channelCreatePermissionsAllow_one": "- **Allowed Permission**: {{values}}", - "channelCreatePermissionsAllow_other": "- **Allowed Permissions**: {{values, list(conjunction)}}", + "channelCreatePermissionsAllow_other": "- **Allowed Permissions**: {{values, andList}}", "channelCreatePermissionsDeny_one": "- **Denied Permission**: {{values}}", - "channelCreatePermissionsDeny_other": "- **Denied Permissions**: {{values, list(conjunction)}}", + "channelCreatePermissionsDeny_other": "- **Denied Permissions**: {{values, andList}}", "channelCreateNsfw": "• **Set as NSFW**", "channelCreateTopic": "• **Topic**: `{{value}}`", "channelCreateRateLimit": "• **Rate Limit**: `{{value, duration}}`", @@ -22,16 +22,16 @@ "channelUpdateParentRemoved": "• **Parent**: {{value}} → Not Set", "channelUpdatePosition": "• **Position**: `{{previous, number}}` → `{{next, number}}`", "channelUpdateAddedPermissionsAllow_one": "- **Added Allowed Permission**: {{values}}", - "channelUpdateAddedPermissionsAllow_other": "- **Added Allowed Permissions**: {{values, list(conjunction)}}", + "channelUpdateAddedPermissionsAllow_other": "- **Added Allowed Permissions**: {{values, andList}}", "channelUpdateAddedPermissionsDeny_one": "- **Added Denied Permission**: {{values}}", - "channelUpdateAddedPermissionsDeny_other": "- **Added Denied Permissions**: {{values, list(conjunction)}}", + "channelUpdateAddedPermissionsDeny_other": "- **Added Denied Permissions**: {{values, andList}}", "channelUpdateAddedPermissionsTitle": "• **Added Permissions for {{value}}**", "channelUpdateDeletedPermissionsTitle": "• **Removed Permissions for {{value}}**", "channelUpdatePermissionsTitle": "• **Updated Permissions for {{value}}**", "channelUpdateRemovedPermissionsAllow_one": "- **Removed Allowed Permission**: {{values}}", - "channelUpdateRemovedPermissionsAllow_other": "- **Removed Allowed Permissions**: {{values, list(conjunction)}}", + "channelUpdateRemovedPermissionsAllow_other": "- **Removed Allowed Permissions**: {{values, andList}}", "channelUpdateRemovedPermissionsDeny_one": "- **Removed Denied Permission**: {{values}}", - "channelUpdateRemovedPermissionsDeny_other": "- **Removed Denied Permissions**: {{values, list(conjunction)}}", + "channelUpdateRemovedPermissionsDeny_other": "- **Removed Denied Permissions**: {{values, andList}}", "channelUpdateRateLimit": "• **Rate Limit**: `{{previous, duration}}` → `{{next, duration}}`", "channelUpdateRateLimitAdded": "• **Rate Limit**: Not Set → `{{value, duration}}`", "channelUpdateRateLimitRemoved": "• **Rate Limit**: `{{value, duration}}` → Not Set", @@ -57,15 +57,15 @@ "emojiUpdateName": "• **Name**: `{{previous}}` → `{{next}}`", "emojiUpdateRequiresColons": "• **Requires Colons**: `{{previous}}` → `{{next}}`", "emojiUpdateRolesAdded_one": "• **Added Required Role**: {{values}}", - "emojiUpdateRolesAdded_other": "• **Added Required Roles**: {{values, list(conjunction)}}", + "emojiUpdateRolesAdded_other": "• **Added Required Roles**: {{values, andList}}", "emojiUpdateRolesRemoved_one": "• **Removed Required Role**: {{values}}", - "emojiUpdateRolesRemoved_other": "• **Removed Required Roles**: {{values, list(conjunction)}}", + "emojiUpdateRolesRemoved_other": "• **Removed Required Roles**: {{values, andList}}", "roleCreate": "Role Created", "roleCreateColor": "• **Color**: `{{value}}`", "roleCreateHoist": "• **Hoisted**", "roleCreateMentionable": "• **Mentionable**", "roleCreatePermissions_one": "• **With Permission**: {{values}}", - "roleCreatePermissions_other": "• **With Permissions**: {{values, list(conjunction)}}", + "roleCreatePermissions_other": "• **With Permissions**: {{values, andList}}", "roleCreatePosition": "• **Position**: `{{value, number}}`", "roleDelete": "Role Deleted", "roleUpdate": "Role Updated", @@ -74,9 +74,9 @@ "roleUpdateMentionable": "• **Mentionable**: `{{previous}}` → `{{next}}`", "roleUpdateName": "• **Name**: `{{previous}}` → `{{next}}`", "roleUpdatePermissionsAdded_one": "• **Added Permission**: {{values}}", - "roleUpdatePermissionsAdded_other": "• **Added Permissions**: {{values, list(conjunction)}}", + "roleUpdatePermissionsAdded_other": "• **Added Permissions**: {{values, andList}}", "roleUpdatePermissionsRemoved_one": "• **Removed Permissions**: {{values}}", - "roleUpdatePermissionsRemoved_other": "• **Removed Permissions**: {{values, list(conjunction)}}", + "roleUpdatePermissionsRemoved_other": "• **Removed Permissions**: {{values, andList}}", "roleUpdatePosition": "• **Position**: `{{previous, number}}` → `{{next, number}}`", "serverUpdate": "Server Updated", "serverUpdateAfkChannelAdded": "• **AFK Channel**: Not Set → {{value}}", @@ -95,9 +95,9 @@ "serverUpdateDiscoverySplash": "• **Splash**: [Old]({{previous}}) → [New]({{next}})", "serverUpdateExplicitContentFilter": "• **Explicit Content Filter**: `{{previous, explicitContentFilter}}` → `{{next, explicitContentFilter}}`", "serverUpdateFeaturesAdded_one": "• **Added Feature**: {{values}}", - "serverUpdateFeaturesAdded_other": "• **Added Features**: {{values, list(conjunction)}}", + "serverUpdateFeaturesAdded_other": "• **Added Features**: {{values, andList}}", "serverUpdateFeaturesRemoved_one": "• **Removed Feature**: {{values}}", - "serverUpdateFeaturesRemoved_other": "• **Removed Features**: {{values, list(conjunction)}}", + "serverUpdateFeaturesRemoved_other": "• **Removed Features**: {{values, andList}}", "serverUpdateIconAdded": "• **Icon**: Not Set → [New]({{value}})", "serverUpdateIconRemoved": "• **Icon**: [Old]({{value}}) → Not Set", "serverUpdateIcon": "• **Icon**: [Old]({{previous}}) → [New]({{next}})", @@ -125,9 +125,9 @@ "serverUpdateSplashRemoved": "• **Splash**: [Old]({{value}}) → Not Set", "serverUpdateSplash": "• **Splash**: [Old]({{previous}}) → [New]({{next}})", "serverUpdateSystemChannelFlagsAdded_one": "• **Added System Channel Option**: {{values}}", - "serverUpdateSystemChannelFlagsAdded_other": "• **Added System Channel Options**: {{values, list(conjunction)}}", + "serverUpdateSystemChannelFlagsAdded_other": "• **Added System Channel Options**: {{values, andList}}", "serverUpdateSystemChannelFlagsRemoved_one": "• **Removed System Channel Option**: {{values}}", - "serverUpdateSystemChannelFlagsRemoved_other": "• **Removed System Channel Options**: {{values, list(conjunction)}}", + "serverUpdateSystemChannelFlagsRemoved_other": "• **Removed System Channel Options**: {{values, andList}}", "serverUpdateSystemChannelAdded": "• **System Channel**: Not Set → {{value}}", "serverUpdateSystemChannelRemoved": "• **System Channel**: {{value}} → Not Set", "serverUpdateSystemChannel": "• **System Channel**: {{previous}} → {{next}}", @@ -139,20 +139,5 @@ "serverUpdateWidgetChannelRemoved": "• **Widget Channel**: {{value}} → Not Set", "serverUpdateWidgetChannel": "• **Widget Channel**: {{previous}} → {{next}}", "serverUpdateWidgetEnabled": "• **Widget Enabled**", - "serverUpdateWidgetDisabled": "• **Widget Disabled**", - "voiceChannelJoin": "Joined {{channel}}", - "voiceChannelLeave": "Left {{channel}}", - "voiceChannelMove": "Moved from {{oldChannel}} to {{newChannel}}", - "commandExecuteTitle": "Command Executed", - "settingsUpdateTitle": "Settings Updated", - "settingsAccessDeniedTitle": "Settings Access Denied", - "logFieldUser": "User", - "logFieldCommand": "Command", - "logFieldType": "Type", - "logFieldChannel": "Channel", - "logFieldChange": "Changes", - "logFieldReason": "Reason", - "commandTypeChatInput": "Chat Input", - "commandTypeContextMenu": "Context Menu", - "commandTypeMessage": "Message Command" + "serverUpdateWidgetDisabled": "• **Widget Disabled**" } diff --git a/src/languages/en-US/events/guilds-members.json b/projects/bot/src/locales/en-US/events/guilds-members.json similarity index 74% rename from src/languages/en-US/events/guilds-members.json rename to projects/bot/src/locales/en-US/events/guilds-members.json index ac993520d..9046a3851 100644 --- a/src/languages/en-US/events/guilds-members.json +++ b/projects/bot/src/locales/en-US/events/guilds-members.json @@ -1,16 +1,16 @@ { "guildMemberAdd": "User Joined", - "guildMemberAddDescription": "{{user}} joined Discord {{relativeTime}}", - "guildMemberAddedRoles_other": "**Added roles**: {{addedRoles, list(conjunction)}}", + "guildMemberAddDescription": "{{mention}} | **Joined Discord**: {{time, duration}} ago.", + "guildMemberAddedRoles_other": "**Added roles**: {{addedRoles, andList}}", "guildMemberAddedRoles_one": "**Added role**: {{addedRoles}}", "guildMemberAddMute": "Muted User joined", "guildMemberBanned": "User Banned", "guildMemberKicked": "User Kicked", "guildMemberNoUpdate": "No update detected", "guildMemberRemove": "User Left", - "guildMemberRemoveDescription": "{{user}} joined this server *an unknown time ago*", - "guildMemberRemoveDescriptionWithJoinedAt": "{{user}} joined this server {{relativeTime}}", - "guildMemberRemovedRoles_other": "**Removed roles**: {{removedRoles, list(conjunction)}}", + "guildMemberRemoveDescription": "{{mention}} | **Joined Server**: Unknown.", + "guildMemberRemoveDescriptionWithJoinedAt": "{{mention}} | **Joined Server**: {{time, duration}} ago.", + "guildMemberRemovedRoles_other": "**Removed roles**: {{removedRoles, andList}}", "guildMemberRemovedRoles_one": "**Removed role**: {{removedRoles}}", "guildMemberSoftBanned": "User Softbanned", "nameUpdateNextWasNotSet": "**Next**: Unset", diff --git a/projects/bot/src/locales/en-US/events/messages.json b/projects/bot/src/locales/en-US/events/messages.json new file mode 100644 index 000000000..9ecf6d630 --- /dev/null +++ b/projects/bot/src/locales/en-US/events/messages.json @@ -0,0 +1,4 @@ +{ + "messageDelete": "Message Deleted • {{channel}}", + "messageUpdate": "Message Edited • {{channel}}" +} diff --git a/src/languages/en-US/events/moderation.json b/projects/bot/src/locales/en-US/events/moderation.json similarity index 95% rename from src/languages/en-US/events/moderation.json rename to projects/bot/src/locales/en-US/events/moderation.json index fdcfebeb1..4eabded00 100644 --- a/src/languages/en-US/events/moderation.json +++ b/projects/bot/src/locales/en-US/events/moderation.json @@ -9,8 +9,8 @@ "capsFilterDm": "Speak lower! I know you need to express your thoughts. There is the message I deleted:{{message}}", "capsFilterFooter": "Too Many UpperCases", "inviteFilterAlert": "{{REDCROSS}} Dear {{user}}, invite links aren't allowed here.", - "inviteFilterLog_one": "**Link**: {{links, list(conjunction)}}", - "inviteFilterLog_other": "**Links**: {{links, list(conjunction)}}", + "inviteFilterLog_one": "**Link**: {{links, andList}}", + "inviteFilterLog_other": "**Links**: {{links, andList}}", "inviteLink": "Invite link", "invites": "[Auto-Moderation] Triggered invite filter, no threshold.", "invitesWithMaximum": "[Auto-Moderation] Triggered invite filter, reached {{amount}} out of {{maximum}} infractions.", diff --git a/src/languages/en-US/events/noMentionSpam.json b/projects/bot/src/locales/en-US/events/noMentionSpam.json similarity index 61% rename from src/languages/en-US/events/noMentionSpam.json rename to projects/bot/src/locales/en-US/events/noMentionSpam.json index 7afc530ab..c4ecb8440 100644 --- a/src/languages/en-US/events/noMentionSpam.json +++ b/projects/bot/src/locales/en-US/events/noMentionSpam.json @@ -1,6 +1,6 @@ { "footer": "[NOMENTIONSPAM]", "alert": "Be careful mentioning any more, as you are about to be banned for exceeding this server's mention threshold.", - "message": "The banhammer has landed and now the user {{userTag}} with id {{userId}} is banned for mention spam.\nDo not worry! I'm here to help you! 😄", + "message": "The banhammer has landed and now the user {{user.tag}} with id {{user.id}} is banned for mention spam.\nDo not worry! I'm here to help you! 😄", "modlog": "[NOMENTIONSPAM] Automatic: Mention Spam threshold exceeded.\nThreshold: {{threshold}}." } diff --git a/src/languages/en-US/events/reactions.json b/projects/bot/src/locales/en-US/events/reactions.json similarity index 70% rename from src/languages/en-US/events/reactions.json rename to projects/bot/src/locales/en-US/events/reactions.json index 94ab655d5..a228f39ff 100644 --- a/src/languages/en-US/events/reactions.json +++ b/projects/bot/src/locales/en-US/events/reactions.json @@ -1,6 +1,5 @@ { - "reactionDescription": "Reacted with {{emoji}} on {{message}}", - "reactionFooter": "First Reaction Added", + "reaction": "Reaction Added", "filterFooter": "Filtered Reaction", "filter": "{{REDCROSS}} Hey {{user}}, please do not add that reaction!", "selfRoleHierarchy": "{{REDCROSS}} My role needs to be higher than all self-assignable roles, otherwise I can't grant them to people!" diff --git a/projects/bot/src/locales/en-US/events/twitch.json b/projects/bot/src/locales/en-US/events/twitch.json new file mode 100644 index 000000000..0da0b3407 --- /dev/null +++ b/projects/bot/src/locales/en-US/events/twitch.json @@ -0,0 +1,5 @@ +{ + "embedDescription": "{{userName}} is now live!", + "embedDescriptionWithGame": "{{userName}} is now live - Streaming {{gameName}}!", + "offlinePostfix": "Skyra Twitch Notifications" +} diff --git a/src/languages/en-US/fuzzySearch.json b/projects/bot/src/locales/en-US/fuzzySearch.json similarity index 99% rename from src/languages/en-US/fuzzySearch.json rename to projects/bot/src/locales/en-US/fuzzySearch.json index 79d02f872..d19a4ba17 100644 --- a/src/languages/en-US/fuzzySearch.json +++ b/projects/bot/src/locales/en-US/fuzzySearch.json @@ -3,4 +3,4 @@ "invalidIndex": "That number was out of range, aborting prompt.", "invalidNumber": "I expected you to give me a (single digit) number, got a potato.", "matches": "I found multiple matches! **Please select a number within 0 and {{matches}}**:\n{{codeblock}}\nWrite **ABORT** if you want to exit the prompt." -} \ No newline at end of file +} diff --git a/src/languages/en-US/globals.json b/projects/bot/src/locales/en-US/globals.json similarity index 67% rename from src/languages/en-US/globals.json rename to projects/bot/src/locales/en-US/globals.json index 3214374b7..562660e62 100644 --- a/src/languages/en-US/globals.json +++ b/projects/bot/src/locales/en-US/globals.json @@ -7,20 +7,13 @@ "yes": "Yes", "paginatedMessagePage": "Page", "paginatedMessageWrongUserInteractionReply": "Please stop clicking the buttons on this message. They are only for {{user}}.", + "ordinalValue": "{{value, ordinal}}", "durationValue": "{{value, duration}}", "numberValue": "{{value, number}}", "numberCompactValue": "{{value, numberCompact}}", "dateTimeValue": "{{value, dateTime}}", - "humanDateTimeValue": "{{value, humanDateTime}}", - "andListValue": "{{value, list(conjunction)}}", + "andListValue": "{{value, andList}}", "orListValue": "{{value, orList}}", "dateFormat": "MM/DD/YYYY", - "dateFormatExplanation": "Month/Day/Year", - "back": "Back", - "stop": "Stop", - "set": "Set", - "remove": "Remove", - "reset": "Reset", - "value": "Value", - "cancel": "Cancel" + "dateFormatExplanation": "Month/Day/Year" } diff --git a/projects/bot/src/locales/en-US/guilds.json b/projects/bot/src/locales/en-US/guilds.json new file mode 100644 index 000000000..7511b95ff --- /dev/null +++ b/projects/bot/src/locales/en-US/guilds.json @@ -0,0 +1,11 @@ +{ + "explicitContentFilterDisabled": "Disabled", + "explicitContentFilterMembersWithoutRoles": "Members without roles", + "explicitContentFilterAllMembers": "All members", + "messageNotificationsAll": "All Messages", + "messageNotificationsMentions": "Only @mentions", + "SUPPRESS_JOIN_NOTIFICATIONS": "Member join notifications", + "SUPPRESS_JOIN_NOTIFICATION_REPLIES": "Member join sticker reply buttons", + "SUPPRESS_PREMIUM_SUBSCRIPTIONS": "Server boost notifications", + "SUPPRESS_GUILD_REMINDER_NOTIFICATIONS": "Server setup tips" +} diff --git a/projects/bot/src/locales/en-US/humanLevels.json b/projects/bot/src/locales/en-US/humanLevels.json new file mode 100644 index 000000000..a35c4b3c8 --- /dev/null +++ b/projects/bot/src/locales/en-US/humanLevels.json @@ -0,0 +1,7 @@ +{ + "NONE": "None", + "LOW": "Low", + "MEDIUM": "Medium", + "HIGH": "High", + "VERY_HIGH": "Highest" +} diff --git a/projects/bot/src/locales/en-US/moderation.json b/projects/bot/src/locales/en-US/moderation.json new file mode 100644 index 000000000..2a0dddc4e --- /dev/null +++ b/projects/bot/src/locales/en-US/moderation.json @@ -0,0 +1,21 @@ +{ + "caseNotExists_one": "{{REDCROSS}} I am sorry, but the selected moderation log case does not exist.", + "caseNotExists_other": "{{REDCROSS}} I am sorry, but none of the selected moderation logs cases exist.", + "logAppealed": "{{REDCROSS}} I am sorry, but the selected moderation log has expired or cannot be cannot be made temporary.", + "logDescriptionTypeAndUser": "❯ **Type**: {{data.type}}\n❯ **User:** {{data.userName}}#{{data.userDiscriminator}} ({{data.userId}})", + "logDescriptionWithReason": "❯ **Reason:** {{data.reason}}{{data.formattedDuration}}", + "logDescriptionWithoutReason": "❯ **Reason:** Please use `{{data.prefix}}reason {{data.caseId}} ` to set the reason.{{data.formattedDuration}}", + "logExpiresIn": "\n❯ **Expires In**: {{duration, duration}}", + "logFooter": "Case {{caseId}}", + "muteCannotManageRoles": "I must have **{{MANAGE_ROLES, permissions}}** permissions to be able to mute.", + "muteLowHierarchy": "I cannot mute a user which higher role hierarchy than me.", + "muteNotConfigured": "The muted role must be configured for this action to happen.", + "muteNotExists": "The specified user is not muted.", + "muteNotInMember": "The muted role is not set in the member.", + "restrictionNotConfigured": "The restriction role must be configured for this action to happen", + "roleHigher": "The selected member has a role position that is higher than or equal to yours.", + "roleHigherSkyra": "The selected member has a role position that is higher than or equal to mine.", + "success": "Successfully executed the command.", + "toSkyra": "Why... I thought you loved me! 💔", + "userSelf": "Why would you do that to yourself?" +} diff --git a/src/languages/en-US/moderationActions.json b/projects/bot/src/locales/en-US/moderationActions.json similarity index 77% rename from src/languages/en-US/moderationActions.json rename to projects/bot/src/locales/en-US/moderationActions.json index 6f617fc74..e91d9b12d 100644 --- a/src/languages/en-US/moderationActions.json +++ b/projects/bot/src/locales/en-US/moderationActions.json @@ -1,25 +1,19 @@ { "actions": { - "addRole": "Role Add", + "addRole": "Added Role", "ban": "Ban", "kick": "Kick", "mute": "Mute", - "removeRole": "Role Remove", + "removeRole": "Remove Role", "restrictedAttachment": "Attachment Restriction", "restrictedEmbed": "Embed Restriction", - "restrictedEmoji": "Emoji Restriction", "restrictedReact": "Reaction Restriction", "restrictedVoice": "Voice Restriction", "setNickname": "Set Nickname", "softban": "Softban", "vkick": "Voice Kick", - "vmute": "Voice Mute", - "warning": "Warning" + "vmute": "Voice Mute" }, - "actionCannotManageRoles": "I cannot give or remove roles in this server.", - "actionRoleNotConfigured": "The role for this action is not configured.", - "actionRoleHigherPosition": "I cannot give or remove the role for this action because it has higher or equal hierarchy position than me.", - "actionRoleManaged": "I cannot give or remove the role for this action because it is managed by an integration.", "applyNoReason": "[Action] Applied {{action}}", "applyReason": "[Action] Applied {{action}} | Reason: {{reason}}", "requiredMember": "The user does not exist or is not in this server.", @@ -30,6 +24,7 @@ "setNicknameRemoved": "[Action] Removed Nickname | Reason: {{reason}}", "setNicknameSet": "[Action] Set Nickname | Reason: {{reason}}", "setupMuteExists": "**Aborting creating muted**: There is already a role called \"Muted\".", + "setupRestrictionExists": "**Aborting restriction role creation**: There is already one that exists.", "setupTooManyRoles": "**Aborting role creation**: There are 250 roles in this server, you need to delete one role.", "sharedRoleSetupAsk": "{{LOADING}} Can I modify {{channels}} channel to apply the role {{role}} the following permission: {{permissions}}?", "sharedRoleSetupNoMessage": "You did not input a message on time, cancelling the set up!", diff --git a/projects/bot/src/locales/en-US/permissions.json b/projects/bot/src/locales/en-US/permissions.json new file mode 100644 index 000000000..9bf1eda16 --- /dev/null +++ b/projects/bot/src/locales/en-US/permissions.json @@ -0,0 +1,43 @@ +{ + "ADD_REACTIONS": "Add Reactions", + "ADMINISTRATOR": "Administrator", + "ATTACH_FILES": "Attach Files", + "BAN_MEMBERS": "Ban Members", + "CHANGE_NICKNAME": "Change Nickname", + "CONNECT": "Connect", + "CREATE_INSTANT_INVITE": "Create Invite", + "CREATE_PRIVATE_THREADS": "Create Private Threads", + "CREATE_PUBLIC_THREADS": "Create Public Threads", + "DEAFEN_MEMBERS": "Deafen Members", + "EMBED_LINKS": "Embed Links", + "KICK_MEMBERS": "Kick Members", + "MANAGE_CHANNELS": "Manage Channels", + "MANAGE_EMOJIS_AND_STICKERS": "Manage Emojis and Stickers", + "MANAGE_EVENTS": "Manage Events", + "MANAGE_GUILD": "Manage Server", + "MANAGE_MESSAGES": "Manage Messages", + "MANAGE_NICKNAMES": "Manage Nicknames", + "MANAGE_ROLES": "Manage Roles", + "MANAGE_THREADS": "Manage Threads", + "MANAGE_WEBHOOKS": "Manage Webhooks", + "MENTION_EVERYONE": "Mention everyone, here, and All Roles", + "MODERATE_MEMBERS": "Timeout Members", + "MOVE_MEMBERS": "Move Members", + "MUTE_MEMBERS": "Mute Members", + "PRIORITY_SPEAKER": "Priority Speaker", + "READ_MESSAGE_HISTORY": "Read Message History", + "REQUEST_TO_SPEAK": "Request to Speak", + "SEND_MESSAGES": "Send Messages", + "SEND_TTS_MESSAGES": "Send Text-to-Speech Messages", + "SPEAK": "Speak", + "STREAM": "Video", + "USE_APPLICATION_COMMANDS": "Use Application Commands", + "USE_EXTERNAL_EMOJIS": "Use External Emojis", + "USE_EXTERNAL_STICKERS": "Use External Stickers", + "USE_PRIVATE_THREADS": "Create Private Threads", + "USE_PUBLIC_THREADS": "Create Public Threads", + "USE_VAD": "Use Voice Activity", + "VIEW_AUDIT_LOG": "View Audit Log", + "VIEW_CHANNEL": "View Channels", + "VIEW_GUILD_INSIGHTS": "View Server Insights" +} diff --git a/src/languages/en-US/preconditions.json b/projects/bot/src/locales/en-US/preconditions.json similarity index 57% rename from src/languages/en-US/preconditions.json rename to projects/bot/src/locales/en-US/preconditions.json index 790c65973..731c9d138 100644 --- a/src/languages/en-US/preconditions.json +++ b/projects/bot/src/locales/en-US/preconditions.json @@ -1,22 +1,6 @@ { - "clientPermissions": "I don't have sufficient permissions! I'm missing: {{missing, permissions, list(conjunction)}}", - "clientPermissionsNoClient": "This should never happen, I don't know who I am.", - "clientPermissionsNoPermissions": "This should never happen, I failed to determine what permissions I have.", - "runIn": "This command cannot be run in this channel type.", - "userPermissionsNoPermissions": "This should never happen, I failed to determine what permissions you have.", - "unavailable": "This should never happen, I could not find a required precondition for this command.", + "clientPermissions": "I don't have sufficient permissions! I'm missing: {{missing, permissionsAndList}}", "cooldown": "You have just used this command. You can use this command again in {{remaining, duration}}.", - "nsfw": "You may not use NSFW commands in this channel!", - "userPermissions": "You don't have sufficient permissions! You're missing: {{missing, permissions, list(conjunction)}}", - "missingMessageHandler": "This should never happen, one of the preconditions this command requires is missing a message handler.", - "missingChatInputHandler": "This should never happen, one of the preconditions this command requires is missing a slash command handler.", - "missingContextMenuHandler": "This should never happen, one of the preconditions this command requires is missing a context menu handler.", - "administrator": "You need administrator privileges to run `{{command.name}}`!", - "disabledGlobal": "This command has been globally disabled by the bot owners. Want to know why and find out when it will be back? Join the official WolfStar server: ", - "disabledGuild": "This command has been disabled by an admin in this server!", - "moderator": "You need moderator privileges to run `{{command.name}}`!", - "permissionNodes": "{{REDCROSS}} You do not have permission to use this command!", - "serverOwner": "You need to be the server's owner to run `{{command.name}}`!", "dmOnly": "This command can only be used in DM channels.", "guildNewsOnly": "This command can only be used in announcement channels.", "guildNewsThreadOnly": "This command can only be used in announcement thread channels.", @@ -24,5 +8,14 @@ "guildPrivateThreadOnly": "This command can only be used in private thread channels.", "guildPublicThreadOnly": "This command can only be used in public thread channels.", "guildTextOnly": "This command can only be used in text channels.", - "threadOnly": "This command can only be used in thread channels." + "nsfw": "You may not use NSFW commands in this channel!", + "threadOnly": "This command can only be used in thread channels.", + "userPermissions": "You don't have sufficient permissions! You're missing: {{missing, permissionsAndList}}", + "administrator": "You need administrator privileges to run `{{command.name}}`!", + "disabledGlobal": "This command has been globally disabled by the bot owners. Want to know why and find out when it will be back? Join the official Skyra server: ", + "disabledGuild": "This command has been disabled by an admin in this server!", + "moderator": "You need moderator privileges to run `{{command.name}}`!", + "permissionNodes": "{{REDCROSS}} You do not have permission to use this command!", + "serverOwner": "You need to be the server's owner to run `{{command.name}}`!", + "subCommandGuildOnly": "This subcommand can only be used in server channels due to Discord limitations. We will likely make this command available in DMs when we implement the new \"buttons\" feature." } diff --git a/projects/bot/src/locales/en-US/promptList.json b/projects/bot/src/locales/en-US/promptList.json new file mode 100644 index 000000000..3d145c7b9 --- /dev/null +++ b/projects/bot/src/locales/en-US/promptList.json @@ -0,0 +1,6 @@ +{ + "aborted": "Successfully aborted the prompt.", + "attemptFailed": "Invalid input. Attempt **{{attempt}}** out of **{{maxAttempts}}**\n{{list}}", + "multipleChoice_other": "There are {{count}} results. Please choose a number between 1 and {{count}}, or write **`CANCEL`** to cancel the prompt.\n{{list}}", + "multipleChoice_one": "There are {{count}} result. Please choose a number between 1 and {{count}}, or write **`CANCEL`** to cancel the prompt.\n{{list}}" +} diff --git a/src/languages/en-US/selfModeration.json b/projects/bot/src/locales/en-US/selfModeration.json similarity index 88% rename from src/languages/en-US/selfModeration.json rename to projects/bot/src/locales/en-US/selfModeration.json index 73dd9ea48..93cf3a247 100644 --- a/src/languages/en-US/selfModeration.json +++ b/projects/bot/src/locales/en-US/selfModeration.json @@ -4,10 +4,10 @@ "commandHardAction": "{{GREENTICK}} Successfully set punishment: {{value}}", "commandHardActionDuration": "{{GREENTICK}} Successfully removed the punishment appeal timer.", "commandHardActionDurationWithValue": "{{GREENTICK}} Successfully set the punishment appeal timer to: {{value, duration}}", - "commandInvalidHardaction": "{{REDCROSS}} Value must be any of the following: `none`, `warn`, `mute`, `kick`, `softban`, or `ban`. Check `WolfStar, help {{name}}` for more information.", - "commandInvalidMissingAction": "{{REDCROSS}} Action must be any of the following: `enable`, `disable`, `action`, `punish`, `punish-duration`, `threshold-maximum`, `threshold-duration`, or `show`. Check `WolfStar, help {{name}}` for more information.", - "commandInvalidMissingArguments": "{{REDCROSS}} The specified action requires an extra argument to be passed. Check `WolfStar, help {{name}}` for more information.", - "commandInvalidSoftaction": "{{REDCROSS}} Value must be any of the following: `alert`, `log`, or `delete`. Check `WolfStar, help {{name}}` for more information.", + "commandInvalidHardaction": "{{REDCROSS}} Value must be any of the following: `none`, `warn`, `mute`, `kick`, `softban`, or `ban`. Check `Skyra, help {{name}}` for more information.", + "commandInvalidMissingAction": "{{REDCROSS}} Action must be any of the following: `enable`, `disable`, `action`, `punish`, `punish-duration`, `threshold-maximum`, `threshold-duration`, or `show`. Check `Skyra, help {{name}}` for more information.", + "commandInvalidMissingArguments": "{{REDCROSS}} The specified action requires an extra argument to be passed. Check `Skyra, help {{name}}` for more information.", + "commandInvalidSoftaction": "{{REDCROSS}} Value must be any of the following: `alert`, `log`, or `delete`. Check `Skyra, help {{name}}` for more information.", "commandShow": "Enabled : {{kEnabled}}\nAction\n - Alert : {{kAlert}}\n - Log : {{kLog}}\n - Delete : {{kDelete}}\nPunishment\n - Type : {{kHardAction}}\n - Duration : {{hardActionDurationText}}\nThreshold\n - Maximum : {{thresholdMaximumText}}\n - Duration : {{thresholdDurationText}}", "commandShowDurationPermanent": "Permanent", "commandShowUnset": "Unset", @@ -26,4 +26,4 @@ "softActionAlert": "Alert", "softActionDelete": "Delete", "softActionLog": "Log" -} \ No newline at end of file +} diff --git a/src/languages/en-US/settings.json b/projects/bot/src/locales/en-US/settings.json similarity index 79% rename from src/languages/en-US/settings.json rename to projects/bot/src/locales/en-US/settings.json index a84c97241..d7d086956 100644 --- a/src/languages/en-US/settings.json +++ b/projects/bot/src/locales/en-US/settings.json @@ -4,7 +4,6 @@ "channelsIgnoreMessageDelete": "Channels I should ignore when checking for deleted messages to log.", "channelsIgnoreMessageEdit": "Channels I should ignore when checking for edited messages to log.", "channelsIgnoreReactionAdd": "Channels I should ignore when checking for added reactions.", - "channelsIgnoreVoiceActivity": "The channels I should ignore when reporting activity changes.", "channelsLogsChannelCreate": "The channel for channel creation logs, if set, I will send a message when another channel is created.", "channelsLogsChannelDelete": "The channel for channel deletion logs, if set, I will send a message to this channel when another channel is deleted.", "channelsLogsChannelUpdate": "The channel for channel update logs, if set, I will send a message to this channel when any channel (including this one) gets updated in any way. This message will contain the changes made to the channel.", @@ -28,19 +27,13 @@ "channelsLogsRoleDelete": "The channel for role deletion logs, if set, I send a message when a role is deleted.", "channelsLogsRoleUpdate": "The channel for role update logs, if set, I send a message when a role is updated in any way. This message will contain the changes made to the role.", "channelsLogsServerUpdate": "The channel for server update logs, if set, I send a message when the server is updated in any way. This message will contain the changes made to the server.", - "channelsLogsVoiceChannel": "The channel for voice channel logs, if set, I send a message when a user joins, leaves, or moves to another voice channel.", - "channelsLogsCommand": "The channel for command execution logs, if set, I send a message whenever a bot command is used.", - "channelsLogsSettings": "The channel for settings change logs, if set, I send a message whenever settings are updated, added, removed, or access is denied.", - "dashboardOnlyKey": "This key can only be configured through [the web dashboard](https://wolfstar.rocks)", + "dashboardOnlyKey": "This key can only be configured through [the web dashboard](https://skyra.pw)", "disabledChannels": "A list of channels for disabled commands, for example, setting up a channel called general will forbid all users from using my commands there. Moderators+ override this purposely to allow them to moderate without switching channels.", "disabledCommands": "The disabled commands, core commands may not be disabled, and moderators will override this. All commands must be in lower case.", - "disableNaturalPrefix": "Whether or not I should listen for my natural prefix, `WolfStar,`", - "eventsBanAdd": "This event posts non-bot moderation logs when a user gets banned. You must set up `channels.moderation-logs`.", - "eventsBanRemove": "This event posts non-bot moderation logs when a user gets unbanned. You must set up `channels.moderation-logs`.", - "eventsTimeout": "This event posts non-bot moderation logs when a user's timeout status changes. You must set up `channels.moderation-logs`.", - "eventsUnknownMessages": "Whether or not I should post updates on unknown command messages.", + "disableNaturalPrefix": "Whether or not I should listen for my natural prefix, `Skyra,`", + "eventsBanAdd": "This event posts anonymous moderation logs when a user gets banned. You must set up `channels.moderation-logs`.", + "eventsBanRemove": "This event posts anonymous moderation logs when a user gets unbanned. You must set up `channels.moderation-logs`.", "eventsTwemojiReactions": "Whether or not twemoji reactions are posted in the reaction logs channel.", - "eventsIncludeBots": "Whether or not I should ignore bots in the server logs.", "language": "The language I will use for your server. It may not be available in the language you want.", "messagesIgnoreChannels": "The channels configured to not increase the point counter for users.", "messagesModerationAutoDelete": "Whether or not moderation commands should be auto-deleted or not.", @@ -91,22 +84,35 @@ "selfmodLinksIgnoredChannels": "The channels that will be ignored by the links filter sub-system", "selfmodLinksIgnoredRoles": "The roles that will be ignored by the links filters sub-system", "selfmodLinksAllowed": "The links that are allowed", - "selfmodMessagesEnabled": "Whether WolfStar should attempt to remove duplicated messages or not.", + "selfmodMessagesEnabled": "Whether Skyra should attempt to remove duplicated messages or not.", "selfmodMessagesIgnoredChannels": "The channels that will be ignored by the duplicate messages sub-system", "selfmodMessagesIgnoredRoles": "The roles that will be ignored by the duplicate messages sub-system", "selfmodMessagesMaximum": "The amount of duplicated messages required in the queue before taking action The queue size is configurable in `selfmod.messages.queue-size`.", - "selfmodMessagesQueueSize": "The amount of messages WolfStar will keep track of for the message duplication detection.", + "selfmodMessagesQueueSize": "The amount of messages Skyra will keep track of for the message duplication detection.", "selfmodNewlinesEnabled": "Whether the new lines filter selfmod sub-system is enabled or not.", "selfmodNewlinesIgnoredChannels": "The channels that will be ignored by the new lines sub-system", "selfmodNewlinesIgnoredRoles": "The roles that will be ignored by the new lines sub-system", - "selfmodNewlinesMaximum": "The maximum amount of new lines before WolfStar will start applying penalties", + "selfmodNewlinesMaximum": "The maximum amount of new lines before Skyra will start applying penalties", "selfmodReactionsBlocked": "The reactions that are blocked", "selfmodReactionsEnabled": "Whether the reactions filter selfmod sub-system is enabled or not.", "selfmodReactionsIgnoredChannels": "The channels that will be ignored by the reactions sub-system", "selfmodReactionsIgnoredRoles": "The roles that will be ignored by the reactions sub-system", "selfmodReactionsMaximum": "The maximum amount of reactions before I will start applying penalties", "selfmodReactionsAllowed": "The reactions that are allowed", - "validationChooseKey": "You cannot configure a group, please pick one of the following keys: {{keys, list(conjunction)}}.", + "socialSharedAchieveMessage": "- `{user}`: The user's mention.\n- `{user.id}`: The user's ID.\n- `{user.name}`: The user's name.\n- `{member.name}`: The member's display name.\n- `{user.tag}`: The user's tag (`username#NNNN`).\n- `{server}`: This server's name.\n- `{server.id}`: This server's ID.\n- `{points}`: The user's points in this server.\n- `{level}`: The user's level in this server.", + "socialAchieveRole": "The message I should use to congratulate people who get a new leveled role. The following will be replaced with their respective values:\n- `{role}`: The tag of the level role.\n- `{role.id}`: The ID of the level role.\n- `{role.name}`: The name of the level role.\n- `{role.position}`: The hierarchy position of the level role.\n- `{role.color}`: The color of the level role.\n$t(settings:socialSharedAchieveMessage)", + "socialAchieveLevel": "The message I should use to congratulate people who get a new level. The following will be replaced with their respective values:\n$t(settings:socialSharedAchieveMessage)", + "socialAchieveChannel": "The channel where I should send congratulation messages at. If not set, the message will be sent in the channel the user sent the message in.", + "socialAchieveMultiple": "The multiplier for level achievement messages, by default (1) it will send in any level change. The multiplier works so if you set it to `5` (for example), I will congratulate users only when they get level 5, 10, 15, etc.", + "socialEnabled": "Whether the social module should be enabled or not", + "socialIgnoredChannels": "The channels I should ignore when adding points.", + "socialIgnoredRoles": "The roles I should ignore when adding points.", + "socialMultiplier": "The multiplier to apply to the gain of points for users", + "suggestionsChannel": "The channel where suggestions will be sent.", + "suggestionsOnActionDm": "If this setting is enabled, Skyra will DM the suggestion's author every time it is updated.", + "suggestionsOnActionHideAuthor": "This setting allows you to update suggestions anonymously. It will substitute the updater's name with either `An administrator` or `A moderator`, according to their permission level.", + "suggestionsOnActionRePost": "If this setting is enabled, Skyra will repost the suggestion's message every time it is updated. If it is disabled, it will edit the original message.", + "validationChooseKey": "You cannot configure a group, please pick one of the following keys: {{keys, andList}}.", "validationMissingValue": "The value ``{{value}}`` was not set in the key **{{path}}**.", "validationDuplicatedValue": "The value for the key `{{path}}` was already set to ``{{value}}``!" } diff --git a/src/languages/en-US/system.json b/projects/bot/src/locales/en-US/system.json similarity index 50% rename from src/languages/en-US/system.json rename to projects/bot/src/locales/en-US/system.json index db341e7ab..85f00364a 100644 --- a/src/languages/en-US/system.json +++ b/projects/bot/src/locales/en-US/system.json @@ -1,5 +1,13 @@ { "discordAbortError": "I had a small network error when messaging Discord, please run this command again!", + "exceededLengthChooseOutput": "Choose one of the following options: {{output, orList}}", + "exceededLengthOutput": "**Output**:{{output}}", + "exceededLengthOutputConsole": "Sent the result to console.", + "exceededLengthOutputType": "**Type**:{{type}}", + "exceededLengthOutputTime": "{{time}}", + "exceededLengthOutputFile": "Sent the result as a file.", + "exceededLengthOutputHastebin": "Sent the result to hastebin: {{url}}", + "externalServerError": "The external service we use could not process our message. Please try again later.", "fetchBansFail": "Failed to fetch bans. Do I have the **{{ADMINISTRATOR, permissions}}** permission?", "helpTitles": { "aliases": "🖇️ | **Aliases**", @@ -21,5 +29,11 @@ "{{LOADING}} Tuning in to the right frequencies...", "{{LOADING}} Reticulating splines..." ], - "prefixReminder": "The prefix in this server is set to: `{{prefix}}`" + "messagePromptTimeout": "The prompt has timed out.", + "noResults": "I wasn't able to find any results for that query", + "parseError": "{{REDCROSS}} I failed to process the data I was given, sorry~!", + "prefixReminder": "The prefix in this server is set to: `{{prefix}}`", + "queryFail": "I am sorry, but the application could not resolve your request. Are you sure you wrote the name correctly?", + "textPromptAbortOptions": ["abort", "cancel", "stop"], + "reminderHeader": "⏲ Hey there! You asked to be reminded at {{timestamp}} about:" } diff --git a/projects/bot/src/main.ts b/projects/bot/src/main.ts new file mode 100644 index 000000000..16b0eb53e --- /dev/null +++ b/projects/bot/src/main.ts @@ -0,0 +1,49 @@ +import { createClient, loadAll } from '#lib/Client'; +import { envParseString, setup } from '@wolfstar/env-utilities'; +import { createBanner } from '@wolfstar/start-banner'; +import { bold } from 'colorette'; +import gradient from 'gradient-string'; +import { container } from 'wolfstar-shared'; + +setup(new URL('../src/.env', import.meta.url)); + +createClient(); +await loadAll(); + +console.log( + gradient.vice.multiline( + createBanner({ + logo: [ + String.raw` / `, + String.raw` ${bold('/╬')}▓ `, + String.raw` ${bold('/▓▓')}╢ `, + String.raw` [${bold('▓▓')}▓╣/ `, + String.raw` [╢╢╣▓ `, + String.raw` %,╚╣╣@\ `, + String.raw` #,╙▓▓▓\╙N `, + String.raw` '╙ \▓▓▓╖╙╦ `, + String.raw` \@╣▓╗╢% `, + String.raw` ▓╣╢╢] `, + String.raw` /╣▓${bold('▓▓')}] `, + String.raw` ╢${bold('▓▓/')} `, + String.raw` ▓${bold('╬/')} `, + String.raw` / ` + ], + name: [ + String.raw` ________ __ ___ ___ ___ _______ __ `, + String.raw` /" )|/"| / ")|" \/" |/" \ /""\ `, + String.raw`(: \___/ (: |/ / \ \ /|: | / \ `, + String.raw` \___ \ | __/ \\ \/ |_____/ ) /' /\ \ `, + String.raw` __/ \\ (// _ \ / / // / // __' \ `, + String.raw` /" \ :) |: | \ \ / / |: __ \ / / \\ \ `, + String.raw`(_______/ (__| \__)|___/ |__| \___)(___/ \___) ` + ], + extra: [ + ` Skyra ${envParseString('CLIENT_VERSION')} Gateway`, + ...container.stores.map((store) => `├─ Loaded ${store.size.toString().padEnd(3, ' ')} ${store.name}.`), + ` └ Redis : ${container.redis.options.host}:${container.redis.options.port}` + ] + }) + ) +); +console.log('Ready'); diff --git a/projects/bot/src/routes/commands.ts b/projects/bot/src/routes/commands.ts new file mode 100644 index 000000000..c5504bd73 --- /dev/null +++ b/projects/bot/src/routes/commands.ts @@ -0,0 +1,35 @@ +import { ratelimit } from '#lib/api/utils'; +import type { WolfCommand } from '#lib/structures'; +import { seconds } from '#utils/common'; +import { ApplyOptions } from '@sapphire/decorators'; +import type { Command } from '@sapphire/framework'; +import { ApiRequest, ApiResponse, methods, Route, RouteOptions } from '@sapphire/plugin-api'; +import type { TFunction } from 'i18next'; + +@ApplyOptions({ route: 'commands' }) +export class UserRoute extends Route { + @ratelimit(seconds(2), 2) + public [methods.GET](request: ApiRequest, response: ApiResponse) { + const { lang, category } = request.query; + const { i18n, stores } = this.container; + const language = i18n.getT((lang as string) ?? 'en-US'); + const commands = ( + category ? stores.get('commands').filter((cmd) => (cmd as WolfCommand).category === category) : stores.get('commands') + ).filter((cmd) => (cmd as WolfCommand).permissionLevel < 9); + + return response.json(commands.map(UserRoute.process.bind(null, language))); + } + + private static process(t: TFunction, cmd: Command) { + const command = cmd as WolfCommand; + return { + category: command.category, + description: t(command.description), + extendedHelp: t(command.detailedDescription, { replace: { prefix: process.env.CLIENT_PREFIX }, postProcess: 'helpUsagePostProcessor' }), + guarded: command.guarded, + name: command.name, + permissionLevel: command.permissionLevel, + preconditions: command.preconditions + }; + } +} diff --git a/src/routes/guilds/[guild]/index.get.ts b/projects/bot/src/routes/guilds/guild.ts similarity index 68% rename from src/routes/guilds/[guild]/index.get.ts rename to projects/bot/src/routes/guilds/guild.ts index 55562aefc..b15937a42 100644 --- a/src/routes/guilds/[guild]/index.get.ts +++ b/projects/bot/src/routes/guilds/guild.ts @@ -2,12 +2,14 @@ import { flattenGuild } from '#lib/api/ApiTransformers'; import { authenticated, canManage, ratelimit } from '#lib/api/utils'; import { api } from '#lib/discord/Api'; import { seconds } from '#utils/common'; -import { HttpCodes, Route } from '@sapphire/plugin-api'; +import { ApplyOptions } from '@sapphire/decorators'; +import { ApiRequest, ApiResponse, HttpCodes, methods, Route, RouteOptions } from '@sapphire/plugin-api'; +@ApplyOptions({ route: 'guilds/:guild' }) export class UserRoute extends Route { @authenticated() @ratelimit(seconds(5), 2, true) - public async run(request: Route.Request, response: Route.Response) { + public async [methods.GET](request: ApiRequest, response: ApiResponse) { const guildId = request.params.guild; const guild = this.container.client.guilds.cache.get(guildId); @@ -18,7 +20,7 @@ export class UserRoute extends Route { if (!(await canManage(guild, member))) return response.error(HttpCodes.Forbidden); - const emojis = await api().guilds.getEmojis(guildId); + const emojis = await api().guilds(guildId).emojis.get(); return response.json({ ...flattenGuild(guild), emojis }); } } diff --git a/src/routes/guilds/[guild]/channels.get.ts b/projects/bot/src/routes/guilds/guild/channels.ts similarity index 70% rename from src/routes/guilds/[guild]/channels.get.ts rename to projects/bot/src/routes/guilds/guild/channels.ts index dfcf9b7f8..a48ace921 100644 --- a/src/routes/guilds/[guild]/channels.get.ts +++ b/projects/bot/src/routes/guilds/guild/channels.ts @@ -1,12 +1,14 @@ import { flattenChannel } from '#lib/api/ApiTransformers'; import { authenticated, canManage, ratelimit } from '#lib/api/utils'; import { seconds } from '#utils/common'; -import { HttpCodes, Route } from '@sapphire/plugin-api'; +import { ApplyOptions } from '@sapphire/decorators'; +import { ApiRequest, ApiResponse, HttpCodes, methods, Route, RouteOptions } from '@sapphire/plugin-api'; +@ApplyOptions({ route: 'guilds/:guild/channels' }) export class UserRoute extends Route { @authenticated() @ratelimit(seconds(5), 2, true) - public async run(request: Route.Request, response: Route.Response) { + public async [methods.GET](request: ApiRequest, response: ApiResponse) { const guildId = request.params.guild; const guild = this.container.client.guilds.cache.get(guildId); diff --git a/src/routes/guilds/[guild]/channels/[channel].get.ts b/projects/bot/src/routes/guilds/guild/channels/channel.ts similarity index 73% rename from src/routes/guilds/[guild]/channels/[channel].get.ts rename to projects/bot/src/routes/guilds/guild/channels/channel.ts index 114c67a5e..bb6c5280d 100644 --- a/src/routes/guilds/[guild]/channels/[channel].get.ts +++ b/projects/bot/src/routes/guilds/guild/channels/channel.ts @@ -1,12 +1,14 @@ import { flattenChannel } from '#lib/api/ApiTransformers'; import { authenticated, canManage, ratelimit } from '#lib/api/utils'; import { seconds } from '#utils/common'; -import { HttpCodes, Route } from '@sapphire/plugin-api'; +import { ApplyOptions } from '@sapphire/decorators'; +import { ApiRequest, ApiResponse, HttpCodes, methods, Route, RouteOptions } from '@sapphire/plugin-api'; +@ApplyOptions({ route: 'guilds/:guild/channels/:channel' }) export class UserRoute extends Route { @authenticated() @ratelimit(seconds(5), 2, true) - public async run(request: Route.Request, response: Route.Response) { + public async [methods.GET](request: ApiRequest, response: ApiResponse) { const guildId = request.params.guild; const guild = this.container.client.guilds.cache.get(guildId); diff --git a/src/routes/guilds/[guild]/members/[member].get.ts b/projects/bot/src/routes/guilds/guild/members/member.ts similarity index 74% rename from src/routes/guilds/[guild]/members/[member].get.ts rename to projects/bot/src/routes/guilds/guild/members/member.ts index 887a10ea4..81b7ae836 100644 --- a/src/routes/guilds/[guild]/members/[member].get.ts +++ b/projects/bot/src/routes/guilds/guild/members/member.ts @@ -1,12 +1,14 @@ import { flattenMember } from '#lib/api/ApiTransformers'; import { authenticated, canManage, ratelimit } from '#lib/api/utils'; import { seconds } from '#utils/common'; -import { HttpCodes, Route } from '@sapphire/plugin-api'; +import { ApplyOptions } from '@sapphire/decorators'; +import { ApiRequest, ApiResponse, HttpCodes, methods, Route, RouteOptions } from '@sapphire/plugin-api'; +@ApplyOptions({ route: 'guilds/:guild/members/:member' }) export class UserRoute extends Route { @authenticated() @ratelimit(seconds(5), 2, true) - public async run(request: Route.Request, response: Route.Response) { + public async [methods.GET](request: ApiRequest, response: ApiResponse) { const guildId = request.params.guild; const guild = this.container.client.guilds.cache.get(guildId); diff --git a/src/routes/guilds/[guild]/roles.get.ts b/projects/bot/src/routes/guilds/guild/roles.ts similarity index 70% rename from src/routes/guilds/[guild]/roles.get.ts rename to projects/bot/src/routes/guilds/guild/roles.ts index ea6ab252c..aecb94ad7 100644 --- a/src/routes/guilds/[guild]/roles.get.ts +++ b/projects/bot/src/routes/guilds/guild/roles.ts @@ -1,12 +1,14 @@ import { flattenRole } from '#lib/api/ApiTransformers'; import { authenticated, canManage, ratelimit } from '#lib/api/utils'; import { seconds } from '#utils/common'; -import { HttpCodes, Route } from '@sapphire/plugin-api'; +import { ApplyOptions } from '@sapphire/decorators'; +import { ApiRequest, ApiResponse, HttpCodes, methods, Route, RouteOptions } from '@sapphire/plugin-api'; +@ApplyOptions({ route: 'guilds/:guild/roles' }) export class UserRoute extends Route { @authenticated() @ratelimit(seconds(5), 2, true) - public async run(request: Route.Request, response: Route.Response) { + public async [methods.GET](request: ApiRequest, response: ApiResponse) { const guildId = request.params.guild; const guild = this.container.client.guilds.cache.get(guildId); diff --git a/src/routes/guilds/[guild]/roles/[role].get.ts b/projects/bot/src/routes/guilds/guild/roles/role.ts similarity index 73% rename from src/routes/guilds/[guild]/roles/[role].get.ts rename to projects/bot/src/routes/guilds/guild/roles/role.ts index 7aa08ae2b..6282393dd 100644 --- a/src/routes/guilds/[guild]/roles/[role].get.ts +++ b/projects/bot/src/routes/guilds/guild/roles/role.ts @@ -1,12 +1,14 @@ import { flattenRole } from '#lib/api/ApiTransformers'; import { authenticated, canManage, ratelimit } from '#lib/api/utils'; import { seconds } from '#utils/common'; -import { HttpCodes, Route } from '@sapphire/plugin-api'; +import { ApplyOptions } from '@sapphire/decorators'; +import { ApiRequest, ApiResponse, HttpCodes, methods, Route, RouteOptions } from '@sapphire/plugin-api'; +@ApplyOptions({ route: 'guilds/:guild/roles/:role' }) export class UserRoute extends Route { @authenticated() @ratelimit(seconds(5), 2, true) - public async run(request: Route.Request, response: Route.Response) { + public async [methods.GET](request: ApiRequest, response: ApiResponse) { const guildId = request.params.guild; const guild = this.container.client.guilds.cache.get(guildId); diff --git a/src/routes/guilds/[guild]/settings.patch.ts b/projects/bot/src/routes/guilds/guild/settings.ts similarity index 50% rename from src/routes/guilds/[guild]/settings.patch.ts rename to projects/bot/src/routes/guilds/guild/settings.ts index 90dc09ac0..afd2b9972 100644 --- a/src/routes/guilds/[guild]/settings.patch.ts +++ b/projects/bot/src/routes/guilds/guild/settings.ts @@ -1,25 +1,35 @@ import { authenticated, canManage, ratelimit } from '#lib/api/utils'; -import { - getConfigurableKeys, - isSchemaKey, - serializeSettings, - writeSettingsTransaction, - type GuildDataValue, - type ReadonlyGuildData, - type SchemaDataKey, - type Serializer -} from '#lib/database'; -import { getT } from '#lib/i18n'; +import { configurableKeys, GuildEntity, isSchemaKey, readSettings, SerializerUpdateContext, writeSettings } from '#lib/database'; import { seconds } from '#utils/common'; import { cast } from '#utils/util'; -import { HttpCodes, Route, type MimeType } from '@sapphire/plugin-api'; +import { ApplyOptions } from '@sapphire/decorators'; +import { ApiRequest, ApiResponse, HttpCodes, methods, Route, RouteOptions } from '@sapphire/plugin-api'; import type { Guild } from 'discord.js'; +@ApplyOptions({ name: 'guildSettings', route: 'guilds/:guild/settings' }) export class UserRoute extends Route { + private readonly kBlockList: string[] = ['commandUses']; + + @authenticated() + @ratelimit(seconds(5), 2, true) + public async [methods.GET](request: ApiRequest, response: ApiResponse) { + const guildId = request.params.guild; + + const guild = this.container.client.guilds.cache.get(guildId); + if (!guild) return response.error(HttpCodes.BadRequest); + + const member = await guild.members.fetch(request.auth!.id).catch(() => null); + if (!member) return response.error(HttpCodes.BadRequest); + + if (!(await canManage(guild, member))) return response.error(HttpCodes.Forbidden); + + return readSettings(guild, (settings) => response.json(settings)); + } + @authenticated() @ratelimit(seconds(1), 2, true) - public async run(request: Route.Request, response: Route.Response) { - const requestBody = (await request.readBodyJson()) as { guild_id: string; data: [SchemaDataKey, GuildDataValue][] | undefined }; + public async [methods.PATCH](request: ApiRequest, response: ApiResponse) { + const requestBody = request.body as { guild_id: string; data: [string, unknown][] | undefined }; if (!requestBody.guild_id || !Array.isArray(requestBody.data) || requestBody.guild_id !== request.params.guild) { return response.status(HttpCodes.BadRequest).json(['Invalid body.']); @@ -34,34 +44,33 @@ export class UserRoute extends Route { if (!(await canManage(guild, member))) return response.error(HttpCodes.Forbidden); const entries = requestBody.data; + if (entries.some(([key]) => this.kBlockList.includes(key))) return response.error(HttpCodes.BadRequest); + try { - using trx = await writeSettingsTransaction(guild); - const data = await this.validateAll(trx.settings, guild, entries); - const settingsData = Object.fromEntries(data); + const settings = await writeSettings(guild, async (settings) => { + const pairs = await this.validateAll(settings, guild, entries); - await trx.write(settingsData).submitWithAudit(request.auth!.id); + for (const [key, value] of pairs) { + Reflect.set(settings, key, value); + } - return this.sendSettings(response, trx.settings); + return settings.toJSON(); + }); + + return response.status(HttpCodes.OK).json(settings); } catch (errors) { return response.status(HttpCodes.BadRequest).json(errors); } } - private sendSettings(response: Route.Response, settings: ReadonlyGuildData) { - return response - .status(HttpCodes.OK) - .setContentType('application/json' satisfies MimeType) - .end(serializeSettings(settings)); - } - - private async validate(key: SchemaDataKey, value: unknown, context: PartialSerializerUpdateContext) { - const entry = getConfigurableKeys().get(key); + private async validate(key: string, value: unknown, context: PartialSerializerUpdateContext) { + const entry = configurableKeys.get(key); if (!entry || !isSchemaKey(entry)) throw `${key}: The key ${key} does not exist in the current schema.`; try { // If null is passed, reset to default: if (value === null) return [entry.property, entry.default]; - const ctx = { ...context, entry } as Serializer.UpdateContext; + const ctx = { ...context, entry }; const result = await (entry.array ? this.validateArray(value, ctx) : entry.serializer.isValid(value as any, ctx)); if (!result) throw 'The value is not valid.'; @@ -72,18 +81,18 @@ export class UserRoute extends Route { } } - private async validateArray(value: any, ctx: Serializer.UpdateContext) { + private async validateArray(value: any, ctx: SerializerUpdateContext) { if (!Array.isArray(value)) throw new Error('Expected an array.'); const { serializer } = ctx.entry; return Promise.all(value.map((value) => serializer.isValid(value, ctx))); } - private async validateAll(entity: ReadonlyGuildData, guild: Guild, pairs: readonly [SchemaDataKey, GuildDataValue][]) { + private async validateAll(entity: GuildEntity, guild: Guild, pairs: readonly [string, unknown][]) { const context: PartialSerializerUpdateContext = { entity, guild, - t: getT(entity.language) + t: entity.getLanguage() }; const errors: string[] = []; @@ -97,10 +106,10 @@ export class UserRoute extends Route { }); const results = await Promise.all(promises); - if (errors.length === 0) return cast(results); + if (errors.length === 0) return cast(results); throw errors; } } -type PartialSerializerUpdateContext = Omit; +type PartialSerializerUpdateContext = Omit; diff --git a/projects/bot/src/routes/languages.ts b/projects/bot/src/routes/languages.ts new file mode 100644 index 000000000..17ae24bfe --- /dev/null +++ b/projects/bot/src/routes/languages.ts @@ -0,0 +1,12 @@ +import { ratelimit } from '#lib/api/utils'; +import { seconds } from '#utils/common'; +import { ApplyOptions } from '@sapphire/decorators'; +import { ApiRequest, ApiResponse, methods, Route, RouteOptions } from '@sapphire/plugin-api'; + +@ApplyOptions({ route: 'languages' }) +export class UserRoute extends Route { + @ratelimit(seconds(2), 2) + public [methods.GET](_: ApiRequest, response: ApiResponse) { + return response.json([...this.container.i18n.languages.keys()]); + } +} diff --git a/projects/bot/src/routes/main.ts b/projects/bot/src/routes/main.ts new file mode 100644 index 000000000..e4c7ae8e3 --- /dev/null +++ b/projects/bot/src/routes/main.ts @@ -0,0 +1,15 @@ +import { authenticated } from '#lib/api/utils'; +import { ApplyOptions } from '@sapphire/decorators'; +import { ApiRequest, ApiResponse, methods, Route, RouteOptions } from '@sapphire/plugin-api'; + +@ApplyOptions({ route: '' }) +export class UserRoute extends Route { + public [methods.GET](_request: ApiRequest, response: ApiResponse) { + response.json({ message: 'Hello World' }); + } + + @authenticated() + public [methods.POST](_request: ApiRequest, response: ApiResponse) { + response.json({ message: 'Hello World' }); + } +} diff --git a/src/routes/oauth/user.post.ts b/projects/bot/src/routes/oauth/oauthUser.ts similarity index 78% rename from src/routes/oauth/user.post.ts rename to projects/bot/src/routes/oauth/oauthUser.ts index bafcb8372..549ce7eba 100644 --- a/src/routes/oauth/user.post.ts +++ b/projects/bot/src/routes/oauth/oauthUser.ts @@ -1,16 +1,18 @@ import { authenticated, ratelimit } from '#lib/api/utils'; import { minutes } from '#utils/common'; -import { FetchResultTypes, fetch } from '@sapphire/fetch'; -import { HttpCodes, Route, type MimeType } from '@sapphire/plugin-api'; +import { ApplyOptions } from '@sapphire/decorators'; +import { fetch, FetchResultTypes } from '@sapphire/fetch'; +import { ApiRequest, ApiResponse, HttpCodes, methods, MimeTypes, Route, RouteOptions } from '@sapphire/plugin-api'; import { Time } from '@sapphire/time-utilities'; -import { OAuth2Routes, type RESTPostOAuth2AccessTokenResult } from 'discord.js'; +import { OAuth2Routes, RESTPostOAuth2AccessTokenResult } from 'discord-api-types/v9'; import { stringify } from 'node:querystring'; +@ApplyOptions({ route: 'oauth/user' }) export class UserRoute extends Route { @authenticated() @ratelimit(minutes(5), 2, true) - public async run(request: Route.Request, response: Route.Response) { - const requestBody = (await request.readBodyJson()) as Record; + public async [methods.POST](request: ApiRequest, response: ApiResponse) { + const requestBody = request.body as Record; if (typeof requestBody.action !== 'string') { return response.badRequest(); } @@ -65,7 +67,7 @@ export class UserRoute extends Route { scope: server.auth!.scopes }), headers: { - 'Content-Type': 'application/x-www-form-urlencoded' satisfies MimeType + 'Content-Type': MimeTypes.ApplicationFormUrlEncoded } }, FetchResultTypes.JSON diff --git a/src/routes/users/@me.get.ts b/projects/bot/src/routes/users/user.ts similarity index 62% rename from src/routes/users/@me.get.ts rename to projects/bot/src/routes/users/user.ts index d7b1d99b6..f51c7971c 100644 --- a/src/routes/users/@me.get.ts +++ b/projects/bot/src/routes/users/user.ts @@ -1,12 +1,14 @@ -import { flattenGuild, flattenUser, type FlattenedGuild } from '#lib/api/ApiTransformers'; +import { FlattenedGuild, flattenGuild, flattenUser } from '#lib/api/ApiTransformers'; import { authenticated, ratelimit } from '#lib/api/utils'; import { seconds } from '#utils/common'; -import { HttpCodes, Route } from '@sapphire/plugin-api'; +import { ApplyOptions } from '@sapphire/decorators'; +import { ApiRequest, ApiResponse, HttpCodes, methods, Route, RouteOptions } from '@sapphire/plugin-api'; +@ApplyOptions({ route: 'users/@me' }) export class UserRoute extends Route { @authenticated() @ratelimit(seconds(5), 2, true) - public async run(request: Route.Request, response: Route.Response) { + public async [methods.GET](request: ApiRequest, response: ApiResponse) { const { client } = this.container; const user = await client.users.fetch(request.auth!.id).catch(() => null); if (user === null) return response.error(HttpCodes.InternalServerError); diff --git a/projects/bot/src/routes/users/user/settings.ts b/projects/bot/src/routes/users/user/settings.ts new file mode 100644 index 000000000..0ef0cf493 --- /dev/null +++ b/projects/bot/src/routes/users/user/settings.ts @@ -0,0 +1,55 @@ +import { authenticated, ratelimit } from '#lib/api/utils'; +import { seconds } from '#utils/common'; +import { ApplyOptions } from '@sapphire/decorators'; +import { ApiRequest, ApiResponse, HttpCodes, methods, Route, RouteOptions } from '@sapphire/plugin-api'; +import { inspect } from 'node:util'; + +interface BodyData { + darkTheme?: boolean; + moderationDM?: boolean; +} + +@ApplyOptions({ name: 'userSettings', route: 'users/@me/settings' }) +export class UserRoute extends Route { + @authenticated() + @ratelimit(seconds(1), 5, true) + public async [methods.GET](request: ApiRequest, response: ApiResponse) { + const { users } = this.container.db; + const user = await users.ensureProfile(request.auth!.id); + + return response.json(user); + } + + @authenticated() + @ratelimit(seconds(1), 2, true) + public async [methods.POST](request: ApiRequest, response: ApiResponse) { + const requestBody = request.body as { data: BodyData }; + + const { users } = this.container.db; + const userId = request.auth!.id; + + try { + const newSettings = await users.lock([userId], async (id) => { + const user = await users.ensureProfile(id); + + if (requestBody.data.darkTheme) { + if (typeof requestBody.data.darkTheme !== 'boolean') return response.badRequest('darkTheme must be a boolean'); + user.profile.darkTheme = requestBody.data.darkTheme; + } + + if (requestBody.data.moderationDM) { + if (typeof requestBody.data.moderationDM !== 'boolean') return response.badRequest('moderationDM must be a boolean'); + user.moderationDM = requestBody.data.moderationDM; + } + + return user.save(); + }); + + return response.json({ newSettings }); + } catch (errors) { + this.container.logger.error(`[${userId}] failed user settings update:\n${inspect(errors)}`); + + return response.error(HttpCodes.InternalServerError); + } + } +} diff --git a/projects/bot/src/tasks/moderation/moderationEndAddRole.ts b/projects/bot/src/tasks/moderation/moderationEndAddRole.ts new file mode 100644 index 000000000..bef99c19a --- /dev/null +++ b/projects/bot/src/tasks/moderation/moderationEndAddRole.ts @@ -0,0 +1,24 @@ +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { ModerationData, ModerationTask } from '#lib/moderation'; +import { getSecurity } from '#utils/functions'; +import { fetchT } from '@sapphire/plugin-i18next'; +import { Guild, Permissions, Role } from 'discord.js'; + +export class UserModerationTask extends ModerationTask { + protected async handle(guild: Guild, data: ModerationData<{ role: Role }>) { + const me = guild.me === null ? await guild.members.fetch(process.env.CLIENT_ID) : guild.me; + if (!me.permissions.has(Permissions.FLAGS.MANAGE_ROLES)) return null; + + const t = await fetchT(guild); + await getSecurity(guild).actions.unAddRole( + { + moderatorId: process.env.CLIENT_ID, + userId: data.userID, + reason: `[MODERATION] Role removed after ${t(LanguageKeys.Globals.DurationValue, { value: data.duration })}` + }, + data.extraData.role, + await this.getTargetDM(guild, await this.container.client.users.fetch(data.userID)) + ); + return null; + } +} diff --git a/projects/bot/src/tasks/moderation/moderationEndBan.ts b/projects/bot/src/tasks/moderation/moderationEndBan.ts new file mode 100644 index 000000000..e88db8595 --- /dev/null +++ b/projects/bot/src/tasks/moderation/moderationEndBan.ts @@ -0,0 +1,23 @@ +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { ModerationData, ModerationTask } from '#lib/moderation'; +import { getSecurity } from '#utils/functions'; +import { fetchT } from '@sapphire/plugin-i18next'; +import { Guild, Permissions } from 'discord.js'; + +export class UserModerationTask extends ModerationTask { + protected async handle(guild: Guild, data: ModerationData) { + const me = guild.me === null ? await guild.members.fetch(process.env.CLIENT_ID) : guild.me; + if (!me.permissions.has(Permissions.FLAGS.BAN_MEMBERS)) return null; + + const t = await fetchT(guild); + await getSecurity(guild).actions.unBan( + { + moderatorId: process.env.CLIENT_ID, + userId: data.userID, + reason: `[MODERATION] Ban released after ${t(LanguageKeys.Globals.DurationValue, { value: data.duration })}` + }, + await this.getTargetDM(guild, await this.container.client.users.fetch(data.userID)) + ); + return null; + } +} diff --git a/projects/bot/src/tasks/moderation/moderationEndMute.ts b/projects/bot/src/tasks/moderation/moderationEndMute.ts new file mode 100644 index 000000000..b7bf78967 --- /dev/null +++ b/projects/bot/src/tasks/moderation/moderationEndMute.ts @@ -0,0 +1,20 @@ +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { ModerationData, ModerationTask } from '#lib/moderation'; +import { getSecurity } from '#utils/functions'; +import { fetchT } from '@sapphire/plugin-i18next'; +import type { Guild } from 'discord.js'; + +export class UserModerationTask extends ModerationTask { + protected async handle(guild: Guild, data: ModerationData) { + const t = await fetchT(guild); + await getSecurity(guild).actions.unMute( + { + moderatorId: process.env.CLIENT_ID, + userId: data.userID, + reason: `[MODERATION] Mute released after ${t(LanguageKeys.Globals.DurationValue, { value: data.duration })}` + }, + await this.getTargetDM(guild, await this.container.client.users.fetch(data.userID)) + ); + return null; + } +} diff --git a/projects/bot/src/tasks/moderation/moderationEndRemoveRole.ts b/projects/bot/src/tasks/moderation/moderationEndRemoveRole.ts new file mode 100644 index 000000000..9b2de499c --- /dev/null +++ b/projects/bot/src/tasks/moderation/moderationEndRemoveRole.ts @@ -0,0 +1,24 @@ +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { ModerationData, ModerationTask } from '#lib/moderation'; +import { getSecurity } from '#utils/functions'; +import { fetchT } from '@sapphire/plugin-i18next'; +import { Guild, Permissions, Role } from 'discord.js'; + +export class UserModerationTask extends ModerationTask { + protected async handle(guild: Guild, data: ModerationData<{ role: Role }>) { + const me = guild.me === null ? await guild.members.fetch(process.env.CLIENT_ID) : guild.me; + if (!me.permissions.has(Permissions.FLAGS.MANAGE_ROLES)) return null; + + const t = await fetchT(guild); + await getSecurity(guild).actions.unRemoveRole( + { + moderatorId: process.env.CLIENT_ID, + userId: data.userID, + reason: `[MODERATION] Role re-added after ${t(LanguageKeys.Globals.DurationValue, { value: data.duration })}` + }, + data.extraData.role, + await this.getTargetDM(guild, await this.container.client.users.fetch(data.userID)) + ); + return null; + } +} diff --git a/projects/bot/src/tasks/moderation/moderationEndSetNickname.ts b/projects/bot/src/tasks/moderation/moderationEndSetNickname.ts new file mode 100644 index 000000000..36d997fa5 --- /dev/null +++ b/projects/bot/src/tasks/moderation/moderationEndSetNickname.ts @@ -0,0 +1,24 @@ +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { ModerationData, ModerationTask } from '#lib/moderation'; +import { getSecurity } from '#utils/functions'; +import { fetchT } from '@sapphire/plugin-i18next'; +import { Guild, Permissions } from 'discord.js'; + +export class UserModerationTask extends ModerationTask { + protected async handle(guild: Guild, data: ModerationData<{ oldName: string }>) { + const me = guild.me === null ? await guild.members.fetch(process.env.CLIENT_ID) : guild.me; + if (!me.permissions.has(Permissions.FLAGS.MANAGE_NICKNAMES)) return null; + + const t = await fetchT(guild); + await getSecurity(guild).actions.unSetNickname( + { + moderatorId: process.env.CLIENT_ID, + userId: data.userID, + reason: `[MODERATION] Nickname reverted after ${t(LanguageKeys.Globals.DurationValue, { value: data.duration })}` + }, + data.extraData.oldName, + await this.getTargetDM(guild, await this.container.client.users.fetch(data.userID)) + ); + return null; + } +} diff --git a/projects/bot/src/tasks/moderation/moderationEndVoiceMute.ts b/projects/bot/src/tasks/moderation/moderationEndVoiceMute.ts new file mode 100644 index 000000000..69269dbce --- /dev/null +++ b/projects/bot/src/tasks/moderation/moderationEndVoiceMute.ts @@ -0,0 +1,23 @@ +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { ModerationData, ModerationTask } from '#lib/moderation'; +import { getSecurity } from '#utils/functions'; +import { fetchT } from '@sapphire/plugin-i18next'; +import { Guild, Permissions } from 'discord.js'; + +export class UserModerationTask extends ModerationTask { + protected async handle(guild: Guild, data: ModerationData) { + const me = guild.me === null ? await guild.members.fetch(process.env.CLIENT_ID) : guild.me; + if (!me.permissions.has(Permissions.FLAGS.MUTE_MEMBERS)) return null; + + const t = await fetchT(guild); + await getSecurity(guild).actions.unVoiceMute( + { + moderatorId: process.env.CLIENT_ID, + userId: data.userID, + reason: `[MODERATION] Voice Mute released after ${t(LanguageKeys.Globals.DurationValue, { value: data.duration })}` + }, + await this.getTargetDM(guild, await this.container.client.users.fetch(data.userID)) + ); + return null; + } +} diff --git a/projects/bot/src/tasks/moderation/moderationEndWarning.ts b/projects/bot/src/tasks/moderation/moderationEndWarning.ts new file mode 100644 index 000000000..579500d63 --- /dev/null +++ b/projects/bot/src/tasks/moderation/moderationEndWarning.ts @@ -0,0 +1,24 @@ +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { ModerationData, ModerationTask } from '#lib/moderation'; +import { getSecurity } from '#utils/functions'; +import { fetchT } from '@sapphire/plugin-i18next'; +import { Guild, Permissions } from 'discord.js'; + +export class UserModerationTask extends ModerationTask { + protected async handle(guild: Guild, data: ModerationData) { + const me = guild.me === null ? await guild.members.fetch(process.env.CLIENT_ID) : guild.me; + if (!me.permissions.has(Permissions.FLAGS.BAN_MEMBERS)) return null; + + const t = await fetchT(guild); + await getSecurity(guild).actions.unWarning( + { + moderatorId: process.env.CLIENT_ID, + userId: data.userID, + reason: `[MODERATION] Warning released after ${t(LanguageKeys.Globals.DurationValue, { value: data.duration })}` + }, + data.caseID, + await this.getTargetDM(guild, await this.container.client.users.fetch(data.userID)) + ); + return null; + } +} diff --git a/src/tasks/poststats.ts b/projects/bot/src/tasks/poststats.ts similarity index 74% rename from src/tasks/poststats.ts rename to projects/bot/src/tasks/poststats.ts index 549730991..3ff0d195f 100644 --- a/src/tasks/poststats.ts +++ b/projects/bot/src/tasks/poststats.ts @@ -1,18 +1,19 @@ -import { ResponseType, Task, type PartialResponseValue } from '#lib/schedule'; -import { Events } from '#lib/types'; -import { FetchResultTypes, QueryError, fetch } from '@sapphire/fetch'; -import type { MimeType } from '@sapphire/plugin-api'; +import { ResponseType, Task, type PartialResponseValue } from '#lib/database'; +import { Events } from '#lib/types/Enums'; +import { fetch, FetchResultTypes, type QueryError } from '@sapphire/fetch'; +import { MimeTypes } from '@sapphire/plugin-api'; import { blueBright, green, red } from 'colorette'; -import { Status } from 'discord.js'; +import { Constants } from 'discord.js'; const header = blueBright('[POST STATS ]'); enum Lists { + BotListSpace = 'botlist.space', Discords = 'discords.com', DiscordBotList = 'discordbotlist.com', TopGG = 'top.gg', DiscordBotsGG = 'discord.bots.gg', - VoidBots = 'voidbots.net' + BotsOnDiscord = 'bots.ondiscord.xyz' } export class UserTask extends Task { @@ -20,7 +21,7 @@ export class UserTask extends Task { const { client, logger } = this.container; // If the websocket isn't ready, delay the execution by 30 seconds: - if (client.ws.status !== Status.Ready) { + if (client.ws.status !== Constants.Status.READY) { return { type: ResponseType.Delay, value: 30000 }; } @@ -59,10 +60,16 @@ export class UserTask extends Task { Lists.DiscordBotList ), this.query( - `https://api.voidbots.net/bot/stats/${process.env.CLIENT_ID}`, + `https://bots.ondiscord.xyz/bot-api/bots/${process.env.CLIENT_ID}/guilds`, + `{"guildCount":${guilds}}`, + process.env.BOTS_ON_DISCORD_TOKEN, + Lists.BotsOnDiscord + ), + this.query( + `https://api.discordlist.space/v1/bots/${process.env.CLIENT_ID}`, `{"server_count":${guilds}}`, - process.env.VOID_BOTS_TOKEN, - Lists.VoidBots + process.env.BOTLIST_SPACE_TOKEN, + Lists.BotListSpace ) ]) ).filter((value) => value !== null); @@ -78,15 +85,14 @@ export class UserTask extends Task { url, { body, - headers: { 'content-type': 'application/json' satisfies MimeType, authorization: token }, + headers: { 'content-type': MimeTypes.ApplicationJson, authorization: token }, method: 'POST' }, FetchResultTypes.Result ); return green(list); } catch (error) { - const message = String(error instanceof Error ? (error instanceof QueryError ? error.code : error.message) : error); - return `${red(list)} [${red(message)}]`; + return `${red(list)} [${red((error as QueryError).code.toString())}]`; } } diff --git a/projects/bot/src/tasks/reminder.ts b/projects/bot/src/tasks/reminder.ts new file mode 100644 index 000000000..96432e6ee --- /dev/null +++ b/projects/bot/src/tasks/reminder.ts @@ -0,0 +1,31 @@ +import { ResponseType, Task, type PartialResponseValue } from '#lib/database'; +import { LanguageKeys } from '#lib/i18n/languageKeys'; +import { resolveOnErrorCodes } from '#utils/common'; +import { time, TimestampStyles } from '@discordjs/builders'; +import { RESTJSONErrorCodes } from 'discord-api-types/v9'; +import i18next from 'i18next'; + +export class UserTask extends Task { + public async run(data: ReminderTaskData): Promise { + // Fetch the user to send the message to + const user = await resolveOnErrorCodes(this.container.client.users.fetch(data.user), RESTJSONErrorCodes.UnknownUser); + + if (user) { + const timestamp = time(new Date(), TimestampStyles.ShortDateTime); + const reminderHeader = i18next.t(LanguageKeys.System.ReminderHeader, { timestamp }); + + await resolveOnErrorCodes( + // + user.send(`${reminderHeader}\n*${data.content}*`), + RESTJSONErrorCodes.CannotSendMessagesToThisUser + ); + } + + return { type: ResponseType.Finished }; + } +} + +interface ReminderTaskData { + user: string; + content: string; +} diff --git a/projects/bot/src/tsconfig.json b/projects/bot/src/tsconfig.json new file mode 100644 index 000000000..aea036c8f --- /dev/null +++ b/projects/bot/src/tsconfig.json @@ -0,0 +1,18 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "allowJs": true, + "outDir": "../dist", + "rootDir": ".", + "baseUrl": ".", + "paths": { + "#utils/*": ["lib/util/*"], + "#lib/*": ["lib/*"], + "#languages": ["locales/index"], + "#root/*": ["*"] + }, + "composite": true + }, + "include": [".", "./**/*.json"], + "exclude": ["./tsconfig.json"] +} diff --git a/tests/lib/CommandMatcher.test.ts b/projects/bot/tests/lib/CommandMatcher.test.ts similarity index 100% rename from tests/lib/CommandMatcher.test.ts rename to projects/bot/tests/lib/CommandMatcher.test.ts diff --git a/tests/lib/RegexCreator.test.ts b/projects/bot/tests/lib/RegexCreator.test.ts similarity index 100% rename from tests/lib/RegexCreator.test.ts rename to projects/bot/tests/lib/RegexCreator.test.ts diff --git a/tests/lib/bits.test.ts b/projects/bot/tests/lib/bits.test.ts similarity index 100% rename from tests/lib/bits.test.ts rename to projects/bot/tests/lib/bits.test.ts diff --git a/tests/lib/database/settings/functions.test.ts b/projects/bot/tests/lib/database/settings/functions.test.ts similarity index 100% rename from tests/lib/database/settings/functions.test.ts rename to projects/bot/tests/lib/database/settings/functions.test.ts diff --git a/tests/lib/database/settings/structures/AuditLogEnvelope.test.ts b/projects/bot/tests/lib/database/settings/structures/AuditLogEnvelope.test.ts similarity index 100% rename from tests/lib/database/settings/structures/AuditLogEnvelope.test.ts rename to projects/bot/tests/lib/database/settings/structures/AuditLogEnvelope.test.ts diff --git a/tests/lib/database/settings/structures/AuditLogManager.test.ts b/projects/bot/tests/lib/database/settings/structures/AuditLogManager.test.ts similarity index 100% rename from tests/lib/database/settings/structures/AuditLogManager.test.ts rename to projects/bot/tests/lib/database/settings/structures/AuditLogManager.test.ts diff --git a/tests/lib/database/settings/structures/PermissionNodeManager.test.ts b/projects/bot/tests/lib/database/settings/structures/PermissionNodeManager.test.ts similarity index 100% rename from tests/lib/database/settings/structures/PermissionNodeManager.test.ts rename to projects/bot/tests/lib/database/settings/structures/PermissionNodeManager.test.ts diff --git a/tests/lib/formatters.test.ts b/projects/bot/tests/lib/formatters.test.ts similarity index 100% rename from tests/lib/formatters.test.ts rename to projects/bot/tests/lib/formatters.test.ts diff --git a/tests/lib/i18n/LanguageHelp.test.ts b/projects/bot/tests/lib/i18n/LanguageHelp.test.ts similarity index 100% rename from tests/lib/i18n/LanguageHelp.test.ts rename to projects/bot/tests/lib/i18n/LanguageHelp.test.ts diff --git a/tests/lib/i18n/translate.test.ts b/projects/bot/tests/lib/i18n/translate.test.ts similarity index 100% rename from tests/lib/i18n/translate.test.ts rename to projects/bot/tests/lib/i18n/translate.test.ts diff --git a/tests/lib/listeners/commands/commandLogShared.test.ts b/projects/bot/tests/lib/listeners/commands/commandLogShared.test.ts similarity index 100% rename from tests/lib/listeners/commands/commandLogShared.test.ts rename to projects/bot/tests/lib/listeners/commands/commandLogShared.test.ts diff --git a/tests/lib/moderation/workers/WorkerHandler.test.ts b/projects/bot/tests/lib/moderation/workers/WorkerHandler.test.ts similarity index 100% rename from tests/lib/moderation/workers/WorkerHandler.test.ts rename to projects/bot/tests/lib/moderation/workers/WorkerHandler.test.ts diff --git a/tests/lib/moderation/workers/WorkerManager.test.ts b/projects/bot/tests/lib/moderation/workers/WorkerManager.test.ts similarity index 100% rename from tests/lib/moderation/workers/WorkerManager.test.ts rename to projects/bot/tests/lib/moderation/workers/WorkerManager.test.ts diff --git a/tests/lib/moderation/workers/WorkerResponseHandler.test.ts b/projects/bot/tests/lib/moderation/workers/WorkerResponseHandler.test.ts similarity index 100% rename from tests/lib/moderation/workers/WorkerResponseHandler.test.ts rename to projects/bot/tests/lib/moderation/workers/WorkerResponseHandler.test.ts diff --git a/tests/lib/util.test.ts b/projects/bot/tests/lib/util.test.ts similarity index 100% rename from tests/lib/util.test.ts rename to projects/bot/tests/lib/util.test.ts diff --git a/tests/lib/util/common/comparators.test.ts b/projects/bot/tests/lib/util/common/comparators.test.ts similarity index 100% rename from tests/lib/util/common/comparators.test.ts rename to projects/bot/tests/lib/util/common/comparators.test.ts diff --git a/tests/lib/util/common/times.test.ts b/projects/bot/tests/lib/util/common/times.test.ts similarity index 100% rename from tests/lib/util/common/times.test.ts rename to projects/bot/tests/lib/util/common/times.test.ts diff --git a/projects/bot/tests/lib/util/constants.test.ts b/projects/bot/tests/lib/util/constants.test.ts new file mode 100644 index 000000000..7ae31a2b2 --- /dev/null +++ b/projects/bot/tests/lib/util/constants.test.ts @@ -0,0 +1,25 @@ +import * as utilConstants from '#utils/constants'; + +describe('Util Constants', () => { + describe('helpUsagePostProcessor', () => { + test('GIVEN value matching key THEN returns empty string', () => { + // @ts-expect-error i18next is weird and its types are different from what we actually see in usage + expect(utilConstants.helpUsagePostProcessor.process('yarnExtended.extendedHelp', ['yarnExtended.extendedHelp'], {}, '')).toEqual(''); + }); + + test('GIVEN value not matching key THEN returns value', () => { + // @ts-expect-error i18next is weird and its types are different from what we actually see in usage + expect(utilConstants.helpUsagePostProcessor.process('This is so much help', ['yarnExtended.extendedHelp'], {}, '')).toEqual( + 'This is so much help' + ); + }); + + test('GIVEN check on name THEN returns helpUsagePostProcessor', () => { + expect(utilConstants.helpUsagePostProcessor.name).toEqual('helpUsagePostProcessor'); + }); + + test('GIVEN check on type THEN returns postProcessor', () => { + expect(utilConstants.helpUsagePostProcessor.type).toEqual('postProcessor'); + }); + }); +}); diff --git a/tests/lib/util/formatters.test.ts b/projects/bot/tests/lib/util/formatters.test.ts similarity index 100% rename from tests/lib/util/formatters.test.ts rename to projects/bot/tests/lib/util/formatters.test.ts diff --git a/tests/lib/util/functions/auditLogEmbeds.test.ts b/projects/bot/tests/lib/util/functions/auditLogEmbeds.test.ts similarity index 100% rename from tests/lib/util/functions/auditLogEmbeds.test.ts rename to projects/bot/tests/lib/util/functions/auditLogEmbeds.test.ts diff --git a/projects/bot/tests/lib/util/functions/emojis/areEmojisEqual.test.ts b/projects/bot/tests/lib/util/functions/emojis/areEmojisEqual.test.ts new file mode 100644 index 000000000..5f89793d0 --- /dev/null +++ b/projects/bot/tests/lib/util/functions/emojis/areEmojisEqual.test.ts @@ -0,0 +1,24 @@ +import { encodedBunnyTwemoji, serializedAnimatedSkyraGlasses, serializedStaticSkyra } from '#mocks/constants'; +import { areEmojisEqual, SerializedEmoji } from '#utils/functions/emojis'; + +describe('areEmojisEqual', () => { + test('GIVEN two encoded twemoji THEN true', () => { + expect(areEmojisEqual(encodedBunnyTwemoji, encodedBunnyTwemoji)).toBe(true); + }); + + test('GIVEN two custom static serialized emojis THEN returns true', () => { + expect(areEmojisEqual(serializedStaticSkyra, serializedStaticSkyra)).toBe(true); + }); + + test('GIVEN two custom animated serialized emojis THEN returns true', () => { + expect(areEmojisEqual(serializedAnimatedSkyraGlasses, serializedAnimatedSkyraGlasses)).toBe(true); + }); + + test('GIVEN custom animated serialized emoji and custom static serialized emoji THEN returns false', () => { + expect(areEmojisEqual(serializedAnimatedSkyraGlasses, serializedStaticSkyra)).toBe(false); + }); + + test('GIVEN custom animated serialized emoji and custom static serialized emoji WITH same ID THEN returns true', () => { + expect(areEmojisEqual('a819227046453444620' as SerializedEmoji, 's819227046453444620' as SerializedEmoji)).toBe(true); + }); +}); diff --git a/tests/lib/util/functions/emojis/getEmojiId.test.ts b/projects/bot/tests/lib/util/functions/emojis/getEmojiId.test.ts similarity index 100% rename from tests/lib/util/functions/emojis/getEmojiId.test.ts rename to projects/bot/tests/lib/util/functions/emojis/getEmojiId.test.ts diff --git a/tests/lib/util/functions/emojis/getEmojiObject.test.ts b/projects/bot/tests/lib/util/functions/emojis/getEmojiObject.test.ts similarity index 100% rename from tests/lib/util/functions/emojis/getEmojiObject.test.ts rename to projects/bot/tests/lib/util/functions/emojis/getEmojiObject.test.ts diff --git a/tests/lib/util/functions/emojis/getEmojiReactionFormat.test.ts b/projects/bot/tests/lib/util/functions/emojis/getEmojiReactionFormat.test.ts similarity index 100% rename from tests/lib/util/functions/emojis/getEmojiReactionFormat.test.ts rename to projects/bot/tests/lib/util/functions/emojis/getEmojiReactionFormat.test.ts diff --git a/tests/lib/util/functions/emojis/getEmojiString.test.ts b/projects/bot/tests/lib/util/functions/emojis/getEmojiString.test.ts similarity index 100% rename from tests/lib/util/functions/emojis/getEmojiString.test.ts rename to projects/bot/tests/lib/util/functions/emojis/getEmojiString.test.ts diff --git a/tests/lib/util/functions/emojis/getEmojiTextFormat.test.ts b/projects/bot/tests/lib/util/functions/emojis/getEmojiTextFormat.test.ts similarity index 100% rename from tests/lib/util/functions/emojis/getEmojiTextFormat.test.ts rename to projects/bot/tests/lib/util/functions/emojis/getEmojiTextFormat.test.ts diff --git a/tests/lib/util/functions/emojis/getEncodedTwemoji.test.ts b/projects/bot/tests/lib/util/functions/emojis/getEncodedTwemoji.test.ts similarity index 100% rename from tests/lib/util/functions/emojis/getEncodedTwemoji.test.ts rename to projects/bot/tests/lib/util/functions/emojis/getEncodedTwemoji.test.ts diff --git a/tests/lib/util/functions/emojis/getTwemojiUrl.test.ts b/projects/bot/tests/lib/util/functions/emojis/getTwemojiUrl.test.ts similarity index 100% rename from tests/lib/util/functions/emojis/getTwemojiUrl.test.ts rename to projects/bot/tests/lib/util/functions/emojis/getTwemojiUrl.test.ts diff --git a/tests/lib/util/functions/emojis/isSerializedTwemoji.test.ts b/projects/bot/tests/lib/util/functions/emojis/isSerializedTwemoji.test.ts similarity index 100% rename from tests/lib/util/functions/emojis/isSerializedTwemoji.test.ts rename to projects/bot/tests/lib/util/functions/emojis/isSerializedTwemoji.test.ts diff --git a/tests/lib/util/functions/emojis/isValidCustomEmoji.test.ts b/projects/bot/tests/lib/util/functions/emojis/isValidCustomEmoji.test.ts similarity index 100% rename from tests/lib/util/functions/emojis/isValidCustomEmoji.test.ts rename to projects/bot/tests/lib/util/functions/emojis/isValidCustomEmoji.test.ts diff --git a/tests/lib/util/functions/emojis/isValidSerializedCustomEmoji.test.ts b/projects/bot/tests/lib/util/functions/emojis/isValidSerializedCustomEmoji.test.ts similarity index 100% rename from tests/lib/util/functions/emojis/isValidSerializedCustomEmoji.test.ts rename to projects/bot/tests/lib/util/functions/emojis/isValidSerializedCustomEmoji.test.ts diff --git a/tests/lib/util/functions/emojis/isValidSerializedEmoji.test.ts b/projects/bot/tests/lib/util/functions/emojis/isValidSerializedEmoji.test.ts similarity index 100% rename from tests/lib/util/functions/emojis/isValidSerializedEmoji.test.ts rename to projects/bot/tests/lib/util/functions/emojis/isValidSerializedEmoji.test.ts diff --git a/tests/lib/util/functions/emojis/isValidSerializedTwemoji.test.ts b/projects/bot/tests/lib/util/functions/emojis/isValidSerializedTwemoji.test.ts similarity index 100% rename from tests/lib/util/functions/emojis/isValidSerializedTwemoji.test.ts rename to projects/bot/tests/lib/util/functions/emojis/isValidSerializedTwemoji.test.ts diff --git a/tests/lib/util/functions/emojis/isValidTwemoji.test.ts b/projects/bot/tests/lib/util/functions/emojis/isValidTwemoji.test.ts similarity index 100% rename from tests/lib/util/functions/emojis/isValidTwemoji.test.ts rename to projects/bot/tests/lib/util/functions/emojis/isValidTwemoji.test.ts diff --git a/tests/lib/util/functions/emojis/resolveEmojiId.test.ts b/projects/bot/tests/lib/util/functions/emojis/resolveEmojiId.test.ts similarity index 100% rename from tests/lib/util/functions/emojis/resolveEmojiId.test.ts rename to projects/bot/tests/lib/util/functions/emojis/resolveEmojiId.test.ts diff --git a/projects/bot/tests/lib/util/sanitizeInput.test.ts b/projects/bot/tests/lib/util/sanitizeInput.test.ts new file mode 100644 index 000000000..914f85078 --- /dev/null +++ b/projects/bot/tests/lib/util/sanitizeInput.test.ts @@ -0,0 +1,30 @@ +import { sanitizeInput } from '#utils/util'; + +describe('util sanitizeInput', () => { + test('GIVEN invalid characters THEN removes', () => { + const input = 'h⣫╶ellཻུ۪⸙͎o'; + const expected = 'hello'; + + const sanitized = sanitizeInput(input); + + expect(sanitized).toBe(expected); + }); + + test('GIVEN spaces THEN does not remove', () => { + const input = 'h⣫╶el lཻུ۪⸙͎o'; + const expected = 'hel lo'; + + const sanitized = sanitizeInput(input); + + expect(sanitized).toBe(expected); + }); + + test('GIVEN emojis THEN does not remove', () => { + const input = '😄h⣫╶el 😢 lཻུ۪⸙͎o 🤣'; + const expected = '😄hel 😢 lo 🤣'; + + const sanitized = sanitizeInput(input); + + expect(sanitized).toBe(expected); + }); +}); diff --git a/tests/mocks/MockInstances.ts b/projects/bot/tests/mocks/MockInstances.ts similarity index 100% rename from tests/mocks/MockInstances.ts rename to projects/bot/tests/mocks/MockInstances.ts diff --git a/tests/mocks/constants.ts b/projects/bot/tests/mocks/constants.ts similarity index 100% rename from tests/mocks/constants.ts rename to projects/bot/tests/mocks/constants.ts diff --git a/tests/mocks/image.png b/projects/bot/tests/mocks/image.png similarity index 100% rename from tests/mocks/image.png rename to projects/bot/tests/mocks/image.png diff --git a/tests/scripts/migrate-audit-log-to-audit-event.test.ts b/projects/bot/tests/scripts/migrate-audit-log-to-audit-event.test.ts similarity index 100% rename from tests/scripts/migrate-audit-log-to-audit-event.test.ts rename to projects/bot/tests/scripts/migrate-audit-log-to-audit-event.test.ts diff --git a/projects/bot/tests/tsconfig.json b/projects/bot/tests/tsconfig.json new file mode 100644 index 000000000..98172baf3 --- /dev/null +++ b/projects/bot/tests/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "noEmit": true, + "incremental": false, + "baseUrl": ".", + "types": ["vitest/globals"], + "verbatimModuleSyntax": false, + "paths": { + "#utils/*": ["../src/lib/util/*"], + "#lib/*": ["../src/lib/*"], + "#languages": ["../src/locales/index"], + "#root/*": ["../src/*"] + } + }, + "include": [".", "../src/**/*"], + "exclude": ["../dist/**/*"], + "references": [{ "path": "../src" }] +} diff --git a/tests/vitest.setup.ts b/projects/bot/tests/vitest.setup.ts similarity index 83% rename from tests/vitest.setup.ts rename to projects/bot/tests/vitest.setup.ts index bb23d9265..ccbd7533c 100644 --- a/tests/vitest.setup.ts +++ b/projects/bot/tests/vitest.setup.ts @@ -1,4 +1,3 @@ -import '#lib/setup'; import { client } from './mocks/MockInstances.js'; afterAll(async () => { diff --git a/projects/bot/tsconfig.eslint.json b/projects/bot/tsconfig.eslint.json new file mode 100644 index 000000000..388bb593b --- /dev/null +++ b/projects/bot/tsconfig.eslint.json @@ -0,0 +1,4 @@ +{ + "extends": "../../tsconfig.eslint.json", + "include": ["src", "tests"] +} diff --git a/projects/bot/tsdown.config.ts b/projects/bot/tsdown.config.ts new file mode 100644 index 000000000..a65116dcf --- /dev/null +++ b/projects/bot/tsdown.config.ts @@ -0,0 +1,89 @@ +import { defineConfig } from 'tsdown'; +import { resolve, dirname, join } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { existsSync, copyFileSync, mkdirSync, cpSync } from 'node:fs'; +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); +import type { RolldownPluginOption } from 'rolldown'; +import alias from '@rollup/plugin-alias'; + +// Plugin to copy static files from src to dist +function copyPlugin(): RolldownPluginOption { + return { + name: 'copy-static-files', + buildEnd() { + // Copy worker.mjs to dist (if present) + const workerFile = resolve(__dirname, 'src/lib/moderation/workers/worker.mjs'); + const destWorkerDir = resolve(__dirname, 'dist/lib/moderation/workers'); + const destWorkerFile = join(destWorkerDir, 'worker.mjs'); + + // Copy locales directory to dist + const srcLocalesDir = resolve(__dirname, 'src/locales'); + const destLocalesDir = resolve(__dirname, 'dist/locales'); + + if (existsSync(workerFile)) { + mkdirSync(destWorkerDir, { recursive: true }); + copyFileSync(workerFile, destWorkerFile); + console.log('✓ Copied worker.mjs to dist'); + } + + if (existsSync(srcLocalesDir)) { + mkdirSync(destLocalesDir, { recursive: true }); + cpSync(srcLocalesDir, destLocalesDir, { recursive: true }); + console.log('✓ Copied locales to dist'); + } + } + }; +} + +export default defineConfig({ + entry: ['src/**/*.ts', '!src/locales/**/*.ts'], + format: 'esm', + plugins: [ + alias({ + entries: [ + { + find: '#lib', + replacement: '#lib', + customResolver(source) { + if (source === '#lib/database') return resolve(__dirname, 'src/lib/database/index.ts'); + if (source === '#lib/database/entities') return resolve(__dirname, 'src/lib/database/entities/index.ts'); + if (source === '#lib/database/keys') return resolve(__dirname, 'src/lib/database/keys/index.ts'); + if (source === '#lib/database/settings') return resolve(__dirname, 'src/lib/database/settings/index.ts'); + if (source === '#lib/discord') return resolve(__dirname, 'src/lib/discord/index.ts'); + if (source === '#lib/moderation') return resolve(__dirname, 'src/lib/moderation/index.ts'); + if (source === '#lib/moderation/managers') return resolve(__dirname, 'src/lib/moderation/managers/index.ts'); + if (source === '#lib/moderation/workers') return resolve(__dirname, 'src/lib/moderation/workers/index.ts'); + if (source === '#lib/structures') return resolve(__dirname, 'src/lib/structures/index.ts'); + if (source === '#lib/i18n/languageKeys') return resolve(__dirname, 'src/lib/i18n/languageKeys/index.ts'); + if (source === '#lib/types') return resolve(__dirname, 'src/lib/types/index.ts'); + // Handle other #lib/* imports + const subPath = source.replace('#lib/', ''); + return resolve(__dirname, 'src/lib', `${subPath}.ts`); + } + }, + { find: /^#root\/(.*)/, replacement: resolve(__dirname, 'src/$1.ts') }, + { + find: '#utils', + replacement: '#utils', + customResolver(source) { + if (source === '#utils/common') return resolve(__dirname, 'src/lib/util/common/index.ts'); + if (source === '#utils/functions') return resolve(__dirname, 'src/lib/util/functions/index.ts'); + // Handle other #utils/* imports + const subPath = source.replace('#utils/', ''); + return resolve(__dirname, 'src/lib/util', `${subPath}.ts`); + } + } + ] + }), + copyPlugin() + ], + dts: true, + unbundle: true, + sourcemap: true, + minify: false, + platform: 'node', + tsconfig: 'src/tsconfig.json', + treeshake: true, + deps: { skipNodeModulesBundle: true } +}); diff --git a/projects/docker/README.md b/projects/docker/README.md new file mode 100644 index 000000000..3161cba73 --- /dev/null +++ b/projects/docker/README.md @@ -0,0 +1,21 @@ +# Skyra Dockerfiles + +This folder contains all the files required to control Docker development environments for Skyra. Most of the meat of +the content is in the `docker-compose.yml` file which has the info on which images can be build and as which containers +they would be ran. In order to easily control the docker-compose file there is a powershell, `control.ps1`. + +Skyra currently has the following microservices that can be dockerized: + +- PostgreSQL Database + - Service name in docker-compose: `postgres` + - Image used: `skyrabot/postgres:latest` + - For more information see [skyra-project/docker-images] +- Redis + - Service name in docker-compose: `redis` + - Image used: `redis:alpine` + - For more information see [redis] + + + +[redis]: https://hub.docker.com/_/redis +[skyra-project/docker-images]: https://github.com/skyra-project/docker-images diff --git a/projects/docker/control.ps1 b/projects/docker/control.ps1 new file mode 100644 index 000000000..bc12d1976 --- /dev/null +++ b/projects/docker/control.ps1 @@ -0,0 +1,55 @@ +function Remove-All-Containers { + docker container stop $(docker ps -aq) + docker container rm $(docker ps -aq) +} + +function Show-Help { + Write-Host "" + Write-Host "Skyra Docker Control Script" -ForegroundColor blue + Write-Host "" + Write-Host "Usage" -ForegroundColor yellow + Write-Host " +./.docker/control.ps1 [COMMAND] [ARGS...] +./.docker/control.ps1 -h | --help" + Write-Host "" + Write-Host "Commands" -ForegroundColor yellow + Write-Host " +build Builds a Docker image so it is prepped for running +start Starts a service in detached state +stop Stops a service +remove Removes a single service +removeall Removes all services - For this command no service is required and it can be skipped by just hitting enter when prompted +push Pushes a docker image to Dockerhub +logs Shows the logs of a service +tail Tails the logs of a service +update Updates a running service" +} + +function Step-Run { + Param ( + [String]$Command = $( Read-Host "What command do you want to run? If unsure type help" ), + [String]$Service + ) + + Begin { + if ($Command -Ne "help" -And $Command -Ne "h" -And $Command -Ne "removeall" -And $Service -Eq "") { + $Service = $( Read-Host "What Docker service do you want to control?" ) + } + } + + Process { + switch ($Command) { + build { docker-compose -p skyra -f "$($PSScriptRoot)/docker-compose.yml" -f "$($PSScriptRoot)/docker-build.yml" build $Service } + start { docker-compose -p skyra -f "$($PSScriptRoot)/docker-compose.yml" up -d $Service } + logs { docker-compose -p skyra -f "$($PSScriptRoot)/docker-compose.yml" logs $Service } + tail { docker-compose -p skyra -f "$($PSScriptRoot)/docker-compose.yml" logs -f $Service } + push { docker push $Service } + remove { docker-compose -p skyra -f "$($PSScriptRoot)/docker-compose.yml" rm -fv $Service } + update { docker-compose -p skyra -f "$($PSScriptRoot)/docker-compose.yml" pull $Service; docker-compose -p skyra -f "$($PSScriptRoot)/docker-compose.yml" up -d --force-recreate $Service } + removeall { Remove-All-Containers } + default { Show-Help } + } + } +} + +Step-Run @Args diff --git a/projects/docker/docker-compose.yml b/projects/docker/docker-compose.yml new file mode 100644 index 000000000..60490511c --- /dev/null +++ b/projects/docker/docker-compose.yml @@ -0,0 +1,63 @@ +version: '2.4' +services: + postgres: + container_name: postgres + image: 'skyrabot/postgres:latest' + networks: + - wolfstar + ports: + - '5432:5432' + restart: always + volumes: + - 'postgres-data:/var/lib/postgresql/data' + + redis: + command: 'redis-server --port 8287 --requirepass redis' + container_name: redis + image: 'redis:alpine' + networks: + - wolfstar + ports: + - '8287:8287' + restart: always + + wolfstar-bot: + build: + context: ../../ + dockerfile: ../bot/Dockerfile + container_name: wolfstar-bot + depends_on: + - redis + - postgres + env_file: + - ../bot/src/.env.development + - ../bot/src/.env.development.local + image: 'ghcr.io/wolfstar-project/wolfstar-bot:latest' + networks: + - wolfstar + ports: + - '8282:8282' + - '7282:7282' + restart: always + tty: true + + wolfstar-gateway: + build: + context: ../../ + dockerfile: ../gateway/Dockerfile + container_name: wolfstar-gateway + env_file: + - ../gateway/src/.env.development + - ../gateway/src/.env.development.local + image: 'ghcr.io/wolfstar-project/wolfstar-gateway:latest' + networks: + - wolfstar + restart: always + tty: true + +volumes: + postgres-data: + external: true + +networks: + wolfstar: diff --git a/projects/gateway/Dockerfile b/projects/gateway/Dockerfile new file mode 100644 index 000000000..2b166f7da --- /dev/null +++ b/projects/gateway/Dockerfile @@ -0,0 +1,61 @@ +# ================ # +# Base Stage # +# ================ # + +FROM node:16-buster-slim as base + +WORKDIR /usr/src/app + +ENV HUSKY=0 +ENV CI=true + +RUN apt-get update && \ + apt-get upgrade -y --no-install-recommends && \ + apt-get install -y --no-install-recommends build-essential python3 libfontconfig1 dumb-init && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +COPY --chown=node:node yarn.lock . +COPY --chown=node:node package.json . +COPY --chown=node:node projects/gateway/package.json projects/gateway/package.json +COPY --chown=node:node .yarnrc.yml . +COPY --chown=node:node .yarn/ .yarn/ + +ENTRYPOINT ["dumb-init", "--"] + +# ================ # +# Builder Stage # +# ================ # + +FROM base as builder + +ENV NODE_ENV="development" + +COPY --chown=node:node tsconfig.base.json tsconfig.base.json +COPY --chown=node:node scripts/ scripts/ +COPY --chown=node:node projects/gateway/scripts/ projects/gateway/scripts/ +COPY --chown=node:node projects/gateway/src/ projects/gateway/src/ + +RUN yarn install --immutable +RUN cd projects/gateway/ && yarn run build + +# ================ # +# Runner Stage # +# ================ # + +FROM base AS runner + +ENV NODE_ENV="production" +ENV NODE_OPTIONS="--enable-source-maps --max_old_space_size=4096" + +COPY --chown=node:node projects/gateway/src/.env projects/gateway/src/.env +COPY --chown=node:node --from=builder /usr/src/app/projects/gateway/dist projects/gateway/dist + +RUN yarn workspaces focus --all --production +RUN chown node:node /usr/src/app/ + +USER node + +WORKDIR /usr/src/app/projects/gateway + +CMD [ "yarn", "run", "start" ] diff --git a/projects/gateway/package.json b/projects/gateway/package.json new file mode 100644 index 000000000..beb8e6fc9 --- /dev/null +++ b/projects/gateway/package.json @@ -0,0 +1,33 @@ +{ + "name": "wolfstar-gateway", + "version": "7.0.0", + "description": "Multipurpose Discord Bot built on Sapphire Framework", + "author": "WolfStar Project", + "license": "Apache-2.0", + "private": true, + "main": "dist/main.js", + "type": "module", + "imports": { + "#lib/*": "./dist/lib/*.js" + }, + "scripts": { + "build": "tsc -b src", + "dev": "pnpm build && pnpm start", + "watch": "tsc -b src -w", + "clean": "node scripts/clean.mjs", + "start": "node --enable-source-maps dist/main.js" + }, + "dependencies": { + "@discordjs/rest": "^1.0.1", + "@discordjs/ws": "^0.2.0", + "@sapphire/utilities": "^3.8.0", + "@wolfstar/env-utilities": "^3.0.1", + "@wolfstar/start-banner": "^3.0.1", + "discord-api-types": "^0.37.0", + "gradient-string": "^2.0.1", + "wolfstar-shared": "workspace:^" + }, + "devDependencies": { + "typescript": "^4.7.4" + } +} diff --git a/projects/gateway/scripts/clean.mjs b/projects/gateway/scripts/clean.mjs new file mode 100644 index 000000000..1bd25ff10 --- /dev/null +++ b/projects/gateway/scripts/clean.mjs @@ -0,0 +1,8 @@ +import { rm } from 'node:fs/promises'; + +const rootFolder = new URL('../', import.meta.url); +const distFolder = new URL('dist/', rootFolder); + +const options = { recursive: true, force: true }; + +await rm(distFolder, options); diff --git a/projects/gateway/src/.env b/projects/gateway/src/.env new file mode 100644 index 000000000..9b3c0a193 --- /dev/null +++ b/projects/gateway/src/.env @@ -0,0 +1,15 @@ +CLIENT_VERSION='7.0.0 [Testa Edition]' + +# Discord Client Public Key +DISCORD_TOKEN= + +# Redis options +REDIS_HOST='localhost' +REDIS_PORT=8287 +REDIS_DB=0 +REDIS_PASSWORD='redis' + +# Redis Message Broker options +BROKER_STREAM_NAME='g-stream' +BROKER_BLOCK=5000 +BROKER_MAX=10 diff --git a/projects/gateway/src/.env.development b/projects/gateway/src/.env.development new file mode 100644 index 000000000..1ac313506 --- /dev/null +++ b/projects/gateway/src/.env.development @@ -0,0 +1 @@ +CLIENT_VERSION='7.0.0-dev [Testa Edition]' diff --git a/projects/gateway/src/lib/Client.ts b/projects/gateway/src/lib/Client.ts new file mode 100644 index 000000000..f04ff41ee --- /dev/null +++ b/projects/gateway/src/lib/Client.ts @@ -0,0 +1,57 @@ +import { REST, RESTOptions } from '@discordjs/rest'; +import { OptionalWebSocketManagerOptions, RequiredWebSocketManagerOptions, WebSocketManager } from '@discordjs/ws'; +import { envParseInteger, envParseString } from '@wolfstar/env-utilities'; +import { Cache, container, ListenerStore, MessageBroker, Redis, type RedisOptions } from 'wolfstar-shared'; + +export function createClient(options: ClientOptions) { + const token = envParseString('DISCORD_TOKEN'); + container.rest = new REST(options.rest).setToken(token); + container.ws = new WebSocketManager({ + ...options.ws, + rest: container.rest, + token + }); + + container.redis = new Redis({ + ...options.redis, + lazyConnect: true, + host: envParseString('REDIS_HOST'), + port: envParseInteger('REDIS_PORT'), + db: envParseInteger('REDIS_DB'), + password: envParseString('REDIS_PASSWORD') + }); + container.cache = new Cache({ + client: container.redis, + prefix: 's7' + }); + container.broker = new MessageBroker({ + redis: container.redis, + stream: envParseString('BROKER_STREAM_NAME'), + block: envParseInteger('BROKER_BLOCK', 5000), + max: envParseInteger('BROKER_MAX', 10) + }); + + container.stores.register(new ListenerStore()); +} + +export async function loadAll() { + await container.redis.connect(); + await container.stores.load(); + await container.ws.connect(); +} + +export interface ClientOptions { + redis?: Omit; + rest?: Partial; + ws: Omit, 'rest' | 'token'>; +} + +declare module '@sapphire/pieces' { + interface Container { + broker: MessageBroker; + cache: Cache; + redis: Redis; + rest: REST; + ws: WebSocketManager; + } +} diff --git a/projects/gateway/src/lib/actions/All.ts b/projects/gateway/src/lib/actions/All.ts new file mode 100644 index 000000000..17076c348 --- /dev/null +++ b/projects/gateway/src/lib/actions/All.ts @@ -0,0 +1,113 @@ +import { GatewayDispatchEvents, GatewayDispatchPayload } from 'discord-api-types/v10'; +import { handleChannelCreate } from './ChannelCreate'; +import { handleChannelDelete } from './ChannelDelete'; +import { handleChannelUpdate } from './ChannelUpdate'; +import { handleGuildBanAdd } from './GuildBanAdd'; +import { handleGuildBanRemove } from './GuildBanRemove'; +import { handleGuildCreate } from './GuildCreate'; +import { handleGuildDelete } from './GuildDelete'; +import { handleGuildEmojisUpdate } from './GuildEmojisUpdate'; +import { handleGuildMemberAdd } from './GuildMemberAdd'; +import { handleGuildMemberRemove } from './GuildMemberRemove'; +import { handleGuildMembersChunk } from './GuildMembersChunk'; +import { handleGuildMemberUpdate } from './GuildMemberUpdate'; +import { handleGuildRoleCreate } from './GuildRoleCreate'; +import { handleGuildRoleDelete } from './GuildRoleDelete'; +import { handleGuildRoleUpdate } from './GuildRoleUpdate'; +import { handleGuildStickersUpdate } from './GuildStickersUpdate'; +import { handleGuildUpdate } from './GuildUpdate'; +import { handleMessageCreate } from './MessageCreate'; +import { handleMessageDelete } from './MessageDelete'; +import { handleMessageDeleteBulk } from './MessageDeleteBulk'; +import { handleMessageReactionAdd } from './MessageReactionAdd'; +import { handleMessageReactionRemove } from './MessageReactionRemove'; +import { handleMessageReactionRemoveAll } from './MessageReactionRemoveAll'; +import { handleMessageReactionRemoveEmoji } from './MessageReactionRemoveEmoji'; +import { handleMessageUpdate } from './MessageUpdate'; + +export function all(payload: GatewayDispatchPayload) { + switch (payload.t) { + case GatewayDispatchEvents.ChannelCreate: + return handleChannelCreate(payload.d); + case GatewayDispatchEvents.ChannelDelete: + return handleChannelDelete(payload.d); + case GatewayDispatchEvents.ChannelUpdate: + return handleChannelUpdate(payload.d); + case GatewayDispatchEvents.GuildBanAdd: + return handleGuildBanAdd(payload.d); + case GatewayDispatchEvents.GuildBanRemove: + return handleGuildBanRemove(payload.d); + case GatewayDispatchEvents.GuildCreate: + return handleGuildCreate(payload.d); + case GatewayDispatchEvents.GuildDelete: + return handleGuildDelete(payload.d); + case GatewayDispatchEvents.GuildEmojisUpdate: + return handleGuildEmojisUpdate(payload.d); + case GatewayDispatchEvents.GuildMemberAdd: + return handleGuildMemberAdd(payload.d); + case GatewayDispatchEvents.GuildMemberRemove: + return handleGuildMemberRemove(payload.d); + case GatewayDispatchEvents.GuildMembersChunk: + return handleGuildMembersChunk(payload.d); + case GatewayDispatchEvents.GuildMemberUpdate: + return handleGuildMemberUpdate(payload.d); + case GatewayDispatchEvents.GuildRoleCreate: + return handleGuildRoleCreate(payload.d); + case GatewayDispatchEvents.GuildRoleDelete: + return handleGuildRoleDelete(payload.d); + case GatewayDispatchEvents.GuildRoleUpdate: + return handleGuildRoleUpdate(payload.d); + case GatewayDispatchEvents.GuildStickersUpdate: + return handleGuildStickersUpdate(payload.d); + case GatewayDispatchEvents.GuildUpdate: + return handleGuildUpdate(payload.d); + case GatewayDispatchEvents.MessageCreate: + return handleMessageCreate(payload.d); + case GatewayDispatchEvents.MessageDelete: + return handleMessageDelete(payload.d); + case GatewayDispatchEvents.MessageDeleteBulk: + return handleMessageDeleteBulk(payload.d); + case GatewayDispatchEvents.MessageReactionAdd: + return handleMessageReactionAdd(payload.d); + case GatewayDispatchEvents.MessageReactionRemove: + return handleMessageReactionRemove(payload.d); + case GatewayDispatchEvents.MessageReactionRemoveAll: + return handleMessageReactionRemoveAll(payload.d); + case GatewayDispatchEvents.MessageReactionRemoveEmoji: + return handleMessageReactionRemoveEmoji(payload.d); + case GatewayDispatchEvents.MessageUpdate: + return handleMessageUpdate(payload.d); + // case GatewayDispatchEvents.ChannelPinsUpdate: + // case GatewayDispatchEvents.GuildIntegrationsUpdate: + // case GatewayDispatchEvents.IntegrationCreate: + // case GatewayDispatchEvents.IntegrationDelete: + // case GatewayDispatchEvents.IntegrationUpdate: + // case GatewayDispatchEvents.InteractionCreate: + // case GatewayDispatchEvents.InviteCreate: + // case GatewayDispatchEvents.InviteDelete: + // case GatewayDispatchEvents.PresenceUpdate: + // case GatewayDispatchEvents.StageInstanceCreate: + // case GatewayDispatchEvents.StageInstanceDelete: + // case GatewayDispatchEvents.StageInstanceUpdate: + // case GatewayDispatchEvents.Ready: + // case GatewayDispatchEvents.Resumed: + // case GatewayDispatchEvents.ThreadCreate: + // case GatewayDispatchEvents.ThreadDelete: + // case GatewayDispatchEvents.ThreadListSync: + // case GatewayDispatchEvents.ThreadMembersUpdate: + // case GatewayDispatchEvents.ThreadMemberUpdate: + // case GatewayDispatchEvents.ThreadUpdate: + // case GatewayDispatchEvents.TypingStart: + // case GatewayDispatchEvents.UserUpdate: + // case GatewayDispatchEvents.VoiceServerUpdate: + // case GatewayDispatchEvents.VoiceStateUpdate: + // case GatewayDispatchEvents.WebhooksUpdate: + // case GatewayDispatchEvents.GuildScheduledEventCreate: + // case GatewayDispatchEvents.GuildScheduledEventUpdate: + // case GatewayDispatchEvents.GuildScheduledEventDelete: + // case GatewayDispatchEvents.GuildScheduledEventUserAdd: + // case GatewayDispatchEvents.GuildScheduledEventUserRemove: + default: + return null; + } +} diff --git a/projects/gateway/src/lib/actions/ChannelCreate.ts b/projects/gateway/src/lib/actions/ChannelCreate.ts new file mode 100644 index 000000000..86c8735eb --- /dev/null +++ b/projects/gateway/src/lib/actions/ChannelCreate.ts @@ -0,0 +1,11 @@ +import { isNullish } from '@sapphire/utilities'; +import type { GatewayChannelCreateDispatchData } from 'discord-api-types/v10'; +import { Channel, container, RedisMessageType } from 'wolfstar-shared'; + +export async function handleChannelCreate(payload: GatewayChannelCreateDispatchData) { + if (!('guild_id' in payload)) return; + if (isNullish(payload.guild_id)) return; + + await container.cache.channels.set(payload.guild_id, Channel.fromAPI(payload)); + await container.broker.send({ type: RedisMessageType.ChannelCreate, data: payload }); +} diff --git a/projects/gateway/src/lib/actions/ChannelDelete.ts b/projects/gateway/src/lib/actions/ChannelDelete.ts new file mode 100644 index 000000000..126e81dc4 --- /dev/null +++ b/projects/gateway/src/lib/actions/ChannelDelete.ts @@ -0,0 +1,11 @@ +import { isNullish } from '@sapphire/utilities'; +import type { GatewayChannelDeleteDispatchData } from 'discord-api-types/v10'; +import { container, RedisMessageType } from 'wolfstar-shared'; + +export async function handleChannelDelete(payload: GatewayChannelDeleteDispatchData) { + if (!('guild_id' in payload)) return; + if (isNullish(payload.guild_id)) return; + + await container.cache.channels.remove(payload.guild_id, payload.id); + await container.broker.send({ type: RedisMessageType.ChannelDelete, old: payload }); +} diff --git a/projects/gateway/src/lib/actions/ChannelUpdate.ts b/projects/gateway/src/lib/actions/ChannelUpdate.ts new file mode 100644 index 000000000..5aac9d742 --- /dev/null +++ b/projects/gateway/src/lib/actions/ChannelUpdate.ts @@ -0,0 +1,12 @@ +import { isNullish } from '@sapphire/utilities'; +import type { GatewayChannelUpdateDispatchData } from 'discord-api-types/v10'; +import { Channel, container, RedisMessageType } from 'wolfstar-shared'; + +export async function handleChannelUpdate(payload: GatewayChannelUpdateDispatchData) { + if (!('guild_id' in payload)) return; + if (isNullish(payload.guild_id)) return; + + const old = (await container.cache.channels.get(payload.guild_id, payload.id))?.toJSON() ?? null; + await container.cache.channels.set(payload.guild_id, Channel.fromAPI(payload)); + await container.broker.send({ type: RedisMessageType.ChannelUpdate, old, data: payload }); +} diff --git a/projects/gateway/src/lib/actions/GuildBanAdd.ts b/projects/gateway/src/lib/actions/GuildBanAdd.ts new file mode 100644 index 000000000..a29791be3 --- /dev/null +++ b/projects/gateway/src/lib/actions/GuildBanAdd.ts @@ -0,0 +1,6 @@ +import type { GatewayGuildBanAddDispatchData } from 'discord-api-types/v10'; +import { container, RedisMessageType } from 'wolfstar-shared'; + +export async function handleGuildBanAdd(payload: GatewayGuildBanAddDispatchData) { + await container.broker.send({ type: RedisMessageType.GuildBanAdd, data: payload }); +} diff --git a/projects/gateway/src/lib/actions/GuildBanRemove.ts b/projects/gateway/src/lib/actions/GuildBanRemove.ts new file mode 100644 index 000000000..4111cc422 --- /dev/null +++ b/projects/gateway/src/lib/actions/GuildBanRemove.ts @@ -0,0 +1,6 @@ +import type { GatewayGuildBanRemoveDispatchData } from 'discord-api-types/v10'; +import { container, RedisMessageType } from 'wolfstar-shared'; + +export async function handleGuildBanRemove(payload: GatewayGuildBanRemoveDispatchData) { + await container.broker.send({ type: RedisMessageType.GuildBanRemove, data: payload }); +} diff --git a/projects/gateway/src/lib/actions/GuildCreate.ts b/projects/gateway/src/lib/actions/GuildCreate.ts new file mode 100644 index 000000000..ab51179d7 --- /dev/null +++ b/projects/gateway/src/lib/actions/GuildCreate.ts @@ -0,0 +1,26 @@ +import type { GatewayGuildCreateDispatchData } from 'discord-api-types/v10'; +import { Channel, container, Emoji, Guild, Member, Role, Sticker } from 'wolfstar-shared'; + +export async function handleGuildCreate(payload: GatewayGuildCreateDispatchData) { + await container.cache.guilds.set(Guild.fromAPI(payload)); + await container.cache.emojis.set( + payload.id, + payload.emojis.map((emoji) => Emoji.fromAPI(emoji)) + ); + await container.cache.channels.set( + payload.id, + payload.channels.map((entry) => Channel.fromAPI(entry)) + ); + await container.cache.members.set( + payload.id, + payload.members.map((entry) => Member.fromAPI(entry)) + ); + await container.cache.roles.set( + payload.id, + payload.roles.map((emoji) => Role.fromAPI(emoji)) + ); + await container.cache.stickers.set( + payload.id, + payload.stickers.map((emoji) => Sticker.fromAPI(emoji)) + ); +} diff --git a/projects/gateway/src/lib/actions/GuildDelete.ts b/projects/gateway/src/lib/actions/GuildDelete.ts new file mode 100644 index 000000000..992f6ce8d --- /dev/null +++ b/projects/gateway/src/lib/actions/GuildDelete.ts @@ -0,0 +1,9 @@ +import type { GatewayGuildDeleteDispatchData } from 'discord-api-types/v10'; +import { container } from 'wolfstar-shared'; + +export async function handleGuildDelete(payload: GatewayGuildDeleteDispatchData) { + for (const channelId of await container.cache.channels.keys(payload.id)) { + await container.cache.messages.clear(channelId); + } + await container.cache.guilds.remove(payload.id); +} diff --git a/projects/gateway/src/lib/actions/GuildEmojisUpdate.ts b/projects/gateway/src/lib/actions/GuildEmojisUpdate.ts new file mode 100644 index 000000000..fe1aa629c --- /dev/null +++ b/projects/gateway/src/lib/actions/GuildEmojisUpdate.ts @@ -0,0 +1,38 @@ +import { isNullish } from '@sapphire/utilities'; +import type { GatewayGuildEmojisUpdateDispatchData } from 'discord-api-types/v10'; +import { container, Emoji, RedisMessageType } from 'wolfstar-shared'; + +export async function handleGuildEmojisUpdate(payload: GatewayGuildEmojisUpdateDispatchData) { + const oldEntries = await container.cache.emojis.entries(payload.guild_id); + + for (const emoji of payload.emojis) { + const updated = Emoji.fromAPI(emoji); + const old = oldEntries.get(updated.id); + + if (isNullish(old)) { + // A new emoji has been created: + await container.cache.emojis.set(payload.guild_id, updated); + await container.broker.send({ type: RedisMessageType.EmojiCreate, data: emoji, guild_id: payload.guild_id }); + } else if (!updated.equals(old)) { + // An emoji has been updated: + await container.cache.emojis.set(payload.guild_id, updated); + await container.broker.send({ type: RedisMessageType.EmojiUpdate, old: old.toJSON(), data: emoji, guild_id: payload.guild_id }); + } + + // Remove the processed entry from the retrieved map, as the current + // entry is a created, updated, or untouched one. + // + // The remaining entries will be deleted ones, so this operation comes + // handy to create a fast emoji deletion dispatch. + // + // On a side note, this does not mutate the actual cache, which is in + // Redis. + oldEntries.delete(updated.id); + } + + // Process deleted entries: + await container.cache.emojis.remove(payload.guild_id, [...oldEntries.keys()]); + for (const emoji of oldEntries.values()) { + await container.broker.send({ type: RedisMessageType.EmojiDelete, old: emoji.toJSON(), guild_id: payload.guild_id }); + } +} diff --git a/projects/gateway/src/lib/actions/GuildMemberAdd.ts b/projects/gateway/src/lib/actions/GuildMemberAdd.ts new file mode 100644 index 000000000..1329fa24c --- /dev/null +++ b/projects/gateway/src/lib/actions/GuildMemberAdd.ts @@ -0,0 +1,7 @@ +import type { GatewayGuildMemberAddDispatchData } from 'discord-api-types/v10'; +import { container, Member, RedisMessageType } from 'wolfstar-shared'; + +export async function handleGuildMemberAdd(payload: GatewayGuildMemberAddDispatchData) { + await container.cache.members.set(payload.guild_id, Member.fromAPI(payload)); + await container.broker.send({ type: RedisMessageType.MemberAdd, data: payload }); +} diff --git a/projects/gateway/src/lib/actions/GuildMemberRemove.ts b/projects/gateway/src/lib/actions/GuildMemberRemove.ts new file mode 100644 index 000000000..71e0c2ad7 --- /dev/null +++ b/projects/gateway/src/lib/actions/GuildMemberRemove.ts @@ -0,0 +1,13 @@ +import { isNullish } from '@sapphire/utilities'; +import type { GatewayGuildMemberRemoveDispatchData } from 'discord-api-types/v10'; +import { container, RedisMessageType } from 'wolfstar-shared'; + +export async function handleGuildMemberRemove(payload: GatewayGuildMemberRemoveDispatchData) { + const old = await container.cache.members.get(payload.guild_id, payload.user.id); + if (isNullish(old)) { + await container.broker.send({ type: RedisMessageType.MemberRemove, old: null, user: payload.user, guild_id: payload.guild_id }); + } else { + await container.cache.members.remove(payload.guild_id, old.id); + await container.broker.send({ type: RedisMessageType.MemberRemove, old: old.toJSON(), user: payload.user, guild_id: payload.guild_id }); + } +} diff --git a/projects/gateway/src/lib/actions/GuildMemberUpdate.ts b/projects/gateway/src/lib/actions/GuildMemberUpdate.ts new file mode 100644 index 000000000..fda424ad3 --- /dev/null +++ b/projects/gateway/src/lib/actions/GuildMemberUpdate.ts @@ -0,0 +1,15 @@ +import { isNullish } from '@sapphire/utilities'; +import type { GatewayGuildMemberUpdateDispatchData } from 'discord-api-types/v10'; +import { container, Member, RedisMessageType } from 'wolfstar-shared'; + +export async function handleGuildMemberUpdate(payload: GatewayGuildMemberUpdateDispatchData) { + const old = await container.cache.members.get(payload.guild_id, payload.user.id); + if (isNullish(old)) { + await container.cache.members.set(payload.guild_id, Member.fromAPI(payload)); + await container.broker.send({ type: RedisMessageType.MemberUpdate, old: null, data: payload }); + } else { + const data = old.patch(payload); + await container.cache.members.set(payload.guild_id, data); + await container.broker.send({ type: RedisMessageType.MemberUpdate, old: old.toJSON(), data: data.toJSON() }); + } +} diff --git a/projects/gateway/src/lib/actions/GuildMembersChunk.ts b/projects/gateway/src/lib/actions/GuildMembersChunk.ts new file mode 100644 index 000000000..1b919580c --- /dev/null +++ b/projects/gateway/src/lib/actions/GuildMembersChunk.ts @@ -0,0 +1,9 @@ +import type { GatewayGuildMembersChunkDispatchData } from 'discord-api-types/v10'; +import { container, Member } from 'wolfstar-shared'; + +export async function handleGuildMembersChunk(payload: GatewayGuildMembersChunkDispatchData) { + await container.cache.members.set( + payload.guild_id, + payload.members.map((data) => Member.fromAPI(data)) + ); +} diff --git a/projects/gateway/src/lib/actions/GuildRoleCreate.ts b/projects/gateway/src/lib/actions/GuildRoleCreate.ts new file mode 100644 index 000000000..ea6274bae --- /dev/null +++ b/projects/gateway/src/lib/actions/GuildRoleCreate.ts @@ -0,0 +1,7 @@ +import type { GatewayGuildRoleCreateDispatchData } from 'discord-api-types/v10'; +import { container, RedisMessageType, Role } from 'wolfstar-shared'; + +export async function handleGuildRoleCreate(payload: GatewayGuildRoleCreateDispatchData) { + await container.cache.roles.set(payload.guild_id, Role.fromAPI(payload.role)); + await container.broker.send({ type: RedisMessageType.RoleCreate, data: payload.role, guild_id: payload.guild_id }); +} diff --git a/projects/gateway/src/lib/actions/GuildRoleDelete.ts b/projects/gateway/src/lib/actions/GuildRoleDelete.ts new file mode 100644 index 000000000..d589f1d07 --- /dev/null +++ b/projects/gateway/src/lib/actions/GuildRoleDelete.ts @@ -0,0 +1,13 @@ +import { isNullish } from '@sapphire/utilities'; +import type { GatewayGuildRoleDeleteDispatchData } from 'discord-api-types/v10'; +import { container, RedisMessageType } from 'wolfstar-shared'; + +export async function handleGuildRoleDelete(payload: GatewayGuildRoleDeleteDispatchData) { + const old = await container.cache.roles.get(payload.guild_id, payload.role_id); + if (isNullish(old)) { + await container.broker.send({ type: RedisMessageType.RoleDelete, old: { id: payload.role_id }, guild_id: payload.guild_id }); + } else { + await container.cache.roles.remove(payload.guild_id, old.id); + await container.broker.send({ type: RedisMessageType.RoleDelete, old: old.toJSON(), guild_id: payload.guild_id }); + } +} diff --git a/projects/gateway/src/lib/actions/GuildRoleUpdate.ts b/projects/gateway/src/lib/actions/GuildRoleUpdate.ts new file mode 100644 index 000000000..62b7e44b9 --- /dev/null +++ b/projects/gateway/src/lib/actions/GuildRoleUpdate.ts @@ -0,0 +1,8 @@ +import type { GatewayGuildRoleUpdateDispatchData } from 'discord-api-types/v10'; +import { container, RedisMessageType, Role } from 'wolfstar-shared'; + +export async function handleGuildRoleUpdate(payload: GatewayGuildRoleUpdateDispatchData) { + const old = await container.cache.roles.get(payload.guild_id, payload.role.id); + await container.cache.roles.set(payload.guild_id, Role.fromAPI(payload.role)); + await container.broker.send({ type: RedisMessageType.RoleUpdate, old: old?.toJSON() ?? null, data: payload.role, guild_id: payload.guild_id }); +} diff --git a/projects/gateway/src/lib/actions/GuildStickersUpdate.ts b/projects/gateway/src/lib/actions/GuildStickersUpdate.ts new file mode 100644 index 000000000..a4cd26a97 --- /dev/null +++ b/projects/gateway/src/lib/actions/GuildStickersUpdate.ts @@ -0,0 +1,38 @@ +import { isNullish } from '@sapphire/utilities'; +import type { GatewayGuildStickersUpdateDispatchData } from 'discord-api-types/v10'; +import { container, RedisMessageType, Sticker } from 'wolfstar-shared'; + +export async function handleGuildStickersUpdate(payload: GatewayGuildStickersUpdateDispatchData) { + const oldEntries = await container.cache.stickers.entries(payload.guild_id); + + for (const sticker of payload.stickers) { + const updated = Sticker.fromAPI(sticker); + const old = oldEntries.get(updated.id); + + if (isNullish(old)) { + // A new sticker has been created: + await container.cache.stickers.set(payload.guild_id, updated); + await container.broker.send({ type: RedisMessageType.StickerCreate, data: sticker, guild_id: payload.guild_id }); + } else if (!updated.equals(old)) { + // A sticker has been updated: + await container.cache.stickers.set(payload.guild_id, updated); + await container.broker.send({ type: RedisMessageType.StickerUpdate, old: old.toJSON(), data: sticker, guild_id: payload.guild_id }); + } + + // Remove the processed entry from the retrieved map, as the current + // entry is a created, updated, or untouched one. + // + // The remaining entries will be deleted ones, so this operation comes + // handy to create a fast sticker deletion dispatch. + // + // On a side note, this does not mutate the actual cache, which is in + // Redis. + oldEntries.delete(updated.id); + } + + // Process deleted entries: + await container.cache.stickers.remove(payload.guild_id, [...oldEntries.keys()]); + for (const sticker of oldEntries.values()) { + await container.broker.send({ type: RedisMessageType.StickerDelete, old: sticker.toJSON(), guild_id: payload.guild_id }); + } +} diff --git a/projects/gateway/src/lib/actions/GuildUpdate.ts b/projects/gateway/src/lib/actions/GuildUpdate.ts new file mode 100644 index 000000000..1349b12da --- /dev/null +++ b/projects/gateway/src/lib/actions/GuildUpdate.ts @@ -0,0 +1,9 @@ +import type { GatewayGuildUpdateDispatchData } from 'discord-api-types/v10'; +import { container, Guild, RedisMessageType } from 'wolfstar-shared'; + +export async function handleGuildUpdate(payload: GatewayGuildUpdateDispatchData) { + const old = await container.cache.guilds.get(payload.id); + const data = Guild.fromAPI(payload); + await container.cache.guilds.set(data); + await container.broker.send({ type: RedisMessageType.GuildUpdate, old: old?.toJSON() ?? null, data: data.toJSON() }); +} diff --git a/projects/gateway/src/lib/actions/MessageCreate.ts b/projects/gateway/src/lib/actions/MessageCreate.ts new file mode 100644 index 000000000..934007283 --- /dev/null +++ b/projects/gateway/src/lib/actions/MessageCreate.ts @@ -0,0 +1,11 @@ +import { isNullish } from '@sapphire/utilities'; +import type { GatewayMessageCreateDispatchData } from 'discord-api-types/v10'; +import { container, Message, RedisMessageType } from 'wolfstar-shared'; + +export async function handleMessageCreate(payload: GatewayMessageCreateDispatchData) { + if (!('guild_id' in payload)) return; + if (isNullish(payload.guild_id)) return; + + await container.cache.messages.set(payload.channel_id, Message.fromAPI(payload)); + await container.broker.send({ type: RedisMessageType.MessageCreate, data: payload }); +} diff --git a/projects/gateway/src/lib/actions/MessageDelete.ts b/projects/gateway/src/lib/actions/MessageDelete.ts new file mode 100644 index 000000000..b1f580683 --- /dev/null +++ b/projects/gateway/src/lib/actions/MessageDelete.ts @@ -0,0 +1,19 @@ +import { isNullish } from '@sapphire/utilities'; +import type { GatewayMessageDeleteDispatchData } from 'discord-api-types/v10'; +import { container, RedisMessageType } from 'wolfstar-shared'; + +export async function handleMessageDelete(payload: GatewayMessageDeleteDispatchData) { + if (!('guild_id' in payload)) return; + if (isNullish(payload.guild_id)) return; + + const old = await container.cache.messages.get(payload.channel_id, payload.id); + if (isNullish(old)) { + await container.broker.send({ + type: RedisMessageType.MessageDelete, + old: { id: payload.id, channel_id: payload.channel_id, guild_id: payload.guild_id } + }); + } else { + await container.cache.messages.remove(payload.channel_id, payload.id); + await container.broker.send({ type: RedisMessageType.MessageDelete, old: old.toJSON() }); + } +} diff --git a/projects/gateway/src/lib/actions/MessageDeleteBulk.ts b/projects/gateway/src/lib/actions/MessageDeleteBulk.ts new file mode 100644 index 000000000..69576c543 --- /dev/null +++ b/projects/gateway/src/lib/actions/MessageDeleteBulk.ts @@ -0,0 +1,18 @@ +import { isNullish } from '@sapphire/utilities'; +import type { GatewayMessageDeleteBulkDispatchData } from 'discord-api-types/v10'; +import { container, RedisMessageType } from 'wolfstar-shared'; + +export async function handleMessageDeleteBulk(payload: GatewayMessageDeleteBulkDispatchData) { + if (!('guild_id' in payload)) return; + if (isNullish(payload.guild_id)) return; + + const entries = await container.cache.messages.get(payload.channel_id, payload.ids); + await container.cache.messages.remove(payload.channel_id, payload.ids); + + await container.broker.send({ + type: RedisMessageType.MessageDeleteBulk, + old: payload.ids.map((id) => entries.get(BigInt(id))?.toJSON() ?? { id }), + channel_id: payload.channel_id, + guild_id: payload.guild_id + }); +} diff --git a/projects/gateway/src/lib/actions/MessageReactionAdd.ts b/projects/gateway/src/lib/actions/MessageReactionAdd.ts new file mode 100644 index 000000000..c42822924 --- /dev/null +++ b/projects/gateway/src/lib/actions/MessageReactionAdd.ts @@ -0,0 +1,6 @@ +import type { GatewayMessageReactionAddDispatchData } from 'discord-api-types/v10'; +import { container, RedisMessageType } from 'wolfstar-shared'; + +export async function handleMessageReactionAdd(payload: GatewayMessageReactionAddDispatchData) { + await container.broker.send({ type: RedisMessageType.MessageReactionAdd, data: payload }); +} diff --git a/projects/gateway/src/lib/actions/MessageReactionRemove.ts b/projects/gateway/src/lib/actions/MessageReactionRemove.ts new file mode 100644 index 000000000..098350167 --- /dev/null +++ b/projects/gateway/src/lib/actions/MessageReactionRemove.ts @@ -0,0 +1,6 @@ +import type { GatewayMessageReactionRemoveDispatchData } from 'discord-api-types/v10'; +import { container, RedisMessageType } from 'wolfstar-shared'; + +export async function handleMessageReactionRemove(payload: GatewayMessageReactionRemoveDispatchData) { + await container.broker.send({ type: RedisMessageType.MessageReactionRemove, data: payload }); +} diff --git a/projects/gateway/src/lib/actions/MessageReactionRemoveAll.ts b/projects/gateway/src/lib/actions/MessageReactionRemoveAll.ts new file mode 100644 index 000000000..d14ac3b2b --- /dev/null +++ b/projects/gateway/src/lib/actions/MessageReactionRemoveAll.ts @@ -0,0 +1,6 @@ +import type { GatewayMessageReactionRemoveAllDispatchData } from 'discord-api-types/v10'; +import { container, RedisMessageType } from 'wolfstar-shared'; + +export async function handleMessageReactionRemoveAll(payload: GatewayMessageReactionRemoveAllDispatchData) { + await container.broker.send({ type: RedisMessageType.MessageReactionRemoveAll, data: payload }); +} diff --git a/projects/gateway/src/lib/actions/MessageReactionRemoveEmoji.ts b/projects/gateway/src/lib/actions/MessageReactionRemoveEmoji.ts new file mode 100644 index 000000000..be8dd20b7 --- /dev/null +++ b/projects/gateway/src/lib/actions/MessageReactionRemoveEmoji.ts @@ -0,0 +1,6 @@ +import type { GatewayMessageReactionRemoveEmojiDispatchData } from 'discord-api-types/v10'; +import { container, RedisMessageType } from 'wolfstar-shared'; + +export async function handleMessageReactionRemoveEmoji(payload: GatewayMessageReactionRemoveEmojiDispatchData) { + await container.broker.send({ type: RedisMessageType.MessageReactionRemoveEmoji, data: payload }); +} diff --git a/projects/gateway/src/lib/actions/MessageUpdate.ts b/projects/gateway/src/lib/actions/MessageUpdate.ts new file mode 100644 index 000000000..d3ac1cf4d --- /dev/null +++ b/projects/gateway/src/lib/actions/MessageUpdate.ts @@ -0,0 +1,17 @@ +import { isNullish } from '@sapphire/utilities'; +import type { GatewayMessageUpdateDispatchData } from 'discord-api-types/v10'; +import { container, Message, RedisMessageType } from 'wolfstar-shared'; + +export async function handleMessageUpdate(payload: GatewayMessageUpdateDispatchData) { + if (!('guild_id' in payload)) return; + if (isNullish(payload.guild_id)) return; + + const old = await container.cache.messages.get(payload.guild_id, payload.id); + if (isNullish(old)) { + await container.cache.messages.set(payload.guild_id, Message.fromAPI(payload as any)); + await container.broker.send({ type: RedisMessageType.MessageUpdate, old: null, data: payload }); + } else { + await container.cache.messages.set(payload.guild_id, old.patch(payload)); + await container.broker.send({ type: RedisMessageType.MessageUpdate, old: old.toJSON(), data: payload }); + } +} diff --git a/projects/gateway/src/lib/augments.d.ts b/projects/gateway/src/lib/augments.d.ts new file mode 100644 index 000000000..cbd3e3c5d --- /dev/null +++ b/projects/gateway/src/lib/augments.d.ts @@ -0,0 +1,18 @@ +import type { IntegerString } from '@wolfstar/env-utilities'; + +declare module '@wolfstar/env-utilities' { + interface Env { + CLIENT_VERSION: string; + + DISCORD_TOKEN: string; + + REDIS_HOST: string; + REDIS_PORT: IntegerString; + REDIS_DB: IntegerString; + REDIS_PASSWORD: string; + + BROKER_STREAM_NAME: string; + BROKER_BLOCK?: IntegerString; + BROKER_MAX?: IntegerString; + } +} diff --git a/projects/gateway/src/lib/structures/ws-listener.ts b/projects/gateway/src/lib/structures/ws-listener.ts new file mode 100644 index 000000000..9f167da95 --- /dev/null +++ b/projects/gateway/src/lib/structures/ws-listener.ts @@ -0,0 +1,21 @@ +import type { ManagerShardEventsMap } from '@discordjs/ws'; +import { Listener } from 'wolfstar-shared'; + +export function makeWebSocketListener>( + event: K, + cb: (...args: ListenerEvents[K]) => unknown +) { + class UserListener extends Listener { + public constructor(context: Listener.Context, options: Listener.Options) { + super(context, { ...options, emitter: 'ws', event }); + } + + public run(...args: ListenerEvents[K]) { + return cb(...args); + } + } + + return UserListener as typeof Listener; +} + +type ListenerEvents = T & { error: [error: Error] }; diff --git a/projects/gateway/src/listeners/ws/dispatch.mts b/projects/gateway/src/listeners/ws/dispatch.mts new file mode 100644 index 000000000..2b4166db7 --- /dev/null +++ b/projects/gateway/src/listeners/ws/dispatch.mts @@ -0,0 +1,6 @@ +import { makeWebSocketListener } from '#lib/structures/ws-listener'; +import { WebSocketShardEvents } from '@discordjs/ws'; + +export default makeWebSocketListener(WebSocketShardEvents.Dispatch, (payload) => { + console.log(payload.data.t); +}); diff --git a/projects/gateway/src/listeners/ws/error.mts b/projects/gateway/src/listeners/ws/error.mts new file mode 100644 index 000000000..4d21585fc --- /dev/null +++ b/projects/gateway/src/listeners/ws/error.mts @@ -0,0 +1,5 @@ +import { makeWebSocketListener } from '#lib/structures/ws-listener'; + +export default makeWebSocketListener('error', (error) => { + console.error('Received error:', error); +}); diff --git a/projects/gateway/src/listeners/ws/ready.mts b/projects/gateway/src/listeners/ws/ready.mts new file mode 100644 index 000000000..5c02e15e2 --- /dev/null +++ b/projects/gateway/src/listeners/ws/ready.mts @@ -0,0 +1,6 @@ +import { makeWebSocketListener } from '#lib/structures/ws-listener'; +import { WebSocketShardEvents } from '@discordjs/ws'; + +export default makeWebSocketListener(WebSocketShardEvents.Ready, (payload) => { + console.log(`[WS] ${payload.shardId} is now ready.`); +}); diff --git a/projects/gateway/src/listeners/ws/resumed.mts b/projects/gateway/src/listeners/ws/resumed.mts new file mode 100644 index 000000000..fb0f62ba6 --- /dev/null +++ b/projects/gateway/src/listeners/ws/resumed.mts @@ -0,0 +1,6 @@ +import { makeWebSocketListener } from '#lib/structures/ws-listener'; +import { WebSocketShardEvents } from '@discordjs/ws'; + +export default makeWebSocketListener(WebSocketShardEvents.Resumed, (payload) => { + console.log(`[WS] ${payload.shardId} has resumed previous session.`); +}); diff --git a/projects/gateway/src/main.ts b/projects/gateway/src/main.ts new file mode 100644 index 000000000..0c424aa98 --- /dev/null +++ b/projects/gateway/src/main.ts @@ -0,0 +1,55 @@ +import { createClient, loadAll } from '#lib/Client'; +import { envParseString, setup } from '@wolfstar/env-utilities'; +import { createBanner } from '@wolfstar/start-banner'; +import { GatewayIntentBits } from 'discord-api-types/v10'; +import gradient from 'gradient-string'; +import { container } from 'wolfstar-shared'; + +setup(new URL('../src/.env', import.meta.url)); + +createClient({ + ws: { + intents: + GatewayIntentBits.GuildBans | + GatewayIntentBits.GuildEmojisAndStickers | + GatewayIntentBits.GuildInvites | + GatewayIntentBits.GuildMembers | + GatewayIntentBits.GuildMessageReactions | + GatewayIntentBits.GuildMessages | + GatewayIntentBits.GuildVoiceStates | + GatewayIntentBits.Guilds | + GatewayIntentBits.MessageContent + } +}); + +await loadAll(); + +console.log( + gradient.vice.multiline( + createBanner({ + logo: [ + String.raw` __`, + String.raw` __╱‾‾╲__`, + String.raw` __╱‾‾╲__╱‾‾╲__`, + String.raw`╱‾‾╲__╱ ╲__╱‾‾╲`, + String.raw`╲__╱ ╲__╱ ╲__╱`, + String.raw` ╲__╱ ╲__╱`, + String.raw` ╲__╱`, + '' + ], + name: [ + String.raw` _______ ________ ________ ________ ________ ________ ________ `, + String.raw` ╱╱ ╲╱ ╲╱ ╲╱ ╲╱ ╱ ╱ ╲╱ ╲╱ ╱ ╲ `, + String.raw` ╱╱ __╱ ╱ _╱ ╱ ╱ ╱ ╱ `, + String.raw`╱ ╱ ╱ ╱╱ ╱╱ _╱ ╱ ╱╲__ ╱ `, + String.raw`╲________╱╲___╱____╱ ╲______╱ ╲________╱╲________╱╲___╱____╱ ╲_____╱ ` + ], + extra: [ + ` Skyra ${envParseString('CLIENT_VERSION')} Gateway`, + ` ├ WebSocket: ${container.ws.options.shardCount} shards`, + ` └ Redis : ${container.redis.options.host}:${container.redis.options.port}` + ] + }) + ) +); +console.log('Ready'); diff --git a/projects/gateway/src/tsconfig.json b/projects/gateway/src/tsconfig.json new file mode 100644 index 000000000..c7306c7c8 --- /dev/null +++ b/projects/gateway/src/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "../dist", + "rootDir": ".", + "baseUrl": ".", + "paths": { + "#lib/*": ["lib/*"] + }, + "composite": true + }, + "include": ["."] +} diff --git a/projects/gateway/tests/.gitkeep b/projects/gateway/tests/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/projects/gateway/tsconfig.eslint.json b/projects/gateway/tsconfig.eslint.json new file mode 100644 index 000000000..388bb593b --- /dev/null +++ b/projects/gateway/tsconfig.eslint.json @@ -0,0 +1,4 @@ +{ + "extends": "../../tsconfig.eslint.json", + "include": ["src", "tests"] +} diff --git a/projects/shared/package.json b/projects/shared/package.json new file mode 100644 index 000000000..ea343af93 --- /dev/null +++ b/projects/shared/package.json @@ -0,0 +1,39 @@ +{ + "name": "wolfstar-shared", + "version": "7.0.0", + "description": "Shared utilities for Skyra's projects", + "author": "WolfStar Project", + "license": "Apache-2.0", + "private": true, + "main": "dist/index.js", + "types": "dist/index.d.ts", + "exports": { + "import": "./dist/index.js", + "types": "./dist/index.d.ts" + }, + "type": "module", + "imports": { + "#lib/*": "./dist/lib/*.js" + }, + "scripts": { + "build": "tsc -b src", + "dev": "pnpm build && pnpm start", + "watch": "tsc -b src -w", + "prisma:generate": "pnpm prisma generate", + "clean": "node scripts/clean.mjs", + "start": "node --enable-source-maps dist/main.js" + }, + "dependencies": { + "@discordjs/collection": "^1.0.1", + "@sapphire/pieces": "^3.3.5", + "@sapphire/result": "^2.1.1", + "@sapphire/utilities": "^3.8.0", + "@vladfrangu/async_event_emitter": "^2.0.1", + "discord-api-types": "^0.37.0", + "ioredis": "^5.2.2", + "ix": "^5.0.0" + }, + "devDependencies": { + "typescript": "^4.7.4" + } +} diff --git a/projects/shared/scripts/clean.mjs b/projects/shared/scripts/clean.mjs new file mode 100644 index 000000000..1bd25ff10 --- /dev/null +++ b/projects/shared/scripts/clean.mjs @@ -0,0 +1,8 @@ +import { rm } from 'node:fs/promises'; + +const rootFolder = new URL('../', import.meta.url); +const distFolder = new URL('dist/', rootFolder); + +const options = { recursive: true, force: true }; + +await rm(distFolder, options); diff --git a/projects/shared/src/index.ts b/projects/shared/src/index.ts new file mode 100644 index 000000000..84e8a7a41 --- /dev/null +++ b/projects/shared/src/index.ts @@ -0,0 +1,51 @@ +export { + AliasPiece, + AliasPieceOptions, + AliasStore, + container, + LoaderError, + MissingExportsError, + Piece, + Store, + StoreRegistry, + StoreRegistryEntries +} from '@sapphire/pieces'; +export { default as Redis, type RedisOptions } from 'ioredis'; +export type { HashScopedCache } from './lib/cache/base/HashScopedCache.js'; +export type { ScopedCache } from './lib/cache/base/ScopedCache.js'; +export * from './lib/cache/Cache.js'; +export type { CacheChannels } from './lib/cache/CacheChannels.js'; +export type { CacheEmojis } from './lib/cache/CacheEmojis.js'; +export type { CacheGuilds } from './lib/cache/CacheGuilds.js'; +export type { CacheMembers } from './lib/cache/CacheMembers.js'; +export type { CacheMessages } from './lib/cache/CacheMessages.js'; +export type { CacheRoles } from './lib/cache/CacheRoles.js'; +export type { CacheStickers } from './lib/cache/CacheStickers.js'; +export * from './lib/cache/structures/Channel.js'; +export * from './lib/cache/structures/Emoji.js'; +export * from './lib/cache/structures/Guild.js'; +export * from './lib/cache/structures/interfaces/BufferEncodable.js'; +export * from './lib/cache/structures/interfaces/Identifiable.js'; +export * from './lib/cache/structures/interfaces/IStructure.js'; +export * from './lib/cache/structures/interfaces/JsonEncodable.js'; +export * from './lib/cache/structures/Member.js'; +export * from './lib/cache/structures/Message.js'; +export * from './lib/cache/structures/Role.js'; +export * from './lib/cache/structures/Sticker.js'; +export * from './lib/cache/structures/unions/channel/base/GuildBasedChannel.js'; +export * from './lib/cache/structures/unions/channel/base/GuildTextBasedChannel.js'; +export * from './lib/cache/structures/unions/channel/GuildCategoryChannel.js'; +export * from './lib/cache/structures/unions/channel/GuildForumChannel.js'; +export * from './lib/cache/structures/unions/channel/GuildNewsChannel.js'; +export * from './lib/cache/structures/unions/channel/GuildTextChannel.js'; +export * from './lib/cache/structures/unions/channel/GuildThreadChannel.js'; +export * from './lib/cache/structures/unions/channel/GuildVoiceChannel.js'; +export * from './lib/cache/structures/values/GuildFeatures.js'; +export * from './lib/common/bits.js'; +export * from './lib/common/util.js'; +export * from './lib/data/Reader.js'; +export * from './lib/data/Writer.js'; +export * from './lib/messaging/MessageBroker.js'; +export * from './lib/messaging/RedisMessage.js'; +export * from './lib/structures/Listener.js'; +export * from './lib/structures/ListenerStore.js'; diff --git a/projects/shared/src/lib/cache/Cache.ts b/projects/shared/src/lib/cache/Cache.ts new file mode 100644 index 000000000..7dbb0b5cf --- /dev/null +++ b/projects/shared/src/lib/cache/Cache.ts @@ -0,0 +1,41 @@ +import { isNullishOrEmpty, type Nullish } from '@sapphire/utilities'; +import type { Redis } from 'ioredis'; +import { CacheChannels } from './CacheChannels.js'; +import { CacheEmojis } from './CacheEmojis.js'; +import { CacheGuilds } from './CacheGuilds.js'; +import { CacheMembers } from './CacheMembers.js'; +import { CacheMessages } from './CacheMessages.js'; +import { CacheRoles } from './CacheRoles.js'; +import { CacheStickers } from './CacheStickers.js'; + +export class Cache { + public readonly client: Redis; + public readonly channels: CacheChannels; + public readonly emojis: CacheEmojis; + public readonly guilds: CacheGuilds; + public readonly members: CacheMembers; + public readonly messages: CacheMessages; + public readonly roles: CacheRoles; + public readonly stickers: CacheStickers; + protected readonly prefix: string; + + public constructor(options: Cache.Options) { + this.client = options.client; + this.prefix = isNullishOrEmpty(options.prefix) ? '' : `${options.prefix}:`; + + this.channels = new CacheChannels(this); + this.emojis = new CacheEmojis(this); + this.guilds = new CacheGuilds(this); + this.members = new CacheMembers(this); + this.messages = new CacheMessages(this); + this.roles = new CacheRoles(this); + this.stickers = new CacheStickers(this); + } +} + +export namespace Cache { + export interface Options { + client: Redis; + prefix?: string | Nullish; + } +} diff --git a/projects/shared/src/lib/cache/CacheChannels.ts b/projects/shared/src/lib/cache/CacheChannels.ts new file mode 100644 index 000000000..26e647613 --- /dev/null +++ b/projects/shared/src/lib/cache/CacheChannels.ts @@ -0,0 +1,7 @@ +import { Channel } from './structures/Channel.js'; +import { HashScopedCache } from './base/HashScopedCache.js'; + +export class CacheChannels extends HashScopedCache { + public readonly tail = ':channels'; + public readonly structure = Channel; +} diff --git a/projects/shared/src/lib/cache/CacheEmojis.ts b/projects/shared/src/lib/cache/CacheEmojis.ts new file mode 100644 index 000000000..47f11470c --- /dev/null +++ b/projects/shared/src/lib/cache/CacheEmojis.ts @@ -0,0 +1,7 @@ +import { Emoji } from './structures/Emoji.js'; +import { HashScopedCache } from './base/HashScopedCache.js'; + +export class CacheEmojis extends HashScopedCache { + public readonly tail = ':emojis'; + public readonly structure = Emoji; +} diff --git a/projects/shared/src/lib/cache/CacheGuilds.ts b/projects/shared/src/lib/cache/CacheGuilds.ts new file mode 100644 index 000000000..b4fad7ff9 --- /dev/null +++ b/projects/shared/src/lib/cache/CacheGuilds.ts @@ -0,0 +1,72 @@ +import { Collection } from '@discordjs/collection'; +import { isNullish } from '@sapphire/utilities'; +import { count } from 'ix/asynciterable/count.js'; +import { Reader } from '../data/Reader.js'; +import { ScopedCache } from './base/ScopedCache.js'; +import { Guild } from './structures/Guild.js'; + +export class CacheGuilds extends ScopedCache { + public async set(guild: Guild) { + await this.client.set(this.makeId(guild.id), guild.toBuffer()); + } + + public async has(guildId: ScopedCache.Snowflake) { + const data = await this.client.exists(this.makeId(guildId)); + return data === 1; + } + + public async get(guildId: ScopedCache.Snowflake) { + const data = await this.client.getBuffer(this.makeId(guildId)); + return data ? Guild.fromBinary(new Reader(data)) : null; + } + + public async getAll() { + const result = new Collection(); + for await (const guild of this.values()) { + result.set(guild.id, guild); + } + + return result; + } + + public count() { + return count(this.client.scanBufferStream({ match: this.makeId('*'), count: 100 })); + } + + public async remove(guildId: ScopedCache.Snowflake) { + const key = this.makeId(guildId); + const result = await this.client.del(key, `${key}:channels`, `${key}:emojis`, `${key}:members`, `${key}:roles`, `${key}:stickers`); + return result > 0; + } + + public async *keys(): AsyncIterable { + // eslint-disable-next-line @typescript-eslint/dot-notation + const offset = this.parent['prefix'].length; + for await (const id of this.client.scanStream({ match: this.makeId('*'), count: 100 }) as AsyncIterable) { + yield BigInt(id.slice(offset)); + } + } + + public async *values(): AsyncIterable { + const match = this.makeId('*'); + const count = 100; + + let cursor = '0'; + do { + const [next, keys] = await this.client.scanBuffer(cursor, 'MATCH', match, 'COUNT', count); + const buffers = await this.client.mgetBuffer(...keys); + for (const buffer of buffers) { + if (isNullish(buffer)) continue; + yield Guild.fromBinary(new Reader(buffer)); + } + + cursor = next.toString(); + } while (cursor !== '0'); + } + + public async *entries(): AsyncIterable<[id: bigint, value: Guild]> { + for await (const value of this.values()) { + yield [value.id, value]; + } + } +} diff --git a/projects/shared/src/lib/cache/CacheMembers.ts b/projects/shared/src/lib/cache/CacheMembers.ts new file mode 100644 index 000000000..54325196c --- /dev/null +++ b/projects/shared/src/lib/cache/CacheMembers.ts @@ -0,0 +1,7 @@ +import { Member } from './structures/Member.js'; +import { HashScopedCache } from './base/HashScopedCache.js'; + +export class CacheMembers extends HashScopedCache { + public readonly tail = ':members'; + public readonly structure = Member; +} diff --git a/projects/shared/src/lib/cache/CacheMessages.ts b/projects/shared/src/lib/cache/CacheMessages.ts new file mode 100644 index 000000000..667923215 --- /dev/null +++ b/projects/shared/src/lib/cache/CacheMessages.ts @@ -0,0 +1,7 @@ +import { Message } from './structures/Message.js'; +import { HashScopedCache } from './base/HashScopedCache.js'; + +export class CacheMessages extends HashScopedCache { + public readonly tail = ':messages'; + public readonly structure = Message; +} diff --git a/projects/shared/src/lib/cache/CacheRoles.ts b/projects/shared/src/lib/cache/CacheRoles.ts new file mode 100644 index 000000000..a55e94e81 --- /dev/null +++ b/projects/shared/src/lib/cache/CacheRoles.ts @@ -0,0 +1,7 @@ +import { Role } from './structures/Role.js'; +import { HashScopedCache } from './base/HashScopedCache.js'; + +export class CacheRoles extends HashScopedCache { + public readonly tail = ':roles'; + public readonly structure = Role; +} diff --git a/projects/shared/src/lib/cache/CacheStickers.ts b/projects/shared/src/lib/cache/CacheStickers.ts new file mode 100644 index 000000000..82aabae9e --- /dev/null +++ b/projects/shared/src/lib/cache/CacheStickers.ts @@ -0,0 +1,7 @@ +import { Sticker } from './structures/Sticker.js'; +import { HashScopedCache } from './base/HashScopedCache.js'; + +export class CacheStickers extends HashScopedCache { + public readonly tail = ':stickers'; + public readonly structure = Sticker; +} diff --git a/projects/shared/src/lib/cache/base/HashScopedCache.ts b/projects/shared/src/lib/cache/base/HashScopedCache.ts new file mode 100644 index 000000000..5d3a0c216 --- /dev/null +++ b/projects/shared/src/lib/cache/base/HashScopedCache.ts @@ -0,0 +1,154 @@ +import { Collection } from '@discordjs/collection'; +import { isNullish } from '@sapphire/utilities'; +import { Reader } from '../../data/Reader.js'; +import type { IStructure, IStructureConstructor } from '../structures/interfaces/IStructure.js'; +import { ScopedCache } from './ScopedCache.js'; + +export abstract class HashScopedCache extends ScopedCache { + public abstract readonly tail: string; + public abstract readonly structure: IStructureConstructor; + + /** + * Sets an entry to the hashmap. + * @param parentId The parent's ID. + * @param entries The entries to set to the cache. Duplicated entries will be replaced. + */ + public set(parentId: ScopedCache.Snowflake, entries: T | readonly T[]) { + return Array.isArray(entries) ? this.setMany(parentId, entries as readonly T[]) : this.setOne(parentId, entries as T); + } + + /** + * Checks whether or not an ID is in the hashmap. + * @param parentId The parent's ID. + * @param entryId The entry's ID to check. + */ + public async has(parentId: ScopedCache.Snowflake, entryId: ScopedCache.Snowflake) { + const data = await this.client.hexists(this.makeId(parentId), entryId.toString()); + return data === 1; + } + + /** + * Gets an entry by its ID from the hashmap. + * @param parentId The parent's ID. + * @param entryId The entry's ID to retrieve. + * @returns The entry, if any. + */ + public async get(parentId: ScopedCache.Snowflake, entryId: ScopedCache.Snowflake): Promise; + /** + * Gets multiple entries by its ID from the hashmap. + * @param parentId The parent's ID. + * @param entries The IDs of the entries to retrieve. + * @returns The entries inside a Collection, keyed by their ID. + * @remark The IDs of entries that do not exist are dropped. + */ + public async get(parentId: ScopedCache.Snowflake, entries: readonly ScopedCache.Snowflake[]): Promise>; + public async get(parentId: ScopedCache.Snowflake, entries: ScopedCache.Snowflake | readonly ScopedCache.Snowflake[]) { + return Array.isArray(entries) + ? this.getMany(parentId, entries as readonly ScopedCache.Snowflake[]) + : this.getOne(parentId, entries as ScopedCache.Snowflake); + } + + /** + * Gets all the keys from the hashmap. + * @param parentId The parent's ID. + */ + public async keys(parentId: ScopedCache.Snowflake) { + return this.client.hkeys(this.makeId(parentId)); + } + + /** + * Gets all the values from the hashmap. + * @param parentId The parent's ID. + */ + public async values(parentId: ScopedCache.Snowflake) { + const buffers = await this.client.hvalsBuffer(this.makeId(parentId)); + return buffers.map((buffer) => this.structure.fromBinary(new Reader(buffer))); + } + + /** + * Gets all the entries from the hashmap. + * @param parentId The parent's ID. + * @returns The entries inside a Collection, keyed by their ID. + */ + public async entries(parentId: ScopedCache.Snowflake) { + const buffers = await this.client.hvalsBuffer(this.makeId(parentId)); + + const result = new Collection(); + for (const buffer of buffers) { + const channel = this.structure.fromBinary(new Reader(buffer)); + result.set(channel.id, channel); + } + + return result; + } + + /** + * Counts the amount of entries in the hashmap. + * @param parentId The parent's ID. + * @returns The amount of entries the hashmap has. + */ + public count(parentId: ScopedCache.Snowflake) { + return this.client.hlen(this.makeId(parentId)); + } + + /** + * Removes one or more entries from the hashmap. + * @param parentId The parent's ID. + * @param entries The IDs of the entries to remove. + * @returns The amount of entries that were removed. + */ + public async remove(parentId: ScopedCache.Snowflake, entries: ScopedCache.Snowflake | readonly ScopedCache.Snowflake[]) { + const result = await (Array.isArray(entries) + ? this.client.hdel(this.makeId(parentId), ...entries.map((entry: ScopedCache.Snowflake) => entry.toString())) + : this.client.hdel(this.makeId(parentId), entries.toString())); + return result; + } + + /** + * Removes the hashmap from the cache, effectively clearing all of its entries. + * @param parentId The parent's ID. + * @returns Whether or not the hashmap has been cleared. + */ + public async clear(parentId: ScopedCache.Snowflake) { + const result = await this.client.del(this.makeId(parentId)); + return result > 0; + } + + protected override makeId(parentId: ScopedCache.Snowflake) { + // eslint-disable-next-line @typescript-eslint/dot-notation + return `${this.parent['prefix']}${parentId}${this.tail}`; + } + + private async getOne(parentId: ScopedCache.Snowflake, entryId: ScopedCache.Snowflake) { + const data = await this.client.hgetBuffer(this.makeId(parentId), entryId.toString()); + return data ? this.structure.fromBinary(new Reader(data)) : null; + } + + private async getMany(parentId: ScopedCache.Snowflake, entries: readonly ScopedCache.Snowflake[]): Promise> { + const buffers = await this.client.hmgetBuffer(this.makeId(parentId), ...entries.map((entry) => entry.toString())); + + const result = new Collection(); + for (const buffer of buffers) { + if (isNullish(buffer)) continue; + + const channel = this.structure.fromBinary(new Reader(buffer)); + result.set(channel.id, channel); + } + + return result; + } + + private async setOne(parentId: ScopedCache.Snowflake, entry: T) { + await this.client.hset(this.makeId(parentId), entry.id.toString(), entry.toBuffer()); + } + + private async setMany(parentId: ScopedCache.Snowflake, entries: readonly T[]) { + if (entries.length === 0) return; + if (entries.length === 1) return this.setOne(parentId, entries[0]); + await this.client.hmset(this.makeId(parentId), ...entries.flatMap((entry) => [entry.id.toString(), entry.toBuffer()])); + } +} + +export namespace HashScopedCache { + export type Snowflake = ScopedCache.Snowflake; +} diff --git a/projects/shared/src/lib/cache/base/ScopedCache.ts b/projects/shared/src/lib/cache/base/ScopedCache.ts new file mode 100644 index 000000000..427e32b95 --- /dev/null +++ b/projects/shared/src/lib/cache/base/ScopedCache.ts @@ -0,0 +1,22 @@ +import type { Cache } from '../Cache.js'; + +export abstract class ScopedCache { + public readonly parent: Cache; + + public constructor(parent: Cache) { + this.parent = parent; + } + + protected get client() { + return this.parent.client; + } + + protected makeId(parentId: ScopedCache.Snowflake) { + // eslint-disable-next-line @typescript-eslint/dot-notation + return `${this.parent['prefix']}${parentId}`; + } +} + +export namespace ScopedCache { + export type Snowflake = bigint | string; +} diff --git a/projects/shared/src/lib/cache/structures/Channel.ts b/projects/shared/src/lib/cache/structures/Channel.ts new file mode 100644 index 000000000..d456f526e --- /dev/null +++ b/projects/shared/src/lib/cache/structures/Channel.ts @@ -0,0 +1,95 @@ +import { ChannelType, type APIChannel } from 'discord-api-types/v10'; +import type { Reader } from '../../data/Reader.js'; +import { GuildCategoryChannel } from './unions/channel/GuildCategoryChannel.js'; +import { GuildForumChannel } from './unions/channel/GuildForumChannel.js'; +import { GuildNewsChannel } from './unions/channel/GuildNewsChannel.js'; +import { GuildTextChannel } from './unions/channel/GuildTextChannel.js'; +import { GuildThreadChannel } from './unions/channel/GuildThreadChannel.js'; +import { GuildVoiceChannel } from './unions/channel/GuildVoiceChannel.js'; + +export type Channel = + | GuildCategoryChannel // + | GuildForumChannel + | GuildNewsChannel + | GuildTextChannel + | GuildThreadChannel + | GuildVoiceChannel; + +export namespace Channel { + export type Type = + | GuildTextChannel.Type + | GuildVoiceChannel.Type + | GuildCategoryChannel.Type + | GuildNewsChannel.Type + | GuildForumChannel.Type + | GuildThreadChannel.Type; + + export type Json = + | GuildTextChannel.Json + | GuildVoiceChannel.Json + | GuildCategoryChannel.Json + | GuildNewsChannel.Json + | GuildForumChannel.Json + | GuildThreadChannel.Json; + + export type Data = + | GuildTextChannel.Data + | GuildVoiceChannel.Data + | GuildCategoryChannel.Data + | GuildNewsChannel.Data + | GuildForumChannel.Data + | GuildThreadChannel.Data; + + export function fromAPI(data: APIChannel): Channel { + const { type } = data; + switch (type) { + case ChannelType.GuildText: + return GuildTextChannel.fromAPI(data); + case ChannelType.GuildStageVoice: + case ChannelType.GuildVoice: + return GuildVoiceChannel.fromAPI(data); + case ChannelType.GuildCategory: + return GuildCategoryChannel.fromAPI(data); + case ChannelType.GuildNews: + return GuildNewsChannel.fromAPI(data); + case ChannelType.GuildForum: + return GuildForumChannel.fromAPI(data); + case ChannelType.GuildPublicThread: + case ChannelType.GuildPrivateThread: + case ChannelType.GuildNewsThread: + return GuildThreadChannel.fromAPI(data); + default: + throw new RangeError(`Unsupported channel type: ${type}`); + } + } + + export function fromBinary(reader: Reader): Channel { + // Channel data is encoded in the following way: + // + // | 0 | 1...8 | 9 | 10 | ... + // | Null | ID (u64) | Null | Type (u8) | ... + // + // So in order to read which type the channel is, we read the 10th bit, + // which will contain the value for `channel.type`: + const type = reader.data.readUInt8(10) as ChannelType; + switch (type) { + case ChannelType.GuildText: + return GuildTextChannel.fromBinary(reader); + case ChannelType.GuildStageVoice: + case ChannelType.GuildVoice: + return GuildVoiceChannel.fromBinary(reader); + case ChannelType.GuildCategory: + return GuildCategoryChannel.fromBinary(reader); + case ChannelType.GuildNews: + return GuildNewsChannel.fromBinary(reader); + case ChannelType.GuildForum: + return GuildForumChannel.fromBinary(reader); + case ChannelType.GuildPublicThread: + case ChannelType.GuildPrivateThread: + case ChannelType.GuildNewsThread: + return GuildThreadChannel.fromBinary(reader); + default: + throw new RangeError(`Unsupported channel type: ${type}`); + } + } +} diff --git a/projects/shared/src/lib/cache/structures/Emoji.ts b/projects/shared/src/lib/cache/structures/Emoji.ts new file mode 100644 index 000000000..c79014cb1 --- /dev/null +++ b/projects/shared/src/lib/cache/structures/Emoji.ts @@ -0,0 +1,98 @@ +import type { Nullish } from '@sapphire/utilities'; +import type { APIEmoji } from 'discord-api-types/v10'; +import { arrayEquals } from '../../common/util.js'; +import type { Reader } from '../../data/Reader.js'; +import { Writer } from '../../data/Writer.js'; +import type { IStructure } from './interfaces/IStructure.js'; + +export class Emoji implements IStructure { + public readonly id: bigint; + public readonly name: string; + public readonly animated: boolean | null; + public readonly available: boolean | null; + public readonly managed: boolean | null; + public readonly requireColons: boolean | null; + public readonly roles: readonly bigint[]; + + public constructor(data: Emoji.Data) { + this.id = data.id; + this.name = data.name; + this.animated = data.animated ?? null; + this.available = data.available ?? null; + this.managed = data.managed ?? null; + this.requireColons = data.requireColons ?? null; + this.roles = data.roles; + } + + public equals(other: Emoji) { + return ( + this.id === other.id && + this.name === other.name && + this.animated === other.animated && + this.available === other.available && + this.managed === other.managed && + this.requireColons === other.requireColons && + arrayEquals(this.roles, other.roles) + ); + } + + public toBuffer(): Buffer { + return new Writer(100) + .u64(this.id) + .string(this.name) + .bool(this.animated) + .bool(this.available) + .bool(this.managed) + .bool(this.requireColons) + .array(this.roles, (buffer, value) => buffer.u64(value)).trimmed; + } + + public toJSON(): Emoji.Json { + return { + id: this.id.toString(), + name: this.name, + animated: this.animated ?? undefined, + available: this.available ?? undefined, + managed: this.managed ?? undefined, + require_colons: this.requireColons ?? undefined, + roles: this.roles.length === 0 ? undefined : this.roles.map((role) => role.toString()) + }; + } + + public static fromAPI(data: Emoji.Json): Emoji { + return new Emoji({ + id: BigInt(data.id!), + name: data.name!, + animated: data.animated, + available: data.available, + managed: data.managed, + requireColons: data.require_colons, + roles: data.roles?.map((roles) => BigInt(roles)) ?? [] + }); + } + + public static fromBinary(reader: Reader): Emoji { + return new Emoji({ + id: reader.u64()!, + name: reader.string()!, + animated: reader.bool(), + available: reader.bool(), + managed: reader.bool(), + requireColons: reader.bool(), + roles: reader.array((reader) => reader.u64()!) + }); + } +} + +export namespace Emoji { + export type Json = APIEmoji; + export interface Data { + id: bigint; + name: string; + animated?: boolean | Nullish; + available?: boolean | Nullish; + managed?: boolean | Nullish; + requireColons?: boolean | Nullish; + roles: readonly bigint[]; + } +} diff --git a/projects/shared/src/lib/cache/structures/Guild.ts b/projects/shared/src/lib/cache/structures/Guild.ts new file mode 100644 index 000000000..1b02d9e6a --- /dev/null +++ b/projects/shared/src/lib/cache/structures/Guild.ts @@ -0,0 +1,266 @@ +import type { Nullish } from '@sapphire/utilities'; +import type { + APIGuild, + GuildDefaultMessageNotifications, + GuildExplicitContentFilter, + GuildHubType, + GuildMFALevel, + GuildNSFWLevel, + GuildPremiumTier, + GuildSystemChannelFlags, + GuildVerificationLevel +} from 'discord-api-types/v10'; +import { normalizeNullable } from '../../common/util.js'; +import type { Reader } from '../../data/Reader.js'; +import { Writer } from '../../data/Writer.js'; +import type { IStructure } from './interfaces/IStructure.js'; +import { fromFeatures, toFeatures } from './values/GuildFeatures.js'; + +export class Guild implements IStructure { + public readonly id: bigint; + public readonly afkChannelId: bigint | null; + public readonly afkTimeout: number; + public readonly banner: string | null; + public readonly defaultMessageNotifications: GuildDefaultMessageNotifications; + public readonly description: string | null; + public readonly discoverySplash: string | null; + public readonly explicitContentFilter: GuildExplicitContentFilter; + public readonly hubType: GuildHubType | null; + public readonly icon: string | null; + public readonly features: number; + public readonly maxMembers: number | null; + public readonly maxPresences: number | null; + public readonly maxVideoChannelUsers: number | null; + public readonly mfaLevel: GuildMFALevel; + public readonly name: string; + public readonly nsfwLevel: GuildNSFWLevel; + public readonly ownerId: bigint; + public readonly preferredLocale: string; + public readonly premiumProgressBarEnabled: boolean; + public readonly premiumSubscriptionCount: number | null; + public readonly premiumTier: GuildPremiumTier; + public readonly publicUpdatesChannelId: bigint | null; + public readonly rulesChannelId: bigint | null; + public readonly splash: string | null; + public readonly systemChannelFlags: GuildSystemChannelFlags; + public readonly systemChannelId: bigint | null; + public readonly vanityUrlCode: string | null; + public readonly verificationLevel: GuildVerificationLevel; + public readonly widgetChannelId: bigint | null; + public readonly widgetEnabled: boolean | null; + + public constructor(data: Guild.Data) { + this.id = data.id; + this.afkChannelId = data.afkChannelId ?? null; + this.afkTimeout = data.afkTimeout; + this.banner = data.banner ?? null; + this.defaultMessageNotifications = data.defaultMessageNotifications; + this.description = data.description ?? null; + this.discoverySplash = data.discoverySplash ?? null; + this.explicitContentFilter = data.explicitContentFilter; + this.hubType = data.hubType ?? null; + this.icon = data.icon ?? null; + this.features = data.features; + this.maxMembers = data.maxMembers ?? null; + this.maxPresences = data.maxPresences ?? null; + this.maxVideoChannelUsers = data.maxVideoChannelUsers ?? null; + this.mfaLevel = data.mfaLevel; + this.name = data.name; + this.nsfwLevel = data.nsfwLevel; + this.ownerId = data.ownerId; + this.preferredLocale = data.preferredLocale; + this.premiumProgressBarEnabled = data.premiumProgressBarEnabled; + this.premiumSubscriptionCount = data.premiumSubscriptionCount ?? null; + this.premiumTier = data.premiumTier; + this.publicUpdatesChannelId = data.publicUpdatesChannelId ?? null; + this.rulesChannelId = data.rulesChannelId ?? null; + this.splash = data.splash ?? null; + this.systemChannelFlags = data.systemChannelFlags; + this.systemChannelId = data.systemChannelId ?? null; + this.vanityUrlCode = data.vanityUrlCode ?? null; + this.verificationLevel = data.verificationLevel; + this.widgetChannelId = data.widgetChannelId ?? null; + this.widgetEnabled = data.widgetEnabled ?? null; + } + + public toBuffer(): Buffer { + return new Writer(200) + .u64(this.id) + .u64(this.afkChannelId) + .i32(this.afkTimeout) + .string(this.banner) + .u8(this.defaultMessageNotifications) + .string(this.description) + .string(this.discoverySplash) + .u8(this.explicitContentFilter) + .u8(this.hubType) + .string(this.icon) + .u32(this.features) + .u32(this.maxMembers) + .u32(this.maxPresences) + .u32(this.maxVideoChannelUsers) + .u8(this.mfaLevel) + .string(this.name) + .u8(this.nsfwLevel) + .u64(this.ownerId) + .string(this.preferredLocale) + .bool(this.premiumProgressBarEnabled) + .u16(this.premiumSubscriptionCount) + .u8(this.premiumTier) + .u64(this.publicUpdatesChannelId) + .u64(this.rulesChannelId) + .string(this.splash) + .u8(this.systemChannelFlags) + .u64(this.systemChannelId) + .string(this.vanityUrlCode) + .u8(this.verificationLevel) + .u64(this.widgetChannelId) + .bool(this.widgetEnabled).trimmed; + } + + public toJSON(): Guild.Json { + return { + id: this.id.toString(), + afk_channel_id: this.afkChannelId?.toString() ?? null, + afk_timeout: this.afkTimeout, + banner: this.banner, + default_message_notifications: this.defaultMessageNotifications, + description: this.description, + discovery_splash: this.discoverySplash, + explicit_content_filter: this.explicitContentFilter, + hub_type: this.hubType, + icon: this.icon, + features: fromFeatures(this.features), + max_members: this.maxMembers ?? undefined, + max_presences: this.maxPresences ?? undefined, + max_video_channel_users: this.maxVideoChannelUsers ?? undefined, + mfa_level: this.mfaLevel, + name: this.name, + nsfw_level: this.nsfwLevel, + owner_id: this.ownerId.toString(), + preferred_locale: this.preferredLocale, + premium_progress_bar_enabled: this.premiumProgressBarEnabled, + premium_subscription_count: this.premiumSubscriptionCount ?? undefined, + premium_tier: this.premiumTier, + public_updates_channel_id: this.publicUpdatesChannelId?.toString() ?? null, + rules_channel_id: this.rulesChannelId?.toString() ?? null, + splash: this.splash, + system_channel_flags: this.systemChannelFlags, + system_channel_id: this.systemChannelId?.toString() ?? null, + vanity_url_code: this.vanityUrlCode, + verification_level: this.verificationLevel, + widget_channel_id: this.widgetChannelId?.toString(), + widget_enabled: this.widgetEnabled ?? undefined + }; + } + + public static fromAPI(data: Guild.Json): Guild { + return new Guild({ + id: BigInt(data.id), + afkChannelId: normalizeNullable(data.afk_channel_id, BigInt), + afkTimeout: data.afk_timeout, + banner: data.banner, + defaultMessageNotifications: data.default_message_notifications, + description: data.description, + discoverySplash: data.discovery_splash, + explicitContentFilter: data.explicit_content_filter, + hubType: data.hub_type, + icon: data.icon, + features: toFeatures(data.features), + maxMembers: data.max_members, + maxPresences: data.max_presences, + maxVideoChannelUsers: data.max_video_channel_users, + mfaLevel: data.mfa_level, + name: data.name, + nsfwLevel: data.nsfw_level, + ownerId: BigInt(data.owner_id), + preferredLocale: data.preferred_locale, + premiumProgressBarEnabled: data.premium_progress_bar_enabled, + premiumSubscriptionCount: data.premium_subscription_count, + premiumTier: data.premium_tier, + publicUpdatesChannelId: normalizeNullable(data.public_updates_channel_id, BigInt), + rulesChannelId: normalizeNullable(data.rules_channel_id, BigInt), + splash: data.splash, + systemChannelFlags: data.system_channel_flags, + systemChannelId: normalizeNullable(data.system_channel_id, BigInt), + vanityUrlCode: data.vanity_url_code, + verificationLevel: data.verification_level, + widgetChannelId: normalizeNullable(data.widget_channel_id, BigInt), + widgetEnabled: data.widget_enabled + }); + } + + public static fromBinary(reader: Reader): Guild { + return new Guild({ + id: reader.u64()!, + afkChannelId: reader.u64(), + afkTimeout: reader.i32()!, + banner: reader.string(), + defaultMessageNotifications: reader.u8()!, + description: reader.string(), + discoverySplash: reader.string(), + explicitContentFilter: reader.u8()!, + hubType: reader.u8(), + icon: reader.string(), + features: reader.u32()!, + maxMembers: reader.u32(), + maxPresences: reader.u32(), + maxVideoChannelUsers: reader.u32(), + mfaLevel: reader.u8()!, + name: reader.string()!, + nsfwLevel: reader.u8()!, + ownerId: reader.u64()!, + preferredLocale: reader.string()!, + premiumProgressBarEnabled: reader.bool()!, + premiumSubscriptionCount: reader.u16(), + premiumTier: reader.u8()!, + publicUpdatesChannelId: reader.u64(), + rulesChannelId: reader.u64(), + splash: reader.string(), + systemChannelFlags: reader.u8()!, + systemChannelId: reader.u64(), + vanityUrlCode: reader.string(), + verificationLevel: reader.u8()!, + widgetChannelId: reader.u64(), + widgetEnabled: reader.bool() + }); + } +} + +export namespace Guild { + export type Json = Omit; + + export interface Data { + id: bigint; + afkChannelId?: bigint | Nullish; + afkTimeout: number; + banner?: string | Nullish; + defaultMessageNotifications: GuildDefaultMessageNotifications; + description?: string | Nullish; + discoverySplash?: string | Nullish; + explicitContentFilter: GuildExplicitContentFilter; + hubType?: GuildHubType | Nullish; + icon?: string | Nullish; + features: number; + maxMembers?: number | Nullish; + maxPresences?: number | Nullish; + maxVideoChannelUsers?: number | Nullish; + mfaLevel: GuildMFALevel; + name: string; + nsfwLevel: GuildNSFWLevel; + ownerId: bigint; + preferredLocale: string; + premiumProgressBarEnabled: boolean; + premiumSubscriptionCount?: number | Nullish; + premiumTier: GuildPremiumTier; + publicUpdatesChannelId?: bigint | Nullish; + rulesChannelId?: bigint | Nullish; + splash?: string | Nullish; + systemChannelFlags: GuildSystemChannelFlags; + systemChannelId?: bigint | Nullish; + vanityUrlCode?: string | Nullish; + verificationLevel: GuildVerificationLevel; + widgetChannelId?: bigint | Nullish; + widgetEnabled?: boolean | Nullish; + } +} diff --git a/projects/shared/src/lib/cache/structures/Member.ts b/projects/shared/src/lib/cache/structures/Member.ts new file mode 100644 index 000000000..482fad13c --- /dev/null +++ b/projects/shared/src/lib/cache/structures/Member.ts @@ -0,0 +1,171 @@ +import { isNullish, type Nullish } from '@sapphire/utilities'; +import type { Nullable } from 'discord-api-types/utils/internals.js'; +import type { APIGuildMember, APIUser } from 'discord-api-types/v10'; +import { defaultOptional, fromTimestamp, toTimestamp } from '../../common/util.js'; +import type { Reader } from '../../data/Reader.js'; +import { Writer } from '../../data/Writer.js'; +import type { IStructure } from './interfaces/IStructure.js'; + +export class Member implements IStructure { + public readonly id: bigint; + public readonly username: string; + public readonly discriminator: number; + public readonly bot: boolean | null; + public readonly avatar: string | null; + public readonly flags: number | null; + public readonly nickname: string | null; + public readonly guildAvatar: string | null; + public readonly roles: readonly bigint[]; + public readonly joinedAt: number | null; + public readonly premiumSince: number | null; + public readonly deaf: boolean | null; + public readonly mute: boolean | null; + public readonly pending: boolean | null; + public readonly communicationDisabledUntil: number | null; + + public constructor(data: Member.Data) { + this.id = data.id; + this.username = data.username; + this.discriminator = data.discriminator; + this.bot = data.bot ?? null; + this.avatar = data.avatar ?? null; + this.flags = data.flags ?? null; + this.nickname = data.nickname ?? null; + this.guildAvatar = data.guildAvatar ?? null; + this.roles = data.roles; + this.joinedAt = data.joinedAt ?? null; + this.premiumSince = data.premiumSince ?? null; + this.deaf = data.deaf ?? null; + this.mute = data.mute ?? null; + this.pending = data.pending ?? null; + this.communicationDisabledUntil = data.communicationDisabledUntil ?? null; + } + + public patch(data: Partial) { + return new Member({ + id: this.id, + username: defaultOptional(data.user?.username, this.username), + discriminator: defaultOptional(data.user?.discriminator, this.discriminator, Number), + bot: defaultOptional(data.user?.bot, this.bot), + avatar: defaultOptional(data.user?.avatar, this.avatar), + flags: defaultOptional(data.user?.public_flags, this.flags), + nickname: defaultOptional(data.nick, this.nickname), + guildAvatar: defaultOptional(data.avatar, this.guildAvatar), + roles: defaultOptional(data.roles, this.roles, (values) => values.map((role) => BigInt(role))), + joinedAt: defaultOptional(data.joined_at, this.joinedAt, toTimestamp)!, + premiumSince: defaultOptional(data.premium_since, this.premiumSince, toTimestamp), + deaf: defaultOptional(data.deaf, this.deaf), + mute: defaultOptional(data.mute, this.mute), + pending: defaultOptional(data.pending, this.pending), + communicationDisabledUntil: defaultOptional(data.communication_disabled_until, this.communicationDisabledUntil, toTimestamp) + }); + } + + public toBuffer(): Buffer { + return new Writer(100) + .u64(this.id) + .string(this.username) + .u16(this.discriminator) + .bool(this.bot) + .string(this.avatar) + .u32(this.flags) + .string(this.nickname) + .string(this.guildAvatar) + .array(this.roles, (buffer, value) => buffer.u64(value)) + .date(this.joinedAt) + .date(this.premiumSince) + .bool(this.deaf) + .bool(this.mute) + .bool(this.pending) + .date(this.communicationDisabledUntil).trimmed; + } + + public toJSON(): Member.Json { + return { + user: { + id: this.id.toString(), + username: this.username, + discriminator: this.discriminator.toString().padStart(4, '0'), + bot: this.bot ?? undefined, + avatar: this.avatar, + public_flags: this.flags ?? undefined + }, + nick: this.nickname, + avatar: this.guildAvatar, + roles: this.roles.map((role) => role.toString()), + joined_at: fromTimestamp(this.joinedAt), + premium_since: fromTimestamp(this.premiumSince), + deaf: this.deaf ?? undefined, + mute: this.mute ?? undefined, + pending: this.pending ?? undefined, + communication_disabled_until: fromTimestamp(this.communicationDisabledUntil) + }; + } + + public static fromAPI(data: Member.Json, user?: APIUser): Member { + user ??= data.user; + if (isNullish(user)) throw new TypeError('Expected user to be defined'); + + return new Member({ + id: BigInt(user.id), + username: user.username, + discriminator: Number(user.discriminator), + bot: user.bot, + avatar: user.avatar, + flags: user.public_flags, + nickname: data.nick, + guildAvatar: data.avatar, + roles: data.roles.map((role) => BigInt(role)), + joinedAt: toTimestamp(data.joined_at), + premiumSince: toTimestamp(data.premium_since), + deaf: data.deaf, + mute: data.mute, + pending: data.pending, + communicationDisabledUntil: toTimestamp(data.communication_disabled_until) + }); + } + + public static fromBinary(reader: Reader): Member { + return new Member({ + id: reader.u64()!, + username: reader.string()!, + discriminator: reader.u16()!, + bot: reader.bool(), + avatar: reader.string(), + flags: reader.u32(), + nickname: reader.string(), + guildAvatar: reader.string(), + roles: reader.array((reader) => reader.u64()!), + joinedAt: reader.date()!, + premiumSince: reader.date(), + deaf: reader.bool()!, + mute: reader.bool()!, + pending: reader.bool(), + communicationDisabledUntil: reader.date() + }); + } +} + +export namespace Member { + export type Json = Omit & + Partial> & + Nullable>; + + export interface Data { + id: bigint; + username: string; + discriminator: number; + bot?: boolean | Nullish; + avatar?: string | Nullish; + flags?: number | Nullish; + nickname?: string | Nullish; + guildAvatar?: string | Nullish; + roles: readonly bigint[]; + joinedAt?: number | Nullish; + premiumSince?: number | Nullish; + deaf?: boolean | Nullish; + mute?: boolean | Nullish; + pending?: boolean | Nullish; + communicationDisabledUntil?: number | Nullish; + } +} diff --git a/projects/shared/src/lib/cache/structures/Message.ts b/projects/shared/src/lib/cache/structures/Message.ts new file mode 100644 index 000000000..52b28dca2 --- /dev/null +++ b/projects/shared/src/lib/cache/structures/Message.ts @@ -0,0 +1,242 @@ +import type { Nullish } from '@sapphire/utilities'; +import type { APIAttachment, APIEmbed, APIEmbedAuthor, APIMessage, APIUser } from 'discord-api-types/v10'; +import { defaultOptional, fromTimestamp, normalizeArray, normalizeNullable, normalizeOptional, toTimestamp } from '../../common/util.js'; +import type { Reader } from '../../data/Reader.js'; +import { Writer } from '../../data/Writer.js'; +import type { IStructure } from './interfaces/IStructure.js'; + +export class Message implements IStructure { + public readonly id: bigint; + public readonly channelId: bigint; + public readonly author: Message.DataUser; + public readonly content: string; + public readonly attachments: Message.DataAttachment[]; + public readonly embeds: Message.DataEmbed[]; + + public constructor(data: Message.Data) { + this.id = data.id; + this.channelId = data.channelId; + this.author = data.author; + this.content = data.content; + this.attachments = data.attachments ?? []; + this.embeds = data.embeds ?? []; + } + + public patch(data: Partial) { + return new Message({ + id: this.id, + channelId: this.channelId, + author: defaultOptional(data.author, this.author, (author) => Message.mapAuthor(author)), + content: defaultOptional(data.content, this.content), + attachments: defaultOptional(data.attachments, this.attachments, (attachments) => Message.mapAttachments(attachments)), + embeds: defaultOptional(data.embeds, this.embeds, (embeds) => Message.mapEmbeds(embeds)) + }); + } + + public toBuffer(): Buffer { + return new Writer(400) + .u64(this.id) + .u64(this.channelId) + .object(this.author, (buffer, value) => buffer.u64(value.id).string(value.username).u16(value.discriminator).string(value.avatar)) + .string(this.content) + .array(this.attachments, (buffer, value) => buffer.u64(value.id).string(value.name).string(value.url)) + .array(this.embeds, (buffer, value) => + buffer + .object(value.author, (buffer, author) => buffer.string(author.name).string(author.icon).string(author.url)) + .string(value.description) + .array(value.fields, (buffer, value) => buffer.string(value.name).string(value.value)) + .object(value.footer, (buffer, value) => buffer.string(value.text).string(value.icon)) + .object(value.image, (buffer, value) => buffer.string(value.url)) + .object(value.thumbnail, (buffer, value) => buffer.string(value.url)) + .date(value.timestamp) + .string(value.title) + .string(value.url) + ).trimmed; + } + + public toJSON(): Message.Json { + return { + id: this.id.toString(), + channel_id: this.channelId.toString(), + author: { + id: this.author.id.toString(), + username: this.author.username, + discriminator: this.author.discriminator.toString().padStart(4, '0'), + avatar: this.author.avatar ?? null + }, + content: this.content, + attachments: this.attachments.map((entry) => ({ + id: entry.id.toString(), + filename: entry.name, + url: entry.url + })), + embeds: this.embeds.map( + (entry): APIEmbed => ({ + author: normalizeOptional( + entry.author, + (entry): APIEmbedAuthor => ({ + name: entry.name, + icon_url: entry.icon ?? undefined, + url: entry.url ?? undefined + }) + ), + description: entry.description ?? undefined, + fields: entry.fields ?? undefined, + footer: entry.footer ?? undefined, + image: entry.image ?? undefined, + thumbnail: entry.thumbnail ?? undefined, + timestamp: fromTimestamp(entry.timestamp) ?? undefined, + title: entry.title ?? undefined, + url: entry.url ?? undefined + }) + ) + }; + } + + public static fromAPI(data: Message.Json): Message { + return new Message({ + id: BigInt(data.id!), + channelId: BigInt(data.channel_id), + author: Message.mapAuthor(data.author), + content: data.content, + attachments: Message.mapAttachments(data.attachments ?? []), + embeds: Message.mapEmbeds(data.embeds) + }); + } + + public static fromBinary(reader: Reader): Message { + return new Message({ + id: reader.u64()!, + channelId: reader.u64()!, + author: reader.object((reader) => ({ + id: reader.u64()!, + username: reader.string()!, + discriminator: reader.u16()!, + avatar: reader.string() + }))!, + content: reader.string()!, + attachments: reader.array((reader) => ({ + id: reader.u64()!, + name: reader.string()!, + url: reader.string()! + }))!, + embeds: reader.array( + (reader): Message.DataEmbed => ({ + author: reader.object( + (reader): Message.DataEmbedAuthor => ({ name: reader.string()!, icon: reader.string(), url: reader.string() }) + ), + description: reader.string(), + fields: reader.array((reader): Message.DataEmbedField => ({ name: reader.string()!, value: reader.string()! })), + footer: reader.object((reader): Message.DataEmbedFooter => ({ text: reader.string()!, icon: reader.string() })), + image: reader.object((reader): Message.DataEmbedImage => ({ url: reader.string()! })), + thumbnail: reader.object((reader): Message.DataEmbedThumbnail => ({ url: reader.string()! })), + timestamp: reader.date(), + title: reader.string(), + url: reader.string() + }) + ) + }); + } + + private static mapAuthor(author: APIUser) { + return { + id: BigInt(author.id), + username: author.username, + discriminator: Number(author.discriminator), + avatar: author.avatar + }; + } + + private static mapAttachments(attachments: Message.JsonAttachment[]) { + return attachments.map((attachment) => ({ + id: BigInt(attachment.id), + name: attachment.filename, + url: attachment.url + })); + } + + private static mapEmbeds(embeds: APIEmbed[]) { + return embeds.map( + (embed): Message.DataEmbed => ({ + author: normalizeNullable( + embed.author, + (author): Message.DataEmbedAuthor => ({ name: author.name, icon: author.icon_url, url: author.url }) + ), + description: embed.description, + fields: normalizeArray(embed.fields, (field): Message.DataEmbedField => ({ name: field.name, value: field.value })), + footer: normalizeNullable(embed.footer, (footer): Message.DataEmbedFooter => ({ text: footer.text, icon: footer.icon_url })), + image: normalizeNullable(embed.image, (image): Message.DataEmbedImage => ({ url: image.url })), + thumbnail: normalizeNullable(embed.thumbnail, (thumbnail): Message.DataEmbedThumbnail => ({ url: thumbnail.url })), + timestamp: toTimestamp(embed.timestamp), + title: embed.title, + url: embed.url + }) + ); + } +} + +export namespace Message { + export interface Json extends Pick { + attachments?: JsonAttachment[]; + } + + export type JsonAttachment = Pick; + + export interface Data { + id: bigint; + channelId: bigint; + author: DataUser; + content: string; + attachments?: DataAttachment[] | Nullish; + embeds?: DataEmbed[] | Nullish; + } + + export interface DataUser { + id: bigint; + username: string; + discriminator: number; + avatar?: string | Nullish; + } + + export interface DataAttachment { + id: bigint; + name: string; + url: string; + } + + export interface DataEmbed { + author?: DataEmbedAuthor | Nullish; + description?: string | Nullish; + fields?: DataEmbedField[] | Nullish; + footer?: DataEmbedFooter | Nullish; + image?: DataEmbedImage | Nullish; + thumbnail?: DataEmbedThumbnail | Nullish; + timestamp?: number | Nullish; + title?: string | Nullish; + url?: string | Nullish; + } + + export interface DataEmbedFooter { + text: string; + icon?: string | Nullish; + } + + export interface DataEmbedImage { + url: string; + } + + export interface DataEmbedThumbnail { + url: string; + } + + export interface DataEmbedAuthor { + name: string; + url?: string | Nullish; + icon?: string | Nullish; + } + + export interface DataEmbedField { + name: string; + value: string; + } +} diff --git a/projects/shared/src/lib/cache/structures/Role.ts b/projects/shared/src/lib/cache/structures/Role.ts new file mode 100644 index 000000000..65e01428f --- /dev/null +++ b/projects/shared/src/lib/cache/structures/Role.ts @@ -0,0 +1,138 @@ +import type { Nullish } from '@sapphire/utilities'; +import type { APIRole } from 'discord-api-types/v10'; +import { normalizeNullable } from '../../common/util.js'; +import type { Reader } from '../../data/Reader.js'; +import { Writer } from '../../data/Writer.js'; +import type { IStructure } from './interfaces/IStructure.js'; + +export class Role implements IStructure { + public readonly id: bigint; + public readonly name: string; + public readonly color: number; + public readonly hoist: boolean; + public readonly icon: string | null; + public readonly managed: boolean; + public readonly mentionable: boolean; + public readonly permissions: bigint; + public readonly position: number; + public readonly tags: Role.DataTags | null; + public readonly unicodeEmoji: string | null; + + public constructor(data: Role.Data) { + this.id = data.id; + this.name = data.name; + this.color = data.color; + this.hoist = data.hoist; + this.icon = data.icon ?? null; + this.managed = data.managed; + this.mentionable = data.mentionable; + this.permissions = data.permissions; + this.position = data.position; + this.tags = data.tags ?? null; + this.unicodeEmoji = data.unicodeEmoji ?? null; + } + + public toBuffer(): Buffer { + return new Writer(100) + .u64(this.id) + .string(this.name) + .u32(this.color) + .bool(this.hoist) + .string(this.icon) + .bool(this.managed) + .bool(this.mentionable) + .u64(this.permissions) + .u16(this.position) + .object(this.tags, (buffer, value) => + buffer + .u64(value.botId) + .bool(value.premiumSubscriber === null) + .u64(value.integrationId) + ) + .string(this.unicodeEmoji).trimmed; + } + + public toJSON(): Role.Json { + return { + id: this.id.toString(), + name: this.name, + color: this.color, + hoist: this.hoist, + icon: this.icon, + managed: this.managed, + mentionable: this.mentionable, + permissions: this.permissions.toString(), + position: this.position, + tags: + normalizeNullable(this.tags, (value) => ({ + bot_id: value.botId?.toString() ?? undefined, + premium_subscriber: value.premiumSubscriber ? null : undefined, + integration_id: value.integrationId?.toString() ?? undefined + })) ?? undefined, + unicode_emoji: this.unicodeEmoji + }; + } + + public static fromAPI(data: Role.Json): Role { + return new Role({ + id: BigInt(data.id), + name: data.name, + color: data.color, + hoist: data.hoist, + icon: data.icon, + managed: data.managed, + mentionable: data.mentionable, + permissions: BigInt(data.permissions), + position: data.position, + tags: normalizeNullable(data.tags, (value) => ({ + botId: normalizeNullable(value.bot_id, BigInt), + premiumSubscriber: value.premium_subscriber, + integrationId: normalizeNullable(value.integration_id, BigInt) + })), + unicodeEmoji: data.unicode_emoji + }); + } + + public static fromBinary(reader: Reader): Role { + return new Role({ + id: reader.u64()!, + name: reader.string()!, + color: reader.u32()!, + hoist: reader.bool()!, + icon: reader.string(), + managed: reader.bool()!, + mentionable: reader.bool()!, + permissions: reader.u64()!, + position: reader.u16()!, + tags: reader.object((reader) => ({ + botId: reader.u64(), + premiumSubscriber: reader.bool(), + integrationId: reader.u64() + })), + unicodeEmoji: reader.string() + }); + } +} + +export namespace Role { + export type Json = APIRole; + export interface Data { + id: bigint; + name: string; + color: number; + hoist: boolean; + icon?: string | Nullish; + managed: boolean; + mentionable: boolean; + permissions: bigint; + position: number; + tags?: DataTags | Nullish; + unicodeEmoji?: string | Nullish; + } + + export interface DataTags { + botId?: bigint | Nullish; + premiumSubscriber?: boolean | Nullish; + integrationId?: bigint | Nullish; + } +} diff --git a/projects/shared/src/lib/cache/structures/Sticker.ts b/projects/shared/src/lib/cache/structures/Sticker.ts new file mode 100644 index 000000000..4eb19a7e5 --- /dev/null +++ b/projects/shared/src/lib/cache/structures/Sticker.ts @@ -0,0 +1,106 @@ +import type { Nullish } from '@sapphire/utilities'; +import type { APISticker, StickerFormatType, StickerType } from 'discord-api-types/v10'; +import { normalizeNullable } from '../../common/util.js'; +import type { Reader } from '../../data/Reader.js'; +import { Writer } from '../../data/Writer.js'; +import type { IStructure } from './interfaces/IStructure.js'; + +export class Sticker implements IStructure { + public readonly id: bigint; + public readonly packId: bigint | null; + public readonly name: string; + public readonly description: string | null; + public readonly tags: string; + public readonly type: StickerType; + public readonly formatType: StickerFormatType; + public readonly available: boolean | null; + + public constructor(data: Sticker.Data) { + this.id = data.id; + this.packId = data.packId ?? null; + this.name = data.name; + this.description = data.description ?? null; + this.tags = data.tags; + this.type = data.type; + this.formatType = data.formatType; + this.available = data.available ?? null; + } + + public equals(other: Sticker) { + return ( + this.id === other.id && + this.packId === other.packId && + this.name === other.name && + this.description === other.description && + this.tags === other.tags && + this.type === other.type && + this.formatType === other.formatType && + this.available === other.available + ); + } + + public toBuffer(): Buffer { + return new Writer(100) + .u64(this.id) + .u64(this.packId) + .string(this.name) + .string(this.description) + .string(this.tags) + .u8(this.type) + .u8(this.formatType) + .bool(this.available).trimmed; + } + + public toJSON(): Sticker.Json { + return { + id: this.id.toString(), + pack_id: this.packId?.toString() ?? undefined, + name: this.name, + description: this.description, + tags: this.tags, + type: this.type, + format_type: this.formatType, + available: this.available ?? undefined + }; + } + + public static fromAPI(data: Sticker.Json): Sticker { + return new Sticker({ + id: BigInt(data.id), + packId: normalizeNullable(data.pack_id, BigInt), + name: data.name, + description: data.description, + tags: data.tags, + type: data.type, + formatType: data.format_type, + available: data.available + }); + } + + public static fromBinary(reader: Reader): Sticker { + return new Sticker({ + id: reader.u64()!, + packId: reader.u64(), + name: reader.string()!, + description: reader.string(), + tags: reader.string()!, + type: reader.u8()!, + formatType: reader.u8()!, + available: reader.bool() + }); + } +} + +export namespace Sticker { + export type Json = APISticker; + export interface Data { + id: bigint; + packId?: bigint | Nullish; + name: string; + description?: string | Nullish; + tags: string; + type: StickerType; + formatType: StickerFormatType; + available?: boolean | Nullish; + } +} diff --git a/projects/shared/src/lib/cache/structures/interfaces/BufferEncodable.ts b/projects/shared/src/lib/cache/structures/interfaces/BufferEncodable.ts new file mode 100644 index 000000000..bdf23c4f8 --- /dev/null +++ b/projects/shared/src/lib/cache/structures/interfaces/BufferEncodable.ts @@ -0,0 +1,3 @@ +export interface BufferEncodable { + toBuffer(): Buffer; +} diff --git a/projects/shared/src/lib/cache/structures/interfaces/IStructure.ts b/projects/shared/src/lib/cache/structures/interfaces/IStructure.ts new file mode 100644 index 000000000..5f7137985 --- /dev/null +++ b/projects/shared/src/lib/cache/structures/interfaces/IStructure.ts @@ -0,0 +1,12 @@ +import type { NonNullObject } from '@sapphire/utilities'; +import type { Reader } from '../../../data/Reader.js'; +import type { BufferEncodable } from './BufferEncodable.js'; +import type { Identifiable } from './Identifiable.js'; +import type { JsonEncodable } from './JsonEncodable.js'; + +export interface IStructure extends BufferEncodable, JsonEncodable, Identifiable {} + +export interface IStructureConstructor { + fromAPI(data: NonNullObject): T; + fromBinary(reader: Reader): T; +} diff --git a/projects/shared/src/lib/cache/structures/interfaces/Identifiable.ts b/projects/shared/src/lib/cache/structures/interfaces/Identifiable.ts new file mode 100644 index 000000000..55d2307ce --- /dev/null +++ b/projects/shared/src/lib/cache/structures/interfaces/Identifiable.ts @@ -0,0 +1,3 @@ +export interface Identifiable { + readonly id: bigint; +} diff --git a/projects/shared/src/lib/cache/structures/interfaces/JsonEncodable.ts b/projects/shared/src/lib/cache/structures/interfaces/JsonEncodable.ts new file mode 100644 index 000000000..a163bcc37 --- /dev/null +++ b/projects/shared/src/lib/cache/structures/interfaces/JsonEncodable.ts @@ -0,0 +1,5 @@ +import type { NonNullObject } from '@sapphire/utilities'; + +export interface JsonEncodable { + toJSON(): NonNullObject; +} diff --git a/projects/shared/src/lib/cache/structures/unions/channel/GuildCategoryChannel.ts b/projects/shared/src/lib/cache/structures/unions/channel/GuildCategoryChannel.ts new file mode 100644 index 000000000..604a9c8ba --- /dev/null +++ b/projects/shared/src/lib/cache/structures/unions/channel/GuildCategoryChannel.ts @@ -0,0 +1,19 @@ +import type { APIGuildCategoryChannel, ChannelType } from 'discord-api-types/v10'; +import type { Reader } from '../../../../data/Reader.js'; +import { GuildBasedChannel, guildBasedFromAPIShared, guildBasedFromBinaryShared } from './base/GuildBasedChannel.js'; + +export class GuildCategoryChannel extends GuildBasedChannel { + public static fromAPI(data: GuildCategoryChannel.Json): GuildCategoryChannel { + return new GuildCategoryChannel(guildBasedFromAPIShared(data)); + } + + public static fromBinary(reader: Reader): GuildCategoryChannel { + return new GuildCategoryChannel(guildBasedFromBinaryShared(reader)); + } +} + +export namespace GuildCategoryChannel { + export type Type = ChannelType.GuildCategory; + export type Json = Omit; + export interface Data extends GuildBasedChannel.Data {} +} diff --git a/projects/shared/src/lib/cache/structures/unions/channel/GuildForumChannel.ts b/projects/shared/src/lib/cache/structures/unions/channel/GuildForumChannel.ts new file mode 100644 index 000000000..bdf4f033f --- /dev/null +++ b/projects/shared/src/lib/cache/structures/unions/channel/GuildForumChannel.ts @@ -0,0 +1,19 @@ +import type { APIGuildForumChannel, ChannelType } from 'discord-api-types/v10'; +import type { Reader } from '../../../../data/Reader.js'; +import { GuildBasedChannel, guildBasedFromAPIShared, guildBasedFromBinaryShared } from './base/GuildBasedChannel.js'; + +export class GuildForumChannel extends GuildBasedChannel { + public static fromAPI(data: GuildForumChannel.Json): GuildForumChannel { + return new GuildForumChannel(guildBasedFromAPIShared(data)); + } + + public static fromBinary(reader: Reader): GuildForumChannel { + return new GuildForumChannel(guildBasedFromBinaryShared(reader)); + } +} + +export namespace GuildForumChannel { + export type Type = ChannelType.GuildForum; + export type Json = Omit; + export interface Data extends GuildBasedChannel.Data {} +} diff --git a/projects/shared/src/lib/cache/structures/unions/channel/GuildNewsChannel.ts b/projects/shared/src/lib/cache/structures/unions/channel/GuildNewsChannel.ts new file mode 100644 index 000000000..c2918c1f8 --- /dev/null +++ b/projects/shared/src/lib/cache/structures/unions/channel/GuildNewsChannel.ts @@ -0,0 +1,19 @@ +import type { APINewsChannel, ChannelType } from 'discord-api-types/v10'; +import type { Reader } from '../../../../data/Reader.js'; +import { GuildTextBasedChannel, guildTextBasedFromAPIShared, guildTextBasedFromBinaryShared } from './base/GuildTextBasedChannel.js'; + +export class GuildNewsChannel extends GuildTextBasedChannel { + public static fromAPI(data: GuildNewsChannel.Json): GuildNewsChannel { + return new GuildNewsChannel(guildTextBasedFromAPIShared(data)); + } + + public static fromBinary(reader: Reader): GuildNewsChannel { + return new GuildNewsChannel(guildTextBasedFromBinaryShared(reader)); + } +} + +export namespace GuildNewsChannel { + export type Type = ChannelType.GuildNews; + export type Json = Omit; + export interface Data extends GuildTextBasedChannel.Data {} +} diff --git a/projects/shared/src/lib/cache/structures/unions/channel/GuildTextChannel.ts b/projects/shared/src/lib/cache/structures/unions/channel/GuildTextChannel.ts new file mode 100644 index 000000000..4dda9194d --- /dev/null +++ b/projects/shared/src/lib/cache/structures/unions/channel/GuildTextChannel.ts @@ -0,0 +1,46 @@ +import type { Nullish } from '@sapphire/utilities'; +import type { APITextChannel, ChannelType } from 'discord-api-types/v10'; +import type { Reader } from '../../../../data/Reader.js'; +import { GuildTextBasedChannel, guildTextBasedFromAPIShared, guildTextBasedFromBinaryShared } from './base/GuildTextBasedChannel.js'; + +export class GuildTextChannel extends GuildTextBasedChannel { + public readonly rateLimitPerUser: number | null; + + public constructor(data: GuildTextChannel.Data) { + super(data); + this.rateLimitPerUser = data.rateLimitPerUser ?? null; + } + + public override toBuffer(): Buffer { + return this.toBufferShared().u16(this.rateLimitPerUser).trimmed; + } + + public override toJSON(): GuildTextChannel.Json { + return { + ...super.toJSON(), + rate_limit_per_user: this.rateLimitPerUser ?? undefined + }; + } + + public static fromAPI(data: GuildTextChannel.Json): GuildTextChannel { + return new GuildTextChannel({ + ...guildTextBasedFromAPIShared(data), + rateLimitPerUser: data.rate_limit_per_user + }); + } + + public static fromBinary(reader: Reader): GuildTextChannel { + return new GuildTextChannel({ + ...guildTextBasedFromBinaryShared(reader), + rateLimitPerUser: reader.u16() + }); + } +} + +export namespace GuildTextChannel { + export type Type = ChannelType.GuildText; + export type Json = Omit; + export interface Data extends GuildTextBasedChannel.Data { + rateLimitPerUser?: number | Nullish; + } +} diff --git a/projects/shared/src/lib/cache/structures/unions/channel/GuildThreadChannel.ts b/projects/shared/src/lib/cache/structures/unions/channel/GuildThreadChannel.ts new file mode 100644 index 000000000..c5ead1572 --- /dev/null +++ b/projects/shared/src/lib/cache/structures/unions/channel/GuildThreadChannel.ts @@ -0,0 +1,99 @@ +import type { Nullish } from '@sapphire/utilities'; +import type { APIThreadChannel, ChannelType, ThreadAutoArchiveDuration } from 'discord-api-types/v10'; +import { fromTimestamp, normalizeNullable, toTimestamp } from '../../../../common/util.js'; +import type { Reader } from '../../../../data/Reader.js'; +import { GuildBasedChannel, guildBasedFromAPIShared, guildBasedFromBinaryShared } from './base/GuildBasedChannel.js'; + +export class GuildThreadChannel extends GuildBasedChannel { + public readonly ownerId: bigint | null; + public readonly rateLimitPerUser: number | null; + public readonly archived: boolean; + public readonly autoArchiveDuration: ThreadAutoArchiveDuration; + public readonly archiveAt: number; + public readonly locked: boolean | null; + public readonly invitable: boolean | null; + public readonly createdAt: number | null; + + public constructor(data: GuildThreadChannel.Data) { + super(data); + this.ownerId = data.ownerId ?? null; + this.rateLimitPerUser = data.rateLimitPerUser ?? null; + this.archived = data.archived; + this.autoArchiveDuration = data.autoArchiveDuration; + this.archiveAt = data.archiveAt; + this.locked = data.locked ?? null; + this.invitable = data.invitable ?? null; + this.createdAt = data.createdAt ?? null; + } + + public override toBuffer(): Buffer { + return this.toBufferShared() + .u64(this.ownerId) + .u16(this.rateLimitPerUser) + .bool(this.archived) + .u16(this.autoArchiveDuration) + .date(this.archiveAt) + .bool(this.locked) + .bool(this.invitable) + .date(this.createdAt).trimmed; + } + + public override toJSON(): GuildThreadChannel.Json { + return { + ...super.toJSON(), + owner_id: this.ownerId?.toString(), + rate_limit_per_user: this.rateLimitPerUser ?? undefined, + thread_metadata: { + archived: this.archived, + auto_archive_duration: this.autoArchiveDuration, + archive_timestamp: fromTimestamp(this.archiveAt), + locked: this.locked ?? undefined, + invitable: this.invitable ?? undefined, + create_timestamp: fromTimestamp(this.createdAt) ?? undefined + } + }; + } + + public static fromAPI(data: GuildThreadChannel.Json): GuildThreadChannel { + return new GuildThreadChannel({ + ...guildBasedFromAPIShared(data), + ownerId: normalizeNullable(data.owner_id, BigInt), + rateLimitPerUser: data.rate_limit_per_user, + archived: data.thread_metadata!.archived, + autoArchiveDuration: data.thread_metadata!.auto_archive_duration, + archiveAt: toTimestamp(data.thread_metadata!.archive_timestamp), + locked: data.thread_metadata!.locked, + invitable: data.thread_metadata!.invitable, + createdAt: toTimestamp(data.thread_metadata!.create_timestamp) + }); + } + + public static fromBinary(reader: Reader): GuildThreadChannel { + return new GuildThreadChannel({ + ...guildBasedFromBinaryShared(reader), + ownerId: reader.u64(), + rateLimitPerUser: reader.u16(), + archived: reader.bool()!, + autoArchiveDuration: reader.u16()!, + archiveAt: reader.date()!, + locked: reader.bool(), + invitable: reader.bool(), + createdAt: reader.date() + }); + } +} + +export namespace GuildThreadChannel { + export type Type = ChannelType.GuildPublicThread | ChannelType.GuildPrivateThread | ChannelType.GuildNewsThread; + export type Json = Omit; + export interface Data extends GuildBasedChannel.Data { + ownerId?: bigint | Nullish; + rateLimitPerUser?: number | Nullish; + archived: boolean; + autoArchiveDuration: ThreadAutoArchiveDuration; + archiveAt: number; + locked?: boolean | Nullish; + invitable?: boolean | Nullish; + createdAt?: number | Nullish; + } +} diff --git a/projects/shared/src/lib/cache/structures/unions/channel/GuildVoiceChannel.ts b/projects/shared/src/lib/cache/structures/unions/channel/GuildVoiceChannel.ts new file mode 100644 index 000000000..f4cda89ff --- /dev/null +++ b/projects/shared/src/lib/cache/structures/unions/channel/GuildVoiceChannel.ts @@ -0,0 +1,64 @@ +import type { Nullish } from '@sapphire/utilities'; +import type { APIVoiceChannel, ChannelType, VideoQualityMode } from 'discord-api-types/v10'; +import type { Reader } from '../../../../data/Reader.js'; +import { GuildBasedChannel, guildBasedFromAPIShared, guildBasedFromBinaryShared } from './base/GuildBasedChannel.js'; + +export class GuildVoiceChannel extends GuildBasedChannel { + public readonly bitrate: number | null; + public readonly userLimit: number | null; + public readonly rtcRegion: string | null; + public readonly videoQualityMode: VideoQualityMode | null; + + public constructor(data: GuildVoiceChannel.Data) { + super(data); + this.bitrate = data.bitrate ?? null; + this.userLimit = data.userLimit ?? null; + this.rtcRegion = data.rtcRegion ?? null; + this.videoQualityMode = data.videoQualityMode ?? null; + } + + public override toBuffer(): Buffer { + return this.toBufferShared().u32(this.bitrate).u32(this.userLimit).string(this.rtcRegion).u8(this.videoQualityMode).trimmed; + } + + public override toJSON(): GuildVoiceChannel.Json { + return { + ...super.toJSON(), + bitrate: this.bitrate ?? undefined, + user_limit: this.userLimit ?? undefined, + rtc_region: this.rtcRegion, + video_quality_mode: this.videoQualityMode ?? undefined + }; + } + + public static fromAPI(data: GuildVoiceChannel.Json): GuildVoiceChannel { + return new GuildVoiceChannel({ + ...guildBasedFromAPIShared(data), + bitrate: data.bitrate, + userLimit: data.user_limit, + rtcRegion: data.rtc_region, + videoQualityMode: data.video_quality_mode + }); + } + + public static fromBinary(reader: Reader): GuildVoiceChannel { + return new GuildVoiceChannel({ + ...guildBasedFromBinaryShared(reader), + bitrate: reader.u32(), + userLimit: reader.u32(), + rtcRegion: reader.string(), + videoQualityMode: reader.u8() + }); + } +} + +export namespace GuildVoiceChannel { + export type Type = ChannelType.GuildStageVoice | ChannelType.GuildVoice; + export type Json = Omit; + export interface Data extends GuildBasedChannel.Data { + bitrate?: number | Nullish; + userLimit?: number | Nullish; + rtcRegion?: string | Nullish; + videoQualityMode?: VideoQualityMode | Nullish; + } +} diff --git a/projects/shared/src/lib/cache/structures/unions/channel/base/GuildBasedChannel.ts b/projects/shared/src/lib/cache/structures/unions/channel/base/GuildBasedChannel.ts new file mode 100644 index 000000000..a2328360b --- /dev/null +++ b/projects/shared/src/lib/cache/structures/unions/channel/base/GuildBasedChannel.ts @@ -0,0 +1,126 @@ +import type { Nullish } from '@sapphire/utilities'; +import type { APIGuildChannel, APIOverwrite, ChannelFlags, ChannelType, OverwriteType } from 'discord-api-types/v10'; +import { normalizeNullable } from '../../../../../common/util.js'; +import type { Reader } from '../../../../../data/Reader.js'; +import { Writer } from '../../../../../data/Writer.js'; +import type { IStructure } from '../../../interfaces/IStructure.js'; + +export abstract class GuildBasedChannel implements IStructure { + public readonly id: bigint; + public readonly type: T; + public readonly name: string; + public readonly flags: ChannelFlags | null; + public readonly nsfw: boolean | null; + public readonly parentId: bigint | null; + public readonly permissionOverwrites: readonly GuildBasedChannel.DataPermissionOverwrite[]; + public readonly position: number | null; + + public constructor(data: GuildBasedChannel.Data) { + this.id = data.id; + this.type = data.type; + this.name = data.name; + this.flags = data.flags ?? null; + this.nsfw = data.nsfw ?? null; + this.parentId = data.parentId ?? null; + this.permissionOverwrites = data.permissionOverwrites ?? []; + this.position = data.position ?? null; + } + + public toBuffer(): Buffer { + return this.toBufferShared().trimmed; + } + + public toJSON(): GuildBasedChannel.Json { + return { + id: this.id.toString(), + type: this.type, + name: this.name, + flags: this.flags ?? undefined, + nsfw: this.nsfw ?? undefined, + parent_id: this.parentId?.toString(), + permission_overwrites: this.permissionOverwrites.map( + (entry): APIOverwrite => ({ + id: entry.id.toString(), + type: entry.type, + allow: entry.allow.toString(), + deny: entry.deny.toString() + }) + ), + position: this.position ?? undefined + }; + } + + protected toBufferShared(): Writer { + return new Writer(100) + .u64(this.id) + .u8(this.type) + .string(this.name) + .u8(this.flags) + .bool(this.nsfw) + .u64(this.parentId) + .array(this.permissionOverwrites, (buffer, value) => buffer.u64(value.id).u8(value.type).u64(value.allow).u64(value.deny)) + .u16(this.position); + } +} + +export namespace GuildBasedChannel { + export type Json = Omit, 'guild_id'>; + + export interface Data { + id: bigint; + name: string; + type: T; + flags?: ChannelFlags | Nullish; + nsfw?: boolean | Nullish; + parentId?: bigint | Nullish; + permissionOverwrites?: readonly DataPermissionOverwrite[] | Nullish; + position?: number | Nullish; + } + + export interface DataPermissionOverwrite { + id: bigint; + type: OverwriteType; + allow: bigint; + deny: bigint; + } +} + +export function guildBasedFromAPIShared(data: GuildBasedChannel.Json): GuildBasedChannel.Data { + return { + id: BigInt(data.id), + type: data.type, + name: data.name!, + flags: data.flags, + nsfw: data.nsfw, + parentId: normalizeNullable(data.parent_id, BigInt), + permissionOverwrites: data.permission_overwrites?.map( + (value): GuildBasedChannel.DataPermissionOverwrite => ({ + id: BigInt(value.id), + type: value.type, + allow: BigInt(value.allow), + deny: BigInt(value.deny) + }) + ), + position: data.position + }; +} + +export function guildBasedFromBinaryShared(reader: Reader): GuildBasedChannel.Data { + return { + id: reader.u64()!, + type: reader.u8()! as T, + name: reader.string()!, + flags: reader.u8(), + nsfw: reader.bool(), + parentId: reader.u64(), + permissionOverwrites: reader.array( + (reader): GuildBasedChannel.DataPermissionOverwrite => ({ + id: reader.u64()!, + type: reader.u8()!, + allow: reader.u64()!, + deny: reader.u64()! + }) + ), + position: reader.u16() + }; +} diff --git a/projects/shared/src/lib/cache/structures/unions/channel/base/GuildTextBasedChannel.ts b/projects/shared/src/lib/cache/structures/unions/channel/base/GuildTextBasedChannel.ts new file mode 100644 index 000000000..a72e4b573 --- /dev/null +++ b/projects/shared/src/lib/cache/structures/unions/channel/base/GuildTextBasedChannel.ts @@ -0,0 +1,55 @@ +import type { Nullish } from '@sapphire/utilities'; +import type { APIGuildTextChannel, GuildTextChannelType, ThreadAutoArchiveDuration } from 'discord-api-types/v10'; +import type { Reader } from '../../../../../data/Reader.js'; +import type { Writer } from '../../../../../data/Writer.js'; +import { GuildBasedChannel, guildBasedFromAPIShared } from './GuildBasedChannel.js'; + +export abstract class GuildTextBasedChannel extends GuildBasedChannel { + public readonly defaultAutoArchiveDuration: ThreadAutoArchiveDuration | null; + public readonly topic: string | null; + + public constructor(data: GuildTextBasedChannel.Data) { + super(data); + this.defaultAutoArchiveDuration = data.defaultAutoArchiveDuration ?? null; + this.topic = data.topic ?? null; + } + + public override toJSON(): GuildTextBasedChannel.Json { + return { + ...super.toJSON(), + default_auto_archive_duration: this.defaultAutoArchiveDuration ?? undefined, + topic: this.topic + }; + } + + protected override toBufferShared(): Writer { + return super.toBufferShared().u32(this.defaultAutoArchiveDuration).string(this.topic); + } +} + +export namespace GuildTextBasedChannel { + export type Json = Omit, 'guild_id' | 'last_message_id'>; + + export interface Data extends GuildBasedChannel.Data { + defaultAutoArchiveDuration?: ThreadAutoArchiveDuration | Nullish; + topic?: string | Nullish; + } + + export type DataPermissionOverwrite = GuildBasedChannel.DataPermissionOverwrite; +} + +export function guildTextBasedFromAPIShared(data: GuildTextBasedChannel.Json): GuildTextBasedChannel.Data { + return { + ...guildBasedFromAPIShared(data), + defaultAutoArchiveDuration: data.default_auto_archive_duration, + topic: data.topic + }; +} + +export function guildTextBasedFromBinaryShared(reader: Reader): GuildTextBasedChannel.Data { + return { + ...guildTextBasedFromBinaryShared(reader), + defaultAutoArchiveDuration: reader.u32(), + topic: reader.string() + }; +} diff --git a/projects/shared/src/lib/cache/structures/values/GuildFeatures.ts b/projects/shared/src/lib/cache/structures/values/GuildFeatures.ts new file mode 100644 index 000000000..61766d51e --- /dev/null +++ b/projects/shared/src/lib/cache/structures/values/GuildFeatures.ts @@ -0,0 +1,47 @@ +import { isNullishOrZero } from '@sapphire/utilities'; +import type { GuildFeature } from 'discord-api-types/v10'; +import { bitHas } from '../../../common/bits.js'; + +export const GuildFeatureBits = { + ANIMATED_BANNER: 1 << 0, + ANIMATED_ICON: 1 << 1, + BANNER: 1 << 2, + COMMUNITY: 1 << 3, + DISCOVERABLE: 1 << 4, + FEATURABLE: 1 << 5, + HAS_DIRECTORY_ENTRY: 1 << 6, + HUB: 1 << 7, + INVITE_SPLASH: 1 << 8, + LINKED_TO_HUB: 1 << 9, + MEMBER_VERIFICATION_GATE_ENABLED: 1 << 10, + MONETIZATION_ENABLED: 1 << 11, + MORE_STICKERS: 1 << 12, + NEWS: 1 << 13, + PARTNERED: 1 << 14, + PREVIEW_ENABLED: 1 << 15, + PRIVATE_THREADS: 1 << 16, + RELAY_ENABLED: 1 << 17, + ROLE_ICONS: 1 << 18, + TICKETED_EVENTS_ENABLED: 1 << 19, + VANITY_URL: 1 << 20, + VERIFIED: 1 << 21, + VIP_REGIONS: 1 << 22, + WELCOME_SCREEN_ENABLED: 1 << 23 +} as const; + +export const GuildFeatureEntries = Object.entries(GuildFeatureBits) as [feature: GuildFeature, bit: number][]; + +export function toFeatures(features: readonly GuildFeature[]) { + return features.reduce((bits, feature) => bits | (GuildFeatureBits[feature] ?? 0), 0); +} + +export function fromFeatures(value: number): GuildFeature[] { + if (isNullishOrZero(value)) return []; + + const features: GuildFeature[] = []; + for (const [feature, bit] of GuildFeatureEntries) { + if (bitHas(value, bit)) features.push(feature); + } + + return features; +} diff --git a/projects/shared/src/lib/common/bits.ts b/projects/shared/src/lib/common/bits.ts new file mode 100644 index 000000000..e43f97627 --- /dev/null +++ b/projects/shared/src/lib/common/bits.ts @@ -0,0 +1,3 @@ +export function bitHas(value: T, bit: T) { + return (value & bit) === bit; +} diff --git a/projects/shared/src/lib/common/util.ts b/projects/shared/src/lib/common/util.ts new file mode 100644 index 000000000..8405dbadd --- /dev/null +++ b/projects/shared/src/lib/common/util.ts @@ -0,0 +1,48 @@ +import { isNullish, type Nullish } from '@sapphire/utilities'; + +export function arrayEquals(a: readonly T[], b: readonly T[]): boolean { + return a.length === b.length && a.every((value, index) => b[index] === value); +} + +export function isDefined(value: Value): value is Exclude { + return value !== undefined; +} + +export function defaultOptional(value: Value | undefined, fallback: Value): Value; +export function defaultOptional(value: Value | undefined, fallback: Return, cb: (value: Value) => Return): Return; +export function defaultOptional(value: Value | undefined, fallback: Return, cb?: (value: Value) => Return): Value | Return { + return value === undefined ? fallback : typeof cb === 'function' ? cb(value) : value; +} + +export function normalizeNullable(value: Value | Nullish, cb: (value: Value) => Return): Return | null { + return isNullish(value) ? null : cb(value); +} + +export function normalizeOptional(value: Value | Nullish, cb: (value: Value) => Return): Return | undefined { + return isNullish(value) ? undefined : cb(value); +} + +export function normalizeArray(values: readonly Value[] | Nullish, cb: (value: Value) => Return): Return[] | null { + return isNullish(values) ? null : values.map((value) => cb(value)); +} + +export function toTimestamp(value: string | number): number; +export function toTimestamp(value: string | number | Nullish): number | null; +export function toTimestamp(value: string | number | Nullish): number | null { + switch (typeof value) { + case 'number': + return value; + case 'string': + return Date.parse(value); + case 'bigint': + return Number(value); + default: + return null; + } +} + +export function fromTimestamp(value: number): string; +export function fromTimestamp(value: number | Nullish): string | null; +export function fromTimestamp(value: number | Nullish): string | null { + return typeof value === 'number' ? new Date(value).toISOString() : null; +} diff --git a/projects/shared/src/lib/data/Reader.ts b/projects/shared/src/lib/data/Reader.ts new file mode 100644 index 000000000..03e075836 --- /dev/null +++ b/projects/shared/src/lib/data/Reader.ts @@ -0,0 +1,97 @@ +import type { NonNullObject } from '@sapphire/utilities'; + +const decoder = new TextDecoder(); + +export class Reader { + public readonly data: Buffer; + private offset = 0; + + public constructor(data: Buffer) { + this.data = data; + } + + public bool(): boolean | null { + if (this.readNull()) return null; + return this.data.readUInt8(this.offset++) === 1; + } + + public i8(): number | null { + if (this.readNull()) return null; + return this.data.readInt8(this.offset++); + } + + public u8(): number | null { + if (this.readNull()) return null; + return this.data.readUInt8(this.offset++); + } + + public u16(): number | null { + if (this.readNull()) return null; + const value = this.data.readUInt16LE(this.offset); + this.offset += 2; + return value; + } + + public i32(): number | null { + if (this.readNull()) return null; + const value = this.data.readInt32LE(this.offset); + this.offset += 4; + return value; + } + + public u32(): number | null { + if (this.readNull()) return null; + const value = this.data.readUInt32LE(this.offset); + this.offset += 4; + return value; + } + + public u64(): bigint | null { + if (this.readNull()) return null; + const value = this.data.readBigUInt64LE(this.offset); + this.offset += 8; + return value; + } + + public string(): string | null { + if (this.readNull()) return null; + + const length = this.data.readUInt32LE(this.offset); + this.offset += 4; + + const string = decoder.decode(this.data.subarray(this.offset, this.offset + length)); + this.offset += length; + return string; + } + + public date(): number | null { + if (this.readNull()) return null; + const value = this.data.readBigUInt64LE(this.offset); + this.offset += 8; + return Number(value); + } + + public array(cb: (buffer: this) => T): T[] { + if (this.readNull()) return []; + + const length = this.data.readUInt32LE(this.offset); + this.offset += 4; + + const values: T[] = []; + for (let i = 0; i < length; i++) { + values.push(cb(this)); + } + + return values; + } + + public object(cb: (buffer: this) => T): T | null { + if (this.readNull()) return null; + + return cb(this); + } + + private readNull() { + return this.data.readUInt8(this.offset++); + } +} diff --git a/projects/shared/src/lib/data/Writer.ts b/projects/shared/src/lib/data/Writer.ts new file mode 100644 index 000000000..e75ca98d5 --- /dev/null +++ b/projects/shared/src/lib/data/Writer.ts @@ -0,0 +1,147 @@ +import { isNullish, isNullishOrEmpty, type NonNullObject, type Nullish } from '@sapphire/utilities'; + +const encoder = new TextEncoder(); + +export class Writer { + private data: Buffer; + private offset = 0; + + public constructor(size: number) { + this.data = Buffer.alloc(size); + } + + public get raw() { + return this.data; + } + + public get trimmed() { + return this.data.subarray(0, this.offset); + } + + public bool(value: boolean | Nullish) { + if (isNullish(value)) return this.writeNull(); + + this.ensure(2); + this.offset += this.data.writeUInt8(1, this.offset); + this.offset += this.data.writeUInt8(value ? 1 : 0, this.offset); + + return this; + } + + public i8(value: number | Nullish) { + if (isNullish(value)) return this.writeNull(); + + this.ensure(2); + this.offset += this.data.writeUInt8(1, this.offset); + this.offset += this.data.writeInt8(value, this.offset); + + return this; + } + + public u8(value: number | Nullish) { + if (isNullish(value)) return this.writeNull(); + + this.ensure(2); + this.offset += this.data.writeUInt8(1, this.offset); + this.offset += this.data.writeUInt8(value, this.offset); + + return this; + } + + public u16(value: number | Nullish) { + if (isNullish(value)) return this.writeNull(); + + this.ensure(5); + this.offset += this.data.writeUInt8(1, this.offset); + this.offset += this.data.writeUInt16LE(value, this.offset); + + return this; + } + + public i32(value: number | Nullish) { + if (isNullish(value)) return this.writeNull(); + + this.ensure(5); + this.offset += this.data.writeUInt8(1, this.offset); + this.offset += this.data.writeInt32LE(value, this.offset); + + return this; + } + + public u32(value: number | Nullish) { + if (isNullish(value)) return this.writeNull(); + + this.ensure(5); + this.offset += this.data.writeUInt8(1, this.offset); + this.offset += this.data.writeUInt32LE(value, this.offset); + + return this; + } + + public u64(value: string | number | bigint | Nullish) { + if (isNullish(value)) return this.writeNull(); + + this.ensure(9); + this.offset += this.data.writeUInt8(1, this.offset); + this.offset += this.data.writeBigUInt64LE(BigInt(value), this.offset); + + return this; + } + + public string(value: string | Nullish) { + if (isNullishOrEmpty(value)) return this.writeNull(); + + const data = encoder.encode(value); + + // Ensure length + characters + this.ensure(4 + data.byteLength); + this.offset += this.data.writeUInt32LE(data.byteLength, this.offset); + this.data.set(data, this.offset); + this.offset += data.byteLength; + + return this; + } + + public date(value: string | number | Nullish) { + if (typeof value === 'string') value = Date.parse(value); + return this.u64(value); + } + + public array(values: readonly T[] | Nullish, cb: (buffer: this, value: T) => void) { + if (isNullishOrEmpty(values)) return this.writeNull(); + + this.ensure(4); + this.offset += this.data.writeUInt32LE(values.length, this.offset); + for (const value of values) { + cb(this, value); + } + + return this; + } + + public object(value: T | Nullish, cb: (buffer: this, value: T) => void) { + if (isNullish(value)) return this.writeNull(); + + this.ensure(1); + this.offset += this.data.writeUInt8(1, this.offset); + cb(this, value); + + return this; + } + + private writeNull() { + this.ensure(1); + this.offset += this.data.writeUInt8(0, this.offset); + + return this; + } + + private ensure(bytes: number) { + const nextOffset = this.offset + bytes; + if (nextOffset < this.data.byteLength) return; + + const data = Buffer.alloc(Math.max(nextOffset, this.data.byteLength * 2)); + data.set(this.data, 0); + this.data = data; + } +} diff --git a/projects/shared/src/lib/messaging/MessageBroker.ts b/projects/shared/src/lib/messaging/MessageBroker.ts new file mode 100644 index 000000000..f0db0a476 --- /dev/null +++ b/projects/shared/src/lib/messaging/MessageBroker.ts @@ -0,0 +1,116 @@ +import { Result } from '@sapphire/result'; +import { isNullishOrEmpty, type Nullish } from '@sapphire/utilities'; +import { AsyncEventEmitter } from '@vladfrangu/async_event_emitter'; +import type { Redis } from 'ioredis'; +import { deserialize, serialize } from 'node:v8'; +import { RedisMessage } from './RedisMessage.js'; + +export class MessageBroker extends AsyncEventEmitter<{ + message: [message: RedisMessage]; +}> { + public readonly redis: Redis; + public readonly stream: string; + private readonly block: string; + private readonly max: string; + private readonly serialize: Serializer; + private readonly deserialize: Deserializer; + private redisReader: Redis | null = null; + private listening = false; + private lastId = '$'; + + public constructor(options: MessageBroker.Options) { + super(); + + this.redis = options.redis; + this.stream = options.stream; + this.block = String(options.block ?? 5000); + this.max = String(options.max ?? 10); + this.serialize = options.serialize ?? serialize; + this.deserialize = options.deserialize ?? deserialize; + } + + public send(value: RedisMessage.Data) { + return this.redis.xadd(this.stream, '*', MessageBroker.STREAM_DATA_FIELD, this.serialize(value)); + } + + public listen() { + if (this.listening) return false; + + void this.handleListen(); + return true; + } + + public disconnect() { + this.listening = false; + this.redisReader?.disconnect(false); + } + + private async handleListen() { + if (this.redisReader) throw new Error('The reader is already active'); + this.redisReader = this.redis.duplicate(); + this.listening = true; + + while (this.listening) { + const result = await Result.fromAsync( + this.redisReader.xreadBuffer('COUNT', this.max, 'BLOCK', this.block, 'STREAMS', this.stream, this.lastId) + ); + + result.match({ + ok: (data) => this.handleBulk(data), + err: (error) => this.handleError(error) + }); + } + + this.lastId = '$'; + this.redisReader = null; + } + + private handleBulk(data: [key: Buffer, items: [id: Buffer, fields: Buffer[]][]][] | null) { + if (isNullishOrEmpty(data)) return; + + for (const [streamIdBuffer, items] of data) { + const streamId = streamIdBuffer.toString('utf8'); + + // Verify that the stream is the one the application is listening for. + if (streamId !== this.stream) continue; + + for (const [entryIdBuffer, fields] of items) { + const entryId = entryIdBuffer.toString('utf8'); + this.lastId = entryId; + + // The broker sends 1 pair of fields, so anything different is invalid. + if (fields.length !== 2) continue; + + // Verify that the key of the pair of fields is the data the broker sends. + if (fields[0].toString('utf8') !== MessageBroker.STREAM_DATA_FIELD) continue; + + this.emit('message', new RedisMessage(this, streamId, entryId, this.deserialize(fields[1]))); + } + } + } + + private handleError(error: unknown) { + this.emit('error', error); + } + + private static readonly STREAM_DATA_FIELD = 'data'; +} + +export namespace MessageBroker { + export interface Options { + redis: Redis; + stream: string; + block?: number | Nullish; + max?: number | Nullish; + serialize?: Serializer; + deserialize?: Deserializer; + } +} + +export interface Serializer { + (value: RedisMessage.Data): Buffer; +} + +export interface Deserializer { + (value: Buffer): RedisMessage.Data; +} diff --git a/projects/shared/src/lib/messaging/RedisMessage.ts b/projects/shared/src/lib/messaging/RedisMessage.ts new file mode 100644 index 000000000..7b4cb596e --- /dev/null +++ b/projects/shared/src/lib/messaging/RedisMessage.ts @@ -0,0 +1,225 @@ +import type { + APIChannel, + APIUser, + GatewayGuildBanAddDispatchData, + GatewayGuildBanRemoveDispatchData, + GatewayMessageCreateDispatchData, + GatewayMessageReactionAddDispatchData, + GatewayMessageReactionRemoveAllDispatchData, + GatewayMessageReactionRemoveDispatchData, + GatewayMessageReactionRemoveEmojiDispatchData, + GatewayMessageUpdateDispatchData +} from 'discord-api-types/v10'; +import type { Channel } from '../cache/structures/Channel.js'; +import type { Emoji } from '../cache/structures/Emoji.js'; +import type { Guild } from '../cache/structures/Guild.js'; +import type { Member } from '../cache/structures/Member.js'; +import type { Message } from '../cache/structures/Message.js'; +import type { Role } from '../cache/structures/Role.js'; +import type { Sticker } from '../cache/structures/Sticker.js'; +import type { MessageBroker } from './MessageBroker.js'; + +export class RedisMessage { + public readonly streamId: string; + public readonly entryId: string; + public readonly data: RedisMessage.Data; + private readonly broker: MessageBroker; + + public constructor(broker: MessageBroker, streamId: string, entryId: string, data: RedisMessage.Data) { + this.broker = broker; + this.streamId = streamId; + this.entryId = entryId; + this.data = data; + } + + public async ack() { + const value = await this.broker.redis.xack(this.streamId, this.broker.stream, this.entryId); + return value > 0; + } +} + +export namespace RedisMessage { + export type Data = + | ChannelCreateRedisPayload + | ChannelDeleteRedisPayload + | ChannelUpdateRedisPayload + | EmojiCreateRedisPayload + | EmojiDeleteRedisPayload + | EmojiUpdateRedisPayload + | GuildBanAddRedisPayload + | GuildBanRemoveRedisPayload + | GuildUpdateRedisPayload + | MemberAddRedisPayload + | MemberRemoveRedisPayload + | MemberUpdateRedisPayload + | MessageCreateRedisPayload + | MessageDeleteBulkRedisPayload + | MessageDeleteRedisPayload + | MessageReactionAddRedisPayload + | MessageReactionRemoveAllRedisPayload + | MessageReactionRemoveEmojiRedisPayload + | MessageReactionRemoveRedisPayload + | MessageUpdateRedisPayload + | RoleCreateRedisPayload + | RoleDeleteRedisPayload + | RoleUpdateRedisPayload + | StickerCreateRedisPayload + | StickerDeleteRedisPayload + | StickerUpdateRedisPayload; +} + +export enum RedisMessageType { + ChannelCreate, + ChannelDelete, + ChannelUpdate, + EmojiCreate, + EmojiDelete, + EmojiUpdate, + GuildBanAdd, + GuildBanRemove, + GuildUpdate, + MemberAdd, + MemberRemove, + MemberUpdate, + MessageCreate, + MessageDelete, + MessageDeleteBulk, + MessageReactionAdd, + MessageReactionRemove, + MessageReactionRemoveAll, + MessageReactionRemoveEmoji, + MessageUpdate, + RoleCreate, + RoleDelete, + RoleUpdate, + StickerCreate, + StickerDelete, + StickerUpdate +} + +export interface IDataRedisPayload { + data: T; +} + +export interface IOldRedisPayload { + old: T | null; +} + +export interface IUpdateRedisPayload extends IDataRedisPayload, IOldRedisPayload {} + +export interface GuildUpdateRedisPayload extends IUpdateRedisPayload { + type: RedisMessageType.GuildUpdate; +} + +export interface MessageCreateRedisPayload extends IDataRedisPayload { + type: RedisMessageType.MessageCreate; +} + +export interface MessageUpdateRedisPayload extends IUpdateRedisPayload { + type: RedisMessageType.MessageUpdate; +} + +export interface MessageDeleteRedisPayload extends IOldRedisPayload { + type: RedisMessageType.MessageDelete; +} + +export interface MessageDeleteBulkRedisPayload extends IOldRedisPayload<(Message.Json | { id: string })[]> { + type: RedisMessageType.MessageDeleteBulk; + channel_id: string; + guild_id: string; +} + +export interface GuildBanAddRedisPayload extends IDataRedisPayload { + type: RedisMessageType.GuildBanAdd; +} + +export interface GuildBanRemoveRedisPayload extends IDataRedisPayload { + type: RedisMessageType.GuildBanRemove; +} + +export interface ChannelCreateRedisPayload extends IDataRedisPayload { + type: RedisMessageType.ChannelCreate; +} + +export interface ChannelUpdateRedisPayload extends IUpdateRedisPayload { + type: RedisMessageType.ChannelUpdate; +} + +export interface ChannelDeleteRedisPayload extends IOldRedisPayload { + type: RedisMessageType.ChannelDelete; +} + +export interface EmojiCreateRedisPayload extends IDataRedisPayload { + type: RedisMessageType.EmojiCreate; + guild_id: string; +} + +export interface EmojiUpdateRedisPayload extends IUpdateRedisPayload { + type: RedisMessageType.EmojiUpdate; + guild_id: string; +} + +export interface EmojiDeleteRedisPayload extends IOldRedisPayload { + type: RedisMessageType.EmojiDelete; + guild_id: string; +} + +export interface MemberAddRedisPayload extends IDataRedisPayload { + type: RedisMessageType.MemberAdd; +} + +export interface MemberUpdateRedisPayload extends IUpdateRedisPayload { + type: RedisMessageType.MemberUpdate; +} + +export interface MemberRemoveRedisPayload extends IOldRedisPayload { + type: RedisMessageType.MemberRemove; + user: APIUser; + guild_id: string; +} + +export interface RoleCreateRedisPayload extends IDataRedisPayload { + type: RedisMessageType.RoleCreate; + guild_id: string; +} + +export interface RoleUpdateRedisPayload extends IUpdateRedisPayload { + type: RedisMessageType.RoleUpdate; + guild_id: string; +} + +export interface RoleDeleteRedisPayload extends IOldRedisPayload { + type: RedisMessageType.RoleDelete; + guild_id: string; +} + +export interface MessageReactionAddRedisPayload extends IDataRedisPayload { + type: RedisMessageType.MessageReactionAdd; +} + +export interface MessageReactionRemoveRedisPayload extends IDataRedisPayload { + type: RedisMessageType.MessageReactionRemove; +} + +export interface MessageReactionRemoveAllRedisPayload extends IDataRedisPayload { + type: RedisMessageType.MessageReactionRemoveAll; +} + +export interface MessageReactionRemoveEmojiRedisPayload extends IDataRedisPayload { + type: RedisMessageType.MessageReactionRemoveEmoji; +} + +export interface StickerCreateRedisPayload extends IDataRedisPayload { + type: RedisMessageType.StickerCreate; + guild_id: string; +} + +export interface StickerUpdateRedisPayload extends IUpdateRedisPayload { + type: RedisMessageType.StickerUpdate; + guild_id: string; +} + +export interface StickerDeleteRedisPayload extends IOldRedisPayload { + type: RedisMessageType.StickerDelete; + guild_id: string; +} diff --git a/projects/shared/src/lib/structures/Listener.ts b/projects/shared/src/lib/structures/Listener.ts new file mode 100644 index 000000000..9be700076 --- /dev/null +++ b/projects/shared/src/lib/structures/Listener.ts @@ -0,0 +1,50 @@ +import { Piece, type Container } from '@sapphire/pieces'; + +export abstract class Listener extends Piece { + public emitter: Listener.Emitter; + public event: string; + private _listener: (...args: readonly any[]) => unknown; + + public constructor(context: Listener.Context, options: Listener.Options) { + super(context, options); + + this.emitter = typeof options.emitter === 'string' ? this.container[options.emitter] : options.emitter; + this.event = options.event ?? this.name; + this._listener = this.run.bind(this); + } + + public abstract run(...args: readonly any[]): unknown; + + public override onLoad() { + const count = this.emitter.getMaxListeners(); + if (count !== 0) this.emitter.setMaxListeners(count + 1); + + this.emitter.on(this.event, this._listener); + return super.onLoad(); + } + + public override onUnload() { + const count = this.emitter.getMaxListeners(); + if (count !== 0) this.emitter.setMaxListeners(count - 1); + + this.emitter.off(this.event, this._listener); + return super.onUnload(); + } +} + +export namespace Listener { + export interface Options extends Piece.Options { + emitter: Emitter | { [K in keyof Container]: Container[K] extends Emitter ? K : never }[keyof Container]; + event?: string; + } + export type Context = Piece.Context; + + export interface Emitter { + on(eventName: string, listener: (...args: any[]) => void): this; + once(eventName: string, listener: (...args: any[]) => void): this; + off(eventName: string, listener: (...args: any[]) => void): this; + setMaxListeners(n: number): this; + getMaxListeners(): number; + emit(eventName: string, ...args: any[]): boolean; + } +} diff --git a/projects/shared/src/lib/structures/ListenerStore.ts b/projects/shared/src/lib/structures/ListenerStore.ts new file mode 100644 index 000000000..860dee0b0 --- /dev/null +++ b/projects/shared/src/lib/structures/ListenerStore.ts @@ -0,0 +1,9 @@ +import { Store } from '@sapphire/pieces'; +import { Listener } from './Listener.js'; + +export class ListenerStore extends Store { + public constructor() { + // TODO: https://github.com/sapphiredev/pieces/pull/230 + super(Listener as any, { name: 'listeners' }); + } +} diff --git a/projects/shared/src/tsconfig.json b/projects/shared/src/tsconfig.json new file mode 100644 index 000000000..e136cefbe --- /dev/null +++ b/projects/shared/src/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "./", + "outDir": "../dist", + "composite": true, + "tsBuildInfoFile": "../dist/.tsbuildinfo" + }, + "include": ["."] +} diff --git a/projects/shared/tests/.gitkeep b/projects/shared/tests/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/projects/shared/tsconfig.eslint.json b/projects/shared/tsconfig.eslint.json new file mode 100644 index 000000000..388bb593b --- /dev/null +++ b/projects/shared/tsconfig.eslint.json @@ -0,0 +1,4 @@ +{ + "extends": "../../tsconfig.eslint.json", + "include": ["src", "tests"] +} diff --git a/scripts/SetFakeRoles.sql b/scripts/SetFakeRoles.sql deleted file mode 100644 index a61f8d196..000000000 --- a/scripts/SetFakeRoles.sql +++ /dev/null @@ -1,13 +0,0 @@ -create user archid - superuser - createdb - createrole - replication - bypassrls; - -create user skyra - superuser - createdb - createrole - replication - bypassrls; \ No newline at end of file diff --git a/scripts/SetMigrations.sql b/scripts/SetMigrations.sql deleted file mode 100644 index 396e7981f..000000000 --- a/scripts/SetMigrations.sql +++ /dev/null @@ -1,108 +0,0 @@ -BEGIN TRANSACTION; - -DROP TABLE IF EXISTS public.migrations CASCADE; - -CREATE TABLE public.migrations ( - id integer NOT NULL, - "timestamp" bigint NOT NULL, - name VARCHAR NOT NULL -); - -ALTER TABLE ONLY public.migrations - ADD CONSTRAINT "PK_Migrations" PRIMARY KEY (id); - -CREATE SEQUENCE public.migrations_id_seq - AS integer - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - -ALTER SEQUENCE public.migrations_id_seq OWNED BY public.migrations.id; -ALTER TABLE ONLY public.migrations ALTER COLUMN id SET DEFAULT nextval('public.migrations_id_seq'::regclass); - -INSERT INTO public.migrations ("timestamp", name) -VALUES - (1594413973851, 'V01MigrateClientStorage1594413973851'), - (1594582514749, 'V02MigrateDashboardUsers1594582514749'), - (1594582821724, 'V03MigrateBanners1594582821724'), - (1594582905434, 'V04MigrateGiveaways1594582905434'), - (1594583103788, 'V05MigrateGuilds1594583103788'), - (1594583243068, 'V06MigrateMembers1594583243068'), - (1594583300041, 'V07MigrateModeration1594583300041'), - (1594625931497, 'V08MigrateUsers1594625931497'), - (1594628900945, 'V09MigrateSuggestion1594628900945'), - (1594629639526, 'V10MigrateTwitchSubscription1594629639526'), - (1594649287397, 'V11MigrateRpg1594649287397'), - (1594669268323, 'V12ClearOldTables1594669268323'), - (1594757329224, 'V13MigrateAnalytics1594757329224'), - (1594843508131, 'V14FixRpgGuildRankEntity1594843508131'), - (1594843508131, 'V15ClearDashboardUsers1594922379627'), - (1595064247769, 'V16CreateSpousesTable1595064247769'), - (1596269328762, 'V17MigrateModeratorNonNull1596269328762'), - (1596289368633, 'V18CreateIgnoreLogs1596289368633'), - (1596299849081, 'V19MigrateReactionRoles1596299849081'), - (1597088981807, 'V20UpdateGuildEntityChecks1597088981807'), - (1597266996401, 'V21AddMissingChecks1597266996401'), - (1598010877863, 'V22AddSelfStarCapabilities1598010877863'), - (1598083459734, 'V23AddGIData1598083459734'), - (1599692515073, 'V24RemoveCleanUpTask1599692515073'), - (1604530387718, 'V25SettingsGatewayRemoval1604530387718'), - (1605027257347, 'V26RemoveCommandUseCounter1605027257347'), - (1605297776910, 'V27TextToJsonb1605297776910'), - (1605460185741, 'V28SuggestionIdRemoveFromGuild1605460185741'), - (1606138444111, 'V29AttachmentMode1606138444111'), - (1606138444111, 'V30AttachmentModeChecks1606411800922'), - (1606650850324, 'V31MultiRole1606650850324'), - (1606948188150, 'V32SeparatedMemberNameUpdateLogs1606948188150'), - (1610450637243, 'V33LimitLessLanguageCodes1610450637243'), - (1610659806881, 'V34IncreasedModerationDurations1610659806881'), - (1612574048431, 'V35RemoveRaidColumns1612574048431'), - (1614640993140, 'V36RemoveEveryonePermissionNodes1614640993140'), - (1615269810077, 'V37BirthdayIntegration1615269810077'), - (1616108184492, 'V38UpdateBirthdayIntegration1616108184492'), - (1616168146993, 'V39RenamePropertiesToKebabCase1616168146993'), - (1616188199786, 'V40AddSocialIgnoredRoles1616188199786'), - (1616191193015, 'V41AddMusicAllowedVoiceChannelsAndRoles1616191193015'), - (1616201639503, 'V42AddAllowedRolesIntoGiveaways1616201639503'), - (1616786337398, 'V43RemovedReferencesToUndesiredWords1616786337398'), - (1617272351741, 'V44AddAutoDeleteIgnoreOptions1617272351741'), - (1617297815771, 'V45AddAliasesArrayToTags1617297815771'), - (1617314282232, 'V46AddStarboardMaximumAge1617314282232'), - (1617645345960, 'V47AddNewLogsChannels1617645345960'), - (1617890802896, 'V48AddSeparateInitialRoles1617890802896'), - (1618562933625, 'V49StripConfusablesFromWordFilter1618562933625'), - (1618951687674, 'V50RemoveDatabaseChecks1618951687674'), - (1619089555427, 'V51NewSocialFeaturesAndValueRename1619089555427'), - (1619969827210, 'V52JoinAndLeaveMessageAutoDelete1619969827210'), - (1620050724729, 'V53AfkSettings1620050724729'), - (1626169505546, 'V54EventsModernization1626169505546'), - (1627318321333, 'V55MediaOnlyChannels1627318321333'), - (1629315603851, 'V56MigrateTwitchToEventSub1629315603851'), - (1633184279614, 'V57MigrateReactionRolesAndTriggers1633184279614'), - (1633201003755, 'V58GiveawayAuthor1633201003755'), - (1633266112042, 'V59MigrateSelfmodEmojis1633266112042'), - (1633267799333, 'V60MigrateStarboardAndSuggestionEmojis1633267799333'), - (1634379789387, 'V61AddMusicAutoLeave1634379789387'), - (1646161749171, 'V62VersionSevenRemoveGuildSettings1646161749171'), - (1646162907066, 'V63VersionSevenRemoveStarboard1646162907066'), - (1646163533583, 'V64VersionSevenRemoveSpouses1646163533583'), - (1646178098086, 'V65VersionSevenRemoveStaleSchedules1646178098086'), - (1647241680539, 'V66ExpandGuildSubscriptionMessage1647241680539'), - (1648974657502, 'V67RemoveAudioSettings1648974657502'), - (1654278189464, 'V68PartialRemoveSuggestionSettings1654278189464'), - (1654346108374, 'V69RemoveTriggers1654346108374'), - (1662215154740, 'V70RemoveUserGameIntegration1662215154740'), - (1662215310736, 'V71RemoveRpg1662215310736'), - (1662216686859, 'V72RemoveSocial1662216686859'), - (1662291099795, 'V73RemoveSuggestions1662291099795'), - (1706262119737, 'V74RemoveUserTable1706262119737'), - (1707505580449, 'V75SplitModerationType1707505580449'), - (1707558132765, 'V76AddOptOutUnknownMessageLogging1707558132765'), - (1707605222927, 'V77AddEventsIncludeBots1707605222927'), - (1707642380524, 'V78AddVoiceActivityLogging1707642380524'), - (1708164874479, 'V79AddTimeout1708164874479'); - (1720000000000, 'V81RemoveTwitchSubscriptions1720000000000'); - -COMMIT; diff --git a/scripts/dependencycache.ps1 b/scripts/dependencycache.ps1 deleted file mode 100644 index 4be0bf9c5..000000000 --- a/scripts/dependencycache.ps1 +++ /dev/null @@ -1,26 +0,0 @@ -Function Step-Main { - Param ( - [string]$Command = "default", - [string]$Manager = "yarn" - ) - - Process { - switch ( $Command ) { - clear { - Remove-Item -Recurse -Force -ErrorAction Ignore dist - Remove-Item -Recurse -Force -ErrorAction Ignore node_modules - switch ($Manager) { - yarn { - Remove-Item -Recurse -Force -ErrorAction Ignore $(yarn cache dir) - } - npm { - npm cache rm --force - } - } - } - default { Write-Host "Unrecognized command, please try again" -ForegroundColor Red } - } - } -} - -Step-Main @args diff --git a/scripts/migrate-audit-log-to-audit-event.mjs b/scripts/migrate-audit-log-to-audit-event.mjs deleted file mode 100644 index 4d2f6399f..000000000 --- a/scripts/migrate-audit-log-to-audit-event.mjs +++ /dev/null @@ -1,178 +0,0 @@ -/** - * Migrates legacy dashboard audit rows from audit_log into audit_event. - * - * Safe to run multiple times: skips when audit_log is absent or audit_event - * already contains migrated legacy rows. - * - * Usage: - * node scripts/migrate-audit-log-to-audit-event.mjs - * DATABASE_URL=postgres://... node scripts/migrate-audit-log-to-audit-event.mjs - */ - -import { readFileSync } from 'node:fs'; -import { resolve, dirname } from 'node:path'; -import { fileURLToPath } from 'node:url'; -import { createHash } from 'node:crypto'; -import pg from 'pg'; - -const { Pool } = pg; - -const __dirname = dirname(fileURLToPath(import.meta.url)); -const envPath = resolve(__dirname, '../src/.env'); - -try { - const raw = readFileSync(envPath, 'utf8'); - for (const line of raw.split('\n')) { - const trimmed = line.trim(); - if (!trimmed || trimmed.startsWith('#')) continue; - const eqIdx = trimmed.indexOf('='); - if (eqIdx === -1) continue; - const key = trimmed.slice(0, eqIdx).trim(); - const val = trimmed - .slice(eqIdx + 1) - .trim() - .replace(/^["']|["']$/g, ''); - if (key && !(key in process.env)) process.env[key] = val; - } -} catch { - // .env not present — rely on environment variables already set -} - -function canonicalize(value) { - if (typeof value === 'bigint') return JSON.stringify(value.toString()); - if (value === null || typeof value !== 'object') return JSON.stringify(value); - if (Array.isArray(value)) return `[${value.map(canonicalize).join(',')}]`; - const keys = Object.keys(value).sort(); - return `{${keys.map((k) => `${JSON.stringify(k)}:${canonicalize(value[k])}`).join(',')}}`; -} - -function hashEnvelope(envelope) { - return createHash('sha256').update(canonicalize(envelope)).digest('hex'); -} - -const ACTION_MAP = { - 'settings.update': 'guild.settings.update', - 'settings.add': 'guild.settings.add', - 'settings.remove': 'guild.settings.remove' -}; - -function mapAction(action) { - return ACTION_MAP[action] ?? 'guild.settings.update'; -} - -function transformChanges(changes) { - const before = {}; - const after = {}; - - for (const change of changes ?? []) { - if (!change || typeof change !== 'object') continue; - const { key, oldValue, newValue } = change; - if (typeof key !== 'string') continue; - if (oldValue !== undefined) before[key] = oldValue; - if (newValue !== undefined) after[key] = newValue; - } - - return { before, after }; -} - -function toIsoTimestamp(value) { - const date = value instanceof Date ? value : new Date(value); - return date.toISOString(); -} - -const DATABASE_URL = process.env.DATABASE_URL; -if (!DATABASE_URL) { - console.error('[ERROR] DATABASE_URL is not set. Set it in src/.env or the environment.'); - process.exit(1); -} - -const pool = new Pool({ connectionString: DATABASE_URL }); -const client = await pool.connect(); - -try { - const auditLogExists = await client.query(`SELECT to_regclass('public.audit_log') IS NOT NULL AS exists`); - if (!auditLogExists.rows[0]?.exists) { - console.log('No legacy audit_log table found; nothing to migrate.'); - process.exit(0); - } - - const auditEventExists = await client.query(`SELECT to_regclass('public.audit_event') IS NOT NULL AS exists`); - if (!auditEventExists.rows[0]?.exists) { - console.error('[ERROR] audit_event table does not exist. Run prisma migrate deploy first.'); - process.exit(1); - } - - const existingCount = await client.query(`SELECT COUNT(*)::int AS count FROM audit_event`); - if (existingCount.rows[0]?.count > 0) { - console.log('audit_event already has rows; skipping legacy migration to avoid chain conflicts.'); - process.exit(0); - } - - const { rows } = await client.query( - `SELECT id, guild_id, user_id, action, changes, created_at - FROM audit_log - ORDER BY created_at ASC, id ASC` - ); - - if (rows.length === 0) { - await client.query('DROP TABLE IF EXISTS "audit_log" CASCADE'); - console.log('Legacy audit_log was empty and has been dropped.'); - process.exit(0); - } - - await client.query('BEGIN'); - await client.query('SELECT pg_advisory_xact_lock(1096107084)'); - - let prevHash = null; - - for (const row of rows) { - const changes = transformChanges(row.changes); - const timestamp = row.created_at; - const timestampIso = toIsoTimestamp(timestamp); - const action = mapAction(row.action); - - const envelope = { - action, - actor: { type: 'user', id: row.user_id }, - outcome: 'success', - tenantId: row.guild_id, - timestamp: timestampIso, - changes, - reason: null, - requestId: null, - traceId: null, - prevHash - }; - - const hash = hashEnvelope(envelope); - - await client.query( - `INSERT INTO audit_event ( - action, actor_type, actor_id, outcome, tenant_id, reason, - timestamp, changes, prev_hash, hash - ) VALUES ($1, 'user', $2, 'success', $3, NULL, $4, $5::json, $6, $7)`, - [action, row.user_id, row.guild_id, timestamp, JSON.stringify(changes), prevHash, hash] - ); - - prevHash = hash; - } - - await client.query( - `INSERT INTO audit_chain_head (id, hash, updated_at) - VALUES ('default', $1, NOW()) - ON CONFLICT (id) DO UPDATE SET hash = EXCLUDED.hash, updated_at = EXCLUDED.updated_at`, - [prevHash] - ); - - await client.query('DROP TABLE IF EXISTS "audit_log" CASCADE'); - await client.query('COMMIT'); - - console.log(`Migrated ${rows.length} legacy audit_log row(s) into audit_event.`); -} catch (error) { - await client.query('ROLLBACK'); - console.error(`[ERROR] Legacy audit migration failed: ${error.message}`); - process.exit(1); -} finally { - client.release(); - await pool.end(); -} diff --git a/scripts/migrations.mjs b/scripts/migrations.mjs deleted file mode 100644 index 01f9134de..000000000 --- a/scripts/migrations.mjs +++ /dev/null @@ -1,12 +0,0 @@ -import { readFile } from 'node:fs/promises'; -import { AppDataConfig } from '../dist/lib/database/database.config.js'; - -AppDataConfig.setOptions({ logging: true }); - -const [sqlScript, connection] = await Promise.all([ - readFile(new URL('SetMigrations.sql', import.meta.url), { encoding: 'utf-8' }), - AppDataConfig.initialize() -]); - -await connection.query(sqlScript); -await connection.destroy(); diff --git a/scripts/tlds.mjs b/scripts/tlds.mjs index f0540790f..9f1a59e51 100644 --- a/scripts/tlds.mjs +++ b/scripts/tlds.mjs @@ -3,14 +3,14 @@ import { writeFile } from 'node:fs/promises'; import { toUnicode } from 'node:punycode'; // Download entry from IANA, process the data as a string, and split it by new line -const text = await fetch('https://data.iana.org/TLD/tlds-alpha-by-domain.txt', FetchResultTypes.Text); +const text = await fetch('http://data.iana.org/TLD/tlds-alpha-by-domain.txt', FetchResultTypes.Text); const source = text.trim().split('\n'); // Removes the comment from the start of the file if (source[0].startsWith('#')) source.shift(); // Define header and footer, which will wrap the content -const header = '// Autogenerated file from ICANN, source:\n// https://data.iana.org/TLD/tlds-alpha-by-domain.txt\n\nexport const TLDs = [\n'; +const header = '// Autogenerated file from ICANN, source:\n// http://data.iana.org/TLD/tlds-alpha-by-domain.txt\n\nexport const TLDs = [\n'; const footer = '\n];\n'; const content = source .map((line, index) => { @@ -21,6 +21,6 @@ const content = source }) .join('\n'); -const outputFile = new URL('../src/lib/util/Links/TLDs.ts', import.meta.url); +const outputFile = new URL('../projects/bot/src/lib/util/Links/TLDs.ts', import.meta.url); void writeFile(outputFile, header + content + footer); diff --git a/src/.env b/src/.env deleted file mode 100644 index 71bab1c7b..000000000 --- a/src/.env +++ /dev/null @@ -1,48 +0,0 @@ -CLIENT_NAME='WolfStar' -CLIENT_VERSION='6.4.0 [Sapphire Edition]' -CLIENT_PREFIX='w!' -CLIENT_REGEX_PREFIX='^wolf[, ]' -CLIENT_OWNERS='605162125027049472' -CLIENT_ID='854714837388755004' -SHARDS='"auto"' - -CLIENT_PRESENCE_NAME='WolfStar, help' -CLIENT_PRESENCE_TYPE='LISTENING' - -API_ENABLED=true -API_ORIGIN='http://127.0.0.1:3000' -API_PREFIX='/' -API_PORT=8282 -API_HOST='127.0.0.1' - -OAUTH_COOKIE='WOLFSTAR_AUTH' -OAUTH_DOMAIN_OVERWRITE='127.0.0.1' -OAUTH_REDIRECT_URI='http://127.0.0.1:3000/oauth/callback' -OAUTH_SCOPE='identify guilds' -OAUTH_SECRET='' - -INFLUX_ENABLED=true -INFLUX_URL='http://localhost:8285' -INFLUX_TOKEN='' -INFLUX_ORG='WolfStar-Project' -INFLUX_ORG_ANALYTICS_BUCKET='analytics' - -WEBHOOK_ERROR_ID='1233428567946301520' -WEBHOOK_ERROR_TOKEN='' - -WORKER_COUNT=2 - -# Tokens -DISCORD_TOKEN='' -BOTS_FOR_DISCORD_TOKEN='' -DISCORD_BOT_LIST_TOKEN='' -DISCORD_BOTS_TOKEN='' -VOID_BOTS_TOKEN='' -TOP_GG_TOKEN='' - -# Sentry -SENTRY_URL='' - -# The database URL for Prisma, needs to be copied in a local `.env` at the root -# for Prisma's operations to work. -DATABASE_URL="postgresql://postgres:postgres@localhost:5432/wolfstar?schema=public" diff --git a/src/.env.development b/src/.env.development deleted file mode 100644 index 4e5f1fff5..000000000 --- a/src/.env.development +++ /dev/null @@ -1,12 +0,0 @@ -CLIENT_VERSION='6.4.0-dev [Sapphire Edition]' -CLIENT_PREFIX='wd!' -CLIENT_REGEX_PREFIX='' -CLIENT_ID='' - -CLIENT_PRESENCE_NAME='wd!help, Dev Build' - -INFLUX_ENABLED=true -INFLUX_URL='http://localhost:8285' -INFLUX_TOKEN='' -INFLUX_ORG='WolfStar-Project' -INFLUX_ORG_ANALYTICS_BUCKET='analytics' diff --git a/src/arguments/boolean.ts b/src/arguments/boolean.ts deleted file mode 100644 index b9a737b56..000000000 --- a/src/arguments/boolean.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { getT } from '#lib/i18n/translate'; -import { Argument, Resolvers } from '@sapphire/framework'; -import { filterNullishOrEmpty } from '@sapphire/utilities'; - -export class CoreArgument extends Argument { - private defaultTruthValues: string[] | null = null; - private defaultFalseValues: string[] | null = null; - - public run(parameter: string, context: Argument.Context) { - let truths = context.args.t(LanguageKeys.Arguments.BooleanTrueOptions).filter(filterNullishOrEmpty); - let falses = context.args.t(LanguageKeys.Arguments.BooleanFalseOptions).filter(filterNullishOrEmpty); - - if (!truths.length) truths = this.getDefaultTruthValues; - if (!falses.length) falses = this.getDefaultFalseValues; - - return Resolvers.resolveBoolean(parameter, { truths, falses }) // - .mapErrInto((identifier) => this.error({ parameter, identifier, context })); - } - - private get getDefaultTruthValues() { - return (this.defaultTruthValues ??= getT()(LanguageKeys.Arguments.BooleanTrueOptions).filter(filterNullishOrEmpty)); - } - - private get getDefaultFalseValues() { - return (this.defaultFalseValues ??= getT()(LanguageKeys.Arguments.BooleanFalseOptions).filter(filterNullishOrEmpty)); - } -} diff --git a/src/arguments/case.ts b/src/arguments/case.ts deleted file mode 100644 index d5a12bbf1..000000000 --- a/src/arguments/case.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { resolveCaseId } from '#utils/resolvers'; -import { Argument } from '@sapphire/framework'; - -export class UserArgument extends Argument { - public async run(parameter: string, context: Argument.Context) { - return (await resolveCaseId(parameter, context.args.t, context.message.guild!)) // - .mapErrInto((error) => this.error({ parameter, identifier: error.identifier, context: { ...(error.context as object), ...context } })); - } -} diff --git a/src/arguments/channelName.ts b/src/arguments/channelName.ts deleted file mode 100644 index 91febfd20..000000000 --- a/src/arguments/channelName.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { isGuildMessage } from '#utils/common'; -import { FuzzySearch } from '#utils/Parsers/FuzzySearch'; -import { validateChannelAccess } from '#utils/util'; -import { ChannelMentionRegex, SnowflakeRegex } from '@sapphire/discord.js-utilities'; -import { Argument } from '@sapphire/framework'; -import type { Guild, GuildChannel, ThreadChannel, User } from 'discord.js'; - -export class UserArgument extends Argument { - public resolveChannel(query: string, guild: Guild) { - const channelId = ChannelMentionRegex.exec(query) ?? SnowflakeRegex.exec(query); - return (channelId !== null && guild.channels.cache.get(channelId.groups!.id)) ?? null; - } - - public async run(parameter: string, { message, minimum, context, filter }: ChannelArgumentContext) { - if (!isGuildMessage(message)) return this.error({ parameter, identifier: LanguageKeys.Arguments.GuildChannelMissingGuildError, context }); - filter = this.getFilter(message.author, filter); - - const resChannel = this.resolveChannel(parameter, message.guild); - if (resChannel) { - if (filter(resChannel)) return this.ok(resChannel); - return this.error({ parameter, identifier: LanguageKeys.Arguments.GuildChannelMismatchingError, context }); - } - - const result = await new FuzzySearch(message.guild.channels.cache, (entry) => entry.name, filter).run(message, parameter, minimum); - if (result) return this.ok(result[1]); - return this.error({ parameter, identifier: LanguageKeys.Arguments.GuildChannelError, context }); - } - - private getFilter(author: User, filter?: (entry: GuildChannel | ThreadChannel) => boolean) { - const clientUser = author.client.user!; - return typeof filter === 'undefined' - ? (entry: GuildChannel | ThreadChannel) => validateChannelAccess(entry, author) && validateChannelAccess(entry, clientUser) - : (entry: GuildChannel | ThreadChannel) => - filter(entry) && validateChannelAccess(entry, author) && validateChannelAccess(entry, clientUser); - } -} - -interface ChannelArgumentContext extends Argument.Context { - filter?: (entry: GuildChannel | ThreadChannel) => boolean; -} diff --git a/src/arguments/command.ts b/src/arguments/command.ts deleted file mode 100644 index 3c7f117c3..000000000 --- a/src/arguments/command.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import type { WolfCommand } from '#lib/structures'; -import { PermissionLevels } from '#lib/types'; -import { OWNERS } from '#root/config'; -import { Argument } from '@sapphire/framework'; - -export class UserArgument extends Argument { - public run(parameter: string, context: CommandArgumentContext) { - const resolved = this.container.stores.get('commands').get(parameter.toLowerCase()) as WolfCommand | undefined; - if (resolved !== undefined && this.isAllowed(resolved, context)) return this.ok(resolved); - return this.error({ parameter, identifier: LanguageKeys.Arguments.Command, context }); - } - - private isAllowed(command: WolfCommand, context: CommandArgumentContext): boolean { - if (command.permissionLevel !== PermissionLevels.BotOwner) return true; - return context.owners ?? OWNERS.includes(context.message.author.id); - } -} - -interface CommandArgumentContext extends Argument.Context { - owners?: boolean; -} diff --git a/src/arguments/commandMatch.ts b/src/arguments/commandMatch.ts deleted file mode 100644 index 07de64d52..000000000 --- a/src/arguments/commandMatch.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { CommandMatcher } from '#lib/database'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import type { WolfCommand } from '#lib/structures'; -import { PermissionLevels } from '#lib/types'; -import { OWNERS } from '#root/config'; -import { Argument } from '@sapphire/framework'; - -export class UserArgument extends Argument { - public run(parameter: string, context: CommandArgumentContext) { - const resolved = CommandMatcher.resolve(parameter); - if (resolved !== null && this.isAllowed(resolved, context)) return this.ok(resolved); - return this.error({ parameter, identifier: LanguageKeys.Arguments.CommandMatch, context }); - } - - private isAllowed(resolved: string, context: CommandArgumentContext): boolean { - const command = this.container.stores.get('commands').get(resolved) as WolfCommand | undefined; - if (command === undefined) return true; - - if (command.permissionLevel !== PermissionLevels.BotOwner) return true; - return context.owners ?? OWNERS.includes(context.message.author.id); - } -} - -interface CommandArgumentContext extends Argument.Context { - owners?: boolean; -} diff --git a/src/arguments/commandName.ts b/src/arguments/commandName.ts deleted file mode 100644 index e71e91790..000000000 --- a/src/arguments/commandName.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import type { WolfCommand } from '#lib/structures'; -import { PermissionLevels, type NonGroupMessage } from '#lib/types'; -import { OWNERS } from '#root/config'; -import { FuzzySearch } from '#utils/Parsers/FuzzySearch'; -import { Argument, Command } from '@sapphire/framework'; - -export class UserArgument extends Argument { - public async run(parameter: string, context: CommandArgumentContext) { - const commands = this.container.stores.get('commands'); - const found = commands.get(parameter.toLowerCase()) as WolfCommand | undefined; - if (found) { - return this.isAllowed(found, context) ? this.ok(found) : this.error({ parameter, identifier: LanguageKeys.Arguments.Command, context }); - } - - const command = await new FuzzySearch(commands, (command) => command.name, context.filter).run( - context.message as NonGroupMessage, - parameter, - context.minimum - ); - if (command) return this.ok(command[1]); - - return this.error({ parameter, identifier: LanguageKeys.Arguments.Command, context }); - } - - private isAllowed(command: WolfCommand, context: CommandArgumentContext): boolean { - if (command.permissionLevel !== PermissionLevels.BotOwner) return true; - return context.owners ?? OWNERS.includes(context.message.author.id); - } -} - -interface CommandArgumentContext extends Argument.Context { - filter?: (entry: Command) => boolean; - owners?: boolean; -} diff --git a/src/arguments/duration.ts b/src/arguments/duration.ts deleted file mode 100644 index 2916035a6..000000000 --- a/src/arguments/duration.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { Argument } from '@sapphire/framework'; -import { Duration } from '@sapphire/time-utilities'; - -export class UserArgument extends Argument { - public run(parameter: string, context: Argument.Context) { - const date = new Duration(parameter).fromNow; - if (!Number.isNaN(date.getTime()) && date.getTime() > Date.now()) return this.ok(date); - return this.error({ parameter, identifier: LanguageKeys.Arguments.Duration, context }); - } -} diff --git a/src/arguments/emoji.ts b/src/arguments/emoji.ts deleted file mode 100644 index 857da04be..000000000 --- a/src/arguments/emoji.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { getEmojiObject, type EmojiObject } from '#utils/functions'; -import { Argument } from '@sapphire/framework'; - -export class UserArgument extends Argument { - public run(parameter: string, context: Argument.Context) { - const resolved = getEmojiObject(parameter); - if (resolved === null) return this.error({ parameter, identifier: LanguageKeys.Arguments.EmojiError, context }); - return this.ok(resolved); - } -} diff --git a/src/arguments/invite.ts b/src/arguments/invite.ts deleted file mode 100644 index b947e40fb..000000000 --- a/src/arguments/invite.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { DiscordInviteLinkRegex } from '@sapphire/discord-utilities'; -import { Argument } from '@sapphire/framework'; - -export class UserArgument extends Argument { - public async run(parameter: string, context: Argument.Context) { - const parsed = DiscordInviteLinkRegex.exec(parameter); - if (parsed === null) { - return this.error({ parameter, identifier: LanguageKeys.Arguments.Invite, context }); - } - - const { code } = parsed.groups!; - const invite = await this.container.client.invites.fetch(code); - if (invite === null || !Reflect.has(invite, 'guildId')) { - return this.error({ parameter, identifier: LanguageKeys.Arguments.Invite, context }); - } - - return this.ok(code); - } -} diff --git a/src/arguments/language.ts b/src/arguments/language.ts deleted file mode 100644 index 823bbddc2..000000000 --- a/src/arguments/language.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { Argument } from '@sapphire/framework'; -import type { Locale } from 'discord.js'; - -export class UserArgument extends Argument { - public run(parameter: string, context: Argument.Context) { - const { languages } = this.container.i18n; - if (languages.has(parameter)) return this.ok(parameter as Locale); - return this.error({ parameter, identifier: LanguageKeys.Arguments.Language, context: { ...context, possibles: [...languages.keys()] } }); - } -} diff --git a/src/arguments/range.ts b/src/arguments/range.ts deleted file mode 100644 index 36a86b5cc..000000000 --- a/src/arguments/range.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { parseRange } from '#utils/util'; -import { Argument } from '@sapphire/framework'; - -export class UserArgument extends Argument { - public run(parameter: string, context: Argument.Context) { - const number = Number(parameter); - if (Number.isSafeInteger(number)) return this.ok([number]); - - const range = parseRange(parameter); - if (range.length === 0) return this.error({ parameter, identifier: LanguageKeys.Arguments.RangeInvalid, context }); - if (typeof context.maximum === 'number' && range.length > context.maximum) { - return this.error({ parameter, identifier: LanguageKeys.Arguments.RangeMax, context: { ...context, count: context.maximum } }); - } - - return this.ok(range); - } -} diff --git a/src/arguments/reset.ts b/src/arguments/reset.ts deleted file mode 100644 index 5b6690395..000000000 --- a/src/arguments/reset.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { Argument } from '@sapphire/framework'; - -export class UserArgument extends Argument { - public run(parameter: string, context: Argument.Context) { - const lowerCasedParameter = parameter.toLowerCase(); - if (context.args.t(LanguageKeys.Arguments.ResetPossibles).includes(lowerCasedParameter)) return this.ok(true); - return this.error({ parameter, context }); - } -} diff --git a/src/arguments/roleName.ts b/src/arguments/roleName.ts deleted file mode 100644 index 885e25350..000000000 --- a/src/arguments/roleName.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { isGuildMessage } from '#utils/common'; -import { FuzzySearch } from '#utils/Parsers/FuzzySearch'; -import { RoleMentionRegex, SnowflakeRegex } from '@sapphire/discord.js-utilities'; -import { Argument } from '@sapphire/framework'; -import type { Guild, Role } from 'discord.js'; - -export class UserArgument extends Argument { - public get role() { - return this.store.get('role') as Argument; - } - - public async run(parameter: string, context: RoleArgumentContext) { - const { message } = context; - if (!isGuildMessage(message)) return this.role.run(parameter, context); - - const resolvedRole = this.resolveRole(parameter, message.guild); - if (resolvedRole) return this.ok(resolvedRole); - - const result = await new FuzzySearch(message.guild.roles.cache, (entry) => entry.name, context.filter).run( - message, - parameter, - context.minimum - ); - if (result) return this.ok(result[1]); - return this.error({ parameter, identifier: LanguageKeys.Arguments.RoleError, context }); - } - - public resolveRole(query: string, guild: Guild) { - const role = RoleMentionRegex.exec(query) ?? SnowflakeRegex.exec(query); - return role ? (guild.roles.cache.get(role[1]) ?? null) : null; - } -} - -interface RoleArgumentContext extends Argument.Context { - filter?: (entry: Role) => boolean; -} diff --git a/src/arguments/snowflake.ts b/src/arguments/snowflake.ts deleted file mode 100644 index 8f84ebf6f..000000000 --- a/src/arguments/snowflake.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { Argument } from '@sapphire/framework'; -import { DiscordSnowflake } from '@sapphire/snowflake'; -import type { Snowflake } from 'discord.js'; - -export class UserArgument extends Argument { - /** - * The validator, requiring all numbers and 17 to 19 digits (future-proof). - */ - private readonly kRegExp = /^\d{17,19}$/; - - /** - * Stanislav's join day, known as the oldest user in Discord, and practically - * the lowest snowflake we can get (as they're bound by the creation date). - */ - private readonly kMinimum = new Date(2015, 1, 28).getTime(); - - public run(parameter: string, context: Argument.Context) { - if (this.kRegExp.test(parameter)) { - const snowflake = DiscordSnowflake.deconstruct(parameter); - const timestamp = Number(snowflake.timestamp); - if (timestamp >= this.kMinimum && timestamp < Date.now()) return this.ok(parameter); - } - return this.error({ parameter, identifier: LanguageKeys.Arguments.Snowflake, context }); - } -} diff --git a/src/arguments/textChannelName.ts b/src/arguments/textChannelName.ts deleted file mode 100644 index 8aed4910b..000000000 --- a/src/arguments/textChannelName.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { isTextChannel } from '@sapphire/discord.js-utilities'; -import { Argument } from '@sapphire/framework'; -import type { TextChannel } from 'discord.js'; - -export class UserArgument extends Argument { - public get channelName(): Argument { - return this.store.get('channelName') as Argument; - } - - public run(argument: string, context: Argument.Context) { - return this.channelName.run(argument, { ...context, filter: isTextChannel }); - } -} diff --git a/src/arguments/textOrNewsChannelName.ts b/src/arguments/textOrNewsChannelName.ts deleted file mode 100644 index c60b600f1..000000000 --- a/src/arguments/textOrNewsChannelName.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { orMix } from '#utils/common'; -import { isNewsChannel, isTextChannel } from '@sapphire/discord.js-utilities'; -import { Argument } from '@sapphire/framework'; -import type { NewsChannel, TextChannel } from 'discord.js'; - -export class UserArgument extends Argument { - private readonly filter = orMix(isTextChannel, isNewsChannel); - - public get channelName(): Argument { - return this.store.get('channelName') as Argument; - } - - public run(argument: string, context: Argument.Context) { - return this.channelName.run(argument, { ...context, filter: this.filter }); - } -} diff --git a/src/arguments/time.ts b/src/arguments/time.ts deleted file mode 100644 index e637383b7..000000000 --- a/src/arguments/time.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { Argument } from '@sapphire/framework'; - -export class UserArgument extends Argument { - private get date() { - return this.container.stores.get('arguments').get('date') as Argument; - } - - private get duration() { - return this.container.stores.get('arguments').get('duration') as Argument; - } - - public async run(parameter: string, context: Argument.Context) { - let result = await this.date.run(parameter, context); - if (result.isErr()) result = await this.duration.run(parameter, context); - - if (result.isOkAnd((date) => date.getTime() > Date.now())) return this.ok(result.unwrap()); - return this.error({ parameter, identifier: LanguageKeys.Arguments.Time, context }); - } -} diff --git a/src/arguments/timespan.ts b/src/arguments/timespan.ts deleted file mode 100644 index 0dc8d78e4..000000000 --- a/src/arguments/timespan.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { resolveTimeSpan } from '#utils/resolvers'; -import { Argument } from '@sapphire/framework'; - -export class UserArgument extends Argument { - public run(parameter: string, context: Argument.Context) { - return resolveTimeSpan(parameter, { minimum: context.minimum, maximum: context.maximum }) // - .mapErrInto((identifier) => this.error({ parameter, identifier, context })); - } -} diff --git a/src/arguments/userName.ts b/src/arguments/userName.ts deleted file mode 100644 index ae5c45f85..000000000 --- a/src/arguments/userName.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import type { GuildMessage } from '#lib/types'; -import { isGuildMessage } from '#utils/common'; -import { SnowflakeRegex, UserOrMemberMentionRegex } from '@sapphire/discord.js-utilities'; -import { Argument, Identifiers } from '@sapphire/framework'; -import type { User } from 'discord.js'; - -export class UserArgument extends Argument { - private get user(): Argument { - return this.store.get('user') as Argument; - } - - public async run(parameter: string, context: Argument.Context) { - const message = context.message as GuildMessage; - if (!isGuildMessage(message)) return this.user.run(parameter, context); - - const user = await this.resolveUser(message, parameter); - if (user) return this.ok(user); - if (user === null) return this.error({ parameter, identifier: Identifiers.ArgumentUserError, context }); - - const result = await this.fetchMember(message, parameter); - if (result) return this.ok(result.user); - return this.error({ parameter, identifier: LanguageKeys.Arguments.UserError, context }); - } - - private async resolveUser(message: GuildMessage, argument: string) { - const result = UserOrMemberMentionRegex.exec(argument) ?? SnowflakeRegex.exec(argument); - if (result === null) return undefined; - - try { - return await message.client.users.fetch(result[1]); - } catch { - return null; - } - } - - private async fetchMember(message: GuildMessage, query: string) { - try { - const results = await message.guild.members.fetch({ query }); - return results.first() ?? null; - } catch { - return null; - } - } -} diff --git a/src/commands/Admin/conf.ts b/src/commands/Admin/conf.ts deleted file mode 100644 index 8383a1608..000000000 --- a/src/commands/Admin/conf.ts +++ /dev/null @@ -1,224 +0,0 @@ -import { getConfigurableGroups, isSchemaKey, readSettings, remove, reset, SchemaKey, set, writeSettingsTransaction } from '#lib/database'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { getSupportedUserLanguageT } from '#lib/i18n/translate'; -import { SettingsMenu, WolfArgs, WolfSubcommand } from '#lib/structures'; -import { PermissionLevels, type GuildMessage } from '#lib/types'; -import { isValidCustomEmoji, isValidSerializedTwemoji, isValidTwemoji } from '#lib/util/functions/emojis'; -import { chatInputApplicationCommandMention, inlineCode } from '@discordjs/builders'; -import { ApplyOptions, RequiresClientPermissions } from '@sapphire/decorators'; -import { ApplicationCommandRegistry, CommandOptionsRunTypeEnum } from '@sapphire/framework'; -import { applyLocalizedBuilder } from '@sapphire/plugin-i18next'; -import { filter, map, toArray } from '@sapphire/iterator-utilities'; -import { isNullish, toTitleCase } from '@sapphire/utilities'; -import { InteractionContextType, MessageFlags, PermissionFlagsBits } from 'discord.js'; -import { send } from '@sapphire/plugin-editable-commands'; -import { cast } from '#utils/util'; - -const Root = LanguageKeys.Commands.Conf; - -@ApplyOptions({ - description: Root.Description, - detailedDescription: LanguageKeys.Commands.Shared.SlashOnlyDetailedDescription, - guarded: true, - permissionLevel: PermissionLevels.Administrator, - requiredClientPermissions: [PermissionFlagsBits.EmbedLinks], - runIn: [CommandOptionsRunTypeEnum.GuildAny], - hidden: true, - subcommands: [ - { name: 'menu', chatInputRun: 'chatInputRunMenu', default: true }, - { name: 'show', chatInputRun: 'chatInputRunShow' }, - { name: 'set', chatInputRun: 'chatInputRunSet' }, - { name: 'remove', chatInputRun: 'chatInputRunRemove' }, - { name: 'reset', chatInputRun: 'chatInputRunReset' } - ] -}) -export class UserCommand extends WolfSubcommand { - public override registerApplicationCommands(registry: ApplicationCommandRegistry) { - registry.registerChatInputCommand( - (builder) => - applyLocalizedBuilder(builder, Root.Name, Root.Description) - .setContexts(InteractionContextType.Guild) - .setDefaultMemberPermissions(PermissionFlagsBits.ManageGuild) - .addSubcommand( - (subcommand) => applyLocalizedBuilder(subcommand, Root.Menu, Root.MenuDescription) // - ) - .addSubcommand((subcommand) => - applyLocalizedBuilder(subcommand, Root.Show, Root.ShowDescription) // - .addStringOption((option) => applyLocalizedBuilder(option, Root.OptionKey, Root.OptionKeyDescription).setRequired(false)) - ) - .addSubcommand((subcommand) => - applyLocalizedBuilder(subcommand, Root.Set, Root.SetDescription) // - .addStringOption((option) => applyLocalizedBuilder(option, Root.OptionKey, Root.OptionKeyDescription).setRequired(true)) - .addStringOption((option) => - applyLocalizedBuilder(option, Root.OptionValue, Root.OptionValueDescription).setRequired(true) - ) - ) - .addSubcommand((subcommand) => - applyLocalizedBuilder(subcommand, Root.Remove, Root.RemoveDescription) // - .addStringOption((option) => applyLocalizedBuilder(option, Root.OptionKey, Root.OptionKeyDescription).setRequired(true)) - .addStringOption((option) => - applyLocalizedBuilder(option, Root.OptionValue, Root.OptionValueDescription).setRequired(true) - ) - ) - .addSubcommand((subcommand) => - applyLocalizedBuilder(subcommand, Root.Reset, Root.ResetDescription) // - .addStringOption((option) => applyLocalizedBuilder(option, Root.OptionKey, Root.OptionKeyDescription).setRequired(true)) - ), - { - idHints: [ - '1492494867425787924' // wolfstar-prod production - ] - } - ); - } - - @RequiresClientPermissions(PermissionFlagsBits.EmbedLinks) - public menu(message: GuildMessage, args: WolfSubcommand.Args) { - return send(message, { - content: args.t(LanguageKeys.Commands.Shared.DeprecatedMessage, { - command: chatInputApplicationCommandMention(this.name, 'show', this.getGlobalCommandId()) - }) - }); - } - - public async show(message: GuildMessage, args: WolfSubcommand.Args) { - return send(message, { - content: args.t(LanguageKeys.Commands.Shared.DeprecatedMessage, { - command: chatInputApplicationCommandMention(this.name, 'show', this.getGlobalCommandId()) - }) - }); - } - - public async set(message: GuildMessage, args: WolfSubcommand.Args) { - return send(message, { - content: args.t(LanguageKeys.Commands.Shared.DeprecatedMessage, { - command: chatInputApplicationCommandMention(this.name, 'show', this.getGlobalCommandId()) - }) - }); - } - - public async remove(message: GuildMessage, args: WolfSubcommand.Args) { - return send(message, { - content: args.t(LanguageKeys.Commands.Shared.DeprecatedMessage, { - command: chatInputApplicationCommandMention(this.name, 'show', this.getGlobalCommandId()) - }) - }); - } - - public async reset(message: GuildMessage, args: WolfSubcommand.Args) { - return send(message, { - content: args.t(LanguageKeys.Commands.Shared.DeprecatedMessage, { - command: chatInputApplicationCommandMention(this.name, 'show', this.getGlobalCommandId()) - }) - }); - } - - public async chatInputRunMenu(interaction: WolfSubcommand.Interaction, context: WolfSubcommand.RunContext) { - const t = getSupportedUserLanguageT(interaction); - return new SettingsMenu(interaction, t).init(context); - } - - public async chatInputRunShow(interaction: WolfSubcommand.Interaction) { - const t = getSupportedUserLanguageT(interaction); - const key = interaction.options.getString('key') ?? ''; - const schemaValue = getConfigurableGroups().getPathString(key.toLowerCase()); - if (schemaValue === null) this.error(Root.GetNoExt, { key }); - - const settings = await readSettings(interaction.guild); - const output = schemaValue.display(settings, t); - - if (isSchemaKey(schemaValue)) { - const content = t(Root.Get, { key: schemaValue.name, value: output }); - return interaction.reply({ content, allowedMentions: { users: [], roles: [] }, flags: MessageFlags.Ephemeral }); - } - - const title = key - ? `: ${key - .split('.') - .map((key) => toTitleCase(key)) - .join('/')}` - : ''; - const content = t(Root.Server, { key: title, list: output }); - return interaction.reply({ content, allowedMentions: { users: [], roles: [] }, flags: MessageFlags.Ephemeral }); - } - - public async chatInputRunSet(interaction: WolfSubcommand.Interaction) { - const t = getSupportedUserLanguageT(interaction); - const [key, schemaKey] = await this.#fetchKeyFromInteraction(interaction, t); - - using trx = await writeSettingsTransaction(interaction.guild); - const value = interaction.options.getString('value', true); - - // Create a minimal message proxy for WolfArgs compatibility - const messageProxy = cast({ - guild: interaction.guild, - channel: interaction.channel, - author: interaction.user, - client: interaction.client - }); - const args = WolfArgs.from(this, messageProxy, value, {} as any, t); - await trx.write(await set(trx.settings, schemaKey, args)).submitWithAudit(interaction.user.id); - - const response = schemaKey.display(trx.settings, t); - const content = t(Root.Updated, { key, response: this.#getTextResponse(response) }); - return interaction.reply({ content, allowedMentions: { users: [], roles: [] }, flags: MessageFlags.Ephemeral }); - } - - public async chatInputRunRemove(interaction: WolfSubcommand.Interaction) { - const t = getSupportedUserLanguageT(interaction); - const [key, schemaKey] = await this.#fetchKeyFromInteraction(interaction, t); - - using trx = await writeSettingsTransaction(interaction.guild); - const value = interaction.options.getString('value', true); - - // Create a minimal message proxy for WolfArgs compatibility - const messageProxy = cast({ - guild: interaction.guild, - channel: interaction.channel, - author: interaction.user, - client: interaction.client - }); - const args = WolfArgs.from(this, messageProxy, value, {} as any, t); - await trx.write(await remove(trx.settings, schemaKey, args)).submitWithAudit(interaction.user.id); - - const response = schemaKey.display(trx.settings, t); - const content = t(Root.Updated, { key, response: this.#getTextResponse(response) }); - return interaction.reply({ content, allowedMentions: { users: [], roles: [] }, flags: MessageFlags.Ephemeral }); - } - - public async chatInputRunReset(interaction: WolfSubcommand.Interaction) { - const t = getSupportedUserLanguageT(interaction); - const [key, schemaKey] = await this.#fetchKeyFromInteraction(interaction, t); - - using trx = await writeSettingsTransaction(interaction.guild); - await trx.write(reset(schemaKey)).submitWithAudit(interaction.user.id); - - const response = schemaKey.display(trx.settings, t); - const content = t(Root.ResetSuccess, { key, value: response }); - return interaction.reply({ content, allowedMentions: { users: [], roles: [] }, flags: MessageFlags.Ephemeral }); - } - - #getTextResponse(response: string) { - return isValidCustomEmoji(response) || isValidSerializedTwemoji(response) || isValidTwemoji(response) ? response : inlineCode(response); - } - - async #fetchKeyFromInteraction(interaction: WolfSubcommand.Interaction, t: ReturnType) { - const key = interaction.options.getString('key', true); - const message = t(Root.GetNoExt, { key }); - - const value = getConfigurableGroups().getPathString(key.toLowerCase()); - if (isNullish(value) || value.dashboardOnly) { - this.error(message); - } - - if (isSchemaKey(value)) { - return [value.name, value as SchemaKey] as const; - } - - const keys = map( - filter(value.childValues(), (value) => !value.dashboardOnly), - (value) => inlineCode(value.name) - ); - this.error(LanguageKeys.Settings.Gateway.ChooseKey, { keys: toArray(keys) }); - } -} diff --git a/src/commands/Admin/roleset.ts b/src/commands/Admin/roleset.ts deleted file mode 100644 index 23344ea86..000000000 --- a/src/commands/Admin/roleset.ts +++ /dev/null @@ -1,204 +0,0 @@ -import { readSettings, writeSettings, writeSettingsTransaction, type ReadonlyGuildData, type UniqueRoleSet } from '#lib/database'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { WolfCommand, WolfSubcommand } from '#lib/structures'; -import { PermissionLevels, type GuildMessage } from '#lib/types'; -import { ApplyOptions } from '@sapphire/decorators'; -import { CommandOptionsRunTypeEnum } from '@sapphire/framework'; -import { send } from '@sapphire/plugin-editable-commands'; - -const Root = LanguageKeys.Commands.Admin; - -@ApplyOptions({ - aliases: ['rs'], - description: Root.RoleSetDescription, - detailedDescription: Root.RoleSetExtended, - permissionLevel: PermissionLevels.Administrator, - runIn: [CommandOptionsRunTypeEnum.GuildAny], - subcommands: [ - { name: 'add', messageRun: 'add' }, - { name: 'remove', messageRun: 'remove' }, - { name: 'reset', messageRun: 'reset' }, - { name: 'list', messageRun: 'list' }, - { name: 'auto', messageRun: 'auto', default: true } - ] -}) -export class UserCommand extends WolfSubcommand { - // This subcommand will always ADD roles in to a existing set OR it will create a new set if that set does not exist - public async add(message: GuildMessage, args: WolfSubcommand.Args) { - return this.handleAdd(message, await args.pick('string'), args); - } - - // This subcommand will always remove roles from a provided role set. - public async remove(message: GuildMessage, args: WolfSubcommand.Args) { - const name = await args.pick('string'); - const roles = await args.repeat('roleName'); - - // Get all rolesets from settings and check if there is an existing set with the name provided by the user - await writeSettings( - message.guild, - (settings) => ({ - // The set does exist so we want to only REMOVE provided roles from it - // Create a new array that we can use to overwrite the existing one in settings - rolesUniqueRoleSets: settings.rolesUniqueRoleSets.map((set) => - set.name === name ? { name, roles: set.roles.filter((id: string) => !roles.find((role) => role.id === id)) } : set - ) - }), - message.author.id - ); - - return send(message, args.t(Root.RoleSetRemoved, { name, roles: roles.map((role) => role.name) })); - } - - public async reset(message: GuildMessage, args: WolfSubcommand.Args) { - const [name, sets] = await Promise.all([ - args.pick('string').catch(() => null), - // Get all rolesets from settings and check if there is an existing set with the name provided by the user - this.#getUniqueRoleSets(message) - ]); - if (sets.length === 0) this.error(Root.RoleSetResetEmpty); - - if (!name) { - await writeSettings(message.guild, { rolesUniqueRoleSets: [] }, message.author.id); - return send(message, args.t(Root.RoleSetResetAll)); - } - - const arrayIndex = sets.findIndex((set) => set.name === name); - if (arrayIndex === -1) this.error(Root.RoleSetResetNotExists, { name }); - - await writeSettings( - message.guild, - { - rolesUniqueRoleSets: sets.toSpliced(arrayIndex, 1) - }, - message.author.id - ); - - return send(message, args.t(Root.RoleSetResetGroup, { name })); - } - - // This subcommand will run if a user doesn't type add or remove. The bot will then add AND remove based on whether that role is in the set already. - public async auto(message: GuildMessage, args: WolfSubcommand.Args) { - const name = await args.pick('string'); - - // Get all role sets from settings and check if there is an existing set with the name provided by the user - const sets = await this.#getUniqueRoleSets(message); - const set = sets.find((set) => set.name === name); - - // If this role set does not exist we have to create it - if (!set) return this.handleAdd(message, name, args); - - // The role set exists - const roles = await args.repeat('roleName'); - const newSets = sets.map((set) => { - if (set.name !== name) return set; - // Add any role that wasn't in the set that the user provided - // This will also remove any of the roles that user provided and were already in the set - const newRoles = set.roles // - .map((id) => (roles.some((role) => role.id === id) ? null : id)) - .filter((id) => id) as string[]; - - for (const role of roles) if (!set.roles.includes(role.id)) newRoles.push(role.id); - - return { name, roles: newRoles }; - }); - - await writeSettings(message.guild, { rolesUniqueRoleSets: newSets }, message.author.id); - return send(message, args.t(Root.RoleSetUpdated, { name })); - } - - // This subcommand will show the user a list of role sets and each role in that set. - public async list(message: GuildMessage, args: WolfCommand.Args) { - // Get all rolesets from settings - const sets = await this.#getUniqueRoleSets(message); - if (sets.length === 0) this.error(Root.RoleSetNoRoleSets); - - const list = await this.handleList(message, args, sets); - return send(message, list.join('\n')); - } - - private async handleList(message: GuildMessage, args: WolfCommand.Args, sets: readonly UniqueRoleSet[]) { - let changed = false; - - const list: string[] = []; - const guildRoles = message.guild.roles.cache; - for (const set of sets) { - const roles: string[] = []; - for (const id of set.roles) { - const role = guildRoles.get(id); - if (role === undefined) { - changed = true; - continue; - } - - roles.push(role.name); - } - - if (roles.length === 0) { - changed = true; - continue; - } - - list.push(`💠 **${set.name}**: ${args.t(LanguageKeys.Globals.AndListValue, { value: roles })}`); - } - - // If there were changes, scan a second time to clean up the data: - if (changed) { - // If after cleaning up, all sets end up empty, reset and return error: - if (list.length === 0) { - await writeSettings(message.guild, { rolesUniqueRoleSets: [] }, message.author.id); - this.error(Root.RoleSetNoRoleSets); - } - - // Else, clean up: - await writeSettings( - message.guild, - (settings) => ({ - rolesUniqueRoleSets: this.cleanRoleSets(message, settings) - }), - message.author.id - ); - } - - return list; - } - - private cleanRoleSets(message: GuildMessage, settings: ReadonlyGuildData) { - const guildRoles = message.guild.roles.cache; - - return settings.rolesUniqueRoleSets - .map((set) => ({ name: set.name, roles: set.roles.filter((role) => guildRoles.has(role)) })) - .filter((set) => set.roles.length > 0); - } - - private async handleAdd(message: GuildMessage, name: string, args: WolfCommand.Args) { - const roles = await args.repeat('roleName'); - - // Get all rolesets from settings and check if there is an existing set with the name provided by the user - using trx = await writeSettingsTransaction(message.guild); - - const entries = trx.settings.rolesUniqueRoleSets; - const index = entries.findIndex((set) => set.name === name); - - // If it does not exist we need to create a brand new set - if (index === -1) { - const rolesUniqueRoleSets = entries.concat({ name, roles: roles.map((role) => role.id) }); - trx.write({ rolesUniqueRoleSets }); - } else { - // The set does exist so we want to only ADD new roles in - // Create a new array that we can use to overwrite the existing one in settings - const entry = entries[index]; - const rolesUniqueRoleSets = entries.with(index, { name, roles: entry.roles.concat(roles.map((role) => role.id)) }); - trx.write({ rolesUniqueRoleSets }); - } - await trx.submitWithAudit(message.author.id); - - const created = index === -1; - const key = created ? Root.RoleSetCreated : Root.RoleSetAdded; - return send(message, args.t(key, { name, roles: roles.map((role) => role.name) })); - } - - async #getUniqueRoleSets(message: GuildMessage) { - const settings = await readSettings(message.guild); - return settings.rolesUniqueRoleSets; - } -} diff --git a/src/commands/Fun/escaperope.ts b/src/commands/Fun/escaperope.ts deleted file mode 100644 index 7f1c43410..000000000 --- a/src/commands/Fun/escaperope.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { WolfCommand } from '#lib/structures'; -import { CdnUrls } from '#utils/constants'; -import { deleteMessage } from '#utils/functions'; -import { getColor, getFullEmbedAuthor } from '#utils/util'; -import { EmbedBuilder } from '@discordjs/builders'; -import { ApplyOptions } from '@sapphire/decorators'; -import { send } from '@sapphire/plugin-editable-commands'; -import type { Message } from 'discord.js'; - -@ApplyOptions({ - aliases: ['escape'], - description: LanguageKeys.Commands.Fun.EscapeRopeDescription, - detailedDescription: LanguageKeys.Commands.Fun.EscapeRopeExtended -}) -export class UserCommand extends WolfCommand { - public override async messageRun(message: Message, args: WolfCommand.Args) { - if (message.deletable) await deleteMessage(message).catch(() => null); - - const embed = new EmbedBuilder() - .setColor(getColor(message)) - .setImage(CdnUrls.EscapeRopeGif) - .setDescription(args.t(LanguageKeys.Commands.Fun.EscapeRopeOutput, { user: message.author.toString() })) - .setAuthor(getFullEmbedAuthor(message.author)); - return send(message, { embeds: [embed] }); - } -} diff --git a/src/commands/Games/c4.ts b/src/commands/Games/c4.ts deleted file mode 100644 index 943b860b5..000000000 --- a/src/commands/Games/c4.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { ConnectFourBotController } from '#lib/games/connect-four/ConnectFourBotController'; -import { ConnectFourGame } from '#lib/games/connect-four/ConnectFourGame'; -import { ConnectFourHumanController } from '#lib/games/connect-four/ConnectFourHumanController'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { WolfCommand } from '#lib/structures'; -import type { GuildMessage } from '#lib/types'; -import { promptConfirmation } from '#utils/functions'; -import { ApplyOptions } from '@sapphire/decorators'; -import { CommandOptionsRunTypeEnum } from '@sapphire/framework'; -import { PermissionFlagsBits, type User } from 'discord.js'; - -@ApplyOptions({ - aliases: ['connect-four'], - description: LanguageKeys.Commands.Games.C4Description, - detailedDescription: LanguageKeys.Commands.Games.C4Extended, - flags: ['easy', 'medium', 'hard'], - requiredClientPermissions: [PermissionFlagsBits.UseExternalEmojis, PermissionFlagsBits.AddReactions, PermissionFlagsBits.ReadMessageHistory], - runIn: [CommandOptionsRunTypeEnum.GuildAny] -}) -export class UserCommand extends WolfCommand { - private readonly channels = new Set(); - - public override async messageRun(message: GuildMessage, args: WolfCommand.Args) { - if (this.channels.has(message.channel.id)) this.error(LanguageKeys.Commands.Games.GamesProgress); - - const user = await args.pick('userName'); - const player1 = this.getAuthorController(message); - const player2 = await this.getTargetController(message, user, args); - - this.channels.add(message.channel.id); - const game = new ConnectFourGame(message, player1, player2); - - try { - await game.run(); - } finally { - this.channels.delete(message.channel.id); - } - } - - private getAuthorController(message: GuildMessage) { - return new ConnectFourHumanController(message.author.username, message.author.id); - } - - private async getTargetController(message: GuildMessage, user: User, args: WolfCommand.Args) { - if (user.id === process.env.CLIENT_ID) return new ConnectFourBotController(this.getDifficulty(args)); - if (user.bot) this.error(LanguageKeys.Commands.Games.GamesBot); - if (user.id === message.author.id) this.error(LanguageKeys.Commands.Games.GamesSelf); - - const response = await promptConfirmation(message, { - content: args.t(LanguageKeys.Commands.Games.C4Prompt, { - challenger: message.author.toString(), - challengee: user.toString() - }), - target: user - }); - - if (response) return new ConnectFourHumanController(user.username, user.id); - this.error(LanguageKeys.Commands.Games.GamesPromptDeny); - } - - private getDifficulty(args: WolfCommand.Args) { - if (args.getFlags('hard')) return 7; - if (args.getFlags('easy')) return 3; - return 5; - } -} diff --git a/src/commands/Games/hungergames.ts b/src/commands/Games/hungergames.ts deleted file mode 100644 index 639bc4726..000000000 --- a/src/commands/Games/hungergames.ts +++ /dev/null @@ -1,272 +0,0 @@ -import { HungerGamesUsage } from '#lib/games/HungerGamesUsage'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { WolfCommand } from '#lib/structures'; -import type { GuildMessage } from '#lib/types'; -import { LongLivingReactionCollector, type LLRCData } from '#utils/LongLivingReactionCollector'; -import { minutes } from '#utils/common'; -import { deleteMessage, isModerator } from '#utils/functions'; -import { cleanMentions } from '#utils/util'; -import { ApplyOptions } from '@sapphire/decorators'; -import { canSendMessages } from '@sapphire/discord.js-utilities'; -import { CommandOptionsRunTypeEnum } from '@sapphire/framework'; -import { send } from '@sapphire/plugin-editable-commands'; -import type { TFunction } from '@sapphire/plugin-i18next'; -import { chunk, isFunction } from '@sapphire/utilities'; -import { PermissionFlagsBits } from 'discord.js'; -import { setTimeout as sleep } from 'node:timers/promises'; - -@ApplyOptions({ - aliases: ['hunger-games', 'hg'], - description: LanguageKeys.Commands.Games.HungerGamesDescription, - detailedDescription: LanguageKeys.Commands.Games.HungerGamesExtended, - flags: ['autofill', 'autoskip'], - requiredClientPermissions: [PermissionFlagsBits.AddReactions, PermissionFlagsBits.ReadMessageHistory], - runIn: [CommandOptionsRunTypeEnum.GuildAny] -}) -export class UserCommand extends WolfCommand { - public readonly playing: Set = new Set(); - public readonly kEmojis = ['🇳', '🇾']; - - public override async messageRun(message: GuildMessage, args: WolfCommand.Args, context: WolfCommand.RunContext) { - const autoFilled = args.getFlags('autofill'); - const tributes = args.finished && autoFilled ? [] : args.nextSplit({ times: 50 }); - const autoSkip = args.getFlags('autoskip'); - - if (autoFilled) { - const messages = await message.channel.messages.fetch({ limit: 100 }); - - for (const { author } of messages.values()) { - if (author && !tributes.includes(author.username)) tributes.push(author.username); - } - } else if (tributes.length === 0) { - this.error(LanguageKeys.Commands.Games.GamesNoPlayers, { prefix: context.commandPrefix }); - } - - const filtered = new Set(tributes); - if (filtered.size !== tributes.length) this.error(LanguageKeys.Commands.Games.GamesRepeat); - if (this.playing.has(message.channel.id)) this.error(LanguageKeys.Commands.Games.GamesProgress); - if (filtered.size < 4 || filtered.size > 48) this.error(LanguageKeys.Commands.Games.GamesTooManyOrFew, { min: 4, max: 48 }); - this.playing.add(message.channel.id); - - let resolve: ((value: boolean) => void) | null = null; - let gameMessage: GuildMessage | null = null; - const game: HungerGamesGame = Object.seal({ - bloodbath: true, - llrc: new LongLivingReactionCollector( - async (reaction) => { - // Ignore if resolve is not ready - if ( - !isFunction(resolve) || - // Run the collector inhibitor - (await this.collectorInhibitor(message, gameMessage!, reaction)) - ) - return; - resolve(Boolean(this.kEmojis.indexOf(reaction.emoji.id ?? reaction.emoji.name!))); - resolve = null; - }, - () => { - if (isFunction(resolve)) resolve(false); - this.playing.delete(message.channel.id); - } - ), - sun: true, - tributes: this.shuffle([...filtered].map(cleanMentions.bind(null, message.guild))), - turn: 0 - }); - - try { - while (game.tributes.size > 1) { - // If it's not bloodbath and it became the day, increase the turn - if (!game.bloodbath && game.sun) ++game.turn; - const events = game.bloodbath - ? LanguageKeys.Commands.Games.HungerGamesBloodbath - : game.sun - ? LanguageKeys.Commands.Games.HungerGamesDay - : LanguageKeys.Commands.Games.HungerGamesNight; - - // Main logic of the game - const { results, deaths } = this.makeResultEvents( - game, - args.t(events).map((usage) => HungerGamesUsage.create(usage)) - ); - const texts = this.buildTexts(args.t, game, results, deaths); - - // Ask for the user to proceed: - for (const text of texts) { - // If the we can not longer send messages to the channel, break: - if (!canSendMessages(message.channel)) return; - - // Refresh the LLRC's timer, send new message with new reactions: - game.llrc.setTime(minutes(2)); - gameMessage = (await message.channel.send(text)) as GuildMessage; - for (const emoji of ['🇾', '🇳']) { - await gameMessage.react(emoji); - } - - // Ask for verification. - // NOTE: This does not deadlock because the callback is assigned to a variable in the scope, which - // is called with `false` when the LLRC times out. - const verification = await new Promise((res) => { - resolve = res; - if (autoSkip) { - sleep((gameMessage!.content.length / 20) * 1000).then(() => res(true)); - } - }); - - // Delete the previous message, and if stopped, send stop. - await deleteMessage(gameMessage); - if (!verification) { - if (canSendMessages(message.channel)) { - const content = args.t(LanguageKeys.Commands.Games.HungerGamesStop); - await send(message, content); - } - return; - } - } - if (game.bloodbath) game.bloodbath = false; - else game.sun = !game.sun; - } - - // The match finished with one remaining player - const content = args.t(LanguageKeys.Commands.Games.HungerGamesWinner, { winner: game.tributes.values().next().value as string }); - await send(message, content); - } finally { - game.llrc.end(); - } - } - - private async collectorInhibitor(message: GuildMessage, gameMessage: GuildMessage, reaction: LLRCData) { - // If there's no gameMessage, inhibit - if (!gameMessage) return true; - - // If the message reacted is not the game's, inhibit - if (reaction.messageId !== gameMessage.id) return true; - - // If the emoji reacted is not valid, inhibit - if (!this.kEmojis.includes(reaction.emoji.id ?? reaction.emoji.name!)) return true; - - // If the user who reacted is the author, don't inhibit - if (reaction.userId === message.author.id) return false; - - // Don't listen to herself - if (reaction.userId === process.env.CLIENT_ID) return true; - - try { - // Fetch the member for level measuring purposes - const member = await message.guild.members.fetch(reaction.userId); - // Check if the user is a moderator - return !(await isModerator(member)); - } catch { - return true; - } - } - - private buildTexts(t: TFunction, game: HungerGamesGame, results: string[], deaths: string[]) { - const headerKey = game.bloodbath - ? LanguageKeys.Commands.Games.HungerGamesResultHeaderBloodbath - : game.sun - ? LanguageKeys.Commands.Games.HungerGamesResultHeaderSun - : LanguageKeys.Commands.Games.HungerGamesResultHeaderMoon; - - const header = t(headerKey, { game }); - const death = deaths.length - ? `${t(LanguageKeys.Commands.Games.HungerGamesResultDeaths, { count: deaths.length })}\n\n${deaths.map((d) => `- ${d}`).join('\n')}` - : ''; - const proceed = t(LanguageKeys.Commands.Games.HungerGamesResultProceed); - const panels = chunk(results, 5); - - const texts = panels.map((panel) => `__**${header}:**__\n\n${panel.map((text) => `- ${text}`).join('\n')}\n\n_${proceed}_`) as string[]; - if (deaths.length) texts.push(`${death}\n\n_${proceed}_`); - return texts; - } - - private pick(events: readonly HungerGamesUsage[], tributes: number, maxDeaths: number) { - events = events.filter((event) => event.tributes <= tributes && event.deaths.size <= maxDeaths); - return events[Math.floor(Math.random() * events.length)]; - } - - private pickTributes(tribute: string, turn: Set, amount: number) { - if (amount === 0) return []; - if (amount === 1) return [tribute]; - const array = [...turn]; - array.splice(array.indexOf(tribute), 1); - - let m = array.length; - while (m) { - const i = Math.floor(Math.random() * m--); - [array[m], array[i]] = [array[i], array[m]]; - } - array.unshift(tribute); - return array.slice(0, amount); - } - - private makeResultEvents(game: HungerGamesGame, events: readonly HungerGamesUsage[]) { - const results = [] as string[]; - const deaths = [] as string[]; - let maxDeaths = this.calculateMaxDeaths(game); - - const turn = new Set(game.tributes); - for (const tribute of game.tributes) { - // If the player already had its turn, skip - if (!turn.has(tribute)) continue; - - // Pick a valid event - const event = this.pick(events, turn.size, maxDeaths); - - // Pick the tributes - const pickedTributes = this.pickTributes(tribute, turn, event.tributes); - - // Delete all the picked tributes from this round - for (const picked of pickedTributes) { - turn.delete(picked); - } - - // Kill all the unfortunate tributes - for (const death of event.deaths) { - game.tributes.delete(pickedTributes[death]); - deaths.push(pickedTributes[death]); - maxDeaths--; - } - - // Push the result of this match - results.push(event.display(...pickedTributes)); - } - - return { results, deaths }; - } - - private shuffle(tributes: string[]) { - let m = tributes.length; - while (m) { - const i = Math.floor(Math.random() * m--); - [tributes[m], tributes[i]] = [tributes[i], tributes[m]]; - } - return new Set(tributes); - } - - private calculateMaxDeaths(game: HungerGamesGame) { - // If there are more than 16 tributes, perform a large blood bath - return game.tributes.size >= 16 - ? // For 16 people, 4 die, 36 -> 6, and so on keeps the game interesting. - // If it's in bloodbath, perform 50% more deaths. - Math.ceil(Math.sqrt(game.tributes.size) * (game.bloodbath ? 1.5 : 1)) - : // If there are more than 7 tributes, proceed to kill them in 4 or more. - game.tributes.size > 7 - ? // If it's a bloodbath, perform mass death (12 -> 7), else eliminate 4. - game.bloodbath - ? Math.ceil(Math.min(game.tributes.size - 3, Math.sqrt(game.tributes.size) * 2)) - : 4 - : // If there are 4 tributes, eliminate 2, else 1 (3 -> 2, 2 -> 1) - game.tributes.size === 4 - ? 2 - : 1; - } -} - -export interface HungerGamesGame { - bloodbath: boolean; - llrc: LongLivingReactionCollector; - sun: boolean; - tributes: Set; - turn: number; -} diff --git a/src/commands/Games/tictactoe.ts b/src/commands/Games/tictactoe.ts deleted file mode 100644 index 2e3e25c77..000000000 --- a/src/commands/Games/tictactoe.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { TicTacToeBotController } from '#lib/games/tic-tac-toe/TicTacToeBotController'; -import { TicTacToeGame } from '#lib/games/tic-tac-toe/TicTacToeGame'; -import { TicTacToeHumanController } from '#lib/games/tic-tac-toe/TicTacToeHumanController'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { WolfCommand } from '#lib/structures'; -import type { GuildMessage } from '#lib/types'; -import { promptConfirmation } from '#utils/functions'; -import { ApplyOptions } from '@sapphire/decorators'; -import { CommandOptionsRunTypeEnum } from '@sapphire/framework'; -import type { TFunction } from '@sapphire/plugin-i18next'; -import { PermissionFlagsBits, type User } from 'discord.js'; - -@ApplyOptions({ - aliases: ['ttt'], - description: LanguageKeys.Commands.Games.TicTacToeDescription, - detailedDescription: LanguageKeys.Commands.Games.TicTacToeExtended, - requiredClientPermissions: [PermissionFlagsBits.AddReactions, PermissionFlagsBits.ReadMessageHistory], - runIn: [CommandOptionsRunTypeEnum.GuildAny] -}) -export class UserCommand extends WolfCommand { - private readonly channels: Set = new Set(); - - public override async messageRun(message: GuildMessage, args: WolfCommand.Args) { - if (this.channels.has(message.channel.id)) this.error(LanguageKeys.Commands.Games.GamesProgress); - - const user = await args.pick('userName'); - const player1 = this.getAuthorController(message); - const player2 = await this.getTargetController(message, args.t, user); - - this.channels.add(message.channel.id); - const game = new TicTacToeGame(message, player1, player2); - - try { - await game.run(); - } finally { - this.channels.delete(message.channel.id); - } - } - - private getAuthorController(message: GuildMessage) { - return new TicTacToeHumanController(message.author.username, message.author.id); - } - - private async getTargetController(message: GuildMessage, t: TFunction, user: User) { - if (user.id === process.env.CLIENT_ID) return new TicTacToeBotController(); - if (user.bot) this.error(LanguageKeys.Commands.Games.GamesBot); - if (user.id === message.author.id) this.error(LanguageKeys.Commands.Games.GamesSelf); - - const response = await promptConfirmation(message, { - content: t(LanguageKeys.Commands.Games.TicTacToePrompt, { - challenger: message.author.toString(), - challengee: user.toString() - }), - target: user - }); - - if (response) return new TicTacToeHumanController(user.username, user.id); - this.error(LanguageKeys.Commands.Games.GamesPromptDeny); - } -} diff --git a/src/commands/Games/trivia.ts b/src/commands/Games/trivia.ts deleted file mode 100644 index 506152daa..000000000 --- a/src/commands/Games/trivia.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { CATEGORIES, QuestionDifficulty, QuestionType, getQuestion, type QuestionData } from '#lib/games/TriviaManager'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { WolfCommand } from '#lib/structures'; -import { floatPromise, minutes, seconds } from '#utils/common'; -import { sendTemporaryMessage } from '#utils/functions'; -import { sendLoadingMessage, shuffle } from '#utils/util'; -import { EmbedBuilder } from '@discordjs/builders'; -import { ApplyOptions } from '@sapphire/decorators'; -import { Args } from '@sapphire/framework'; -import { send } from '@sapphire/plugin-editable-commands'; -import type { TFunction } from '@sapphire/plugin-i18next'; -import { MessageCollector, PermissionFlagsBits, type Message, type User } from 'discord.js'; -import he from 'he'; - -@ApplyOptions({ - description: LanguageKeys.Commands.Games.TriviaDescription, - detailedDescription: LanguageKeys.Commands.Games.TriviaExtended, - requiredClientPermissions: [PermissionFlagsBits.AddReactions, PermissionFlagsBits.EmbedLinks, PermissionFlagsBits.ReadMessageHistory] -}) -export class UserCommand extends WolfCommand { - #channels = new Set(); - - public override async messageRun(message: Message, args: WolfCommand.Args) { - const category = await args.pick(UserCommand.category).catch(() => CATEGORIES.general); - const questionType = await args.pick(UserCommand.questionType).catch(() => QuestionType.Multiple); - const difficulty = await args.pick(UserCommand.questionDifficulty).catch(() => QuestionDifficulty.Easy); - const duration = args.finished ? seconds(30) : await args.pick('timespan', { minimum: seconds(1), maximum: minutes(1) }); - - if (this.#channels.has(message.channel.id)) this.error(LanguageKeys.Commands.Games.TriviaActiveGame); - this.#channels.add(message.channel.id); - - try { - await sendLoadingMessage(message, args.t); - const data = await getQuestion(category, difficulty, questionType); - const possibleAnswers = - questionType === QuestionType.Boolean - ? ['True', 'False'] - : shuffle([data.correct_answer, ...data.incorrect_answers].map((ans) => he.decode(ans))); - const correctAnswer = he.decode(data.correct_answer); - - const questionEmbed = this.buildQuestionEmbed(args.t, data, possibleAnswers); - await send(message, { embeds: [questionEmbed] }); - const filter = (msg: Message) => { - const num = Number(msg.content); - return Number.isInteger(num) && num > 0 && num <= possibleAnswers.length; - }; - const collector = new MessageCollector(message.channel, { filter, time: duration }); - - let winner: User | null = null; - // users who have already participated - const participants = new Set(); - - return collector - .on('collect', (collected: Message) => { - if (participants.has(collected.author.id)) return; - const attempt = possibleAnswers[Number.parseInt(collected.content, 10) - 1]; - if (attempt === correctAnswer) { - winner = collected.author; - return collector.stop(); - } - participants.add(collected.author.id); - floatPromise(sendTemporaryMessage(collected, args.t(LanguageKeys.Commands.Games.TriviaIncorrect, { attempt }))); - }) - .on('end', () => { - this.#channels.delete(message.channel.id); - - const content = winner - ? args.t(LanguageKeys.Commands.Games.TriviaWinner, { winner: winner.toString(), correctAnswer }) - : args.t(LanguageKeys.Commands.Games.TriviaNoAnswer, { correctAnswer }); - floatPromise(send(message, content)); - }); - } catch (error) { - this.#channels.delete(message.channel.id); - this.container.logger.fatal(error); - this.error(LanguageKeys.Misc.UnexpectedIssue); - } - } - - public buildQuestionEmbed(t: TFunction, data: QuestionData, possibleAnswers: string[]) { - const titles = t(LanguageKeys.Commands.Games.TriviaEmbedTitles); - const questionDisplay = possibleAnswers.map((possible, i) => `${i + 1}. ${possible}`); - return new EmbedBuilder() - .setAuthor({ name: titles.trivia }) - .setTitle(data.category) - .setColor(0xf37917) - .setThumbnail('https://i.imgur.com/zPtu5aP.png') - .setDescription([`${titles.difficulty}: ${data.difficulty}`, '', he.decode(data.question), '', questionDisplay.join('\n')].join('\n')); - } - - private static category = Args.make((parameter, { argument }) => { - const lowerCasedParameter = parameter.toLowerCase(); - const category = Reflect.get(CATEGORIES, lowerCasedParameter); - if (typeof category === 'number') return Args.ok(category); - return Args.error({ argument, parameter, identifier: LanguageKeys.Commands.Games.TriviaInvalidCategory }); - }); - - private static questionType = Args.make((parameter, { argument }) => { - const lowerCasedParameter = parameter.toLowerCase(); - if (lowerCasedParameter === 'boolean' || lowerCasedParameter === 'truefalse') return Args.ok(QuestionType.Boolean); - if (lowerCasedParameter === 'multiple') return Args.ok(QuestionType.Multiple); - return Args.error({ argument, parameter }); - }); - - private static questionDifficulty = Args.make((parameter, { argument }) => { - const lowerCasedParameter = parameter.toLowerCase(); - if (lowerCasedParameter === 'easy') return Args.ok(QuestionDifficulty.Easy); - if (lowerCasedParameter === 'medium') return Args.ok(QuestionDifficulty.Medium); - if (lowerCasedParameter === 'hard') return Args.ok(QuestionDifficulty.Hard); - return Args.error({ argument, parameter }); - }); -} diff --git a/src/commands/General/help.ts b/src/commands/General/help.ts deleted file mode 100644 index ec639014f..000000000 --- a/src/commands/General/help.ts +++ /dev/null @@ -1,208 +0,0 @@ -import { LanguageHelp, type LanguageHelpDisplayOptions } from '#lib/i18n/LanguageHelp'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { WolfCommand } from '#lib/structures'; -import { isGuildMessage, isPrivateMessage } from '#utils/common'; -import { getColor, splitMessage } from '#utils/util'; -import { ApplyOptions, RequiresClientPermissions } from '@sapphire/decorators'; -import { UserOrMemberMentionRegex } from '@sapphire/discord-utilities'; -import { PaginatedMessage } from '@sapphire/discord.js-utilities'; -import { Args, Result, container, type MessageCommand } from '@sapphire/framework'; -import { send } from '@sapphire/plugin-editable-commands'; -import type { TFunction } from '@sapphire/plugin-i18next'; -import { Collection, EmbedBuilder, PermissionFlagsBits, type Message } from 'discord.js'; - -/** - * Sorts a collection alphabetically as based on the keys, rather than the values. - * This is used to ensure that subcategories are listed in the pages right after the main category. - * @param _ The first element for comparison - * @param __ The second element for comparison - * @param firstCategory Key of the first element for comparison - * @param secondCategory Key of the second element for comparison - */ -function sortCommandsAlphabetically(_: WolfCommand[], __: WolfCommand[], firstCategory: string, secondCategory: string): 1 | -1 | 0 { - if (firstCategory > secondCategory) return 1; - if (secondCategory > firstCategory) return -1; - return 0; -} - -@ApplyOptions({ - aliases: ['commands', 'cmd', 'cmds'], - description: LanguageKeys.Commands.General.HelpDescription, - detailedDescription: LanguageKeys.Commands.General.HelpExtended, - flags: ['cat', 'categories', 'all'], - guarded: true -}) -export class UserCommand extends WolfCommand { - public override async messageRun(message: Message, args: WolfCommand.Args, context: WolfCommand.RunContext) { - if (args.finished) { - if (args.getFlags('cat', 'categories')) return this.helpCategories(message, args); - if (args.getFlags('all')) return this.all(message, args, context); - } - - const category = await args.pickResult(UserCommand.categories); - if (category.isOk()) return this.display(message, args, category.unwrap() - 1, context); - - const page = await args.pickResult('integer', { minimum: 0 }); - if (page.isOk()) return this.display(message, args, page.unwrap() - 1, context); - - // Handle case for a single command - const command = await args.pickResult('commandName'); - if (command.isOk()) { - const embed = await this.buildCommandHelp(message, args, command.unwrap(), this.getCommandPrefix(context)); - return send(message, { embeds: [embed] }); - } - - return this.display(message, args, null, context); - } - - private getCommandPrefix(context: WolfCommand.RunContext): string { - return (context.prefix instanceof RegExp && !context.commandPrefix.endsWith(' ')) || UserOrMemberMentionRegex.test(context.commandPrefix) - ? `${context.commandPrefix} ` - : context.commandPrefix; - } - - private async helpCategories(message: Message, args: WolfCommand.Args) { - const commandsByCategory = await UserCommand.fetchCommands(message); - let i = 0; - const commandCategories: string[] = []; - for (const [category, commands] of commandsByCategory) { - const line = String(++i).padStart(2, '0'); - commandCategories.push( - `\`${line}.\` **${category}** → ${args.t(LanguageKeys.Commands.General.HelpCommandCount, { count: commands.length })}` - ); - } - - const content = commandCategories.join('\n'); - return send(message, content); - } - - private async all(message: Message, args: WolfCommand.Args, context: WolfCommand.RunContext) { - const fullContent = await this.buildHelp(message, args.t, this.getCommandPrefix(context)); - const contents = splitMessage(fullContent, { char: '\n', maxLength: 2000 }); - - for (const content of contents) { - const result = await Result.fromAsync(message.author.send(content)); - if (result.isOk()) continue; - - if (isPrivateMessage(message)) this.error(LanguageKeys.Commands.General.HelpNoDm); - return; - } - - if (isGuildMessage(message)) await send(message, args.t(LanguageKeys.Commands.General.HelpDm)); - } - - @RequiresClientPermissions(PermissionFlagsBits.EmbedLinks) - private async display(message: Message, args: WolfCommand.Args, index: number | null, context: WolfCommand.RunContext) { - const prefix = this.getCommandPrefix(context); - - const content = args.t(LanguageKeys.Commands.General.HelpAllFlag, { prefix }); - - const display = await this.buildDisplay(message, args.t, prefix); - if (index !== null) display.setIndex(index); - - const response = await send(message, content); - await display.run(response, message.author); - return response; - } - - private async buildHelp(message: Message, language: TFunction, prefix: string) { - const commands = await UserCommand.fetchCommands(message); - - const helpMessage: string[] = []; - for (const [category, list] of commands) { - helpMessage.push(`**${category} Commands**:\n`, list.map(this.formatCommand.bind(this, language, prefix, false)).join('\n'), ''); - } - - return helpMessage.join('\n'); - } - - private async buildDisplay(message: Message, language: TFunction, prefix: string) { - const commandsByCategory = await UserCommand.fetchCommands(message); - - const display = new PaginatedMessage({ - template: new EmbedBuilder().setColor(getColor(message)) - }) // - .setSelectMenuOptions((pageIndex) => ({ label: commandsByCategory.at(pageIndex - 1)![0].fullCategory!.join(' → ') })); - - for (const [category, commands] of commandsByCategory) { - display.addPageEmbed((embed) => - embed // - .setTitle(`${category} Commands`) - .setDescription(commands.map(this.formatCommand.bind(this, language, prefix, true)).join('\n')) - ); - } - - return display; - } - - @RequiresClientPermissions(PermissionFlagsBits.EmbedLinks) - private async buildCommandHelp(message: Message, args: WolfCommand.Args, command: WolfCommand, prefixUsed: string) { - const builderData = args.t(LanguageKeys.System.HelpTitles); - - const builder = new LanguageHelp() - .setUsages(builderData.usages) - .setAliases(builderData.aliases) - .setExtendedHelp(builderData.extendedHelp) - .setExplainedUsage(builderData.explainedUsage) - .setExamples(builderData.examples) - .setPossibleFormats(builderData.possibleFormats) - .setReminder(builderData.reminders); - - const extendedHelpData = args.t(command.detailedDescription, { - replace: { prefix: prefixUsed } - }) as LanguageHelpDisplayOptions; - const extendedHelp = builder.display(command.name, this.formatAliases(args.t, command.aliases), extendedHelpData, prefixUsed); - - const data = args.t(LanguageKeys.Commands.General.HelpData, { - footerName: command.name, - titleDescription: args.t(command.description) - }); - return new EmbedBuilder() - .setColor(getColor(message)) - .setTimestamp() - .setFooter({ text: data.footer }) - .setTitle(data.title) - .setDescription(extendedHelp); - } - - private formatAliases(t: TFunction, aliases: readonly string[]): string | null { - if (aliases.length === 0) return null; - return t(LanguageKeys.Globals.AndListValue, { value: aliases.map((alias) => `\`${alias}\``) }); - } - - private formatCommand(t: TFunction, prefix: string, paginatedMessage: boolean, command: WolfCommand) { - const description = t(command.description); - return paginatedMessage ? `• ${prefix}${command.name} → ${description}` : `• **${prefix}${command.name}** → ${description}`; - } - - private static categories = Args.make(async (parameter, { argument, message }) => { - const lowerCasedParameter = parameter.toLowerCase(); - const commandsByCategory = await UserCommand.fetchCommands(message); - for (const [page, category] of [...commandsByCategory.keys()].entries()) { - // Add 1, since 1 will be subtracted later - if (category.toLowerCase() === lowerCasedParameter) return Args.ok(page + 1); - } - - return Args.error({ argument, parameter }); - }); - - private static async fetchCommands(message: Message) { - const commands = container.stores.get('commands'); - const filtered = new Collection(); - await Promise.all( - commands.map(async (cmd) => { - const command = cmd as WolfCommand; - if (command.hidden) return; - - const result = await cmd.preconditions.messageRun(message, command as MessageCommand, { command: null! }); - if (result.isErr()) return; - - const category = filtered.get(command.fullCategory.join(' → ')); - if (category) category.push(command); - else filtered.set(command.fullCategory.join(' → '), [command]); - }) - ); - - return filtered.sort(sortCommandsAlphabetically); - } -} diff --git a/src/commands/General/info-deprecations.ts b/src/commands/General/info-deprecations.ts deleted file mode 100644 index 54a37ee23..000000000 --- a/src/commands/General/info-deprecations.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { WolfCommand } from '#lib/structures'; -import { PermissionLevels, type GuildMessage } from '#lib/types'; -import { ApplyOptions } from '@sapphire/decorators'; -import { CommandOptionsRunTypeEnum } from '@sapphire/framework'; -import { send } from '@sapphire/plugin-editable-commands'; -import { chatInputApplicationCommandMention } from 'discord.js'; - -@ApplyOptions({ - name: '\u200Binfo-deprecations', - aliases: ['invite', 'donate', 'support', 'support-server', 'server'], - description: LanguageKeys.Commands.General.V7Description, - detailedDescription: LanguageKeys.Commands.General.V7Extended, - permissionLevel: PermissionLevels.Moderator, - runIn: [CommandOptionsRunTypeEnum.GuildAny] -}) -export class UserCommand extends WolfCommand { - public override async messageRun(message: GuildMessage, args: WolfCommand.Args) { - const caseCommand = this.store.get('info') as WolfCommand; - const id = caseCommand.getGlobalCommandId(); - const command = chatInputApplicationCommandMention(caseCommand.name, id); - const content = args.t(LanguageKeys.Commands.Shared.DeprecatedMessage, { command }); - return send(message, content); - } -} diff --git a/src/commands/General/info.ts b/src/commands/General/info.ts deleted file mode 100644 index 1d412859a..000000000 --- a/src/commands/General/info.ts +++ /dev/null @@ -1,189 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { getSupportedUserLanguageT } from '#lib/i18n/translate'; -import { WolfCommand } from '#lib/structures'; -import { EmbedBuilder, TimestampStyles, time } from '@discordjs/builders'; -import { ApplyOptions } from '@sapphire/decorators'; -import { ApplicationCommandRegistry, version as sapphireVersion } from '@sapphire/framework'; -import { send } from '@sapphire/plugin-editable-commands'; -import { applyLocalizedBuilder, type TFunction } from '@sapphire/plugin-i18next'; -import { - ButtonStyle, - ComponentType, - InteractionContextType, - MessageFlags, - OAuth2Scopes, - PermissionFlagsBits, - chatInputApplicationCommandMention, - version as djsVersion, - type APIActionRowComponent, - type APIEmbedField, - type APIButtonComponent, - type Message -} from 'discord.js'; -import { cpus, uptime, type CpuInfo } from 'node:os'; - -const Root = LanguageKeys.Commands.Info; - -@ApplyOptions({ - aliases: ['bot-info', 'stats', 'sts'], - description: Root.Description, - detailedDescription: LanguageKeys.Commands.Shared.SlashOnlyDetailedDescription, - hidden: true -}) -export class UserCommand extends WolfCommand { - public override registerApplicationCommands(registry: ApplicationCommandRegistry) { - registry.registerChatInputCommand( - (command) => - applyLocalizedBuilder(command, Root.Name, Root.Description) // - .setContexts(InteractionContextType.Guild, InteractionContextType.PrivateChannel), - { - idHints: [ - '1239990526061711554' // wolfstar-prod production - ] - } - ); - } - - public override messageRun(message: Message, args: WolfCommand.Args) { - const content = args.t(LanguageKeys.Commands.Shared.DeprecatedMessage, { - command: chatInputApplicationCommandMention(this.name, this.getGlobalCommandId()) - }); - return send(message, { content }); - } - - public override async chatInputRun(interaction: WolfCommand.ChatInputInteraction) { - const t = getSupportedUserLanguageT(interaction); - const embed = new EmbedBuilder() - .setDescription(t(Root.EmbedDescription)) - .addFields(this.getApplicationStatistics(t), this.getUptimeStatistics(t), this.getServerUsageStatistics(t)); - const components = this.getComponents(t); - - return interaction.reply({ embeds: [embed], components, flags: MessageFlags.Ephemeral }); - } - - private getApplicationStatistics(t: TFunction): APIEmbedField { - return { - name: t(Root.EmbedFieldApplicationTitle), - value: t(Root.EmbedFieldApplicationValue, { - channels: this.container.client.channels.cache.size, - guilds: this.container.client.guilds.cache.size, - users: this.container.client.guilds.cache.reduce((acc, val) => acc + (val.memberCount ?? 0), 0), - versionNode: process.version, - versionDiscord: `v${djsVersion}`, - versionSapphire: `v${sapphireVersion}` - }) - }; - } - - private getUptimeStatistics(t: TFunction): APIEmbedField { - const now = Date.now(); - const nowSeconds = Math.round(now / 1000); - - return { - name: t(Root.EmbedFieldUptimeTitle), - value: t(Root.EmbedFieldUptimeValue, { - host: time(Math.round(nowSeconds - uptime()), TimestampStyles.RelativeTime), - client: time(Math.round(nowSeconds - process.uptime()), TimestampStyles.RelativeTime) - }) - }; - } - - private getServerUsageStatistics(t: TFunction): APIEmbedField { - const usage = process.memoryUsage(); - - return { - name: t(Root.EmbedFieldServerUsageTitle), - value: t(Root.EmbedFieldServerUsageValue, { - cpu: cpus().map(this.formatCpuInfo.bind(null)).join(' | '), - heapUsed: (usage.heapUsed / 1048576).toLocaleString(t.lng, { maximumFractionDigits: 2 }), - heapTotal: (usage.heapTotal / 1048576).toLocaleString(t.lng, { maximumFractionDigits: 2 }) - }) - }; - } - - private getComponents(t: TFunction) { - const url = this.getInvite(); - const support = this.getSupportComponent(t); - const github = this.getGitHubComponent(t); - const donate = this.getDonateComponent(t); - const data = url - ? [this.getActionRow(support, this.getInviteComponent(t, url)), this.getActionRow(github, donate)] - : [this.getActionRow(support, github, donate)]; - - return data; - } - - private getActionRow(...components: APIButtonComponent[]): APIActionRowComponent { - return { type: ComponentType.ActionRow, components }; - } - - private getSupportComponent(t: TFunction): APIButtonComponent { - return { - type: ComponentType.Button, - style: ButtonStyle.Link, - label: t(Root.ButtonSupport), - emoji: { name: '🆘' }, - url: 'https://join.wolfstar.rocks' - }; - } - - private getInviteComponent(t: TFunction, url: string): APIButtonComponent { - return { - type: ComponentType.Button, - style: ButtonStyle.Link, - label: t(Root.ButtonInvite), - emoji: { name: '🎉' }, - url - }; - } - - private getGitHubComponent(t: TFunction): APIButtonComponent { - return { - type: ComponentType.Button, - style: ButtonStyle.Link, - label: t(Root.ButtonGitHub), - emoji: { id: '950888087188283422', name: 'github2' }, - url: 'https://github.com/wolfstar-project/wolfstar' - }; - } - - private getDonateComponent(t: TFunction): APIButtonComponent { - return { - type: ComponentType.Button, - style: ButtonStyle.Link, - label: t(Root.ButtonDonate), - emoji: { name: '🧡' }, - url: 'https://donate.wolfstar.rocks' - }; - } - - private formatCpuInfo({ times }: CpuInfo) { - return `${Math.round(((times.user + times.nice + times.sys + times.irq) / times.idle) * 10000) / 100}%`; - } - - private getInvite() { - return this.container.client.generateInvite({ - scopes: [OAuth2Scopes.Bot, OAuth2Scopes.ApplicationsCommands], - permissions: - PermissionFlagsBits.AddReactions | - PermissionFlagsBits.AttachFiles | - PermissionFlagsBits.BanMembers | - PermissionFlagsBits.ChangeNickname | - PermissionFlagsBits.DeafenMembers | - PermissionFlagsBits.EmbedLinks | - PermissionFlagsBits.KickMembers | - PermissionFlagsBits.ManageChannels | - PermissionFlagsBits.ManageMessages | - PermissionFlagsBits.ManageNicknames | - PermissionFlagsBits.ManageRoles | - PermissionFlagsBits.ManageThreads | - PermissionFlagsBits.MoveMembers | - PermissionFlagsBits.MuteMembers | - PermissionFlagsBits.ReadMessageHistory | - PermissionFlagsBits.SendMessages | - PermissionFlagsBits.SendMessagesInThreads | - PermissionFlagsBits.UseExternalEmojis | - PermissionFlagsBits.ViewChannel - }); - } -} diff --git a/src/commands/General/v7-artiel.ts b/src/commands/General/v7-artiel.ts deleted file mode 100644 index f2bd7f1cd..000000000 --- a/src/commands/General/v7-artiel.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { WolfCommand } from '#lib/structures'; -import { ButtonInviteArtiel, ButtonSkyraV7, createDeprecatedList, makeReplacedMessage, makeRow } from '#utils/deprecate'; -import { ApplyOptions } from '@sapphire/decorators'; -import { send } from '@sapphire/plugin-editable-commands'; -import type { Message } from 'discord.js'; - -const list = createDeprecatedList({ - entries: [ - { out: '', in: ['dice', 'roll'] }, - { out: '', in: ['bunny', 'bunbun', 'rabbit'] }, - { out: '', in: ['kitty', 'kitten', 'cat'] }, - { out: '', in: ['dog', 'doggo', 'puppy'] }, - { out: '', in: ['fox'] }, - { out: '', in: ['shibe'] }, - { - out: '', - in: [ - 'changemymind', - 'cmm', - 'chase', - 'cuddle', - 'deletthis', - 'deletethis', - 'f', - 'pray', - 'good-night', - 'gn', - 'night', - 'goofytime', - 'goof', - 'goofy', - 'daddy', - 'goofie', - 'goofietime', - 'hug', - 'ineedhealing', - 'heal', - 'healing', - 'shindeiru', - 'thesearch', - 'think', - 'triggered', - 'wakanda', - 'where' - ] - }, - { out: '', in: ['ship'] }, - { out: '', in: ['xkcd'] } - ] -}); - -const row = makeRow(ButtonInviteArtiel, ButtonSkyraV7); - -@ApplyOptions({ - name: '\u200Bv7-artiel', - aliases: [...list.keys()], - description: LanguageKeys.Commands.General.V7Description, - detailedDescription: LanguageKeys.Commands.General.V7Extended, - generateDashLessAliases: false, - hidden: true -}) -export class UserCommand extends WolfCommand { - public override messageRun(message: Message, args: WolfCommand.Args) { - return send(message, makeReplacedMessage(args.commandContext.commandName, row, list)); - } -} diff --git a/src/commands/General/v7-skyra.ts b/src/commands/General/v7-skyra.ts deleted file mode 100644 index 242512d56..000000000 --- a/src/commands/General/v7-skyra.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { WolfCommand } from '#lib/structures'; -import { ButtonSkyraV7, makeRemovedMessage, makeRow } from '#utils/deprecate'; -import { ApplyOptions } from '@sapphire/decorators'; -import { send } from '@sapphire/plugin-editable-commands'; -import type { Message } from 'discord.js'; - -const row = makeRow(ButtonSkyraV7); - -@ApplyOptions({ - name: '\u200Bv7-skyra', - aliases: ['ping', 'pong'], - description: LanguageKeys.Commands.General.V7SkyraDescription, - detailedDescription: LanguageKeys.Commands.General.V7SkyraExtended, - hidden: true -}) -export class UserCommand extends WolfCommand { - public messageRun(message: Message, args: WolfCommand.Args) { - return send(message, makeRemovedMessage(args.commandContext.commandName, row)); - } -} diff --git a/src/commands/General/v7-teryl.ts b/src/commands/General/v7-teryl.ts deleted file mode 100644 index d64cdb3a0..000000000 --- a/src/commands/General/v7-teryl.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { WolfCommand } from '#lib/structures'; -import { ButtonInviteTeryl, ButtonSkyraV7, createDeprecatedList, makeReplacedMessage, makeRow } from '#utils/deprecate'; -import { ApplyOptions } from '@sapphire/decorators'; -import { send } from '@sapphire/plugin-editable-commands'; -import type { Message } from 'discord.js'; - -const list = createDeprecatedList({ - entries: [{ out: '', in: ['remindme', 'rmm', 'remind', 'reminder', 'reminders'] }] -}); - -const row = makeRow(ButtonInviteTeryl, ButtonSkyraV7); - -@ApplyOptions({ - name: '\u200Bv7-teryl', - aliases: [...list.keys()], - description: LanguageKeys.Commands.General.V7Description, - detailedDescription: LanguageKeys.Commands.General.V7Extended, - generateDashLessAliases: false, - hidden: true -}) -export class UserCommand extends WolfCommand { - public override messageRun(message: Message, args: WolfCommand.Args) { - return send(message, makeReplacedMessage(args.commandContext.commandName, row, list)); - } -} diff --git a/src/commands/Management/AutoModeration/automod-attachments.ts b/src/commands/Management/AutoModeration/automod-attachments.ts deleted file mode 100644 index b8e03f104..000000000 --- a/src/commands/Management/AutoModeration/automod-attachments.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { AutoModerationCommand } from '#lib/moderation'; -import { ApplyOptions } from '@sapphire/decorators'; - -const Root = LanguageKeys.Commands.AutoModeration; - -@ApplyOptions({ - aliases: ['attachment-mode', 'attachments-mode', 'manage-attachment', 'manage-attachments'], - description: Root.AttachmentsDescription, - localizedNameKey: Root.AttachmentsName, - adderPropertyName: 'attachments', - keyEnabled: 'selfmodAttachmentsEnabled', - keyOnInfraction: 'selfmodAttachmentsSoftAction', - keyPunishment: 'selfmodAttachmentsHardAction', - keyPunishmentDuration: 'selfmodAttachmentsHardActionDuration', - keyPunishmentThreshold: 'selfmodAttachmentsThresholdMaximum', - keyPunishmentThresholdPeriod: 'selfmodAttachmentsThresholdDuration', - idHints: [ - '1239990528351932426' // wolfstar-prod production - ] -}) -export class UserAutoModerationCommand extends AutoModerationCommand {} diff --git a/src/commands/Management/AutoModeration/automod-capitals.ts b/src/commands/Management/AutoModeration/automod-capitals.ts deleted file mode 100644 index 0d989ddf3..000000000 --- a/src/commands/Management/AutoModeration/automod-capitals.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { AutoModerationCommand } from '#lib/moderation'; -import { ApplyOptions } from '@sapphire/decorators'; - -const Root = LanguageKeys.Commands.AutoModeration; - -@ApplyOptions({ - aliases: ['capitals-mode', 'manage-capitals'], - description: Root.CapitalsDescription, - localizedNameKey: Root.CapitalsName, - adderPropertyName: 'capitals', - keyEnabled: 'selfmodCapitalsEnabled', - keyOnInfraction: 'selfmodCapitalsSoftAction', - keyPunishment: 'selfmodCapitalsHardAction', - keyPunishmentDuration: 'selfmodCapitalsHardActionDuration', - keyPunishmentThreshold: 'selfmodCapitalsThresholdMaximum', - keyPunishmentThresholdPeriod: 'selfmodCapitalsThresholdDuration', - idHints: [ - '1239990532885839872' // wolfstar-prod production - ] -}) -export class UserAutoModerationCommand extends AutoModerationCommand {} diff --git a/src/commands/Management/AutoModeration/automod-invites.ts b/src/commands/Management/AutoModeration/automod-invites.ts deleted file mode 100644 index a729d2e40..000000000 --- a/src/commands/Management/AutoModeration/automod-invites.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { AutoModerationCommand } from '#lib/moderation'; -import { ApplyOptions } from '@sapphire/decorators'; - -const Root = LanguageKeys.Commands.AutoModeration; - -@ApplyOptions({ - aliases: ['invite-mode', 'invites-mode', 'manage-invite', 'manage-invites'], - description: Root.InvitesDescription, - localizedNameKey: Root.InvitesName, - adderPropertyName: 'invites', - keyEnabled: 'selfmodInvitesEnabled', - keyOnInfraction: 'selfmodInvitesSoftAction', - keyPunishment: 'selfmodInvitesHardAction', - keyPunishmentDuration: 'selfmodInvitesHardActionDuration', - keyPunishmentThreshold: 'selfmodInvitesThresholdMaximum', - keyPunishmentThresholdPeriod: 'selfmodInvitesThresholdDuration', - idHints: [ - '1239990535293243392' // wolfstar-prod production - ] -}) -export class UserAutoModerationCommand extends AutoModerationCommand {} diff --git a/src/commands/Management/AutoModeration/automod-links.ts b/src/commands/Management/AutoModeration/automod-links.ts deleted file mode 100644 index e72601f35..000000000 --- a/src/commands/Management/AutoModeration/automod-links.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { AutoModerationCommand } from '#lib/moderation'; -import { ApplyOptions } from '@sapphire/decorators'; - -const Root = LanguageKeys.Commands.AutoModeration; - -@ApplyOptions({ - aliases: ['link-mode', 'links-mode', 'manage-link', 'manage-links'], - description: Root.LinksDescription, - localizedNameKey: Root.LinksName, - adderPropertyName: 'links', - keyEnabled: 'selfmodLinksEnabled', - keyOnInfraction: 'selfmodLinksSoftAction', - keyPunishment: 'selfmodLinksHardAction', - keyPunishmentDuration: 'selfmodLinksHardActionDuration', - keyPunishmentThreshold: 'selfmodLinksThresholdMaximum', - keyPunishmentThresholdPeriod: 'selfmodLinksThresholdDuration', - idHints: [ - '1239990537793310843' // wolfstar-prod production - ] -}) -export class UserAutoModerationCommand extends AutoModerationCommand {} diff --git a/src/commands/Management/AutoModeration/automod-newlines.ts b/src/commands/Management/AutoModeration/automod-newlines.ts deleted file mode 100644 index 631faab54..000000000 --- a/src/commands/Management/AutoModeration/automod-newlines.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { AutoModerationCommand } from '#lib/moderation'; -import { ApplyOptions } from '@sapphire/decorators'; - -const Root = LanguageKeys.Commands.AutoModeration; - -@ApplyOptions({ - aliases: ['newline-mode', 'newlines-mode', 'manage-newline', 'manage-newlines'], - description: Root.NewlinesDescription, - localizedNameKey: Root.NewlinesName, - adderPropertyName: 'newlines', - keyEnabled: 'selfmodNewlinesEnabled', - keyOnInfraction: 'selfmodNewlinesSoftAction', - keyPunishment: 'selfmodNewlinesHardAction', - keyPunishmentDuration: 'selfmodNewlinesHardActionDuration', - keyPunishmentThreshold: 'selfmodNewlinesThresholdMaximum', - keyPunishmentThresholdPeriod: 'selfmodNewlinesThresholdDuration', - idHints: [ - '1239990614796402820' // wolfstar-prod production - ] -}) -export class UserAutoModerationCommand extends AutoModerationCommand {} diff --git a/src/commands/Management/AutoModeration/automod-reactions.ts b/src/commands/Management/AutoModeration/automod-reactions.ts deleted file mode 100644 index db0ea6e74..000000000 --- a/src/commands/Management/AutoModeration/automod-reactions.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { AutoModerationCommand } from '#lib/moderation'; -import { ApplyOptions } from '@sapphire/decorators'; - -const Root = LanguageKeys.Commands.AutoModeration; - -@ApplyOptions({ - aliases: ['reaction-mode', 'r-mode'], - description: Root.ReactionsDescription, - localizedNameKey: Root.ReactionsName, - adderPropertyName: 'reactions', - keyEnabled: 'selfmodReactionsEnabled', - keyOnInfraction: 'selfmodReactionsSoftAction', - keyPunishment: 'selfmodReactionsHardAction', - keyPunishmentDuration: 'selfmodReactionsHardActionDuration', - keyPunishmentThreshold: 'selfmodReactionsThresholdMaximum', - keyPunishmentThresholdPeriod: 'selfmodReactionsThresholdDuration', - idHints: [ - '1239990618831458466' // wolfstar-prod production - ] -}) -export class UserAutoModerationCommand extends AutoModerationCommand {} diff --git a/src/commands/Management/AutoModeration/automod-spam.ts b/src/commands/Management/AutoModeration/automod-spam.ts deleted file mode 100644 index e7a32c231..000000000 --- a/src/commands/Management/AutoModeration/automod-spam.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { AutoModerationCommand } from '#lib/moderation'; -import { ApplyOptions } from '@sapphire/decorators'; - -const Root = LanguageKeys.Commands.AutoModeration; - -@ApplyOptions({ - aliases: ['message-mode', 'messages-mode', 'manage-message', 'manage-messages'], - description: Root.SpamDescription, - localizedNameKey: Root.SpamName, - adderPropertyName: 'messages', - keyEnabled: 'selfmodMessagesEnabled', - keyOnInfraction: 'selfmodMessagesSoftAction', - keyPunishment: 'selfmodMessagesHardAction', - keyPunishmentDuration: 'selfmodMessagesHardActionDuration', - keyPunishmentThreshold: 'selfmodMessagesThresholdMaximum', - keyPunishmentThresholdPeriod: 'selfmodMessagesThresholdDuration', - idHints: [ - '1239990622207737866' // wolfstar-prod production - ] -}) -export class UserAutoModerationCommand extends AutoModerationCommand {} diff --git a/src/commands/Management/AutoModeration/automod-words.ts b/src/commands/Management/AutoModeration/automod-words.ts deleted file mode 100644 index 336d51d6c..000000000 --- a/src/commands/Management/AutoModeration/automod-words.ts +++ /dev/null @@ -1,148 +0,0 @@ -import { - readSettingsWordFilterRegExp, - writeSettingsTransaction, - type GuildDataValue, - type ReadonlyGuildData, - type SchemaDataKey -} from '#lib/database'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { getSupportedUserLanguageT } from '#lib/i18n/translate'; -import { AutoModerationCommand } from '#lib/moderation'; -import { IncomingType, OutgoingType } from '#lib/moderation/workers'; -import type { WolfSubcommand } from '#lib/structures'; -import type { GuildMessage } from '#lib/types'; -import { addAutomaticFields } from '#utils/functions'; -import { chatInputApplicationCommandMention, type SlashCommandBuilder, type SlashCommandSubcommandBuilder } from '@discordjs/builders'; -import { ApplyOptions } from '@sapphire/decorators'; -import { send } from '@sapphire/plugin-editable-commands'; -import { applyLocalizedBuilder, type TFunction } from '@sapphire/plugin-i18next'; -import { isNullishOrEmpty, type Awaitable } from '@sapphire/utilities'; -import { remove as removeConfusables } from 'confusables'; -import { inlineCode, MessageFlags, type Guild } from 'discord.js'; - -const Root = LanguageKeys.Commands.AutoModeration; - -@ApplyOptions({ - aliases: ['filter-mode', 'word-filter-mode', 'manage-filter', 'filter'], - description: Root.WordsDescription, - localizedNameKey: Root.WordsName, - subcommands: [ - { name: 'add', chatInputRun: 'chatInputRunAdd', messageRun: 'messageRunAdd' }, - { name: 'remove', chatInputRun: 'chatInputRunRemove', messageRun: 'messageRunRemove' } - ], - resetKeys: [{ key: Root.OptionsKeyWords, value: 'words' }], - adderPropertyName: 'words', - keyEnabled: 'selfmodFilterEnabled', - keyOnInfraction: 'selfmodFilterSoftAction', - keyPunishment: 'selfmodFilterHardAction', - keyPunishmentDuration: 'selfmodFilterHardActionDuration', - keyPunishmentThreshold: 'selfmodFilterThresholdMaximum', - keyPunishmentThresholdPeriod: 'selfmodFilterThresholdDuration', - idHints: [ - '1239990625965834270' // wolfstar-prod production - ] -}) -export class UserAutoModerationCommand extends AutoModerationCommand { - /** @deprecated */ - public messageRunAdd(message: GuildMessage, args: WolfSubcommand.Args) { - const command = chatInputApplicationCommandMention(this.name, 'add', this.getGlobalCommandId()); - return send(message, args.t(LanguageKeys.Commands.Shared.DeprecatedMessage, { command })); - } - - /** @deprecated */ - public messageRunRemove(message: GuildMessage, args: WolfSubcommand.Args) { - const command = chatInputApplicationCommandMention(this.name, 'remove', this.getGlobalCommandId()); - return send(message, args.t(LanguageKeys.Commands.Shared.DeprecatedMessage, { command })); - } - - public async chatInputRunAdd(interaction: AutoModerationCommand.Interaction) { - const word = this.#getWord(interaction); - const { guild } = interaction; - - const t = getSupportedUserLanguageT(interaction); - using trx = await writeSettingsTransaction(guild); - if (await this.#hasWord(trx.settings, word)) { - return interaction.reply({ content: t(Root.WordAddFiltered, { word }), flags: MessageFlags.Ephemeral }); - } - - await trx.write({ selfmodFilterRaw: trx.settings.selfmodFilterRaw.concat(word) }).submitWithAudit(interaction.user.id); - return interaction.reply({ content: t(Root.EditSuccess), flags: MessageFlags.Ephemeral }); - } - - public async chatInputRunRemove(interaction: AutoModerationCommand.Interaction) { - const word = this.#getWord(interaction); - const { guild } = interaction; - - const t = getSupportedUserLanguageT(interaction); - using trx = await writeSettingsTransaction(guild); - - const index = trx.settings.selfmodFilterRaw.indexOf(word); - if (index === -1) { - return interaction.reply({ content: t(Root.WordRemoveNotFiltered, { word }), flags: MessageFlags.Ephemeral }); - } - - await trx.write({ selfmodFilterRaw: trx.settings.selfmodFilterRaw.toSpliced(index, 1) }).submitWithAudit(interaction.user.id); - return interaction.reply({ content: t(Root.EditSuccess), flags: MessageFlags.Ephemeral }); - } - - protected override showEnabled(t: TFunction, settings: ReadonlyGuildData) { - const embed = super.showEnabled(t, settings); - - const words = settings.selfmodFilterRaw; - if (isNullishOrEmpty(words)) { - const command = chatInputApplicationCommandMention(this.name, 'add', this.getGlobalCommandId()); - embed.addFields({ - name: t(Root.WordShowListTitleEmpty), - value: t(Root.WordShowListEmpty, { command }) - }); - } else { - addAutomaticFields( - embed, - t(Root.WordShowListTitle, { count: words.length }), - t(Root.WordShowList, { words: words.map((word) => inlineCode(word)) }) - ); - } - return embed; - } - - protected override registerSubcommands(builder: SlashCommandBuilder) { - return super - .registerSubcommands(builder) - .addSubcommand((subcommand) => this.registerAddSubcommand(subcommand)) - .addSubcommand((subcommand) => this.registerRemoveSubcommand(subcommand)); - } - - protected registerAddSubcommand(subcommand: SlashCommandSubcommandBuilder) { - return applyLocalizedBuilder(subcommand, Root.AddName, Root.WordAddDescription) // - .addStringOption((option) => applyLocalizedBuilder(option, Root.OptionsWord).setRequired(true).setMinLength(2).setMaxLength(32)); - } - - protected registerRemoveSubcommand(subcommand: SlashCommandSubcommandBuilder) { - return applyLocalizedBuilder(subcommand, Root.RemoveName, Root.WordRemoveDescription) // - .addStringOption((option) => applyLocalizedBuilder(option, Root.OptionsWord).setRequired(true).setMinLength(2).setMaxLength(32)); - } - - protected override resetGetKeyValuePairFallback(guild: Guild, key: string): Awaitable { - if (key === 'words') return ['selfmodFilterRaw', []]; - return super.resetGetKeyValuePairFallback(guild, key); - } - - #getWord(interaction: AutoModerationCommand.Interaction) { - return removeConfusables(interaction.options.getString('word', true).toLowerCase()); - } - - async #hasWord(settings: ReadonlyGuildData, word: string) { - const words = settings.selfmodFilterRaw; - if (words.includes(word)) return true; - - const regExp = readSettingsWordFilterRegExp(settings); - if (regExp === null) return false; - - try { - const result = await this.container.workers.send({ type: IncomingType.RunRegExp, content: word, regExp }); - return result.type === OutgoingType.RegExpMatch; - } catch { - return false; - } - } -} diff --git a/src/commands/Management/Configuration/manage-command-auto-delete.ts b/src/commands/Management/Configuration/manage-command-auto-delete.ts deleted file mode 100644 index 84ab75691..000000000 --- a/src/commands/Management/Configuration/manage-command-auto-delete.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { readSettings, writeSettings, writeSettingsTransaction, type CommandAutoDelete } from '#lib/database'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { WolfSubcommand } from '#lib/structures'; -import { PermissionLevels, type GuildMessage } from '#lib/types'; -import { minutes, seconds } from '#utils/common'; -import { ApplyOptions } from '@sapphire/decorators'; -import type { GuildTextBasedChannelTypes } from '@sapphire/discord.js-utilities'; -import { CommandOptionsRunTypeEnum } from '@sapphire/framework'; -import { send } from '@sapphire/plugin-editable-commands'; -import { codeBlock } from '@sapphire/utilities'; - -@ApplyOptions({ - aliases: ['mcad'], - description: LanguageKeys.Commands.Management.ManageCommandAutoDeleteDescription, - detailedDescription: LanguageKeys.Commands.Management.ManageCommandAutoDeleteExtended, - permissionLevel: PermissionLevels.Administrator, - runIn: [CommandOptionsRunTypeEnum.GuildAny], - subcommands: [ - { name: 'add', messageRun: 'add' }, - { name: 'remove', messageRun: 'remove' }, - { name: 'reset', messageRun: 'reset' }, - { name: 'show', messageRun: 'show', default: true } - ] -}) -export class UserCommand extends WolfSubcommand { - public async add(message: GuildMessage, args: WolfSubcommand.Args) { - const channel = await args.pick('textChannelName'); - const time = await args.pick('timespan', { minimum: seconds(1), maximum: minutes(2) }); - - using trx = await writeSettingsTransaction(message.guild); - const index = trx.settings.commandAutoDelete.findIndex(([id]) => id === channel.id); - const value: CommandAutoDelete = [channel.id, time]; - - const commandAutoDelete = - index === -1 // - ? trx.settings.commandAutoDelete.concat(value) - : trx.settings.commandAutoDelete.with(index, value); - await trx.write({ commandAutoDelete }).submitWithAudit(message.author.id); - - const content = args.t(LanguageKeys.Commands.Management.ManageCommandAutoDeleteAdd, { channel: channel.toString(), time }); - return send(message, content); - } - - public async remove(message: GuildMessage, args: WolfSubcommand.Args) { - const channel = await args.pick('textChannelName'); - - using trx = await writeSettingsTransaction(message.guild); - const index = trx.settings.commandAutoDelete.findIndex(([id]) => id === channel.id); - if (index === -1) { - this.error(LanguageKeys.Commands.Management.ManageCommandAutoDeleteRemoveNotSet, { channel: channel.toString() }); - } - - const commandAutoDelete = trx.settings.commandAutoDelete.toSpliced(index, 1); - await trx.write({ commandAutoDelete }).submitWithAudit(message.author.id); - - const content = args.t(LanguageKeys.Commands.Management.ManageCommandAutoDeleteRemove, { channel: channel.toString() }); - return send(message, content); - } - - public async reset(message: GuildMessage, args: WolfSubcommand.Args) { - await writeSettings(message.guild, { commandAutoDelete: [] }, message.author.id); - - const content = args.t(LanguageKeys.Commands.Management.ManageCommandAutoDeleteReset); - return send(message, content); - } - - public async show(message: GuildMessage, args: WolfSubcommand.Args) { - const settings = await readSettings(message.guild); - - const { commandAutoDelete } = settings; - if (!commandAutoDelete.length) this.error(LanguageKeys.Commands.Management.ManageCommandAutoDeleteShowEmpty); - - const list: string[] = []; - for (const entry of commandAutoDelete) { - const channel = this.container.client.channels.cache.get(entry[0]) as GuildTextBasedChannelTypes; - if (channel) list.push(`${channel.name.padEnd(26)} :: ${args.t(LanguageKeys.Globals.DurationValue, { value: seconds(entry[1]) })}`); - } - if (!list.length) this.error(LanguageKeys.Commands.Management.ManageCommandAutoDeleteShowEmpty); - - const content = args.t(LanguageKeys.Commands.Management.ManageCommandAutoDeleteShow, { codeblock: codeBlock('asciidoc', list.join('\n')) }); - return send(message, content); - } -} diff --git a/src/commands/Management/Configuration/manage-command-channel.ts b/src/commands/Management/Configuration/manage-command-channel.ts deleted file mode 100644 index e1b5004b9..000000000 --- a/src/commands/Management/Configuration/manage-command-channel.ts +++ /dev/null @@ -1,113 +0,0 @@ -import { readSettings, writeSettingsTransaction } from '#lib/database'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { WolfSubcommand } from '#lib/structures'; -import { PermissionLevels, type GuildMessage } from '#lib/types'; -import { ApplyOptions } from '@sapphire/decorators'; -import { CommandOptionsRunTypeEnum } from '@sapphire/framework'; -import { send } from '@sapphire/plugin-editable-commands'; - -@ApplyOptions({ - aliases: ['mcc'], - description: LanguageKeys.Commands.Management.ManageCommandChannelDescription, - detailedDescription: LanguageKeys.Commands.Management.ManageCommandChannelExtended, - permissionLevel: PermissionLevels.Administrator, - runIn: [CommandOptionsRunTypeEnum.GuildAny], - subcommands: [ - { name: 'add', messageRun: 'add' }, - { name: 'remove', messageRun: 'remove' }, - { name: 'reset', messageRun: 'reset' }, - { name: 'show', messageRun: 'show', default: true } - ] -}) -export class UserCommand extends WolfSubcommand { - public async add(message: GuildMessage, args: WolfSubcommand.Args) { - const channel = await args.pick('textChannelName'); - const command = await args.pick('command'); - - using trx = await writeSettingsTransaction(message.guild); - - const index = trx.settings.disabledCommandsChannels.findIndex((entry) => entry.channel === channel.id); - if (index === -1) { - trx.write({ - disabledCommandsChannels: trx.settings.disabledCommandsChannels.concat({ channel: channel.id, commands: [command.name] }) - }); - } else { - const entry = trx.settings.disabledCommandsChannels[index]; - if (entry.commands.includes(command.name)) { - this.error(LanguageKeys.Commands.Management.ManageCommandChannelAddAlreadySet); - } - - trx.write({ - disabledCommandsChannels: trx.settings.disabledCommandsChannels.with(index, { - channel: channel.id, - commands: entry.commands.concat(command.name) - }) - }); - } - - await trx.submitWithAudit(message.author.id); - - const content = args.t(LanguageKeys.Commands.Management.ManageCommandChannelAdd, { channel: channel.toString(), command: command.name }); - return send(message, content); - } - - public async remove(message: GuildMessage, args: WolfSubcommand.Args) { - const channel = await args.pick('textChannelName'); - const command = await args.pick('command'); - - using trx = await writeSettingsTransaction(message.guild); - - const index = trx.settings.disabledCommandsChannels.findIndex((entry) => entry.channel === channel.id); - if (index === -1) { - this.error(LanguageKeys.Commands.Management.ManageCommandChannelRemoveNotSet, { channel: channel.toString() }); - } - - const entry = trx.settings.disabledCommandsChannels[index]; - const commandIndex = entry.commands.indexOf(command.name); - if (commandIndex === -1) { - this.error(LanguageKeys.Commands.Management.ManageCommandChannelRemoveNotSet, { channel: channel.toString() }); - } - - const disabledCommandsChannels = - entry.commands.length === 1 - ? trx.settings.disabledCommandsChannels.toSpliced(index, 1) - : trx.settings.disabledCommandsChannels.with(index, { channel: channel.id, commands: entry.commands.toSpliced(commandIndex, 1) }); - await trx.write({ disabledCommandsChannels }).submitWithAudit(message.author.id); - - const content = args.t(LanguageKeys.Commands.Management.ManageCommandChannelRemove, { channel: channel.toString(), command: command.name }); - return send(message, content); - } - - public async reset(message: GuildMessage, args: WolfSubcommand.Args) { - const channel = await args.pick('textChannelName'); - - using trx = await writeSettingsTransaction(message.guild); - - const index = trx.settings.disabledCommandsChannels.findIndex((entry) => entry.channel === channel.id); - if (index === -1) { - this.error(LanguageKeys.Commands.Management.ManageCommandChannelResetEmpty); - } - - await trx.write({ disabledCommandsChannels: trx.settings.disabledCommandsChannels.toSpliced(index, 1) }).submitWithAudit(message.author.id); - - const content = args.t(LanguageKeys.Commands.Management.ManageCommandChannelReset, { channel: channel.toString() }); - return send(message, content); - } - - public async show(message: GuildMessage, args: WolfSubcommand.Args) { - const channel = await args.pick('textChannelName'); - const settings = await readSettings(message.guild); - - const { disabledCommandsChannels } = settings; - const entry = disabledCommandsChannels.find((e) => e.channel === channel.id); - if (!entry?.commands.length) { - this.error(LanguageKeys.Commands.Management.ManageCommandChannelShowEmpty); - } - - const content = args.t(LanguageKeys.Commands.Management.ManageCommandChannelShow, { - channel: channel.toString(), - commands: `\`${entry.commands.join('` | `')}\`` - }); - return send(message, content); - } -} diff --git a/src/commands/Management/Configuration/manage-reaction-roles.ts b/src/commands/Management/Configuration/manage-reaction-roles.ts deleted file mode 100644 index 172d58459..000000000 --- a/src/commands/Management/Configuration/manage-reaction-roles.ts +++ /dev/null @@ -1,143 +0,0 @@ -import { readSettings, writeSettingsTransaction, type ReactionRole } from '#lib/database'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { WolfSubcommand } from '#lib/structures'; -import { PermissionLevels, type GuildMessage } from '#lib/types'; -import { minutes } from '#utils/common'; -import { getEmojiString, getEmojiTextFormat } from '#utils/functions'; -import { LongLivingReactionCollector } from '#utils/LongLivingReactionCollector'; -import { getColor, sendLoadingMessage } from '#utils/util'; -import { channelMention, hideLinkEmbed, hyperlink, roleMention } from '@discordjs/builders'; -import { ApplyOptions, RequiresClientPermissions } from '@sapphire/decorators'; -import { PaginatedMessage } from '@sapphire/discord.js-utilities'; -import { CommandOptionsRunTypeEnum } from '@sapphire/framework'; -import { send } from '@sapphire/plugin-editable-commands'; -import { chunk } from '@sapphire/utilities'; -import { EmbedBuilder, PermissionFlagsBits, type Guild } from 'discord.js'; - -@ApplyOptions({ - aliases: ['mrr', 'managereactionrole', 'managerolereaction', 'managerolereactions'], - description: LanguageKeys.Commands.Management.ManageReactionRolesDescription, - detailedDescription: LanguageKeys.Commands.Management.ManageReactionRolesExtended, - permissionLevel: PermissionLevels.Administrator, - runIn: [CommandOptionsRunTypeEnum.GuildAny], - subcommands: [ - { name: 'add', messageRun: 'add' }, - { name: 'remove', messageRun: 'remove' }, - { name: 'reset', messageRun: 'reset' }, - { name: 'show', messageRun: 'show', default: true } - ] -}) -export class UserCommand extends WolfSubcommand { - public async add(message: GuildMessage, args: WolfSubcommand.Args) { - const role = await args.pick('roleName'); - if (!args.finished) { - const channel = await args.pick('textChannelName'); - const emoji = await args.pick('emoji'); - const reactionRole: ReactionRole = { - emoji: getEmojiString(emoji), - message: null, - channel: channel.id, - role: role.id - }; - - await writeSettings( - message.guild, - (settings) => ({ - reactionRoles: settings.reactionRoles.concat(reactionRole) - }), - message.author.id - ); - const content = args.t(LanguageKeys.Commands.Management.ManageReactionRolesAddChannel, { - emoji: getEmojiTextFormat(reactionRole.emoji), - channel: channel!.toString() - }); - return send(message, content); - } - - await send(message, args.t(LanguageKeys.Commands.Management.ManageReactionRolesAddPrompt)); - - const reaction = await LongLivingReactionCollector.collectOne({ - filter: (reaction) => reaction.userId === message.author.id && reaction.guild.id === message.guild.id - }); - - if (!reaction) this.error(LanguageKeys.Commands.Management.ManageReactionRolesAddMissing); - - const reactionRole: ReactionRole = { - emoji: getEmojiString(reaction.emoji), - message: reaction.messageId, - channel: reaction.channel.id, - role: role.id - }; - using trx = await writeSettingsTransaction(message.guild); - await trx.write({ reactionRoles: trx.settings.reactionRoles.concat(reactionRole) }).submitWithAudit(message.author.id); - - const url = ``; - const content = args.t(LanguageKeys.Commands.Management.ManageReactionRolesAdd, { - emoji: getEmojiTextFormat(reactionRole.emoji), - url - }); - return send(message, content); - } - - public async remove(message: GuildMessage, args: WolfSubcommand.Args) { - const role = await args.pick('roleName'); - const messageId = await args.pick('snowflake'); - - using trx = await writeSettingsTransaction(message.guild); - const index = trx.settings.reactionRoles.findIndex((entry) => (entry.message ?? entry.channel) === messageId && entry.role === role.id); - if (index === -1) this.error(LanguageKeys.Commands.Management.ManageReactionRolesRemoveNotExists); - - const reactionRole = trx.settings.reactionRoles[index]; - await trx.write({ reactionRoles: trx.settings.reactionRoles.toSpliced(index, 1) }).submitWithAudit(message.author.id); - - const url = reactionRole.message - ? `` - : `<#${reactionRole.channel}>`; - - const content = args.t(LanguageKeys.Commands.Management.ManageReactionRolesRemove, { - emoji: getEmojiTextFormat(reactionRole.emoji), - url - }); - return send(message, content); - } - - public async reset(message: GuildMessage, args: WolfSubcommand.Args) { - using trx = await writeSettingsTransaction(message.guild); - await trx.write({ reactionRoles: [] }).submitWithAudit(message.author.id); - const content = args.t(LanguageKeys.Commands.Management.ManageReactionRolesReset); - return send(message, content); - } - - @RequiresClientPermissions(PermissionFlagsBits.EmbedLinks) - public async show(message: GuildMessage, args: WolfSubcommand.Args) { - const settings = await readSettings(message.guild); - const { reactionRoles } = settings; - if (reactionRoles.length === 0) { - this.error(LanguageKeys.Commands.Management.ManageReactionRolesShowEmpty); - } - - const response = await sendLoadingMessage(message, args.t); - - const display = new PaginatedMessage({ - template: new EmbedBuilder().setColor(getColor(message)) - }); - - display.setIdle(minutes(5)); - for (const bulk of chunk(reactionRoles, 15)) { - const serialized = bulk.map((value) => this.format(value, message.guild)).join('\n'); - display.addPageEmbed((embed) => embed.setDescription(serialized)); - } - - await display.run(response, message.author); - return response; - } - - private format(entry: ReactionRole, guild: Guild): string { - const emoji = getEmojiTextFormat(entry.emoji); - const role = roleMention(entry.role); - const url = entry.message - ? hyperlink('🔗', hideLinkEmbed(`https://discord.com/channels/${guild.id}/${entry.channel}/${entry.message}`)) - : channelMention(entry.channel); - return `${emoji} | ${role} -> ${url}`; - } -} diff --git a/src/commands/Management/Configuration/setIgnoreChannels.ts b/src/commands/Management/Configuration/setIgnoreChannels.ts deleted file mode 100644 index 40341ec0a..000000000 --- a/src/commands/Management/Configuration/setIgnoreChannels.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { writeSettingsTransaction } from '#lib/database'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { WolfCommand } from '#lib/structures'; -import { PermissionLevels, type GuildMessage } from '#lib/types'; -import { ApplyOptions } from '@sapphire/decorators'; -import type { GuildTextBasedChannelTypes } from '@sapphire/discord.js-utilities'; -import { Args, Argument, CommandOptionsRunTypeEnum, container } from '@sapphire/framework'; -import { send } from '@sapphire/plugin-editable-commands'; - -@ApplyOptions({ - description: LanguageKeys.Commands.Management.SetIgnoreChannelsDescription, - detailedDescription: LanguageKeys.Commands.Management.SetIgnoreChannelsExtended, - permissionLevel: PermissionLevels.Administrator, - runIn: [CommandOptionsRunTypeEnum.GuildAny] -}) -export class UserCommand extends WolfCommand { - public override async messageRun(message: GuildMessage, args: WolfCommand.Args) { - const channel = await args.pick(UserCommand.hereOrTextChannelResolver); - - using trx = await writeSettingsTransaction(message.guild); - - const index = trx.settings.disabledChannels.indexOf(channel.id); - const disabledChannels = index === -1 ? trx.settings.disabledChannels.concat(channel.id) : trx.settings.disabledChannels.toSpliced(index, 1); - await trx.write({ disabledChannels }).submitWithAudit(message.author.id); - - const added = index === -1; - const contentKey = added ? LanguageKeys.Commands.Management.SetIgnoreChannelsSet : LanguageKeys.Commands.Management.SetIgnoreChannelsRemoved; - const content = args.t(contentKey, { channel: channel.toString() }); - return send(message, content); - } - - private static hereOrTextChannelResolver = Args.make((argument, context) => { - if (argument === 'here') return Args.ok(context.message.channel as GuildTextBasedChannelTypes); - return (container.stores.get('arguments').get('textOrNewsChannelName') as Argument).run(argument, context); - }); -} diff --git a/src/commands/Management/Configuration/setImageLogs.ts b/src/commands/Management/Configuration/setImageLogs.ts deleted file mode 100644 index d0226bb53..000000000 --- a/src/commands/Management/Configuration/setImageLogs.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { ChannelConfigurationCommand } from '#lib/structures'; -import { ApplyOptions } from '@sapphire/decorators'; - -@ApplyOptions({ - description: LanguageKeys.Commands.Management.SetImageLogsDescription, - detailedDescription: LanguageKeys.Commands.Management.SetImageLogsExtended, - responseKey: LanguageKeys.Commands.Management.SetImageLogsSet, - settingsKey: 'channelsLogsImage' -}) -export class UserChannelConfigurationCommand extends ChannelConfigurationCommand {} diff --git a/src/commands/Management/Configuration/setMemberAddLogs.ts b/src/commands/Management/Configuration/setMemberAddLogs.ts deleted file mode 100644 index cafb1024f..000000000 --- a/src/commands/Management/Configuration/setMemberAddLogs.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { ChannelConfigurationCommand } from '#lib/structures'; -import { ApplyOptions } from '@sapphire/decorators'; - -@ApplyOptions({ - description: LanguageKeys.Commands.Management.SetMemberAddLogsDescription, - detailedDescription: LanguageKeys.Commands.Management.SetMemberAddLogsExtended, - responseKey: LanguageKeys.Commands.Management.SetMemberAddLogsSet, - settingsKey: 'channelsLogsMemberAdd' -}) -export class UserChannelConfigurationCommand extends ChannelConfigurationCommand {} diff --git a/src/commands/Management/Configuration/setMemberRemoveLogs.ts b/src/commands/Management/Configuration/setMemberRemoveLogs.ts deleted file mode 100644 index 02ef33325..000000000 --- a/src/commands/Management/Configuration/setMemberRemoveLogs.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { ChannelConfigurationCommand } from '#lib/structures'; -import { ApplyOptions } from '@sapphire/decorators'; - -@ApplyOptions({ - description: LanguageKeys.Commands.Management.SetMemberRemoveLogsDescription, - detailedDescription: LanguageKeys.Commands.Management.SetMemberRemoveLogsExtended, - responseKey: LanguageKeys.Commands.Management.SetMemberRemoveLogsSet, - settingsKey: 'channelsLogsMemberRemove' -}) -export class UserChannelConfigurationCommand extends ChannelConfigurationCommand {} diff --git a/src/commands/Management/Configuration/setMessageDeleteLogs.ts b/src/commands/Management/Configuration/setMessageDeleteLogs.ts deleted file mode 100644 index d41adaa51..000000000 --- a/src/commands/Management/Configuration/setMessageDeleteLogs.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { ChannelConfigurationCommand } from '#lib/structures'; -import { ApplyOptions } from '@sapphire/decorators'; - -@ApplyOptions({ - description: LanguageKeys.Commands.Management.SetMessageDeleteLogsDescription, - detailedDescription: LanguageKeys.Commands.Management.SetMessageDeleteLogsExtended, - responseKey: LanguageKeys.Commands.Management.SetMessageDeleteLogsSet, - settingsKey: 'channelsLogsMessageDelete' -}) -export class UserChannelConfigurationCommand extends ChannelConfigurationCommand {} diff --git a/src/commands/Management/Configuration/setMessageUpdateLogs.ts b/src/commands/Management/Configuration/setMessageUpdateLogs.ts deleted file mode 100644 index 4869ddeb7..000000000 --- a/src/commands/Management/Configuration/setMessageUpdateLogs.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { ChannelConfigurationCommand } from '#lib/structures'; -import { ApplyOptions } from '@sapphire/decorators'; - -@ApplyOptions({ - description: LanguageKeys.Commands.Management.SetMessageUpdateLogsDescription, - detailedDescription: LanguageKeys.Commands.Management.SetMessageUpdateLogsExtended, - responseKey: LanguageKeys.Commands.Management.SetMessageUpdateLogsSet, - settingsKey: 'channelsLogsMessageUpdate' -}) -export class UserChannelConfigurationCommand extends ChannelConfigurationCommand {} diff --git a/src/commands/Management/Configuration/setModLogs.ts b/src/commands/Management/Configuration/setModLogs.ts deleted file mode 100644 index f1a4db7b3..000000000 --- a/src/commands/Management/Configuration/setModLogs.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { ChannelConfigurationCommand } from '#lib/structures'; -import { ApplyOptions } from '@sapphire/decorators'; - -@ApplyOptions({ - description: LanguageKeys.Commands.Management.SetModerationLogsDescription, - detailedDescription: LanguageKeys.Commands.Management.SetModerationLogsExtended, - responseKey: LanguageKeys.Commands.Management.SetModerationLogsSet, - settingsKey: 'channelsLogsModeration' -}) -export class UserChannelConfigurationCommand extends ChannelConfigurationCommand {} diff --git a/src/commands/Management/Configuration/setPrefix.ts b/src/commands/Management/Configuration/setPrefix.ts deleted file mode 100644 index d8b5e926b..000000000 --- a/src/commands/Management/Configuration/setPrefix.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { writeSettingsTransaction } from '#lib/database'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { WolfCommand } from '#lib/structures'; -import { PermissionLevels, type GuildMessage } from '#lib/types'; -import { ApplyOptions } from '@sapphire/decorators'; -import { CommandOptionsRunTypeEnum } from '@sapphire/framework'; -import { send } from '@sapphire/plugin-editable-commands'; - -@ApplyOptions({ - description: LanguageKeys.Commands.Management.SetPrefixDescription, - detailedDescription: LanguageKeys.Commands.Management.SetPrefixExtended, - permissionLevel: PermissionLevels.Administrator, - runIn: [CommandOptionsRunTypeEnum.GuildAny], - aliases: ['prefix'] -}) -export class UserCommand extends WolfCommand { - public override async messageRun(message: GuildMessage, args: WolfCommand.Args) { - const prefix = await args.pick('string', { minimum: 1, maximum: 10 }); - - using trx = await writeSettingsTransaction(message.guild); - - // If it's the same value, throw: - if (trx.settings.prefix === prefix) { - this.error(LanguageKeys.Misc.ConfigurationEquals); - } - - await trx.write({ prefix }).submitWithAudit(message.author.id); - - const content = args.t(LanguageKeys.Commands.Management.SetPrefixSet, { prefix }); - return send(message, { content, allowedMentions: { users: [message.author.id], roles: [] } }); - } -} diff --git a/src/commands/Management/create-mute.ts b/src/commands/Management/create-mute.ts deleted file mode 100644 index ea54a2aa0..000000000 --- a/src/commands/Management/create-mute.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { writeSettingsTransaction } from '#lib/database'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { ModerationActions } from '#lib/moderation'; -import { WolfCommand } from '#lib/structures'; -import { PermissionLevels, type GuildMessage } from '#lib/types'; -import { minutes } from '#utils/common'; -import { Emojis } from '#utils/constants'; -import { getEmojiReactionFormat, promptConfirmation, promptForMessage, type SerializedEmoji } from '#utils/functions'; -import { ApplyOptions } from '@sapphire/decorators'; -import { canReact } from '@sapphire/discord.js-utilities'; -import { Argument, CommandOptionsRunTypeEnum, Result, UserError } from '@sapphire/framework'; -import { send } from '@sapphire/plugin-editable-commands'; -import { PermissionFlagsBits, type Role } from 'discord.js'; - -@ApplyOptions({ - cooldownDelay: minutes(5), - description: LanguageKeys.Commands.Management.CreateMuteDescription, - detailedDescription: LanguageKeys.Commands.Management.CreateMuteExtended, - permissionLevel: PermissionLevels.Administrator, - requiredClientPermissions: [PermissionFlagsBits.ManageChannels, PermissionFlagsBits.ManageRoles], - runIn: [CommandOptionsRunTypeEnum.GuildAny] -}) -export class UserCommand extends WolfCommand { - private get role() { - return this.container.stores.get('arguments').get('role') as Argument; - } - - public override async messageRun(message: GuildMessage, args: WolfCommand.Args, context: WolfCommand.RunContext) { - const { t } = args; - - if (await promptConfirmation(message, t(LanguageKeys.Commands.Moderation.ActionSharedRoleSetupExisting))) { - const result = await this.askForRole(message, args, context); - if (result.isOk()) { - const role = result.unwrap(); - using trx = await writeSettingsTransaction(message.guild); - await trx.write({ rolesMuted: role.id }).submitWithAudit(message.author.id); - if (canReact(message.channel)) return message.react(getEmojiReactionFormat(Emojis.GreenTickSerialized as SerializedEmoji)); - - const content = t(LanguageKeys.Commands.Conf.Updated, { - key: 'rolesMuted', - response: role.name - }); - return send(message, content); - } - } else if (await promptConfirmation(message, t(LanguageKeys.Commands.Moderation.ActionSharedRoleSetupNew))) { - await ModerationActions.mute.setup(message); - - const content = t(LanguageKeys.Commands.Moderation.Success); - await send(message, content); - } else { - const content = t(LanguageKeys.Commands.Management.CommandHandlerAborted); - await send(message, content); - } - - return null; - } - - private async askForRole(message: GuildMessage, args: WolfCommand.Args, context: WolfCommand.RunContext): Promise> { - const result = await promptForMessage(message, args.t(LanguageKeys.Commands.Moderation.ActionSharedRoleSetupExistingName)); - if (result === null) this.error(LanguageKeys.Commands.Moderation.ActionSharedRoleSetupNoMessage); - - const argument = this.role; - return argument.run(result, { args, argument, command: this, commandContext: context, message }); - } -} diff --git a/src/commands/Management/permissionNodes.ts b/src/commands/Management/permissionNodes.ts deleted file mode 100644 index a0d5c6506..000000000 --- a/src/commands/Management/permissionNodes.ts +++ /dev/null @@ -1,165 +0,0 @@ -import { PermissionNodeAction, readSettings, readSettingsPermissionNodes, writeSettingsTransaction, type PermissionsNode } from '#lib/database'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { WolfSubcommand } from '#lib/structures'; -import { PermissionLevels, type GuildMessage } from '#lib/types'; -import { resolveOnErrorCodes } from '#utils/common'; -import { ApplyOptions } from '@sapphire/decorators'; -import { Args, CommandOptionsRunTypeEnum } from '@sapphire/framework'; -import { send } from '@sapphire/plugin-editable-commands'; -import { isNullish } from '@sapphire/utilities'; -import { RESTJSONErrorCodes, Role, type GuildMember } from 'discord.js'; - -@ApplyOptions({ - aliases: ['pnodes', 'pnode'], - permissionLevel: PermissionLevels.Administrator, - description: LanguageKeys.Commands.Management.PermissionNodesDescription, - detailedDescription: LanguageKeys.Commands.Management.PermissionNodesExtended, - subcommands: [ - { name: 'add', messageRun: 'add' }, - { name: 'remove', messageRun: 'remove' }, - { name: 'reset', messageRun: 'reset' }, - { name: 'show', messageRun: 'show', default: true } - ], - runIn: [CommandOptionsRunTypeEnum.GuildAny] -}) -export class UserCommand extends WolfSubcommand { - public async add(message: GuildMessage, args: WolfSubcommand.Args) { - const target = await args.pick('roleName').catch(() => args.pick('member')); - const action = await args.pick(UserCommand.type); - - // Permission Nodes do not allow allows for the @everyone role: - if (target.id === message.guild.id && action === PermissionNodeAction.Allow) { - this.error(LanguageKeys.Commands.Management.PermissionNodesCannotAllowEveryone); - } - - if (!this.checkPermissions(message, target)) { - this.error(LanguageKeys.Commands.Management.PermissionNodesHigher); - } - - const command = await args.pick('commandMatch', { owners: false }); - using trx = await writeSettingsTransaction(message.guild); - const nodes = readSettingsPermissionNodes(trx.settings); - const propertyKey = nodes.settingsPropertyFor(target); - await trx.write({ [propertyKey]: nodes.add(target, command, action) } as any).submitWithAudit(message.author.id); - - const content = args.t(LanguageKeys.Commands.Management.PermissionNodesAdd); - return send(message, content); - } - - public async remove(message: GuildMessage, args: WolfSubcommand.Args) { - const target = await args.pick('roleName').catch(() => args.pick('member')); - const action = await args.pick(UserCommand.type); - const command = await args.pick('commandMatch', { owners: false }); - - if (!this.checkPermissions(message, target)) this.error(LanguageKeys.Commands.Management.PermissionNodesHigher); - - using trx = await writeSettingsTransaction(message.guild); - const nodes = readSettingsPermissionNodes(trx.settings); - const propertyKey = nodes.settingsPropertyFor(target); - await trx.write({ [propertyKey]: nodes.remove(target, command, action) } as any).submitWithAudit(message.author.id); - - const content = args.t(LanguageKeys.Commands.Management.PermissionNodesRemove); - return send(message, content); - } - - public async reset(message: GuildMessage, args: WolfSubcommand.Args) { - const target = await args.pick('roleName').catch(() => args.pick('member')); - - if (!this.checkPermissions(message, target)) this.error(LanguageKeys.Commands.Management.PermissionNodesHigher); - - using trx = await writeSettingsTransaction(message.guild); - const nodes = readSettingsPermissionNodes(trx.settings); - const propertyKey = nodes.settingsPropertyFor(target); - await trx.write({ [propertyKey]: nodes.reset(target) } as any).submitWithAudit(message.author.id); - - const content = args.t(LanguageKeys.Commands.Management.PermissionNodesReset); - return send(message, content); - } - - public async show(message: GuildMessage, args: WolfSubcommand.Args) { - const content = args.finished ? await this.showAll(message, args) : await this.showOne(message, args); - return send(message, { content, allowedMentions: { users: [], roles: [] } }); - } - - private async showOne(message: GuildMessage, args: WolfSubcommand.Args) { - const target = await args.pick('roleName').catch(() => args.pick('member')); - - if (!this.checkPermissions(message, target)) this.error(LanguageKeys.Commands.Management.PermissionNodesHigher); - const isRole = target instanceof Role; - - const settings = await readSettings(message.guild); - const nodes = isRole ? settings.permissionsRoles : settings.permissionsUsers; - const node = nodes.find((n) => n.id === target.id); - if (typeof node === 'undefined') this.error(LanguageKeys.Commands.Management.PermissionNodesNodeNotExists); - - return this.formatPermissionNode(args, node, isRole, target); - } - - private async showAll(message: GuildMessage, args: WolfSubcommand.Args) { - const settings = await readSettings(message.guild); - const [users, roles] = await Promise.all([ - this.formatPermissionNodes(args, settings.permissionsUsers, false), - this.formatPermissionNodes(args, settings.permissionsRoles, true) - ]); - const total = users.concat(roles); - if (total.length === 0) this.error(LanguageKeys.Commands.Management.PermissionNodesNodeNotExists); - - return total.join('\n\n'); - } - - private async formatPermissionNodes(args: WolfSubcommand.Args, nodes: readonly PermissionsNode[], isRole: boolean) { - const output: string[] = []; - for (const node of nodes) { - const target = isRole - ? args.message.guild!.roles.cache.get(node.id) - : await resolveOnErrorCodes(args.message.guild!.members.fetch(node.id), RESTJSONErrorCodes.UnknownMember); - - if (isNullish(target)) continue; - if (!this.checkPermissions(args.message as GuildMessage, target)) continue; - output.push(`> ${this.formatPermissionNode(args, node, isRole, target)}`); - } - - return output; - } - - private formatPermissionNode(args: WolfSubcommand.Args, node: PermissionsNode, isRole: boolean, target: Role | GuildMember) { - return [ - args.t(LanguageKeys.Commands.Management.PermissionNodesShowName, { name: this.formatTarget(isRole, target) }), - args.t(LanguageKeys.Commands.Management.PermissionNodesShowAllow, { allow: this.formatCommands(args, node.allow) }), - args.t(LanguageKeys.Commands.Management.PermissionNodesShowDeny, { deny: this.formatCommands(args, node.deny) }) - ].join('\n'); - } - - private formatTarget(isRole: boolean, target: Role | GuildMember) { - return isRole ? (target as Role).name : (target as GuildMember).displayName; - } - - private formatCommands(args: WolfSubcommand.Args, commands: readonly string[]) { - return commands.length === 0 - ? args.t(LanguageKeys.Globals.None) - : args.t(LanguageKeys.Globals.AndListValue, { value: commands.map((command) => `\`${command}\``) }); - } - - private checkPermissions(message: GuildMessage, target: Role | GuildMember) { - // If it's to itself, always block - if (message.member!.id === target.id) return false; - - // If the target is the owner, always block - if (message.guild.ownerId === target.id) return false; - - // If the author is the owner, always allow - if (message.author.id === message.guild.ownerId) return true; - - // Check hierarchy role positions, allow when greater, block otherwise - const targetPosition = target instanceof Role ? target.position : target.roles.highest.position; - const authorPosition = message.member!.roles.highest?.position ?? 0; - return authorPosition > targetPosition; - } - - private static type = Args.make((parameter, { argument }) => { - const lowerCasedParameter = parameter.toLowerCase(); - if (lowerCasedParameter === 'allow') return Args.ok(PermissionNodeAction.Allow); - if (lowerCasedParameter === 'deny') return Args.ok(PermissionNodeAction.Deny); - return Args.error({ argument, parameter, identifier: LanguageKeys.Commands.Management.PermissionNodesInvalidType }); - }); -} diff --git a/src/commands/Management/roles.ts b/src/commands/Management/roles.ts deleted file mode 100644 index b82bcec16..000000000 --- a/src/commands/Management/roles.ts +++ /dev/null @@ -1,144 +0,0 @@ -import { readSettings, writeSettings } from '#lib/database'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { WolfCommand } from '#lib/structures'; -import type { GuildMessage } from '#lib/types'; -import { minutes } from '#utils/common'; -import { getColor, sendLoadingMessage } from '#utils/util'; -import { ApplyOptions } from '@sapphire/decorators'; -import { PaginatedMessage } from '@sapphire/discord.js-utilities'; -import { CommandOptionsRunTypeEnum } from '@sapphire/framework'; -import { send } from '@sapphire/plugin-editable-commands'; -import type { TFunction } from '@sapphire/plugin-i18next'; -import { chunk } from '@sapphire/utilities'; -import { EmbedBuilder, PermissionFlagsBits, type Role } from 'discord.js'; - -@ApplyOptions( - WolfCommand.PaginatedOptions({ - aliases: ['pr', 'role', 'public-roles', 'public-role'], - description: LanguageKeys.Commands.Management.RolesDescription, - detailedDescription: LanguageKeys.Commands.Management.RolesExtended, - requiredClientPermissions: [PermissionFlagsBits.ManageRoles, PermissionFlagsBits.ManageMessages], - runIn: [CommandOptionsRunTypeEnum.GuildAny] - }) -) -export class UserPaginatedMessageCommand extends WolfCommand { - public override async messageRun(message: GuildMessage, args: WolfCommand.Args) { - const settings = await readSettings(message.guild); - - const { rolesPublic } = settings; - if (!rolesPublic.length) this.error(LanguageKeys.Commands.Management.RolesListEmpty); - - // If no argument was provided then show the list of available roles - if (args.finished) return this.list(message, args.t, rolesPublic); - - const roles = [...new Set(await args.repeat('roleName', { filter: (role: Role) => rolesPublic.includes(role.id) }))]; - - // Otherwise start process of claiming a role - const memberRoles = new Set(message.member!.roles.cache.keys()); - - // Remove the everyone role - memberRoles.delete(message.guild.id); - - const filterRoles = new Set(roles); - const unlistedRoles: string[] = []; - const unmanageable: string[] = []; - const addedRoles: string[] = []; - const removedRoles: string[] = []; - const { position } = message.guild.members.me!.roles.highest; - - for (const role of filterRoles) { - if (!role) continue; - if (!rolesPublic.includes(role.id)) { - unlistedRoles.push(role.name); - } else if (position <= role.position) { - unmanageable.push(role.name); - } else if (memberRoles.has(role.id)) { - memberRoles.delete(role.id); - removedRoles.push(role.name); - } else { - memberRoles.add(role.id); - addedRoles.push(role.name); - - for (const set of settings.rolesUniqueRoleSets) { - // If the set does not have the role being added skip to next set - if (!set.roles.includes(role.id)) continue; - - for (const id of set.roles) { - // If this role is the role being added skip - if (role.id === id) continue; - - if (memberRoles.has(id)) { - // If the member has this role we need to delete it - memberRoles.delete(id); - // get to the role object so we can get the name of the role to show the user it was removed - const roleToRemove = message.guild.roles.cache.get(id)!; - removedRoles.push(roleToRemove.name); - } - } - } - } - } - - const actualInitialRole = settings.rolesInitial ?? (message.author.bot ? settings.rolesInitialBots : settings.rolesInitialHumans); - // If the guild requests to remove the initial role upon claiming, remove the initial role - if (actualInitialRole && settings.rolesRemoveInitial && addedRoles.length) { - // If the role was deleted, remove it from the settings - if (!message.guild.roles.cache.has(actualInitialRole)) { - await writeSettings(message.guild, { rolesInitial: null }).catch((error) => this.container.logger.fatal(error)); - } else if (message.member!.roles.cache.has(actualInitialRole)) { - memberRoles.delete(actualInitialRole); - } - } - - const { t } = args; - - // Apply the roles - if (removedRoles.length || addedRoles.length) - await message.member!.roles.set([...memberRoles], t(LanguageKeys.Commands.Management.RolesAuditLog)); - - const output: string[] = []; - if (unlistedRoles.length) output.push(t(LanguageKeys.Commands.Management.RolesNotPublic, { roles: unlistedRoles.join('`, `') })); - if (unmanageable.length) output.push(t(LanguageKeys.Commands.Management.RolesNotManageable, { roles: unmanageable.join('`, `') })); - if (removedRoles.length) output.push(t(LanguageKeys.Commands.Management.RolesRemoved, { roles: removedRoles.join('`, `') })); - if (addedRoles.length) output.push(t(LanguageKeys.Commands.Management.RolesAdded, { roles: addedRoles.join('`, `') })); - - const content = output.join('\n'); - return send(message, content); - } - - private async list(message: GuildMessage, t: TFunction, publicRoles: readonly string[]) { - const remove: string[] = []; - const roles: string[] = []; - for (const roleId of publicRoles) { - const role = message.guild.roles.cache.get(roleId); - if (role) roles.push(role.name); - else remove.push(roleId); - } - - // Automatic role deletion - if (remove.length) { - const allRoles = new Set(publicRoles); - for (const role of remove) allRoles.delete(role); - await writeSettings(message.guild, { rolesPublic: [...allRoles] }); - } - - // There's the possibility all roles could be inexistent, therefore the system - // would filter and remove them all, causing this to be empty. - if (!roles.length) this.error(LanguageKeys.Commands.Management.RolesListEmpty); - - const display = new PaginatedMessage({ - template: new EmbedBuilder() // - .setColor(getColor(message)) - .setTitle(t(LanguageKeys.Commands.Management.RolesListTitle)) - }); - - display.setIdle(minutes(5)); - for (const page of chunk(roles, 10)) { - display.addPageEmbed((embed) => embed.setDescription(page.join('\n'))); - } - - const response = await sendLoadingMessage(message, t); - await display.run(response, message.author); - return response; - } -} diff --git a/src/commands/Misc/snipe.ts b/src/commands/Misc/snipe.ts deleted file mode 100644 index d74c124d1..000000000 --- a/src/commands/Misc/snipe.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { getSupportedLanguageT } from '#lib/i18n'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { WolfCommand } from '#lib/structures'; -import { PermissionLevels, type GuildMessage } from '#lib/types'; -import { Urls } from '#utils/constants'; -import { getSnipedMessage } from '#utils/functions'; -import { getColor, getContent, getFullEmbedAuthor, getImages, setMultipleEmbedImages } from '#utils/util'; -import { EmbedBuilder, chatInputApplicationCommandMention } from '@discordjs/builders'; -import { ApplyOptions } from '@sapphire/decorators'; -import { ApplicationCommandRegistry, CommandOptionsRunTypeEnum } from '@sapphire/framework'; -import { send } from '@sapphire/plugin-editable-commands'; -import { applyLocalizedBuilder } from '@sapphire/plugin-i18next'; -import { InteractionContextType, MessageFlags, PermissionFlagsBits, type GuildTextBasedChannel } from 'discord.js'; - -const Root = LanguageKeys.Commands.Snipe; - -@ApplyOptions({ - aliases: ['sniped'], - description: Root.Description, - detailedDescription: LanguageKeys.Commands.Shared.SlashOnlyDetailedDescription, - requiredClientPermissions: [PermissionFlagsBits.EmbedLinks], - permissionLevel: PermissionLevels.Moderator, - runIn: [CommandOptionsRunTypeEnum.GuildAny] -}) -export class UserCommand extends WolfCommand { - public override registerApplicationCommands(registry: ApplicationCommandRegistry) { - registry.registerChatInputCommand( - (builder) => - applyLocalizedBuilder(builder, Root.Name, Root.Description) - .setContexts(InteractionContextType.Guild) - .setDefaultMemberPermissions(PermissionFlagsBits.KickMembers), - { - idHints: [ - '1297896659283345408' // wolfstar-prod production - - // coming soon beta - ] - } - ); - } - - public override async messageRun(message: GuildMessage, args: WolfCommand.Args) { - const content = args.t(LanguageKeys.Commands.Shared.DeprecatedMessage, { - command: chatInputApplicationCommandMention(this.name, this.getGlobalCommandId()) - }); - - return send(message, { content }); - } - - public override chatInputRun(interaction: WolfCommand.ChatInputInteraction) { - const t = getSupportedLanguageT(interaction); - const sniped = getSnipedMessage(interaction.channel as GuildTextBasedChannel); - if (sniped === null) { - const content = t(Root.MessageEmpty); - return interaction.reply({ content, flags: MessageFlags.Ephemeral }); - } - - const embed = new EmbedBuilder() - .setURL(Urls.Website) - .setFooter({ text: t(Root.EmbedTitle) }) - .setColor(getColor(sniped)) - .setAuthor(getFullEmbedAuthor(sniped.author)) - .setTimestamp(sniped.createdTimestamp); - - const content = getContent(sniped); - if (content !== null) embed.setDescription(content); - - const embeds = setMultipleEmbedImages(embed, getImages(sniped)); - return interaction.reply({ embeds, flags: MessageFlags.Ephemeral }); - } -} diff --git a/src/commands/Moderation/Restriction/restrictAttachment.ts b/src/commands/Moderation/Restriction/restrictAttachment.ts deleted file mode 100644 index 533ff57e2..000000000 --- a/src/commands/Moderation/Restriction/restrictAttachment.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { SetUpModerationCommand } from '#lib/moderation'; -import { TypeVariation } from '#utils/moderationConstants'; -import { ApplyOptions } from '@sapphire/decorators'; - -type Type = TypeVariation.RestrictedAttachment; -type ValueType = null; - -@ApplyOptions>({ - aliases: ['restricted-attachment', 'ra'], - description: LanguageKeys.Commands.Moderation.RestrictAttachmentDescription, - detailedDescription: LanguageKeys.Commands.Moderation.RestrictAttachmentExtended, - type: TypeVariation.RestrictedAttachment -}) -export class UserSetUpModerationCommand extends SetUpModerationCommand {} diff --git a/src/commands/Moderation/Restriction/restrictEmbed.ts b/src/commands/Moderation/Restriction/restrictEmbed.ts deleted file mode 100644 index 238807176..000000000 --- a/src/commands/Moderation/Restriction/restrictEmbed.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { SetUpModerationCommand } from '#lib/moderation'; -import { TypeVariation } from '#utils/moderationConstants'; -import { ApplyOptions } from '@sapphire/decorators'; - -type Type = TypeVariation.RestrictedEmbed; -type ValueType = null; - -@ApplyOptions>({ - aliases: ['restricted-embed', 're'], - description: LanguageKeys.Commands.Moderation.RestrictEmbedDescription, - detailedDescription: LanguageKeys.Commands.Moderation.RestrictEmbedExtended, - type: TypeVariation.RestrictedEmbed -}) -export class UserSetUpModerationCommand extends SetUpModerationCommand {} diff --git a/src/commands/Moderation/Restriction/restrictEmoji.ts b/src/commands/Moderation/Restriction/restrictEmoji.ts deleted file mode 100644 index a3ac1748b..000000000 --- a/src/commands/Moderation/Restriction/restrictEmoji.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { SetUpModerationCommand } from '#lib/moderation'; -import { TypeVariation } from '#utils/moderationConstants'; -import { ApplyOptions } from '@sapphire/decorators'; - -type Type = TypeVariation.RestrictedEmoji; -type ValueType = null; - -@ApplyOptions>({ - aliases: ['restrict-external-emoji', 'restricted-emoji', 'restricted-external-emoji', 'ree', 'restrict-emojis'], - description: LanguageKeys.Commands.Moderation.RestrictEmojiDescription, - detailedDescription: LanguageKeys.Commands.Moderation.RestrictEmojiExtended, - type: TypeVariation.RestrictedEmoji -}) -export class UserSetUpModerationCommand extends SetUpModerationCommand {} diff --git a/src/commands/Moderation/Restriction/restrictReaction.ts b/src/commands/Moderation/Restriction/restrictReaction.ts deleted file mode 100644 index 50cc8746a..000000000 --- a/src/commands/Moderation/Restriction/restrictReaction.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { SetUpModerationCommand } from '#lib/moderation'; -import { TypeVariation } from '#utils/moderationConstants'; -import { ApplyOptions } from '@sapphire/decorators'; - -type Type = TypeVariation.RestrictedReaction; -type ValueType = null; - -@ApplyOptions>({ - aliases: ['restricted-reaction', 'rr'], - description: LanguageKeys.Commands.Moderation.RestrictReactionDescription, - detailedDescription: LanguageKeys.Commands.Moderation.RestrictReactionExtended, - type: TypeVariation.RestrictedReaction -}) -export class UserSetUpModerationCommand extends SetUpModerationCommand {} diff --git a/src/commands/Moderation/Restriction/restrictVoice.ts b/src/commands/Moderation/Restriction/restrictVoice.ts deleted file mode 100644 index 921f2d0dd..000000000 --- a/src/commands/Moderation/Restriction/restrictVoice.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { SetUpModerationCommand } from '#lib/moderation'; -import { TypeVariation } from '#utils/moderationConstants'; -import { ApplyOptions } from '@sapphire/decorators'; - -type Type = TypeVariation.RestrictedVoice; -type ValueType = null; - -@ApplyOptions>({ - aliases: ['restricted-voice', 'rv'], - description: LanguageKeys.Commands.Moderation.RestrictVoiceDescription, - detailedDescription: LanguageKeys.Commands.Moderation.RestrictVoiceExtended, - type: TypeVariation.RestrictedVoice -}) -export class UserSetUpModerationCommand extends SetUpModerationCommand {} diff --git a/src/commands/Moderation/Restriction/unrestrictAttachment.ts b/src/commands/Moderation/Restriction/unrestrictAttachment.ts deleted file mode 100644 index c6b704072..000000000 --- a/src/commands/Moderation/Restriction/unrestrictAttachment.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { SetUpModerationCommand } from '#lib/moderation'; -import { TypeVariation } from '#utils/moderationConstants'; -import { ApplyOptions } from '@sapphire/decorators'; - -type Type = TypeVariation.RestrictedAttachment; -type ValueType = null; - -@ApplyOptions>({ - aliases: ['un-restricted-attachment', 'ura'], - description: LanguageKeys.Commands.Moderation.UnrestrictAttachmentDescription, - detailedDescription: LanguageKeys.Commands.Moderation.UnrestrictAttachmentExtended, - type: TypeVariation.RestrictedAttachment, - isUndoAction: true -}) -export class UserSetUpModerationCommand extends SetUpModerationCommand {} diff --git a/src/commands/Moderation/Restriction/unrestrictEmbed.ts b/src/commands/Moderation/Restriction/unrestrictEmbed.ts deleted file mode 100644 index 24b80dd5c..000000000 --- a/src/commands/Moderation/Restriction/unrestrictEmbed.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { SetUpModerationCommand } from '#lib/moderation'; -import { TypeVariation } from '#utils/moderationConstants'; -import { ApplyOptions } from '@sapphire/decorators'; - -type Type = TypeVariation.RestrictedEmbed; -type ValueType = null; - -@ApplyOptions>({ - aliases: ['un-restricted-embed', 'ure'], - description: LanguageKeys.Commands.Moderation.UnrestrictEmbedDescription, - detailedDescription: LanguageKeys.Commands.Moderation.UnrestrictEmbedExtended, - type: TypeVariation.RestrictedEmbed, - isUndoAction: true -}) -export class UserSetUpModerationCommand extends SetUpModerationCommand {} diff --git a/src/commands/Moderation/Restriction/unrestrictEmoji.ts b/src/commands/Moderation/Restriction/unrestrictEmoji.ts deleted file mode 100644 index cc18c34ba..000000000 --- a/src/commands/Moderation/Restriction/unrestrictEmoji.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { SetUpModerationCommand } from '#lib/moderation'; -import { TypeVariation } from '#utils/moderationConstants'; -import { ApplyOptions } from '@sapphire/decorators'; - -type Type = TypeVariation.RestrictedEmoji; -type ValueType = null; - -@ApplyOptions>({ - aliases: ['un-restrict-external-emoji', 'unrestricted-emoji', 'unrestricted-external-emoji', 'uree', 'unrestrict-emojis'], - description: LanguageKeys.Commands.Moderation.UnrestrictEmojiDescription, - detailedDescription: LanguageKeys.Commands.Moderation.UnrestrictEmojiExtended, - type: TypeVariation.RestrictedEmoji, - isUndoAction: true -}) -export class UserSetUpModerationCommand extends SetUpModerationCommand {} diff --git a/src/commands/Moderation/Restriction/unrestrictReaction.ts b/src/commands/Moderation/Restriction/unrestrictReaction.ts deleted file mode 100644 index e27fa817b..000000000 --- a/src/commands/Moderation/Restriction/unrestrictReaction.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { SetUpModerationCommand } from '#lib/moderation'; -import { TypeVariation } from '#utils/moderationConstants'; -import { ApplyOptions } from '@sapphire/decorators'; - -type Type = TypeVariation.RestrictedReaction; -type ValueType = null; - -@ApplyOptions>({ - aliases: ['un-restricted-reaction', 'urr'], - description: LanguageKeys.Commands.Moderation.UnrestrictReactionDescription, - detailedDescription: LanguageKeys.Commands.Moderation.UnrestrictReactionExtended, - type: TypeVariation.RestrictedReaction, - isUndoAction: true -}) -export class UserSetUpModerationCommand extends SetUpModerationCommand {} diff --git a/src/commands/Moderation/Restriction/unrestrictVoice.ts b/src/commands/Moderation/Restriction/unrestrictVoice.ts deleted file mode 100644 index 4b4b30c67..000000000 --- a/src/commands/Moderation/Restriction/unrestrictVoice.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { SetUpModerationCommand } from '#lib/moderation'; -import { TypeVariation } from '#utils/moderationConstants'; -import { ApplyOptions } from '@sapphire/decorators'; - -type Type = TypeVariation.RestrictedVoice; -type ValueType = null; - -@ApplyOptions>({ - aliases: ['un-restricted-voice', 'urv'], - description: LanguageKeys.Commands.Moderation.UnrestrictVoiceDescription, - detailedDescription: LanguageKeys.Commands.Moderation.UnrestrictVoiceExtended, - type: TypeVariation.RestrictedVoice, - isUndoAction: true -}) -export class UserSetUpModerationCommand extends SetUpModerationCommand {} diff --git a/src/commands/Moderation/Utilities/case-deprecations.ts b/src/commands/Moderation/Utilities/case-deprecations.ts deleted file mode 100644 index 6ca65df70..000000000 --- a/src/commands/Moderation/Utilities/case-deprecations.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { WolfCommand } from '#lib/structures'; -import { PermissionLevels, type GuildMessage } from '#lib/types'; -import { ApplyOptions } from '@sapphire/decorators'; -import { CommandOptionsRunTypeEnum } from '@sapphire/framework'; -import { send } from '@sapphire/plugin-editable-commands'; -import { chatInputApplicationCommandMention } from 'discord.js'; - -@ApplyOptions({ - name: '\u200Bcase-deprecations', - aliases: ['reason', 'time', 'unwarn', 'uw', 'unwarning', 'history', 'hd', 'ho', 'moderation', 'moderations', 'mutes', 'warnings'], - description: LanguageKeys.Commands.General.V7Description, - detailedDescription: LanguageKeys.Commands.General.V7Extended, - permissionLevel: PermissionLevels.Moderator, - runIn: [CommandOptionsRunTypeEnum.GuildAny] -}) -export class UserCommand extends WolfCommand { - public override async messageRun(message: GuildMessage, args: WolfCommand.Args, context: WolfCommand.RunContext) { - const caseCommand = this.store.get('case') as WolfCommand; - const id = caseCommand.getGlobalCommandId(); - const command = chatInputApplicationCommandMention(caseCommand.name, this.#getSubcommand(context.commandName), id); - const content = args.t(LanguageKeys.Commands.Shared.DeprecatedMessage, { command }); - return send(message, content); - } - - #getSubcommand(name: string) { - switch (name) { - case 'reason': - case 'time': - return 'edit'; - case 'unwarn': - case 'unwarning': - case 'uw': - return 'archive'; - case 'hd': - case 'history': - case 'ho': - case 'moderation': - case 'moderations': - case 'mutes': - case 'warnings': - return 'list'; - default: - return 'view'; - } - } -} diff --git a/src/commands/Moderation/Utilities/case.ts b/src/commands/Moderation/Utilities/case.ts deleted file mode 100644 index cd3c1b55d..000000000 --- a/src/commands/Moderation/Utilities/case.ts +++ /dev/null @@ -1,332 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { getSupportedLanguageT, getSupportedUserLanguageT } from '#lib/i18n/translate'; -import { ModerationManager, getAction } from '#lib/moderation'; -import { getEmbed, getTitle, getTranslationKey } from '#lib/moderation/common'; -import { WolfCommand, WolfSubcommand } from '#lib/structures'; -import { PermissionLevels, type GuildMessage } from '#lib/types'; -import { desc, minutes, seconds } from '#utils/common'; -import { BrandingColors, Emojis } from '#utils/constants'; -import { getModeration } from '#utils/functions'; -import { TypeVariation } from '#utils/moderationConstants'; -import { resolveCase, resolveTimeSpan } from '#utils/resolvers'; -import { getFullEmbedAuthor, isUserSelf } from '#utils/util'; -import { ApplyOptions } from '@sapphire/decorators'; -import { PaginatedMessageEmbedFields } from '@sapphire/discord.js-utilities'; -import { ApplicationCommandRegistry, CommandOptionsRunTypeEnum } from '@sapphire/framework'; -import { send } from '@sapphire/plugin-editable-commands'; -import { applyLocalizedBuilder, createLocalizedChoice, type TFunction } from '@sapphire/plugin-i18next'; -import { cutText, isNullish, isNullishOrEmpty, isNullishOrZero } from '@sapphire/utilities'; -import { - EmbedBuilder, - InteractionContextType, - MessageFlags, - PermissionFlagsBits, - TimestampStyles, - User, - blockQuote, - chatInputApplicationCommandMention, - inlineCode, - time, - userMention, - type EmbedField -} from 'discord.js'; - -const Root = LanguageKeys.Commands.Case; -const RootModeration = LanguageKeys.Moderation; -const OverviewColors = [0x80f31f, 0xa5de0b, 0xc7c101, 0xe39e03, 0xf6780f, 0xfe5326, 0xfb3244]; - -@ApplyOptions({ - description: Root.Description, - detailedDescription: LanguageKeys.Commands.Shared.SlashOnlyDetailedDescription, - permissionLevel: PermissionLevels.Moderator, - requiredClientPermissions: [PermissionFlagsBits.EmbedLinks], - runIn: [CommandOptionsRunTypeEnum.GuildAny], - hidden: true, - subcommands: [ - { name: 'view', chatInputRun: 'chatInputRunView', messageRun: 'viewMessageRun', default: true }, - { name: 'list', chatInputRun: 'chatInputRunList' }, - { name: 'edit', chatInputRun: 'chatInputRunEdit' }, - { name: 'archive', chatInputRun: 'chatInputRunArchive' }, - { name: 'delete', chatInputRun: 'chatInputRunDelete', messageRun: 'deleteMessageRun' } - ] -}) -export class UserCommand extends WolfSubcommand { - public override registerApplicationCommands(registry: ApplicationCommandRegistry) { - registry.registerChatInputCommand( - (builder) => - applyLocalizedBuilder(builder, Root.Name, Root.Description) - .setContexts(InteractionContextType.Guild) - .setDefaultMemberPermissions(PermissionFlagsBits.ManageGuild) - .addSubcommand((subcommand) => - applyLocalizedBuilder(subcommand, Root.View) // - .addIntegerOption((option) => applyLocalizedBuilder(option, Root.OptionsCase).setMinValue(1).setRequired(true)) - .addBooleanOption((option) => applyLocalizedBuilder(option, Root.OptionsShow)) - ) - .addSubcommand((subcommand) => - applyLocalizedBuilder(subcommand, Root.List) // - .addUserOption((option) => applyLocalizedBuilder(option, Root.OptionsUser)) - .addBooleanOption((option) => applyLocalizedBuilder(option, Root.OptionsOverview)) - .addBooleanOption((option) => applyLocalizedBuilder(option, Root.OptionsShow)) - .addIntegerOption((option) => - applyLocalizedBuilder(option, Root.OptionsType) // - .addChoices( - createLocalizedChoice(RootModeration.TypeRoleAdd, { value: TypeVariation.RoleAdd }), - createLocalizedChoice(RootModeration.TypeBan, { value: TypeVariation.Ban }), - createLocalizedChoice(RootModeration.TypeKick, { value: TypeVariation.Kick }), - createLocalizedChoice(RootModeration.TypeMute, { value: TypeVariation.Mute }), - createLocalizedChoice(RootModeration.TypeRoleRemove, { value: TypeVariation.RoleRemove }), - createLocalizedChoice(RootModeration.TypeRestrictedAttachment, { value: TypeVariation.RestrictedAttachment }), - createLocalizedChoice(RootModeration.TypeRestrictedEmbed, { value: TypeVariation.RestrictedEmbed }), - createLocalizedChoice(RootModeration.TypeRestrictedEmoji, { value: TypeVariation.RestrictedEmoji }), - createLocalizedChoice(RootModeration.TypeRestrictedReaction, { value: TypeVariation.RestrictedReaction }), - createLocalizedChoice(RootModeration.TypeRestrictedVoice, { value: TypeVariation.RestrictedVoice }), - createLocalizedChoice(RootModeration.TypeSetNickname, { value: TypeVariation.SetNickname }), - createLocalizedChoice(RootModeration.TypeSoftban, { value: TypeVariation.Softban }), - createLocalizedChoice(RootModeration.TypeVoiceKick, { value: TypeVariation.VoiceKick }), - createLocalizedChoice(RootModeration.TypeVoiceMute, { value: TypeVariation.VoiceMute }), - createLocalizedChoice(RootModeration.TypeWarning, { value: TypeVariation.Warning }) - ) - ) - .addBooleanOption((option) => applyLocalizedBuilder(option, Root.OptionsPendingOnly)) - ) - .addSubcommand((subcommand) => - applyLocalizedBuilder(subcommand, Root.Edit) // - .addIntegerOption((option) => applyLocalizedBuilder(option, Root.OptionsCase).setMinValue(1).setRequired(true)) - .addStringOption((option) => applyLocalizedBuilder(option, Root.OptionsReason).setMaxLength(200)) - .addStringOption((option) => applyLocalizedBuilder(option, Root.OptionsDuration).setMaxLength(50)) - ) - .addSubcommand((subcommand) => - applyLocalizedBuilder(subcommand, Root.Archive) // - .addIntegerOption((option) => applyLocalizedBuilder(option, Root.OptionsCase).setMinValue(1).setRequired(true)) - ) - .addSubcommand((subcommand) => - applyLocalizedBuilder(subcommand, Root.Delete) // - .addIntegerOption((option) => applyLocalizedBuilder(option, Root.OptionsCase).setMinValue(1).setRequired(true)) - ), - { - idHints: [ - '1239990630537629716' // wolfstar-prod production - - // coming soon beta - ] - } - ); - } - - public async chatInputRunView(interaction: WolfSubcommand.Interaction) { - const entry = await this.#getCase(interaction, true); - const show = interaction.options.getBoolean('show') ?? false; - const t = show ? getSupportedLanguageT(interaction) : getSupportedUserLanguageT(interaction); - - return interaction.reply({ embeds: [await getEmbed(t, entry)], ephemeral: !show }); - } - - public async chatInputRunList(interaction: WolfSubcommand.Interaction) { - const user = interaction.options.getUser('user'); - const show = interaction.options.getBoolean('show') ?? false; - const type = interaction.options.getInteger('type') as TypeVariation | null; - const pendingOnly = interaction.options.getBoolean('pending-only') ?? false; - - const moderation = getModeration(interaction.guild); - let entries = [...(await moderation.fetch({ userId: user?.id })).values()]; - if (!isNullish(type)) entries = entries.filter((entry) => entry.type === type); - if (pendingOnly) entries = entries.filter((entry) => !isNullishOrZero(entry.duration) && !entry.isCompleted()); - - const t = show ? getSupportedLanguageT(interaction) : getSupportedUserLanguageT(interaction); - return interaction.options.getBoolean('overview') // - ? this.#listOverview(interaction, t, entries, user, show) - : this.#listDetails(interaction, t, this.#sortEntries(entries), isNullish(user), show); - } - - public async chatInputRunEdit(interaction: WolfSubcommand.Interaction) { - const entry = await this.#getCase(interaction, true); - const reason = interaction.options.getString('reason'); - const duration = this.#getDuration(interaction, entry); - - const moderation = getModeration(interaction.guild); - const t = getSupportedUserLanguageT(interaction); - if (!isNullish(duration)) { - const action = getAction(entry.type); - if (!action.isUndoActionAvailable) { - const content = t(Root.TimeNotAllowed, { type: t(getTranslationKey(entry.type)) }); - return interaction.reply({ content, flags: MessageFlags.Ephemeral }); - } - - if (entry.isCompleted()) { - const content = t(Root.TimeNotAllowedInCompletedEntries, { caseId: entry.id }); - return interaction.reply({ content, flags: MessageFlags.Ephemeral }); - } - - if (duration !== 0) { - const next = entry.createdAt + duration; - if (next <= Date.now()) { - const content = t(Root.TimeTooEarly, { - start: time(seconds.fromMilliseconds(entry.createdAt), TimestampStyles.LongDateTime), - time: time(seconds.fromMilliseconds(next), TimestampStyles.RelativeTime) - }); - return interaction.reply({ content, flags: MessageFlags.Ephemeral }); - } - } - } - - await moderation.edit(entry, { - reason: isNullish(reason) ? entry.reason : reason, - duration: isNullish(duration) ? entry.duration : duration || null - }); - - const content = t(Root.EditSuccess, { caseId: entry.id }); - return interaction.reply({ content, flags: MessageFlags.Ephemeral }); - } - - public async chatInputRunArchive(interaction: WolfSubcommand.Interaction) { - const entry = await this.#getCase(interaction, true); - await getModeration(interaction.guild).archive(entry); - - const content = getSupportedUserLanguageT(interaction)(Root.ArchiveSuccess, { caseId: entry.id }); - return interaction.reply({ content, flags: MessageFlags.Ephemeral }); - } - - public async chatInputRunDelete(interaction: WolfSubcommand.Interaction) { - const entry = await this.#getCase(interaction, true); - await getModeration(interaction.guild).delete(entry); - - const content = getSupportedUserLanguageT(interaction)(Root.DeleteSuccess, { caseId: entry.id }); - return interaction.reply({ content, flags: MessageFlags.Ephemeral }); - } - - public async viewMessageRun(message: GuildMessage, args: WolfSubcommand.Args) { - return send(message, { - content: args.t(LanguageKeys.Commands.Shared.DeprecatedMessage, { - command: chatInputApplicationCommandMention(this.name, 'show', this.getGlobalCommandId()) - }) - }); - } - - public async deleteMessageRun(message: GuildMessage, args: WolfCommand.Args) { - return send(message, { - content: args.t(LanguageKeys.Commands.Shared.DeprecatedMessage, { - command: chatInputApplicationCommandMention(this.name, 'delete', this.getGlobalCommandId()) - }) - }); - } - - async #listDetails( - interaction: WolfSubcommand.Interaction, - t: TFunction, - entries: ModerationManager.Entry[], - displayUser: boolean, - show: boolean - ) { - if (entries.length === 0) { - const content = getSupportedUserLanguageT(interaction)(Root.ListEmpty); - return interaction.reply({ content, flags: MessageFlags.Ephemeral }); - } - - await interaction.deferReply({ ephemeral: !show }); - - const title = t(Root.ListDetailsTitle, { count: entries.length }); - const color = interaction.member?.displayColor ?? BrandingColors.Primary; - return new PaginatedMessageEmbedFields() - .setTemplate(new EmbedBuilder().setTitle(title).setColor(color)) - .setIdle(minutes(5)) - .setItemsPerPage(5) - .setItems(entries.map((entry) => this.#listDetailsEntry(t, entry, displayUser))) - .make() - .run(interaction, interaction.user); - } - - #listDetailsEntry(t: TFunction, entry: ModerationManager.Entry, displayUser: boolean): EmbedField { - const moderatorEmoji = isUserSelf(entry.moderatorId) ? Emojis.AutoModerator : Emojis.Moderator; - const lines = [ - `${Emojis.Calendar} ${time(seconds.fromMilliseconds(entry.createdAt), TimestampStyles.ShortDateTime)}`, - t(Root.ListDetailsModerator, { emoji: moderatorEmoji, mention: userMention(entry.moderatorId), userId: entry.moderatorId }) - ]; - if (displayUser && entry.userId) { - lines.push(t(Root.ListDetailsUser, { emoji: Emojis.ShieldMember, mention: userMention(entry.userId), userId: entry.userId })); - } - - if (!isNullishOrZero(entry.duration) && !entry.expired) { - const timestamp = time(seconds.fromMilliseconds(entry.expiresTimestamp!), TimestampStyles.RelativeTime); - lines.push(t(Root.ListDetailsExpires, { emoji: Emojis.Hourglass, time: timestamp })); - } - - if (!isNullishOrEmpty(entry.reason)) lines.push(blockQuote(cutText(entry.reason, 150))); - - return { - name: `${inlineCode(entry.id.toString())} → ${getTitle(t, entry)}`, - value: lines.join('\n'), - inline: false - }; - } - - async #listOverview(interaction: WolfSubcommand.Interaction, t: TFunction, entries: ModerationManager.Entry[], user: User | null, show: boolean) { - let [warnings, mutes, timeouts, kicks, bans] = [0, 0, 0, 0, 0]; - for (const entry of entries) { - if (entry.isArchived() || entry.isUndo()) continue; - switch (entry.type) { - case TypeVariation.Ban: - case TypeVariation.Softban: - ++bans; - break; - case TypeVariation.Mute: - ++mutes; - break; - case TypeVariation.Timeout: - ++timeouts; - break; - case TypeVariation.Kick: - ++kicks; - break; - case TypeVariation.Warning: - ++warnings; - break; - default: - break; - } - } - - const footer = t(user ? Root.ListOverviewFooterUser : Root.ListOverviewFooter, { - warnings: t(Root.ListOverviewFooterWarning, { count: warnings }), - mutes: t(Root.ListOverviewFooterMutes, { count: mutes }), - timeouts: t(Root.ListOverviewFooterTimeouts, { count: timeouts }), - kicks: t(Root.ListOverviewFooterKicks, { count: kicks }), - bans: t(Root.ListOverviewFooterBans, { count: bans }) - }); - - const embed = new EmbedBuilder() - .setColor(OverviewColors[Math.min(OverviewColors.length - 1, warnings + mutes + kicks + bans)]) - .setFooter({ text: footer }); - if (user) embed.setAuthor(getFullEmbedAuthor(user)); - await interaction.reply({ embeds: [embed], ephemeral: !show }); - } - - #sortEntries(entries: ModerationManager.Entry[]) { - return entries.sort((a, b) => desc(a.id, b.id)); - } - - #getDuration(interaction: WolfSubcommand.Interaction, entry: ModerationManager.Entry) { - const parameter = interaction.options.getString('duration'); - if (isNullishOrEmpty(parameter)) return null; - - const action = getAction(entry.type); - if (action.durationExternal) { - const t = getSupportedUserLanguageT(interaction); - throw t(Root.TimeEditNotSupported, { type: t(getTranslationKey(entry.type)) }); - } - - return resolveTimeSpan(parameter, { minimum: action.minimumDuration, maximum: action.maximumDuration }) // - .mapErr((key) => getSupportedUserLanguageT(interaction)(key, { parameter: parameter.toString() })) - .unwrapRaw(); - } - - async #getCase(interaction: WolfSubcommand.Interaction, required: true): Promise; - async #getCase(interaction: WolfSubcommand.Interaction, required?: false): Promise; - async #getCase(interaction: WolfSubcommand.Interaction, required?: boolean) { - const caseId = interaction.options.getInteger('case', required); - if (isNullish(caseId)) return null; - - const parameter = caseId.toString(); - const t = getSupportedUserLanguageT(interaction); - return (await resolveCase(parameter, t, interaction.guild)).unwrapRaw(); - } -} diff --git a/src/commands/Moderation/Utilities/permissions.ts b/src/commands/Moderation/Utilities/permissions.ts deleted file mode 100644 index e573f4353..000000000 --- a/src/commands/Moderation/Utilities/permissions.ts +++ /dev/null @@ -1,139 +0,0 @@ -import { getSupportedLanguageT, getSupportedUserLanguageT } from '#lib/i18n'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { WolfCommand } from '#lib/structures'; -import { PermissionLevels, type GuildMessage } from '#lib/types'; -import { PermissionsBits, PermissionsBitsList } from '#utils/bits'; -import { ModeratorPermissionsBits, ModeratorPermissionsList } from '#utils/constants'; -import { getColor, getTag } from '#utils/util'; -import { bold, chatInputApplicationCommandMention, EmbedBuilder } from '@discordjs/builders'; -import { ApplyOptions } from '@sapphire/decorators'; -import { ApplicationCommandRegistry, CommandOptionsRunTypeEnum } from '@sapphire/framework'; -import { send } from '@sapphire/plugin-editable-commands'; -import { applyLocalizedBuilder, applyNameLocalizedBuilder, type TFunction } from '@sapphire/plugin-i18next'; -import { ApplicationCommandType, GuildMember, InteractionContextType, PermissionFlagsBits } from 'discord.js'; - -const Root = LanguageKeys.Commands.Permissions; - -@ApplyOptions({ - description: Root.Description, - detailedDescription: LanguageKeys.Commands.Shared.SlashOnlyDetailedDescription, - permissionLevel: PermissionLevels.Administrator, - requiredClientPermissions: [PermissionFlagsBits.EmbedLinks], - runIn: [CommandOptionsRunTypeEnum.GuildAny], - hidden: true -}) -export class UserCommand extends WolfCommand { - public override registerApplicationCommands(registry: ApplicationCommandRegistry) { - registry.registerChatInputCommand( - (builder) => - applyLocalizedBuilder(builder, Root.Name, Root.Description) - .setContexts(InteractionContextType.Guild) - .setDefaultMemberPermissions(PermissionFlagsBits.ManageGuild) - .addUserOption((option) => applyLocalizedBuilder(option, Root.OptionsUser)) - .addBooleanOption((option) => applyLocalizedBuilder(option, Root.OptionsListAll)) - .addBooleanOption((option) => applyLocalizedBuilder(option, Root.OptionsListMissing)) - .addBooleanOption((option) => applyLocalizedBuilder(option, Root.OptionsShow)), - { - idHints: [ - '1288868398196981792' // wolfstar production - ] - } - ); - - registry.registerContextMenuCommand( - (builder) => - applyNameLocalizedBuilder(builder, Root.ContextMenuName) - .setType(ApplicationCommandType.User) - .setContexts(InteractionContextType.Guild) - .setDefaultMemberPermissions(PermissionFlagsBits.ManageGuild), - { - idHints: [ - '1288868407055482986' // wolfstar production - ] - } - ); - } - - public override async messageRun(message: GuildMessage, args: WolfCommand.Args) { - const content = args.t(LanguageKeys.Commands.Shared.DeprecatedMessage, { - command: chatInputApplicationCommandMention(this.name, this.getGlobalCommandId()) - }); - return send(message, { content }); - } - - public override chatInputRun(interaction: WolfCommand.ChatInputInteraction) { - const target = interaction.options.getMember('user') ?? interaction.member; - const listAll = interaction.options.getBoolean('list-all') ?? false; - const listMissing = interaction.options.getBoolean('list-missing') ?? false; - const show = interaction.options.getBoolean('show') ?? false; - - return this.#sharedRun(interaction, target, listAll, listMissing, show); - } - - public override contextMenuRun(interaction: WolfCommand.UserContextMenuInteraction) { - return this.#sharedRun(interaction, interaction.targetMember!, false, false, false); - } - - #sharedRun( - interaction: WolfCommand.ChatInputInteraction | WolfCommand.UserContextMenuInteraction, - target: GuildMember, - listAll: boolean, - listMissing: boolean, - show: boolean - ) { - let content: string; - const permissions = target.permissions.bitfield; - - const t = (show ? getSupportedLanguageT : getSupportedUserLanguageT)(interaction); - if (PermissionsBits.has(permissions, PermissionFlagsBits.Administrator)) { - content = t(LanguageKeys.Commands.Moderation.PermissionsAll); - } else { - const list = listAll ? PermissionsBitsList : ModeratorPermissionsList; - content = listMissing ? this.#renderAllPermissions(t, permissions, list) : this.#renderPermissions(t, permissions, list); - } - - const embed = new EmbedBuilder() // - .setColor(getColor(interaction)) - .setTitle(t(Root.Title, { username: getTag(target.user), id: target.id })) - .setDescription(content); - return interaction.reply({ embeds: [embed], ephemeral: !show }); - } - - #renderPermissions(t: TFunction, permissions: bigint, list: readonly (readonly [string, bigint])[]): string { - const output: string[] = []; - for (const [name, flag] of list) { - if (PermissionsBits.has(permissions, flag)) { - const isModerator = this.#isModeratorFlag(flag); - const localizedName = isModerator ? bold(this.#localizePermission(t, name)) : this.#localizePermission(t, name); - - output.push(localizedName); - } - } - - return t(LanguageKeys.Globals.AndListValue, { value: output }); - } - - #renderAllPermissions(t: TFunction, permissions: bigint, list: readonly (readonly [string, bigint])[]): string { - const output: string[] = []; - for (const [name, flag] of list) { - const isModerator = this.#isModeratorFlag(flag); - const localizedName = isModerator ? bold(this.#localizePermission(t, name)) : this.#localizePermission(t, name); - - if (PermissionsBits.has(permissions, flag)) { - output.push(`${isModerator ? '🔸' : '🔹'} ${localizedName}`); - } else { - output.push(`-# ◾ ${localizedName}`); - } - } - - return output.join('\n'); - } - - #isModeratorFlag(flag: bigint) { - return PermissionsBits.any(flag, ModeratorPermissionsBits); - } - - #localizePermission(t: TFunction, name: string) { - return t(`permissions:${name}`); - } -} diff --git a/src/commands/Moderation/addrole.ts b/src/commands/Moderation/addrole.ts deleted file mode 100644 index 40ff6d677..000000000 --- a/src/commands/Moderation/addrole.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { ModerationCommand } from '#lib/moderation'; -import { PermissionLevels, type GuildMessage } from '#lib/types'; -import { TypeVariation } from '#utils/moderationConstants'; -import { ApplyOptions } from '@sapphire/decorators'; -import { PermissionFlagsBits, type Role } from 'discord.js'; - -type Type = TypeVariation.RoleAdd; -type ValueType = null; - -@ApplyOptions>({ - aliases: ['ar'], - description: LanguageKeys.Commands.Moderation.AddRoleDescription, - detailedDescription: LanguageKeys.Commands.Moderation.AddRoleExtended, - permissionLevel: PermissionLevels.Administrator, - requiredClientPermissions: [PermissionFlagsBits.ManageRoles], - type: TypeVariation.RoleAdd, - requiredMember: true, - actionStatusKey: LanguageKeys.Moderation.ActionIsActiveRole -}) -export class UserModerationCommand extends ModerationCommand { - protected override async resolveParameters(args: ModerationCommand.Args) { - return { - targets: await this.resolveParametersUser(args), - role: await args.pick('roleName'), - duration: await this.resolveParametersDuration(args), - reason: await this.resolveParametersReason(args) - }; - } - - protected override getHandleDataContext(_message: GuildMessage, context: HandlerParameters) { - return context.role; - } -} - -interface HandlerParameters extends ModerationCommand.HandlerParameters { - role: Role; -} diff --git a/src/commands/Moderation/ban.ts b/src/commands/Moderation/ban.ts deleted file mode 100644 index 4080e9778..000000000 --- a/src/commands/Moderation/ban.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { readSettings } from '#lib/database'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { ModerationCommand } from '#lib/moderation'; -import type { GuildMessage } from '#lib/types'; -import { getModeration } from '#utils/functions'; -import { TimeOptions, getSeconds } from '#utils/moderation-utilities'; -import { TypeVariation, type Unlock } from '#utils/moderationConstants'; -import { ApplyOptions } from '@sapphire/decorators'; -import { PermissionFlagsBits } from 'discord.js'; - -type Type = TypeVariation.Ban; -type ValueType = Unlock | null; - -@ApplyOptions>({ - aliases: ['b'], - description: LanguageKeys.Commands.Moderation.BanDescription, - detailedDescription: LanguageKeys.Commands.Moderation.BanExtended, - options: TimeOptions, - requiredClientPermissions: [PermissionFlagsBits.BanMembers], - type: TypeVariation.Ban -}) -export class UserModerationCommand extends ModerationCommand { - protected override async preHandle(message: GuildMessage) { - const settings = await readSettings(message.guild); - return settings.eventsBanAdd ? { unlock: getModeration(message.guild).createLock() } : null; - } - - protected override getHandleDataContext(_message: GuildMessage, context: ModerationCommand.HandlerParameters) { - return getSeconds(context.args); - } - - protected override postHandle(_message: GuildMessage, { preHandled }: ModerationCommand.PostHandleParameters) { - preHandled?.unlock(); - } - - protected override async checkTargetCanBeModerated(message: GuildMessage, context: ModerationCommand.HandlerParameters) { - const member = await super.checkTargetCanBeModerated(message, context); - if (member && !member.bannable) throw context.args.t(LanguageKeys.Commands.Moderation.BanNotBannable); - return member; - } -} diff --git a/src/commands/Moderation/kick.ts b/src/commands/Moderation/kick.ts deleted file mode 100644 index d99e1d01d..000000000 --- a/src/commands/Moderation/kick.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { readSettings } from '#lib/database'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { ModerationCommand } from '#lib/moderation'; -import type { GuildMessage } from '#lib/types'; -import { getModeration } from '#utils/functions'; -import { TypeVariation, type Unlock } from '#utils/moderationConstants'; -import { ApplyOptions } from '@sapphire/decorators'; -import { PermissionFlagsBits } from 'discord.js'; - -type Type = TypeVariation.Kick; -type ValueType = Unlock | null; - -@ApplyOptions>({ - aliases: ['k'], - description: LanguageKeys.Commands.Moderation.KickDescription, - detailedDescription: LanguageKeys.Commands.Moderation.KickExtended, - requiredClientPermissions: [PermissionFlagsBits.KickMembers], - requiredMember: true, - type: TypeVariation.Kick -}) -export class UserModerationCommand extends ModerationCommand { - protected override async preHandle(message: GuildMessage) { - const settings = await readSettings(message.guild); - return settings.channelsLogsMemberRemove ? { unlock: getModeration(message.guild).createLock() } : null; - } - - protected override postHandle(_message: GuildMessage, { preHandled }: ModerationCommand.PostHandleParameters) { - preHandled?.unlock(); - } - - protected override async checkTargetCanBeModerated(message: GuildMessage, context: ModerationCommand.HandlerParameters) { - const member = await super.checkTargetCanBeModerated(message, context); - if (member && !member.kickable) throw context.args.t(LanguageKeys.Commands.Moderation.KickNotKickable); - return member; - } -} diff --git a/src/commands/Moderation/mute.ts b/src/commands/Moderation/mute.ts deleted file mode 100644 index 5440359d9..000000000 --- a/src/commands/Moderation/mute.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { SetUpModerationCommand } from '#lib/moderation'; -import { TypeVariation } from '#utils/moderationConstants'; -import { ApplyOptions } from '@sapphire/decorators'; -import { PermissionFlagsBits } from 'discord.js'; - -type Type = TypeVariation.Mute; -type ValueType = null; - -@ApplyOptions>({ - aliases: ['m'], - description: LanguageKeys.Commands.Moderation.MuteDescription, - detailedDescription: LanguageKeys.Commands.Moderation.MuteExtended, - requiredClientPermissions: [PermissionFlagsBits.ManageRoles], - type: TypeVariation.Mute -}) -export class UserSetUpModerationCommand extends SetUpModerationCommand {} diff --git a/src/commands/Moderation/prune.ts b/src/commands/Moderation/prune.ts deleted file mode 100644 index 870b958bb..000000000 --- a/src/commands/Moderation/prune.ts +++ /dev/null @@ -1,447 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { WolfSubcommand } from '#lib/structures'; -import { PermissionLevels, type GuildMessage } from '#lib/types'; -import { urlRegex } from '#utils/Links/UrlRegex'; -import { days, isGuildMessage, seconds } from '#utils/common'; -import { andMix, type BooleanFn } from '#utils/common/comparators'; -import { getLogger, sendTemporaryMessage } from '#utils/functions'; -import { getImageUrl } from '#utils/util'; -import { ApplyOptions } from '@sapphire/decorators'; -import { Args, Argument, CommandOptionsRunTypeEnum } from '@sapphire/framework'; -import { filterNullAndUndefined, isNullish, isNullishOrEmpty } from '@sapphire/utilities'; -import { Collection, PermissionFlagsBits, RESTJSONErrorCodes, Message, type PartialMessage, TextChannel, DiscordAPIError } from 'discord.js'; -import { chunk } from '@sapphire/iterator-utilities'; -import { setTimeout } from 'node:timers/promises'; - -const enum Position { - Before, - After -} - -const attachmentsFlags = ['f', 'file', 'files', 'upload', 'uploads'] as const; -const imageFlags = ['img', 'image', 'images'] as const; -const authorFlags = ['a', 'author', 'me'] as const; -const botsFlags = ['b', 'bot', 'bots'] as const; -const humansFlags = ['h', 'human', 'humans'] as const; -const invitesFlags = ['i', 'inv', 'invite', 'invites'] as const; -const linksFlags = ['l', 'link', 'links'] as const; -const youFlags = ['y', 'you', 'wolfstar'] as const; -const pinsFlags = ['p', 'pin', 'pins'] as const; -const silentFlags = ['s', 'silent'] as const; -const mentionsFlags = ['men', 'mentions'] as const; -const embedsFlags = ['e', 'embeds'] as const; -const ageOptions = ['age'] as const; -const includesOptions = ['include', 'includes', 'contain', 'contains'] as const; -const matchOptions = ['m', 'match'] as const; -const startswithOptions = ['sw', 'startswith'] as const; -const endswithOptions = ['ew', 'endswith'] as const; - -@ApplyOptions({ - aliases: ['purge', 'nuke', 'sweep'], - description: LanguageKeys.Commands.Moderation.PruneDescription, - detailedDescription: LanguageKeys.Commands.Moderation.PruneExtended, - subcommands: [ - { name: 'attachments', messageRun: 'attachments' }, - { name: 'images', messageRun: 'images' }, - { name: 'author', messageRun: 'author' }, - { name: 'bots', messageRun: 'bots' }, - { name: 'humans', messageRun: 'humans' }, - { name: 'invites', messageRun: 'invites' }, - { name: 'links', messageRun: 'links' }, - { name: 'you', messageRun: 'you' }, - { name: 'pins', messageRun: 'pins' }, - { name: 'silent', messageRun: 'silent' }, - { name: 'age', messageRun: 'age' }, - { name: 'includes', messageRun: 'includes' }, - { name: 'match', messageRun: 'match' }, - { name: 'startswith', messageRun: 'startswith' }, - { name: 'endswith', messageRun: 'endswith' }, - { name: 'mentions', messageRun: 'mentions' }, - { name: 'embeds', messageRun: 'embeds' }, - { name: 'any', messageRun: 'any', default: true } - ], - flags: [ - ...attachmentsFlags, - ...imageFlags, - ...authorFlags, - ...botsFlags, - ...humansFlags, - ...invitesFlags, - ...linksFlags, - ...youFlags, - ...pinsFlags, - ...silentFlags - ], - options: [...ageOptions, ...matchOptions, ...startswithOptions, ...endswithOptions, ...includesOptions], - permissionLevel: PermissionLevels.Moderator, - requiredClientPermissions: [PermissionFlagsBits.ManageMessages, PermissionFlagsBits.ReadMessageHistory, PermissionFlagsBits.EmbedLinks], - runIn: [CommandOptionsRunTypeEnum.GuildAny] -}) -export class UserCommand extends WolfSubcommand { - private get timespan(): Argument { - return this.container.stores.get('arguments').get('timespan') as Argument; - } - - public async any(message: GuildMessage, args: WolfSubcommand.Args) { - return this.handlePurge(message, args, () => true, 'any'); - } - - public async attachments(message: GuildMessage, args: WolfSubcommand.Args) { - return this.handlePurge(message, args, (msg) => msg.attachments.size > 0, 'attachments'); - } - - public async images(message: GuildMessage, args: WolfSubcommand.Args) { - return this.handlePurge(message, args, (msg) => msg.attachments.some((at) => !isNullish(getImageUrl(at.url))), 'images'); - } - - public async author(message: GuildMessage, args: WolfSubcommand.Args) { - const author = args.finished ? message.author : await args.pick('user'); - return this.handlePurge(message, args, (msg) => msg.author.id === author.id, 'author'); - } - - public async bots(message: GuildMessage, args: WolfSubcommand.Args) { - return this.handlePurge(message, args, (msg) => msg.author.bot, 'bots'); - } - - public async humans(message: GuildMessage, args: WolfSubcommand.Args) { - return this.handlePurge(message, args, (msg) => !msg.author.bot, 'humans'); - } - - public async invites(message: GuildMessage, args: WolfSubcommand.Args) { - return this.handlePurge(message, args, (msg) => UserCommand.kInviteRegExp.test(msg.content), 'invites'); - } - - public async links(message: GuildMessage, args: WolfSubcommand.Args) { - return this.handlePurge(message, args, (msg) => UserCommand.kLinkRegExp.test(msg.content), 'links'); - } - - public async you(message: GuildMessage, args: WolfSubcommand.Args) { - return this.handlePurge(message, args, (msg) => msg.author.id === process.env.CLIENT_ID, 'you'); - } - - public async pins(message: GuildMessage, args: WolfSubcommand.Args) { - return this.handlePurge(message, args, (msg) => msg.pinned, 'pins'); - } - - public async silent(message: GuildMessage, args: WolfSubcommand.Args) { - return this.handlePurge(message, args, () => true, 'silent', true); - } - - public async age(message: GuildMessage, args: WolfSubcommand.Args) { - const maximumAge = await this.getAge(args); - const oldestMessageTimestamp = Date.now() - maximumAge; - return this.handlePurge(message, args, (msg) => msg.createdTimestamp > oldestMessageTimestamp, 'age'); - } - - public async includes(message: GuildMessage, args: WolfSubcommand.Args) { - const includes = (await args.rest('string')).toLowerCase(); - return this.handlePurge(message, args, (msg) => msg.content.toLowerCase().includes(includes), 'includes'); - } - - public async match(message: GuildMessage, args: WolfSubcommand.Args) { - const pattern = new RegExp(await args.rest('string'), 'i'); - return this.handlePurge(message, args, (msg) => pattern.test(msg.content), 'match'); - } - - public async startswith(message: GuildMessage, args: WolfSubcommand.Args) { - const startswith = (await args.rest('string')).toLowerCase(); - return this.handlePurge(message, args, (msg) => msg.content.toLowerCase().startsWith(startswith), 'startswith'); - } - - public async endswith(message: GuildMessage, args: WolfSubcommand.Args) { - const endswith = (await args.rest('string')).toLowerCase(); - return this.handlePurge(message, args, (msg) => msg.content.toLowerCase().endsWith(endswith), 'endswith'); - } - - public async mentions(message: GuildMessage, args: WolfSubcommand.Args) { - return this.handlePurge( - message, - args, - (msg) => msg.mentions.users.size > 0 || msg.mentions.roles.size > 0 || msg.mentions.channels.size > 0, - 'mentions' - ); - } - - public async embeds(message: GuildMessage, args: WolfSubcommand.Args) { - return this.handlePurge(message, args, (msg) => msg.embeds.length > 0, 'embeds'); - } - - private async handlePurge( - message: GuildMessage, - args: WolfSubcommand.Args, - filter: BooleanFn<[GuildMessage]>, - subcommand: string, - silent = false - ) { - const limit = await args.pick('integer', { minimum: 1, maximum: subcommand === 'any' ? 1000 : 100 }); - const rawPosition = args.finished ? null : await args.pick(UserCommand.position); - const targetMessage = args.finished && rawPosition === null ? message : await args.pick('message'); - const combinedFilter = await this.getFilters(args); - - // Combine the filter with the additional filter provided by the subcommand - const finalFilter = (msg: GuildMessage) => { - switch (subcommand) { - case 'bots': - if (args.getFlags(...botsFlags)) { - this.error(LanguageKeys.Commands.Moderation.PruneNotSubcommandSameOFSameFlag); - } - break; - case 'humans': - if (args.getFlags(...humansFlags)) { - this.error(LanguageKeys.Commands.Moderation.PruneNotSubcommandSameOFSameFlag); - } - break; - case 'attachments': - if (args.getFlags(...attachmentsFlags)) { - this.error(LanguageKeys.Commands.Moderation.PruneNotSubcommandSameOFSameFlag); - } - break; - case 'images': - if (args.getFlags(...imageFlags)) { - this.error(LanguageKeys.Commands.Moderation.PruneNotSubcommandSameOFSameFlag); - } - break; - case 'author': - if (args.getFlags(...authorFlags)) { - this.error(LanguageKeys.Commands.Moderation.PruneNotSubcommandSameOFSameFlag); - } - break; - case 'invites': - if (args.getFlags(...invitesFlags)) { - this.error(LanguageKeys.Commands.Moderation.PruneNotSubcommandSameOFSameFlag); - } - break; - case 'links': - if (args.getFlags(...linksFlags)) { - this.error(LanguageKeys.Commands.Moderation.PruneNotSubcommandSameOFSameFlag); - } - break; - case 'you': - if (args.getFlags(...youFlags)) { - this.error(LanguageKeys.Commands.Moderation.PruneNotSubcommandSameOFSameFlag); - } - break; - case 'pins': - if (args.getFlags(...pinsFlags)) { - this.error(LanguageKeys.Commands.Moderation.PruneNotSubcommandSameOFSameFlag); - } - break; - case 'silent': - if (args.getFlags(...silentFlags)) { - this.error(LanguageKeys.Commands.Moderation.PruneNotSubcommandSameOFSameFlag); - } - break; - case 'mentions': - if (args.getFlags(...mentionsFlags)) { - this.error(LanguageKeys.Commands.Moderation.PruneNotSubcommandSameOFSameFlag); - } - break; - case 'embeds': - if (args.getFlags(...embedsFlags)) { - this.error(LanguageKeys.Commands.Moderation.PruneNotSubcommandSameOFSameFlag); - } - break; - case 'age': - if (args.getOption(...ageOptions)) { - this.error(LanguageKeys.Commands.Moderation.PruneNotSubcommandSameOFSameFlag); - } - break; - case 'includes': - if (args.getOption(...includesOptions)) { - this.error(LanguageKeys.Commands.Moderation.PruneNotSubcommandSameOFSameFlag); - } - break; - case 'match': - if (args.getOption(...matchOptions)) { - this.error(LanguageKeys.Commands.Moderation.PruneNotSubcommandSameOFSameFlag); - } - break; - case 'startswith': - if (args.getOption(...startswithOptions)) { - this.error(LanguageKeys.Commands.Moderation.PruneNotSubcommandSameOFSameFlag); - } - break; - case 'endswith': - if (args.getOption(...endswithOptions)) { - this.error(LanguageKeys.Commands.Moderation.PruneNotSubcommandSameOFSameFlag); - } - break; - } - return filter(msg) && combinedFilter(msg); - }; - - const position = this.resolvePosition(rawPosition); - - if (args.getFlags(...silentFlags) && !silent) silent = true; - // Fetch and filter messages using purgeBulk - const filteredMessages = await this.fetchMessages(message.channel as TextChannel, { - limit, - [position]: targetMessage.id, - filter: finalFilter - }); - - if (filteredMessages.size === 0) this.error(LanguageKeys.Commands.Moderation.PruneNoDeletes); - - if (silent && filteredMessages.size !== 100) { - filteredMessages.set(message.id, message); - } - - const filteredKeys = this.resolveKeys(filteredMessages, position, limit); - if (silent) return null; - - // Perform a bulk delete, throw if it returns unknown message, and log deleted messages - await this.bulkDeleteMessages(message.channel as TextChannel, filteredKeys); - - const content = args.t(LanguageKeys.Commands.Moderation.PruneAlert, { - count: filteredKeys.size, - total: limit - }); - return sendTemporaryMessage(message, content, seconds(10)); - } - - private async fetchMessages( - channel: TextChannel, - options: { limit: number; before?: string; after?: string; filter: BooleanFn<[GuildMessage]> } - ): Promise> { - const { before, after, filter, limit } = options; - let remainingLimit = limit; - const fetchedMessages = new Collection(); - - const fetchAndFilter = async (before?: string, after?: string) => { - let messages = new Collection(); - try { - messages = await channel.messages.fetch({ limit: 100, before, after, cache: true }); - } catch (error) { - if ((error as any).code === RESTJSONErrorCodes.ProvidedTooFewOrTooManyMessagesToDelete) { - messages = new Collection([[channel.lastMessageId!, channel.lastMessage!]]); - } else throw error; - } - const filteredMessage = (msg: Message) => isGuildMessage(msg) && filter(msg); - - const filteredMessages = messages.filter(filteredMessage).sort((a, b) => b.createdTimestamp - a.createdTimestamp); - - for (const message of filteredMessages.values()) { - if (remainingLimit <= 0) break; - fetchedMessages.set(message.id, message as GuildMessage); - remainingLimit--; - } - - if (remainingLimit > 0 && filteredMessages.size > 0) { - await setTimeout(2000); - await fetchAndFilter(before && filteredMessages.last()?.id, after && filteredMessages.first()?.id); - } - }; - - await fetchAndFilter(before, after); - return fetchedMessages; - } - - private async bulkDeleteMessages( - channel: TextChannel, - messages: Collection> - ): Promise> { - const logger = getLogger(channel.guild.id); - logger.prune.set(channel.id, { userId: channel.client.user!.id }); - const deletedMessages = new Collection(); - - const messageIds = Array.from(messages.filter((msg) => msg.bulkDeletable).keys()); - - for (const chunked of chunk(messageIds, 100)) { - try { - const deleted = await channel.bulkDelete(chunked); - deletedMessages.concat(deleted.filter(filterNullAndUndefined)); - } catch (error) { - logger.prune.unset(channel.id); - if ((error as DiscordAPIError).code !== RESTJSONErrorCodes.UnknownMessage) throw error; - } - } - - return deletedMessages; - } - - private async getFilters(args: WolfSubcommand.Args): Promise> { - const fns: BooleanFn<[GuildMessage]>[] = []; - - const user = args.finished ? null : await args.pick('user').catch(() => null); - if (user !== null) fns.push((mes: GuildMessage) => mes.author.id === user.id); - - const maximumAge = await this.getAge(args); - const oldestMessageTimestamp = Date.now() - maximumAge; - fns.push((mes: GuildMessage) => mes.createdTimestamp > oldestMessageTimestamp); - - if (args.getFlags(...attachmentsFlags)) fns.push((mes: GuildMessage) => mes.attachments.size > 0); - else if (args.getFlags(...imageFlags)) fns.push((mes: GuildMessage) => mes.attachments.some((at) => !isNullish(getImageUrl(at.url)))); - if (args.getFlags(...authorFlags)) fns.push((mes: GuildMessage) => mes.author.id === args.message.author.id); - if (args.getFlags(...botsFlags)) fns.push((mes: GuildMessage) => mes.author.bot); - if (args.getFlags(...humansFlags)) fns.push((mes: GuildMessage) => !mes.author.bot); - if (args.getFlags(...invitesFlags)) fns.push((mes: GuildMessage) => UserCommand.kInviteRegExp.test(mes.content)); - if (args.getFlags(...linksFlags)) fns.push((mes: GuildMessage) => UserCommand.kLinkRegExp.test(mes.content)); - if (args.getFlags(...youFlags)) fns.push((mes: GuildMessage) => mes.author.id === process.env.CLIENT_ID); - if (!args.getFlags(...pinsFlags)) fns.push((mes: GuildMessage) => !mes.pinned); - if (args.getFlags(...mentionsFlags)) - fns.push((mes: GuildMessage) => mes.mentions.users.size > 0 || mes.mentions.roles.size > 0 || mes.mentions.channels.size > 0); - if (args.getFlags(...embedsFlags)) fns.push((mes: GuildMessage) => mes.embeds.length > 0); - - const includes = args.getOption(...includesOptions)?.toLowerCase(); - if (!isNullishOrEmpty(includes)) fns.push((mes: GuildMessage) => mes.content.toLowerCase().includes(includes)); - const pattern = args.getOption(...matchOptions); - if (!isNullishOrEmpty(pattern)) fns.push((mes: GuildMessage) => new RegExp(pattern, 'i').test(mes.content)); - const startswith = args.getOption(...startswithOptions)?.toLowerCase(); - if (!isNullishOrEmpty(startswith)) fns.push((mes: GuildMessage) => mes.content.toLowerCase().startsWith(startswith)); - const endswith = args.getOption(...endswithOptions)?.toLowerCase(); - if (!isNullishOrEmpty(endswith)) fns.push((mes: GuildMessage) => mes.content.toLowerCase().endsWith(endswith)); - - return andMix(...fns); - } - - private resolveKeys(messages: Collection, position: 'before' | 'after', limit: number): Collection { - const keys = position === 'before' ? [...messages.keys()].slice(0, limit) : [...messages.keys()].slice(messages.size - limit); - const collection = new Collection(); - for (const key of keys) { - const message = messages.get(key); - if (message) { - collection.set(key, message); - } - } - return collection; - } - - private resolvePosition(position: Position | null) { - return position === Position.After ? 'after' : 'before'; - } - - private async getAge(args: WolfSubcommand.Args) { - const parameter = args.getOption(...ageOptions); - if (parameter === null) return days(14); - - const argument = this.timespan; - const result = await argument.run(parameter, { - args, - argument, - command: this, - commandContext: args.commandContext, - message: args.message, - minimum: 0, - maximum: days(14) - }); - return result.unwrapRaw(); - } - - private static position = Args.make((parameter, { argument }) => { - const position = UserCommand.kCommandPrunePositions[parameter.toLowerCase()]; - if (typeof position === 'undefined') { - return Args.error({ parameter, argument, identifier: LanguageKeys.Commands.Moderation.PruneInvalidPosition }); - } - - return Args.ok(position); - }); - - private static readonly kInviteRegExp = /(?:discord\.(?:gg|io|me|plus|link)|invite\.(?:gg|ink)|discord(?:app)?\.com\/invite)\/(?:[\w-]{2,})/i; - private static readonly kLinkRegExp = urlRegex({ requireProtocol: true, tlds: true }); - private static readonly kCommandPrunePositions: Record = { - before: Position.Before, - b: Position.Before, - after: Position.After, - a: Position.After - }; -} diff --git a/src/commands/Moderation/removerole.ts b/src/commands/Moderation/removerole.ts deleted file mode 100644 index dcf900e5e..000000000 --- a/src/commands/Moderation/removerole.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { ModerationCommand } from '#lib/moderation'; -import { PermissionLevels, type GuildMessage } from '#lib/types'; -import { TypeVariation } from '#utils/moderationConstants'; -import { ApplyOptions } from '@sapphire/decorators'; -import { PermissionFlagsBits, type Role } from 'discord.js'; - -type Type = TypeVariation.RoleRemove; -type ValueType = null; - -@ApplyOptions>({ - aliases: ['rro'], - description: LanguageKeys.Commands.Moderation.RemoveRoleDescription, - detailedDescription: LanguageKeys.Commands.Moderation.RemoveRoleExtended, - permissionLevel: PermissionLevels.Administrator, - requiredClientPermissions: [PermissionFlagsBits.ManageRoles], - requiredMember: true, - type: TypeVariation.RoleRemove, - actionStatusKey: LanguageKeys.Moderation.ActionIsNotActiveRole -}) -export class UserModerationCommand extends ModerationCommand { - protected override async resolveParameters(args: ModerationCommand.Args) { - return { - targets: await this.resolveParametersUser(args), - role: await args.pick('roleName'), - duration: await this.resolveParametersDuration(args), - reason: await this.resolveParametersReason(args) - }; - } - - protected override getHandleDataContext(_message: GuildMessage, context: HandlerParameters) { - return context.role; - } -} - -interface HandlerParameters extends ModerationCommand.HandlerParameters { - role: Role; -} diff --git a/src/commands/Moderation/setnickname.ts b/src/commands/Moderation/setnickname.ts deleted file mode 100644 index 653ce6c7f..000000000 --- a/src/commands/Moderation/setnickname.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { ModerationCommand } from '#lib/moderation'; -import type { GuildMessage } from '#lib/types'; -import { TypeVariation } from '#utils/moderationConstants'; -import { ApplyOptions } from '@sapphire/decorators'; -import { PermissionFlagsBits } from 'discord.js'; - -type Type = TypeVariation.SetNickname; -type ValueType = null; - -@ApplyOptions>({ - aliases: ['sn'], - description: LanguageKeys.Commands.Moderation.SetNicknameDescription, - detailedDescription: LanguageKeys.Commands.Moderation.SetNicknameExtended, - requiredClientPermissions: [PermissionFlagsBits.ManageNicknames], - type: TypeVariation.SetNickname, - requiredMember: true -}) -export class UserModerationCommand extends ModerationCommand { - protected override async resolveParameters(args: ModerationCommand.Args) { - return { - targets: await this.resolveParametersUser(args), - nickname: args.finished ? null : await args.pick('string'), - duration: await this.resolveParametersDuration(args), - reason: await this.resolveParametersReason(args) - }; - } - - protected override getHandleDataContext(_message: GuildMessage, context: HandlerParameters) { - return context.nickname; - } - - protected override getActionStatusKey(context: HandlerParameters) { - return context.nickname === null ? LanguageKeys.Moderation.ActionIsNotActiveNickname : LanguageKeys.Moderation.ActionIsActiveNickname; - } -} - -interface HandlerParameters extends ModerationCommand.HandlerParameters { - nickname: string | null; -} diff --git a/src/commands/Moderation/softban.ts b/src/commands/Moderation/softban.ts deleted file mode 100644 index 4633f5c2e..000000000 --- a/src/commands/Moderation/softban.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { readSettings } from '#lib/database'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { ModerationCommand } from '#lib/moderation'; -import type { GuildMessage } from '#lib/types'; -import { getModeration } from '#utils/functions'; -import { TimeOptions, getSeconds } from '#utils/moderation-utilities'; -import { TypeVariation, type Unlock } from '#utils/moderationConstants'; -import { ApplyOptions } from '@sapphire/decorators'; -import { PermissionFlagsBits } from 'discord.js'; - -type Type = TypeVariation.Softban; -type ValueType = Unlock | null; - -@ApplyOptions>({ - aliases: ['sb'], - description: LanguageKeys.Commands.Moderation.SoftBanDescription, - detailedDescription: LanguageKeys.Commands.Moderation.SoftBanExtended, - options: TimeOptions, - requiredClientPermissions: [PermissionFlagsBits.BanMembers], - requiredMember: false, - type: TypeVariation.Softban -}) -export class UserModerationCommand extends ModerationCommand { - public override async preHandle(message: GuildMessage) { - const settings = await readSettings(message.guild); - return settings.eventsBanAdd || settings.eventsBanRemove ? { unlock: getModeration(message.guild).createLock() } : null; - } - - public override getHandleDataContext(_message: GuildMessage, context: ModerationCommand.HandlerParameters) { - return getSeconds(context.args); - } - - public override postHandle(_message: GuildMessage, { preHandled }: ModerationCommand.PostHandleParameters) { - preHandled?.unlock(); - } - - public override async checkTargetCanBeModerated(message: GuildMessage, context: ModerationCommand.HandlerParameters) { - const member = await super.checkTargetCanBeModerated(message, context); - if (member && !member.bannable) throw context.args.t(LanguageKeys.Commands.Moderation.BanNotBannable); - return member; - } -} diff --git a/src/commands/Moderation/timeout.ts b/src/commands/Moderation/timeout.ts deleted file mode 100644 index 9dd54f6a3..000000000 --- a/src/commands/Moderation/timeout.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { ModerationCommand } from '#lib/moderation'; -import type { GuildMessage } from '#lib/types'; -import { TypeVariation } from '#utils/moderationConstants'; -import { ApplyOptions } from '@sapphire/decorators'; -import { PermissionFlagsBits } from 'discord.js'; - -type Type = TypeVariation.Timeout; -type ValueType = null; - -@ApplyOptions>({ - description: LanguageKeys.Commands.Moderation.TimeoutApplyDescription, - detailedDescription: LanguageKeys.Commands.Moderation.TimeoutApplyExtended, - requiredClientPermissions: [PermissionFlagsBits.ModerateMembers], - requiredMember: true, - type: TypeVariation.Timeout -}) -export class UserModerationCommand extends ModerationCommand { - protected override async checkTargetCanBeModerated(message: GuildMessage, context: ModerationCommand.HandlerParameters) { - const member = await super.checkTargetCanBeModerated(message, context); - if (member && !member.moderatable) throw context.args.t(LanguageKeys.Commands.Moderation.TimeoutNotModeratable); - return member; - } -} diff --git a/src/commands/Moderation/unban.ts b/src/commands/Moderation/unban.ts deleted file mode 100644 index 2106285e5..000000000 --- a/src/commands/Moderation/unban.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { readSettings } from '#lib/database'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { ModerationCommand } from '#lib/moderation'; -import type { GuildMessage } from '#lib/types'; -import { getModeration } from '#utils/functions'; -import { TypeVariation, type Unlock } from '#utils/moderationConstants'; -import { ApplyOptions } from '@sapphire/decorators'; -import { PermissionFlagsBits } from 'discord.js'; - -type Type = TypeVariation.Ban; -type ValueType = Unlock | null; - -@ApplyOptions>({ - aliases: ['ub'], - description: LanguageKeys.Commands.Moderation.UnbanDescription, - detailedDescription: LanguageKeys.Commands.Moderation.UnbanExtended, - requiredClientPermissions: [PermissionFlagsBits.BanMembers], - requiredMember: false, - type: TypeVariation.Ban, - isUndoAction: true -}) -export class UserModerationCommand extends ModerationCommand { - public override async preHandle(message: GuildMessage) { - const settings = await readSettings(message.guild); - return settings.eventsBanRemove ? { unlock: getModeration(message.guild).createLock() } : null; - } - - public override postHandle(_message: GuildMessage, { preHandled }: ModerationCommand.PostHandleParameters) { - preHandled?.unlock(); - } -} diff --git a/src/commands/Moderation/unmute.ts b/src/commands/Moderation/unmute.ts deleted file mode 100644 index 59a11fddf..000000000 --- a/src/commands/Moderation/unmute.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { SetUpModerationCommand } from '#lib/moderation'; -import { TypeVariation } from '#utils/moderationConstants'; -import { ApplyOptions } from '@sapphire/decorators'; - -type Type = TypeVariation.Mute; -type ValueType = null; - -@ApplyOptions>({ - aliases: ['um'], - description: LanguageKeys.Commands.Moderation.UnmuteDescription, - detailedDescription: LanguageKeys.Commands.Moderation.UnmuteExtended, - type: TypeVariation.Mute, - isUndoAction: true -}) -export class UserSetUpModerationCommand extends SetUpModerationCommand {} diff --git a/src/commands/Moderation/untimeout.ts b/src/commands/Moderation/untimeout.ts deleted file mode 100644 index 7f88fc624..000000000 --- a/src/commands/Moderation/untimeout.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { ModerationCommand } from '#lib/moderation'; -import { TypeVariation } from '#utils/moderationConstants'; -import { ApplyOptions } from '@sapphire/decorators'; -import { PermissionFlagsBits } from 'discord.js'; - -type Type = TypeVariation.Timeout; -type ValueType = null; - -@ApplyOptions>({ - description: LanguageKeys.Commands.Moderation.TimeoutUndoDescription, - detailedDescription: LanguageKeys.Commands.Moderation.TimeoutUndoExtended, - requiredClientPermissions: [PermissionFlagsBits.ModerateMembers], - requiredMember: true, - isUndoAction: true, - type: TypeVariation.Timeout -}) -export class UserModerationCommand extends ModerationCommand {} diff --git a/src/commands/Moderation/vmute.ts b/src/commands/Moderation/vmute.ts deleted file mode 100644 index 4144ef6d2..000000000 --- a/src/commands/Moderation/vmute.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { ModerationCommand } from '#lib/moderation'; -import { TypeVariation } from '#utils/moderationConstants'; -import { ApplyOptions } from '@sapphire/decorators'; -import { PermissionFlagsBits } from 'discord.js'; - -type Type = TypeVariation.VoiceMute; -type ValueType = null; - -@ApplyOptions>({ - aliases: ['vm'], - description: LanguageKeys.Commands.Moderation.VmuteDescription, - detailedDescription: LanguageKeys.Commands.Moderation.VmuteExtended, - requiredClientPermissions: [PermissionFlagsBits.MuteMembers], - requiredMember: true, - type: TypeVariation.VoiceMute -}) -export class UserModerationCommand extends ModerationCommand {} diff --git a/src/commands/Moderation/voicekick.ts b/src/commands/Moderation/voicekick.ts deleted file mode 100644 index 7694c8372..000000000 --- a/src/commands/Moderation/voicekick.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { ModerationCommand } from '#lib/moderation'; -import { TypeVariation } from '#utils/moderationConstants'; -import { ApplyOptions } from '@sapphire/decorators'; -import { PermissionFlagsBits } from 'discord.js'; - -type Type = TypeVariation.VoiceKick; -type ValueType = null; - -@ApplyOptions>({ - aliases: ['vk', 'vkick'], - description: LanguageKeys.Commands.Moderation.VoiceKickDescription, - detailedDescription: LanguageKeys.Commands.Moderation.VoiceKickExtended, - requiredClientPermissions: [PermissionFlagsBits.ManageChannels, PermissionFlagsBits.MoveMembers], - requiredMember: true, - type: TypeVariation.VoiceKick -}) -export class UserModerationCommand extends ModerationCommand {} diff --git a/src/commands/Moderation/vunmute.ts b/src/commands/Moderation/vunmute.ts deleted file mode 100644 index c287ce0d7..000000000 --- a/src/commands/Moderation/vunmute.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { ModerationCommand } from '#lib/moderation'; -import { TypeVariation } from '#utils/moderationConstants'; -import { ApplyOptions } from '@sapphire/decorators'; -import { PermissionFlagsBits } from 'discord.js'; - -type Type = TypeVariation.VoiceMute; -type ValueType = null; - -@ApplyOptions>({ - aliases: ['uvm', 'vum', 'unvmute'], - description: LanguageKeys.Commands.Moderation.VunmuteDescription, - detailedDescription: LanguageKeys.Commands.Moderation.VunmuteExtended, - requiredClientPermissions: [PermissionFlagsBits.MuteMembers], - requiredMember: true, - type: TypeVariation.VoiceMute, - isUndoAction: true -}) -export class UserModerationCommand extends ModerationCommand {} diff --git a/src/commands/Moderation/warn.ts b/src/commands/Moderation/warn.ts deleted file mode 100644 index 332646933..000000000 --- a/src/commands/Moderation/warn.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { ModerationCommand } from '#lib/moderation'; -import { TypeVariation } from '#utils/moderationConstants'; -import { ApplyOptions } from '@sapphire/decorators'; - -type Type = TypeVariation.Warning; -type ValueType = null; - -@ApplyOptions>({ - aliases: ['w', 'warning'], - description: LanguageKeys.Commands.Moderation.WarnDescription, - detailedDescription: LanguageKeys.Commands.Moderation.WarnExtended, - requiredMember: true, - type: TypeVariation.Warning -}) -export class UserModerationCommand extends ModerationCommand {} diff --git a/src/commands/System/Admin/eval.ts b/src/commands/System/Admin/eval.ts deleted file mode 100644 index 29dab9d57..000000000 --- a/src/commands/System/Admin/eval.ts +++ /dev/null @@ -1,253 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { WolfCommand } from '#lib/structures'; -import { PermissionLevels } from '#lib/types'; -import { clean } from '#utils/Sanitizer/clean'; -import { createReferPromise, seconds } from '#utils/common'; -import { ZeroWidthSpace } from '#utils/constants'; -import { cast } from '#utils/util'; -import { bold } from '@discordjs/builders'; -import { ApplyOptions } from '@sapphire/decorators'; -import { send } from '@sapphire/plugin-editable-commands'; -import { Stopwatch } from '@sapphire/stopwatch'; -import { codeBlock, isThenable } from '@sapphire/utilities'; -import type { Message } from 'discord.js'; -import { createRequire } from 'node:module'; -import { fileURLToPath } from 'node:url'; -import { inspect } from 'node:util'; -import { Script, createContext } from 'node:vm'; - -@ApplyOptions({ - aliases: ['ev'], - description: LanguageKeys.Commands.System.EvalDescription, - detailedDescription: LanguageKeys.Commands.System.EvalExtended, - flags: ['async', 'no-timeout', 'json', 'silent', 'showHidden', 'hidden', 'sql'], - options: ['timeout', 'wait', 'lang', 'language', 'depth'], - permissionLevel: PermissionLevels.BotOwner, - quotes: [] -}) -export class UserCommand extends WolfCommand { - private readonly kTimeout = 60000; - #cachedEvalContext: object | null = null; - - public override async messageRun(message: Message, args: WolfCommand.Args) { - const code = await args.rest('string'); - - const wait = args.getOption('timeout', 'wait'); - const flagTime = args.getFlags('no-timeout') ? Infinity : wait === null ? this.kTimeout : Number(wait); - const executeSql = args.getFlags('sql'); - const language = args.getOption('lang', 'language') ?? (executeSql || args.getFlags('json') ? 'json' : 'js'); - const { success, result, time } = executeSql ? await this.sql(code) : await this.eval(message, args, code, flagTime); - - if (args.getFlags('silent')) { - if (!success && result && cast(result).stack) this.container.logger.fatal(cast(result).stack); - return null; - } - - const body = codeBlock(language, result || ZeroWidthSpace); - const header = `${bold(success ? 'Output' : 'Error')}: ${time}`; - // If the sum of the length between the header and the body exceed 2000 characters, send as file: - if ([...header, ...body].length > 2000) { - const file = { attachment: Buffer.from(result, 'utf8'), name: `output.${language}` } as const; - return send(message, { content: header, files: [file] }); - } - - // Otherwise send as a single message: - return send(message, `${header}${body}`); - } - - private async fetchContext() { - if (!this.#cachedEvalContext) { - this.#cachedEvalContext = { - ...globalThis, - buffer: await import('node:buffer'), - crypto: await import('node:crypto'), - events: await import('node:events'), - fs: await import('node:fs'), - http: await import('node:http'), - os: await import('node:os'), - module: await import('node:module'), - path: await import('node:path'), - process: await import('node:process'), - url: await import('node:url'), - util: await import('node:util'), - v8: await import('node:v8'), - vm: await import('node:vm'), - worker_threads: await import('node:worker_threads'), - stream: { web: await import('node:stream/web'), ...(await import('node:stream')) }, - timers: { ...(await import('node:timers')), promises: await import('node:timers/promises') }, - discord: { - ...(await import('discord.js')), - builders: await import('@discordjs/builders'), - collection: await import('@discordjs/collection'), - types: await import('discord-api-types/v10') - }, - sapphire: { - asyncQueue: await import('@sapphire/async-queue'), - fetch: await import('@sapphire/fetch'), - pieces: await import('@sapphire/pieces'), - framework: await import('@sapphire/framework'), - snowflake: await import('@sapphire/snowflake'), - stopwatch: await import('@sapphire/stopwatch'), - utilities: { - ...(await import('@sapphire/utilities')), - time: await import('@sapphire/time-utilities'), - discord: await import('@sapphire/discord.js-utilities') - } - }, - skyra: { - utils: { - common: await import('#utils/common'), - functions: await import('#utils/functions'), - resolvers: await import('#utils/resolvers') - }, - database: { - ...(await import('#lib/database')), - settings: await import('#lib/database/settings') - }, - moderation: { - ...(await import('#lib/moderation')), - actions: await import('#lib/moderation/actions'), - common: await import('#lib/moderation/common'), - managers: { - ...(await import('#lib/moderation/managers')), - loggers: await import('#lib/moderation/managers/loggers') - }, - workers: await import('#lib/moderation/workers') - }, - structures: { - ...(await import('#lib/structures')), - data: await import('#lib/structures/data'), - managers: await import('#lib/structures/managers') - } - }, - container: this.container, - client: this.container.client, - command: this, - require: createRequire(import.meta.url), - __filename: fileURLToPath(import.meta.url), - __dirname: fileURLToPath(new URL('.', import.meta.url)) - }; - } - - return this.#cachedEvalContext; - } - - private async eval(message: Message, args: WolfCommand.Args, code: string, timeout: number): Promise { - if (timeout === Infinity || timeout === 0) return this.runEval(message, args, code, null, undefined); - - const controller = new AbortController(); - const sleepPromise = createReferPromise(); - const timer = setTimeout(() => { - controller.abort(); - sleepPromise.resolve({ - success: false, - time: '⏱ ...', - result: args.t(LanguageKeys.Commands.System.EvalTimeout, { seconds: seconds.fromMilliseconds(timeout) }) - }); - }, timeout); - return Promise.race([this.runEval(message, args, code, controller.signal, timeout).finally(() => clearTimeout(timer)), sleepPromise.promise]); - } - - private async runEval( - message: Message, - args: WolfCommand.Args, - code: string, - signal: AbortSignal | null, - timeout: number | undefined - ): Promise { - if (args.getFlags('async')) code = `(async () => {\n${code}\n})();`; - - let script: Script; - try { - script = new Script(code, { filename: 'eval' }); - } catch (error) { - return { success: false, time: '💥 Syntax Error', result: (error as SyntaxError).message }; - } - - const context = createContext({ ...(await this.fetchContext()), msg: message, message, args, signal }); - - const stopwatch = new Stopwatch(); - let success: boolean; - let syncTime = ''; - let asyncTime = ''; - let result: unknown; - let thenable = false; - - try { - result = script.runInNewContext(context, { timeout, microtaskMode: 'afterEvaluate' }); - - // If the signal aborted, it should not continue processing the result: - if (signal?.aborted) return { success: false, time: '⏱ ...', result: 'AbortError' }; - - syncTime = stopwatch.toString(); - if (isThenable(result)) { - thenable = true; - stopwatch.restart(); - result = await result; - asyncTime = stopwatch.toString(); - } - success = true; - } catch (error) { - if (!syncTime.length) syncTime = stopwatch.toString(); - if (thenable && !asyncTime.length) asyncTime = stopwatch.toString(); - result = error; - success = false; - } - - // If the signal aborted, it should not continue processing the result: - if (signal?.aborted) return { success: false, time: '⏱ ...', result: 'AbortError' }; - - stopwatch.stop(); - if (typeof result !== 'string') { - result = - result instanceof Error - ? result.stack - : args.getFlags('json') - ? JSON.stringify(result, null, 4) - : inspect(result, { - depth: Number(args.getOption('depth') ?? 0) || 0, - showHidden: args.getFlags('showHidden', 'hidden') - }); - } - return { - success, - time: this.formatTime(syncTime, asyncTime ?? ''), - result: clean(result as string) - }; - } - - private async sql(sql: string) { - const stopwatch = new Stopwatch(); - let success: boolean; - let time: string; - let result: unknown; - - try { - result = await this.container.prisma.$queryRawUnsafe(sql); - time = stopwatch.toString(); - success = true; - } catch (error) { - time = stopwatch.toString(); - result = error; - success = false; - } - - stopwatch.stop(); - - return { - success, - time: this.formatTime(time), - result: JSON.stringify(result, null, 2) - }; - } - - private formatTime(syncTime: string, asyncTime?: string) { - return asyncTime ? `⏱ ${asyncTime}<${syncTime}>` : `⏱ ${syncTime}`; - } -} - -interface EvalResult { - success: boolean; - time: string; - result: string; -} diff --git a/src/commands/System/Admin/reboot.ts b/src/commands/System/Admin/reboot.ts deleted file mode 100644 index 1eb958a68..000000000 --- a/src/commands/System/Admin/reboot.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { WolfCommand } from '#lib/structures'; -import { Events, PermissionLevels } from '#lib/types'; -import { ApplyOptions } from '@sapphire/decorators'; -import { send } from '@sapphire/plugin-editable-commands'; -import { envParseBoolean } from '@skyra/env-utilities'; -import type { Message } from 'discord.js'; - -@ApplyOptions({ - description: LanguageKeys.Commands.System.RebootDescription, - detailedDescription: LanguageKeys.Commands.System.RebootExtended, - permissionLevel: PermissionLevels.BotOwner -}) -export class UserCommand extends WolfCommand { - public override async messageRun(message: Message, args: WolfCommand.Args) { - const content = args.t(LanguageKeys.Commands.System.Reboot); - await send(message, content).catch((error) => this.container.logger.fatal(error)); - - if (envParseBoolean('INFLUX_ENABLED')) { - const { client } = this.container; - try { - client.emit( - Events.AnalyticsSync, - client.guilds.cache.size, - client.guilds.cache.reduce((acc, val) => acc + val.memberCount, 0) - ); - - await client.analytics!.writeApi.flush(); - await client.analytics!.writeApi.close(); - } catch { - // noop - } - } - - process.exit(0); - } -} diff --git a/src/commands/Tools/avatar.ts b/src/commands/Tools/avatar.ts deleted file mode 100644 index b6d12f2f8..000000000 --- a/src/commands/Tools/avatar.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { WolfCommand } from '#lib/structures'; -import { getColor, getDisplayAvatar, getEmbedAuthor } from '#utils/util'; -import { EmbedBuilder } from '@discordjs/builders'; -import { ApplyOptions } from '@sapphire/decorators'; -import { send } from '@sapphire/plugin-editable-commands'; -import { PermissionFlagsBits, type ImageSize, type Message } from 'discord.js'; - -const VALID_SIZES = [16, 32, 64, 128, 256, 512, 1024, 2048, 4096] as const satisfies readonly ImageSize[]; - -function isValidImageSize(value: number): value is ImageSize { - return VALID_SIZES.includes(value as (typeof VALID_SIZES)[number]); -} - -@ApplyOptions({ - aliases: ['a', 'av', 'ava'], - description: LanguageKeys.Commands.Tools.AvatarDescription, - detailedDescription: LanguageKeys.Commands.Tools.AvatarExtended, - options: ['size'], - requiredClientPermissions: [PermissionFlagsBits.EmbedLinks] -}) -export class UserCommand extends WolfCommand { - public override async messageRun(message: Message, args: WolfCommand.Args) { - const user = args.finished ? message.author : await args.pick('userName'); - if (!user.avatar) this.error(LanguageKeys.Commands.Tools.AvatarNone); - - const sizeFlag = args.getOption('size'); - const size = sizeFlag ? this.resolveSize(sizeFlag) : 2048; - - const embed = new EmbedBuilder() // - .setAuthor(getEmbedAuthor(user)) - .setColor(getColor(message)) - .setImage(getDisplayAvatar(user, { size })); - return send(message, { embeds: [embed] }); - } - - private resolveSize(parameter: string): ImageSize { - const raw = Number(parameter); - if (Number.isNaN(raw) || !isValidImageSize(raw)) return 2048; - return raw; // narrowed by type guard - } -} diff --git a/src/commands/Tools/vote.ts b/src/commands/Tools/vote.ts deleted file mode 100644 index 6672ed4ba..000000000 --- a/src/commands/Tools/vote.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { WolfCommand } from '#lib/structures'; -import { ApplyOptions } from '@sapphire/decorators'; -import { CommandOptionsRunTypeEnum } from '@sapphire/framework'; -import { DiscordAPIError, PermissionFlagsBits, RESTJSONErrorCodes, type Message } from 'discord.js'; - -@ApplyOptions({ - description: LanguageKeys.Commands.Tools.VoteDescription, - detailedDescription: LanguageKeys.Commands.Tools.VoteExtended, - requiredClientPermissions: [PermissionFlagsBits.AddReactions, PermissionFlagsBits.ReadMessageHistory], - runIn: [CommandOptionsRunTypeEnum.GuildAny] -}) -export class UserCommand extends WolfCommand { - public override async messageRun(message: Message, args: WolfCommand.Args) { - if (args.finished) this.error(LanguageKeys.Commands.Tools.VoteContentNeeded); - - for (const reaction of ['👍', '👎', '🤷']) { - if (!message.reactions.cache.has(reaction)) await this.react(message, reaction); - } - - return message; - } - - private async react(message: Message, reaction: string) { - try { - await message.react(reaction); - } catch (error) { - if (error instanceof DiscordAPIError && error.code === RESTJSONErrorCodes.ReactionWasBlocked) { - this.error(LanguageKeys.Commands.Tools.VoteReactionBlocked); - } - throw error; - } - } -} diff --git a/src/commands/Tools/whois.ts b/src/commands/Tools/whois.ts deleted file mode 100644 index 8f5743163..000000000 --- a/src/commands/Tools/whois.ts +++ /dev/null @@ -1,254 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { getSupportedUserLanguageT } from '#lib/i18n/translate'; -import { WolfCommand } from '#lib/structures'; -import type { GuildMessage } from '#lib/types'; -import { PermissionsBits } from '#utils/bits'; -import { desc, maybeParseDate, months, seconds } from '#utils/common'; -import { Colors, EmojiData, Emojis } from '#utils/constants'; -import { addAutomaticFields } from '#utils/functions'; -import { getDisplayAvatar, getTag } from '#utils/util'; -import { ActionRowBuilder, ButtonBuilder, EmbedBuilder, TimestampStyles, time } from '@discordjs/builders'; -import { ApplyOptions } from '@sapphire/decorators'; -import { ApplicationCommandRegistry, CommandOptionsRunTypeEnum } from '@sapphire/framework'; -import { map } from '@sapphire/iterator-utilities/map'; -import { send } from '@sapphire/plugin-editable-commands'; -import { applyLocalizedBuilder, applyNameLocalizedBuilder, type TFunction } from '@sapphire/plugin-i18next'; -import { isNullishOrEmpty, isNullishOrZero } from '@sapphire/utilities'; -import { - ApplicationCommandType, - ButtonStyle, - ChatInputCommandInteraction, - GuildMember, - InteractionContextType, - MessageFlags, - PermissionFlagsBits, - UserContextMenuCommandInteraction, - bold, - chatInputApplicationCommandMention, - inlineCode, - roleMention, - type APIInteractionDataResolvedGuildMember, - type APIInteractionGuildMember, - type Role, - type Snowflake, - type User -} from 'discord.js'; - -const sortRanks = (x: Role, y: Role) => desc(x.position, y.position); - -const Root = LanguageKeys.Commands.Whois; - -type IncomingGuildMember = GuildMember | RawIncomingGuildMember; -type RawIncomingGuildMember = APIInteractionGuildMember | APIInteractionDataResolvedGuildMember; - -@ApplyOptions({ - aliases: ['userinfo', 'uinfo', 'user'], - description: Root.Description, - detailedDescription: LanguageKeys.Commands.Tools.WhoisExtended, - requiredClientPermissions: [PermissionFlagsBits.EmbedLinks], - runIn: [CommandOptionsRunTypeEnum.GuildAny] -}) -export class UserCommand extends WolfCommand { - private readonly KeyPermissions = PermissionsBits.resolve([ - PermissionFlagsBits.BanMembers, - PermissionFlagsBits.KickMembers, - PermissionFlagsBits.ManageChannels, - PermissionFlagsBits.ManageGuildExpressions, - PermissionFlagsBits.ManageGuild, - PermissionFlagsBits.ManageMessages, - PermissionFlagsBits.ManageNicknames, - PermissionFlagsBits.ManageRoles, - PermissionFlagsBits.ManageWebhooks, - PermissionFlagsBits.MentionEveryone - ]); - - public override async messageRun(message: GuildMessage, args: WolfCommand.Args) { - const user = args.finished ? message.author : await args.pick('userName'); - const member = await message.guild.members.fetch(user.id).catch(() => null); - - return send(message, { - ...this.sharedRun(args.t, user, member), - content: args.t(LanguageKeys.Commands.Shared.DeprecatedMessage, { - command: chatInputApplicationCommandMention(this.name, this.getGlobalCommandId()) - }) - }); - } - - public override async chatInputRun(interaction: ChatInputCommandInteraction) { - const user = interaction.options.getUser('user', true); - const member = interaction.options.getMember('user'); - - return interaction.reply({ - ...this.sharedRun(getSupportedUserLanguageT(interaction), user, member), - flags: MessageFlags.Ephemeral - }); - } - - public override async contextMenuRun(interaction: UserContextMenuCommandInteraction) { - const user = interaction.targetUser; - const member = interaction.targetMember; - - return interaction.reply({ - ...this.sharedRun(getSupportedUserLanguageT(interaction), user, member), - flags: MessageFlags.Ephemeral - }); - } - - public override registerApplicationCommands(registry: ApplicationCommandRegistry) { - registry.registerChatInputCommand( - (builder) => - applyLocalizedBuilder(builder, Root.Name, Root.Description) // - .addUserOption((option) => applyLocalizedBuilder(option, Root.User).setRequired(true)) // - .setContexts(InteractionContextType.Guild), - { - idHints: [ - '1277288918756233298' // wolfstar-prod production - ] - } - ); - - registry.registerContextMenuCommand( - (builder) => - applyNameLocalizedBuilder(builder, Root.ContextMenuName) // - .setType(ApplicationCommandType.User) // - .setContexts(InteractionContextType.Guild), - { - idHints: [ - '1239990702570733608' // wolfstar-prod production - ] - } - ); - } - - private sharedRun(t: TFunction, user: User, member: IncomingGuildMember | null) { - const embed = member ? this.member(t, member, user) : this.user(t, user); - return { embeds: [embed], components: [this.getComponentRow(t, user)] }; - } - - private user(t: TFunction, user: User) { - return new EmbedBuilder() - .setColor(Colors.White) - .setThumbnail(getDisplayAvatar(user, { size: 256 })) - .setDescription(this.getUserInformation(t, user)); - } - - private member(t: TFunction, member: IncomingGuildMember, user: User) { - const isCached = member instanceof GuildMember; - const displayColor = isCached ? member.displayColor || Colors.White : Colors.White; - const embed = new EmbedBuilder() - .setColor(displayColor) - .setThumbnail(getDisplayAvatar(user, { size: 256 })) - .setDescription(this.getMemberInformation(t, member, user)); - - this.applyMemberRoles(t, isCached ? this.getGuildMemberRoles(member) : this.getRawMemberRoles(member), embed); - this.applyMemberKeyPermissions(t, member, embed); - return embed; - } - - private getUserInformation(t: TFunction, user: User, extras = ''): string { - const bot = user.bot ? ` ${Emojis.IntegrationIcon}` : ''; - const header = `${user.toString()} - ${bold(getTag(user))}${bot}${extras} (${inlineCode(user.id)})`; - const description = t(Root.EmbedDescription, { - id: user.id, - createdAt: time(seconds.fromMilliseconds(user.createdTimestamp), TimestampStyles.RelativeTime) - }); - return `${header}\n\n${description}`; - } - - private getMemberInformation(t: TFunction, member: IncomingGuildMember, user: User): string { - const isCached = member instanceof GuildMember; - const premiumSince = isCached ? member.premiumSinceTimestamp : maybeParseDate(member.premium_since); - const joinedAt = isCached ? member.joinedTimestamp : maybeParseDate(member.joined_at); - - const header = this.getUserInformation(t, user, this.getBoostIcon(premiumSince)); - const description = t(Root.EmbedMemberDescription, { - joinedAt: time(seconds.fromMilliseconds(joinedAt!), TimestampStyles.RelativeTime) - }); - return `${header}\n${description}`; - } - - private applyMemberRoles(t: TFunction, roles: string[] | null, embed: EmbedBuilder) { - if (isNullishOrEmpty(roles)) return; - - addAutomaticFields(embed, t(Root.RolesTitle, { count: roles.length }), roles.join(' ')); - } - - private getGuildMemberRoles(member: GuildMember) { - const roles = member.roles.cache; - // If the member has @everyone or no roles, return null: - if (roles.size <= 1) return null; - - const sorted = roles.sorted(sortRanks); - sorted.delete(member.guild.id); - return sorted.map((role) => role.toString()); - } - - private getRawMemberRoles(member: RawIncomingGuildMember) { - // We cannot sort the roles because we do not have the guild, so we just map them: - return member.roles.map((id) => roleMention(id)); - } - - private applyMemberKeyPermissions(t: TFunction, member: IncomingGuildMember, embed: EmbedBuilder) { - const bitfield = this.getMemberPermissions(member); - - // If the member has Administrator, add a field indicating the member - // has all permissions and return: - if (PermissionsBits.has(bitfield, PermissionFlagsBits.Administrator)) { - embed.addFields({ name: t(Root.PermissionsTitle), value: t(Root.PermissionsAll) }); - return; - } - - // Create an intersection between the permissions the member has and the - // key permissions, if there are no permissions, return, else add a field - // with the permissions: - const intersection = PermissionsBits.intersection(bitfield, this.KeyPermissions); - if (intersection === 0n) return; - - embed.addFields({ - name: t(Root.PermissionsTitle), - value: [...map(PermissionsBits.toKeys(intersection), (name) => t(`permissions:${name}`))].join(', ') - }); - } - - private getMemberPermissions(member: IncomingGuildMember): bigint { - const { permissions } = member; - return typeof permissions === 'string' ? BigInt(permissions) : permissions.bitfield; - } - - private getBoostIcon(boostingSince: number | null): string { - return isNullishOrZero(boostingSince) ? '' : ` ${this.getBoostEmoji(Date.now() - boostingSince)}`; - } - - private getBoostEmoji(duration: number): string { - if (duration >= months(24)) return Emojis.BoostLevel9; - if (duration >= months(18)) return Emojis.BoostLevel8; - if (duration >= months(15)) return Emojis.BoostLevel7; - if (duration >= months(12)) return Emojis.BoostLevel6; - if (duration >= months(9)) return Emojis.BoostLevel5; - if (duration >= months(6)) return Emojis.BoostLevel4; - if (duration >= months(3)) return Emojis.BoostLevel3; - if (duration >= months(2)) return Emojis.BoostLevel2; - return Emojis.BoostLevel1; - } - - private getComponentRow(t: TFunction, user: User) { - return new ActionRowBuilder() // - .addComponents(this.getAvatarButton(t, getDisplayAvatar(user, { size: 4096 })), this.getProfileLinkButton(t, user.id)); - } - - private getAvatarButton(t: TFunction, url: string) { - return new ButtonBuilder() // - .setStyle(ButtonStyle.Link) - .setEmoji(EmojiData.MessageAttachmentIcon) - .setLabel(t(Root.ButtonAvatar)) - .setURL(url); - } - - private getProfileLinkButton(t: TFunction, id: Snowflake) { - return new ButtonBuilder() // - .setStyle(ButtonStyle.Link) - .setEmoji(EmojiData.MembersIcon) - .setLabel(t(Root.ButtonProfile)) - .setURL(`discord://-/users/${id}`); - } -} diff --git a/src/commands/Twitch/twitchsubscription.ts b/src/commands/Twitch/twitchsubscription.ts deleted file mode 100644 index 951444b25..000000000 --- a/src/commands/Twitch/twitchsubscription.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { WolfCommand, WolfSubcommand } from '#lib/structures'; -import { PermissionLevels, type GuildMessage } from '#lib/types'; -import { ButtonWolfStarV7, makeRemovedMessage, makeRow } from '#utils/deprecate'; -import { ApplyOptions, RequiresClientPermissions } from '@sapphire/decorators'; -import { CommandOptionsRunTypeEnum } from '@sapphire/framework'; -import { send } from '@sapphire/plugin-editable-commands'; -import { PermissionFlagsBits } from 'discord.js'; - -const row = makeRow(ButtonWolfStarV7); - -@ApplyOptions({ - aliases: ['twitch-subscription', 't-subscription', 't-sub'], - description: LanguageKeys.Commands.General.V7Description, - detailedDescription: LanguageKeys.Commands.General.V7Extended, - permissionLevel: PermissionLevels.Administrator, - requiredClientPermissions: [PermissionFlagsBits.EmbedLinks], - runIn: [CommandOptionsRunTypeEnum.GuildAny], - subcommands: [ - { name: 'add', messageRun: 'add' }, - { name: 'remove', messageRun: 'remove' }, - { name: 'reset', messageRun: 'reset' }, - { name: 'show', messageRun: 'show', default: true } - ] -}) -export class UserCommand extends WolfSubcommand { - public async add(message: GuildMessage, args: WolfSubcommand.Args) { - return send(message, makeRemovedMessage(args.commandContext.commandName, row)); - } - - public async remove(message: GuildMessage, args: WolfCommand.Args) { - return send(message, makeRemovedMessage(args.commandContext.commandName, row)); - } - - public async reset(message: GuildMessage, args: WolfCommand.Args) { - return send(message, makeRemovedMessage(args.commandContext.commandName, row)); - } - - @RequiresClientPermissions(PermissionFlagsBits.EmbedLinks) - public async show(message: GuildMessage, args: WolfCommand.Args) { - return send(message, makeRemovedMessage(args.commandContext.commandName, row)); - } -} diff --git a/src/config.ts b/src/config.ts deleted file mode 100644 index fd8b48b88..000000000 --- a/src/config.ts +++ /dev/null @@ -1,262 +0,0 @@ -import { transformOauthGuildsAndUser } from '#lib/api/utils'; -import { readSettings } from '#lib/database/settings'; -import { CATEGORIES as TRIVIA_CATEGORIES } from '#lib/games/TriviaManager'; -import { getHandler } from '#root/languages/index'; -import { minutes, seconds } from '#utils/common'; -import { Emojis, LanguageFormatters, rootFolder } from '#utils/constants'; -import type { ConnectionOptions } from '@influxdata/influxdb-client'; -import { LogLevel } from '@sapphire/framework'; -import type { ServerOptions, ServerOptionsAuth } from '@sapphire/plugin-api'; -import { i18next, type I18nextFormatter, type InternationalizationOptions } from '@sapphire/plugin-i18next'; -import { envIsDefined, envParseArray, envParseBoolean, envParseInteger, envParseString, setup } from '@skyra/env-utilities'; -import { - ActivityType, - GatewayIntentBits, - GuildDefaultMessageNotifications, - GuildExplicitContentFilter, - GuildVerificationLevel, - type Locale, - Options, - Partials, - PermissionFlagsBits, - TimestampStyles, - time, - type ActivitiesOptions, - type ClientOptions, - type OAuth2Scopes, - type WebhookClientData -} from 'discord.js'; -import type { InterpolationOptions } from 'i18next'; -import { join } from 'node:path'; - -// Read config: -setup(join(rootFolder, 'src', '.env')); - -export const OWNERS = envParseArray('CLIENT_OWNERS'); - -export function parseAnalytics(): ConnectionOptions { - const url = envParseString('INFLUX_URL'); - const token = envParseString('INFLUX_TOKEN'); - - if (envIsDefined('INFLUX_PROXY_URL')) { - const proxyUrl = envParseString('INFLUX_PROXY_URL'); - return { proxyUrl, url, token }; - } - - return { url, token }; -} - -function parseApiAuth(): ServerOptionsAuth | undefined { - if (!envIsDefined('OAUTH_SECRET')) return undefined; - - return { - id: envParseString('CLIENT_ID'), - secret: envParseString('OAUTH_SECRET'), - cookie: envParseString('OAUTH_COOKIE'), - redirect: envParseString('OAUTH_REDIRECT_URI'), - scopes: envParseArray('OAUTH_SCOPE') as OAuth2Scopes[], - transformers: [transformOauthGuildsAndUser], - domainOverwrite: envParseString('OAUTH_DOMAIN_OVERWRITE') - }; -} - -function parseApi(): ServerOptions | undefined { - if (!envParseBoolean('API_ENABLED', false)) return undefined; - - return { - auth: parseApiAuth(), - prefix: envParseString('API_PREFIX', '/'), - origin: envParseString('API_ORIGIN'), - listenOptions: { port: envParseInteger('API_PORT'), host: envParseString('API_HOST', 'localhost') } - }; -} - -function parsePresenceActivity(): ActivitiesOptions[] { - const { CLIENT_PRESENCE_NAME } = process.env; - if (!CLIENT_PRESENCE_NAME) return []; - - return [ - { - name: CLIENT_PRESENCE_NAME, - type: ActivityType[envParseString('CLIENT_PRESENCE_TYPE', 'Listening') as keyof typeof ActivityType] - } - ]; -} - -function parseRegExpPrefix(): RegExp | undefined { - const { CLIENT_REGEX_PREFIX } = process.env; - return CLIENT_REGEX_PREFIX ? new RegExp(CLIENT_REGEX_PREFIX, 'i') : undefined; -} - -export const PROJECT_ROOT = join(rootFolder, process.env.OVERRIDE_ROOT_PATH ?? 'dist'); -export const LANGUAGE_ROOT = join(PROJECT_ROOT, 'languages'); - -function parseInternationalizationDefaultVariablesPermissions() { - const keys = Object.keys(PermissionFlagsBits) as readonly (keyof typeof PermissionFlagsBits)[]; - const entries = keys.map((key) => [key, key] as const); - - return Object.fromEntries(entries) as Readonly>; -} - -function parseInternationalizationDefaultVariables() { - return { - TRIVIA_CATEGORIES: Object.keys(TRIVIA_CATEGORIES ?? {}).join(', '), - VERSION: process.env.CLIENT_VERSION, - LOADING: Emojis.Loading, - GREENTICK: Emojis.GreenTick, - REDCROSS: Emojis.RedCross, - DEFAULT_PREFIX: process.env.CLIENT_PREFIX, - CLIENT_ID: process.env.CLIENT_ID, - ...parseInternationalizationDefaultVariablesPermissions() - }; -} - -function parseInternationalizationInterpolation(): InterpolationOptions { - return { escapeValue: false, defaultVariables: parseInternationalizationDefaultVariables() }; -} - -function parseInternationalizationFormatters(): I18nextFormatter[] { - const { t } = i18next; - - return [ - // Add custom formatters: - { - name: LanguageFormatters.Number, - format: (lng, options) => { - const formatter = new Intl.NumberFormat(lng, { maximumFractionDigits: 2, ...options }); - return (value) => formatter.format(value); - }, - cached: true - }, - { - name: LanguageFormatters.NumberCompact, - format: (lng, options) => { - const formatter = new Intl.NumberFormat(lng, { notation: 'compact', compactDisplay: 'short', maximumFractionDigits: 2, ...options }); - return (value) => formatter.format(value); - }, - cached: true - }, - { - name: LanguageFormatters.Duration, - format: (lng, options) => { - const formatter = getHandler((lng ?? 'en-US') as Locale).duration; - const precision = (options?.precision as number) ?? 2; - return (value) => formatter.format(value, precision); - }, - cached: true - }, - { - name: LanguageFormatters.HumanDateTime, - format: (lng, options) => { - const formatter = new Intl.DateTimeFormat(lng, { timeZone: 'Etc/UTC', dateStyle: 'short', timeStyle: 'medium', ...options }); - return (value) => formatter.format(value); - }, - cached: true - }, - // Add Discord markdown formatters: - { name: LanguageFormatters.DateTime, format: (value) => time(new Date(value), TimestampStyles.ShortDateTime) }, - // Add alias formatters: - { - name: LanguageFormatters.Permissions, - format: (value, lng, options) => t(`permissions:${value}`, { lng, ...options }) as string - }, - { - name: LanguageFormatters.HumanLevels, - format: (value, lng, options) => t(`humanLevels:${GuildVerificationLevel[value]}`, { lng, ...options }) as string - }, - { - name: LanguageFormatters.ExplicitContentFilter, - format: (value, lng, options) => t(`guilds:explicitContentFilter${GuildExplicitContentFilter[value]}`, { lng, ...options }) as string - }, - { - name: LanguageFormatters.MessageNotifications, - format: (value, lng, options) => - t(`guilds:defaultMessageNotifications${GuildDefaultMessageNotifications[value]}`, { lng, ...options }) as string - } - ]; -} - -function parseInternationalizationOptions(): InternationalizationOptions { - return { - defaultMissingKey: 'default', - defaultNS: 'globals', - defaultLanguageDirectory: LANGUAGE_ROOT, - fetchLanguage: async ({ guild }) => { - if (!guild) return 'en-US'; - return (await readSettings(guild)).language; - }, - formatters: parseInternationalizationFormatters(), - i18next: (_: string[], languages: string[]) => ({ - supportedLngs: languages, - preload: languages, - returnObjects: true, - returnEmptyString: false, - returnNull: false, - load: 'all', - lng: 'en-US', - fallbackLng: { - 'es-419': ['es-ES', 'en-US'], // Latin America Spanish falls back to Spain Spanish - default: ['en-US'] - }, - defaultNS: 'globals', - overloadTranslationOptionHandler: (args) => ({ defaultValue: args[1] ?? 'globals:default' }), - initImmediate: false, - interpolation: parseInternationalizationInterpolation() - }) - }; -} - -export const CLIENT_OPTIONS: ClientOptions = { - allowedMentions: { users: [], roles: [] }, - api: parseApi(), - caseInsensitiveCommands: true, - caseInsensitivePrefixes: true, - defaultPrefix: envParseString('CLIENT_PREFIX'), - intents: [ - GatewayIntentBits.Guilds, - GatewayIntentBits.GuildMembers, - GatewayIntentBits.GuildModeration, - GatewayIntentBits.GuildExpressions, - GatewayIntentBits.GuildVoiceStates, - GatewayIntentBits.GuildMessages, - GatewayIntentBits.GuildMessageReactions, - GatewayIntentBits.DirectMessages, - GatewayIntentBits.DirectMessageReactions, - GatewayIntentBits.MessageContent - ], - enforceNonce: true, - loadDefaultErrorListeners: false, - loadMessageCommandListeners: true, - makeCache: Options.cacheEverything(), - sweepers: { - ...Options.DefaultSweeperSettings, - messages: { - interval: minutes.toSeconds(3), - lifetime: minutes.toSeconds(15) - } - }, - partials: [Partials.Channel], - presence: { activities: parsePresenceActivity() }, - regexPrefix: parseRegExpPrefix(), - schedule: { interval: seconds(5) }, - nms: { - everyone: 5, - role: 2 - }, - logger: { - level: envParseString('NODE_ENV') === 'production' ? LogLevel.Info : LogLevel.Debug - }, - i18n: parseInternationalizationOptions() -}; - -function parseWebhookError(): WebhookClientData | null { - const { WEBHOOK_ERROR_TOKEN } = process.env; - if (!WEBHOOK_ERROR_TOKEN) return null; - - return { - id: envParseString('WEBHOOK_ERROR_ID'), - token: WEBHOOK_ERROR_TOKEN - }; -} - -export const WEBHOOK_ERROR = parseWebhookError(); diff --git a/src/index.ts b/src/index.ts deleted file mode 100644 index 8d2c58cac..000000000 --- a/src/index.ts +++ /dev/null @@ -1,35 +0,0 @@ -import '#lib/setup'; - -import { WolfClient } from '#lib/WolfClient'; -import { rootFolder } from '#utils/constants'; -import { container } from '@sapphire/framework'; -import * as Sentry from '@sentry/node'; -import { envIsDefined, envParseString } from '@skyra/env-utilities'; - -const client = new WolfClient(); - -// Load in Sentry for error logging -if (envIsDefined('SENTRY_URL')) { - Sentry.init({ - dsn: envParseString('SENTRY_URL'), - integrations: [ - Sentry.consoleIntegration(), - Sentry.functionToStringIntegration(), - Sentry.linkedErrorsIntegration(), - Sentry.onUncaughtExceptionIntegration(), - Sentry.onUnhandledRejectionIntegration(), - Sentry.httpIntegration({ breadcrumbs: true }), - Sentry.prismaIntegration(), - Sentry.rewriteFramesIntegration({ root: rootFolder }) - ] - }); -} - -try { - // Login to the Discord gateway - await client.login(); -} catch (error) { - container.logger.error(error); - await client.destroy(); - process.exit(1); -} diff --git a/src/languages/bg/arguments.json b/src/languages/bg/arguments.json deleted file mode 100644 index a7befa6f3..000000000 --- a/src/languages/bg/arguments.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "boolean_one": "", - "boolean_other": "", - "booleanError": "", - "booleanDisabled": "", - "booleanEnabled": "", - "booleanFalseOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "booleanTrueOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "caseNoEntries": "", - "caseUnknownEntry": "", - "caseNotInThisGuild": "", - "caseLatestOptions": [ - "", - "" - ], - "categoryChannelError": "", - "channelError": "", - "command": "", - "commandMatch": "", - "dateError": "", - "dateFormats": "", - "dateTooEarly": "", - "dateTooFar": "", - "dmChannelError": "", - "duration": "", - "durationFormats": "", - "emojiError": "", - "floatError": "", - "floatTooLarge": "", - "floatTooSmall": "", - "guildChannelError": "", - "guildChannelMismatchingError": "", - "guildChannelMissingGuildError": "", - "guildPrivateThreadChannelError": "", - "guildPublicThreadChannelError": "", - "guildStageVoiceChannelError": "", - "guildTextChannelError": "", - "guildThreadChannelError": "", - "guildVoiceChannelError": "", - "hyperlinkError": "", - "integerError": "", - "integerTooLarge": "", - "integerTooSmall": "", - "invite": "", - "language": "", - "memberError": "", - "memberMissingGuild": "", - "messageError": "", - "missing": "", - "newsChannel": "", - "numberError": "", - "numberTooLarge": "", - "numberTooSmall": "", - "piece": "", - "rangeInvalid": "", - "rangeMax_other": "", - "rangeMax_one": "", - "resetPossibles": [ - "", - "" - ], - "roleError": "", - "roleMissingGuild": "", - "snowflake": "", - "store": "", - "stringTooLong": "", - "stringTooShort": "", - "time": "", - "timeSpan": "", - "timeSpanTooBig": "", - "timeSpanTooSmall": "", - "tooFewWinners": "", - "tooManyWinners": "", - "unavailable": "", - "userError": "", - "enumEmptyError": "", - "enumError": "" -} \ No newline at end of file diff --git a/src/languages/bg/assertions.json b/src/languages/bg/assertions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/bg/assertions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/bg/commands/admin.json b/src/languages/bg/commands/admin.json deleted file mode 100644 index 444f39c28..000000000 --- a/src/languages/bg/commands/admin.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "confUpdated": "", - "confGetNoExt": "", - "confGet": "", - "confReset": "", - "confNochange": "", - "confServerDescription": "", - "confServerExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "confServer": "", - "confDashboardOnlyKey": "", - "confSettingNotSet": "", - "rolesetDescription": "", - "rolesetExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesetCreated": "", - "rolesetAdded": "", - "rolesetRemoved": "", - "rolesetResetEmpty": "", - "rolesetResetAll": "", - "rolesetResetNotExists": "", - "rolesetResetGroup": "", - "rolesetUpdated": "", - "rolesetNoRolesets": "", - "confMenuRenderAtFolder": "", - "confMenuRenderAtPiece": "", - "confMenuRenderNokeys": "", - "confMenuRenderSelect": "", - "confMenuRenderUpdate": "", - "confMenuRenderRemove": "", - "confMenuRenderReset": "", - "confMenuRenderUndo": "", - "confMenuRenderCvalue": "", - "confMenuRenderBack": "", - "confMenuInvalidKey": "", - "confMenuInvalidAction": "", - "confMenuSaved": "" -} \ No newline at end of file diff --git a/src/languages/bg/commands/animal.json b/src/languages/bg/commands/animal.json deleted file mode 100644 index 6d00e57af..000000000 --- a/src/languages/bg/commands/animal.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "bunnyDescription": "", - "bunnyExtended": { - "extendedHelp": "" - }, - "bunnyEmbedData": { - "title": "", - "source": "" - }, - "dogDescription": "", - "dogExtended": { - "extendedHelp": "" - }, - "foxDescription": "", - "foxExtended": { - "extendedHelp": "" - }, - "kittyDescription": "", - "kittyExtended": { - "extendedHelp": "" - }, - "shibeDescription": "", - "shibeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/bg/commands/auto-moderation.json b/src/languages/bg/commands/auto-moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/bg/commands/auto-moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/bg/commands/case.json b/src/languages/bg/commands/case.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/bg/commands/case.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/bg/commands/fun.json b/src/languages/bg/commands/fun.json deleted file mode 100644 index 7892e327d..000000000 --- a/src/languages/bg/commands/fun.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "escaperopeDescription": "", - "escaperopeExtended": { - "extendedHelp": "" - }, - "escaperopeOutput": "" -} \ No newline at end of file diff --git a/src/languages/bg/commands/game.json b/src/languages/bg/commands/game.json deleted file mode 100644 index 8075ca93c..000000000 --- a/src/languages/bg/commands/game.json +++ /dev/null @@ -1,447 +0,0 @@ -{ - "c4Description": "", - "c4Extended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "c4Prompt": "", - "gamesBot": "", - "gamesNoPlayers": "", - "gamesProgress": "", - "gamesPromptDeny": "", - "gamesRepeat": "", - "gamesSelf": "", - "gamesTooManyOrFew": "", - "hgBloodbath": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgDay": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgNight": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hungerGamesDescription": "", - "hungerGamesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "examples": [ - "" - ], - "reminder": "" - }, - "hungerGamesResultDeaths_one": "", - "hungerGamesResultDeaths_other": "", - "hungerGamesResultHeaderBloodbath": "", - "hungerGamesResultHeaderMoon": "", - "hungerGamesResultHeaderSun": "", - "hungerGamesResultProceed": "", - "hungerGamesStop": "", - "hungerGamesWinner": "", - "ticTacToeDescription": "", - "ticTacToeDraw": "", - "ticTacToeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "ticTacToePrompt": "", - "ticTacToeTurn": "", - "ticTacToeWinner": "", - "triviaActiveGame": "", - "triviaDescription": "", - "triviaEmbedTitles": { - "difficulty": "", - "trivia": "" - }, - "triviaExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "triviaIncorrect": "", - "triviaInvalidCategory": "", - "triviaNoAnswer": "", - "triviaWinner": "" -} \ No newline at end of file diff --git a/src/languages/bg/commands/general.json b/src/languages/bg/commands/general.json deleted file mode 100644 index 5e16f992d..000000000 --- a/src/languages/bg/commands/general.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "helpAllFlag": "", - "helpCommandCount_one": "", - "helpCommandCount_other": "", - "helpData": { - "footer": "", - "title": "" - }, - "helpDescription": "", - "helpExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "reminder": "", - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "helpDm": "", - "helpNodm": "", - "v7Description": "", - "v7Extended": { - "extendedHelp": "" - }, - "v7Message": "", - "v7NayreMessage": "" -} \ No newline at end of file diff --git a/src/languages/bg/commands/info.json b/src/languages/bg/commands/info.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/bg/commands/info.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/bg/commands/management.json b/src/languages/bg/commands/management.json deleted file mode 100644 index 21ef26ce2..000000000 --- a/src/languages/bg/commands/management.json +++ /dev/null @@ -1,445 +0,0 @@ -{ - "commandHandlerAborted": "", - "permissionNodesHigher": "", - "permissionNodesCannotAllowEveryone": "", - "permissionNodesInvalidType": "", - "permissionNodesAdd": "", - "permissionNodesNodeNotExists": "", - "permissionNodesCommandNotExists": "", - "permissionNodesRemove": "", - "permissionNodesReset": "", - "permissionNodesShowName": "", - "permissionNodesShowAllow": "", - "permissionNodesShowDeny": "", - "guildInfoTitles": { - "CHANNELS": "", - "MEMBERS": "", - "OTHER": "" - }, - "guildInfoChannels": "", - "guildInfoChannelsAfkChannelText": "", - "guildInfoMembers": "", - "guildInfoOther": "", - "guildInfoBanner": "", - "guildInfoIcon": "", - "guildInfoSplash": "", - "guildInfoDiscoverySplash": "", - "roleInfoTitles": { - "PERMISSIONS": "" - }, - "roleInfoData": "", - "roleInfoAll": "", - "roleInfoNoPermissions": "", - "manageCommandAutoDeleteShowEmpty": "", - "manageCommandAutoDeleteShow": "", - "manageCommandAutoDeleteAdd": "", - "manageCommandAutoDeleteRemove": "", - "manageCommandAutoDeleteRemoveNotset": "", - "manageCommandAutoDeleteReset": "", - "manageCommandChannelShow": "", - "manageCommandChannelShowEmpty": "", - "manageCommandChannelAddAlreadyset": "", - "manageCommandChannelAdd": "", - "manageCommandChannelRemoveNotset": "", - "manageCommandChannelRemove": "", - "manageCommandChannelResetEmpty": "", - "manageCommandChannelReset": "", - "manageReactionRolesShowEmpty": "", - "manageReactionRolesAddChannel": "", - "manageReactionRolesAddPrompt": "", - "manageReactionRolesAddMissing": "", - "manageReactionRolesAdd": "", - "manageReactionRolesRemoveNotExists": "", - "manageReactionRolesRemove": "", - "manageReactionRolesResetEmpty": "", - "manageReactionRolesReset": "", - "configurationEquals": "", - "setIgnoreChannelsSet": "", - "setIgnoreChannelsRemoved": "", - "setImageLogsSet": "", - "setMemberAddLogsSet": "", - "setMemberRemoveLogsSet": "", - "setMessageUpdateLogsSet": "", - "setMessageDeleteLogsSet": "", - "setModLogsSet": "", - "setPrefixSet": "", - "stickyRolesNotExists": "", - "stickyRolesReset": "", - "stickyRolesRemove": "", - "stickyRolesAdd": "", - "stickyRolesShowEmpty": "", - "stickyRolesShowSingle": "", - "createMuteDescription": "", - "createMuteExtended": { - "extendedHelp": "" - }, - "permissionNodesDescription": "", - "permissionNodesExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "managecommandautodeleteDescription": "", - "managecommandautodeleteExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageCommandChannelDescription": "", - "manageCommandChannelExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageReactionRolesDescription": "", - "manageReactionRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "rolesAdded": "", - "rolesAuditlog": "", - "rolesListEmpty": "", - "rolesListTitle": "", - "rolesNotManageable": "", - "rolesNotPublic": "", - "rolesRemoved": "", - "setIgnoreChannelsDescription": "", - "setIgnoreChannelsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setImageLogsDescription": "", - "setImageLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "setMemberAddLogsDescription": "", - "setMemberAddLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMemberRemoveLogsDescription": "", - "setMemberRemoveLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMessageUpdateLogsDescription": "", - "setMessageUpdateLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setMessageDeleteLogsDescription": "", - "setMessageDeleteLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setmodlogsDescription": "", - "setmodlogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setprefixDescription": "", - "setprefixExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "guildInfoDescription": "", - "guildInfoExtended": { - "extendedHelp": "" - }, - "roleInfoDescription": "", - "roleInfoExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "stickyRolesDescription": "", - "stickyRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesDescription": "", - "rolesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/bg/commands/misc.json b/src/languages/bg/commands/misc.json deleted file mode 100644 index 32f64d584..000000000 --- a/src/languages/bg/commands/misc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "snipeEmpty": "", - "snipeTitle": "", - "snipeDescription": "", - "snipeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/bg/commands/moderation.json b/src/languages/bg/commands/moderation.json deleted file mode 100644 index 815d1c788..000000000 --- a/src/languages/bg/commands/moderation.json +++ /dev/null @@ -1,889 +0,0 @@ -{ - "permissions": "", - "permissionsAll": "", - "slowmodeSet": "", - "slowmodeReset": "", - "banNotBannable": "", - "dehoistStarting": "", - "dehoistProgress": "", - "dehoistEmbed": { - "title": "", - "descriptionNoone": "", - "descriptionWithError": "", - "descriptionWithMultipleErrors": "", - "description": "", - "descriptionMultipleMembers": "", - "fieldErrorTitle": "" - }, - "kickNotKickable": "", - "lockdownLock": "", - "lockdownLocking": "", - "lockdownLocked": "", - "lockdownUnlocked": "", - "lockdownOpen": "", - "muteMuted": "", - "muteUserNotMuted": "", - "restrictLowlevel": "", - "pruneAlert_one": "", - "pruneAlert_other": "", - "pruneInvalidPosition": "", - "pruneNoDeletes": "", - "pruneLogHeader": "", - "toggleModerationDmToggledEnabled": "", - "toggleModerationDmToggledDisabled": "", - "moderationOutput_one": "", - "moderationOutput_other": "", - "moderationOutputWithReason_one": "", - "moderationOutputWithReason_other": "", - "moderationFailed_one": "", - "moderationFailed_other": "", - "moderationDmFooter": "", - "moderationDmDescription": "", - "moderationDmDescriptionWithReason": "", - "moderationDmDescriptionWithDuration": "", - "moderationDmDescriptionWithReasonWithDuration": "", - "slowmodeDescription": "", - "slowmodeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "banDescription": "", - "banExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "dehoistDescription": "", - "dehoistExtended": { - "extendedHelp": "", - "reminder": "" - }, - "kickDescription": "", - "kickExtended": { - "usages": [ - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "lockdownDescription": "", - "lockdownExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "muteDescription": "", - "muteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "setNicknameDescription": "", - "setNicknameExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ], - "reminder": "" - }, - "addRoleDescription": "", - "addRoleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "removeroleDescription": "", - "removeroleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "pruneDescription": "", - "pruneExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "permissionsDescription": "", - "permissionsExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ], - "extendedHelp": "" - }, - "restrictAttachmentDescription": "", - "restrictAttachmentExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictEmbedDescription": "", - "restrictEmbedExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictEmojiDescription": "", - "restrictEmojiExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictReactionDescription": "", - "restrictReactionExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictVoiceDescription": "", - "restrictVoiceExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "softBanDescription": "", - "softBanExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "timeoutApplyDescription": "", - "timeoutApplyExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutUndoDescription": "", - "timeoutUndoExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutNotModeratable": "", - "toggleModerationDmDescription": "", - "toggleModerationDmExtended": { - "extendedHelp": "" - }, - "unbanDescription": "", - "unbanExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unmuteDescription": "", - "unmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unrestrictAttachmentDescription": "", - "unrestrictAttachmentExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmbedDescription": "", - "unrestrictEmbedExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmojiDescription": "", - "unrestrictEmojiExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictReactionDescription": "", - "unrestrictReactionExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictVoiceDescription": "", - "unrestrictVoiceExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unwarnDescription": "", - "unwarnExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vmuteDescription": "", - "vmuteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "voiceKickDescription": "", - "voiceKickExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vunmuteDescription": "", - "vunmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "warnDescription": "", - "warnExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/bg/commands/shared.json b/src/languages/bg/commands/shared.json deleted file mode 100644 index ddbb28e7f..000000000 --- a/src/languages/bg/commands/shared.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "deprecatedMessage": "", - "slashOnlyDetailedDescription": { - "extendedHelp": "" - }, - "slashOnlyErrorMessage": "" -} \ No newline at end of file diff --git a/src/languages/bg/commands/system.json b/src/languages/bg/commands/system.json deleted file mode 100644 index e9cfdeec4..000000000 --- a/src/languages/bg/commands/system.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "evalDescription": "", - "evalExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "evalTimeout": "", - "evalError": "", - "dmNotSent": "", - "dmSent": "", - "reboot": "", - "rebootDescription": "", - "rebootExtended": { - "extendedHelp": "", - "reminder": "" - } -} \ No newline at end of file diff --git a/src/languages/bg/commands/tools.json b/src/languages/bg/commands/tools.json deleted file mode 100644 index 01bd03e25..000000000 --- a/src/languages/bg/commands/tools.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "avatarDescription": "", - "avatarExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "" - }, - "avatarNone": "", - "voteDescription": "", - "voteExtended": { - "usages": [ - "" - ], - "examples": [ - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "voteContentNeeded": "", - "voteReactionBlocked": "", - "whoisExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "whoisMemberRoleListAndMore": "" -} \ No newline at end of file diff --git a/src/languages/bg/commands/twitch.json b/src/languages/bg/commands/twitch.json deleted file mode 100644 index 2f12e1b08..000000000 --- a/src/languages/bg/commands/twitch.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "twitchSubscriptionStreamerNotFound": "", - "twitchSubscriptionStatusValues": [ - "", - "" - ], - "twitchSubscriptionInvalidStatus": "", - "twitchSubscriptionAddDuplicated": "", - "twitchSubscriptionAddSuccessOffline": "", - "twitchSubscriptionAddSuccessLive": "", - "twitchSubscriptionAddMessageForOfflineRequired": "", - "twitchSubscriptionRemoveOrResetEmpty": "", - "twitchSubscriptionRemoveStreamerNotSubscribed": "", - "twitchSubscriptionRemoveNotToProvidedChannel": "", - "twitchSubscriptionRemoveStreamerStatusNotMatch": "", - "twitchSubscriptionRemoveSuccessOffline": "", - "twitchSubscriptionRemoveSuccessLive": "", - "twitchSubscriptionResetSuccess_one": "", - "twitchSubscriptionResetSuccess_other": "", - "twitchSubscriptionShowStreamerNotSubscribed": "", - "twitchSubscriptionShowStatus": { - "live": "", - "offline": "" - }, - "twitchSubscriptionShowUnknownUser": "", - "twitchSubscriptionDescription": "", - "twitchSubscriptionExtended": { - "usages": [ - "", - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/bg/commands/whois.json b/src/languages/bg/commands/whois.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/bg/commands/whois.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/bg/errors.json b/src/languages/bg/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/bg/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/bg/events/errors.json b/src/languages/bg/events/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/bg/events/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/bg/events/guilds-logs.json b/src/languages/bg/events/guilds-logs.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/bg/events/guilds-logs.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/bg/events/guilds-members.json b/src/languages/bg/events/guilds-members.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/bg/events/guilds-members.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/bg/events/messages.json b/src/languages/bg/events/messages.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/bg/events/messages.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/bg/events/moderation.json b/src/languages/bg/events/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/bg/events/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/bg/events/noMentionSpam.json b/src/languages/bg/events/noMentionSpam.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/bg/events/noMentionSpam.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/bg/events/reactions.json b/src/languages/bg/events/reactions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/bg/events/reactions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/bg/events/twitch.json b/src/languages/bg/events/twitch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/bg/events/twitch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/bg/fuzzySearch.json b/src/languages/bg/fuzzySearch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/bg/fuzzySearch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/bg/globals.json b/src/languages/bg/globals.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/bg/globals.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/bg/guilds.json b/src/languages/bg/guilds.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/bg/guilds.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/bg/humanLevels.json b/src/languages/bg/humanLevels.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/bg/humanLevels.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/bg/moderation.json b/src/languages/bg/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/bg/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/bg/moderationActions.json b/src/languages/bg/moderationActions.json deleted file mode 100644 index 4c440ae54..000000000 --- a/src/languages/bg/moderationActions.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "actions": { - "addRole": "", - "ban": "", - "kick": "", - "mute": "", - "removeRole": "", - "restrictedAttachment": "", - "restrictedEmbed": "", - "restrictedEmoji": "", - "restrictedReact": "", - "restrictedVoice": "", - "setNickname": "", - "softban": "", - "vkick": "", - "vmute": "", - "warning": "" - }, - "actionCannotManageRoles": "", - "actionRoleNotConfigured": "", - "actionRoleHigherPosition": "", - "actionRoleManaged": "", - "applyNoReason": "", - "applyReason": "", - "requiredMember": "", - "revokeNoReason": "", - "revokeReason": "", - "setNicknameNoReasonRemoved": "", - "setNicknameNoReasonSet": "", - "setNicknameRemoved": "", - "setNicknameSet": "", - "setupMuteExists": "", - "setupTooManyRoles": "", - "sharedRoleSetupAsk": "", - "sharedRoleSetupNoMessage": "", - "sharedRoleSetupExisting": "", - "sharedRoleSetupExistingName": "", - "sharedRoleSetupNew": "", - "softbanNoReason": "", - "softbanReason": "", - "unSoftbanNoReason": "", - "unSoftbanReason": "" -} \ No newline at end of file diff --git a/src/languages/bg/permissions.json b/src/languages/bg/permissions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/bg/permissions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/bg/preconditions.json b/src/languages/bg/preconditions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/bg/preconditions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/bg/selfModeration.json b/src/languages/bg/selfModeration.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/bg/selfModeration.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/bg/serializers.json b/src/languages/bg/serializers.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/bg/serializers.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/bg/settings.json b/src/languages/bg/settings.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/bg/settings.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/bg/system.json b/src/languages/bg/system.json deleted file mode 100644 index 073b9b683..000000000 --- a/src/languages/bg/system.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "discordAbortError": "", - "fetchBansFail": "", - "helpTitles": { - "aliases": "", - "usages": "", - "extendedHelp": "", - "explainedUsage": "", - "possibleFormats": "", - "examples": "", - "reminders": "" - }, - "jumpTo": "", - "loading": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "prefixReminder": "" -} \ No newline at end of file diff --git a/src/languages/cs/arguments.json b/src/languages/cs/arguments.json deleted file mode 100644 index a7befa6f3..000000000 --- a/src/languages/cs/arguments.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "boolean_one": "", - "boolean_other": "", - "booleanError": "", - "booleanDisabled": "", - "booleanEnabled": "", - "booleanFalseOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "booleanTrueOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "caseNoEntries": "", - "caseUnknownEntry": "", - "caseNotInThisGuild": "", - "caseLatestOptions": [ - "", - "" - ], - "categoryChannelError": "", - "channelError": "", - "command": "", - "commandMatch": "", - "dateError": "", - "dateFormats": "", - "dateTooEarly": "", - "dateTooFar": "", - "dmChannelError": "", - "duration": "", - "durationFormats": "", - "emojiError": "", - "floatError": "", - "floatTooLarge": "", - "floatTooSmall": "", - "guildChannelError": "", - "guildChannelMismatchingError": "", - "guildChannelMissingGuildError": "", - "guildPrivateThreadChannelError": "", - "guildPublicThreadChannelError": "", - "guildStageVoiceChannelError": "", - "guildTextChannelError": "", - "guildThreadChannelError": "", - "guildVoiceChannelError": "", - "hyperlinkError": "", - "integerError": "", - "integerTooLarge": "", - "integerTooSmall": "", - "invite": "", - "language": "", - "memberError": "", - "memberMissingGuild": "", - "messageError": "", - "missing": "", - "newsChannel": "", - "numberError": "", - "numberTooLarge": "", - "numberTooSmall": "", - "piece": "", - "rangeInvalid": "", - "rangeMax_other": "", - "rangeMax_one": "", - "resetPossibles": [ - "", - "" - ], - "roleError": "", - "roleMissingGuild": "", - "snowflake": "", - "store": "", - "stringTooLong": "", - "stringTooShort": "", - "time": "", - "timeSpan": "", - "timeSpanTooBig": "", - "timeSpanTooSmall": "", - "tooFewWinners": "", - "tooManyWinners": "", - "unavailable": "", - "userError": "", - "enumEmptyError": "", - "enumError": "" -} \ No newline at end of file diff --git a/src/languages/cs/assertions.json b/src/languages/cs/assertions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/cs/assertions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/cs/commands/admin.json b/src/languages/cs/commands/admin.json deleted file mode 100644 index 444f39c28..000000000 --- a/src/languages/cs/commands/admin.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "confUpdated": "", - "confGetNoExt": "", - "confGet": "", - "confReset": "", - "confNochange": "", - "confServerDescription": "", - "confServerExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "confServer": "", - "confDashboardOnlyKey": "", - "confSettingNotSet": "", - "rolesetDescription": "", - "rolesetExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesetCreated": "", - "rolesetAdded": "", - "rolesetRemoved": "", - "rolesetResetEmpty": "", - "rolesetResetAll": "", - "rolesetResetNotExists": "", - "rolesetResetGroup": "", - "rolesetUpdated": "", - "rolesetNoRolesets": "", - "confMenuRenderAtFolder": "", - "confMenuRenderAtPiece": "", - "confMenuRenderNokeys": "", - "confMenuRenderSelect": "", - "confMenuRenderUpdate": "", - "confMenuRenderRemove": "", - "confMenuRenderReset": "", - "confMenuRenderUndo": "", - "confMenuRenderCvalue": "", - "confMenuRenderBack": "", - "confMenuInvalidKey": "", - "confMenuInvalidAction": "", - "confMenuSaved": "" -} \ No newline at end of file diff --git a/src/languages/cs/commands/animal.json b/src/languages/cs/commands/animal.json deleted file mode 100644 index 6d00e57af..000000000 --- a/src/languages/cs/commands/animal.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "bunnyDescription": "", - "bunnyExtended": { - "extendedHelp": "" - }, - "bunnyEmbedData": { - "title": "", - "source": "" - }, - "dogDescription": "", - "dogExtended": { - "extendedHelp": "" - }, - "foxDescription": "", - "foxExtended": { - "extendedHelp": "" - }, - "kittyDescription": "", - "kittyExtended": { - "extendedHelp": "" - }, - "shibeDescription": "", - "shibeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/cs/commands/auto-moderation.json b/src/languages/cs/commands/auto-moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/cs/commands/auto-moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/cs/commands/case.json b/src/languages/cs/commands/case.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/cs/commands/case.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/cs/commands/fun.json b/src/languages/cs/commands/fun.json deleted file mode 100644 index 7892e327d..000000000 --- a/src/languages/cs/commands/fun.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "escaperopeDescription": "", - "escaperopeExtended": { - "extendedHelp": "" - }, - "escaperopeOutput": "" -} \ No newline at end of file diff --git a/src/languages/cs/commands/game.json b/src/languages/cs/commands/game.json deleted file mode 100644 index 8075ca93c..000000000 --- a/src/languages/cs/commands/game.json +++ /dev/null @@ -1,447 +0,0 @@ -{ - "c4Description": "", - "c4Extended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "c4Prompt": "", - "gamesBot": "", - "gamesNoPlayers": "", - "gamesProgress": "", - "gamesPromptDeny": "", - "gamesRepeat": "", - "gamesSelf": "", - "gamesTooManyOrFew": "", - "hgBloodbath": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgDay": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgNight": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hungerGamesDescription": "", - "hungerGamesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "examples": [ - "" - ], - "reminder": "" - }, - "hungerGamesResultDeaths_one": "", - "hungerGamesResultDeaths_other": "", - "hungerGamesResultHeaderBloodbath": "", - "hungerGamesResultHeaderMoon": "", - "hungerGamesResultHeaderSun": "", - "hungerGamesResultProceed": "", - "hungerGamesStop": "", - "hungerGamesWinner": "", - "ticTacToeDescription": "", - "ticTacToeDraw": "", - "ticTacToeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "ticTacToePrompt": "", - "ticTacToeTurn": "", - "ticTacToeWinner": "", - "triviaActiveGame": "", - "triviaDescription": "", - "triviaEmbedTitles": { - "difficulty": "", - "trivia": "" - }, - "triviaExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "triviaIncorrect": "", - "triviaInvalidCategory": "", - "triviaNoAnswer": "", - "triviaWinner": "" -} \ No newline at end of file diff --git a/src/languages/cs/commands/general.json b/src/languages/cs/commands/general.json deleted file mode 100644 index 5e16f992d..000000000 --- a/src/languages/cs/commands/general.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "helpAllFlag": "", - "helpCommandCount_one": "", - "helpCommandCount_other": "", - "helpData": { - "footer": "", - "title": "" - }, - "helpDescription": "", - "helpExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "reminder": "", - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "helpDm": "", - "helpNodm": "", - "v7Description": "", - "v7Extended": { - "extendedHelp": "" - }, - "v7Message": "", - "v7NayreMessage": "" -} \ No newline at end of file diff --git a/src/languages/cs/commands/info.json b/src/languages/cs/commands/info.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/cs/commands/info.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/cs/commands/management.json b/src/languages/cs/commands/management.json deleted file mode 100644 index 21ef26ce2..000000000 --- a/src/languages/cs/commands/management.json +++ /dev/null @@ -1,445 +0,0 @@ -{ - "commandHandlerAborted": "", - "permissionNodesHigher": "", - "permissionNodesCannotAllowEveryone": "", - "permissionNodesInvalidType": "", - "permissionNodesAdd": "", - "permissionNodesNodeNotExists": "", - "permissionNodesCommandNotExists": "", - "permissionNodesRemove": "", - "permissionNodesReset": "", - "permissionNodesShowName": "", - "permissionNodesShowAllow": "", - "permissionNodesShowDeny": "", - "guildInfoTitles": { - "CHANNELS": "", - "MEMBERS": "", - "OTHER": "" - }, - "guildInfoChannels": "", - "guildInfoChannelsAfkChannelText": "", - "guildInfoMembers": "", - "guildInfoOther": "", - "guildInfoBanner": "", - "guildInfoIcon": "", - "guildInfoSplash": "", - "guildInfoDiscoverySplash": "", - "roleInfoTitles": { - "PERMISSIONS": "" - }, - "roleInfoData": "", - "roleInfoAll": "", - "roleInfoNoPermissions": "", - "manageCommandAutoDeleteShowEmpty": "", - "manageCommandAutoDeleteShow": "", - "manageCommandAutoDeleteAdd": "", - "manageCommandAutoDeleteRemove": "", - "manageCommandAutoDeleteRemoveNotset": "", - "manageCommandAutoDeleteReset": "", - "manageCommandChannelShow": "", - "manageCommandChannelShowEmpty": "", - "manageCommandChannelAddAlreadyset": "", - "manageCommandChannelAdd": "", - "manageCommandChannelRemoveNotset": "", - "manageCommandChannelRemove": "", - "manageCommandChannelResetEmpty": "", - "manageCommandChannelReset": "", - "manageReactionRolesShowEmpty": "", - "manageReactionRolesAddChannel": "", - "manageReactionRolesAddPrompt": "", - "manageReactionRolesAddMissing": "", - "manageReactionRolesAdd": "", - "manageReactionRolesRemoveNotExists": "", - "manageReactionRolesRemove": "", - "manageReactionRolesResetEmpty": "", - "manageReactionRolesReset": "", - "configurationEquals": "", - "setIgnoreChannelsSet": "", - "setIgnoreChannelsRemoved": "", - "setImageLogsSet": "", - "setMemberAddLogsSet": "", - "setMemberRemoveLogsSet": "", - "setMessageUpdateLogsSet": "", - "setMessageDeleteLogsSet": "", - "setModLogsSet": "", - "setPrefixSet": "", - "stickyRolesNotExists": "", - "stickyRolesReset": "", - "stickyRolesRemove": "", - "stickyRolesAdd": "", - "stickyRolesShowEmpty": "", - "stickyRolesShowSingle": "", - "createMuteDescription": "", - "createMuteExtended": { - "extendedHelp": "" - }, - "permissionNodesDescription": "", - "permissionNodesExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "managecommandautodeleteDescription": "", - "managecommandautodeleteExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageCommandChannelDescription": "", - "manageCommandChannelExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageReactionRolesDescription": "", - "manageReactionRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "rolesAdded": "", - "rolesAuditlog": "", - "rolesListEmpty": "", - "rolesListTitle": "", - "rolesNotManageable": "", - "rolesNotPublic": "", - "rolesRemoved": "", - "setIgnoreChannelsDescription": "", - "setIgnoreChannelsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setImageLogsDescription": "", - "setImageLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "setMemberAddLogsDescription": "", - "setMemberAddLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMemberRemoveLogsDescription": "", - "setMemberRemoveLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMessageUpdateLogsDescription": "", - "setMessageUpdateLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setMessageDeleteLogsDescription": "", - "setMessageDeleteLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setmodlogsDescription": "", - "setmodlogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setprefixDescription": "", - "setprefixExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "guildInfoDescription": "", - "guildInfoExtended": { - "extendedHelp": "" - }, - "roleInfoDescription": "", - "roleInfoExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "stickyRolesDescription": "", - "stickyRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesDescription": "", - "rolesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/cs/commands/misc.json b/src/languages/cs/commands/misc.json deleted file mode 100644 index 32f64d584..000000000 --- a/src/languages/cs/commands/misc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "snipeEmpty": "", - "snipeTitle": "", - "snipeDescription": "", - "snipeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/cs/commands/moderation.json b/src/languages/cs/commands/moderation.json deleted file mode 100644 index 815d1c788..000000000 --- a/src/languages/cs/commands/moderation.json +++ /dev/null @@ -1,889 +0,0 @@ -{ - "permissions": "", - "permissionsAll": "", - "slowmodeSet": "", - "slowmodeReset": "", - "banNotBannable": "", - "dehoistStarting": "", - "dehoistProgress": "", - "dehoistEmbed": { - "title": "", - "descriptionNoone": "", - "descriptionWithError": "", - "descriptionWithMultipleErrors": "", - "description": "", - "descriptionMultipleMembers": "", - "fieldErrorTitle": "" - }, - "kickNotKickable": "", - "lockdownLock": "", - "lockdownLocking": "", - "lockdownLocked": "", - "lockdownUnlocked": "", - "lockdownOpen": "", - "muteMuted": "", - "muteUserNotMuted": "", - "restrictLowlevel": "", - "pruneAlert_one": "", - "pruneAlert_other": "", - "pruneInvalidPosition": "", - "pruneNoDeletes": "", - "pruneLogHeader": "", - "toggleModerationDmToggledEnabled": "", - "toggleModerationDmToggledDisabled": "", - "moderationOutput_one": "", - "moderationOutput_other": "", - "moderationOutputWithReason_one": "", - "moderationOutputWithReason_other": "", - "moderationFailed_one": "", - "moderationFailed_other": "", - "moderationDmFooter": "", - "moderationDmDescription": "", - "moderationDmDescriptionWithReason": "", - "moderationDmDescriptionWithDuration": "", - "moderationDmDescriptionWithReasonWithDuration": "", - "slowmodeDescription": "", - "slowmodeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "banDescription": "", - "banExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "dehoistDescription": "", - "dehoistExtended": { - "extendedHelp": "", - "reminder": "" - }, - "kickDescription": "", - "kickExtended": { - "usages": [ - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "lockdownDescription": "", - "lockdownExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "muteDescription": "", - "muteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "setNicknameDescription": "", - "setNicknameExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ], - "reminder": "" - }, - "addRoleDescription": "", - "addRoleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "removeroleDescription": "", - "removeroleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "pruneDescription": "", - "pruneExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "permissionsDescription": "", - "permissionsExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ], - "extendedHelp": "" - }, - "restrictAttachmentDescription": "", - "restrictAttachmentExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictEmbedDescription": "", - "restrictEmbedExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictEmojiDescription": "", - "restrictEmojiExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictReactionDescription": "", - "restrictReactionExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictVoiceDescription": "", - "restrictVoiceExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "softBanDescription": "", - "softBanExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "timeoutApplyDescription": "", - "timeoutApplyExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutUndoDescription": "", - "timeoutUndoExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutNotModeratable": "", - "toggleModerationDmDescription": "", - "toggleModerationDmExtended": { - "extendedHelp": "" - }, - "unbanDescription": "", - "unbanExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unmuteDescription": "", - "unmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unrestrictAttachmentDescription": "", - "unrestrictAttachmentExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmbedDescription": "", - "unrestrictEmbedExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmojiDescription": "", - "unrestrictEmojiExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictReactionDescription": "", - "unrestrictReactionExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictVoiceDescription": "", - "unrestrictVoiceExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unwarnDescription": "", - "unwarnExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vmuteDescription": "", - "vmuteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "voiceKickDescription": "", - "voiceKickExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vunmuteDescription": "", - "vunmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "warnDescription": "", - "warnExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/cs/commands/shared.json b/src/languages/cs/commands/shared.json deleted file mode 100644 index ddbb28e7f..000000000 --- a/src/languages/cs/commands/shared.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "deprecatedMessage": "", - "slashOnlyDetailedDescription": { - "extendedHelp": "" - }, - "slashOnlyErrorMessage": "" -} \ No newline at end of file diff --git a/src/languages/cs/commands/system.json b/src/languages/cs/commands/system.json deleted file mode 100644 index e9cfdeec4..000000000 --- a/src/languages/cs/commands/system.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "evalDescription": "", - "evalExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "evalTimeout": "", - "evalError": "", - "dmNotSent": "", - "dmSent": "", - "reboot": "", - "rebootDescription": "", - "rebootExtended": { - "extendedHelp": "", - "reminder": "" - } -} \ No newline at end of file diff --git a/src/languages/cs/commands/tools.json b/src/languages/cs/commands/tools.json deleted file mode 100644 index 01bd03e25..000000000 --- a/src/languages/cs/commands/tools.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "avatarDescription": "", - "avatarExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "" - }, - "avatarNone": "", - "voteDescription": "", - "voteExtended": { - "usages": [ - "" - ], - "examples": [ - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "voteContentNeeded": "", - "voteReactionBlocked": "", - "whoisExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "whoisMemberRoleListAndMore": "" -} \ No newline at end of file diff --git a/src/languages/cs/commands/twitch.json b/src/languages/cs/commands/twitch.json deleted file mode 100644 index 2f12e1b08..000000000 --- a/src/languages/cs/commands/twitch.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "twitchSubscriptionStreamerNotFound": "", - "twitchSubscriptionStatusValues": [ - "", - "" - ], - "twitchSubscriptionInvalidStatus": "", - "twitchSubscriptionAddDuplicated": "", - "twitchSubscriptionAddSuccessOffline": "", - "twitchSubscriptionAddSuccessLive": "", - "twitchSubscriptionAddMessageForOfflineRequired": "", - "twitchSubscriptionRemoveOrResetEmpty": "", - "twitchSubscriptionRemoveStreamerNotSubscribed": "", - "twitchSubscriptionRemoveNotToProvidedChannel": "", - "twitchSubscriptionRemoveStreamerStatusNotMatch": "", - "twitchSubscriptionRemoveSuccessOffline": "", - "twitchSubscriptionRemoveSuccessLive": "", - "twitchSubscriptionResetSuccess_one": "", - "twitchSubscriptionResetSuccess_other": "", - "twitchSubscriptionShowStreamerNotSubscribed": "", - "twitchSubscriptionShowStatus": { - "live": "", - "offline": "" - }, - "twitchSubscriptionShowUnknownUser": "", - "twitchSubscriptionDescription": "", - "twitchSubscriptionExtended": { - "usages": [ - "", - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/cs/commands/whois.json b/src/languages/cs/commands/whois.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/cs/commands/whois.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/cs/errors.json b/src/languages/cs/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/cs/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/cs/events/errors.json b/src/languages/cs/events/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/cs/events/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/cs/events/guilds-logs.json b/src/languages/cs/events/guilds-logs.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/cs/events/guilds-logs.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/cs/events/guilds-members.json b/src/languages/cs/events/guilds-members.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/cs/events/guilds-members.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/cs/events/messages.json b/src/languages/cs/events/messages.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/cs/events/messages.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/cs/events/moderation.json b/src/languages/cs/events/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/cs/events/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/cs/events/noMentionSpam.json b/src/languages/cs/events/noMentionSpam.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/cs/events/noMentionSpam.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/cs/events/reactions.json b/src/languages/cs/events/reactions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/cs/events/reactions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/cs/events/twitch.json b/src/languages/cs/events/twitch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/cs/events/twitch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/cs/fuzzySearch.json b/src/languages/cs/fuzzySearch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/cs/fuzzySearch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/cs/globals.json b/src/languages/cs/globals.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/cs/globals.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/cs/guilds.json b/src/languages/cs/guilds.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/cs/guilds.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/cs/humanLevels.json b/src/languages/cs/humanLevels.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/cs/humanLevels.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/cs/moderation.json b/src/languages/cs/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/cs/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/cs/moderationActions.json b/src/languages/cs/moderationActions.json deleted file mode 100644 index 4c440ae54..000000000 --- a/src/languages/cs/moderationActions.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "actions": { - "addRole": "", - "ban": "", - "kick": "", - "mute": "", - "removeRole": "", - "restrictedAttachment": "", - "restrictedEmbed": "", - "restrictedEmoji": "", - "restrictedReact": "", - "restrictedVoice": "", - "setNickname": "", - "softban": "", - "vkick": "", - "vmute": "", - "warning": "" - }, - "actionCannotManageRoles": "", - "actionRoleNotConfigured": "", - "actionRoleHigherPosition": "", - "actionRoleManaged": "", - "applyNoReason": "", - "applyReason": "", - "requiredMember": "", - "revokeNoReason": "", - "revokeReason": "", - "setNicknameNoReasonRemoved": "", - "setNicknameNoReasonSet": "", - "setNicknameRemoved": "", - "setNicknameSet": "", - "setupMuteExists": "", - "setupTooManyRoles": "", - "sharedRoleSetupAsk": "", - "sharedRoleSetupNoMessage": "", - "sharedRoleSetupExisting": "", - "sharedRoleSetupExistingName": "", - "sharedRoleSetupNew": "", - "softbanNoReason": "", - "softbanReason": "", - "unSoftbanNoReason": "", - "unSoftbanReason": "" -} \ No newline at end of file diff --git a/src/languages/cs/permissions.json b/src/languages/cs/permissions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/cs/permissions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/cs/preconditions.json b/src/languages/cs/preconditions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/cs/preconditions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/cs/selfModeration.json b/src/languages/cs/selfModeration.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/cs/selfModeration.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/cs/serializers.json b/src/languages/cs/serializers.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/cs/serializers.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/cs/settings.json b/src/languages/cs/settings.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/cs/settings.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/cs/system.json b/src/languages/cs/system.json deleted file mode 100644 index 073b9b683..000000000 --- a/src/languages/cs/system.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "discordAbortError": "", - "fetchBansFail": "", - "helpTitles": { - "aliases": "", - "usages": "", - "extendedHelp": "", - "explainedUsage": "", - "possibleFormats": "", - "examples": "", - "reminders": "" - }, - "jumpTo": "", - "loading": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "prefixReminder": "" -} \ No newline at end of file diff --git a/src/languages/da/arguments.json b/src/languages/da/arguments.json deleted file mode 100644 index a7befa6f3..000000000 --- a/src/languages/da/arguments.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "boolean_one": "", - "boolean_other": "", - "booleanError": "", - "booleanDisabled": "", - "booleanEnabled": "", - "booleanFalseOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "booleanTrueOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "caseNoEntries": "", - "caseUnknownEntry": "", - "caseNotInThisGuild": "", - "caseLatestOptions": [ - "", - "" - ], - "categoryChannelError": "", - "channelError": "", - "command": "", - "commandMatch": "", - "dateError": "", - "dateFormats": "", - "dateTooEarly": "", - "dateTooFar": "", - "dmChannelError": "", - "duration": "", - "durationFormats": "", - "emojiError": "", - "floatError": "", - "floatTooLarge": "", - "floatTooSmall": "", - "guildChannelError": "", - "guildChannelMismatchingError": "", - "guildChannelMissingGuildError": "", - "guildPrivateThreadChannelError": "", - "guildPublicThreadChannelError": "", - "guildStageVoiceChannelError": "", - "guildTextChannelError": "", - "guildThreadChannelError": "", - "guildVoiceChannelError": "", - "hyperlinkError": "", - "integerError": "", - "integerTooLarge": "", - "integerTooSmall": "", - "invite": "", - "language": "", - "memberError": "", - "memberMissingGuild": "", - "messageError": "", - "missing": "", - "newsChannel": "", - "numberError": "", - "numberTooLarge": "", - "numberTooSmall": "", - "piece": "", - "rangeInvalid": "", - "rangeMax_other": "", - "rangeMax_one": "", - "resetPossibles": [ - "", - "" - ], - "roleError": "", - "roleMissingGuild": "", - "snowflake": "", - "store": "", - "stringTooLong": "", - "stringTooShort": "", - "time": "", - "timeSpan": "", - "timeSpanTooBig": "", - "timeSpanTooSmall": "", - "tooFewWinners": "", - "tooManyWinners": "", - "unavailable": "", - "userError": "", - "enumEmptyError": "", - "enumError": "" -} \ No newline at end of file diff --git a/src/languages/da/assertions.json b/src/languages/da/assertions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/da/assertions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/da/commands/admin.json b/src/languages/da/commands/admin.json deleted file mode 100644 index 444f39c28..000000000 --- a/src/languages/da/commands/admin.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "confUpdated": "", - "confGetNoExt": "", - "confGet": "", - "confReset": "", - "confNochange": "", - "confServerDescription": "", - "confServerExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "confServer": "", - "confDashboardOnlyKey": "", - "confSettingNotSet": "", - "rolesetDescription": "", - "rolesetExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesetCreated": "", - "rolesetAdded": "", - "rolesetRemoved": "", - "rolesetResetEmpty": "", - "rolesetResetAll": "", - "rolesetResetNotExists": "", - "rolesetResetGroup": "", - "rolesetUpdated": "", - "rolesetNoRolesets": "", - "confMenuRenderAtFolder": "", - "confMenuRenderAtPiece": "", - "confMenuRenderNokeys": "", - "confMenuRenderSelect": "", - "confMenuRenderUpdate": "", - "confMenuRenderRemove": "", - "confMenuRenderReset": "", - "confMenuRenderUndo": "", - "confMenuRenderCvalue": "", - "confMenuRenderBack": "", - "confMenuInvalidKey": "", - "confMenuInvalidAction": "", - "confMenuSaved": "" -} \ No newline at end of file diff --git a/src/languages/da/commands/animal.json b/src/languages/da/commands/animal.json deleted file mode 100644 index 6d00e57af..000000000 --- a/src/languages/da/commands/animal.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "bunnyDescription": "", - "bunnyExtended": { - "extendedHelp": "" - }, - "bunnyEmbedData": { - "title": "", - "source": "" - }, - "dogDescription": "", - "dogExtended": { - "extendedHelp": "" - }, - "foxDescription": "", - "foxExtended": { - "extendedHelp": "" - }, - "kittyDescription": "", - "kittyExtended": { - "extendedHelp": "" - }, - "shibeDescription": "", - "shibeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/da/commands/auto-moderation.json b/src/languages/da/commands/auto-moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/da/commands/auto-moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/da/commands/case.json b/src/languages/da/commands/case.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/da/commands/case.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/da/commands/fun.json b/src/languages/da/commands/fun.json deleted file mode 100644 index 7892e327d..000000000 --- a/src/languages/da/commands/fun.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "escaperopeDescription": "", - "escaperopeExtended": { - "extendedHelp": "" - }, - "escaperopeOutput": "" -} \ No newline at end of file diff --git a/src/languages/da/commands/game.json b/src/languages/da/commands/game.json deleted file mode 100644 index 8075ca93c..000000000 --- a/src/languages/da/commands/game.json +++ /dev/null @@ -1,447 +0,0 @@ -{ - "c4Description": "", - "c4Extended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "c4Prompt": "", - "gamesBot": "", - "gamesNoPlayers": "", - "gamesProgress": "", - "gamesPromptDeny": "", - "gamesRepeat": "", - "gamesSelf": "", - "gamesTooManyOrFew": "", - "hgBloodbath": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgDay": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgNight": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hungerGamesDescription": "", - "hungerGamesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "examples": [ - "" - ], - "reminder": "" - }, - "hungerGamesResultDeaths_one": "", - "hungerGamesResultDeaths_other": "", - "hungerGamesResultHeaderBloodbath": "", - "hungerGamesResultHeaderMoon": "", - "hungerGamesResultHeaderSun": "", - "hungerGamesResultProceed": "", - "hungerGamesStop": "", - "hungerGamesWinner": "", - "ticTacToeDescription": "", - "ticTacToeDraw": "", - "ticTacToeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "ticTacToePrompt": "", - "ticTacToeTurn": "", - "ticTacToeWinner": "", - "triviaActiveGame": "", - "triviaDescription": "", - "triviaEmbedTitles": { - "difficulty": "", - "trivia": "" - }, - "triviaExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "triviaIncorrect": "", - "triviaInvalidCategory": "", - "triviaNoAnswer": "", - "triviaWinner": "" -} \ No newline at end of file diff --git a/src/languages/da/commands/general.json b/src/languages/da/commands/general.json deleted file mode 100644 index 5e16f992d..000000000 --- a/src/languages/da/commands/general.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "helpAllFlag": "", - "helpCommandCount_one": "", - "helpCommandCount_other": "", - "helpData": { - "footer": "", - "title": "" - }, - "helpDescription": "", - "helpExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "reminder": "", - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "helpDm": "", - "helpNodm": "", - "v7Description": "", - "v7Extended": { - "extendedHelp": "" - }, - "v7Message": "", - "v7NayreMessage": "" -} \ No newline at end of file diff --git a/src/languages/da/commands/info.json b/src/languages/da/commands/info.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/da/commands/info.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/da/commands/management.json b/src/languages/da/commands/management.json deleted file mode 100644 index 21ef26ce2..000000000 --- a/src/languages/da/commands/management.json +++ /dev/null @@ -1,445 +0,0 @@ -{ - "commandHandlerAborted": "", - "permissionNodesHigher": "", - "permissionNodesCannotAllowEveryone": "", - "permissionNodesInvalidType": "", - "permissionNodesAdd": "", - "permissionNodesNodeNotExists": "", - "permissionNodesCommandNotExists": "", - "permissionNodesRemove": "", - "permissionNodesReset": "", - "permissionNodesShowName": "", - "permissionNodesShowAllow": "", - "permissionNodesShowDeny": "", - "guildInfoTitles": { - "CHANNELS": "", - "MEMBERS": "", - "OTHER": "" - }, - "guildInfoChannels": "", - "guildInfoChannelsAfkChannelText": "", - "guildInfoMembers": "", - "guildInfoOther": "", - "guildInfoBanner": "", - "guildInfoIcon": "", - "guildInfoSplash": "", - "guildInfoDiscoverySplash": "", - "roleInfoTitles": { - "PERMISSIONS": "" - }, - "roleInfoData": "", - "roleInfoAll": "", - "roleInfoNoPermissions": "", - "manageCommandAutoDeleteShowEmpty": "", - "manageCommandAutoDeleteShow": "", - "manageCommandAutoDeleteAdd": "", - "manageCommandAutoDeleteRemove": "", - "manageCommandAutoDeleteRemoveNotset": "", - "manageCommandAutoDeleteReset": "", - "manageCommandChannelShow": "", - "manageCommandChannelShowEmpty": "", - "manageCommandChannelAddAlreadyset": "", - "manageCommandChannelAdd": "", - "manageCommandChannelRemoveNotset": "", - "manageCommandChannelRemove": "", - "manageCommandChannelResetEmpty": "", - "manageCommandChannelReset": "", - "manageReactionRolesShowEmpty": "", - "manageReactionRolesAddChannel": "", - "manageReactionRolesAddPrompt": "", - "manageReactionRolesAddMissing": "", - "manageReactionRolesAdd": "", - "manageReactionRolesRemoveNotExists": "", - "manageReactionRolesRemove": "", - "manageReactionRolesResetEmpty": "", - "manageReactionRolesReset": "", - "configurationEquals": "", - "setIgnoreChannelsSet": "", - "setIgnoreChannelsRemoved": "", - "setImageLogsSet": "", - "setMemberAddLogsSet": "", - "setMemberRemoveLogsSet": "", - "setMessageUpdateLogsSet": "", - "setMessageDeleteLogsSet": "", - "setModLogsSet": "", - "setPrefixSet": "", - "stickyRolesNotExists": "", - "stickyRolesReset": "", - "stickyRolesRemove": "", - "stickyRolesAdd": "", - "stickyRolesShowEmpty": "", - "stickyRolesShowSingle": "", - "createMuteDescription": "", - "createMuteExtended": { - "extendedHelp": "" - }, - "permissionNodesDescription": "", - "permissionNodesExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "managecommandautodeleteDescription": "", - "managecommandautodeleteExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageCommandChannelDescription": "", - "manageCommandChannelExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageReactionRolesDescription": "", - "manageReactionRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "rolesAdded": "", - "rolesAuditlog": "", - "rolesListEmpty": "", - "rolesListTitle": "", - "rolesNotManageable": "", - "rolesNotPublic": "", - "rolesRemoved": "", - "setIgnoreChannelsDescription": "", - "setIgnoreChannelsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setImageLogsDescription": "", - "setImageLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "setMemberAddLogsDescription": "", - "setMemberAddLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMemberRemoveLogsDescription": "", - "setMemberRemoveLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMessageUpdateLogsDescription": "", - "setMessageUpdateLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setMessageDeleteLogsDescription": "", - "setMessageDeleteLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setmodlogsDescription": "", - "setmodlogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setprefixDescription": "", - "setprefixExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "guildInfoDescription": "", - "guildInfoExtended": { - "extendedHelp": "" - }, - "roleInfoDescription": "", - "roleInfoExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "stickyRolesDescription": "", - "stickyRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesDescription": "", - "rolesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/da/commands/misc.json b/src/languages/da/commands/misc.json deleted file mode 100644 index 32f64d584..000000000 --- a/src/languages/da/commands/misc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "snipeEmpty": "", - "snipeTitle": "", - "snipeDescription": "", - "snipeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/da/commands/moderation.json b/src/languages/da/commands/moderation.json deleted file mode 100644 index 815d1c788..000000000 --- a/src/languages/da/commands/moderation.json +++ /dev/null @@ -1,889 +0,0 @@ -{ - "permissions": "", - "permissionsAll": "", - "slowmodeSet": "", - "slowmodeReset": "", - "banNotBannable": "", - "dehoistStarting": "", - "dehoistProgress": "", - "dehoistEmbed": { - "title": "", - "descriptionNoone": "", - "descriptionWithError": "", - "descriptionWithMultipleErrors": "", - "description": "", - "descriptionMultipleMembers": "", - "fieldErrorTitle": "" - }, - "kickNotKickable": "", - "lockdownLock": "", - "lockdownLocking": "", - "lockdownLocked": "", - "lockdownUnlocked": "", - "lockdownOpen": "", - "muteMuted": "", - "muteUserNotMuted": "", - "restrictLowlevel": "", - "pruneAlert_one": "", - "pruneAlert_other": "", - "pruneInvalidPosition": "", - "pruneNoDeletes": "", - "pruneLogHeader": "", - "toggleModerationDmToggledEnabled": "", - "toggleModerationDmToggledDisabled": "", - "moderationOutput_one": "", - "moderationOutput_other": "", - "moderationOutputWithReason_one": "", - "moderationOutputWithReason_other": "", - "moderationFailed_one": "", - "moderationFailed_other": "", - "moderationDmFooter": "", - "moderationDmDescription": "", - "moderationDmDescriptionWithReason": "", - "moderationDmDescriptionWithDuration": "", - "moderationDmDescriptionWithReasonWithDuration": "", - "slowmodeDescription": "", - "slowmodeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "banDescription": "", - "banExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "dehoistDescription": "", - "dehoistExtended": { - "extendedHelp": "", - "reminder": "" - }, - "kickDescription": "", - "kickExtended": { - "usages": [ - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "lockdownDescription": "", - "lockdownExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "muteDescription": "", - "muteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "setNicknameDescription": "", - "setNicknameExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ], - "reminder": "" - }, - "addRoleDescription": "", - "addRoleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "removeroleDescription": "", - "removeroleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "pruneDescription": "", - "pruneExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "permissionsDescription": "", - "permissionsExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ], - "extendedHelp": "" - }, - "restrictAttachmentDescription": "", - "restrictAttachmentExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictEmbedDescription": "", - "restrictEmbedExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictEmojiDescription": "", - "restrictEmojiExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictReactionDescription": "", - "restrictReactionExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictVoiceDescription": "", - "restrictVoiceExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "softBanDescription": "", - "softBanExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "timeoutApplyDescription": "", - "timeoutApplyExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutUndoDescription": "", - "timeoutUndoExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutNotModeratable": "", - "toggleModerationDmDescription": "", - "toggleModerationDmExtended": { - "extendedHelp": "" - }, - "unbanDescription": "", - "unbanExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unmuteDescription": "", - "unmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unrestrictAttachmentDescription": "", - "unrestrictAttachmentExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmbedDescription": "", - "unrestrictEmbedExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmojiDescription": "", - "unrestrictEmojiExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictReactionDescription": "", - "unrestrictReactionExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictVoiceDescription": "", - "unrestrictVoiceExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unwarnDescription": "", - "unwarnExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vmuteDescription": "", - "vmuteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "voiceKickDescription": "", - "voiceKickExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vunmuteDescription": "", - "vunmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "warnDescription": "", - "warnExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/da/commands/shared.json b/src/languages/da/commands/shared.json deleted file mode 100644 index ddbb28e7f..000000000 --- a/src/languages/da/commands/shared.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "deprecatedMessage": "", - "slashOnlyDetailedDescription": { - "extendedHelp": "" - }, - "slashOnlyErrorMessage": "" -} \ No newline at end of file diff --git a/src/languages/da/commands/system.json b/src/languages/da/commands/system.json deleted file mode 100644 index e9cfdeec4..000000000 --- a/src/languages/da/commands/system.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "evalDescription": "", - "evalExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "evalTimeout": "", - "evalError": "", - "dmNotSent": "", - "dmSent": "", - "reboot": "", - "rebootDescription": "", - "rebootExtended": { - "extendedHelp": "", - "reminder": "" - } -} \ No newline at end of file diff --git a/src/languages/da/commands/tools.json b/src/languages/da/commands/tools.json deleted file mode 100644 index 01bd03e25..000000000 --- a/src/languages/da/commands/tools.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "avatarDescription": "", - "avatarExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "" - }, - "avatarNone": "", - "voteDescription": "", - "voteExtended": { - "usages": [ - "" - ], - "examples": [ - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "voteContentNeeded": "", - "voteReactionBlocked": "", - "whoisExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "whoisMemberRoleListAndMore": "" -} \ No newline at end of file diff --git a/src/languages/da/commands/twitch.json b/src/languages/da/commands/twitch.json deleted file mode 100644 index 2f12e1b08..000000000 --- a/src/languages/da/commands/twitch.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "twitchSubscriptionStreamerNotFound": "", - "twitchSubscriptionStatusValues": [ - "", - "" - ], - "twitchSubscriptionInvalidStatus": "", - "twitchSubscriptionAddDuplicated": "", - "twitchSubscriptionAddSuccessOffline": "", - "twitchSubscriptionAddSuccessLive": "", - "twitchSubscriptionAddMessageForOfflineRequired": "", - "twitchSubscriptionRemoveOrResetEmpty": "", - "twitchSubscriptionRemoveStreamerNotSubscribed": "", - "twitchSubscriptionRemoveNotToProvidedChannel": "", - "twitchSubscriptionRemoveStreamerStatusNotMatch": "", - "twitchSubscriptionRemoveSuccessOffline": "", - "twitchSubscriptionRemoveSuccessLive": "", - "twitchSubscriptionResetSuccess_one": "", - "twitchSubscriptionResetSuccess_other": "", - "twitchSubscriptionShowStreamerNotSubscribed": "", - "twitchSubscriptionShowStatus": { - "live": "", - "offline": "" - }, - "twitchSubscriptionShowUnknownUser": "", - "twitchSubscriptionDescription": "", - "twitchSubscriptionExtended": { - "usages": [ - "", - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/da/commands/whois.json b/src/languages/da/commands/whois.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/da/commands/whois.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/da/errors.json b/src/languages/da/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/da/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/da/events/errors.json b/src/languages/da/events/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/da/events/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/da/events/guilds-logs.json b/src/languages/da/events/guilds-logs.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/da/events/guilds-logs.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/da/events/guilds-members.json b/src/languages/da/events/guilds-members.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/da/events/guilds-members.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/da/events/messages.json b/src/languages/da/events/messages.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/da/events/messages.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/da/events/moderation.json b/src/languages/da/events/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/da/events/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/da/events/noMentionSpam.json b/src/languages/da/events/noMentionSpam.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/da/events/noMentionSpam.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/da/events/reactions.json b/src/languages/da/events/reactions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/da/events/reactions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/da/events/twitch.json b/src/languages/da/events/twitch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/da/events/twitch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/da/fuzzySearch.json b/src/languages/da/fuzzySearch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/da/fuzzySearch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/da/globals.json b/src/languages/da/globals.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/da/globals.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/da/guilds.json b/src/languages/da/guilds.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/da/guilds.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/da/humanLevels.json b/src/languages/da/humanLevels.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/da/humanLevels.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/da/moderation.json b/src/languages/da/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/da/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/da/moderationActions.json b/src/languages/da/moderationActions.json deleted file mode 100644 index 4c440ae54..000000000 --- a/src/languages/da/moderationActions.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "actions": { - "addRole": "", - "ban": "", - "kick": "", - "mute": "", - "removeRole": "", - "restrictedAttachment": "", - "restrictedEmbed": "", - "restrictedEmoji": "", - "restrictedReact": "", - "restrictedVoice": "", - "setNickname": "", - "softban": "", - "vkick": "", - "vmute": "", - "warning": "" - }, - "actionCannotManageRoles": "", - "actionRoleNotConfigured": "", - "actionRoleHigherPosition": "", - "actionRoleManaged": "", - "applyNoReason": "", - "applyReason": "", - "requiredMember": "", - "revokeNoReason": "", - "revokeReason": "", - "setNicknameNoReasonRemoved": "", - "setNicknameNoReasonSet": "", - "setNicknameRemoved": "", - "setNicknameSet": "", - "setupMuteExists": "", - "setupTooManyRoles": "", - "sharedRoleSetupAsk": "", - "sharedRoleSetupNoMessage": "", - "sharedRoleSetupExisting": "", - "sharedRoleSetupExistingName": "", - "sharedRoleSetupNew": "", - "softbanNoReason": "", - "softbanReason": "", - "unSoftbanNoReason": "", - "unSoftbanReason": "" -} \ No newline at end of file diff --git a/src/languages/da/permissions.json b/src/languages/da/permissions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/da/permissions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/da/preconditions.json b/src/languages/da/preconditions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/da/preconditions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/da/selfModeration.json b/src/languages/da/selfModeration.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/da/selfModeration.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/da/serializers.json b/src/languages/da/serializers.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/da/serializers.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/da/settings.json b/src/languages/da/settings.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/da/settings.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/da/system.json b/src/languages/da/system.json deleted file mode 100644 index 073b9b683..000000000 --- a/src/languages/da/system.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "discordAbortError": "", - "fetchBansFail": "", - "helpTitles": { - "aliases": "", - "usages": "", - "extendedHelp": "", - "explainedUsage": "", - "possibleFormats": "", - "examples": "", - "reminders": "" - }, - "jumpTo": "", - "loading": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "prefixReminder": "" -} \ No newline at end of file diff --git a/src/languages/de/arguments.json b/src/languages/de/arguments.json deleted file mode 100644 index 9fd8fa5e3..000000000 --- a/src/languages/de/arguments.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "boolean_one": "", - "boolean_other": "", - "booleanError": "", - "booleanDisabled": "Deaktiviert", - "booleanEnabled": "Aktiviert", - "booleanFalseOptions": [ - "falsch", - "f", - "Nein", - "n", - "Aus", - "deaktivieren", - "deaktiviert", - "0", - "-" - ], - "booleanTrueOptions": [ - "wahr", - "t", - "Ja", - "j", - "an", - "aktivieren", - "aktiviert", - "1", - "+" - ], - "caseNoEntries": "", - "caseUnknownEntry": "", - "caseNotInThisGuild": "", - "caseLatestOptions": [ - "letztes", - "neuestes" - ], - "categoryChannelError": "", - "channelError": "", - "command": "Ich konnte `{{parameter}}` nicht in einen Command auflösen, bitte stelle sicher, dass du den Namen oder den Alias korrekt eingegeben hast!", - "commandMatch": "", - "dateError": "", - "dateFormats": "- `2016-11-24` (JJJJ-MM-TT)\n- `2016-11-24T23:56` (JJJJ-MM-DDTHH:mm)\n- `2016-11-24T23:56:12` (JJJJ-MM-DDTHH:mm:ss)\n- `2016-11-24T23:56:12.000` (JJJJ-MM-DDTHH:mm:ss.ss)\n\n> **Tipp**: Die letzten 3 Formate akzeptieren `Z` am Ende, um die Zeit als UTC zu markieren. Alternativ kannst du den Offset deiner Zeitzone eingeben, indem du `+HH:MM` hinzufügst, z.B. `+01:00`.", - "dateTooEarly": "", - "dateTooFar": "", - "dmChannelError": "", - "duration": "Ich konnte `{{parameter}}` nicht zu einer gültigen Dauer auflösen, hier sind einige der gültigen Formate:\n\n$t(arguments:durationFormats)", - "durationFormats": "- `4h` (4 Stunden).\n- `20m5s` (20 Minuten und 5 Sekunden).\n- \"1w 2d 16h 40m 10s\"` (1 Woche, 2 Tage, 16 Stunden, 40 Minuten und 10 Sekunden).", - "emojiError": "", - "floatError": "", - "floatTooLarge": "", - "floatTooSmall": "Der Parameter `{{parameter}}` ist zu niedrig! Er muss mindestens {{minimum}} sein!", - "guildChannelError": "", - "guildChannelMismatchingError": "", - "guildChannelMissingGuildError": "", - "guildPrivateThreadChannelError": "", - "guildPublicThreadChannelError": "", - "guildStageVoiceChannelError": "", - "guildTextChannelError": "", - "guildThreadChannelError": "", - "guildVoiceChannelError": "", - "hyperlinkError": "", - "integerError": "", - "integerTooLarge": "", - "integerTooSmall": "Der Parameter `{{parameter}}` ist zu niedrig! Er muss mindestens {{minimum}} sein!", - "invite": "Ich konnte `{{parameter}}` nicht zu einem gültigen Invitelink auflösen, diese sehen so aus:\n\n- `https://discord​.gg/6gakFR2`.\n- `https://discord​.com/invite/6gakFR2`.\n- `https://discordapp​.com/invite/6gakFR2`.\n\n> **Tipp**: Du kannst den `https://` Teil weglassen, `discord​.gg/6gakFR2` wird ebenfalls als gültiger Parameter akzeptiert.", - "language": "", - "memberError": "", - "memberMissingGuild": "Ich konnte `{{parameter}}` nicht auflösen, da dieses Argument in einem Server Channel ausgeführt werden muss.", - "messageError": "", - "missing": "Du musst einen anderen Parameter verwenden!\n\n> **Tipp**: Du kannst `{{commandContext.commandPrefix}}help verwenen {{command.name}}` um herauszufinden, wie du diesen Command benutzt.", - "newsChannel": "Ich konnte `{{parameter}}` nicht zu einem Ankündigungschannel auflösen, bitte stelle sicher, dass du seinen Namen oder seine ID korrekt eingegeben hast!\n\n> **Tipp**: Du kannst ihn auch erwähnen!", - "numberError": "", - "numberTooLarge": "", - "numberTooSmall": "Der Parameter `{{parameter}}` ist zu niedrig! Er muss mindestens {{minimum}} sein!", - "piece": "Ich konnte `{{parameter}}` nicht zu einem Stück auflösen! Stelle sicher, dass du seinen Namen oder einen seiner Aliase korrekt eingegeben hast!", - "rangeInvalid": "", - "rangeMax_other": "", - "rangeMax_one": "", - "resetPossibles": [ - "Aus", - "Zurücksetzen" - ], - "roleError": "", - "roleMissingGuild": "Ich konnte `{{parameter}}` nicht auflösen, da dieses Argument in einem Server Channel ausgeführt werden muss.", - "snowflake": "Ich konnte `{{parameter}}` nicht zu einer gültigen snowflake auflösen! Es sind Zahlen mit 17 bis 18 Ziffern, zum Beispiel, deine Nachricht hat die snowflake `{{message.id}}`!", - "store": "", - "stringTooLong": "Der Parameter `{{parameter}}` ist zu lang! Er muss kürzer als {{maximum}} sein)!", - "stringTooShort": "Der Parameter `{{parameter}}` ist zu kurz! Er muss mindestens {{minimum}} Zeichen haben!", - "time": "Ich konnte `{{parameter}}` nicht zu einer gültigen Zeit auflösen!\n**Tipp*: Folgende Formate werden unterstützt:\n\n$t(arguments:durationFormats)\n$t(arguments:dateFormats)", - "timeSpan": "Ich konnte `{{parameter}}` nicht mit einer gültigen Dauer auflösen, stelle sicher, dass du einen gültigen Integer oder einen zeitlich formatierten Wert eingegeben hast. Einige der gültigen Formate sind:\n\n- `45` (45 Sekunden).\n$t(arguments:durationFormats)\n$t(arguments:dateFormats)", - "timeSpanTooBig": "Der Parameter `{{parameter}}` wurde auf eine längere Dauer als {{{maximum, duration}} aufgelöst, was nicht erlaubt ist!", - "timeSpanTooSmall": "Der Parameter `{{parameter}}` wurde auf eine kürzere Dauer als {{{minimum, duration}} aufgelöst, was nicht erlaubt ist!", - "tooFewWinners": "Der Parameter `{{parameter}}` wurde an eine zu niedrige Zahl aufgelöst, er muss mindestens 1 sein!", - "tooManyWinners": "Der Parameter `{{parameter}}` wurde zu einer Zahl aufgelöst, die zu hoch ist, es darf maximal 20 sein!", - "unavailable": "Hoppla! Es scheint, dass ich keinen Parser für einen Parameter finden konnte, bitte kontaktiere meine Entwickler!", - "userError": "", - "enumEmptyError": "", - "enumError": "" -} \ No newline at end of file diff --git a/src/languages/de/assertions.json b/src/languages/de/assertions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/de/assertions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/de/commands/admin.json b/src/languages/de/commands/admin.json deleted file mode 100644 index 0ec670c17..000000000 --- a/src/languages/de/commands/admin.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "confUpdated": "", - "confGetNoExt": "Der Schlüssel **{{key}}** scheint nicht zu existieren.", - "confGet": "Der Wert für den Schlüssel **{{key}}** ist: `{{value}}`", - "confReset": "Der Schlüssel **{{key}}** wurde zurückgesetzt auf: `{{value}}`", - "confNochange": "Der Wert für **{{key}}** war bereits dieser Wert.", - "confServerDescription": "Einstellungen für jeden Server definieren.", - "confServerExtended": { - "usages": [ - "setze NameOfKey Wert für Schlüssel", - "Zeige", - "zeige NameOfKey", - "entferne NameOfKey Wert für Schlüssel", - "NameOfKey zurücksetzen", - "Menü" - ], - "extendedHelp": "Erlaubt dir, WolfStar von Discord zu konfigurieren, als schnelle Alternative zum [Web-Dashboard](https://wolfstar.rocks).", - "examples": [ - "wechsle Sprache auf en-GB", - "setze channels.moderation-logs #moderation-logs", - "Zeige", - "Channel anzeigen", - "roles.moderator Moderator entfernen", - "roles.moderator zurücksetzen", - "Menü" - ], - "reminder": "Es gibt Schlüssel und Gruppen, Schlüssel, die innerhalb einer Gruppe sind, sind nach `GroupName.KeyName` benannt." - }, - "confServer": "**Servereinstellung {{key}}**\n{{list}}", - "confDashboardOnlyKey": "`{{key}}` kann nur über das Web-Dashboard konfiguriert werden ()", - "confSettingNotSet": "Nicht festgelegt", - "rolesetDescription": "Einzigartige Rollensets verwalten.", - "rolesetExtended": { - "usages": [ - "setze RoleSetName Role1 Role2 Role3...", - "entferne RoleSetName Role1 Role2 Role3...", - "Zurücksetzen", - "RoleSetName zurücksetzen", - "Liste", - "RoleSetName Role1 Role2 Role3" - ], - "extendedHelp": "Ein Rollenset ist eine Gruppe von Rollen, die WolfStar als einzigartig für alle Mitglieder des Servers identifiziert, d.h. ein Rollenset namens `Region` könnte die Rollen `Afrika`, `Amerika`, `Asien` und `Europa` beinhalten, und Mitglieder können nur eine von ihnen haben. Dies ist wie eine Art \"Regel\", die in den folgenden drei Situationen angewendet wird:\n\n- Wenn jemand eine Rolle über den \"Rollen\"-Command beansprucht.\n- Wenn jemand eine Rolle als Reaktionsrolle beansprucht.\n- Wenn jemand eine Rolle entweder manuell oder von einem anderen Bot erhält.", - "explainedUsage": [ - [ - "Hinzufügen", - "Erstelle ein neues Rollenset oder füge eine Rolle zu einem existierenden Set hinzu." - ], - [ - "Entfernen", - "Entferne eine Rolle aus einem existierenden Rollenset." - ], - [ - "Zurücksetzen", - "Entfernt alle Rollen aus einem Rollenset oder, wenn nicht spezifiziert, aus allen vorhandenen Rollensets." - ], - [ - "Liste", - "Listet alle Rollensets auf." - ], - [ - "Automatisch", - "Fügt ein Rollenset hinzu oder entfernt es." - ], - [ - "RoleSetName", - "Der Name des Rollensets" - ], - [ - "Rolle1 Rolle2 Rolle3", - "Die Rollen, die dem Rollenset hinzugefügt werden sollen" - ] - ], - "examples": [ - "füge Region Amerika hinzu", - "füge Regionen Afrika Amerika Asien Europa hinzu", - "entferne Region Amerika", - "Zurücksetzen", - "Regionen zurücksetzen", - "Liste", - "Region Amerika", - "Regionen Afrika Amerika Asien Europa" - ], - "reminder": "Dieser Command kann mehrere Rollen gleichzeitig hinzufügen und/oder entfernen." - }, - "rolesetCreated": "", - "rolesetAdded": "", - "rolesetRemoved": "", - "rolesetResetEmpty": "{{REDCROSS}} In dieser Gruppe sind keine Rollensets konfiguriert.", - "rolesetResetAll": "{{GREENTICK}} Erfolgreich alle Rollensets entfernt.", - "rolesetResetNotExists": "{{REDCROSS}} Das Rollenset `{{name}}` existiert nicht auf diesem Server.", - "rolesetResetGroup": "{{GREENTICK}} Erfolgreich das Rollenset `{{name}}` vom Server entfernt.", - "rolesetUpdated": "Das einzigartige Rollenset {{name}} wurde aktualisiert.", - "rolesetNoRolesets": "Du hast keine Rollensets.", - "confMenuRenderAtFolder": "Momentan bei: 📁 {{path}}", - "confMenuRenderAtPiece": "Momentan bei: ⚙️ {{path}}", - "confMenuRenderNokeys": "Es gibt keine konfigurierbaren Schlüssel für diesen Ordner", - "confMenuRenderSelect": "Bitte gebe einen der Namen der folgenden Einträge ein", - "confMenuRenderUpdate": "• Aktualisiere Wert → `set `", - "confMenuRenderRemove": "• Entferne Wert → `remove `", - "confMenuRenderReset": "• Wert zurücksetzen → `reset`", - "confMenuRenderUndo": "• Update rückgängig → `undo`", - "confMenuRenderCvalue": "Aktueller Wert: **``{{value}}``**", - "confMenuRenderBack": "Drücke ◀ um zurückzugehen", - "confMenuInvalidKey": "Ungültiger Schlüssel, bitte versuche es erneut mit einer der folgenden Optionen.", - "confMenuInvalidAction": "Ungültige Aktion, bitte versuche es erneut mit einer der folgenden Optionen.", - "confMenuSaved": "Alle Änderungen erfolgreich gespeichert." -} \ No newline at end of file diff --git a/src/languages/de/commands/animal.json b/src/languages/de/commands/animal.json deleted file mode 100644 index 86b980eb7..000000000 --- a/src/languages/de/commands/animal.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "bunnyDescription": "", - "bunnyExtended": { - "extendedHelp": "" - }, - "bunnyEmbedData": { - "title": "", - "source": "" - }, - "dogDescription": "Süße Hundis! ❤", - "dogExtended": { - "extendedHelp": "Weißt **du** wie süß Hunde sind? Sie sind so schön!\nDieser Command verwendet [dog.ceo](https://dog.ceo) um Bilder der süßesten Hunde zu zeigen!" - }, - "foxDescription": "Ich zeige dir ein Fuchsbild!", - "foxExtended": { - "extendedHelp": "Dieser Command zeigt ein zufälliges Bild von [randomfox.ca](https://randomfox.ca/)." - }, - "kittyDescription": "KÄTZCHEN!", - "kittyExtended": { - "extendedHelp": "Weißt **du** wie süß Kätzchen sind? Sie sind so schön!\nDieser Command verwendet [cataas.com](https://cataas.com) um Bilder der süßesten Kätzchen zu zeigen!" - }, - "shibeDescription": "Süße shibas!", - "shibeExtended": { - "extendedHelp": "Jeder liebt Shibas, Ich werde sie auch lieben! Sie sind so liebenswert ❤" - } -} \ No newline at end of file diff --git a/src/languages/de/commands/auto-moderation.json b/src/languages/de/commands/auto-moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/de/commands/auto-moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/de/commands/case.json b/src/languages/de/commands/case.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/de/commands/case.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/de/commands/fun.json b/src/languages/de/commands/fun.json deleted file mode 100644 index 994434def..000000000 --- a/src/languages/de/commands/fun.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "escaperopeDescription": "Benutze das Fluchtseil aus Pokémon.", - "escaperopeExtended": { - "extendedHelp": "**WolfStar** benutzte **Fluchtseil**." - }, - "escaperopeOutput": "**{{user}}** benutzte **Fluchtseil**" -} \ No newline at end of file diff --git a/src/languages/de/commands/game.json b/src/languages/de/commands/game.json deleted file mode 100644 index f8331464a..000000000 --- a/src/languages/de/commands/game.json +++ /dev/null @@ -1,447 +0,0 @@ -{ - "c4Description": "Spiele Connect-Four mit jemandem.", - "c4Extended": { - "usages": [ - "Benutzer" - ], - "extendedHelp": "Dieses Spiel wird am besten auf dem PC gespielt.\nConnect Four ist ein Zwei-Spieler-Verbindungsspiel, bei dem die Spieler zuerst eine Farbe auswählen und dann farbige Scheiben von oben in ein raster aus Sieben Spalten und Sechs Reihen fallen lassen.", - "examples": [ - "WolfStar" - ] - }, - "c4Prompt": "Lieber {{challengee}}, du wurdest von {{challenger}} in einem Connect-Four-Spiel herausgefordert. Klicken Sie auf die Reaktion 🇾, um zu akzeptieren!", - "gamesBot": "Es tut mir leid, aber ich glaube nicht, dass sie aufhören wollen, das zu tun, was sie tun, um mit Menschen zu spielen.", - "gamesNoPlayers": "Bitte gib ein paar Tribute an, um die Hungerspiele zu spielen, z.B.: `{{prefix}}hg Bob, Mark, Jim, Kyra`", - "gamesProgress": "Tut mir leid, gerade findet in diesem Channel ein Spiel statt, versuche es noch einmal nachdem das Spiel beendet ist.", - "gamesPromptDeny": "Tut mir leid, der herausgeforderte User hat es abgelehnt zu spielen.", - "gamesRepeat": "Es tut mir leid, aber ein User kann nicht zweimal spielen.", - "gamesSelf": "Du musst wirklich traurig sein um gegen dich selbst zu spielen. Versuchs nochmal mit einem anderen User.", - "gamesTooManyOrFew": "Es tut mir leid, aber die Anzahl der Spieler ist kleiner als {{min}} oder größer als {{max}}.", - "hgBloodbath": [ - "{1} schnappt sich eine Schaufel.", - "{1} schnappt sich einen Rucksack und zieht sich zurück.", - "{1} und {2} kämpfen um eine Tasche. {1} gibt auf und zieht sich zurück.", - "{1} und {2} kämpfen um eine Tasche. {2} gibt auf und zieht sich zurück.", - "{1} findet einen Bogen, einige Pfeile und einen Köder.", - "{1} rennt zum Füllhorn und versteckt sich.", - "{1} nimmt eine Handvoll Wurfmesser.", - "{1} reißt {2} einen Streitkolben aus den Händen.", - "{1} findet einen Wasserbeutel.", - "{1} bleibt beim Füllhorn um ressourcen zu sammeln.", - "{1} sammelt so viel Nahrung wie möglich.", - "{1} schnappt sich ein Schwert.", - "{1} nimmt sich einen Speer aus dem Füllhorn.", - "{1} findet eine Tasche voller Sprengstoffe.", - "{1} greift sich ein Erste-Hilfe-Set und renn weg.", - "{1} nimmt sich eine Sichel aus dem Füllhorn.", - "{1}, {2}, und {3} arbeiten zusammen, um so viele Vorräte wie möglich zu sammeln.", - "{1} läuft mit einem Feuerzeug und etwas Seil weg.", - "{1} erbeutet eine Flasche Alkohol und einen Lumpen.", - "{1} findet einen Rucksack voller Campingausrüstung.", - "{1} schnappt sich einen Rucksack, erkennt aber nicht, dass dieser leer ist.", - "{1} bricht die Nase von {2} für einen Korb Brot.", - "{1}, {2}, {3} und {4} teilen alles, was sie gesammelt haben, bevor sie weggelaufen sind.", - "{1} holt sich einen Dreizack aus dem Füllhorn.", - "{1} schnappt ein Gefäß aus Köder, während {2} Angelausrüstung erhält.", - "{1} verjagt {2} vom Füllhorn.", - "{1} schnappt sich einen Schild der an dem Füllhorn lehnt.", - "", - "{1} schnappt sich ein einsames Paar Hosen.", - "{1T} steigt zu früh vom Podium und explodiert.", - "{1} wirft ein Messer in den Kopf von {2T}.", - "{1T} tritt versehentlich auf eine Landmine.", - "", - "{1} und {2} ertränken zusammen {3T}.", - "{1} erwürgt {2T} nach einem Faustkampf.", - "{1} schießt einen Pfeil in den Kopf von {2T}.", - "{1T} kommt mit der Situation nicht klar und bringt sich um.", - "{1} schlägt den Kopf von {2T} mehrmals gegen einen Felsen.", - "{1} bricht {2T} das Genick.", - "{1} enthauptet {2T} mit einem Schwert.", - "{1} sticht {2T} einen Speer in den Abdomen.", - "{1} zündet {2T} mit einem Molotov an.", - "{1T} fällt in eine Grube und stirbt.", - "{1} ersticht {2T} hinterrücks.", - "{1} verletzt {2T} schwer, aber beendet ihr Leid.", - "{1} verletzt {2T} schwer und lässt sie sterben.", - "{1} schlägt den Kopf von {2T} mit einem Streitkolben ein.", - "{1} schubst während eines Messerkampfes {2T} von einer Klippe runter.", - "{1} wirft ein Messer in die Brust von {2T}.", - "{1T} kann {2} nicht davon überzeugen, sie nicht zu töten.", - "{1} überzeugt {2T}, sie nicht zu töten, nur um {2T} stattdessen zu töten.", - "{1T} fällt in einen gefrorenen See und ertrinkt.", - "{1}, {2}und {3T} beginnen zu kämpfen, aber {2} läuft weg während {1} {3T} tötet.", - "{1} tötet {2T} mit seiner eigenen Waffe.", - "{1} überwältigt und tötet {2T}.", - "{1} löst einen Sprengsatz aus und tötet {2T}.", - "{1} löst einen Sprengsatz aus und tötet {2T} und {3T}.", - "{1} löst einen Sprengsatz aus und tötet {2T}, {3T} und {4T}.", - "{1} löst einen Sprengsatz aus und tötet {2T}, {3T}, {4T} und {5T}.", - "{1} tötet {2T}, während sie versuchen wegzulaufen.", - "{1T} und {2T} drohen mit einem doppelten Selbstmord. Es scheitert und sie sterben.", - "{1T}, {2T}, {3T} und {4T} gehen einen Selbstmordpakt ein und töten sich selbst.", - "{1} tötet {2T} mit einer Axt.", - "{1} und {2} kämpfen gegen {3T} und {4T}. {1} und {2} überleben.", - "{1T} und {2T} kämpfen gegen {3} und {4}. {3} und {4} überleben.", - "{1T} greift {2} an, aber {3} schützt sie und tötet {1T}.", - "{1} verletzt {2T} mit einem Schwert schwer.", - "{1} erwürgt {2T} mit einem Seil.", - "{1} tötet {2T} für seine Vorräte.", - "{1} schießt einen Pfeil auf {2}, verfehlt aber und tötet stattdessen {3T}.", - "{1} schießt einen giftigen Pfeil in den Hals von {2T} ab, und tötet sie langsam.", - "{1} ersticht {2T} mit einem Zweig.", - "{1} sticht mit einem Dreizack {2T} in den Rücken.", - "{1}, {2T} und {3T} stürzen sich in einen Kampf. {1} tötet beide erfolgreich.", - "{1T}, {2} und {3T} stürzen sich in einen Kampf. {2} tötet beide erfolgreich.", - "{1T}, {2T} und {3} stürzen sich in einen Kampf. {3} tötet beide erfolgreich.", - "{1} findet {2T} welche sich im Füllhorn versteckt und tötet Sie.", - "{1T} findet {2} im Füllhorn versteckt, aber {2} tötet Sie.", - "{1} tötet {2T} mit einer Sichel.", - "{1} und {2T} kämpfen um eine Tasche. {1} erwürgt {2T} mit den Riemen und läuft weg.", - "{1T} und {2} kämpfen um eine Tasche. {2} erwürgt {1T} mit den Riemen und läuft weg.", - "{1} sticht {2T} mit einem Sais zu Tode.", - "{1T} stolpert beim wegrennen vor dem Füllhorn und wird von {2} umgebracht.", - "{1} stolpert beim Wegrennen von dem Füllhorn, {2} hilft ihr auf und sie rennen zusammen weg.", - "{1} zielt einen Pfeil auf den Kopf von {2} und schießt ab, {3T} springt in den Weg und opfert sein Leben, um ihn zu retten." - ], - "hgDay": [ - "{1} geht jagen.", - "{1} verletzt sich selbst.", - "{1} erkundet die Arena.", - "{1} schreckt {2} ab.", - "{1} lenkt {2} ab und läuft weg.", - "{1} stalked {2}.", - "{1} fischt.", - "{1} tarnt sich selbst in den Büschen.", - "{1} klaut von {2} während sie wegschauen.", - "{1} macht einen Holzspeer.", - "{1} entdeckt eine Höhle.", - "{1} attackiert {2}, aber sie schaffen es zu entkommen.", - "{1} verfolgt {2}.", - "{1} rennt vor {2} davon.", - "{1} sammelt Früchte von einem Baum.", - "{1} erhält eine Axt von einem unbekannten Sponsor.", - "{1} erhält sauberes Wasser von einem unbekannten Sponsor.", - "{1} erhält medizinische Hilfsmittel von einem unbekannten Sponsor.", - "{1} erhält frisches Essen von einem unbekannten Sponsor.", - "{1} sucht nach einer Wasserquelle.", - "{1} besiegt {2} in einem Kampf, verschont aber ihr Leben.", - "{1} und {2} arbeiten für den Tag zusammen.", - "{1} fleht {2} an sie zu töten. Sie weigern sich und lassen {1} am Leben.", - "{1} versucht den ganzen Tag zu schlafen.", - "{1}, {2}, {3} und {4} plündern {5}'s Camp während sie Jagen.", - "{1} baut eine Hütte auf.", - "{1} hört wie {2} und {3} in der Ferne reden.", - "{1} übt Bogenschießen.", - "{1} denkt an zu Hause.", - "{1} wird während dem Beeren sammeln von Dornen gespickt.", - "{1} versucht mit einem Dreizack zu fischen.", - "{1} sucht nach Feuerholz.", - "{1} und {2} teilen sich auf, um nach Ressourcen zu suchen.", - "{1} pflückt Blumen.", - "{1} kümmert sich um {2}'s Wunden.", - "{1} sieht in der Ferne Rauch aufsteigen, unterlässt aber weitere Untersuchungen.", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "{1} tötet {2T} mit seiner eigenen Waffe.", - "{1} überwältigt und tötet {2T}.", - "{1} löst einen Sprengsatz aus und tötet {2T}.", - "{1} löst einen Sprengsatz aus und tötet {2T} und {3T}.", - "{1} löst einen Sprengsatz aus und tötet {2T}, {3T} und {4T}.", - "{1} löst einen Sprengsatz aus und tötet {2T}, {3T}, {4T} und {5T}.", - "{1} tötet {2T}, während sie versuchen wegzulaufen.", - "{1T} und {2T} drohen mit einem doppelten Selbstmord. Es scheitert und sie sterben.", - "{1T}, {2T}, {3T} und {4T} gehen einen Selbstmordpakt ein und töten sich selbst.", - "{1T} stirbt an Unterkühlung.", - "{1T} stirbt an Hunger.", - "{1T} stirbt an Durst.", - "{1} tötet {2T} mit einer Axt.", - "{1} und {2} kämpfen gegen {3T} und {4T}. {1} und {2} überleben.", - "{1T} und {2T} kämpfen gegen {3} und {4}. {3} und {4} überleben.", - "{1T} stirbt beim Versuch, der Arena zu entkommen.", - "{1T} stirbt an Dysenterie.", - "{1T} löst versehentlich eine Landmine aus, beim versuch sie scharf zu stellen.", - "{1T} greift {2} an, aber {3} schützt sie und tötet {1T}.", - "{1} überrascht und tötet {2T}.", - "{1T} tritt versehentlich auf eine Landmine.", - "{1} verletzt {2T} mit einem Schwert schwer.", - "{1} erwürgt {2T} mit einem Seil.", - "{1} tötet {2T} für seine Vorräte.", - "{1} schießt einen Pfeil auf {2}, verfehlt aber und tötet stattdessen {3T}.", - "{1} schießt einen giftigen Pfeil in den Hals von {2T} ab, und tötet sie dadurch langsam.", - "{1}, {2}, und {3} überraschen und töten {4T}, {5T}, und {6T}.", - "{1T}, {2T}, und {3T} uüberraschen {4}, {5} und {6}, werden aber von ihnen getötet.", - "{1} ersticht {2T} mit einem Zweig.", - "", - "", - "", - "", - "{1} vergiftet {2T}'s Getränk. Sie trinken es und sterben.", - "{1} sticht mit einem Dreizack {2T} in den Rücken.", - "{1T} versucht, auf einen Baum zu klettern, fällt aber auf {2T}, und tötet beide.", - "{1}, {2T} und {3T} stürzen sich in einen Kampf. {1} tötet beide erfolgreich.", - "{1T}, {2} und {3T} stürzen sich in einen Kampf. {2} tötet beide erfolgreich.", - "{1T}, {2T} und {3} stürzen sich in einen Kampf. {3} tötet beide erfolgreich.", - "{1} tötet {2T} mit einer Sichel.", - "", - "", - "", - "", - "{1} verfolgt und tötet {2T}.", - "{1} sticht {2T} mit einem Sais zu Tode.", - "", - "{1} jagt einen Schmetterling.", - "{1T} fällt von einer Klippe und wird von einem Stock aufgespießt.", - "", - "", - "", - "", - "" - ], - "hgNight": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hungerGamesDescription": "", - "hungerGamesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "examples": [ - "" - ], - "reminder": "" - }, - "hungerGamesResultDeaths_one": "", - "hungerGamesResultDeaths_other": "", - "hungerGamesResultHeaderBloodbath": "", - "hungerGamesResultHeaderMoon": "", - "hungerGamesResultHeaderSun": "", - "hungerGamesResultProceed": "", - "hungerGamesStop": "", - "hungerGamesWinner": "", - "ticTacToeDescription": "", - "ticTacToeDraw": "", - "ticTacToeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "ticTacToePrompt": "", - "ticTacToeTurn": "", - "ticTacToeWinner": "", - "triviaActiveGame": "", - "triviaDescription": "", - "triviaEmbedTitles": { - "difficulty": "", - "trivia": "" - }, - "triviaExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "triviaIncorrect": "", - "triviaInvalidCategory": "", - "triviaNoAnswer": "", - "triviaWinner": "" -} \ No newline at end of file diff --git a/src/languages/de/commands/general.json b/src/languages/de/commands/general.json deleted file mode 100644 index 5e16f992d..000000000 --- a/src/languages/de/commands/general.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "helpAllFlag": "", - "helpCommandCount_one": "", - "helpCommandCount_other": "", - "helpData": { - "footer": "", - "title": "" - }, - "helpDescription": "", - "helpExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "reminder": "", - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "helpDm": "", - "helpNodm": "", - "v7Description": "", - "v7Extended": { - "extendedHelp": "" - }, - "v7Message": "", - "v7NayreMessage": "" -} \ No newline at end of file diff --git a/src/languages/de/commands/info.json b/src/languages/de/commands/info.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/de/commands/info.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/de/commands/management.json b/src/languages/de/commands/management.json deleted file mode 100644 index 21ef26ce2..000000000 --- a/src/languages/de/commands/management.json +++ /dev/null @@ -1,445 +0,0 @@ -{ - "commandHandlerAborted": "", - "permissionNodesHigher": "", - "permissionNodesCannotAllowEveryone": "", - "permissionNodesInvalidType": "", - "permissionNodesAdd": "", - "permissionNodesNodeNotExists": "", - "permissionNodesCommandNotExists": "", - "permissionNodesRemove": "", - "permissionNodesReset": "", - "permissionNodesShowName": "", - "permissionNodesShowAllow": "", - "permissionNodesShowDeny": "", - "guildInfoTitles": { - "CHANNELS": "", - "MEMBERS": "", - "OTHER": "" - }, - "guildInfoChannels": "", - "guildInfoChannelsAfkChannelText": "", - "guildInfoMembers": "", - "guildInfoOther": "", - "guildInfoBanner": "", - "guildInfoIcon": "", - "guildInfoSplash": "", - "guildInfoDiscoverySplash": "", - "roleInfoTitles": { - "PERMISSIONS": "" - }, - "roleInfoData": "", - "roleInfoAll": "", - "roleInfoNoPermissions": "", - "manageCommandAutoDeleteShowEmpty": "", - "manageCommandAutoDeleteShow": "", - "manageCommandAutoDeleteAdd": "", - "manageCommandAutoDeleteRemove": "", - "manageCommandAutoDeleteRemoveNotset": "", - "manageCommandAutoDeleteReset": "", - "manageCommandChannelShow": "", - "manageCommandChannelShowEmpty": "", - "manageCommandChannelAddAlreadyset": "", - "manageCommandChannelAdd": "", - "manageCommandChannelRemoveNotset": "", - "manageCommandChannelRemove": "", - "manageCommandChannelResetEmpty": "", - "manageCommandChannelReset": "", - "manageReactionRolesShowEmpty": "", - "manageReactionRolesAddChannel": "", - "manageReactionRolesAddPrompt": "", - "manageReactionRolesAddMissing": "", - "manageReactionRolesAdd": "", - "manageReactionRolesRemoveNotExists": "", - "manageReactionRolesRemove": "", - "manageReactionRolesResetEmpty": "", - "manageReactionRolesReset": "", - "configurationEquals": "", - "setIgnoreChannelsSet": "", - "setIgnoreChannelsRemoved": "", - "setImageLogsSet": "", - "setMemberAddLogsSet": "", - "setMemberRemoveLogsSet": "", - "setMessageUpdateLogsSet": "", - "setMessageDeleteLogsSet": "", - "setModLogsSet": "", - "setPrefixSet": "", - "stickyRolesNotExists": "", - "stickyRolesReset": "", - "stickyRolesRemove": "", - "stickyRolesAdd": "", - "stickyRolesShowEmpty": "", - "stickyRolesShowSingle": "", - "createMuteDescription": "", - "createMuteExtended": { - "extendedHelp": "" - }, - "permissionNodesDescription": "", - "permissionNodesExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "managecommandautodeleteDescription": "", - "managecommandautodeleteExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageCommandChannelDescription": "", - "manageCommandChannelExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageReactionRolesDescription": "", - "manageReactionRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "rolesAdded": "", - "rolesAuditlog": "", - "rolesListEmpty": "", - "rolesListTitle": "", - "rolesNotManageable": "", - "rolesNotPublic": "", - "rolesRemoved": "", - "setIgnoreChannelsDescription": "", - "setIgnoreChannelsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setImageLogsDescription": "", - "setImageLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "setMemberAddLogsDescription": "", - "setMemberAddLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMemberRemoveLogsDescription": "", - "setMemberRemoveLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMessageUpdateLogsDescription": "", - "setMessageUpdateLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setMessageDeleteLogsDescription": "", - "setMessageDeleteLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setmodlogsDescription": "", - "setmodlogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setprefixDescription": "", - "setprefixExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "guildInfoDescription": "", - "guildInfoExtended": { - "extendedHelp": "" - }, - "roleInfoDescription": "", - "roleInfoExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "stickyRolesDescription": "", - "stickyRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesDescription": "", - "rolesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/de/commands/misc.json b/src/languages/de/commands/misc.json deleted file mode 100644 index 32f64d584..000000000 --- a/src/languages/de/commands/misc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "snipeEmpty": "", - "snipeTitle": "", - "snipeDescription": "", - "snipeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/de/commands/moderation.json b/src/languages/de/commands/moderation.json deleted file mode 100644 index 815d1c788..000000000 --- a/src/languages/de/commands/moderation.json +++ /dev/null @@ -1,889 +0,0 @@ -{ - "permissions": "", - "permissionsAll": "", - "slowmodeSet": "", - "slowmodeReset": "", - "banNotBannable": "", - "dehoistStarting": "", - "dehoistProgress": "", - "dehoistEmbed": { - "title": "", - "descriptionNoone": "", - "descriptionWithError": "", - "descriptionWithMultipleErrors": "", - "description": "", - "descriptionMultipleMembers": "", - "fieldErrorTitle": "" - }, - "kickNotKickable": "", - "lockdownLock": "", - "lockdownLocking": "", - "lockdownLocked": "", - "lockdownUnlocked": "", - "lockdownOpen": "", - "muteMuted": "", - "muteUserNotMuted": "", - "restrictLowlevel": "", - "pruneAlert_one": "", - "pruneAlert_other": "", - "pruneInvalidPosition": "", - "pruneNoDeletes": "", - "pruneLogHeader": "", - "toggleModerationDmToggledEnabled": "", - "toggleModerationDmToggledDisabled": "", - "moderationOutput_one": "", - "moderationOutput_other": "", - "moderationOutputWithReason_one": "", - "moderationOutputWithReason_other": "", - "moderationFailed_one": "", - "moderationFailed_other": "", - "moderationDmFooter": "", - "moderationDmDescription": "", - "moderationDmDescriptionWithReason": "", - "moderationDmDescriptionWithDuration": "", - "moderationDmDescriptionWithReasonWithDuration": "", - "slowmodeDescription": "", - "slowmodeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "banDescription": "", - "banExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "dehoistDescription": "", - "dehoistExtended": { - "extendedHelp": "", - "reminder": "" - }, - "kickDescription": "", - "kickExtended": { - "usages": [ - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "lockdownDescription": "", - "lockdownExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "muteDescription": "", - "muteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "setNicknameDescription": "", - "setNicknameExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ], - "reminder": "" - }, - "addRoleDescription": "", - "addRoleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "removeroleDescription": "", - "removeroleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "pruneDescription": "", - "pruneExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "permissionsDescription": "", - "permissionsExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ], - "extendedHelp": "" - }, - "restrictAttachmentDescription": "", - "restrictAttachmentExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictEmbedDescription": "", - "restrictEmbedExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictEmojiDescription": "", - "restrictEmojiExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictReactionDescription": "", - "restrictReactionExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictVoiceDescription": "", - "restrictVoiceExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "softBanDescription": "", - "softBanExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "timeoutApplyDescription": "", - "timeoutApplyExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutUndoDescription": "", - "timeoutUndoExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutNotModeratable": "", - "toggleModerationDmDescription": "", - "toggleModerationDmExtended": { - "extendedHelp": "" - }, - "unbanDescription": "", - "unbanExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unmuteDescription": "", - "unmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unrestrictAttachmentDescription": "", - "unrestrictAttachmentExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmbedDescription": "", - "unrestrictEmbedExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmojiDescription": "", - "unrestrictEmojiExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictReactionDescription": "", - "unrestrictReactionExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictVoiceDescription": "", - "unrestrictVoiceExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unwarnDescription": "", - "unwarnExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vmuteDescription": "", - "vmuteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "voiceKickDescription": "", - "voiceKickExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vunmuteDescription": "", - "vunmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "warnDescription": "", - "warnExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/de/commands/shared.json b/src/languages/de/commands/shared.json deleted file mode 100644 index ddbb28e7f..000000000 --- a/src/languages/de/commands/shared.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "deprecatedMessage": "", - "slashOnlyDetailedDescription": { - "extendedHelp": "" - }, - "slashOnlyErrorMessage": "" -} \ No newline at end of file diff --git a/src/languages/de/commands/system.json b/src/languages/de/commands/system.json deleted file mode 100644 index e9cfdeec4..000000000 --- a/src/languages/de/commands/system.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "evalDescription": "", - "evalExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "evalTimeout": "", - "evalError": "", - "dmNotSent": "", - "dmSent": "", - "reboot": "", - "rebootDescription": "", - "rebootExtended": { - "extendedHelp": "", - "reminder": "" - } -} \ No newline at end of file diff --git a/src/languages/de/commands/tools.json b/src/languages/de/commands/tools.json deleted file mode 100644 index 01bd03e25..000000000 --- a/src/languages/de/commands/tools.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "avatarDescription": "", - "avatarExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "" - }, - "avatarNone": "", - "voteDescription": "", - "voteExtended": { - "usages": [ - "" - ], - "examples": [ - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "voteContentNeeded": "", - "voteReactionBlocked": "", - "whoisExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "whoisMemberRoleListAndMore": "" -} \ No newline at end of file diff --git a/src/languages/de/commands/twitch.json b/src/languages/de/commands/twitch.json deleted file mode 100644 index 2f12e1b08..000000000 --- a/src/languages/de/commands/twitch.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "twitchSubscriptionStreamerNotFound": "", - "twitchSubscriptionStatusValues": [ - "", - "" - ], - "twitchSubscriptionInvalidStatus": "", - "twitchSubscriptionAddDuplicated": "", - "twitchSubscriptionAddSuccessOffline": "", - "twitchSubscriptionAddSuccessLive": "", - "twitchSubscriptionAddMessageForOfflineRequired": "", - "twitchSubscriptionRemoveOrResetEmpty": "", - "twitchSubscriptionRemoveStreamerNotSubscribed": "", - "twitchSubscriptionRemoveNotToProvidedChannel": "", - "twitchSubscriptionRemoveStreamerStatusNotMatch": "", - "twitchSubscriptionRemoveSuccessOffline": "", - "twitchSubscriptionRemoveSuccessLive": "", - "twitchSubscriptionResetSuccess_one": "", - "twitchSubscriptionResetSuccess_other": "", - "twitchSubscriptionShowStreamerNotSubscribed": "", - "twitchSubscriptionShowStatus": { - "live": "", - "offline": "" - }, - "twitchSubscriptionShowUnknownUser": "", - "twitchSubscriptionDescription": "", - "twitchSubscriptionExtended": { - "usages": [ - "", - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/de/commands/whois.json b/src/languages/de/commands/whois.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/de/commands/whois.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/de/constants.ts b/src/languages/de/constants.ts deleted file mode 100644 index 90ccc5ecd..000000000 --- a/src/languages/de/constants.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Handler } from '#lib/i18n/structures/Handler'; -import { TimeTypes } from '@sapphire/time-utilities'; - -export class ExtendedHandler extends Handler { - public constructor() { - super({ - name: 'de', - duration: { - [TimeTypes.Year]: { - 1: 'Jahr', - DEFAULT: 'Jahre' - }, - [TimeTypes.Month]: { - 1: 'Monat', - DEFAULT: 'Monate' - }, - [TimeTypes.Week]: { - 1: 'Woche', - DEFAULT: 'Wochen' - }, - [TimeTypes.Day]: { - 1: 'Tag', - DEFAULT: 'Tage' - }, - [TimeTypes.Hour]: { - 1: 'Stunde', - DEFAULT: 'Stunden' - }, - [TimeTypes.Minute]: { - 1: 'Minute', - DEFAULT: 'Minuten' - }, - [TimeTypes.Second]: { - 1: 'Sekunde', - DEFAULT: 'Sekunden' - } - } - }); - } -} diff --git a/src/languages/de/errors.json b/src/languages/de/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/de/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/de/events/errors.json b/src/languages/de/events/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/de/events/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/de/events/guilds-logs.json b/src/languages/de/events/guilds-logs.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/de/events/guilds-logs.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/de/events/guilds-members.json b/src/languages/de/events/guilds-members.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/de/events/guilds-members.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/de/events/messages.json b/src/languages/de/events/messages.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/de/events/messages.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/de/events/moderation.json b/src/languages/de/events/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/de/events/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/de/events/noMentionSpam.json b/src/languages/de/events/noMentionSpam.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/de/events/noMentionSpam.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/de/events/reactions.json b/src/languages/de/events/reactions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/de/events/reactions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/de/events/twitch.json b/src/languages/de/events/twitch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/de/events/twitch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/de/fuzzySearch.json b/src/languages/de/fuzzySearch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/de/fuzzySearch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/de/globals.json b/src/languages/de/globals.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/de/globals.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/de/guilds.json b/src/languages/de/guilds.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/de/guilds.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/de/humanLevels.json b/src/languages/de/humanLevels.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/de/humanLevels.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/de/moderation.json b/src/languages/de/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/de/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/de/moderationActions.json b/src/languages/de/moderationActions.json deleted file mode 100644 index 4c440ae54..000000000 --- a/src/languages/de/moderationActions.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "actions": { - "addRole": "", - "ban": "", - "kick": "", - "mute": "", - "removeRole": "", - "restrictedAttachment": "", - "restrictedEmbed": "", - "restrictedEmoji": "", - "restrictedReact": "", - "restrictedVoice": "", - "setNickname": "", - "softban": "", - "vkick": "", - "vmute": "", - "warning": "" - }, - "actionCannotManageRoles": "", - "actionRoleNotConfigured": "", - "actionRoleHigherPosition": "", - "actionRoleManaged": "", - "applyNoReason": "", - "applyReason": "", - "requiredMember": "", - "revokeNoReason": "", - "revokeReason": "", - "setNicknameNoReasonRemoved": "", - "setNicknameNoReasonSet": "", - "setNicknameRemoved": "", - "setNicknameSet": "", - "setupMuteExists": "", - "setupTooManyRoles": "", - "sharedRoleSetupAsk": "", - "sharedRoleSetupNoMessage": "", - "sharedRoleSetupExisting": "", - "sharedRoleSetupExistingName": "", - "sharedRoleSetupNew": "", - "softbanNoReason": "", - "softbanReason": "", - "unSoftbanNoReason": "", - "unSoftbanReason": "" -} \ No newline at end of file diff --git a/src/languages/de/permissions.json b/src/languages/de/permissions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/de/permissions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/de/preconditions.json b/src/languages/de/preconditions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/de/preconditions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/de/selfModeration.json b/src/languages/de/selfModeration.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/de/selfModeration.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/de/serializers.json b/src/languages/de/serializers.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/de/serializers.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/de/settings.json b/src/languages/de/settings.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/de/settings.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/de/system.json b/src/languages/de/system.json deleted file mode 100644 index 073b9b683..000000000 --- a/src/languages/de/system.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "discordAbortError": "", - "fetchBansFail": "", - "helpTitles": { - "aliases": "", - "usages": "", - "extendedHelp": "", - "explainedUsage": "", - "possibleFormats": "", - "examples": "", - "reminders": "" - }, - "jumpTo": "", - "loading": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "prefixReminder": "" -} \ No newline at end of file diff --git a/src/languages/el/arguments.json b/src/languages/el/arguments.json deleted file mode 100644 index a7befa6f3..000000000 --- a/src/languages/el/arguments.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "boolean_one": "", - "boolean_other": "", - "booleanError": "", - "booleanDisabled": "", - "booleanEnabled": "", - "booleanFalseOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "booleanTrueOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "caseNoEntries": "", - "caseUnknownEntry": "", - "caseNotInThisGuild": "", - "caseLatestOptions": [ - "", - "" - ], - "categoryChannelError": "", - "channelError": "", - "command": "", - "commandMatch": "", - "dateError": "", - "dateFormats": "", - "dateTooEarly": "", - "dateTooFar": "", - "dmChannelError": "", - "duration": "", - "durationFormats": "", - "emojiError": "", - "floatError": "", - "floatTooLarge": "", - "floatTooSmall": "", - "guildChannelError": "", - "guildChannelMismatchingError": "", - "guildChannelMissingGuildError": "", - "guildPrivateThreadChannelError": "", - "guildPublicThreadChannelError": "", - "guildStageVoiceChannelError": "", - "guildTextChannelError": "", - "guildThreadChannelError": "", - "guildVoiceChannelError": "", - "hyperlinkError": "", - "integerError": "", - "integerTooLarge": "", - "integerTooSmall": "", - "invite": "", - "language": "", - "memberError": "", - "memberMissingGuild": "", - "messageError": "", - "missing": "", - "newsChannel": "", - "numberError": "", - "numberTooLarge": "", - "numberTooSmall": "", - "piece": "", - "rangeInvalid": "", - "rangeMax_other": "", - "rangeMax_one": "", - "resetPossibles": [ - "", - "" - ], - "roleError": "", - "roleMissingGuild": "", - "snowflake": "", - "store": "", - "stringTooLong": "", - "stringTooShort": "", - "time": "", - "timeSpan": "", - "timeSpanTooBig": "", - "timeSpanTooSmall": "", - "tooFewWinners": "", - "tooManyWinners": "", - "unavailable": "", - "userError": "", - "enumEmptyError": "", - "enumError": "" -} \ No newline at end of file diff --git a/src/languages/el/assertions.json b/src/languages/el/assertions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/el/assertions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/el/commands/admin.json b/src/languages/el/commands/admin.json deleted file mode 100644 index 444f39c28..000000000 --- a/src/languages/el/commands/admin.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "confUpdated": "", - "confGetNoExt": "", - "confGet": "", - "confReset": "", - "confNochange": "", - "confServerDescription": "", - "confServerExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "confServer": "", - "confDashboardOnlyKey": "", - "confSettingNotSet": "", - "rolesetDescription": "", - "rolesetExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesetCreated": "", - "rolesetAdded": "", - "rolesetRemoved": "", - "rolesetResetEmpty": "", - "rolesetResetAll": "", - "rolesetResetNotExists": "", - "rolesetResetGroup": "", - "rolesetUpdated": "", - "rolesetNoRolesets": "", - "confMenuRenderAtFolder": "", - "confMenuRenderAtPiece": "", - "confMenuRenderNokeys": "", - "confMenuRenderSelect": "", - "confMenuRenderUpdate": "", - "confMenuRenderRemove": "", - "confMenuRenderReset": "", - "confMenuRenderUndo": "", - "confMenuRenderCvalue": "", - "confMenuRenderBack": "", - "confMenuInvalidKey": "", - "confMenuInvalidAction": "", - "confMenuSaved": "" -} \ No newline at end of file diff --git a/src/languages/el/commands/animal.json b/src/languages/el/commands/animal.json deleted file mode 100644 index 6d00e57af..000000000 --- a/src/languages/el/commands/animal.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "bunnyDescription": "", - "bunnyExtended": { - "extendedHelp": "" - }, - "bunnyEmbedData": { - "title": "", - "source": "" - }, - "dogDescription": "", - "dogExtended": { - "extendedHelp": "" - }, - "foxDescription": "", - "foxExtended": { - "extendedHelp": "" - }, - "kittyDescription": "", - "kittyExtended": { - "extendedHelp": "" - }, - "shibeDescription": "", - "shibeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/el/commands/auto-moderation.json b/src/languages/el/commands/auto-moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/el/commands/auto-moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/el/commands/case.json b/src/languages/el/commands/case.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/el/commands/case.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/el/commands/fun.json b/src/languages/el/commands/fun.json deleted file mode 100644 index 7892e327d..000000000 --- a/src/languages/el/commands/fun.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "escaperopeDescription": "", - "escaperopeExtended": { - "extendedHelp": "" - }, - "escaperopeOutput": "" -} \ No newline at end of file diff --git a/src/languages/el/commands/game.json b/src/languages/el/commands/game.json deleted file mode 100644 index 8075ca93c..000000000 --- a/src/languages/el/commands/game.json +++ /dev/null @@ -1,447 +0,0 @@ -{ - "c4Description": "", - "c4Extended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "c4Prompt": "", - "gamesBot": "", - "gamesNoPlayers": "", - "gamesProgress": "", - "gamesPromptDeny": "", - "gamesRepeat": "", - "gamesSelf": "", - "gamesTooManyOrFew": "", - "hgBloodbath": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgDay": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgNight": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hungerGamesDescription": "", - "hungerGamesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "examples": [ - "" - ], - "reminder": "" - }, - "hungerGamesResultDeaths_one": "", - "hungerGamesResultDeaths_other": "", - "hungerGamesResultHeaderBloodbath": "", - "hungerGamesResultHeaderMoon": "", - "hungerGamesResultHeaderSun": "", - "hungerGamesResultProceed": "", - "hungerGamesStop": "", - "hungerGamesWinner": "", - "ticTacToeDescription": "", - "ticTacToeDraw": "", - "ticTacToeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "ticTacToePrompt": "", - "ticTacToeTurn": "", - "ticTacToeWinner": "", - "triviaActiveGame": "", - "triviaDescription": "", - "triviaEmbedTitles": { - "difficulty": "", - "trivia": "" - }, - "triviaExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "triviaIncorrect": "", - "triviaInvalidCategory": "", - "triviaNoAnswer": "", - "triviaWinner": "" -} \ No newline at end of file diff --git a/src/languages/el/commands/general.json b/src/languages/el/commands/general.json deleted file mode 100644 index 5e16f992d..000000000 --- a/src/languages/el/commands/general.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "helpAllFlag": "", - "helpCommandCount_one": "", - "helpCommandCount_other": "", - "helpData": { - "footer": "", - "title": "" - }, - "helpDescription": "", - "helpExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "reminder": "", - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "helpDm": "", - "helpNodm": "", - "v7Description": "", - "v7Extended": { - "extendedHelp": "" - }, - "v7Message": "", - "v7NayreMessage": "" -} \ No newline at end of file diff --git a/src/languages/el/commands/info.json b/src/languages/el/commands/info.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/el/commands/info.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/el/commands/management.json b/src/languages/el/commands/management.json deleted file mode 100644 index 21ef26ce2..000000000 --- a/src/languages/el/commands/management.json +++ /dev/null @@ -1,445 +0,0 @@ -{ - "commandHandlerAborted": "", - "permissionNodesHigher": "", - "permissionNodesCannotAllowEveryone": "", - "permissionNodesInvalidType": "", - "permissionNodesAdd": "", - "permissionNodesNodeNotExists": "", - "permissionNodesCommandNotExists": "", - "permissionNodesRemove": "", - "permissionNodesReset": "", - "permissionNodesShowName": "", - "permissionNodesShowAllow": "", - "permissionNodesShowDeny": "", - "guildInfoTitles": { - "CHANNELS": "", - "MEMBERS": "", - "OTHER": "" - }, - "guildInfoChannels": "", - "guildInfoChannelsAfkChannelText": "", - "guildInfoMembers": "", - "guildInfoOther": "", - "guildInfoBanner": "", - "guildInfoIcon": "", - "guildInfoSplash": "", - "guildInfoDiscoverySplash": "", - "roleInfoTitles": { - "PERMISSIONS": "" - }, - "roleInfoData": "", - "roleInfoAll": "", - "roleInfoNoPermissions": "", - "manageCommandAutoDeleteShowEmpty": "", - "manageCommandAutoDeleteShow": "", - "manageCommandAutoDeleteAdd": "", - "manageCommandAutoDeleteRemove": "", - "manageCommandAutoDeleteRemoveNotset": "", - "manageCommandAutoDeleteReset": "", - "manageCommandChannelShow": "", - "manageCommandChannelShowEmpty": "", - "manageCommandChannelAddAlreadyset": "", - "manageCommandChannelAdd": "", - "manageCommandChannelRemoveNotset": "", - "manageCommandChannelRemove": "", - "manageCommandChannelResetEmpty": "", - "manageCommandChannelReset": "", - "manageReactionRolesShowEmpty": "", - "manageReactionRolesAddChannel": "", - "manageReactionRolesAddPrompt": "", - "manageReactionRolesAddMissing": "", - "manageReactionRolesAdd": "", - "manageReactionRolesRemoveNotExists": "", - "manageReactionRolesRemove": "", - "manageReactionRolesResetEmpty": "", - "manageReactionRolesReset": "", - "configurationEquals": "", - "setIgnoreChannelsSet": "", - "setIgnoreChannelsRemoved": "", - "setImageLogsSet": "", - "setMemberAddLogsSet": "", - "setMemberRemoveLogsSet": "", - "setMessageUpdateLogsSet": "", - "setMessageDeleteLogsSet": "", - "setModLogsSet": "", - "setPrefixSet": "", - "stickyRolesNotExists": "", - "stickyRolesReset": "", - "stickyRolesRemove": "", - "stickyRolesAdd": "", - "stickyRolesShowEmpty": "", - "stickyRolesShowSingle": "", - "createMuteDescription": "", - "createMuteExtended": { - "extendedHelp": "" - }, - "permissionNodesDescription": "", - "permissionNodesExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "managecommandautodeleteDescription": "", - "managecommandautodeleteExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageCommandChannelDescription": "", - "manageCommandChannelExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageReactionRolesDescription": "", - "manageReactionRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "rolesAdded": "", - "rolesAuditlog": "", - "rolesListEmpty": "", - "rolesListTitle": "", - "rolesNotManageable": "", - "rolesNotPublic": "", - "rolesRemoved": "", - "setIgnoreChannelsDescription": "", - "setIgnoreChannelsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setImageLogsDescription": "", - "setImageLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "setMemberAddLogsDescription": "", - "setMemberAddLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMemberRemoveLogsDescription": "", - "setMemberRemoveLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMessageUpdateLogsDescription": "", - "setMessageUpdateLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setMessageDeleteLogsDescription": "", - "setMessageDeleteLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setmodlogsDescription": "", - "setmodlogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setprefixDescription": "", - "setprefixExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "guildInfoDescription": "", - "guildInfoExtended": { - "extendedHelp": "" - }, - "roleInfoDescription": "", - "roleInfoExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "stickyRolesDescription": "", - "stickyRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesDescription": "", - "rolesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/el/commands/misc.json b/src/languages/el/commands/misc.json deleted file mode 100644 index 32f64d584..000000000 --- a/src/languages/el/commands/misc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "snipeEmpty": "", - "snipeTitle": "", - "snipeDescription": "", - "snipeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/el/commands/moderation.json b/src/languages/el/commands/moderation.json deleted file mode 100644 index 815d1c788..000000000 --- a/src/languages/el/commands/moderation.json +++ /dev/null @@ -1,889 +0,0 @@ -{ - "permissions": "", - "permissionsAll": "", - "slowmodeSet": "", - "slowmodeReset": "", - "banNotBannable": "", - "dehoistStarting": "", - "dehoistProgress": "", - "dehoistEmbed": { - "title": "", - "descriptionNoone": "", - "descriptionWithError": "", - "descriptionWithMultipleErrors": "", - "description": "", - "descriptionMultipleMembers": "", - "fieldErrorTitle": "" - }, - "kickNotKickable": "", - "lockdownLock": "", - "lockdownLocking": "", - "lockdownLocked": "", - "lockdownUnlocked": "", - "lockdownOpen": "", - "muteMuted": "", - "muteUserNotMuted": "", - "restrictLowlevel": "", - "pruneAlert_one": "", - "pruneAlert_other": "", - "pruneInvalidPosition": "", - "pruneNoDeletes": "", - "pruneLogHeader": "", - "toggleModerationDmToggledEnabled": "", - "toggleModerationDmToggledDisabled": "", - "moderationOutput_one": "", - "moderationOutput_other": "", - "moderationOutputWithReason_one": "", - "moderationOutputWithReason_other": "", - "moderationFailed_one": "", - "moderationFailed_other": "", - "moderationDmFooter": "", - "moderationDmDescription": "", - "moderationDmDescriptionWithReason": "", - "moderationDmDescriptionWithDuration": "", - "moderationDmDescriptionWithReasonWithDuration": "", - "slowmodeDescription": "", - "slowmodeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "banDescription": "", - "banExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "dehoistDescription": "", - "dehoistExtended": { - "extendedHelp": "", - "reminder": "" - }, - "kickDescription": "", - "kickExtended": { - "usages": [ - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "lockdownDescription": "", - "lockdownExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "muteDescription": "", - "muteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "setNicknameDescription": "", - "setNicknameExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ], - "reminder": "" - }, - "addRoleDescription": "", - "addRoleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "removeroleDescription": "", - "removeroleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "pruneDescription": "", - "pruneExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "permissionsDescription": "", - "permissionsExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ], - "extendedHelp": "" - }, - "restrictAttachmentDescription": "", - "restrictAttachmentExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictEmbedDescription": "", - "restrictEmbedExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictEmojiDescription": "", - "restrictEmojiExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictReactionDescription": "", - "restrictReactionExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictVoiceDescription": "", - "restrictVoiceExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "softBanDescription": "", - "softBanExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "timeoutApplyDescription": "", - "timeoutApplyExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutUndoDescription": "", - "timeoutUndoExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutNotModeratable": "", - "toggleModerationDmDescription": "", - "toggleModerationDmExtended": { - "extendedHelp": "" - }, - "unbanDescription": "", - "unbanExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unmuteDescription": "", - "unmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unrestrictAttachmentDescription": "", - "unrestrictAttachmentExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmbedDescription": "", - "unrestrictEmbedExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmojiDescription": "", - "unrestrictEmojiExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictReactionDescription": "", - "unrestrictReactionExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictVoiceDescription": "", - "unrestrictVoiceExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unwarnDescription": "", - "unwarnExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vmuteDescription": "", - "vmuteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "voiceKickDescription": "", - "voiceKickExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vunmuteDescription": "", - "vunmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "warnDescription": "", - "warnExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/el/commands/shared.json b/src/languages/el/commands/shared.json deleted file mode 100644 index ddbb28e7f..000000000 --- a/src/languages/el/commands/shared.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "deprecatedMessage": "", - "slashOnlyDetailedDescription": { - "extendedHelp": "" - }, - "slashOnlyErrorMessage": "" -} \ No newline at end of file diff --git a/src/languages/el/commands/system.json b/src/languages/el/commands/system.json deleted file mode 100644 index e9cfdeec4..000000000 --- a/src/languages/el/commands/system.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "evalDescription": "", - "evalExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "evalTimeout": "", - "evalError": "", - "dmNotSent": "", - "dmSent": "", - "reboot": "", - "rebootDescription": "", - "rebootExtended": { - "extendedHelp": "", - "reminder": "" - } -} \ No newline at end of file diff --git a/src/languages/el/commands/tools.json b/src/languages/el/commands/tools.json deleted file mode 100644 index 01bd03e25..000000000 --- a/src/languages/el/commands/tools.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "avatarDescription": "", - "avatarExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "" - }, - "avatarNone": "", - "voteDescription": "", - "voteExtended": { - "usages": [ - "" - ], - "examples": [ - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "voteContentNeeded": "", - "voteReactionBlocked": "", - "whoisExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "whoisMemberRoleListAndMore": "" -} \ No newline at end of file diff --git a/src/languages/el/commands/twitch.json b/src/languages/el/commands/twitch.json deleted file mode 100644 index 2f12e1b08..000000000 --- a/src/languages/el/commands/twitch.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "twitchSubscriptionStreamerNotFound": "", - "twitchSubscriptionStatusValues": [ - "", - "" - ], - "twitchSubscriptionInvalidStatus": "", - "twitchSubscriptionAddDuplicated": "", - "twitchSubscriptionAddSuccessOffline": "", - "twitchSubscriptionAddSuccessLive": "", - "twitchSubscriptionAddMessageForOfflineRequired": "", - "twitchSubscriptionRemoveOrResetEmpty": "", - "twitchSubscriptionRemoveStreamerNotSubscribed": "", - "twitchSubscriptionRemoveNotToProvidedChannel": "", - "twitchSubscriptionRemoveStreamerStatusNotMatch": "", - "twitchSubscriptionRemoveSuccessOffline": "", - "twitchSubscriptionRemoveSuccessLive": "", - "twitchSubscriptionResetSuccess_one": "", - "twitchSubscriptionResetSuccess_other": "", - "twitchSubscriptionShowStreamerNotSubscribed": "", - "twitchSubscriptionShowStatus": { - "live": "", - "offline": "" - }, - "twitchSubscriptionShowUnknownUser": "", - "twitchSubscriptionDescription": "", - "twitchSubscriptionExtended": { - "usages": [ - "", - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/el/commands/whois.json b/src/languages/el/commands/whois.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/el/commands/whois.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/el/errors.json b/src/languages/el/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/el/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/el/events/errors.json b/src/languages/el/events/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/el/events/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/el/events/guilds-logs.json b/src/languages/el/events/guilds-logs.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/el/events/guilds-logs.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/el/events/guilds-members.json b/src/languages/el/events/guilds-members.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/el/events/guilds-members.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/el/events/messages.json b/src/languages/el/events/messages.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/el/events/messages.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/el/events/moderation.json b/src/languages/el/events/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/el/events/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/el/events/noMentionSpam.json b/src/languages/el/events/noMentionSpam.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/el/events/noMentionSpam.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/el/events/reactions.json b/src/languages/el/events/reactions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/el/events/reactions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/el/events/twitch.json b/src/languages/el/events/twitch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/el/events/twitch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/el/fuzzySearch.json b/src/languages/el/fuzzySearch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/el/fuzzySearch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/el/globals.json b/src/languages/el/globals.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/el/globals.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/el/guilds.json b/src/languages/el/guilds.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/el/guilds.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/el/humanLevels.json b/src/languages/el/humanLevels.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/el/humanLevels.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/el/moderation.json b/src/languages/el/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/el/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/el/moderationActions.json b/src/languages/el/moderationActions.json deleted file mode 100644 index 4c440ae54..000000000 --- a/src/languages/el/moderationActions.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "actions": { - "addRole": "", - "ban": "", - "kick": "", - "mute": "", - "removeRole": "", - "restrictedAttachment": "", - "restrictedEmbed": "", - "restrictedEmoji": "", - "restrictedReact": "", - "restrictedVoice": "", - "setNickname": "", - "softban": "", - "vkick": "", - "vmute": "", - "warning": "" - }, - "actionCannotManageRoles": "", - "actionRoleNotConfigured": "", - "actionRoleHigherPosition": "", - "actionRoleManaged": "", - "applyNoReason": "", - "applyReason": "", - "requiredMember": "", - "revokeNoReason": "", - "revokeReason": "", - "setNicknameNoReasonRemoved": "", - "setNicknameNoReasonSet": "", - "setNicknameRemoved": "", - "setNicknameSet": "", - "setupMuteExists": "", - "setupTooManyRoles": "", - "sharedRoleSetupAsk": "", - "sharedRoleSetupNoMessage": "", - "sharedRoleSetupExisting": "", - "sharedRoleSetupExistingName": "", - "sharedRoleSetupNew": "", - "softbanNoReason": "", - "softbanReason": "", - "unSoftbanNoReason": "", - "unSoftbanReason": "" -} \ No newline at end of file diff --git a/src/languages/el/permissions.json b/src/languages/el/permissions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/el/permissions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/el/preconditions.json b/src/languages/el/preconditions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/el/preconditions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/el/selfModeration.json b/src/languages/el/selfModeration.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/el/selfModeration.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/el/serializers.json b/src/languages/el/serializers.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/el/serializers.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/el/settings.json b/src/languages/el/settings.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/el/settings.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/el/system.json b/src/languages/el/system.json deleted file mode 100644 index 073b9b683..000000000 --- a/src/languages/el/system.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "discordAbortError": "", - "fetchBansFail": "", - "helpTitles": { - "aliases": "", - "usages": "", - "extendedHelp": "", - "explainedUsage": "", - "possibleFormats": "", - "examples": "", - "reminders": "" - }, - "jumpTo": "", - "loading": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "prefixReminder": "" -} \ No newline at end of file diff --git a/src/languages/en-GB/arguments.json b/src/languages/en-GB/arguments.json deleted file mode 100644 index f5e3eea19..000000000 --- a/src/languages/en-GB/arguments.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "boolean_one": "", - "boolean_other": "", - "booleanError": "", - "booleanDisabled": "Disabled", - "booleanEnabled": "Enabled", - "booleanFalseOptions": [ - "false", - "f", - "no", - "n", - "off", - "disable", - "disabled", - "0", - "-" - ], - "booleanTrueOptions": [ - "true", - "t", - "yes", - "y", - "on", - "enable", - "enabled", - "1", - "+" - ], - "caseNoEntries": "", - "caseUnknownEntry": "", - "caseNotInThisGuild": "", - "caseLatestOptions": [ - "last", - "latest" - ], - "categoryChannelError": "", - "channelError": "", - "command": "I could not resolve `{{parameter}}` to a command! Make sure you typed its name or one of its aliases correctly!", - "commandMatch": "", - "dateError": "", - "dateFormats": "- `2016-11-24` (YYYY-MM-DD)\n- `2016-11-24T23:56` (YYYY-MM-DDTHH:mm)\n- `2016-11-24T23:56:12` (YYYY-MM-DDTHH:mm:ss)\n- `2016-11-24T23:56:12.000` (YYYY-MM-DDTHH:mm:ss.sss)\n\n> **Tip**: The last 3 formats accept `Z` at the end to mark the time as UTC. Alternatively, you can input your timezone's offset by adding `+HH:MM`, e.g. `+01:00`.", - "dateTooEarly": "", - "dateTooFar": "", - "dmChannelError": "", - "duration": "I could not resolve `{{parameter}}` to a valid duration, there are some of the valid formats:\n\n$t(arguments:durationFormats)", - "durationFormats": "- `4h` (4 hours).\n- `20m5s` (20 minutes and 5 seconds).\n- `\"1w 2d 16h 40m 10s\"` (1 week, 2 days, 16 hours, 40 minutes, and 10 seconds).", - "emojiError": "", - "floatError": "", - "floatTooLarge": "", - "floatTooSmall": "The parameter `{{parameter}}` is too low! It needs to be at least {{minimum}}!", - "guildChannelError": "", - "guildChannelMismatchingError": "", - "guildChannelMissingGuildError": "", - "guildPrivateThreadChannelError": "", - "guildPublicThreadChannelError": "", - "guildStageVoiceChannelError": "", - "guildTextChannelError": "", - "guildThreadChannelError": "", - "guildVoiceChannelError": "", - "hyperlinkError": "", - "integerError": "", - "integerTooLarge": "", - "integerTooSmall": "The parameter `{{parameter}}` is too low! It needs to be at least {{minimum}}!", - "invite": "I could not resolve `{{parameter}}` to a valid invite link, they have one of the following formats:\n\n- `https://discord​.gg/6gakFR2`.\n- `https://discord​.com/invite/6gakFR2`.\n- `https://discordapp​.com/invite/6gakFR2`.\n\n> **Tip**: You can omit the `https://` part, `discord​.gg/6gakFR2` is also accepted as a valid parameter.", - "language": "", - "memberError": "", - "memberMissingGuild": "I was not able to resolve `{{parameter}}` because this argument requires to be run in a server channel.", - "messageError": "", - "missing": "", - "newsChannel": "I could not resolve `{{parameter}}` to an announcement channel, please make sure you typed its name or ID correctly!\n\n> **Tip**: You can also mention it!", - "numberError": "", - "numberTooLarge": "", - "numberTooSmall": "The parameter `{{parameter}}` is too low! It needs to be at least {{minimum}}!", - "piece": "I could not resolve `{{parameter}}` to a piece! Make sure you typed its name or one of its aliases correctly!", - "rangeInvalid": "", - "rangeMax_other": "", - "rangeMax_one": "", - "resetPossibles": [ - "off", - "reset" - ], - "roleError": "", - "roleMissingGuild": "I was not able to resolve `{{parameter}}` because this argument requires to be run in a server channel.", - "snowflake": "I could not resolve `{{parameter}}` to a valid snowflake! They're numbers with 17 to 18 digits, for example, your message has a snowflake of `{{message.id}}`!", - "store": "", - "stringTooLong": "The parameter `{{parameter}}` is too long! It needs to have less than {{maximum}} character(s)!", - "stringTooShort": "The parameter `{{parameter}}` is too short! It needs to have at least {{minimum}} character(s)!", - "time": "I could not resolve `{{parameter}}` to a valid time!\n**Hint**: the following formats are supported:\n\n$t(arguments:durationFormats)\n$t(arguments:dateFormats)", - "timeSpan": "I could not resolve `{{parameter}}` to a valid duration, make sure you typed a valid integer or a duration formatted value. Some of the valid formats are:\n\n- `45` (45 seconds).\n$t(arguments:durationFormats)\n$t(arguments:dateFormats)", - "timeSpanTooBig": "The parameter `{{parameter}}` resolved to a duration longer than {{maximum, duration}}, which is not allowed!", - "timeSpanTooSmall": "The parameter `{{parameter}}` resolved to a duration shorter than {{minimum, duration}}, which is not allowed!", - "tooFewWinners": "", - "tooManyWinners": "", - "unavailable": "", - "userError": "", - "enumEmptyError": "", - "enumError": "" -} \ No newline at end of file diff --git a/src/languages/en-GB/assertions.json b/src/languages/en-GB/assertions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/en-GB/assertions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/en-GB/commands/admin.json b/src/languages/en-GB/commands/admin.json deleted file mode 100644 index b4d3f0e1a..000000000 --- a/src/languages/en-GB/commands/admin.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "confUpdated": "", - "confGetNoExt": "The key **{{key}}** does not seem to exist.", - "confGet": "The value for the key **{{key}}** is: `{{value}}`", - "confReset": "The key **{{key}}** has been reset to: `{{value}}`", - "confNochange": "The value for **{{key}}** was already that value.", - "confServerDescription": "Define per-server settings.", - "confServerExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "confServer": "**Server Setting {{key}}**\n{{list}}", - "confDashboardOnlyKey": "`{{key}}` can only be configured through the web dashboard ()", - "confSettingNotSet": "Not Set", - "rolesetDescription": "Manage unique role sets.", - "rolesetExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "add", - "Create a new roleset or add a role to an existing one." - ], - [ - "remove", - "Remove a role from an existing roleset." - ], - [ - "reset", - "Removes all roles from a roleset or, if not specified, all existing rolesets." - ], - [ - "list", - "Lists all rolesets." - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesetCreated": "", - "rolesetAdded": "", - "rolesetRemoved": "", - "rolesetResetEmpty": "", - "rolesetResetAll": "", - "rolesetResetNotExists": "", - "rolesetResetGroup": "", - "rolesetUpdated": "", - "rolesetNoRolesets": "", - "confMenuRenderAtFolder": "", - "confMenuRenderAtPiece": "", - "confMenuRenderNokeys": "", - "confMenuRenderSelect": "", - "confMenuRenderUpdate": "", - "confMenuRenderRemove": "", - "confMenuRenderReset": "", - "confMenuRenderUndo": "", - "confMenuRenderCvalue": "", - "confMenuRenderBack": "", - "confMenuInvalidKey": "", - "confMenuInvalidAction": "", - "confMenuSaved": "" -} \ No newline at end of file diff --git a/src/languages/en-GB/commands/animal.json b/src/languages/en-GB/commands/animal.json deleted file mode 100644 index af646b851..000000000 --- a/src/languages/en-GB/commands/animal.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "bunnyDescription": "", - "bunnyExtended": { - "extendedHelp": "" - }, - "bunnyEmbedData": { - "title": "", - "source": "" - }, - "dogDescription": "Cute doggos! ❤", - "dogExtended": { - "extendedHelp": "" - }, - "foxDescription": "Let me show you an image of a fox!", - "foxExtended": { - "extendedHelp": "" - }, - "kittyDescription": "KITTENS!", - "kittyExtended": { - "extendedHelp": "" - }, - "shibeDescription": "Cute shibas!", - "shibeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/en-GB/commands/auto-moderation.json b/src/languages/en-GB/commands/auto-moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/en-GB/commands/auto-moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/en-GB/commands/case.json b/src/languages/en-GB/commands/case.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/en-GB/commands/case.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/en-GB/commands/fun.json b/src/languages/en-GB/commands/fun.json deleted file mode 100644 index 7892e327d..000000000 --- a/src/languages/en-GB/commands/fun.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "escaperopeDescription": "", - "escaperopeExtended": { - "extendedHelp": "" - }, - "escaperopeOutput": "" -} \ No newline at end of file diff --git a/src/languages/en-GB/commands/game.json b/src/languages/en-GB/commands/game.json deleted file mode 100644 index ff1e27e2e..000000000 --- a/src/languages/en-GB/commands/game.json +++ /dev/null @@ -1,447 +0,0 @@ -{ - "c4Description": "Play Connect Four with somebody.", - "c4Extended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "c4Prompt": "", - "gamesBot": "", - "gamesNoPlayers": "", - "gamesProgress": "", - "gamesPromptDeny": "", - "gamesRepeat": "", - "gamesSelf": "", - "gamesTooManyOrFew": "", - "hgBloodbath": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgDay": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgNight": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hungerGamesDescription": "", - "hungerGamesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "examples": [ - "" - ], - "reminder": "" - }, - "hungerGamesResultDeaths_one": "", - "hungerGamesResultDeaths_other": "", - "hungerGamesResultHeaderBloodbath": "", - "hungerGamesResultHeaderMoon": "", - "hungerGamesResultHeaderSun": "", - "hungerGamesResultProceed": "", - "hungerGamesStop": "", - "hungerGamesWinner": "", - "ticTacToeDescription": "Play noughts and crosses with somebody.", - "ticTacToeDraw": "", - "ticTacToeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "ticTacToePrompt": "", - "ticTacToeTurn": "", - "ticTacToeWinner": "", - "triviaActiveGame": "", - "triviaDescription": "", - "triviaEmbedTitles": { - "difficulty": "", - "trivia": "" - }, - "triviaExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "triviaIncorrect": "", - "triviaInvalidCategory": "", - "triviaNoAnswer": "", - "triviaWinner": "" -} \ No newline at end of file diff --git a/src/languages/en-GB/commands/general.json b/src/languages/en-GB/commands/general.json deleted file mode 100644 index 5e16f992d..000000000 --- a/src/languages/en-GB/commands/general.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "helpAllFlag": "", - "helpCommandCount_one": "", - "helpCommandCount_other": "", - "helpData": { - "footer": "", - "title": "" - }, - "helpDescription": "", - "helpExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "reminder": "", - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "helpDm": "", - "helpNodm": "", - "v7Description": "", - "v7Extended": { - "extendedHelp": "" - }, - "v7Message": "", - "v7NayreMessage": "" -} \ No newline at end of file diff --git a/src/languages/en-GB/commands/info.json b/src/languages/en-GB/commands/info.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/en-GB/commands/info.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/en-GB/commands/management.json b/src/languages/en-GB/commands/management.json deleted file mode 100644 index 21ef26ce2..000000000 --- a/src/languages/en-GB/commands/management.json +++ /dev/null @@ -1,445 +0,0 @@ -{ - "commandHandlerAborted": "", - "permissionNodesHigher": "", - "permissionNodesCannotAllowEveryone": "", - "permissionNodesInvalidType": "", - "permissionNodesAdd": "", - "permissionNodesNodeNotExists": "", - "permissionNodesCommandNotExists": "", - "permissionNodesRemove": "", - "permissionNodesReset": "", - "permissionNodesShowName": "", - "permissionNodesShowAllow": "", - "permissionNodesShowDeny": "", - "guildInfoTitles": { - "CHANNELS": "", - "MEMBERS": "", - "OTHER": "" - }, - "guildInfoChannels": "", - "guildInfoChannelsAfkChannelText": "", - "guildInfoMembers": "", - "guildInfoOther": "", - "guildInfoBanner": "", - "guildInfoIcon": "", - "guildInfoSplash": "", - "guildInfoDiscoverySplash": "", - "roleInfoTitles": { - "PERMISSIONS": "" - }, - "roleInfoData": "", - "roleInfoAll": "", - "roleInfoNoPermissions": "", - "manageCommandAutoDeleteShowEmpty": "", - "manageCommandAutoDeleteShow": "", - "manageCommandAutoDeleteAdd": "", - "manageCommandAutoDeleteRemove": "", - "manageCommandAutoDeleteRemoveNotset": "", - "manageCommandAutoDeleteReset": "", - "manageCommandChannelShow": "", - "manageCommandChannelShowEmpty": "", - "manageCommandChannelAddAlreadyset": "", - "manageCommandChannelAdd": "", - "manageCommandChannelRemoveNotset": "", - "manageCommandChannelRemove": "", - "manageCommandChannelResetEmpty": "", - "manageCommandChannelReset": "", - "manageReactionRolesShowEmpty": "", - "manageReactionRolesAddChannel": "", - "manageReactionRolesAddPrompt": "", - "manageReactionRolesAddMissing": "", - "manageReactionRolesAdd": "", - "manageReactionRolesRemoveNotExists": "", - "manageReactionRolesRemove": "", - "manageReactionRolesResetEmpty": "", - "manageReactionRolesReset": "", - "configurationEquals": "", - "setIgnoreChannelsSet": "", - "setIgnoreChannelsRemoved": "", - "setImageLogsSet": "", - "setMemberAddLogsSet": "", - "setMemberRemoveLogsSet": "", - "setMessageUpdateLogsSet": "", - "setMessageDeleteLogsSet": "", - "setModLogsSet": "", - "setPrefixSet": "", - "stickyRolesNotExists": "", - "stickyRolesReset": "", - "stickyRolesRemove": "", - "stickyRolesAdd": "", - "stickyRolesShowEmpty": "", - "stickyRolesShowSingle": "", - "createMuteDescription": "", - "createMuteExtended": { - "extendedHelp": "" - }, - "permissionNodesDescription": "", - "permissionNodesExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "managecommandautodeleteDescription": "", - "managecommandautodeleteExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageCommandChannelDescription": "", - "manageCommandChannelExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageReactionRolesDescription": "", - "manageReactionRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "rolesAdded": "", - "rolesAuditlog": "", - "rolesListEmpty": "", - "rolesListTitle": "", - "rolesNotManageable": "", - "rolesNotPublic": "", - "rolesRemoved": "", - "setIgnoreChannelsDescription": "", - "setIgnoreChannelsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setImageLogsDescription": "", - "setImageLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "setMemberAddLogsDescription": "", - "setMemberAddLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMemberRemoveLogsDescription": "", - "setMemberRemoveLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMessageUpdateLogsDescription": "", - "setMessageUpdateLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setMessageDeleteLogsDescription": "", - "setMessageDeleteLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setmodlogsDescription": "", - "setmodlogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setprefixDescription": "", - "setprefixExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "guildInfoDescription": "", - "guildInfoExtended": { - "extendedHelp": "" - }, - "roleInfoDescription": "", - "roleInfoExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "stickyRolesDescription": "", - "stickyRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesDescription": "", - "rolesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/en-GB/commands/misc.json b/src/languages/en-GB/commands/misc.json deleted file mode 100644 index 32f64d584..000000000 --- a/src/languages/en-GB/commands/misc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "snipeEmpty": "", - "snipeTitle": "", - "snipeDescription": "", - "snipeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/en-GB/commands/moderation.json b/src/languages/en-GB/commands/moderation.json deleted file mode 100644 index 815d1c788..000000000 --- a/src/languages/en-GB/commands/moderation.json +++ /dev/null @@ -1,889 +0,0 @@ -{ - "permissions": "", - "permissionsAll": "", - "slowmodeSet": "", - "slowmodeReset": "", - "banNotBannable": "", - "dehoistStarting": "", - "dehoistProgress": "", - "dehoistEmbed": { - "title": "", - "descriptionNoone": "", - "descriptionWithError": "", - "descriptionWithMultipleErrors": "", - "description": "", - "descriptionMultipleMembers": "", - "fieldErrorTitle": "" - }, - "kickNotKickable": "", - "lockdownLock": "", - "lockdownLocking": "", - "lockdownLocked": "", - "lockdownUnlocked": "", - "lockdownOpen": "", - "muteMuted": "", - "muteUserNotMuted": "", - "restrictLowlevel": "", - "pruneAlert_one": "", - "pruneAlert_other": "", - "pruneInvalidPosition": "", - "pruneNoDeletes": "", - "pruneLogHeader": "", - "toggleModerationDmToggledEnabled": "", - "toggleModerationDmToggledDisabled": "", - "moderationOutput_one": "", - "moderationOutput_other": "", - "moderationOutputWithReason_one": "", - "moderationOutputWithReason_other": "", - "moderationFailed_one": "", - "moderationFailed_other": "", - "moderationDmFooter": "", - "moderationDmDescription": "", - "moderationDmDescriptionWithReason": "", - "moderationDmDescriptionWithDuration": "", - "moderationDmDescriptionWithReasonWithDuration": "", - "slowmodeDescription": "", - "slowmodeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "banDescription": "", - "banExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "dehoistDescription": "", - "dehoistExtended": { - "extendedHelp": "", - "reminder": "" - }, - "kickDescription": "", - "kickExtended": { - "usages": [ - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "lockdownDescription": "", - "lockdownExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "muteDescription": "", - "muteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "setNicknameDescription": "", - "setNicknameExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ], - "reminder": "" - }, - "addRoleDescription": "", - "addRoleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "removeroleDescription": "", - "removeroleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "pruneDescription": "", - "pruneExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "permissionsDescription": "", - "permissionsExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ], - "extendedHelp": "" - }, - "restrictAttachmentDescription": "", - "restrictAttachmentExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictEmbedDescription": "", - "restrictEmbedExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictEmojiDescription": "", - "restrictEmojiExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictReactionDescription": "", - "restrictReactionExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictVoiceDescription": "", - "restrictVoiceExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "softBanDescription": "", - "softBanExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "timeoutApplyDescription": "", - "timeoutApplyExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutUndoDescription": "", - "timeoutUndoExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutNotModeratable": "", - "toggleModerationDmDescription": "", - "toggleModerationDmExtended": { - "extendedHelp": "" - }, - "unbanDescription": "", - "unbanExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unmuteDescription": "", - "unmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unrestrictAttachmentDescription": "", - "unrestrictAttachmentExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmbedDescription": "", - "unrestrictEmbedExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmojiDescription": "", - "unrestrictEmojiExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictReactionDescription": "", - "unrestrictReactionExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictVoiceDescription": "", - "unrestrictVoiceExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unwarnDescription": "", - "unwarnExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vmuteDescription": "", - "vmuteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "voiceKickDescription": "", - "voiceKickExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vunmuteDescription": "", - "vunmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "warnDescription": "", - "warnExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/en-GB/commands/shared.json b/src/languages/en-GB/commands/shared.json deleted file mode 100644 index ddbb28e7f..000000000 --- a/src/languages/en-GB/commands/shared.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "deprecatedMessage": "", - "slashOnlyDetailedDescription": { - "extendedHelp": "" - }, - "slashOnlyErrorMessage": "" -} \ No newline at end of file diff --git a/src/languages/en-GB/commands/system.json b/src/languages/en-GB/commands/system.json deleted file mode 100644 index e9cfdeec4..000000000 --- a/src/languages/en-GB/commands/system.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "evalDescription": "", - "evalExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "evalTimeout": "", - "evalError": "", - "dmNotSent": "", - "dmSent": "", - "reboot": "", - "rebootDescription": "", - "rebootExtended": { - "extendedHelp": "", - "reminder": "" - } -} \ No newline at end of file diff --git a/src/languages/en-GB/commands/tools.json b/src/languages/en-GB/commands/tools.json deleted file mode 100644 index 7848eae1d..000000000 --- a/src/languages/en-GB/commands/tools.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "avatarDescription": "View somebody's avatar at full size.", - "avatarExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "As this command's name says, it shows somebody's avatar.", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "Use the --size flag to change the avatar's size." - }, - "avatarNone": "That user has not set an avatar.", - "voteDescription": "", - "voteExtended": { - "usages": [ - "" - ], - "examples": [ - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "voteContentNeeded": "", - "voteReactionBlocked": "", - "whoisExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "whoisMemberRoleListAndMore": "" -} \ No newline at end of file diff --git a/src/languages/en-GB/commands/twitch.json b/src/languages/en-GB/commands/twitch.json deleted file mode 100644 index 2f12e1b08..000000000 --- a/src/languages/en-GB/commands/twitch.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "twitchSubscriptionStreamerNotFound": "", - "twitchSubscriptionStatusValues": [ - "", - "" - ], - "twitchSubscriptionInvalidStatus": "", - "twitchSubscriptionAddDuplicated": "", - "twitchSubscriptionAddSuccessOffline": "", - "twitchSubscriptionAddSuccessLive": "", - "twitchSubscriptionAddMessageForOfflineRequired": "", - "twitchSubscriptionRemoveOrResetEmpty": "", - "twitchSubscriptionRemoveStreamerNotSubscribed": "", - "twitchSubscriptionRemoveNotToProvidedChannel": "", - "twitchSubscriptionRemoveStreamerStatusNotMatch": "", - "twitchSubscriptionRemoveSuccessOffline": "", - "twitchSubscriptionRemoveSuccessLive": "", - "twitchSubscriptionResetSuccess_one": "", - "twitchSubscriptionResetSuccess_other": "", - "twitchSubscriptionShowStreamerNotSubscribed": "", - "twitchSubscriptionShowStatus": { - "live": "", - "offline": "" - }, - "twitchSubscriptionShowUnknownUser": "", - "twitchSubscriptionDescription": "", - "twitchSubscriptionExtended": { - "usages": [ - "", - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/en-GB/commands/whois.json b/src/languages/en-GB/commands/whois.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/en-GB/commands/whois.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/en-GB/constants.ts b/src/languages/en-GB/constants.ts deleted file mode 100644 index 4baff2217..000000000 --- a/src/languages/en-GB/constants.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Handler } from '#lib/i18n/structures/Handler'; -import { TimeTypes } from '@sapphire/time-utilities'; - -export class ExtendedHandler extends Handler { - public constructor() { - super({ - name: 'en-GB', - duration: { - [TimeTypes.Year]: { - 1: 'year', - DEFAULT: 'years' - }, - [TimeTypes.Month]: { - 1: 'month', - DEFAULT: 'months' - }, - [TimeTypes.Week]: { - 1: 'week', - DEFAULT: 'weeks' - }, - [TimeTypes.Day]: { - 1: 'day', - DEFAULT: 'days' - }, - [TimeTypes.Hour]: { - 1: 'hour', - DEFAULT: 'hours' - }, - [TimeTypes.Minute]: { - 1: 'minute', - DEFAULT: 'minutes' - }, - [TimeTypes.Second]: { - 1: 'second', - DEFAULT: 'seconds' - } - } - }); - } -} diff --git a/src/languages/en-GB/errors.json b/src/languages/en-GB/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/en-GB/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/en-GB/events/errors.json b/src/languages/en-GB/events/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/en-GB/events/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/en-GB/events/guilds-logs.json b/src/languages/en-GB/events/guilds-logs.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/en-GB/events/guilds-logs.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/en-GB/events/guilds-members.json b/src/languages/en-GB/events/guilds-members.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/en-GB/events/guilds-members.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/en-GB/events/messages.json b/src/languages/en-GB/events/messages.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/en-GB/events/messages.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/en-GB/events/moderation.json b/src/languages/en-GB/events/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/en-GB/events/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/en-GB/events/noMentionSpam.json b/src/languages/en-GB/events/noMentionSpam.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/en-GB/events/noMentionSpam.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/en-GB/events/reactions.json b/src/languages/en-GB/events/reactions.json deleted file mode 100644 index 5683bd90a..000000000 --- a/src/languages/en-GB/events/reactions.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "filterFooter": "Filtered Reaction", - "filter": "{{REDCROSS}} Hey {{user}}, please do not add that reaction!" -} \ No newline at end of file diff --git a/src/languages/en-GB/events/twitch.json b/src/languages/en-GB/events/twitch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/en-GB/events/twitch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/en-GB/fuzzySearch.json b/src/languages/en-GB/fuzzySearch.json deleted file mode 100644 index 723d33949..000000000 --- a/src/languages/en-GB/fuzzySearch.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "aborted": "Successfully aborted the prompt.", - "invalidIndex": "That number was out of range. Aborting prompt.", - "invalidNumber": "I expected you to give me a (single digit) number, got a potato.", - "matches": "I found multiple matches! **Please select a number within 0 and {{matches}}**:\n{{codeblock}}\nWrite **ABORT** if you want to exit the prompt." -} \ No newline at end of file diff --git a/src/languages/en-GB/globals.json b/src/languages/en-GB/globals.json deleted file mode 100644 index 049785791..000000000 --- a/src/languages/en-GB/globals.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "default": "{{key}} has not been localised for en-GB yet.", - "defaultLanguage": "Default Language", - "no": "No", - "none": "None", - "unknown": "unknown", - "yes": "Yes", - "durationValue": "{{value, duration}}", - "numberValue": "{{value, number}}", - "numberCompactValue": "{{value, numberCompact}}", - "dateTimeValue": "{{value, dateTime}}", - "orListValue": "{{value, orList}}", - "dateFormat": "DD/MM/YYYY", - "dateFormatExplanation": "Day/Month/Year" -} \ No newline at end of file diff --git a/src/languages/en-GB/guilds.json b/src/languages/en-GB/guilds.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/en-GB/guilds.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/en-GB/humanLevels.json b/src/languages/en-GB/humanLevels.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/en-GB/humanLevels.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/en-GB/moderation.json b/src/languages/en-GB/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/en-GB/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/en-GB/moderationActions.json b/src/languages/en-GB/moderationActions.json deleted file mode 100644 index 4c440ae54..000000000 --- a/src/languages/en-GB/moderationActions.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "actions": { - "addRole": "", - "ban": "", - "kick": "", - "mute": "", - "removeRole": "", - "restrictedAttachment": "", - "restrictedEmbed": "", - "restrictedEmoji": "", - "restrictedReact": "", - "restrictedVoice": "", - "setNickname": "", - "softban": "", - "vkick": "", - "vmute": "", - "warning": "" - }, - "actionCannotManageRoles": "", - "actionRoleNotConfigured": "", - "actionRoleHigherPosition": "", - "actionRoleManaged": "", - "applyNoReason": "", - "applyReason": "", - "requiredMember": "", - "revokeNoReason": "", - "revokeReason": "", - "setNicknameNoReasonRemoved": "", - "setNicknameNoReasonSet": "", - "setNicknameRemoved": "", - "setNicknameSet": "", - "setupMuteExists": "", - "setupTooManyRoles": "", - "sharedRoleSetupAsk": "", - "sharedRoleSetupNoMessage": "", - "sharedRoleSetupExisting": "", - "sharedRoleSetupExistingName": "", - "sharedRoleSetupNew": "", - "softbanNoReason": "", - "softbanReason": "", - "unSoftbanNoReason": "", - "unSoftbanReason": "" -} \ No newline at end of file diff --git a/src/languages/en-GB/permissions.json b/src/languages/en-GB/permissions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/en-GB/permissions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/en-GB/preconditions.json b/src/languages/en-GB/preconditions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/en-GB/preconditions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/en-GB/selfModeration.json b/src/languages/en-GB/selfModeration.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/en-GB/selfModeration.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/en-GB/serializers.json b/src/languages/en-GB/serializers.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/en-GB/serializers.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/en-GB/settings.json b/src/languages/en-GB/settings.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/en-GB/settings.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/en-GB/system.json b/src/languages/en-GB/system.json deleted file mode 100644 index 6cd12e112..000000000 --- a/src/languages/en-GB/system.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "discordAbortError": "I had a small network error when messaging Discord. Please run this command again!", - "fetchBansFail": "Failed to fetch bans. Do I have the **{{ADMINISTRATOR, permissions}}** permission?", - "helpTitles": { - "aliases": "🖇️ | **Aliases**", - "usages": "📝 | **Command Usage**", - "extendedHelp": "🔍 | **Extended Help**", - "explainedUsage": "⚙ | **Explained usage**", - "possibleFormats": "🔢 | **Possible formats**", - "examples": "🔗 | **Examples**", - "reminders": "⏰ | **Reminder**" - }, - "jumpTo": "Jump to Message ►", - "loading": [ - "{{LOADING}} Watching hamsters run...", - "{{LOADING}} Finding people in hide-and-seek...", - "{{LOADING}} Trying to figure out this command...", - "{{LOADING}} Fetching data from the cloud...", - "{{LOADING}} Calibrating lenses...", - "{{LOADING}} Playing rock, paper, scissors...", - "{{LOADING}} Tuning in to the right frequencies...", - "{{LOADING}} Reticulating splines..." - ], - "prefixReminder": "The prefix in this server is currently set to `{{prefix}}`" -} \ No newline at end of file diff --git a/src/languages/en-US/arguments.json b/src/languages/en-US/arguments.json deleted file mode 100644 index a33c55db0..000000000 --- a/src/languages/en-US/arguments.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "boolean_one": "I could not resolve `{{parameter}}` to a boolean, the only possible values is: {{possibles}}", - "boolean_other": "I could not resolve `{{parameter}}` to a boolean, the possible values are: {{possibles, orList}}", - "booleanError": "I could not resolve `{{parameter}}` to a boolean, the only possible value is: {{possibles}}", - "booleanDisabled": "Disabled", - "booleanEnabled": "Enabled", - "booleanFalseOptions": [ - "false", - "f", - "no", - "n", - "off", - "disable", - "disabled", - "0", - "-" - ], - "booleanTrueOptions": [ - "true", - "t", - "yes", - "y", - "on", - "enable", - "enabled", - "1", - "+" - ], - "caseNoEntries": "I could not resolve `{{parameter}}` to a case, as there are no moderation cases in this server!", - "caseUnknownEntry": "I could not resolve `{{parameter}}` to a case, make sure you typed its number correctly!", - "caseNotInThisGuild": "I somehow resolved `{{parameter}}` to a case, but it is not from this server!", - "caseLatestOptions": [ - "last", - "latest" - ], - "categoryChannelError": "I could not resolve `{{parameter}}` to a category channel, please make sure you typed its name or ID correctly!", - "channelError": "I could not resolve `{{parameter}}` to a channel, make sure you typed its name or ID correctly!", - "command": "I could not resolve `{{parameter}}` to a command! Make sure you typed its name or one of its aliases correctly!", - "commandMatch": "I could not match `{{parameter}}` to a command nor category, these are some of the valid formats:\n\n- `ping` (matches the ping command only).\n- `management.*` (matches all commands under the **Management** category).\n- `management.configuration.*` (matches all commands under **Management** > **Configuration** sub-category).\n\n> **Hint**: When checking `{{commandContext.commandPrefix}}help`, the category of each command is located at the top of the embed.", - "dateError": "I could not resolve `{{parameter}}` to a date, there are some of the valid formats:\n\n$t(arguments:dateFormats)", - "dateFormats": "- `2016-11-24` (YYYY-MM-DD)\n- `2016-11-24T23:56` (YYYY-MM-DDTHH:mm)\n- `2016-11-24T23:56:12` (YYYY-MM-DDTHH:mm:ss)\n- `2016-11-24T23:56:12.000` (YYYY-MM-DDTHH:mm:ss.sss)\n\n> **Tip**: The last 3 formats accept `Z` at the end to mark the time as UTC. Alternatively, you can input your timezone's offset by adding `+HH:MM`, e.g. `+01:00`.", - "dateTooEarly": "The parameter `{{parameter}}` resolved to a date earlier than {{minimum, dateTime}}, which is not allowed!", - "dateTooFar": "The parameter `{{parameter}}` resolved to a date older than {{maximum, dateTime}}, which is not allowed!", - "dmChannelError": "I could not resolve `{{parameter}}` to a DM channel, make sure you typed its ID correctly!", - "duration": "I could not resolve `{{parameter}}` to a valid duration, there are some of the valid formats:\n\n$t(arguments:durationFormats)", - "durationFormats": "- `4h` (4 hours).\n- `20m5s` (20 minutes and 5 seconds).\n- `\"1w 2d 16h 40m 10s\"` (1 week, 2 days, 16 hours, 40 minutes, and 10 seconds).", - "emojiError": "I could not resolve `{{parameter}}` to a valid emoji, are you sure you used a valid twemoji (e.g. 🌊) or an emoji (e.g. {{GREENTICK}})?", - "floatError": "I could not resolve `{{parameter}}` to a number!", - "floatTooLarge": "The parameter `{{parameter}}` is too high! It needs to be at most {{maximum}}!", - "floatTooSmall": "The parameter `{{parameter}}` is too low! It needs to be at least {{minimum}}!", - "guildChannelError": "I could not resolve `{{parameter}}` to a channel from this server, please make sure you typed its name or ID correctly!", - "guildChannelMismatchingError": "The parameter `{{parameter}}` resolved to an incompatible channel type in this server, please try another channel!", - "guildChannelMissingGuildError": "I was not able to resolve `{{parameter}}` because this argument requires to be run in a server channel.", - "guildPrivateThreadChannelError": "I could not resolve `{{parameter}}` to a private thread channel, please make sure you typed its name or ID correctly!", - "guildPublicThreadChannelError": "I could not resolve `{{parameter}}` to a public thread channel, please make sure you typed its name or ID correctly!", - "guildStageVoiceChannelError": "I could not resolve `{{parameter}}` to a stage voice channel, please make sure you typed its name or ID correctly!", - "guildTextChannelError": "I could not resolve `{{parameter}}` to a text channel, please make sure you typed its name or ID correctly!\n\n> **Tip**: You can also mention it!", - "guildThreadChannelError": "I could not resolve `{{parameter}}` to a thread channel, please make sure you typed its name or ID correctly!", - "guildVoiceChannelError": "I could not resolve `{{parameter}}` to a voice channel, please make sure you typed its name or ID correctly!", - "hyperlinkError": "I could not resolve `{{parameter}}` to an hyperlink, they are usually formatted similarly as `https://discord.com`!", - "integerError": "I could not resolve `{{parameter}}` to an integer!", - "integerTooLarge": "The parameter `{{parameter}}` is too high! It needs to be at most {{maximum}}!", - "integerTooSmall": "The parameter `{{parameter}}` is too low! It needs to be at least {{minimum}}!", - "invite": "I could not resolve `{{parameter}}` to a valid invite link, they have one of the following formats:\n\n- `https://discord​.gg/6gakFR2`.\n- `https://discord​.com/invite/6gakFR2`.\n- `https://discordapp​.com/invite/6gakFR2`.\n\n> **Tip**: You can omit the `https://` part, `discord​.gg/6gakFR2` is also accepted as a valid parameter.", - "language": "I could not resolve `{{parameter}}` to a valid language code!\n**Hint**: the following are supported: {{possibles, list(conjunction)}}.\n\n> **Tip**: You can add more (or improve the existing ones) at !", - "memberError": "I could not resolve `{{parameter}}` to a member from this server, please make sure you typed their name or ID correctly!\n\n> **Tip**: You can also use mentions!", - "memberMissingGuild": "I was not able to resolve `{{parameter}}` because this argument requires to be run in a server channel.", - "messageError": "I could not resolve `{{parameter}}` to a message:\n\n- If you used an **ID** (e.g. `{{message.id}}`), make sure you copied the right ID from this channel (<#{{channel}}>), and not, for example, the author's ID.\n- If you used a **message link** (e.g. `{{message.url}}`), make sure it is from a channel from this server, and that both of us have permissions to read it.\n- You did not input a valid parameter, in that case, check the two above!", - "missing": "You need to write another parameter!\n\n> **Tip**: You can do `{{commandContext.commandPrefix}}help {{command.name}}` to find out how to use this command.", - "newsChannel": "I could not resolve `{{parameter}}` to an announcement channel, please make sure you typed its name or ID correctly!\n\n> **Tip**: You can also mention it!", - "numberError": "I could not resolve `{{parameter}}` to a number!", - "numberTooLarge": "The parameter `{{parameter}}` is too high! It needs to be at most {{maximum}}!", - "numberTooSmall": "The parameter `{{parameter}}` is too low! It needs to be at least {{minimum}}!", - "piece": "I could not resolve `{{parameter}}` to a piece! Make sure you typed its name or one of its aliases correctly!", - "rangeInvalid": "`{{parameter}}` must be a number or a range of numbers.", - "rangeMax_other": "`{{parameter}}` accepts a range of maximum {{maximum}} numbers", - "rangeMax_one": "`{{parameter}}` accepts a range of maximum {{maximum}} number", - "resetPossibles": [ - "off", - "reset" - ], - "roleError": "I could not resolve `{{parameter}}` to a role, please make sure you typed its name or ID correctly!\n\n> **Tip**: You can also mention it!", - "roleMissingGuild": "I was not able to resolve `{{parameter}}` because this argument requires to be run in a server channel.", - "snowflake": "I could not resolve `{{parameter}}` to a valid snowflake! They're numbers with 17 to 18 digits, for example, your message has a snowflake of `{{message.id}}`!", - "store": "I could not resolve `{{parameter}}` to a valid store!\n**Hint**: the following are supported: {{possibles, list(conjunction)}}.", - "stringTooLong": "The parameter `{{parameter}}` is too long! It needs to have less than {{maximum}} character(s)!", - "stringTooShort": "The parameter `{{parameter}}` is too short! It needs to have at least {{minimum}} character(s)!", - "time": "I could not resolve `{{parameter}}` to a valid time!\n**Hint**: the following formats are supported:\n\n$t(arguments:durationFormats)\n$t(arguments:dateFormats)", - "timeSpan": "I could not resolve `{{parameter}}` to a valid duration, make sure you typed a valid integer or a duration formatted value. Some of the valid formats are:\n\n- `45` (45 seconds).\n$t(arguments:durationFormats)\n$t(arguments:dateFormats)", - "timeSpanTooBig": "The parameter `{{parameter}}` resolved to a duration longer than {{maximum, duration}}, which is not allowed!", - "timeSpanTooSmall": "The parameter `{{parameter}}` resolved to a duration shorter than {{minimum, duration}}, which is not allowed!", - "tooFewWinners": "The parameter `{{parameter}}` resolved to a number that is too low, it must be at least 1!", - "tooManyWinners": "The parameter `{{parameter}}` resolved to a number that is too high, it must be at maximum 20!", - "unavailable": "Whoops! It seems I couldn't find a parser for a parameter, please contact my developers about it!", - "userError": "I could not resolve `{{parameter}}` to a user, please make sure you typed their ID correctly!\n\n> **Tip**: You can also use mentions!", - "enumEmptyError": "I was not able to resolve `{{parameter}}` because the list of possible values is empty.", - "enumError": "I could not resolve `{{parameter}}` to a valid value, the possible values are: {{possibles, orList}}" -} diff --git a/src/languages/en-US/assertions.json b/src/languages/en-US/assertions.json deleted file mode 100644 index 2c6c5fb39..000000000 --- a/src/languages/en-US/assertions.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "expectedNonThreadChannel": "Expected a regular text channel, but I received the thread channel {{channel}} instead." -} diff --git a/src/languages/en-US/colors.json b/src/languages/en-US/colors.json deleted file mode 100644 index c6f756c03..000000000 --- a/src/languages/en-US/colors.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "invalidBase10": "Color must be within the range 0 - 16777215 (0xFFFFFF), but received `{{value}}`.", - "invalidHexRed": "Invalid Red range. Must be between '00' and 'ff', but received `{{value}}`.", - "invalidHexGreen": "Invalid Green range. Must be between '00' and 'ff', but received `{{value}}`.", - "invalidHexBlue": "Invalid Blue range. Must be between '00' and 'ff', but received `{{value}}`.", - "invalidHslHue": "Invalid Hue range. Must be between 0 and 360, but received `{{value}}`.", - "invalidHslSaturation": "Invalid Saturation range. Must be between 0 and 100, but received `{{value}}`.", - "invalidHslLightness": "Invalid Lightness range. Must be between 0 and 100, but received `{{value}}`.", - "invalidRgbRed": "Invalid Red range. Must be between 0 and 255, but received `{{value}}`.", - "invalidRgbGreen": "Invalid Green range. Must be between 0 and 255, but received `{{value}}`.", - "invalidRgbBlue": "Invalid Blue range. Must be between 0 and 255, but received `{{value}}`." -} \ No newline at end of file diff --git a/src/languages/en-US/commands/admin.json b/src/languages/en-US/commands/admin.json deleted file mode 100644 index 237a7ea2d..000000000 --- a/src/languages/en-US/commands/admin.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "rolesetDescription": "Manage unique role sets.", - "rolesetExtended": { - "usages": [ - "set RoleSetName Role1 Role2 Role3...", - "remove RoleSetName Role1 Role2 Role3...", - "reset", - "reset RoleSetName", - "list", - "RoleSetName Role1 Role2 Role3" - ], - "extendedHelp": "A role set is a group of roles WolfStar identifies as unique for all members in the server, i.e. a roleset named `region` could have the roles `Africa`, `America`, `Asia`, and `Europe`, and members will only be able to have one of them. This is like a kind of \"rule\" that is applied in the three following situations:\n\n- When somebody claims a role via the `roles` command.\n- When somebody claims a role via reaction roles.\n- When somebody receives a role either manually or from another bot.", - "explainedUsage": [ - [ - "add", - "Create a new roleset or add a role to an existing one." - ], - [ - "remove", - "Remove a role from an existing roleset." - ], - [ - "reset", - "Removes all roles from a roleset or, if not specified, all existing rolesets." - ], - [ - "list", - "Lists all rolesets." - ], - [ - "auto", - "Adds or removes a roleset." - ], - [ - "RoleSetName", - "The name of the roleset" - ], - [ - "Role1 Role2 Role3", - "The roles to add to the roleset" - ] - ], - "examples": [ - "add regions America", - "add regions Africa America Asia Europe", - "remove regions America", - "reset", - "reset regions", - "list", - "regions America", - "regions Africa America Asia Europe" - ], - "reminder": "This command can add and/or remove multiple roles at the same time." - }, - "rolesetCreated": "The {{name}} unique role set has been created with the following roles: {{roles, list(conjunction)}}", - "rolesetAdded": "Updated the {{name}} unique role set, it now has the following roles: {{roles, list(conjunction)}}.", - "rolesetRemoved": "The {{name}} unique role set will no longer include the following roles: {{roles, list(conjunction)}}", - "rolesetResetEmpty": "{{REDCROSS}} There are no rolesets configured in this group.", - "rolesetResetAll": "{{GREENTICK}} Successfully removed all rolesets.", - "rolesetResetNotExists": "{{REDCROSS}} The roleset `{{name}}` does not exist in this server.", - "rolesetResetGroup": "{{GREENTICK}} Successfully removed the roleset `{{name}}` from this server.", - "rolesetUpdated": "The {{name}} unique role set has been updated.", - "rolesetNoRolesets": "You have no rolesets." -} diff --git a/src/languages/en-US/commands/auto-moderation.json b/src/languages/en-US/commands/auto-moderation.json deleted file mode 100644 index 0e111ce72..000000000 --- a/src/languages/en-US/commands/auto-moderation.json +++ /dev/null @@ -1,77 +0,0 @@ -{ - "showName": "show", - "showDescription": "Show the current configuration for this server", - "editName": "edit", - "editDescription": "Edit the configuration for this server", - "resetName": "reset", - "resetDescription": "Reset a configuration key to its default value", - "addName": "add", - "removeName": "remove", - "optionsEnabledName": "enabled", - "optionsEnabledDescription": "Toggle the sub-system", - "optionsActionAlertName": "alert", - "optionsActionAlertDescription": "Toggle message alerts in the channel", - "optionsActionLogName": "log", - "optionsActionLogDescription": "Toggle message logs in the moderation logs channel, if set", - "optionsActionDeleteName": "delete", - "optionsActionDeleteDescription": "Toggle message deletions", - "optionsPunishmentName": "punishment", - "optionsPunishmentDescription": "Set the moderation action to take after the threshold is reached", - "optionsPunishmentDurationName": "punishment-duration", - "optionsPunishmentDurationDescription": "Set the duration for the punishment", - "optionsThresholdName": "threshold", - "optionsThresholdDescription": "Set the amount of infractions allowed within the set period", - "optionsThresholdPeriodName": "threshold-period", - "optionsThresholdPeriodDescription": "Set the time in which infractions will accumulate", - "optionsKeyName": "key", - "optionsKeyDescription": "The key to reset", - "optionsKeyEnabled": "Enabled", - "optionsKeyActionAlert": "Alert Messages", - "optionsKeyActionLog": "Post Moderation Logs", - "optionsKeyActionDelete": "Message Deletions", - "optionsKeyPunishment": "Punishment", - "optionsKeyPunishmentDuration": "Punishment Duration", - "optionsKeyThreshold": "Punishment Threshold", - "optionsKeyThresholdPeriod": "Punishment Threshold Period", - "optionsKeyWords": "Words", - "optionsWordName": "word", - "optionsWordDescription": "The word to add or remove", - "attachmentsName": "automod-attachments", - "attachmentsDescription": "Manage the auto-moderator for attachments", - "capitalsName": "automod-capitals", - "capitalsDescription": "Manage the auto-moderator for capitalization", - "wordsName": "automod-words", - "wordsDescription": "Manage the auto-moderator for words", - "invitesName": "automod-invites", - "invitesDescription": "Manage the auto-moderator for invites", - "linksName": "automod-links", - "linksDescription": "Manage the auto-moderator for links", - "spamName": "automod-spam", - "spamDescription": "Manage the auto-moderator for spam", - "newlinesName": "automod-newlines", - "newlinesDescription": "Manage the auto-moderator for lines", - "reactionsName": "automod-reactions", - "reactionsDescription": "Manage the auto-moderator for reactions", - "showDisabled": "Auto-moderator inactive", - "showEnabled": "Auto-moderator active", - "showReplyActive": "{{emoji}} **Alert Messages**", - "showReplyInactive": "{{emoji}} ~~Alert Messages~~", - "showLogActive": "{{emoji}} **Post Moderation Logs**", - "showLogInactive": "{{emoji}} ~~Post Moderation Logs~~", - "showDeleteActive": "{{emoji}} **Message Deletions**", - "showDeleteInactive": "{{emoji}} ~~Message Deletions~~", - "showPunishmentTitle": "Punishment active", - "showPunishment": "{{emoji}} **Type:** {{name}}", - "showPunishmentTemporary": "{{emoji}} **Type:** {{name}} for {{duration}}", - "showPunishmentThreshold": "{{emoji}} **Applies after:** {{threshold, number}} infractions within {{period}}", - "editSuccess": "Successfully edited the auto-moderator's settings.", - "wordAddDescription": "Add a word to the filter list", - "wordAddFiltered": "The word `{{word}}` was already on the filter list.", - "wordRemoveDescription": "Remove a word from the filter list", - "wordRemoveNotFiltered": "The word `{{word}}` was not on the filter list.", - "wordShowList": "{{words, list(conjunction)}}", - "wordShowListTitle_one": "Filtered Word ({{count, number}})", - "wordShowListTitle_other": "Filtered Words ({{count, number}})", - "wordShowListEmpty": "Please use {{command}} to add words to the filter list.", - "wordShowListTitleEmpty": "No words are currently filtered" -} diff --git a/src/languages/en-US/commands/case.json b/src/languages/en-US/commands/case.json deleted file mode 100644 index fb13285f7..000000000 --- a/src/languages/en-US/commands/case.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "name": "case", - "description": "Manage or view moderation cases.", - "viewName": "view", - "viewDescription": "Retrieve a moderation case's information.", - "archiveName": "archive", - "archiveDescription": "Archive a moderation case.", - "deleteName": "delete", - "deleteDescription": "Delete a moderation case.", - "editName": "edit", - "editDescription": "Edit a moderation case.", - "listName": "list", - "listDescription": "List the moderation cases.", - "optionsCaseName": "case", - "optionsCaseDescription": "The number of the moderation case.", - "optionsReasonName": "reason", - "optionsReasonDescription": "The new reason for the moderation case.", - "optionsDurationName": "duration", - "optionsDurationDescription": "The new duration for the moderation case.", - "optionsUserName": "user", - "optionsUserDescription": "The user to filter the moderation cases by.", - "optionsOverviewName": "overview", - "optionsOverviewDescription": "Whether or not to show the overview of the moderation cases.", - "optionsTypeName": "type", - "optionsTypeDescription": "The type to filter the moderation cases by.", - "optionsPendingOnlyName": "pending-only", - "optionsPendingOnlyDescription": "Whether or not to show only the pending moderation cases.", - "optionsShowName": "show", - "optionsShowDescription": "Whether or not to show the response publicly.", - "timeNotAllowed": "The type of the moderation case (**{{type}}**) does not allow for a duration.", - "timeNotAllowedInCompletedEntries": "The moderation case `{{caseId}}` has already been completed and cannot be edited.", - "timeEditNotSupported": "The type of the moderation case (**{{type}}**) does not allow editing the duration.", - "timeTooEarly": "The duration of the moderation case would end before it starts ({{time}}). The duration starts at {{start}}.", - "listEmpty": "There are no moderation cases with the selected filters.", - "listDetailsTitle_one": "There is 1 entry.", - "listDetailsTitle_other": "There are {{count}} entries.", - "listDetailsModerator": "{{emoji}} **Moderator:** {{mention}} ({{userId}})", - "listDetailsUser": "{{emoji}} **User:** {{mention}} ({{userId}})", - "listDetailsExpires": "{{emoji}} **Expires {{time}}**", - "listOverviewFooter": "This server has {{warnings}}, {{mutes}}, {{timeouts}}, {{kicks}}, and {{bans}}", - "listOverviewFooterUser": "This user has {{warnings}}, {{mutes}}, {{timeouts}}, {{kicks}}, and {{bans}}", - "listOverviewFooterWarning_one": "{{count}} warning", - "listOverviewFooterWarning_other": "{{count}} warnings", - "listOverviewFooterMutes_one": "{{count}} mute", - "listOverviewFooterMutes_other": "{{count}} mutes", - "listOverviewFooterTimeouts_one": "{{count}} timeout", - "listOverviewFooterTimeouts_other": "{{count}} timeouts", - "listOverviewFooterKicks_one": "{{count}} kick", - "listOverviewFooterKicks_other": "{{count}} kicks", - "listOverviewFooterBans_one": "{{count}} ban", - "listOverviewFooterBans_other": "{{count}} bans", - "editSuccess": "Successfully edited case {{caseId}}.", - "archiveSuccess": "Successfully archived case {{caseId}}.", - "deleteSuccess": "Successfully deleted case {{caseId}}." -} diff --git a/src/languages/en-US/commands/conf.json b/src/languages/en-US/commands/conf.json deleted file mode 100644 index ee66c7c4c..000000000 --- a/src/languages/en-US/commands/conf.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "name": "conf", - "description": "Define per-server settings.", - "menuName": "menu", - "menuDescription": "Open an interactive settings menu", - "showName": "show", - "showDescription": "Show current settings or a specific key", - "setName": "set", - "setDescription": "Set a value for a configuration key", - "removeName": "remove", - "removeDescription": "Remove a value from a configuration key", - "resetName": "reset", - "resetDescription": "Reset a configuration key to its default value", - "optionsKeyName": "key", - "optionsKeyDescription": "The configuration key to modify", - "optionsValueName": "value", - "optionsValueDescription": "The value to set or remove", - "updated": "Successfully updated the key **{{key}}**: {{response}}", - "getNoExt": "The key **{{key}}** does not seem to exist.", - "get": "The value for the key **{{key}}** is: `{{value}}`", - "resetSuccess": "The key **{{key}}** has been reset to: `{{value}}`", - "nochange": "The value for **{{key}}** was already that value.", - "server": "Settings{{key}}:\n{{list}}", - "serverDescription": "Define per-server settings.", - "serverExtended": { - "usages": [ - "set NameOfKey Value for Key", - "show", - "show NameOfKey", - "remove NameOfKey Value for Key", - "reset NameOfKey", - "menu" - ], - "extendedHelp": "Allows you to configure WolfStar from Discord, as a quick alternative to the [web dashboard](https://wolfstar.rocks).", - "examples": [ - "set language en-GB", - "set channels.moderation-logs #moderation-logs", - "show", - "show channels", - "remove roles.moderator Moderator", - "reset roles.moderator", - "menu" - ], - "reminder": "There are keys and groups, keys that are within a group are named by `GroupName.KeyName`." - }, - "menuRenderAtFolder": "Currently at: 📁 {{path}}", - "menuRenderAtPiece": "Currently at: ⚙️ {{path}}", - "menuRenderNokeys": "There are no configurable keys for this folder", - "menuRenderSelect": "Please type in any of the following entries' names", - "menuRenderUpdate": "• Update Value → `set `", - "menuRenderRemove": "• Remove Value → `remove `", - "menuRenderReset": "• Reset Value → `reset`", - "menuRenderUndo": "• Undo Update → `undo`", - "menuRenderCvalue": "Current Value: **``{{value}}``**", - "menuRenderBack": "Press ◀ to go back", - "menuInvalidKey": "Invalid Key, please try again with any of the following options.", - "menuInvalidAction": "Invalid Action, please try again with any of the following options.", - "menuSaved": "Successfully saved all changes." - -} diff --git a/src/languages/en-US/commands/fun.json b/src/languages/en-US/commands/fun.json deleted file mode 100644 index 3c66e34f0..000000000 --- a/src/languages/en-US/commands/fun.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "escaperopeDescription": "Use the escape rope from Pokemon.", - "escaperopeExtended": { - "extendedHelp": "**WolfStar** used **Escape Rope**." - }, - "escaperopeOutput": "**{{user}}** used **Escape Rope**" -} diff --git a/src/languages/en-US/commands/game.json b/src/languages/en-US/commands/game.json deleted file mode 100644 index 3c0a2138c..000000000 --- a/src/languages/en-US/commands/game.json +++ /dev/null @@ -1,447 +0,0 @@ -{ - "c4Description": "Play Connect-Four with somebody.", - "c4Extended": { - "usages": [ - "User" - ], - "extendedHelp": "This game is best played on PC.\nConnect Four is a two-player connection game in which the players first choose a color and then take turns dropping colored discs from the top into a seven-column, six-row vertically suspended grid.", - "examples": [ - "WolfStar" - ] - }, - "c4Prompt": "Dear {{challengee}}, you have been challenged by {{challenger}} in a Connect-Four match. Click the 🇾 reaction to accept!", - "gamesBot": "I am sorry, but I do not think they would like to stop doing what they are doing and play with humans.", - "gamesNoPlayers": "Please specify some tributes to play the Hunger Games, like so: `{{prefix}}hg Bob, Mark, Jim, Kyra`", - "gamesProgress": "I am sorry, but there is a game in progress in this channel, try again when it finishes.", - "gamesPromptDeny": "I am sorry, but the challengee refused to play.", - "gamesRepeat": "I am sorry, but a user cannot play twice.", - "gamesSelf": "You must be so sad to play against yourself. Try again with another user.", - "gamesTooManyOrFew": "I am sorry but the amount of players is less than {{min}} or greater than {{max}}.", - "hgBloodbath": [ - "{1} grabs a shovel.", - "{1} grabs a backpack and retreats.", - "{1} and {2} fight for a bag. {1} gives up and retreats.", - "{1} and {2} fight for a bag. {2} gives up and retreats.", - "{1} finds a bow, some arrows, and a quiver.", - "{1} runs into the cornucopia and hides.", - "{1} takes a handful of throwing knives.", - "{1} rips a mace out of {2}'s hands.", - "{1} finds a canteen full of water.", - "{1} stays at the cornucopia for resources.", - "{1} gathers as much food as they can.", - "{1} grabs a sword.", - "{1} takes a spear from inside the cornucopia.", - "{1} finds a bag full of explosives.", - "{1} clutches a first aid kit and runs away.", - "{1} takes a sickle from inside the cornucopia.", - "{1}, {2}, and {3} work together to get as many supplies as possible.", - "{1} runs away with a lighter and some rope.", - "{1} snatches a bottle of alcohol and a rag.", - "{1} finds a backpack full of camping equipment.", - "{1} grabs a backpack, not realizing it is empty.", - "{1} breaks {2}'s nose for a basket of bread.", - "{1}, {2}, {3}, and {4} share everything they gathered before running.", - "{1} retrieves a trident from inside the cornucopia.", - "{1} grabs a jar of fishing bait while {2} gets fishing gear.", - "{1} scares {2} away from the cornucopia.", - "{1} grabs a shield leaning on the cornucopia.", - "{1} snatches a pair of sais.", - "{1} grabs a lone pair of pants.", - "{1T} steps off their podium too soon and blows up.", - "{1} throws a knife into {2T}'s head.", - "{1T} accidently steps on a landmine.", - "{1} catches {2T} off guard and kills them.", - "{1} and {2} work together to drown {3T}.", - "{1} strangles {2T} after engaging in a fist fight.", - "{1} shoots an arrow into {2T}'s head.", - "{1T} cannot handle the circumstances and commits suicide.", - "{1} bashes {2T}'s head against a rock several times.", - "{1} snaps {2T}'s neck.", - "{1} decapitates {2T} with a sword.", - "{1} spears {2T} in the abdomen.", - "{1} sets {2T} on fire with a molotov.", - "{1T} falls into a pit and dies.", - "{1} stabs {2T} while their back is turned.", - "{1} severely injures {2T}, but puts them out of their misery.", - "{1} severely injures {2T} and leaves them to die.", - "{1} bashes {2T}'s head in with a mace.", - "{1} pushes {2T} off a cliff during a knife fight.", - "{1} throws a knife into {2T}'s chest.", - "{1T} is unable to convince {2} to not kill them.", - "{1} convinces {2T} to not kill them, only to kill {2T} instead.", - "{1T} falls into a frozen lake and drowns.", - "{1}, {2}, and {3T} start fighting, but {2} runs away as {1} kills {3T}.", - "{1} kills {2T} with their own weapon.", - "{1} overpowers {2T}, killing them.", - "{1} sets an explosive off, killing {2T}.", - "{1} sets an explosive off, killing {2T}, and {3T}.", - "{1} sets an explosive off, killing {2T}, {3T}, and {4T}.", - "{1} sets an explosive off, killing {2T}, {3T}, {4T} and {5T}.", - "{1} kills {2T} as they try to run.", - "{1T} and {2T} threaten a double suicide. It fails and they die.", - "{1T}, {2T}, {3T}, and {4T} form a suicide pact, killing themselves.", - "{1} kills {2T} with a hatchet.", - "{1} and {2} fight {3T} and {4T}. {1} and {2} survive.", - "{1T} and {2T} fight {3} and {4}. {3} and {4} survive.", - "{1T} attacks {2}, but {3} protects them, killing {1T}.", - "{1} severely slices {2T} with a sword.", - "{1} strangles {2T} with a rope.", - "{1} kills {2T} for their supplies.", - "{1} shoots an arrow at {2}, but misses and kills {3T} instead.", - "{1} shoots a poisonous blow dart into {2T}'s neck, slowly killing them.", - "{1} stabs {2T} with a tree branch.", - "{1} stabs {2T} in the back with a trident.", - "{1}, {2T}, and {3T} get into a fight. {1} triumphantly kills them both.", - "{1T}, {2}, and {3T} get into a fight. {2} triumphantly kills them both.", - "{1T}, {2T}, and {3} get into a fight. {3} triumphantly kills them both.", - "{1} finds {2T} hiding in the cornucopia and kills them.", - "{1T} finds {2} hiding in the cornucopia, but {2} kills them.", - "{1} kills {2T} with a sickle.", - "{1} and {2T} fight for a bag. {1} strangles {2T} with the straps and runs.", - "{1T} and {2} fight for a bag. {2} strangles {1T} with the straps and runs.", - "{1} repeatedly stabs {2T} to death with sais.", - "{1T} trips over while running from the cornucopia, and is killed by {2}.", - "{1} trips over while running from the cornucopia, {2} picks them up, they run off together.", - "{1} aims an arrow at {2}'s head and shoots, {3T} jumps in the way and sacrifies their life to save them." - ], - "hgDay": [ - "{1} goes hunting.", - "{1} injures themself.", - "{1} explores the arena.", - "{1} scares {2} off.", - "{1} diverts {2}'s attention and runs away.", - "{1} stalks {2}.", - "{1} fishes.", - "{1} camouflauges themself in the bushes.", - "{1} steals from {2} while they aren't looking.", - "{1} makes a wooden spear.", - "{1} discovers a cave.", - "{1} attacks {2}, but they manage to escape.", - "{1} chases {2}.", - "{1} runs away from {2}.", - "{1} collects fruit from a tree.", - "{1} receives a hatchet from an unknown sponsor.", - "{1} receives clean water from an unknown sponsor.", - "{1} receives medical supplies from an unknown sponsor.", - "{1} receives fresh food from an unknown sponsor.", - "{1} searches for a water source.", - "{1} defeats {2} in a fight, but spares their life.", - "{1} and {2} work together for the day.", - "{1} begs for {2} to kill them. They refuse, keeping {1} alive.", - "{1} tries to sleep through the entire day.", - "{1}, {2}, {3}, and {4} raid {5}'s camp while they are hunting.", - "{1} constructs a shack.", - "{1} overhears {2} and {3} talking in the distance.", - "{1} practices their archery.", - "{1} thinks about home.", - "{1} is pricked by thorns while picking berries.", - "{1} tries to spear fish with a trident.", - "{1} searches for firewood.", - "{1} and {2} split up to search for resources.", - "{1} picks flowers.", - "{1} tends to {2}'s wounds.", - "{1} sees smoke rising in the distance, but decides not to investigate.", - "{1} sprains their ankle while running away from {2}.", - "{1} makes a slingshot.", - "{1} travels to higher ground.", - "{1} discovers a river.", - "{1} hunts for other tributes.", - "{1} and {2} hunt for other tributes.", - "{1}, {2}, and {3} hunt for other tributes.", - "{1}, {2}, {3}, and {4} hunt for other tributes.", - "{1}, {2}, {3}, {4}, and {5} hunt for other tributes.", - "{1} receives an explosive from an unknown sponsor.", - "{1} questions their sanity.", - "{1} forces {2} to eat pant.", - "{1} forces {2T} to eat pant. {2T} chokes and dies.", - "{1} catches {2T} off guard and kills them.", - "{1} throws a knife into {2T}'s head.", - "{1T} begs for {2} to kill them. They reluctantly oblige, killing {1T}.", - "{1} and {2} work together to drown {3T}.", - "{1} strangles {2T} after engaging in a fist fight.", - "{1} shoots an arrow into {2T}'s head.", - "{1T} bleeds out due to untreated injuries.", - "{1T} cannot handle the circumstances and commits suicide.", - "{1} bashes {2T}'s head against a rock several times.", - "{1T} unknowingly eats toxic berries.", - "{1} silently snaps {2T}'s neck.", - "{1} taints {2T}'s food, killing them.", - "{1} decapitates {2T} with a sword.", - "{1T} dies from an infection.", - "{1} spears {2T} in the abdomen.", - "{1} sets {2T} on fire with a molotov.", - "{1T} falls into a pit and dies.", - "{1} stabs {2T} while their back is turned.", - "{1} severely injures {2T}, but puts them out of their misery.", - "{1} severely injures {2T} and leaves them to die.", - "{1} bashes {2T}'s head in with a mace.", - "{1T} attempts to climb a tree, but falls to their death.", - "{1} pushes {2T} off a cliff during a knife fight.", - "{1} throws a knife into {2T}'s chest.", - "{1}'s trap kills {2T}.", - "{1} kills {2T} while they are resting.", - "{1T} is unable to convince {2} to not kill them.", - "{1} convinces {2T} to not kill them, only to kill {2T} instead.", - "{1T} falls into a frozen lake and drowns.", - "{1}, {2}, and {3T} start fighting, but {2} runs away as {1} kills {3T}.", - "{1} kills {2T} with their own weapon.", - "{1} overpowers {2T}, killing them.", - "{1} sets an explosive off, killing {2T}.", - "{1} sets an explosive off, killing {2T}, and {3T}.", - "{1} sets an explosive off, killing {2T}, {3T}, and {4T}.", - "{1} sets an explosive off, killing {2T}, {3T}, {4T} and {5T}.", - "{1} kills {2T} as they try to run.", - "{1T} and {2T} threaten a double suicide. It fails and they die.", - "{1T}, {2T}, {3T}, and {4T} form a suicide pact, killing themselves.", - "{1T} dies from hypothermia.", - "{1T} dies from hunger.", - "{1T} dies from thirst.", - "{1} kills {2T} with a hatchet.", - "{1} and {2} fight {3T} and {4T}. {1} and {2} survive.", - "{1T} and {2T} fight {3} and {4}. {3} and {4} survive.", - "{1T} dies trying to escape the arena.", - "{1T} dies of dysentery.", - "{1T} accidently detonates a land mine while trying to arm it.", - "{1T} attacks {2}, but {3} protects them, killing {1T}.", - "{1} ambushes {2T} and kills them.", - "{1T} accidently steps on a landmine.", - "{1} severely slices {2T} with a sword.", - "{1} strangles {2T} with a rope.", - "{1} kills {2T} for their supplies.", - "{1} shoots an arrow at {2}, but misses and kills {3T} instead.", - "{1} shoots a poisonous blow dart into {2T}'s neck, slowly killing them.", - "{1}, {2}, and {3} successfully ambush and kill {4T}, {5T}, and {6T}.", - "{1T}, {2T}, and {3T} unsuccessfully ambush {4}, {5}, and {6}, who kill them instead.", - "{1} stabs {2T} with a tree branch.", - "{1} forces {2} to kill {3T} or {4}. They decide to kill {3T}.", - "{1} forces {2} to kill {3} or {4T}. They decide to kill {4T}.", - "{1} forces {2T} to kill {3} or {4}. They refuse to kill, so {1} kills them instead.", - "{1T} poisons {2}'s drink, but mistakes it for their own and dies.", - "{1} poisons {2T}'s drink. They drink it and die.", - "{1} stabs {2T} in the back with a trident.", - "{1T} attempts to climb a tree, but falls on {2T}, killing them both.", - "{1}, {2T}, and {3T} get into a fight. {1} triumphantly kills them both.", - "{1T}, {2}, and {3T} get into a fight. {2} triumphantly kills them both.", - "{1T}, {2T}, and {3} get into a fight. {3} triumphantly kills them both.", - "{1} kills {2T} with a sickle.", - "{1}, {2}, {3}, {4}, and {5} track down and kill {6T}.", - "{1}, {2}, {3}, and {4} track down and kill {5T}.", - "{1}, {2}, and {3} track down and kill {4T}.", - "{1} and {2} track down and kill {3T}.", - "{1} tracks down and kills {2T}.", - "{1} repeatedly stabs {2T} to death with sais.", - "{1} doodles in the dirt.", - "{1} chases a butterfly.", - "{1T} falls off a cliff, and is impaled by a stick.", - "{1} runs into {2}, they decide to team up.", - "{1} sees {2} through the trees, and plans on killing them.", - "{1} sneaks up behind {2T}, and snaps their neck.", - "{1T} challenges {2} to a fight, and promptly dies.", - "{1} murders their partner, {2T}, to have more supplies for themself." - ], - "hgNight": [ - "{1} starts a fire.", - "{1} sets up camp for the night.", - "{1} loses sight of where they are.", - "{1} climbs a tree to rest.", - "{1} goes to sleep.", - "{1} and {2} tell stories about themselves to each other.", - "{1}, {2}, {3}, and {4} sleep in shifts.", - "{1}, {2}, and {3} sleep in shifts.", - "{1} and {2} sleep in shifts.", - "{1} tends to their wounds.", - "{1} sees a fire, but stays hidden.", - "{1} screams for help.", - "{1} stays awake all night.", - "{1} passes out from exhaustion.", - "{1} cooks their food before putting their fire out.", - "{1} and {2} run into each other and decide to truce for the night.", - "{1} fends {2}, {3}, and {4} away from their fire.", - "{1}, {2}, and {3} discuss the games and what might happen in the morning.", - "{1} cries themself to sleep.", - "{1} tries to treat their infection.", - "{1} and {2} talk about the tributes still alive.", - "{1} is awoken by nightmares.", - "{1} and {2} huddle for warmth.", - "{1} thinks about winning.", - "{1}, {2}, {3}, and {4} tell each other ghost stories to lighten the mood.", - "{1} looks at the night sky.", - "{1} defeats {2} in a fight, but spares their life.", - "{1} begs for {2} to kill them. They refuse, keeping {1} alive.", - "{1} destroys {2}'s supplies while they are asleep.", - "{1}, {2}, {3}, {4}, and {5} sleep in shifts.", - "{1} lets {2} into their shelter.", - "{1} receives a hatchet from an unknown sponsor.", - "{1} receives clean water from an unknown sponsor.", - "{1} receives medical supplies from an unknown sponsor.", - "{1} receives fresh food from an unknown sponsor.", - "{1} tries to sing themself to sleep.", - "{1} attempts to start a fire, but is unsuccessful.", - "{1} thinks about home.", - "{1} tends to {2}'s wounds.", - "{1} quietly hums.", - "{1}, {2}, and {3} cheerfully sing songs together.", - "{1} is unable to start a fire and sleeps without warmth.", - "{1} and {2} hold hands.", - "{1} convinces {2} to snuggle with them.", - "{1} receives an explosive from an unknown sponsor.", - "{1} questions their sanity.", - "{1} forces {2} to eat pant.", - "{1} forces {2T} to eat pant. {2T} chokes and dies.", - "{1} catches {2T} off guard and kills them.", - "{1} throws a knife into {2T}'s head.", - "{1T} begs for {2} to kill them. They reluctantly oblige, killing {1T}.", - "{1} and {2} work together to drown {3T}.", - "{1} strangles {2T} after engaging in a fist fight.", - "{1} shoots an arrow into {2T}'s head.", - "{1T} bleeds out due to untreated injuries.", - "{1T} cannot handle the circumstances and commits suicide.", - "{1} bashes {2T}'s head against a rock several times.", - "{1T} unknowingly eats toxic berries.", - "{1} silently snaps {2T}'s neck.", - "{1} taints {2T}'s food, killing them.", - "{1} decapitates {2T} with a sword.", - "{1T} dies from an infection.", - "{1} spears {2T} in the abdomen.", - "{1} sets {2T} on fire with a molotov.", - "{1T} falls into a pit and dies.", - "{1} stabs {2T} while their back is turned.", - "{1} severely injures {2T}, but puts them out of their misery.", - "{1} severely injures {2T} and leaves them to die.", - "{1} bashes {2T}'s head in with a mace.", - "{1T} attempts to climb a tree, but falls to their death.", - "{1} pushes {2T} off a cliff during a knife fight.", - "{1} throws a knife into {2T}'s chest.", - "{1}'s trap kills {2T}.", - "{1} kills {2T} while they are sleeping.", - "{1T} is unable to convince {2} to not kill them.", - "{1} convinces {2T} to not kill them, only to kill {2T} instead.", - "{1T} falls into a frozen lake and drowns.", - "{1}, {2}, and {3T} start fighting, but {2} runs away as {1} kills {3T}.", - "{1} kills {2T} with their own weapon.", - "{1} overpowers {2T}, killing them.", - "{1} sets an explosive off, killing {2T}.", - "{1} sets an explosive off, killing {2T}, and {3T}.", - "{1} sets an explosive off, killing {2T}, {3T}, and {4T}.", - "{1} sets an explosive off, killing {2T}, {3T}, {4T} and {5T}.", - "{1} kills {2T} as they try to run.", - "{1T} and {2T} threaten a double suicide. It fails and they die.", - "{1T}, {2T}, {3T}, and {4T} form a suicide pact, killing themselves.", - "{1T} dies from hypothermia.", - "{1T} dies from hunger.", - "{1T} dies from thirst.", - "{1} kills {2T} with a hatchet.", - "{1} and {2} fight {3T} and {4T}. {1} and {2} survive.", - "{1T} and {2T} fight {3} and {4}. {3} and {4} survive.", - "{1T} dies trying to escape the arena.", - "{1T} dies of dysentery.", - "{1T} accidently detonates a land mine while trying to arm it.", - "{1T} attacks {2}, but {3} protects them, killing {1T}.", - "{1} ambushes {2T} and kills them.", - "{1T} accidently steps on a landmine.", - "{1} severely slices {2T} with a sword.", - "{1} strangles {2T} with a rope.", - "{1} kills {2T} for their supplies.", - "{1} shoots an arrow at {2}, but misses and kills {3T} instead.", - "{1} shoots a poisonous blow dart into {2T}'s neck, slowly killing them.", - "{1}, {2}, and {3} successfully ambush and kill {4T}, {5T}, and {6T}.", - "{1T}, {2T}, and {3T} unsuccessfully ambush {4}, {5}, and {6}, who kill them instead.", - "{1} stabs {2T} with a tree branch.", - "{1} forces {2} to kill {3T} or {4}. They decide to kill {3T}.", - "{1} forces {2} to kill {3} or {4T}. They decide to kill {4T}.", - "{1} forces {2T} to kill {3} or {4}. They refuse to kill, so {1} kills them instead.", - "{1T} poisons {2}'s drink, but mistakes it for their own and dies.", - "{1} poisons {2T}'s drink. They drink it and die.", - "{1} stabs {2T} in the back with a trident.", - "{1T} attempts to climb a tree, but falls on {2T}, killing them both.", - "{1}, {2T}, and {3T} get into a fight. {1} triumphantly kills them both.", - "{1T}, {2}, and {3T} get into a fight. {2} triumphantly kills them both.", - "{1T}, {2T}, and {3} get into a fight. {3} triumphantly kills them both.", - "{1} kills {2T} with a sickle.", - "{1}, {2}, {3}, {4}, and {5} track down and kill {6T}.", - "{1}, {2}, {3}, and {4} track down and kill {5T}.", - "{1}, {2}, and {3} track down and kill {4T}.", - "{1} and {2} track down and kill {3T}.", - "{1} tracks down and kills {2T}.", - "{1} repeatedly stabs {2T} to death with sais.", - "{1} writes in their journal.", - "{1} watches {2} sitting at their campfire, and considers killing them" - ], - "hungerGamesDescription": "Play Hunger Games with your friends!", - "hungerGamesExtended": { - "usages": [ - "User1 User2 User3...", - "--autofill" - ], - "extendedHelp": "Enough discussion, let the games begin!", - "examples": [ - "WolfStar, Katniss, Peeta, Clove, Cato, Johanna, Brutus, Blight" - ], - "reminder": "You can specify `--autoskip` to automatically skip after some time." - }, - "hungerGamesResultDeaths_one": "**{{count}} cannon shot can be heard in the distance.**", - "hungerGamesResultDeaths_other": "**{{count}} cannon shots can be heard in the distance.**", - "hungerGamesResultHeaderBloodbath": "Bloodbath", - "hungerGamesResultHeaderMoon": "Night {{game.turn}}", - "hungerGamesResultHeaderSun": "Day {{game.turn}}", - "hungerGamesResultProceed": "Proceed?", - "hungerGamesStop": "Game finished by choice! See you later!", - "hungerGamesWinner": "And the winner is... {{winner}}!", - "ticTacToeDescription": "Play Tic-Tac-Toe with somebody.", - "ticTacToeDraw": "This match concluded in a **draw**!\n{{board}}", - "ticTacToeExtended": { - "usages": [ - "User" - ], - "extendedHelp": "Tic-tac-toe (also known as noughts and crosses or Xs and Os) is a paper-and-pencil game for two players, X and O, who take turns marking the spaces in a 3×3 grid.\nThe player who succeeds in placing three of their marks in a horizontal, vertical, or diagonal row wins the game.", - "examples": [ - "WolfStar" - ] - }, - "ticTacToePrompt": "Dear {{challengee}}, you have been challenged by {{challenger}} in a Tic-Tac-Toe match. Click the 🇾 reaction to accept!", - "ticTacToeTurn": "({{icon}}) Turn for {{player}}!\n{{board}}", - "ticTacToeWinner": "Winner is... {{winner}}!\n{{board}}", - "triviaActiveGame": "A game of trivia is already being played in this channel", - "triviaDescription": "Play a game of Trivia.", - "triviaEmbedTitles": { - "difficulty": "Difficulty", - "trivia": "Trivia" - }, - "triviaExtended": { - "usages": [ - "", - "Category", - "Category multiple/boolean/truefalse", - "multiple easy/medium/hard", - "hard 2m" - ], - "extendedHelp": "Answer questions of trivia here, with categories ranging from books to mythology! (powered by OpenTDB)\n\n**Categories**: {{TRIVIA_CATEGORIES}}", - "explainedUsage": [ - [ - "Category", - "The category questions are asked from." - ], - [ - "multiple/boolean/truefalse", - "Whether you want a multiple choice or a true/false question." - ], - [ - "easy/medium/hard", - "The difficulty level of the questions asked." - ], - [ - "Timespan", - "The amount of time you get to answer. The minimum is 1 second and the maximum is 1 minute" - ] - ], - "examples": [ - "history", - "books multiple easy", - "videogames 45s" - ] - }, - "triviaIncorrect": "I am sorry, but **{{attempt}}** is not the correct answer. Better luck next time!", - "triviaInvalidCategory": "Invalid category: Please use `WolfStar, help trivia` for a list of categories.", - "triviaNoAnswer": "Looks like nobody got it! The right answer was **{{correctAnswer}}**.", - "triviaWinner": "We have a winner! {{winner}} had a right answer with **{{correctAnswer}}**!" -} diff --git a/src/languages/en-US/commands/general.json b/src/languages/en-US/commands/general.json deleted file mode 100644 index 220794b54..000000000 --- a/src/languages/en-US/commands/general.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "helpAllFlag": "Displaying one category per page. Have issues with the embed? Run `{{prefix}}help --all` for a full list in DMs.", - "helpCommandCount_one": "{{count}} command", - "helpCommandCount_other": "{{count}} commands", - "helpData": { - "footer": "Command help for {{footerName}}", - "title": "{{titleDescription}}" - }, - "helpDescription": "Displays all commands or the description of one.", - "helpExtended": { - "usages": [ - "--cat/--categories", - "--all", - "CategoryName", - "Page", - "CommandName" - ], - "extendedHelp": "The help command shows a paginated list of all commands by their categories, or the extended information of a command if specified.\n\nIf you use `--categories` or `--cat`, you can get the list of all categories and the amount of commands each one of them have.", - "reminder": "The help command **only** shows the commands you can use. For the full list, please visit .", - "examples": [ - "--cat", - "--all", - "Moderation", - "12", - "help" - ] - }, - "helpDm": "📥 | The list of commands you have access to has been sent to your DMs.", - "helpNodm": "{{REDCROSS}} | You have DMs disabled so I couldn't send you the list of commands.", - "v7Description": "Gets the information regarding Skyra v7", - "v7Extended": { - "extendedHelp": "This is a **hidden** command used exclusively to send a notice to everyone who tries to use commands that have been removed according to [WolfStar v7](https://wolfstar.notion.site/wolfstar) plans." - }, - "v7SkyraDescription": "Gets the information regarding WolfStar v7", - "v7SkyraExtended": { - "extendedHelp": "This is a **hidden** command used exclusively to send a notice to everyone who tries to use commands that have been removed according to [Skyra v7](https://skyra.notion.site/skyra/Skyra-v7-922ba06004654142a7b63347a92513a8) plans." - }, - "v7SkyraMessage": "Hello there! Thank you for using this command, however, it was removed due to [Skyra v7](https://skyra.notion.site/skyra/Skyra-v7-922ba06004654142a7b63347a92513a8)'s plans. The link includes an explanation as for why `{{command}}` was removed.\n\nSorry for the inconvenience, and thank you for using WolfStar. 💖", - "v7NayreMessage": "Hello there! Thank you for using this command, however, it was removed and will be either redesigned as part of Nayre's Acryss RPG as mentioned in [Skyra v7](https://skyra.notion.site/skyra/Skyra-v7-922ba06004654142a7b63347a92513a8)'s plans.\n\nSorry for the inconvenience, and thank you for using WolfStar. 💖" -} diff --git a/src/languages/en-US/commands/info.json b/src/languages/en-US/commands/info.json deleted file mode 100644 index d6812467c..000000000 --- a/src/languages/en-US/commands/info.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "info", - "description": "Provides information about me, and links for adding the bot and joining the support server", - "embedDescription": "[WolfStar](https://wolfstar.rocks) {{VERSION}} is a bot designed to help moderating your server. I use the [Sapphire Framework](https://sapphirejs.dev) for the [Discord.js library](https://discord.js.org).\n- [Privacy Policy](https://wolfstar.rocks/privacy) | [Terms of Service](https://github.com/wolfstar-project/wolfstar/blob/main/.github/TERMS_OF_SERVICE.md).", - "embedFieldApplicationTitle": "Statistics", - "embedFieldApplicationValue": "- **Users**: {{users, number}}\n- **Servers**: {{guilds, number}}\n- **Channels**: {{channels, number}}\n- **Discord.js**: {{versionDiscord}}\n- **Sapphire**: {{versionSapphire}}\n- **Node.js**: {{versionNode}}", - "embedFieldUptimeTitle": "Uptime", - "embedFieldUptimeValue": "- **Host**: {{host}}\n- **Client**: {{client}}", - "embedFieldServerUsageTitle": "Server Usage", - "embedFieldServerUsageValue": "- **CPU Usage**: {{cpu}}\n- **Memory**: {{heapUsed}}MB (Total: {{heapTotal}}MB)", - "buttonInvite": "Add me to your server!", - "buttonSupport": "Support server", - "buttonGitHub": "GitHub Repository", - "buttonDonate": "Donate" -} diff --git a/src/languages/en-US/commands/management.json b/src/languages/en-US/commands/management.json deleted file mode 100644 index fdee214ab..000000000 --- a/src/languages/en-US/commands/management.json +++ /dev/null @@ -1,445 +0,0 @@ -{ - "commandHandlerAborted": "Aborted", - "permissionNodesHigher": "{{REDCROSS}} You cannot modify nor preview the permission nodes for this target.", - "permissionNodesCannotAllowEveryone": "{{REDCROSS}} You cannot allow commands for the `@everyone` role.", - "permissionNodesInvalidType": "{{REDCROSS}} Invalid type, expected either of `allow` or `deny`.", - "permissionNodesAdd": "{{GREENTICK}} Successfully added the command to the permission node.", - "permissionNodesNodeNotExists": "{{REDCROSS}} The selected permission node does not exist.", - "permissionNodesCommandNotExists": "{{REDCROSS}} The selected command does not exist in the permision node.", - "permissionNodesRemove": "{{GREENTICK}} Successfully removed the command from the permission node.", - "permissionNodesReset": "{{GREENTICK}} Successfully removed all commands from the permission node.", - "permissionNodesShowName": "Permissions for: __{{name}}__", - "permissionNodesShowAllow": "**Allow**: {{allow}}", - "permissionNodesShowDeny": "**Deny**: {{deny}}", - "guildInfoTitles": { - "CHANNELS": "Channels", - "MEMBERS": "Members", - "OTHER": "Other" - }, - "guildInfoChannels": "• **{{text}}** Text, **{{voice}}** Voice, **{{categories}}** categories.\n• AFK: {{afkChannelText}}", - "guildInfoChannelsAfkChannelText": "**<#{{afkChannel}}>** after **{{afkTime}}**min", - "guildInfoMembers": "• **{{memberCount, number}}** member(s)\n• Owner: **{{ownerTag}}**\n (ID: **{{ownerId}}**)", - "guildInfoOther": "• Roles: **{{size}}**\n• Created: **{{createdAt}}**\n• Verification Level: **{{verificationLevel, humanLevels}}**", - "guildInfoBanner": "Banner Image", - "guildInfoIcon": "Icon Image", - "guildInfoSplash": "Splash Image", - "guildInfoDiscoverySplash": "Discovery Splash Image", - "roleInfoTitles": { - "PERMISSIONS": "Permissions" - }, - "roleInfoData": "ID: **{{role.id}}**\nName: **{{role.name}}**\nColor: **{{role.hexColor}}**\nHoisted: **{{hoisted}}**\nPosition: **{{role.rawPosition}}**\nMentionable: **{{mentionable}}**", - "roleInfoAll": "All Permissions granted.", - "roleInfoNoPermissions": "Permissions not granted.", - "manageCommandAutoDeleteShowEmpty": "There are no command autodelete configured right now.", - "manageCommandAutoDeleteShow": "All command autodeletes configured:{{codeblock}}", - "manageCommandAutoDeleteAdd": "{{GREENTICK}} Success! All successful commands in {{channel}} will be deleted after {{time, duration}}!", - "manageCommandAutoDeleteRemove": "{{GREENTICK}} Success! Commands will not be automatically deleted in {{channel}} anymore!", - "manageCommandAutoDeleteRemoveNotset": "{{REDCROSS}} The channel {{channel}} was not configured to automatically delete messages!", - "manageCommandAutoDeleteReset": "All the command autodeletes have been reset.", - "manageCommandChannelShow": "List of disabled commands in {{channel}}: {{commands}}", - "manageCommandChannelShowEmpty": "The list of disabled commands for the specified channel is empty!", - "manageCommandChannelAddAlreadyset": "The command you are trying to disable is already disabled!", - "manageCommandChannelAdd": "Successfully disabled the command {{command}} for the channel {{channel}}!", - "manageCommandChannelRemoveNotset": "The command you are trying to enable was not disabled for {{channel}}.", - "manageCommandChannelRemove": "Successfully enabled the command {{command}} for the channel {{channel}}!", - "manageCommandChannelResetEmpty": "This channel had no disabled command, so I decided to do nothing.", - "manageCommandChannelReset": "Successfully enabled all disabled commands in {{channel}}, enjoy!", - "manageReactionRolesShowEmpty": "There are no reaction roles set up in this server.", - "manageReactionRolesAddChannel": "{{GREENTICK}} Success! I will now give the role when people react with {{emoji}} to any message from {{channel}}!", - "manageReactionRolesAddPrompt": "Listening now! Please react to a message and I will bind the reaction with the role!", - "manageReactionRolesAddMissing": "I waited, but you did not seem to have reacted to a message.", - "manageReactionRolesAdd": "{{GREENTICK}} Success! I will now give the role when people react with {{emoji}} at {{url}}!", - "manageReactionRolesRemoveNotExists": "The reaction role you specified does not exist.", - "manageReactionRolesRemove": "{{GREENTICK}} Success! I will not longer give the role when people react with {{emoji}} at {{url}}!", - "manageReactionRolesResetEmpty": "There were no reaction roles set up.", - "manageReactionRolesReset": "{{GREENTICK}} Successfully removed all reaction roles.", - "configurationEquals": "Successfully configured: no changes were made.", - "setIgnoreChannelsSet": "Ignoring all command input from {{channel}} now.", - "setIgnoreChannelsRemoved": "Listening all command input from {{channel}} now.", - "setImageLogsSet": "Successfully set the image logs channel to {{channel}}.", - "setMemberAddLogsSet": "Successfully set the member add logs channel to {{channel}}.", - "setMemberRemoveLogsSet": "Successfully set the member remove logs channel to {{channel}}.", - "setMessageUpdateLogsSet": "Successfully set the message update logs channel to {{channel}}.", - "setMessageDeleteLogsSet": "Successfully set the message delete logs channel to {{channel}}.", - "setModLogsSet": "Successfully set the mod logs channel to {{channel}}.", - "setPrefixSet": "Successfully set the prefix to `{{prefix}}`. Use `{{prefix}}setPrefix NewPrefix` to change it again.", - "stickyRolesNotExists": "The user {{user}} does not have any sticky roles or does not have the specified one.", - "stickyRolesReset": "Successfully removed all sticky roles from {{user}}.", - "stickyRolesRemove": "Successfully removed the specified role from {{user}}.", - "stickyRolesAdd": "Successfully added the specified role as sticky to {{user}}.", - "stickyRolesShowEmpty": "There are no sticky roles to show.", - "stickyRolesShowSingle": "Sticky Role(s) for **{{user}}**: {{roles, list(conjunction)}}.", - "createMuteDescription": "Prepare the mute system.", - "createMuteExtended": { - "extendedHelp": "This command prepares the mute system by creating a role called `muted`, and configuring it to the server settings. This command also modifies all channels (where possible) permissions and disables the permission **{{SEND_MESSAGES, permissions}}** in text channels and **{{CONNECT, permissions}}** in voice channels for said role." - }, - "permissionNodesDescription": "Configure the permission nodes for this server.", - "permissionNodesExtended": { - "usages": [ - "add Role/Member allow/deny Command", - "remove Role/Member allow/deny Command", - "reset Role/Member", - "show Role/Member", - "show", - "Role/Member" - ], - "extendedHelp": "Permission nodes are per-user and per-role overrides. They are used when the built-in permissions system is not enough.\nFor example, in some servers they want to give a staff role the permissions to use mute and warn, but not ban and others (reserved to moderators), and only warn is available for the configurable staff-level permission, so you can tell me to allow the mute command for the staff role now.", - "explainedUsage": [ - [ - "Action", - "Either `add`, `remove`, `reset`, or `show`. Defaults to `show`." - ], - [ - "Target", - "Either a role name or a user name, allowing IDs and mentions for either." - ], - [ - "Type", - "Either `allow` or `deny`." - ], - [ - "Command", - "The name of the command to allow or deny." - ] - ], - "examples": [ - "add staff allow warn", - "add moderators deny ban", - "remove staff allow warn", - "reset staff", - "show staff" - ], - "reminder": "The server owner cannot have any actions, nor the `everyone` role can have allowed commands." - }, - "managecommandautodeleteDescription": "Manage per-channel auto-delete timer.", - "managecommandautodeleteExtended": { - "usages": [ - "add TextChannel Seconds", - "remove TextChannel", - "reset", - "show", - "" - ], - "extendedHelp": "This command manages this server's per-channel command auto-delete timer, it serves well to leave a channel clean from commands.", - "explainedUsage": [ - [ - "add", - "Add an auto-delete timer for the specified channel." - ], - [ - "remove", - "Remove the auto-timer from the specified channel." - ], - [ - "reset", - "Clear all auto-delete timers." - ], - [ - "show", - "Show the auto-delete timer for all channels." - ] - ], - "reminder": "The channel argument is optional, defaulting to the message's channel, but it uses fuzzy search when possible.", - "examples": [ - "show", - "add #general 4s", - "remove #general", - "reset" - ] - }, - "manageCommandChannelDescription": "Manage per-channel blocked command list.", - "manageCommandChannelExtended": { - "usages": [ - "add TextChannel Command", - "remove TextChannel Command", - "reset TextChannel", - "show TextChannel" - ], - "extendedHelp": "This command manages this server's per-channel blocked command list, it serves well to disable certain commands you do not want to be used in certain channels (to disable a command globally, use the `disabledCommands` settings key to disable in all channels.", - "explainedUsage": [ - [ - "show [channel]", - "Show the list of commands blocked in the specified channel." - ], - [ - "add [channel] ", - "Add a command to the specified channel's list of blocked commands." - ], - [ - "remove [channel] ", - "Remove a command from the specified channel's list of blocked commands." - ], - [ - "reset [channel]", - "Clear the list of commands blocked in the specified channel." - ] - ], - "reminder": "The channel argument is optional, but it uses fuzzy search when possible.", - "examples": [ - "add #general profile", - "remove #general profile", - "reset #general", - "show #general" - ] - }, - "manageReactionRolesDescription": "Manage the reaction roles for this server.", - "manageReactionRolesExtended": { - "usages": [ - "add Role", - "add Role TextChannel Emoji", - "remove Role Message", - "reset", - "show" - ], - "extendedHelp": "Seamlessly set up reaction roles in your server! When adding reaction roles, I listen to your reactions for 5 minutes and I bind the first reaction from you alongside the channel and the message, with the specified role.\nOtherwise, if a channel is specified, a prompt will not be created, and the reaction role will be bound to all of the channel's messages.\n\nThe best way to add new reaction roles is by using `add @role`. If you prefer not binding the reaction to a specific message then use `add @role #channel emoji`", - "explainedUsage": [ - [ - "show", - "Retrieve the list of all reaction roles." - ], - [ - "add ", - "Adds a reaction role binding the first reacted message since the execution with the role." - ], - [ - "remove ", - "Removes a reaction role, use `show` to get a list of them." - ], - [ - "reset", - "Removes all reaction roles." - ] - ], - "examples": [ - "add @role", - "add @role #channel emoji", - "remove @role 123456789012345678", - "reset", - "show" - ] - }, - "rolesAdded": "The following roles have been added to your profile: `{{roles}}`", - "rolesAuditlog": "Authorized: Public Role Management | 'Roles' Command.", - "rolesListEmpty": "This server does not have a role listed as a public role.", - "rolesListTitle": "List of public roles", - "rolesNotManageable": "The following roles cannot be given by me due to their hierarchy role position: `{{roles}}`", - "rolesNotPublic": "The following roles are not public: `{{roles}}`", - "rolesRemoved": "The following roles have been removed from your profile: `{{roles}}`", - "setIgnoreChannelsDescription": "Set a channel to the ignore channel list.", - "setIgnoreChannelsExtended": { - "usages": [ - "here/TextChannel" - ], - "extendedHelp": "This command helps you setting up ignored channels. An ignored channel is a channel where nobody but moderators can use WolfStar's commands.\nUnlike removing the **{{SEND_MESSAGES, permissions}}** permission, WolfStar is still able to send (and therefore execute commands) messages, which allows moderators to use moderation commands in the channel.\nUse this if you want to ban any command usage from the bot in a specific channel.", - "explainedUsage": [ - [ - "channel", - "A TextChannel. You can either put the name of the channel, tag it, or type in \"here\" to select the channel the message was sent." - ] - ], - "reminder": "You cannot set the same channel twice, instead, WolfStar will remove it.", - "examples": [ - "#general", - "here" - ] - }, - "setImageLogsDescription": "Set the image logs channel.", - "setImageLogsExtended": { - "usages": [ - "here/TextChannel" - ], - "extendedHelp": "This command helps you setting up the image log channel. Whenever a member sends an image attachment, it will send an embed message with the attachment re-uploaded.\nAll messages are in embeds so you will need to enable the permission **{{EMBED_LINKS, permissions}}** for WolfStar.", - "explainedUsage": [ - [ - "channel", - "A TextChannel. You can either put the name of the channel, tag it, or type in \"here\" to select the channel the message was sent." - ] - ], - "examples": [ - "#image-logs", - "here" - ] - }, - "setMemberAddLogsDescription": "Set the member add logs channel.", - "setMemberAddLogsExtended": { - "usages": [ - "here/TextChannel" - ], - "extendedHelp": "This command helps you setting up the member add log channel, which will receive a message each time a user joins.\nIf a muted user joins, it will send a special \"Muted Member Joined\" event.", - "explainedUsage": [ - [ - "channel", - "A TextChannel. You can either put the name of the channel, tag it, or type in \"here\" to select the channel the message was sent." - ] - ], - "examples": [ - "#member-logs", - "here" - ], - "reminder": "All messages are in embeds so you will need to enable the permission **{{EMBED_LINKS, permissions}}** for WolfStar." - }, - "setMemberRemoveLogsDescription": "Set the member remove logs channel.", - "setMemberRemoveLogsExtended": { - "usages": [ - "here/TextChannel" - ], - "extendedHelp": "This command helps you setting up the member remove log channel, which will receive a message each time a user leaves, is kicked, or is banned.\nIn the case of the last two, it will send a special \"User Kicked\" or \"User Banned\" event.", - "explainedUsage": [ - [ - "channel", - "A TextChannel. You can either put the name of the channel, tag it, or type in \"here\" to configure the channel this command was used in." - ] - ], - "examples": [ - "#member-logs", - "here" - ], - "reminder": "All messages are in embeds so you will need to enable the permission **{{EMBED_LINKS, permissions}}** for WolfStar." - }, - "setMessageUpdateLogsDescription": "Set the message update logs channel.", - "setMessageUpdateLogsExtended": { - "usages": [ - "here/TextChannel" - ], - "extendedHelp": "This command helps you setting up the message update log channel, which will receive a message each time a message is edited.", - "explainedUsage": [ - [ - "channel", - "A TextChannel. You can either put the name of the channel, tag it, or type in \"here\" to configure the channel this command was used in." - ] - ], - "reminder": "All messages are in embeds so you will need to enable the permission **{{EMBED_LINKS, permissions}}** for WolfStar.", - "examples": [ - "#message-logs", - "here" - ] - }, - "setMessageDeleteLogsDescription": "Set the message delete logs channel.", - "setMessageDeleteLogsExtended": { - "usages": [ - "here/TextChannel" - ], - "extendedHelp": "This command helps you setting up the message delete log channel, which will receive a message each time a message is deleted.", - "explainedUsage": [ - [ - "channel", - "A TextChannel. You can either put the name of the channel, tag it, or type in \"here\" to configure the channel this command was used in." - ] - ], - "reminder": "All messages are in embeds so you will need to enable the permission **{{EMBED_LINKS, permissions}}** for WolfStar.\nDue to Discord limitations, WolfStar cannot know who deleted a message.", - "examples": [ - "#message-logs", - "here" - ] - }, - "setmodlogsDescription": "Set the mod logs channel.", - "setmodlogsExtended": { - "usages": [ - "here/TextChannel" - ], - "extendedHelp": "This command helps you setting up the mod log channel. A mod log channel only sends case reports indexed by a number case and with \"claimable\" reasons and moderators.\nThis channel is not a must and you can always retrieve specific modlogs with the `case` command.\nAll messages are in embeds so you will need to enable the permission **{{EMBED_LINKS, permissions}}** for WolfStar.\nFor auto-detection, you need to individually set the \"events\" you want to listen: `events.ban-add`, `events.ban-remove` via the `config` command.", - "explainedUsage": [ - [ - "channel", - "A TextChannel. You can either put the name of the channel, tag it, or type in \"here\" to select the channel the message was sent." - ] - ], - "reminder": "Due to Discord limitations, the auto-detection does not detect kicks. You need to use the `kick` command if you want to document them as a formal moderation log case.", - "examples": [ - "#mod-logs", - "here" - ] - }, - "setprefixDescription": "Set WolfStar's prefix.", - "setprefixExtended": { - "usages": [ - "Prefix" - ], - "extendedHelp": "This command helps you setting up WolfStar's prefix. A prefix is an affix that is added in front of the word, in this case, the message.\nIt allows bots to distinguish between a regular message and a command. By nature, the prefix between should be different to avoid conflicts.\nIf you forget WolfStar's prefix, simply mention her with nothing else and she will tell you the current prefix.\nAlternatively, you can prefix the commands with her name and a comma (for example `WolfStar, ping`).", - "explainedUsage": [ - [ - "Prefix", - "The prefix to set. Default one in WolfStar is `{{DEFAULT_PREFIX}}`." - ] - ], - "reminder": "Your prefix should only contain characters everyone can write and type.", - "examples": [ - "&", - "=" - ] - }, - "guildInfoDescription": "Check the information of the server.", - "guildInfoExtended": { - "extendedHelp": "The serverinfo command displays information for the server the message got sent.\nIt shows the amount of channels, with the count for each category, the amount of members (given from the API), the owner with their user id, the amount of roles, region, creation date, verification level... between others." - }, - "roleInfoDescription": "Check the information for a role.", - "roleInfoExtended": { - "usages": [ - "Role", - "" - ], - "extendedHelp": "The roleinfo command displays information for a role, such as its id, name, color, whether it's hoisted (displays separately) or not, it's role hierarchy position, whether it's mentionable or not, how many members have said role, and its permissions.\nIt sends an embedded message with the color of the role.", - "explainedUsage": [ - [ - "Role", - "The role name, name, mention or id." - ] - ], - "examples": [ - "Administrator", - "Moderator", - "" - ] - }, - "stickyRolesDescription": "Manage sticky roles for users.", - "stickyRolesExtended": { - "usages": [ - "add User Role", - "remove User Role", - "reset User", - "show User", - "User" - ], - "extendedHelp": "The stickyRoles command allows you to manage per-member's sticky roles, they are roles that are kept even when you leave, and are applied back as soon as they join.", - "explainedUsage": [ - [ - "Action", - "Either you want to check the sticky roles, add one, remove one, or remove all of them." - ], - [ - "User", - "The user target for all the actions." - ], - [ - "Role", - "The role to add or remove." - ] - ], - "examples": [ - "add WolfStar Goddess", - "show WolfStar", - "remove WolfStar Goddess", - "reset WolfStar" - ], - "reminder": "The member's roles will not be modified by this command, you need to add or remove them." - }, - "rolesDescription": "List, claim or unclaim public roles in this server.", - "rolesExtended": { - "usages": [ - "Role", - "" - ], - "extendedHelp": "Public roles are roles that are available for everyone.\nAn administrator must configure them with the configuration command.", - "explainedUsage": [ - [ - "roles", - "The list of roles to claim or unclaim. Leave this empty to get a list of available roles." - ] - ], - "reminder": "When claiming or unclaiming roles you can provide a single or multiple role(s).\nTo claim multiple roles, you must separate them by a comma, for example `red,green`.\nYou can specify which roles you want by providing the role ID, name, or a sub-section of the name.\n\nAdministrators can add public roles using `{{prefix}}conf set roles.public ExamplePublicRole`.", - "examples": [ - "Designer Programmer", - "Designer" - ] - } -} diff --git a/src/languages/en-US/commands/permissions.json b/src/languages/en-US/commands/permissions.json deleted file mode 100644 index e27e3752a..000000000 --- a/src/languages/en-US/commands/permissions.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "permissions", - "description": "Get the user's permissions", - "contextMenuName": "Inspect Permissions", - "optionsUserName": "user", - "optionsUserDescription": "The user to inspect the permissions of", - "optionsListAllName": "list-all", - "optionsListAllDescription": "Whether or not to display non-moderation permissions (default: False)", - "optionsListMissingName": "list-missing", - "optionsListMissingDescription": "Whether or not to display non-granted permissions (default: False)", - "optionsShowName": "show", - "optionsShowDescription": "Whether or not to show the message publicly (default: False)", - "title": "Permissions for {{username}} ({{id}})" -} diff --git a/src/languages/en-US/commands/shared.json b/src/languages/en-US/commands/shared.json deleted file mode 100644 index b1ffdf250..000000000 --- a/src/languages/en-US/commands/shared.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "deprecatedMessage": "Message based commands are **deprecated**, and will be removed in the future. You should use the {{command}} slash command instead!", - "slashOnlyDetailedDescription": { - "extendedHelp": "This command is only available via slash commands. Please use the slash command instead." - }, - "slashOnlyErrorMessage": "This command is only available via slash commands. Please use the slash command instead." -} diff --git a/src/languages/en-US/commands/snipe.json b/src/languages/en-US/commands/snipe.json deleted file mode 100644 index ac5f79ebd..000000000 --- a/src/languages/en-US/commands/snipe.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "snipe", - "description": "Retrieve the last recently deleted message from a channel", - "messageEmpty": "There are no sniped messages in this channel.", - "embedTitle": "Sniped Message" -} diff --git a/src/languages/en-US/commands/system.json b/src/languages/en-US/commands/system.json deleted file mode 100644 index 96559e17a..000000000 --- a/src/languages/en-US/commands/system.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "evalDescription": "Evaluates arbitrary Javascript.", - "evalExtended": { - "usages": [ - "Expression" - ], - "extendedHelp": "The eval command evaluates code as-in, any error thrown from it will be handled.\nIt also uses the flags feature. Write --silent, --depth=number or --async to customize the output.\nThe --wait flag changes the time the eval will run. Defaults to 60 seconds. Accepts time in milliseconds.\nThe --silent flag will make it output nothing.\nThe --depth flag accepts a number, for example, --depth=2, to customize util.inspect's depth.\nThe --async flag will wrap the code into an async function where you can enjoy the use of await, however, if you want to return something, you will need the return keyword\nThe --showHidden flag will enable the showHidden option in util.inspect.\nThe --lang and --language flags allow different syntax highlight for the output.\nThe --json flag converts the output to json\nThe --no-timeout flag disables the timeout\nIf the output is too large, it'll send the output as a file.", - "explainedUsage": [ - [ - "Expression", - "The expression to evaluate" - ] - ], - "examples": [ - "msg.author.username;", - "1 + 1;" - ], - "reminder": "Reserved for bot owners." - }, - "evalTimeout": "TIMEOUT: Took longer than {{seconds}} seconds.", - "evalError": "**Error**:{{output}}\n**Type**:{{type}}\n{{time}}", - "dmNotSent": "I cannot send you a message in DMs, did you block me?", - "dmSent": "I have sent you the message in DMs.", - "reboot": "{{LOADING}} Rebooting...", - "rebootDescription": "Reboots the bot.", - "rebootExtended": { - "extendedHelp": "The bot goes boom, then the bot goes revive.", - "reminder": "Reserved for bot owners." - } -} diff --git a/src/languages/en-US/commands/tools.json b/src/languages/en-US/commands/tools.json deleted file mode 100644 index 8e0ac3961..000000000 --- a/src/languages/en-US/commands/tools.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "avatarDescription": "View somebody's avatar in full size.", - "avatarExtended": { - "usages": [ - "", - "User" - ], - "extendedHelp": "As this command's name says, it shows somebody's avatar.", - "explainedUsage": [ - [ - "User", - "The user to get the avatar for. Defaults to you yourself." - ] - ], - "reminder": "Use the --size flag to change the avatar's size." - }, - "avatarNone": "The user does not have an avatar set.", - "voteDescription": "Simplified reaction-based vote.", - "voteExtended": { - "usages": [ - "Question" - ], - "examples": [ - "Should I implement the #anime channel?" - ], - "explainedUsage": [ - [ - "Question", - "The question to vote on." - ] - ] - }, - "voteContentNeeded": "{{REDCROSS}} You must give a topic for the poll.", - "voteReactionBlocked": "{{REDCROSS}} I was not able to add the reactions necessary for this command to work because you have me blocked! 😢", - "whoisExtended": { - "usages": [ - "", - "User" - ], - "extendedHelp": "Gets information on any server member. Also known as `userinfo` in many other bots.", - "explainedUsage": [ - [ - "User", - "The user to get information about. Defaults to you yourself." - ] - ] - }, - "whoisMemberRoleListAndMore": "{{count}} more." -} diff --git a/src/languages/en-US/commands/whois.json b/src/languages/en-US/commands/whois.json deleted file mode 100644 index 0e4f90235..000000000 --- a/src/languages/en-US/commands/whois.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "whois", - "description": "Provides information about a Discord user", - "contextMenuName": "Get Information", - "userName": "user", - "userDescription": "The user to get information about", - "rolesTitle_one": "Role [1]", - "rolesTitle_other": "Roles [{{count, number}}]", - "permissionsTitle": "Key Permissions", - "permissionsAll": "All Permissions", - "embedDescription": "**User Since**: {{createdAt}}", - "embedMemberDescription": "**Member Since**: {{joinedAt}}", - "buttonAvatar": "Avatar", - "buttonProfile": "Profile" -} diff --git a/src/languages/en-US/constants.ts b/src/languages/en-US/constants.ts deleted file mode 100644 index 11ac25817..000000000 --- a/src/languages/en-US/constants.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Handler } from '#lib/i18n/structures/Handler'; -import { TimeTypes } from '@sapphire/time-utilities'; - -export class ExtendedHandler extends Handler { - public constructor() { - super({ - name: 'en-US', - duration: { - [TimeTypes.Year]: { - 1: 'year', - DEFAULT: 'years' - }, - [TimeTypes.Month]: { - 1: 'month', - DEFAULT: 'months' - }, - [TimeTypes.Week]: { - 1: 'week', - DEFAULT: 'weeks' - }, - [TimeTypes.Day]: { - 1: 'day', - DEFAULT: 'days' - }, - [TimeTypes.Hour]: { - 1: 'hour', - DEFAULT: 'hours' - }, - [TimeTypes.Minute]: { - 1: 'minute', - DEFAULT: 'minutes' - }, - [TimeTypes.Second]: { - 1: 'second', - DEFAULT: 'seconds' - } - } - }); - } -} diff --git a/src/languages/en-US/errors.json b/src/languages/en-US/errors.json deleted file mode 100644 index 62a23f737..000000000 --- a/src/languages/en-US/errors.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "genericUnknownChannel": "I'm sorry, I tried to perform an action for a channel unknown to Discord and failed, this error has been reported to the developers.", - "genericUnknownGuild": "I'm sorry, I tried to perform an action for a server unknown to Discord and failed, this error has been reported to the developers.", - "genericUnknownMember": "I'm sorry, I tried to perform an action for a member unknown to Discord and failed, this error has been reported to the developers.", - "genericUnknownMessage": "I'm sorry, I tried to perform an action for a message unknown to Discord and failed, this error has been reported to the developers.", - "genericUnknownRole": "I'm sorry, I tried to perform an action for a role unknown to Discord and failed, this error has been reported to the developers.", - "genericMissingAccess": "I'm sorry, I tried to perform an action for a resource without the necessary permissions and failed, this error has been reported to the developers.", - "genericDiscordInternalServerError": "Oops, Discord broke itself, please try again later.", - "genericDiscordGateway": "Oops, the network is struggling to communicate with Discord, please try again later.", - "genericDiscordUnavailable": "Oops, Discord is currently unavailable, please try again later.", - "guildBansEmpty": "There are no bans registered in this server.", - "guildBansNotFound": "I tried and failed to find this user from the ban list. Are you certain this user is banned?", - "guildMemberNotVoicechannel": "I cannot execute this action in a member that is not connected to a voice channel.", - "guildWarnNotFound": "I failed to fetch that warning. Either it does not exist, is not of type warning, or it has been appealed.", - "modlogTimed": "This moderation log is already timed. Expires in {{remaining, duration}}", - "unexpectedIssue": "An unexpected error popped up! Safely aborting this command...", - "userNotInGuild": "This user is not in this server." -} diff --git a/src/languages/en-US/events/messages.json b/src/languages/en-US/events/messages.json deleted file mode 100644 index 827eb2b91..000000000 --- a/src/languages/en-US/events/messages.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "messageDelete": "Message Deleted • {{channel}}", - "messageDeleteUnknown": "Unknown Message Deleted • {{channel}}", - "messageUpdate": "Message Edited • {{channel}}", - "messageUpdateUnknown": "Unknown Message Edited • {{channel}}", - "messageNotFound": "Unknown Message", - "messageDeleteBulk_one": "{{count}} message deleted in {{channel}} by {{author}}", - "messageDeleteBulk_other": "{{count}} messages deleted in {{channel}} by {{author}}", - "messageDeleteBulkUnknown_one": "{{count}} message deleted in {{channel}}", - "messageDeleteBulkUnknown_other": "{{count}} messages deleted in {{channel}}", - "messageDeleteBulkFooter": "Multiple Messages Deleted", - "voiceActivityFooter": "Voice Activity", - "jumpToContext": "Jump to Context" -} diff --git a/src/languages/en-US/guilds.json b/src/languages/en-US/guilds.json deleted file mode 100644 index 7e777395b..000000000 --- a/src/languages/en-US/guilds.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "explicitContentFilterDisabled": "Disabled", - "explicitContentFilterMembersWithoutRoles": "Members without roles", - "explicitContentFilterAllMembers": "All members", - "defaultMessageNotificationsAllMessages": "All Messages", - "defaultMessageNotificationsOnlyMentions": "Only @mentions", - "SuppressJoinNotifications": "Member join notifications", - "SuppressJoinNotificationReplies": "Member join sticker reply buttons", - "SuppressPremiumSubscriptions": "Server boost notifications", - "SuppressGuildReminderNotifications": "Server setup tips", - "SuppressRoleSubscriptionPurchaseNotifications": "Suppress role subscription purchase notifications", - "SuppressRoleSubscriptionPurchaseNotificationReplies": "Suppress replies for role subscription purchase notifications" -} diff --git a/src/languages/en-US/humanLevels.json b/src/languages/en-US/humanLevels.json deleted file mode 100644 index 80314b998..000000000 --- a/src/languages/en-US/humanLevels.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "None": "None", - "Low": "Low", - "Medium": "Medium", - "High": "High", - "VeryHigh": "Highest" -} diff --git a/src/languages/en-US/moderation.json b/src/languages/en-US/moderation.json deleted file mode 100644 index 55e0b4d13..000000000 --- a/src/languages/en-US/moderation.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "typeBan": "Ban", - "typeKick": "Kick", - "typeMute": "Mute", - "typeRestrictedAttachment": "Attachment Restriction", - "typeRestrictedEmbed": "Embed Restriction", - "typeRestrictedEmoji": "Emoji Restriction", - "typeRestrictedReaction": "Reaction Restriction", - "typeRestrictedVoice": "Voice Restriction", - "typeRoleAdd": "Role Add", - "typeRoleRemove": "Role Remove", - "typeSetNickname": "Nickname Set", - "typeSoftban": "Softban", - "typeTimeout": "Timeout", - "typeVoiceKick": "Voice Kick", - "typeVoiceMute": "Voice Mute", - "typeWarning": "Warning", - "metadataUndo": "Remove {{name}}", - "metadataTemporary": "Temporary {{name}}", - "caseNotExists_one": "{{REDCROSS}} I am sorry, but the selected moderation log case does not exist.", - "caseNotExists_other": "{{REDCROSS}} I am sorry, but none of the selected moderation logs cases exist.", - "embedUser": "{{tag}} ({{id}})", - "embedDescription": "❯ **Type:** {{type}}\n❯ **User:** {{user}}\n❯ **Reason:** {{reason}}", - "embedDescriptionTemporary": "❯ **Type:** {{type}}\n❯ **User:** {{user}}\n❯ **Expires {{time}}**\n❯ **Reason:** {{reason}}", - "embedReasonNotSet": "*Please use {{command}} to set a reason.*", - "embedFooter": "Case {{caseId}}", - "actionIsActive": "This moderation action is still active for this user.", - "actionIsNotActive": "This moderation action is not active for this user.", - "actionIsActiveRole": "This user already has the selected role.", - "actionIsNotActiveRole": "This user does not have the selected role.", - "actionIsActiveRestrictionRole": "This user already has the configured restriction role.", - "actionIsNotActiveRestrictionRole": "This user does not have the configured restriction role.", - "actionIsActiveNickname": "This user already has the selected nickname.", - "actionIsNotActiveNickname": "This user does not have the selected nickname.", - "actionTargetSelf": "You cannot perform this action on yourself. Why would you do that anyways?", - "actionTargetGuildOwner": "You cannot perform this action on the server owner.", - "actionTargetWolf": "I... I cannot do that to myself! You broke my heart. 💔", - "actionTargetHigherHierarchyWolf": "This action cannot be performed on a member with a role position that is higher than or equal to mine.", - "actionTargetHigherHierarchyAuthor": "This action cannot be performed on a member with a role position that is higher than or equal to yours.", - "restrictionNotConfigured": "The restriction role must be configured for this action to happen", - "success": "Successfully executed the command." -} diff --git a/src/languages/en-US/permissions.json b/src/languages/en-US/permissions.json deleted file mode 100644 index 6ef55e56c..000000000 --- a/src/languages/en-US/permissions.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "AddReactions": "Add Reactions", - "Administrator": "Administrator", - "AttachFiles": "Attach Files", - "BanMembers": "Ban Members", - "ChangeNickname": "Change Nickname", - "Connect": "Connect", - "CreateEvents": "Create Events", - "CreateExpressions": "Create Expressions", - "CreateGuildExpressions": "Create Expressions", - "CreateInstantInvite": "Create Invite", - "CreatePrivateThreads": "Create Private Threads", - "CreatePublicThreads": "Create Public Threads", - "DeafenMembers": "Deafen Members", - "EmbedLinks": "Embed Links", - "KickMembers": "Kick Members", - "ManageChannels": "Manage Channels", - "ManageEvents": "Manage Events", - "ManageGuild": "Manage Server", - "ManageGuildExpressions": "Manage Expressions", - "ManageMessages": "Manage Messages", - "ManageNicknames": "Manage Nicknames", - "ManageRoles": "Manage Roles", - "ManageThreads": "Manage Threads", - "ManageWebhooks": "Manage Webhooks", - "MentionEveryone": "Mention Everyone", - "ModerateMembers": "Time out members", - "MoveMembers": "Move Members", - "MuteMembers": "Mute Members", - "PrioritySpeaker": "Priority Speaker", - "ReadMessageHistory": "Read Message History", - "RequestToSpeak": "Request to Speak", - "SendMessages": "Send Messages", - "SendMessagesInThreads": "Send Messages in Threads", - "SendPolls": "Create Polls", - "SendTTSMessages": "Send Text-to-speech Messages", - "SendVoiceMessages": "Send Voice Messages", - "Speak": "Speak", - "Stream": "Video", - "UseApplicationCommands": "Use Application Commands", - "UseEmbeddedActivities": "Use Activities", - "UseExternalEmojis": "Use External Emojis", - "UseExternalSounds": "Use External Sounds", - "UseExternalStickers": "Use External Stickers", - "UseSoundboard": "Use Soundboard", - "UseVAD": "Use Voice Activity", - "ViewAuditLog": "View Audit Log", - "ViewChannel": "View Channels", - "ViewCreatorMonetizationAnalytics": "View Creator Monetization Analytics", - "ViewGuildInsights": "View Server Insights", - "UseExternalApps": "Use External Apps" -} diff --git a/src/languages/en-US/serializers.json b/src/languages/en-US/serializers.json deleted file mode 100644 index 5d23cb59f..000000000 --- a/src/languages/en-US/serializers.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "customCommandInvalidAliases": "The property \"aliases\" must be an array of strings.", - "customCommandInvalidColor": "The property \"color\" must be a number.", - "customCommandInvalidContent": "The property \"content\" must be a string.", - "customCommandInvalidEmbed": "The property \"embed\" must be a boolean.", - "customCommandInvalidId": "The property \"id\" must be a string.", - "customCommandInvalidType_one": "The type {{tag.type}} is not valid, it must be the following: {{possibles, orList}}", - "customCommandInvalidType_other": "The type {{tag.type}} is not valid, it must be one of the following: {{possibles, orList}}", - "customCommandMissingParameter": "You need to write another parameter!\n\n> **Tip**: The type for the next argument is `{{type}}`!", - "disabledCommandChannelsChannelsCommandDoesNotExist": "The command `{{name}}` does not exist.", - "disabledCommandChannelsChannelsDoesNotExist": "The channel does not exist.", - "invalidBool": "{{name}} must be true or false.", - "invalidChannel": "{{name}} must be a channel tag or valid channel id.", - "invalidCommand": "{{name}} must be a command name.", - "invalidEmoji": "{{name}} must be a valid emoji.", - "invalidFloat": "{{name}} must be a valid number.", - "invalidGuild": "{{name}} must be a valid server ID.", - "invalidInt": "{{name}} must be an integer.", - "invalidInvite": "{{name}} must be a valid invite code.", - "invalidRole": "{{name}} must be a role mention or role id.", - "invalidSnowflake": "{{name}} must be a valid snowflake.", - "invalidUrl": "{{name}} must be a valid url.", - "invalidUser": "{{name}} must be a mention or valid user id.", - "minMaxBothExclusive": "{{name}} must be between {{min}} and {{max}} exclusively.", - "minMaxBothInclusive": "{{name}} must be between {{min}} and {{max}} inclusively.", - "minMaxExactlyExclusive": "{{name}} must be exactly {{min}}.", - "minMaxExactlyInclusive": "{{name}} must be exactly {{min}}.", - "minMaxMaxExclusive": "{{name}} must be less than {{max}} exclusively.", - "minMaxMaxInclusive": "{{name}} must be less than {{max}} inclusively", - "minMaxMinExclusive": "{{name}} must be greater than {{min}} exclusively.", - "minMaxMinInclusive": "{{name}} must be greater than {{min}} inclusively.", - "permissionNodeDuplicatedCommand": "You have set `{{command}}` twice, either allow it, or deny it.", - "permissionNodeInvalid": "Invalid data.", - "permissionNodeInvalidCommand": "The command `{{command}}` does not exist or is invalid.", - "permissionNodeInvalidTarget": "No data could be found from the ID.", - "permissionNodeSecurityEveryoneAllows": "For security, the everyone role cannot have allows.", - "permissionNodeSecurityGuarded": "For security and for me to work properly, you cannot deny the usage for the command `{{command}}`.", - "wordIncluded": "The key `{{name}}` already includes the word `{{word}}`.", - "permissionNodeSecurityOwner": "You cannot set permission overrides on the server owner.", - "reactionRoleInvalid": "Invalid reaction role data.", - "stickyRoleInvalid": "Invalid sticky role data.", - "twitchSubscriptionInvalid": "Invalid data.", - "twitchSubscriptionInvalidStreamer": "Invalid data streamer.", - "uniqueRoleSetInvalid": "Invalid unique role set data.", - "unknownChannel": "Unknown channel", - "unknownRole": "Unknown role", - "unknownUser": "Unknown user", - "unsupported": "This configuration key cannot be updated via Discord at the moment, please use the dashboard at !" -} diff --git a/src/languages/es-419/arguments.json b/src/languages/es-419/arguments.json deleted file mode 100644 index 3b8900cd2..000000000 --- a/src/languages/es-419/arguments.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "boolean_one": "No pude resolver `{{parameter}}` a un booleano, el único posible valor es: {{possibles}}", - "boolean_other": "No pude resolver `{{parameter}}` a un booleano, los valores posibles son: {{possibles, orList}}", - "booleanError": "No pude resolver `{{parameter}}` a un booleano, el único posible valor es: {{possibles}}", - "booleanDisabled": "Desabilitado", - "booleanEnabled": "Habilitado", - "booleanFalseOptions": [ - "falso", - "f", - "no", - "n", - "apagado", - "desabilitar", - "desabilitado", - "0", - "-" - ], - "booleanTrueOptions": [ - "verdadero", - "v", - "si", - "s", - "encendido", - "habilitar", - "habilitado", - "1", - "+" - ], - "caseNoEntries": "", - "caseUnknownEntry": "", - "caseNotInThisGuild": "", - "caseLatestOptions": [ - "ultimo", - "último" - ], - "categoryChannelError": "No pude resolver `{{parameter}}` a un canal de categoría, ¡por favor asegúrese de que escribió su nombre o ID correctamente!", - "channelError": "No pude resolver `{{parameter}}` a un canal, ¡asegúrate de que escribiste su nombre o ID correctamente!", - "command": "¡No pude resolver `{{parameter}}` a un comando! ¡Asegúrate de que escribiste su nombre o uno de sus alias correctamente!", - "commandMatch": "No pude coincidir `{{parameter}}` con un comando ni categoría, estos son algunos de los formatos válidos:\n\n- `ping` (coincide con el comando ping solamente).\n- `management.*` (coincide con todos los comandos de la categoría **Management**).\n- `management.configuration.*` (coincide con todos los comandos en la subcategoría **Management** > **Configuration**).\n\n> **Pista**: Cuando utilizas `{{commandContext.commandPrefix}}help`, la categoría de cada comando se encuentra en la parte superior de la inserción.", - "dateError": "No pude resolver `{{parameter}}` a una fecha, aquí tiene alguno de los formatos válidos:\n\n$t(arguments:dateFormats)", - "dateFormats": "- `2016-11-24` (AAAA-MM-DD)\n- `2016-11-24T23:56` (AAAA-MM-DDTHH:mm)\n- `2016-11-24T23:56:12` (AAAA-MM-DDTHH:mm:ss)\n- `2016-11-24T23:56:12. 00` (AAAA-MM-DDTHH:mm:sss)\n\n> **Pista**: Los últimos 3 formatos aceptan `Z` al final para marcar la hora como UTC`. Alternativamente, puedes poner la zona horaria añadiendo `+HH:MM`, por ejemplo `+01:00`.", - "dateTooEarly": "El parámetro `{{parameter}}` resuelto a una fecha anterior a {{minimum, dateTime}}, ¡el cual no está permitido!", - "dateTooFar": "El parámetro `{{parameter}}` resuelto a una fecha posterior a {{maximum, dateTime}}, ¡el cual no está permitido!", - "dmChannelError": "No pude resolver `{{parameter}}` a un canal de mensajes directos, ¡asegúrate de que escribiste su nombre o ID correctamente!", - "duration": "No pude resolver `{{parameter}}` a una duración válida, aquí tiene alguno de los formatos válidos:\n\n$t(arguments:durationFormats)", - "durationFormats": "- `4h` (4 horas).\n- `20m5s` (20 minutos y 5 segundos).\n- `\"1w 2d 16h 40m 10s\"` (1 semana, 2 días, 16 horas, 40 minutos y 10 segundos).", - "emojiError": "No pude resolver `{{parameter}}` a un emoji válido, ¿estás seguro de que has usado un twemoji (e.g. 🌊) o un emoji (por ejemplo, {{GREENTICK}})?", - "floatError": "¡No pude resolver `{{parameter}}` a un número!", - "floatTooLarge": "", - "floatTooSmall": "¡El parámetro `{{parameter}}` es demasiado pequeño! ¡Debe ser al menos {{minimum}}!", - "guildChannelError": "No pude resolver `{{parameter}}` a un canal de este servidor, ¡por favor asegúrese de que escribió su nombre o ID correctamente!", - "guildChannelMismatchingError": "El parámetro `{{parameter}}` resuelto a un tipo de canal incompatible en este servidor, ¡por favor prueba otro canal!", - "guildChannelMissingGuildError": "No pude resolver `{{parameter}}` porque este argumento requiere ser ejecutado en un canal de un servidor.", - "guildPrivateThreadChannelError": "No pude resolver `{{parameter}}` a un hilo privado, ¡por favor asegúrese de que escribió su nombre o ID correctamente!", - "guildPublicThreadChannelError": "No pude resolver `{{parameter}}` a un hilo público, ¡por favor asegúrese de que escribió su nombre o ID correctamente!", - "guildStageVoiceChannelError": "No pude resolver `{{parameter}}` a un canal de Stage, ¡por favor asegúrese de que escribió su nombre o ID correctamente!", - "guildTextChannelError": "No pude resolver `{{parameter}}` a un canal de texto, ¡por favor asegúrese de que escribió su nombre o ID correctamente!\n\n> **Consejo**: ¡También puedes mencionarlo!", - "guildThreadChannelError": "No pude resolver `{{parameter}}` a un hilo, ¡por favor asegúrese de que escribió su nombre o ID correctamente!", - "guildVoiceChannelError": "No pude resolver `{{parameter}}` a un canal de voz, ¡por favor asegúrese de que escribió su nombre o ID correctamente!", - "hyperlinkError": "No pude resolver `{{parameter}}` a un enlace, ¡normalmente están formateados de forma similar a `https://discord.com`!", - "integerError": "¡No pude resolver `{{parameter}}` a un entero!", - "integerTooLarge": "", - "integerTooSmall": "¡El parámetro `{{parameter}}` es demasiado pequeño! ¡Debe ser al menos {{minimum}}!", - "invite": "No pude resolver `{{parameter}}` a un enlace de invitación válido, aquí tiene alguno de los formatos válidos:\n\n- `https://discord​.gg/6gakFR2`.\n- `https://discord​.com/invite/6gakFR2`.\n- `https://discordapp​.com/invite/6gakFR2`.\n\n> **Consejo**: Puedes omitir la parte `https://`, `discord​.gg/6gakFR2` también es aceptado como un parámetro válido.", - "language": "", - "memberError": "No pude resolver `{{parameter}}` a un miembro de este servidor, ¡por favor asegúrate de escribir su nombre o ID correctamente!\n\n> **Consejo**: ¡También puedes usar menciones!", - "memberMissingGuild": "No pude resolver `{{parameter}}` porque este argumento requiere ser ejecutado en un canal de un servidor.", - "messageError": "No pude resolver `{{parameter}}` a un mensaje:\n\n- Si usaste un **ID** (p. ej. `{{message.id}}`), asegúrate de que has copiado el ID correcto de este canal (<#{{channel}}>), y no, por ejemplo, el ID del autor.\n- Si usaste un **enlace de mensaje** (ej. `{{message.url}}`), asegúrese de que es de un canal de este servidor, y que ambos tenemos permisos para leerlo.\n- No ha introducido un parámetro válido, en ese caso, ¡compruebe las dos anteriores!", - "missing": "¡Necesitas escribir otro parámetro!\n\n> **Consejo**: puedes hacer `{{commandContext.commandPrefix}}help {{command.name}}` para averiguar cómo usar este comando.", - "newsChannel": "No pude resolver `{{parameter}}` a un canal de anuncios, ¡por favor asegúrese de que escribió su nombre o ID correctamente!\n\n> **Consejo**: ¡También puedes mencionarlo!", - "numberError": "¡No pude resolver `{{parameter}}` a un número!", - "numberTooLarge": "", - "numberTooSmall": "¡El parámetro `{{parameter}}` es demasiado pequeño! ¡Debe ser al menos {{minimum}}!", - "piece": "¡No pude resolver `{{parameter}}` a una pieza! ¡Asegúrate de que escribiste su nombre o uno de sus alias correctamente!", - "rangeInvalid": "`{{parameter}}` debe ser un número o un rango de números.", - "rangeMax_other": "`{{parameter}}` acepta un rango de máximo {{maximum}} números", - "rangeMax_one": "`{{parameter}} acepta un máximo de {{maximum}} número", - "resetPossibles": [ - "apagado", - "restablecer" - ], - "roleError": "No pude resolver `{{parameter}}` a un rol, ¡por favor asegúrate de escribir su nombre o ID correctamente!\n\n> **Consejo**: ¡También puedes mencionarlo!", - "roleMissingGuild": "No pude resolver `{{parameter}}` porque este argumento requiere ser ejecutado en un canal de un servidor.", - "snowflake": "¡No pude resolver `{{parameter}}` a un copo de nieve válido! Son números con 17 a 18 dígitos, por ejemplo, ¡tu mensaje tiene un Snowflake de `{{message.id}}`!", - "store": "", - "stringTooLong": "¡El parámetro `{{parameter}}` es demasiado largo! ¡Debe tener menos de {{maximum}} caracter(es)!", - "stringTooShort": "¡El parámetro `{{parameter}}` es demasiado largo! ¡Debe tener menos de {{minimum}} caracter(es)!", - "time": "¡No pude resolver `{{parameter}}` a un tiempo válido!\n**Pista**: los siguientes formatos son compatibles:\n\n$t(arguments:durationFormats)\n$t(arguments:dateFormats)", - "timeSpan": "No pude resolver `{{parameter}}` a una duración válida, asegúrese de que escribió un entero válido o un valor formateado de duración. Algunos de los formatos válidos son:\n\n- `45` (45 segundos).\n$t(arguments:durationFormats)\n$t(arguments:dateFormats)", - "timeSpanTooBig": "El parámetro `{{parameter}}` resuelto a una duración mayor a {{maximum, duration}}, ¡el cual no está permitido!", - "timeSpanTooSmall": "El parámetro `{{parameter}}` resuelto a una duración menor a {{minimum, duration}}, ¡el cual no está permitido!", - "tooFewWinners": "El parámetro `{{parameter}}` resolvió a un número demasiado bajo, ¡debe ser al menos 1!", - "tooManyWinners": "El parámetro `{{parameter}}` resolvió a un número demasiado alto, ¡debe ser como máximo 20!", - "unavailable": "¡Ups! Parece que no he podido encontrar un analizador para un parámetro, ¡por favor contacta a mis desarrolladores sobre esto!", - "userError": "No pude resolver `{{parameter}}` a un usuario, ¡por favor asegúrate de escribir su nombre o ID correctamente!\n\n> **Consejo**: ¡También puedes mencionarlo!", - "enumEmptyError": "No pude resolver `{{parameter}}` porque la lista de valores posibles está vacía.", - "enumError": "No pude resolver `{{parameter}}` a un valor válido, los valores posibles son: {{possibles, orList}}" -} \ No newline at end of file diff --git a/src/languages/es-419/assertions.json b/src/languages/es-419/assertions.json deleted file mode 100644 index eff4222d4..000000000 --- a/src/languages/es-419/assertions.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "expectedNonThreadChannel": "Se esperaba un canal de texto normal, pero en su lugar recibí el hilo {{channel}}." -} \ No newline at end of file diff --git a/src/languages/es-419/commands/admin.json b/src/languages/es-419/commands/admin.json deleted file mode 100644 index 572e8e35c..000000000 --- a/src/languages/es-419/commands/admin.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "confUpdated": "Se actualizó exitosamente la clave **{{key}}**: `{{response}}", - "confGetNoExt": "La clave **{{key}}** parece no existir.", - "confGet": "El valor para la clave **{{key}}** es: `{{value}}`", - "confReset": "La clave **{{key}}** ha sido restablecida a: `{{value}}`", - "confNochange": "El valor de **{{key}}** ya era de ese valor.", - "confServerDescription": "Define los ajustes por servidor.", - "confServerExtended": { - "usages": [ - "set NombreDeClave Valor para la Clave", - "show", - "show NombreDeClave", - "remove NombreDeClave Valor para la Clave", - "reset NombreDeClave", - "menu" - ], - "extendedHelp": "Te permite configurar WolfStar desde Discord, como una alternativa rápida al [panel de control web](https://wolfstar.rocks).", - "examples": [ - "set language es-ES", - "set channels.moderation-logs #logs-de-moderacion", - "show", - "show channels", - "remove roles.moderator Moderador", - "reset roles.moderator", - "menu" - ], - "reminder": "Hay claves y grupos, claves que están dentro de un grupo son nombradas por `GroupName.KeyName`." - }, - "confServer": "**Configuración del servidor {{key}}**\n{{list}}", - "confDashboardOnlyKey": "`{{key}}` sólo puede configurarse a través del panel web ()", - "confSettingNotSet": "No Establecido", - "rolesetDescription": "Administrar los conjuntos de roles únicos.", - "rolesetExtended": { - "usages": [ - "set NombreDeConjuntoDeRoles Rol1 Rol2 Rol3...", - "remove NombreDeConjuntoDeRoles Rol1 Rol2 Rol3...", - "reset", - "reset NombreDeConjuntoDeRoles", - "list", - "NombreDeConjuntoDeRoles Rol1 Rol2 Rol3" - ], - "extendedHelp": "Un conjunto de roles es un grupo de roles que WolfStar identifica como único para todos los miembros del servidor, por ejemplo. un conjunto de roles llamado `region` podría tener los roles `África`, `America`, `Asia` y `Europa`, y los miembros solo podrán tener uno de ellos. Esto es como una especie de \"regla\" que se aplica en las tres siguientes situaciones:\n\n- Cuando alguien reclama un rol a través del comando `roles`.\n- Cuando alguien reclama un rol a través de roles de reacción.\n- Cuando alguien recibe un rol de forma manual o de otro bot.", - "explainedUsage": [ - [ - "añadir", - "Crea un nuevo conjunto de roles o añade un rol a un conjunto ya existente." - ], - [ - "eliminar", - "Eliminar un rol de un conjunto existente." - ], - [ - "resetear", - "Elimina todos los roles de un rol o, si no se especifica, todos los roles existentes." - ], - [ - "lista", - "Enumera todos los conjuntos de roles." - ], - [ - "automático", - "Añade o elimina un conjunto de roles." - ], - [ - "NombreDeConjuntoDeRoles", - "El nombre del set de roles" - ], - [ - "Rol1 Rol2 Rol3", - "Los roles a añadir al conjunto de roles" - ] - ], - "examples": [ - "add regiones América", - "add regiones África América Asia Europa", - "remove regiones América", - "reset", - "reset regiones", - "list", - "regiones América", - "regiones África América Asia Europa" - ], - "reminder": "Este comando puede agregar y/o eliminar múltiples roles al mismo tiempo." - }, - "rolesetCreated": "", - "rolesetAdded": "", - "rolesetRemoved": "", - "rolesetResetEmpty": "{{REDCROSS}} No existen conjuntos de roles configurados en este servidor.", - "rolesetResetAll": "{{GREENTICK}} Se han eliminado todos los conjuntos de roles con éxito.", - "rolesetResetNotExists": "{{REDCROSS}} The conjunto de roles `{{name}}` no existe en este servidor.", - "rolesetResetGroup": "{{GREENTICK}} Se eliminó correctamente el conjunto de roles `{{name}}` de este servidor.", - "rolesetUpdated": "El conjunto de roles único {{name}} ha sido actualizado.", - "rolesetNoRolesets": "No hay conjuntos de roles.", - "confMenuRenderAtFolder": "Actualmente en: 📁 {{path}}", - "confMenuRenderAtPiece": "Actualmente en: ⚙️ {{path}}", - "confMenuRenderNokeys": "No hay claves configurables para este grupo", - "confMenuRenderSelect": "Por favor ingrese cualquiera de los nombres de las siguientes entradas", - "confMenuRenderUpdate": "• Actualizar Valor → `set `", - "confMenuRenderRemove": "• Eliminar valor → `remove `", - "confMenuRenderReset": "• Restablecer valor → `reset`", - "confMenuRenderUndo": "• Deshacer actualización → `undo`", - "confMenuRenderCvalue": "Valor actual: **``{{value}}``**", - "confMenuRenderBack": "Pulsa ◀ para volver atrás", - "confMenuInvalidKey": "Clave no válida, por favor inténtalo de nuevo con cualquiera de las siguientes opciones.", - "confMenuInvalidAction": "Acción no válida, por favor inténtalo de nuevo con cualquiera de las siguientes opciones.", - "confMenuSaved": "Guardado todos los cambios con éxito." -} \ No newline at end of file diff --git a/src/languages/es-419/commands/animal.json b/src/languages/es-419/commands/animal.json deleted file mode 100644 index 4ab50fc35..000000000 --- a/src/languages/es-419/commands/animal.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "bunnyDescription": "Déjame mostrarte una imagen de un adorable conejito ❤️.", - "bunnyExtended": { - "extendedHelp": "Este comando da una imagen aleatoria de [bunnies.io](https://www.bunnies.io)." - }, - "bunnyEmbedData": { - "title": "Haga clic aquí si la imagen falla al cargar", - "source": "fuente" - }, - "dogDescription": "¡Perritos lindos! ❤", - "dogExtended": { - "extendedHelp": "¿Sabes cuán lindos son los perros? ¡Son tan hermosos!\n¡Este comando usa [dog.ceo](https://dog.ceo) para mostrar imágenes de los cachorros más monos!" - }, - "foxDescription": "¡Permítame mostrarte una imagen de un zorro!", - "foxExtended": { - "extendedHelp": "Este comando da una imagen aleatoria de [randomfox.ca](https://randomfox.ca/)." - }, - "kittyDescription": "¡GATITOS!", - "kittyExtended": { - "extendedHelp": "¿Sabes cuán lindos son los gatitos? ¡Son tan hermosos!\n¡Este comando usa [cataas.com](https://cataas.com/) para mostrar fotos de los gatitos más monos!" - }, - "shibeDescription": "¡Shibas monos!", - "shibeExtended": { - "extendedHelp": "Todo el mundo ama a los shibas, ¡y yo también! Son tan adorables ❤" - } -} \ No newline at end of file diff --git a/src/languages/es-419/commands/auto-moderation.json b/src/languages/es-419/commands/auto-moderation.json deleted file mode 100644 index 0ad2e4ea7..000000000 --- a/src/languages/es-419/commands/auto-moderation.json +++ /dev/null @@ -1,77 +0,0 @@ -{ - "showName": "mostrar", - "showDescription": "Muestra la configuración actual de este servidor", - "editName": "editar", - "editDescription": "Edita la configuración de este servidor", - "resetName": "restablecer", - "resetDescription": "Restablece una opción de configuración a su valor predeterminado", - "addName": "añadir", - "removeName": "eliminar", - "optionsEnabledName": "habilitado", - "optionsEnabledDescription": "Alternar el subsistema", - "optionsActionAlertName": "alerta", - "optionsActionAlertDescription": "Alternar alertas de mensajes en el canal", - "optionsActionLogName": "registro", - "optionsActionLogDescription": "Alterna los registros de mensajes en el canal de registro de moderación, si estuviera definido", - "optionsActionDeleteName": "borrar", - "optionsActionDeleteDescription": "Alterna el borrado de mensajes", - "optionsPunishmentName": "sanción", - "optionsPunishmentDescription": "Establece la acción de moderación a tomar después de que se alcance el umbral", - "optionsPunishmentDurationName": "duración-sanción", - "optionsPunishmentDurationDescription": "Establece la duración de la sanción", - "optionsThresholdName": "umbral", - "optionsThresholdDescription": "Establece la cantidad de infracciones permitidas en el periodo establecido", - "optionsThresholdPeriodName": "periodo-umbral", - "optionsThresholdPeriodDescription": "Establece el tiempo en el que se acumularán las infracciones", - "optionsKeyName": "opción", - "optionsKeyDescription": "La opción a restablecer", - "optionsKeyEnabled": "Habilitado", - "optionsKeyActionAlert": "Mensajes de Alerta", - "optionsKeyActionLog": "Publicar Registros de Moderación", - "optionsKeyActionDelete": "Borrado de Mensajes", - "optionsKeyPunishment": "Sanción", - "optionsKeyPunishmentDuration": "Duración de la Sanción", - "optionsKeyThreshold": "Umbral de la Sanción", - "optionsKeyThresholdPeriod": "Duración del Umbral de la Sanción", - "optionsKeyWords": "Palabras", - "optionsWordName": "palabra", - "optionsWordDescription": "La palabra a añadir o eliminar", - "attachmentsName": "automod-adjuntos", - "attachmentsDescription": "Administra el auto-moderador para archivos adjuntos", - "capitalsName": "automod-mayúsculas", - "capitalsDescription": "Administra el auto-moderador para mayúsculas", - "wordsName": "automod-palabras", - "wordsDescription": "Administra el auto-moderador para el filtro de palabras", - "invitesName": "automod-invitaciones", - "invitesDescription": "Administra el auto-moderador para las invitaciones", - "linksName": "automod-enlaces", - "linksDescription": "Administra el auto-moderador para el filtro de enlaces", - "spamName": "automod-spam", - "spamDescription": "Administra el auto-moderador para el filtro de spam", - "newlinesName": "automod-líneas", - "newlinesDescription": "Administra el auto-moderador para el filtro de líneas", - "reactionsName": "automod-reacciones", - "reactionsDescription": "Administra el auto-moderador para el filtro de reacciones", - "showDisabled": "Auto-moderador inactivo", - "showEnabled": "Auto-moderador activo", - "showReplyActive": "{{emoji}} **Mensajes de Alerta**", - "showReplyInactive": "{{emoji}} ~~Mensajes de Alerta~~", - "showLogActive": "{{emoji}} **Publicar Registros de Moderación**", - "showLogInactive": "{{emoji}} ~~Publicar Registros de Moderación~~", - "showDeleteActive": "{{emoji}} **Borrado de Mensajes**", - "showDeleteInactive": "{{emoji}} ~~Borrado de mensajes~~", - "showPunishmentTitle": "Sanción activa", - "showPunishment": "{{emoji}} **Tipo:** {{name}}", - "showPunishmentTemporary": "{{emoji}} **Tipo:** {{name}} por {{duration}}", - "showPunishmentThreshold": "{{emoji}} **Se aplica tras:** {{threshold, number}} infracciones en {{period}}", - "editSuccess": "Editado con éxito la configuración del auto-moderador.", - "wordAddDescription": "Añade una palabra al filtro", - "wordAddFiltered": "La palabra `{{word}}` ya estaba filtrada.", - "wordRemoveDescription": "Elimina una palabra del filtro", - "wordRemoveNotFiltered": "La palabra `{{word}}` no estaba filtrada.", - "wordShowList": "{{words, list(conjunction)}}", - "wordShowListTitle_one": "Palabra Filtrada ({{count, number}})", - "wordShowListTitle_other": "Palabras Filtradas ({{count, number}})", - "wordShowListEmpty": "Utilice {{command}} para añadir palabras a la lista de filtros.", - "wordShowListTitleEmpty": "No hay palabras filtradas actualmente" -} \ No newline at end of file diff --git a/src/languages/es-419/commands/case.json b/src/languages/es-419/commands/case.json deleted file mode 100644 index d99982bea..000000000 --- a/src/languages/es-419/commands/case.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "name": "caso", - "description": "Gestiona o visualiza casos de moderación.", - "viewName": "visualizar", - "viewDescription": "Muestra la información de un caso de moderación.", - "archiveName": "archivar", - "archiveDescription": "Archiva un caso de moderación.", - "deleteName": "borrar", - "deleteDescription": "Borra un caso de moderación.", - "editName": "editar", - "editDescription": "Edita un caso de moderación.", - "listName": "lista", - "listDescription": "Lista los casos de moderación.", - "optionsCaseName": "caso", - "optionsCaseDescription": "El número del caso de moderación.", - "optionsReasonName": "motivo", - "optionsReasonDescription": "El nuevo motivo para el caso de moderación.", - "optionsDurationName": "duración", - "optionsDurationDescription": "La nueva duración para el caso de moderación.", - "optionsUserName": "usuario", - "optionsUserDescription": "El usuario por el que filtrar los casos de moderación.", - "optionsOverviewName": "resumen", - "optionsOverviewDescription": "Si mostrar un resumen de los casos de moderación.", - "optionsTypeName": "tipo", - "optionsTypeDescription": "El tipo por el que filtrar los casos de moderación.", - "optionsPendingOnlyName": "sólo-pendientes", - "optionsPendingOnlyDescription": "Si mostrar únicamente los casos de moderación pendientes.", - "optionsShowName": "mostrar", - "optionsShowDescription": "Si mostrar o no la respuesta públicamente.", - "timeNotAllowed": "El tipo del caso de moderación (**{{type}}**) no permite una duración.", - "timeNotAllowedInCompletedEntries": "El caso de moderación `{{caseId}}` ya ha sido completado y no puede ser editado.", - "timeEditNotSupported": "El tipo de caso de moderación (**{{type}}**) no permite la edición de la duración.", - "timeTooEarly": "La duración del caso de moderación terminaría antes de que comience ({{time}}). La duración comienza en {{start}}.", - "listEmpty": "No hay casos de moderación con los filtros seleccionados.", - "listDetailsTitle_one": "Hay 1 entrada.", - "listDetailsTitle_other": "Hay {{count}} entradas.", - "listDetailsModerator": "{{emoji}} **Moderador:** {{mention}} ({{userId}})", - "listDetailsUser": "{{emoji}} **Usuario:** {{mention}} ({{userId}})", - "listDetailsExpires": "{{emoji}} **Expira {{time}}**", - "listOverviewFooter": "Este servidor tiene {{warnings}}, {{mutes}}, {{timeouts}}, {{kicks}} y {{bans}}", - "listOverviewFooterUser": "Este usuario tiene {{warnings}}, {{mutes}}, {{timeouts}}, {{kicks}} y {{bans}}", - "listOverviewFooterWarning_one": "{{count}} advertencia", - "listOverviewFooterWarning_other": "{{count}} advertencias", - "listOverviewFooterMutes_one": "{{count}} mute", - "listOverviewFooterMutes_other": "{{count}} mutes", - "listOverviewFooterTimeouts_one": "{{count}} tiempo de espera", - "listOverviewFooterTimeouts_other": "{{count}} tiempos de espera", - "listOverviewFooterKicks_one": "{{count}} expulsión", - "listOverviewFooterKicks_other": "{{count}} expulsiones", - "listOverviewFooterBans_one": "{{count}} baneo", - "listOverviewFooterBans_other": "{{count}} baneos", - "editSuccess": "Se ha editado correctamente el caso {{caseId}}.", - "archiveSuccess": "Se ha archivado correctamente el caso {{caseId}}.", - "deleteSuccess": "Se ha borrado correctamente el caso {{caseId}}." -} \ No newline at end of file diff --git a/src/languages/es-419/commands/fun.json b/src/languages/es-419/commands/fun.json deleted file mode 100644 index da7c134c8..000000000 --- a/src/languages/es-419/commands/fun.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "escaperopeDescription": "Usa la Cuerda Huida de Pokemon.", - "escaperopeExtended": { - "extendedHelp": "**WolfStar** utilizó **Cuerda Huida**." - }, - "escaperopeOutput": "**{{user}}** utilizó **Cuerda Huida**" -} \ No newline at end of file diff --git a/src/languages/es-419/commands/game.json b/src/languages/es-419/commands/game.json deleted file mode 100644 index 1a0ec1faa..000000000 --- a/src/languages/es-419/commands/game.json +++ /dev/null @@ -1,447 +0,0 @@ -{ - "c4Description": "Juega al Conecta Cuatro con alguien.", - "c4Extended": { - "usages": [ - "Usuario" - ], - "extendedHelp": "Este juego se juega mejor en el ordenador.\n\nEl objetivo de Conecta 4 es alinear cuatro fichas sobre un tablero formado por seis filas y siete columnas. Cada jugador dispone de 21 fichas de un color.​ Por turnos, los jugadores deben introducir una ficha en la columna que prefieran (siempre que no esté completa) y ésta caerá a la posición más baja. Gana la partida el primero que consiga alinear cuatro fichas consecutivas de un mismo color en horizontal, vertical o diagonal.​ Si todas las columnas están llenas pero nadie ha hecho una fila válida, hay empate.", - "examples": [ - "WolfStar" - ] - }, - "c4Prompt": "Estimado {{challengee}}. Has sido desafiado por {{challenger}} en una partida de Conecta 4. ¡Haz clic en la reacción to para aceptar!", - "gamesBot": "Lo siento, pero no creo que les gustaría dejar de hacer lo que están haciendo y jugar con los humanos.", - "gamesNoPlayers": "Por favor especifica algunos tributos para jugar a las Partidas del Hambre, así: `{{prefix}}hg Bob, Mark, Jim, Kyra`", - "gamesProgress": "Lo siento, pero hay un juego en curso en este canal, inténtelo de nuevo cuando termine.", - "gamesPromptDeny": "Lo siento, pero el contrincante se negó a jugar.", - "gamesRepeat": "Lo siento, pero un usuario no puede jugar dos veces.", - "gamesSelf": "Debes estar muy triste para jugar contra ti mismo. Inténtalo de nuevo con otro usuario.", - "gamesTooManyOrFew": "Lo siento, pero la cantidad de jugadores es menor que {{min}} o mayor que {{max}}.", - "hgBloodbath": [ - "{1} agarra una pala.", - "{1} toma una mochila y huye.", - "{1} y {2} luchan por una bolsa. {1} abandona y se retira.", - "{1} y {2} luchan por una bolsa. {2} abandona y se retira.", - "{1} encuentra un arco, algunas flechas y una aljaba.", - "{1} corre hacia la cornucopia y se esconde.", - "{1} toma un puñado de cuchillos arrojadizos.", - "{1} le arranca la maza de las manos de {2}.", - "{1} encuentra una cantimplora llena de agua.", - "{1} se queda en la cornucopia para recoger recursos.", - "{1} recolecta tanta comida como puede.", - "{1} agarra una espada.", - "{1} toma una lanza dentro de la cornucopia.", - "{1} encuentra una bolsa llena de explosivos.", - "{1} agarra un kit de primeros auxilios y huye.", - "{1} toma una hoz dentro de la cornucopia.", - "{1}, {2} y {3} trabajan juntos para obtener tantos suministros como sea posible.", - "{1} corre con un mechero y una cuerda.", - "{1} agarra una botella de alcohol y un trapo.", - "{1} encuentra una mochila llena de equipamiento de acampada.", - "{1} agarra una mochila, sin darse cuenta de que está vacía.", - "{1} rompe la nariz de {2} por una cesta de pan.", - "{1}, {2}, {3} y {4} comparten todo lo que recolectaron antes de correr.", - "{1} pilla un tridente dentro de la cornucopia.", - "{1} agarra un tarro de cebo de pesca mientras que {2} obtiene equipamiento de pesca.", - "{1} asusta a {2} de la cornucopia.", - "{1} agarra un escudo de la cornucopia.", - "{1} toma un par de kukris.", - "{1} agarra un solo par de pantalones.", - "{1T} abandona su podio demasiado pronto y explota.", - "{1} tira un cuchillo a la cabeza de {2T}.", - "{1T} pisa accidentalmente en una mina terrestre.", - "{1} pilla a {2T} fuera de guardia y lo mata.", - "{1} y {2} trabajan juntos para ahogar a {3T}.", - "{1} ahoga a {2T} después de una pelea a puños.", - "{1} dispara una flecha a la cabeza de {2T}.", - "{1T} no puede manejar las circunstancias y comete suicidio.", - "{1} golpea la cabeza de {2T} contra una roca varias veces.", - "{1} rompe el cuello de {2T}.", - "{1} decapita a {2T} con una espada.", - "{1} alancea a {2T} en el abdomen.", - "{1} prende fuego a {2T} con un molotov.", - "{1T} cae en un pozo y muere.", - "{1} apuñala a {2T} mientras que estaba de espaldas.", - "{1} hiere severamente a {2T}, pero lo saca de su miseria.", - "{1} hiere severamente a {2T} y le deja morir.", - "{1} rompe la cabeza de {2T} con un mazo.", - "{1} empuja a {2T} de un acantilado durante una pelea de cuchillo.", - "{1} tira un cuchillo a la torso de {2T}.", - "{1T} es incapaz de convencer a {2} de que no le mate.", - "{1} convence a {2T} para que no le mate, solo para matar a {2T} en su lugar.", - "{1T} cae en un lago congelado y se ahoga.", - "{1}, {2} y {3T} empiezan a luchar, pero {2} huye tan pronto como {1} mata a {3T}.", - "{1} mata a {2T} con su propio arma.", - "{1} aplasta a {2T}, matándoles.", - "{1} detona una carga explosiva, matando a {2T}.", - "{1} pone una carga explosiva, matando a {2T} y {3T}.", - "{1} pone una carga explosiva, matando a {2T}, {3T}, {4T}.", - "{1} pone una carga explosiva, matando a {2T}, {3T}, {4T} y {5T}.", - "{1} mata a {2T} mientras que intentaba correr.", - "{1T} y {2T} amenaza con un suicidio doble. Falla y mueren.", - "{1T}, {2T}, {3T} y {4T} forman un pacto de suicidio, matándose a sí mismos.", - "{1} mata a {2T} con un hacha.", - "{1} y {2} luchan contra {3T} y {4T}. {1} y {2} sobreviven.", - "{1T} y {2T} luchan contra {3} y {4}. {3} y {4} sobreviven.", - "{1T} ataca a {2}, pero {3} le protege, matando a {1T}.", - "{1} rebana severamente {2T} con una espada.", - "{1} ahoga a {2T} con una cuerda.", - "{1} mata a {2T} por sus suministros.", - "{1} dispara una flecha a {2}, pero falla y mata a {3T}.", - "{1} dispara un dardo venenoso en el cuello de {2T}, matándolo lentamente.", - "{1} apuñala a {2T} con una rama de árbol.", - "{1} apuñala a {2T} en la espalda con un tridente.", - "{1}, {2T} y {3T} entran en una pelea. {1} mata triunfantemente a ambos.", - "{1T}, {2} y {3T} entran en una pelea. {2} mata triunfantemente a ambos.", - "{1T}, {2T} y {3} entran en una pelea. {3} mata triunfantemente a ambos.", - "{1} encuentra a {2T} escondido en la cornucopia y lo mata.", - "{1T} encuentra a {2} oculto en la cornucopia, pero {2} lo mata.", - "{1} mata a {2T} con una hoz.", - "{1} y {2T} luchan por una bolsa. {1} estrangula a {2T} con las correas y huye.", - "{1T} y {2} luchan por una bolsa. {2} estrangula a {1T} con las correas y huye.", - "{1} apuñala repetidamente con kukris a {2T} hasta morir.", - "{1T} se resbala mientras que corría desde la cornucopia, y es matado por {2}.", - "{1} se resbala mientras que corría de la cornucopia, {2} lo recoge y corren fuera juntos.", - "{1} apunta a una flecha en la cabeza de {2} y dispara, {3T} salta en el camino y sacrifica su vida para salvarle." - ], - "hgDay": [ - "{1} se va de caza.", - "{1} se lesiona a sí mismo.", - "{1} explora la arena.", - "{1} le asusta a {2}.", - "{1} desvía la atención de {2} y huye.", - "{1} acecha a {2}.", - "{1} pesca.", - "{1} se camufla en el arbusto.", - "{1} roba a {2} mientras no estaba mirando.", - "{1} hace una lanza de madera.", - "{1} descubre una cueva.", - "{1} ataca a {2}, pero consigue escapar.", - "{1} persigue a {2}.", - "{1} huye de {2}.", - "{1} recolecta frutos de un árbol.", - "{1} recibe un hacha de un patrocinador desconocido.", - "{1} recibe agua limpia de un patrocinador desconocido.", - "{1} recibe suministros médicos de un patrocinador desconocido.", - "{1} recibe comida fresca de un patrocinador desconocido.", - "{1} busca una fuente de agua.", - "{1} derrota a {2} en una pelea, pero le perdona la vida.", - "{1} y {2} trabajan juntos durante el día.", - "{1} pide a {2} que lo mate. Se niega, dejando a {1} vivo.", - "{1} intenta dormir todo el día.", - "{1}, {2}, {3} y {4} asaltan el campamento de {5} mientras que cazaba.", - "{1} construye una chabola.", - "{1} escucha la conversación de {2} y {3} a distancia.", - "{1} practica su tiro con arco.", - "{1} piensa de su casa.", - "{1} es pinchado por espinas al recoger bayas.", - "{1} intenta alancear peces con un tridente.", - "{1} busca leña.", - "{1} y {2} se dividen para buscar recursos.", - "{1} coge flores.", - "{1} tiende a las heridas de {2}.", - "{1} ve humo en la distancia, pero decide no investigar.", - "{1} se tuece el tobillo mientras huía de {2}.", - "{1} hace un tirachinas.", - "{1} viaja a un terreno más alto.", - "{1} descubre un río.", - "{1} va de caza a por los otros tributos.", - "{1} y {2} van de caza a por los otros tributos.", - "{1}, {2} y {3} van de caza a por los otros tributos.", - "{1}, {2}, {3} y {4} van de caza a por los otros tributos.", - "{1}, {2}, {3}, {4} y {5} van de caza a por los otros tributos.", - "{1} recibe un explosivo de un patrocinador desconocido.", - "{1} cuestiona su cordura.", - "{1} fuerza a {2} a comer un pantalón.", - "{1} fuerza a {2T} a comer un pantalón. {2T} se ahoga y muere.", - "{1} pilla a {2T} fuera de guardia y lo mata.", - "{1} tira un cuchillo a la cabeza de {2T}.", - "{1T} ruega a {2} para que lo mate. Hace el favor y mata a {1T}.", - "{1} y {2} trabajan juntos para ahogar a {3T}.", - "{1} ahoga a {2T} después de una pelea a puños.", - "{1} dispara una flecha a la cabeza de {2T}.", - "{1T} se desangra debido a lesiones no tratadas.", - "{1T} no puede manejar las circunstancias y comete suicidio.", - "{1} golpea la cabeza de {2T} contra una roca varias veces.", - "{1T} consume bayas tóxicas sin saberlo.", - "{1} rompe el cuello de {2T} de forma silenciosa.", - "{1} envenena la comida de {2T}, matándolo.", - "{1} decapita a {2T} con una espada.", - "{1T} muere de una infección.", - "{1} alancea a {2T} en el abdomen.", - "{1} prende fuego a {2T} con un molotov.", - "{1T} cae en un pozo y muere.", - "{1} apuñala a {2T} mientras que estaba de espaldas.", - "{1} hiere severamente a {2T}, pero lo saca de su miseria.", - "{1} hiere severamente a {2T} y le deja morir.", - "{1} rompe la cabeza de {2T} con un mazo.", - "{1T} intenta escalar un árbol, pero se cae y muere.", - "{1} empuja a {2T} de un acantilado durante una pelea de cuchillo.", - "{1} tira un cuchillo al torso de {2T}.", - "La trampa de {1} mata a {2T}.", - "{1} mata a {2T} mientras descansa.", - "{1T} es incapaz de convencer a {2} de que no le mate.", - "{1} convence a {2T} para que no le mate, solo para matar a {2T} en su lugar.", - "{1T} cae en un lago congelado y se ahoga.", - "{1}, {2} y {3T} empiezan a luchar, pero {2} huye tan pronto como {1} mata a {3T}.", - "{1} mata a {2T} con su propio arma.", - "{1} vence a {2T}, matándoles.", - "{1} detona una carga explosiva, matando a {2T}.", - "{1} pone una carga explosiva, matando a {2T} y {3T}.", - "{1} pone una carga explosiva, matando a {2T}, {3T} y {4T}.", - "{1} pone una carga explosiva, matando a {2T}, {3T}, {4T} y {5T}.", - "{1} mata a {2T} mientras que intentaba correr.", - "{1T} y {2T} amenaza con un suicidio doble. Falla y mueren.", - "{1T}, {2T}, {3T} y {4T} forman un pacto de suicidio, matándose a sí mismos.", - "{1T} muere por hipotermia.", - "{1T} muere de hambre.", - "{1T} muere de sed.", - "{1} mata a {2T} con un hacha.", - "{1} y {2} luchan contra {3T} y {4T}. {1} y {2} sobreviven.", - "{1T} y {2T} luchan contra {3} y {4}. {3} y {4} sobreviven.", - "{1T} muere intentando escapar de la arena.", - "{1T} muere de disentería.", - "{1T} detona accidentalmente una mina de tierra mientras intenta armarla.", - "{1T} ataca a {2}, pero {3} le protege, matando a {1T}.", - "{1} embosca a {2T} y lo mata.", - "{1T} pisa accidentalmente en una mina terrestre.", - "{1} rebana severamente {2T} con una espada.", - "{1} ahoga a {2T} con una cuerda.", - "{1} mata a {2T} por sus suministros.", - "{1} dispara una flecha a {2}, pero falla y mata a {3T}.", - "{1} dispara un dardo venenoso en el cuello de {2T}, matándolo lentamente.", - "{1}, {2} y {3} emboscan y matan con éxito a {4T}, {5T} y {6T}.", - "{1T}, {2T} y {3T} emboscan sin éxito a {4}, {5} y {6}, quienes los matan en su lugar.", - "{1} apuñala a {2T} con una rama de árbol.", - "{1} fuerza a {2} a matar o a {3T} o a {4}. Decide matar a {3T}.", - "{1} fuerza a {2} a matar o a {3} o a {4T}. Decide matar a {4T}.", - "{1} fuerza a {2T} a matar a {3} o a {4}. Se niega a matar, así que {1} lo mata en su lugar.", - "{1T} envenena la bebida de {2}, pero la equivoca por su propia y muere.", - "{1} envenena la bebida de {2T}. La bebe y mueren.", - "{1} apuñala a {2T} en la espalda con un tridente.", - "{1T} intenta escalar un árbol, pero se cae en {2T} y ambos mueren.", - "{1}, {2T} y {3T} entran en una pelea. {1} los mata triunfantemente a ambos.", - "{1T}, {2} y {3T} entran en una pelea. {2} los mata triunfantemente a ambos.", - "{1T}, {2T} y {3} entran en una pelea. {3} los mata triunfantemente a ambos.", - "{1} mata a {2T} con una hoz.", - "{1}, {2}, {3}, {4} y {5} buscan y matan a {6T}.", - "{1}, {2}, {3} y {4} buscan y matan a {5T}.", - "{1}, {2} y {3} buscan y matan a {4T}.", - "{1} y {2} buscan y matan a {3T}.", - "{1} busca y mata a {2T}.", - "{1} apuñala repetidamente con una kukris a {2T} hasta matarlo.", - "{1} garabatea en la tierra.", - "{1} persigue a una mariposa.", - "{1T} cae de un acantilado y se ve empalado por un palo.", - "{1} se choca con {2}, deciden crear un equipo.", - "{1} ve {2} a través de los árboles y planea matarle.", - "{1} se acecha detrás de {2T} y rompe su cuello.", - "{1T} desafía a {2} a una pelea, y rápidamente muere.", - "{1} asesina a su compañero, {2T}, para tener más suministros para sí mismo." - ], - "hgNight": [ - "{1} inicia un fuego.", - "{1} instala un campamento para la noche.", - "{1} se ha perdido.", - "{1} sube un árbol para descansar.", - "{1} se va a dormir.", - "{1} y {2} se cuentan historias acerca de sí mismos.", - "{1}, {2}, {3} y {4} se duermen en turnos.", - "{1}, {2} y {3} se duermen en turnos.", - "{1} y {2} se duermen en turnos.", - "{1} tiende a sus heridas.", - "{1} ve un fuego, pero permanece oculto.", - "{1} grita en busca de ayuda.", - "{1} permanece despierto toda la noche.", - "{1} pierde el conocimiento por agotamiento.", - "{1} cocina su comida antes de apagar su fuego.", - "{1} y {2} se encuentran entre sí y deciden hacer tregua por la noche.", - "{1} aleja a {2}, {3} y {4} de su fuego.", - "{1}, {2} y {3} discuten los juegos y lo que podría pasar por la mañana.", - "{1} llora hasta dormir.", - "{1} intenta tratar su infección.", - "{1} y {2} hablan sobre los tributos aún vivos.", - "{1} se despierta por una pesadilla.", - "{1} y {2} se abrazan para mantener el calor.", - "{1} piensa en ganar.", - "{1}, {2}, {3} y {4} se cuentan entre sí historias de fantasmas para mejorar el estado de ánimo.", - "{1} mira al cielo nocturno.", - "{1} derrota a {2} en una pelea, pero le perdona la vida.", - "{1} pide a {2} que lo mate. Se niega, dejando a {1} vivo.", - "{1} destruye los suministros de {2} mientras duerme.", - "{1}, {2}, {3}, {4} y {5} duermen en turnos.", - "{1} permite a {2} entrar en su refugio.", - "{1} recibe un hacha de un patrocinador desconocido.", - "{1} recibe agua limpia de un patrocinador desconocido.", - "{1} recibe suministros médicos de un patrocinador desconocido.", - "{1} recibe comida fresca de un patrocinador desconocido.", - "{1} intenta cantar hasta dormir.", - "{1} intenta iniciar un fuego, pero no tiene éxito.", - "{1} piensa de su casa.", - "{1} tiende a las heridas de {2}.", - "{1} tatarea silenciosamente.", - "{1}, {2} y {3} cantan canciones alegremente juntos.", - "{1} no puede iniciar un fuego y duerme sin calor.", - "{1} y {2} sostienen las manos.", - "{1} convence a {2} para que se pegue con ellos.", - "{1} recibe un explosivo de un patrocinador desconocido.", - "{1} cuestiona su cordura.", - "{1} fuerza a {2} a comer un pantalón.", - "{1} fuerza a {2T} a comer un pantalón. {2T} se ahoga y muere.", - "{1} pilla a {2T} fuera de guardia y lo mata.", - "{1} lanza un cuchillo a la cabeza de {2T}.", - "{1T} ruega a {2} para que lo mate. Hace el favor y mata a {1T}.", - "{1} y {2} trabajan juntos para ahogar a {3T}.", - "{1} ahoga a {2T} después de una pelea a puños.", - "{1} dispara una flecha a la cabeza de {2T}.", - "{1T} se desangra debido a lesiones no tratadas.", - "{1T} no puede manejar las circunstancias y comete suicidio.", - "{1} golpea la cabeza de {2T} contra una roca varias veces.", - "{1T} consume bayas tóxicas sin saberlo.", - "{1} rompe el cuello de {2T} de forma silenciosa.", - "{1} envenena la comida de {2T}, matándolo.", - "{1} decapita a {2T} con una espada.", - "{1T} muere de una infección.", - "{1} alancea a {2T} en el abdomen.", - "{1} prende fuego a {2T} con un molotov.", - "{1T} cae en un pozo y muere.", - "{1} apuñala a {2T} mientras que estaba de espaldas.", - "{1} hiere severamente a {2T}, pero lo saca de su miseria.", - "{1} hiere severamente a {2T} y le deja morir.", - "{1} rompe la cabeza de {2T} con un mazo.", - "{1T} intenta escalar un árbol, pero se cae y muere.", - "{1} empuja a {2T} de un acantilado durante una pelea de cuchillo.", - "{1} lanza un cuchillo al torso de {2T}.", - "La trampa de {1} mata a {2T}.", - "{1} mata a {2T} mientras duerme.", - "{1T} es incapaz de convencer a {2} de que no le mate.", - "{1} convence a {2T} para que no le mate, solo para matar a {2T} en su lugar.", - "{1T} cae en un lago congelado y se ahoga.", - "{1}, {2} y {3T} empiezan a luchar, pero {2} huye tan pronto como {1} mata a {3T}.", - "{1} mata a {2T} con su propio arma.", - "{1} sobrepasa a {2T}, matándoles.", - "{1} detona una carga explosiva, matando a {2T}.", - "{1} pone una carga explosiva, matando a {2T} y {3T}.", - "{1} pone una carga explosiva, matando a {2T}, {3T} y {4T}.", - "{1} pone una carga explosiva, matando a {2T}, {3T}, {4T} y {5T}.", - "{1} mata a {2T} mientras que intentaba correr.", - "{1T} y {2T} amenaza con un suicidio doble. Falla y mueren.", - "{1T}, {2T}, {3T} y {4T} forman un pacto de suicidio, matándose a sí mismos.", - "{1T} muere por hipotermia.", - "{1T} muere de hambre.", - "{1T} muere de sed.", - "{1} mata a {2T} con un hacha.", - "{1} y {2} luchan contra {3T} y {4T}. {1} y {2} sobreviven.", - "{1T} y {2T} luchan contra {3} y {4}. {3} y {4} sobreviven.", - "{1T} muere intentando escapar de la arena.", - "{1T} muere de disentería.", - "{1T} detona accidentalmente una mina de tierra mientras intenta armarla.", - "{1T} ataca a {2}, pero {3} le protege, matando a {1T}.", - "{1} embosca a {2T} y lo mata.", - "{1T} pisa accidentalmente en una mina terrestre.", - "{1} rebana severamente a {2T} con una espada.", - "{1} ahoga a {2T} con una cuerda.", - "{1} mata a {2T} por sus suministros.", - "{1} dispara una flecha a {2}, pero falla y mata a {3T}.", - "{1} dispara un dardo venenoso en el cuello de {2T}, matándolo lentamente.", - "{1}, {2} y {3} emboscan y matan con éxito a {4T}, {5T} y {6T}.", - "{1T}, {2T} y {3T} emboscan sin éxito a {4}, {5} y {6}, quienes los matan en su lugar.", - "{1} apuñala a {2T} con una rama de árbol.", - "{1} fuerza a {2} a matar o a {3T} o a {4}. Decide matar a {3T}.", - "{1} fuerza a {2} a matar o a {3} o a {4T}. Decide matar a {4T}.", - "{1} fuerza a {2T} a matar o a {3} o a {4}. Se niega a matar, así que {1} lo mata en su lugar.", - "{1T} envenena la bebida de {2}, pero la equivoca por su propia y muere.", - "{1} envenena la bebida de {2T}. La bebe y muere.", - "{1} apuñala a {2T} en la espalda con un tridente.", - "{1T} intenta escalar un árbol, pero se cae en {2T} y ambos mueren.", - "{1}, {2T} y {3T} entran en una pelea. {1} los mata triunfantemente a ambos.", - "{1T}, {2} y {3T} entran en una pelea. {2} los mata triunfantemente a ambos.", - "{1T}, {2T} y {3} entran en una pelea. {3} los mata triunfantemente a ambos.", - "{1} mata a {2T} con una hoz.", - "{1}, {2}, {3}, {4} y {5} buscan y matan a {6T}.", - "{1}, {2}, {3} y {4} buscan y matan a {5T}.", - "{1}, {2} y {3} buscan y matan a {4T}.", - "{1} y {2} buscan y matan a {3T}.", - "{1} busca y mata a {2T}.", - "{1} apuñala repetidamente con kukris a {2T} hasta morir.", - "{1} escribe en su diario.", - "{1} mira a {2} sentados en su hoguera, y considera matarle" - ], - "hungerGamesDescription": "¡Juega a los Juegos de Hambre con tus amigos!", - "hungerGamesExtended": { - "usages": [ - "Usuario1 Usuario2 Usuario3...", - "--autofill" - ], - "extendedHelp": "Basta de discusión, ¡que comiencen los juegos del hambre!", - "examples": [ - "WolfStar, Katniss, Peeta, Clove, Cato, Johanna, Brutus, Blight" - ], - "reminder": "Puede especificar `--autoskip` para omitir automáticamente después de algún tiempo." - }, - "hungerGamesResultDeaths_one": "**{{count}} disparo de cañón se puede escuchar en la distancia.**", - "hungerGamesResultDeaths_other": "**{{count}} disparos de cañón se pueden escuchar en la distancia.**", - "hungerGamesResultHeaderBloodbath": "Baño de Sangre", - "hungerGamesResultHeaderMoon": "Noche {{game.turn}}", - "hungerGamesResultHeaderSun": "Día {{game.turn}}", - "hungerGamesResultProceed": "¿Continuar?", - "hungerGamesStop": "¡El juego terminó por elección! ¡Nos vemos más tarde!", - "hungerGamesWinner": "¡Y el ganador es... {{winner}}!", - "ticTacToeDescription": "Juega al Tres en Raya con alguien.", - "ticTacToeDraw": "¡Esta partida concluyó en un **empate**!\n{{board}}", - "ticTacToeExtended": { - "usages": [ - "Usuario" - ], - "extendedHelp": "Tres en Raya es un juego de papel y lápiz para dos jugadores, X y O, que toman turnos marcando los espacios en una cuadrícula de 3×3.\nEl jugador que consigue colocar tres de sus marcas en una fila horizontal, vertical, o diagonal gana el juego.", - "examples": [ - "WolfStar" - ] - }, - "ticTacToePrompt": "Estimado {{challengee}}. Has sido desafiado por {{challenger}} en una partida de Tres en Raya. ¡Haz clic en la reacción to para aceptar!", - "ticTacToeTurn": "({{icon}}) ¡Turno para {{player}}!\n{{board}}", - "ticTacToeWinner": "¡El ganador es... {{winner}}!\n{{board}}", - "triviaActiveGame": "Ya se está jugando una partida de trivia en este canal", - "triviaDescription": "Juega una partida de Trivia.", - "triviaEmbedTitles": { - "difficulty": "Dificultad", - "trivia": "Trivia" - }, - "triviaExtended": { - "usages": [ - "", - "Categoría", - "Categoría multiple/boolean/truefalse", - "multiple easy/medium/hard", - "hard 2m" - ], - "extendedHelp": "Responda a preguntas de trivia aquí, ¡con categorías que van desde los libros hasta la mitología! (alimentado por OpenTDB)\n\n**Categorías**: {{TRIVIA_CATEGORIES}}", - "explainedUsage": [ - [ - "Categoría", - "Las preguntas de la categoría se harán a continuación." - ], - [ - "multiple/boolean/truefalse", - "Si desea una opción múltiple o una pregunta verdadera/falsa." - ], - [ - "easy/medium/hard", - "El nivel de dificultad de las preguntas formuladas." - ], - [ - "Duración", - "La cantidad de tiempo que obtienes para responder. El mínimo es de 1 segundo y el máximo es de 1 minuto" - ] - ], - "examples": [ - "history", - "books multiple easy", - "videogames 45s" - ] - }, - "triviaIncorrect": "Lo siento, pero **{{attempt}}** no es la respuesta correcta. ¡Buena suerte la próxima vez!", - "triviaInvalidCategory": "Categoría no válida: Por favor usa `WolfStar, help trivia` para leer la lista de categorías.", - "triviaNoAnswer": "¡Parece que nadie lo ha conseguido! La respuesta correcta era **{{correctAnswer}}**.", - "triviaWinner": "¡Tenemos un ganador! ¡{{winner}} tuvo una respuesta correcta con **{{correctAnswer}}**!" -} \ No newline at end of file diff --git a/src/languages/es-419/commands/general.json b/src/languages/es-419/commands/general.json deleted file mode 100644 index 3ac130146..000000000 --- a/src/languages/es-419/commands/general.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "helpAllFlag": "Mostrando una categoría por página. ¿Tiene problemas con el incrustado? Ejecute `{{prefix}}help --all` para obtener una lista completa en mensajes directos.", - "helpCommandCount_one": "{{count}} comando", - "helpCommandCount_other": "{{count}} comandos", - "helpData": { - "footer": "Descripción de ayuda para {{footerName}}", - "title": "{{titleDescription}}" - }, - "helpDescription": "Muestra todos los comandos o la descripción de uno.", - "helpExtended": { - "usages": [ - "--cat/--categories", - "--all", - "NombreDeCategoría", - "Página", - "NombreDeComando" - ], - "extendedHelp": "El comando de ayuda muestra una lista paginada de todos los comandos por sus categorías, o la información extendida de un comando si se especifica.\n\nSi utiliza `--categories` o `--cat`, puede obtener la lista de todas las categorías y la cantidad de comandos en cada una de ellas.", - "reminder": "El comando de ayuda **sólo** muestra los comandos que puedes utilizar. Para la lista completa, por favor visita .", - "examples": [ - "--cat", - "--all", - "Moderación", - "12", - "help" - ] - }, - "helpDm": "📥 | La lista de comandos a los que tienes acceso ha sido enviada a tus mensajes directos.", - "helpNodm": "{{REDCROSS}} | Tienes los mensajes directos deshabilitados, por lo que no pude enviarte la lista de comandos.", - "v7Description": "", - "v7Extended": { - "extendedHelp": "" - }, - "v7Message": "", - "v7NayreMessage": "" -} \ No newline at end of file diff --git a/src/languages/es-419/commands/info.json b/src/languages/es-419/commands/info.json deleted file mode 100644 index b184beadf..000000000 --- a/src/languages/es-419/commands/info.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "info", - "description": "Provee la información sobre mí junto a mi enlace de invitación y el del servidor de soporte", - "embedDescription": "[WolfStar](https://wolfstar.rocks) {{VERSION}} es un bot diseñado para ayudarte a moderar tu servidor. Uso [Sapphire Framework](https://sapphirejs.dev) con la [librería Discord.js](https://discord.js.org).\n- [Política de privacidad](https://wolfstar.rocks/privacy) | [Términos de servicio](https://github.com/wolfstar-project/wolfstar/blob/main/.github/TERMS_OF_SERVICE.md).", - "embedFieldApplicationTitle": "Estadísticas", - "embedFieldApplicationValue": "- **Usuarios**: {{users, number}}\n- **Servidores**: {{guilds, number}}\n- **Canales**: {{channels, number}}\n- **Discord.js**: {{versionDiscord}}\n- **Sapphire**: {{versionSapphire}}\n- **Node.js**: {{versionNode}}", - "embedFieldUptimeTitle": "Tiempo de Funcionamiento", - "embedFieldUptimeValue": "- **Servidor**: {{host}}\n- **Cliente**: {{client}}", - "embedFieldServerUsageTitle": "Uso del Servidor", - "embedFieldServerUsageValue": "- **Uso de CPU**: {{cpu}}\n- **Memoria**: {{heapUsed}}MB (Total: {{heapTotal}}MB)", - "buttonInvite": "¡Añádeme a tu servidor!", - "buttonSupport": "Servidor de soporte", - "buttonGitHub": "Repositorio de GitHub", - "buttonDonate": "Donar" -} \ No newline at end of file diff --git a/src/languages/es-419/commands/management.json b/src/languages/es-419/commands/management.json deleted file mode 100644 index 1cf7f148d..000000000 --- a/src/languages/es-419/commands/management.json +++ /dev/null @@ -1,445 +0,0 @@ -{ - "commandHandlerAborted": "Cancelado", - "permissionNodesHigher": "{{REDCROSS}} No puedes modificar ni previsualizar los nodos de permiso para este objetivo.", - "permissionNodesCannotAllowEveryone": "{{REDCROSS}} No puedes habilitar comandos para el rol `@everyone`.", - "permissionNodesInvalidType": "{{REDCROSS}} Tipo inválido, se esperaba ya sea de `allow` o `deny`.", - "permissionNodesAdd": "{{GREENTICK}} Se ha añadido correctamente el comando al nodo de permisos.", - "permissionNodesNodeNotExists": "{{REDCROSS}} El nodo de permiso seleccionado no existe.", - "permissionNodesCommandNotExists": "{{REDCROSS}} El comando seleccionado no existe en el nodo de permiso.", - "permissionNodesRemove": "{{GREENTICK}} Se ha eliminado correctamente el comando del nodo de permisos.", - "permissionNodesReset": "{{GREENTICK}} Se han eliminado correctamente todos los comandos del nodo de permisos.", - "permissionNodesShowName": "Permisos para: __{{name}}__", - "permissionNodesShowAllow": "**Permitidos**: {{allow}}", - "permissionNodesShowDeny": "**Desactivado**: {{deny}}", - "guildInfoTitles": { - "CHANNELS": "", - "MEMBERS": "", - "OTHER": "" - }, - "guildInfoChannels": "", - "guildInfoChannelsAfkChannelText": "", - "guildInfoMembers": "", - "guildInfoOther": "", - "guildInfoBanner": "", - "guildInfoIcon": "", - "guildInfoSplash": "", - "guildInfoDiscoverySplash": "", - "roleInfoTitles": { - "PERMISSIONS": "" - }, - "roleInfoData": "", - "roleInfoAll": "", - "roleInfoNoPermissions": "", - "manageCommandAutoDeleteShowEmpty": "", - "manageCommandAutoDeleteShow": "", - "manageCommandAutoDeleteAdd": "", - "manageCommandAutoDeleteRemove": "", - "manageCommandAutoDeleteRemoveNotset": "", - "manageCommandAutoDeleteReset": "", - "manageCommandChannelShow": "", - "manageCommandChannelShowEmpty": "", - "manageCommandChannelAddAlreadyset": "", - "manageCommandChannelAdd": "", - "manageCommandChannelRemoveNotset": "", - "manageCommandChannelRemove": "", - "manageCommandChannelResetEmpty": "", - "manageCommandChannelReset": "", - "manageReactionRolesShowEmpty": "", - "manageReactionRolesAddChannel": "", - "manageReactionRolesAddPrompt": "", - "manageReactionRolesAddMissing": "", - "manageReactionRolesAdd": "", - "manageReactionRolesRemoveNotExists": "", - "manageReactionRolesRemove": "", - "manageReactionRolesResetEmpty": "", - "manageReactionRolesReset": "", - "configurationEquals": "", - "setIgnoreChannelsSet": "", - "setIgnoreChannelsRemoved": "", - "setImageLogsSet": "", - "setMemberAddLogsSet": "", - "setMemberRemoveLogsSet": "", - "setMessageUpdateLogsSet": "", - "setMessageDeleteLogsSet": "", - "setModLogsSet": "", - "setPrefixSet": "", - "stickyRolesNotExists": "", - "stickyRolesReset": "", - "stickyRolesRemove": "", - "stickyRolesAdd": "", - "stickyRolesShowEmpty": "", - "stickyRolesShowSingle": "", - "createMuteDescription": "", - "createMuteExtended": { - "extendedHelp": "" - }, - "permissionNodesDescription": "Configurar los nodos de permiso para este servidor.", - "permissionNodesExtended": { - "usages": [ - "add Rol/Miembro allow/deny Comando", - "remove Role/Member allow/deny Command", - "reset Rol/Miembro", - "show Rol/Miembro", - "show", - "Rol/Miembro" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "managecommandautodeleteDescription": "", - "managecommandautodeleteExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageCommandChannelDescription": "", - "manageCommandChannelExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageReactionRolesDescription": "", - "manageReactionRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "rolesAdded": "", - "rolesAuditlog": "", - "rolesListEmpty": "", - "rolesListTitle": "", - "rolesNotManageable": "", - "rolesNotPublic": "", - "rolesRemoved": "", - "setIgnoreChannelsDescription": "", - "setIgnoreChannelsExtended": { - "usages": [ - "here/CanalDeTexto" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "canal", - "" - ] - ], - "reminder": "", - "examples": [ - "#general", - "" - ] - }, - "setImageLogsDescription": "", - "setImageLogsExtended": { - "usages": [ - "here/CanalDeTexto" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "#registro-de-imagenes", - "here" - ] - }, - "setMemberAddLogsDescription": "", - "setMemberAddLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMemberRemoveLogsDescription": "", - "setMemberRemoveLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMessageUpdateLogsDescription": "", - "setMessageUpdateLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setMessageDeleteLogsDescription": "", - "setMessageDeleteLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setmodlogsDescription": "", - "setmodlogsExtended": { - "usages": [ - "here/CanalDeTexto" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setprefixDescription": "", - "setprefixExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "guildInfoDescription": "Revise la información del servidor.", - "guildInfoExtended": { - "extendedHelp": "El comando serverinfo muestra información para el servidor en el que el mensaje ha sido enviado.\nMuestra la cantidad de canales, con el recuento para cada categoría, la cantidad de miembros (dada desde la API), el propietario con su id de usuario, la cantidad de roles, región, fecha de creación, nivel de verificación. entre otros." - }, - "roleInfoDescription": "Revise la información de un rol.", - "roleInfoExtended": { - "usages": [ - "Rol", - "" - ], - "extendedHelp": "El comando roleinfo muestra información para un rol, como su id, nombre, color, si está elevado (se muestre por separado), su posición de jerarquía de rol, si mencionable, cuántos miembros tienen dicho el rol y sus permisos.\nEnvía un mensaje incrustado con el color del rol.", - "explainedUsage": [ - [ - "Rol", - "Nombre del rol, mención o id." - ] - ], - "examples": [ - "Administrador", - "Moderador", - "" - ] - }, - "stickyRolesDescription": "", - "stickyRolesExtended": { - "usages": [ - "add Usuario Rol", - "remove Usuario Rol", - "reset Usuario", - "show Usuario", - "Usuario" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "Acción", - "" - ], - [ - "Usuario", - "El usuario objetivo para todas las acciones." - ], - [ - "Rol", - "El rol a añadir o eliminar." - ] - ], - "examples": [ - "add WolfStar Diosa", - "show WolfStar", - "remove WolfStar Diosa", - "reset WolfStar" - ], - "reminder": "" - }, - "rolesDescription": "", - "rolesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/es-419/commands/misc.json b/src/languages/es-419/commands/misc.json deleted file mode 100644 index 32f64d584..000000000 --- a/src/languages/es-419/commands/misc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "snipeEmpty": "", - "snipeTitle": "", - "snipeDescription": "", - "snipeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/es-419/commands/moderation.json b/src/languages/es-419/commands/moderation.json deleted file mode 100644 index 815d1c788..000000000 --- a/src/languages/es-419/commands/moderation.json +++ /dev/null @@ -1,889 +0,0 @@ -{ - "permissions": "", - "permissionsAll": "", - "slowmodeSet": "", - "slowmodeReset": "", - "banNotBannable": "", - "dehoistStarting": "", - "dehoistProgress": "", - "dehoistEmbed": { - "title": "", - "descriptionNoone": "", - "descriptionWithError": "", - "descriptionWithMultipleErrors": "", - "description": "", - "descriptionMultipleMembers": "", - "fieldErrorTitle": "" - }, - "kickNotKickable": "", - "lockdownLock": "", - "lockdownLocking": "", - "lockdownLocked": "", - "lockdownUnlocked": "", - "lockdownOpen": "", - "muteMuted": "", - "muteUserNotMuted": "", - "restrictLowlevel": "", - "pruneAlert_one": "", - "pruneAlert_other": "", - "pruneInvalidPosition": "", - "pruneNoDeletes": "", - "pruneLogHeader": "", - "toggleModerationDmToggledEnabled": "", - "toggleModerationDmToggledDisabled": "", - "moderationOutput_one": "", - "moderationOutput_other": "", - "moderationOutputWithReason_one": "", - "moderationOutputWithReason_other": "", - "moderationFailed_one": "", - "moderationFailed_other": "", - "moderationDmFooter": "", - "moderationDmDescription": "", - "moderationDmDescriptionWithReason": "", - "moderationDmDescriptionWithDuration": "", - "moderationDmDescriptionWithReasonWithDuration": "", - "slowmodeDescription": "", - "slowmodeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "banDescription": "", - "banExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "dehoistDescription": "", - "dehoistExtended": { - "extendedHelp": "", - "reminder": "" - }, - "kickDescription": "", - "kickExtended": { - "usages": [ - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "lockdownDescription": "", - "lockdownExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "muteDescription": "", - "muteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "setNicknameDescription": "", - "setNicknameExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ], - "reminder": "" - }, - "addRoleDescription": "", - "addRoleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "removeroleDescription": "", - "removeroleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "pruneDescription": "", - "pruneExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "permissionsDescription": "", - "permissionsExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ], - "extendedHelp": "" - }, - "restrictAttachmentDescription": "", - "restrictAttachmentExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictEmbedDescription": "", - "restrictEmbedExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictEmojiDescription": "", - "restrictEmojiExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictReactionDescription": "", - "restrictReactionExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictVoiceDescription": "", - "restrictVoiceExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "softBanDescription": "", - "softBanExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "timeoutApplyDescription": "", - "timeoutApplyExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutUndoDescription": "", - "timeoutUndoExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutNotModeratable": "", - "toggleModerationDmDescription": "", - "toggleModerationDmExtended": { - "extendedHelp": "" - }, - "unbanDescription": "", - "unbanExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unmuteDescription": "", - "unmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unrestrictAttachmentDescription": "", - "unrestrictAttachmentExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmbedDescription": "", - "unrestrictEmbedExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmojiDescription": "", - "unrestrictEmojiExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictReactionDescription": "", - "unrestrictReactionExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictVoiceDescription": "", - "unrestrictVoiceExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unwarnDescription": "", - "unwarnExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vmuteDescription": "", - "vmuteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "voiceKickDescription": "", - "voiceKickExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vunmuteDescription": "", - "vunmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "warnDescription": "", - "warnExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/es-419/commands/shared.json b/src/languages/es-419/commands/shared.json deleted file mode 100644 index ddbb28e7f..000000000 --- a/src/languages/es-419/commands/shared.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "deprecatedMessage": "", - "slashOnlyDetailedDescription": { - "extendedHelp": "" - }, - "slashOnlyErrorMessage": "" -} \ No newline at end of file diff --git a/src/languages/es-419/commands/system.json b/src/languages/es-419/commands/system.json deleted file mode 100644 index e9cfdeec4..000000000 --- a/src/languages/es-419/commands/system.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "evalDescription": "", - "evalExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "evalTimeout": "", - "evalError": "", - "dmNotSent": "", - "dmSent": "", - "reboot": "", - "rebootDescription": "", - "rebootExtended": { - "extendedHelp": "", - "reminder": "" - } -} \ No newline at end of file diff --git a/src/languages/es-419/commands/tools.json b/src/languages/es-419/commands/tools.json deleted file mode 100644 index 01bd03e25..000000000 --- a/src/languages/es-419/commands/tools.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "avatarDescription": "", - "avatarExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "" - }, - "avatarNone": "", - "voteDescription": "", - "voteExtended": { - "usages": [ - "" - ], - "examples": [ - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "voteContentNeeded": "", - "voteReactionBlocked": "", - "whoisExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "whoisMemberRoleListAndMore": "" -} \ No newline at end of file diff --git a/src/languages/es-419/commands/twitch.json b/src/languages/es-419/commands/twitch.json deleted file mode 100644 index 2f12e1b08..000000000 --- a/src/languages/es-419/commands/twitch.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "twitchSubscriptionStreamerNotFound": "", - "twitchSubscriptionStatusValues": [ - "", - "" - ], - "twitchSubscriptionInvalidStatus": "", - "twitchSubscriptionAddDuplicated": "", - "twitchSubscriptionAddSuccessOffline": "", - "twitchSubscriptionAddSuccessLive": "", - "twitchSubscriptionAddMessageForOfflineRequired": "", - "twitchSubscriptionRemoveOrResetEmpty": "", - "twitchSubscriptionRemoveStreamerNotSubscribed": "", - "twitchSubscriptionRemoveNotToProvidedChannel": "", - "twitchSubscriptionRemoveStreamerStatusNotMatch": "", - "twitchSubscriptionRemoveSuccessOffline": "", - "twitchSubscriptionRemoveSuccessLive": "", - "twitchSubscriptionResetSuccess_one": "", - "twitchSubscriptionResetSuccess_other": "", - "twitchSubscriptionShowStreamerNotSubscribed": "", - "twitchSubscriptionShowStatus": { - "live": "", - "offline": "" - }, - "twitchSubscriptionShowUnknownUser": "", - "twitchSubscriptionDescription": "", - "twitchSubscriptionExtended": { - "usages": [ - "", - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/es-419/commands/whois.json b/src/languages/es-419/commands/whois.json deleted file mode 100644 index 2c9421e3d..000000000 --- a/src/languages/es-419/commands/whois.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "whois", - "description": "Proporciona información sobre un usuario de Discord", - "contextMenuName": "Obtener Información", - "userName": "usuario", - "userDescription": "El usuario sobre el que obtener información", - "rolesTitle_one": "Rol [1]", - "rolesTitle_other": "Roles [{{count, number}}]", - "permissionsTitle": "Permisos Clave", - "permissionsAll": "Todos los permisos", - "embedDescription": "**Usuario Desde**: {{createdAt}}", - "embedMemberDescription": "**Miembro Desde**: {{joinedAt}}", - "buttonAvatar": "Avatar", - "buttonProfile": "Perfil" -} \ No newline at end of file diff --git a/src/languages/es-419/constants.ts b/src/languages/es-419/constants.ts deleted file mode 100644 index 90b003dd3..000000000 --- a/src/languages/es-419/constants.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Handler } from '#lib/i18n/structures/Handler'; -import { TimeTypes } from '@sapphire/time-utilities'; - -export class ExtendedHandler extends Handler { - public constructor() { - super({ - name: 'es-419', - duration: { - [TimeTypes.Year]: { - 1: 'año', - DEFAULT: 'años' - }, - [TimeTypes.Month]: { - 1: 'mes', - DEFAULT: 'meses' - }, - [TimeTypes.Week]: { - 1: 'semana', - DEFAULT: 'semanas' - }, - [TimeTypes.Day]: { - 1: 'día', - DEFAULT: 'días' - }, - [TimeTypes.Hour]: { - 1: 'hora', - DEFAULT: 'horas' - }, - [TimeTypes.Minute]: { - 1: 'minuto', - DEFAULT: 'minutos' - }, - [TimeTypes.Second]: { - 1: 'segundo', - DEFAULT: 'segundos' - } - } - }); - } -} diff --git a/src/languages/es-419/errors.json b/src/languages/es-419/errors.json deleted file mode 100644 index 3f49a437b..000000000 --- a/src/languages/es-419/errors.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "guildBansEmpty": "No hay baneos registrados en este servidor.", - "guildBansNotFound": "Lo he intentado y no he podido encontrar a este usuario de la lista de baneos. ¿Estás seguro de que este usuario está baneado?", - "guildMemberNotVoicechannel": "No puedo ejecutar esta acción en un miembro que no está conectado a un canal de voz.", - "guildWarnNotFound": "No pude obtener esa advertencia. O bien no existe, o bien no era un aviso, o bien ha sido apelada.", - "modlogTimed": "Este registro de moderación ya está temporizado. Expira en {{remaining, duration}}", - "unexpectedIssue": "¡Se ha producido un error inesperado! Abortando este comando de forma segura...", - "userNotInGuild": "Este usuario no está en este servidor." -} \ No newline at end of file diff --git a/src/languages/es-419/events/errors.json b/src/languages/es-419/events/errors.json deleted file mode 100644 index 344ef3398..000000000 --- a/src/languages/es-419/events/errors.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "string": "{{REDCROSS}} Querido/a {{mention}}, {{message}}", - "unexpectedError": "{{REDCROSS}} He encontrado un error inesperado, ¡por favor informa de los pasos que has dado a mis desarrolladores!", - "unexpectedErrorWithContext": "$t(events/errors:unexpectedError)\nPuede agregar `{{report}}` al informe para que puedan ver qué error fue desencadenado." -} \ No newline at end of file diff --git a/src/languages/es-419/events/guilds-logs.json b/src/languages/es-419/events/guilds-logs.json deleted file mode 100644 index 7e3897c06..000000000 --- a/src/languages/es-419/events/guilds-logs.json +++ /dev/null @@ -1,109 +0,0 @@ -{ - "channelCreate": "Canal Creado", - "channelCreateParent": "• **Categoría**: {{value}}", - "channelCreatePosition": "• **Posición**: `{{value, number}}`", - "channelCreatePermissionsTitle": "• **Permisos para {{value}}**", - "channelCreateNsfw": "• **Establecido como NSFW**", - "channelCreateTopic": "• **Tema**: `{{value}}`", - "channelCreateRateLimit": "• **Modo Pausado**: `{{value, duration}}`", - "channelCreateBitrate": "• **Tasa de Bits**: `{{value}}kbps`", - "channelCreateUserLimit": "• **Límite de Usuarios**: `{{value, number}}`", - "channelDelete": "Canal Eliminado", - "channelUpdate": "Canal Actualizado", - "channelUpdateBitrate": "• **Tasa de Bits**: `{{previous}}kbps` → `{{next}}kbps`", - "channelUpdateName": "• **Nombre**: `{{previous}}` → `{{next}}`", - "channelUpdateNsfw": "• **NSFW**: `{{previous}}` → `{{next}}`", - "channelUpdateParent": "• **Categoría**: {{previous}} → {{next}}", - "channelUpdateParentAdded": "• **Categoría**: No Establecido → {{value}}", - "channelUpdateParentRemoved": "• **Categoría**: {{value}} → No Establecido", - "channelUpdatePosition": "• **Posición**: `{{previous, number}}` → `{{next, number}}`", - "channelUpdateAddedPermissionsTitle": "• **Añadidos los Permisos para {{value}}**", - "channelUpdateDeletedPermissionsTitle": "• **Eliminados los Permisos para {{value}}**", - "channelUpdatePermissionsTitle": "• **Actualizados los Permisos para {{value}}**", - "channelUpdateRateLimit": "• **Modo Pausado**: `{{previous, duration}}` → `{{next, duration}}`", - "channelUpdateRateLimitAdded": "• **Modo Pausado**: No Establecido → `{{value, duration}}`", - "channelUpdateRateLimitRemoved": "• **Modo Pausado**: `{{value, duration}}` → No Establecido", - "channelUpdateTopic": "• **Tema**: `{{previous}}` → `{{next}}`", - "channelUpdateTopicAdded": "• **Tema**: No Establecido → `{{value}}`", - "channelUpdateTopicRemoved": "• **Tema**: `{{value}}` → No Establecido", - "channelUpdateType": "• **Tipo**: `{{previous}}` → `{{next}}`", - "channelUpdateUserLimit": "• **Límite de Usuarios**: `{{previous, number}}` → `{{next, number}}`", - "channelUpdateUserLimitAdded": "• **Límite de Usuarios**: No Establecido → `{{value, number}}`", - "channelUpdateUserLimitRemoved": "• **Límite de Usuarios**: `{{value, number}}` → No Establecido", - "emojiCreate": "Emoji Creado", - "emojiCreateAnimated": "• **Animado**", - "emojiCreateUnAvailable": "• **No Disponible**", - "emojiCreateManaged": "• **Gestionado**", - "emojiCreateRequiresColons": "• **Requiere Dos Puntos**", - "emojiDelete": "Emoji Eliminado", - "emojiUpdate": "Emoji Actualizado", - "emojiUpdateAnimated": "• **Animado**: `{{previous}}` → `{{next}}`", - "emojiUpdateAvailable": "• **Disponible**: `{{previous}}` → `{{next}}`", - "emojiUpdateManaged": "• **Gestionado**: `{{previous}}` → `{{next}}`", - "emojiUpdateName": "• **Nombre**: `{{previous}}` → `{{next}}`", - "emojiUpdateRequiresColons": "• **Requiere Dos Puntos**: `{{previous}}` → `{{next}}`", - "roleCreate": "Rol Creado", - "roleCreateColor": "• **Color**: `{{value}}`", - "roleCreateHoist": "• **Mostrado por Separado**", - "roleCreateMentionable": "• **Mencionable**", - "roleCreatePosition": "• **Posición**: `{{value, number}}`", - "roleDelete": "Rol Eliminado", - "roleUpdate": "Rol Actualizado", - "roleUpdateColor": "• **Color**: `{{previous}}` → `{{next}}`", - "roleUpdateHoist": "• **Mostrado por Separado**: `{{previous}}` → `{{next}}`", - "roleUpdateMentionable": "• **Mencionable**: `{{previous}}` → `{{next}}`", - "roleUpdateName": "• **Nombre**: `{{previous}}` → `{{next}}`", - "roleUpdatePosition": "• **Posición**: `{{previous, number}}` → `{{next, number}}`", - "serverUpdate": "Servidor Actualizado", - "serverUpdateAfkChannelAdded": "**Canal de Inactividad**: No Establecido → {{value}}", - "serverUpdateAfkChannelRemoved": "• **Canal de Inactividad**: {{value}} → No Establecido", - "serverUpdateAfkChannel": "• **Canal de Inactividad**: {{previous}} → {{next}}", - "serverUpdateAfkTimeout": "• **Límite de Tiempo de Inactividad**: `{{previous, duration}}` → `{{next, duration}}`", - "serverUpdateBannerAdded": "• **Banner**: No establecido → [Ahora]({{value}})", - "serverUpdateBannerRemoved": "• **Banner**: [Antes]({{value}}) → No Establecido", - "serverUpdateBanner": "• **Banner**: [Antes]({{previous}}) → [Ahora]({{next}})", - "serverUpdateDefaultMessageNotifications": "• **Notificaciones de Mensajes**: `{{previous, messageNotifications}}` → `{{next, messageNotifications}}`", - "serverUpdateDescriptionAdded": "• **Descripción**: No Establecido → `{{value}}`", - "serverUpdateDescriptionRemoved": "• **Descripción**: `{{value}}` → No Establecido", - "serverUpdateDescription": "• **Descripción**: `{{previous}}` → `{{next}}`", - "serverUpdateDiscoverySplashAdded": "• **Fondo de Invitación**: No Establecido → [Ahora]({{value}})", - "serverUpdateDiscoverySplashRemoved": "• **Fondo de Invitación**: [Antes]({{value}}) → No Establecido", - "serverUpdateDiscoverySplash": "• **Fondo de Invitación**: [Antes]({{previous}}) → [Ahora]({{next}})", - "serverUpdateExplicitContentFilter": "• **Filtro de Contenido Explícito**: `{{previous, explicitContentFilter}}` → `{{next, explicitContentFilter}}`", - "serverUpdateIconAdded": "• **Icono**: No Establecido → [Nuevo]({{value}})", - "serverUpdateIconRemoved": "• **Icono**: [Antes]({{value}}) → No Establecido", - "serverUpdateIcon": "• **Icono**: [Antes]({{previous}}) → [Ahora]({{next}})", - "serverUpdateMaximumMembersAdded": "• **Límite de Usuarios**: No Establecido → `{{value, number}}`", - "serverUpdateMaximumMembersRemoved": "• **Límite de Usuarios**: `{{value, number}}` → No Establecido", - "serverUpdateMaximumMembers": "• **Límite de Usuarios**: `{{previous, number}}` → `{{next, number}}`", - "serverUpdateMfaAdded": "• **Autenticación de Múltiples Factores Añadida**", - "serverUpdateMfaRemoved": "• **Autenticación de Múltiples Factores Eliminada**", - "serverUpdateName": "• **Nombre**: `{{previous}}` → `{{next}}`", - "serverUpdateOwner": "• **Dueño**: {{previous}} → {{next}}", - "serverUpdatePreferredLocale": "• **Idioma Preferido**: `{{previous}}` → `{{next}}`", - "serverUpdatePremiumSubscriptionCountAdded": "• **Mejoras**: No Establecido → `{{value, number}}`", - "serverUpdatePremiumSubscriptionCountRemoved": "• **Mejoras**: `{{value, number}}` → No Establecido", - "serverUpdatePremiumSubscriptionCount": "• **Mejoras**: `{{previous, number}}` → `{{next, number}}`", - "serverUpdatePremiumTier": "• **Nivel de Mejoras**: `{{previous, number}}` → `{{next, number}}`", - "serverUpdatePublicUpdatesChannelAdded": "**Canal de Actualizaciones Públicas**: No Establecido → {{value}}", - "serverUpdatePublicUpdatesChannelRemoved": "• **Canal de Actualizaciones Públicas**: {{value}} → No Establecido", - "serverUpdatePublicUpdatesChannel": "**Canal de Actualizaciones Públicas**: {{previous}} → {{next}}", - "serverUpdateRulesChannelAdded": "• **Canal de Reglas**: No Establecido → {{value}}", - "serverUpdateRulesChannelRemoved": "• **Canal de Reglas**: {{value}} → No Establecido", - "serverUpdateRulesChannel": "• **Canal de Reglas**: {{previous}} → {{next}}", - "serverUpdateSplashAdded": "• **Fondo de Invitación**: No Establecido → [Nuevo]({{value}})", - "serverUpdateSplashRemoved": "• **Fondo de Invitación**: [Antes]({{value}}) → No Establecido", - "serverUpdateSplash": "• **Fondo de Invitación**: [Antes]({{previous}}) → [Ahora]({{next}})", - "serverUpdateSystemChannelAdded": "• **Canal del Sistema**: No Establecido → {{value}}", - "serverUpdateSystemChannelRemoved": "• **Canal del Sistema**: {{value}} → No Establecido", - "serverUpdateSystemChannel": "• **Canal del Sistema**: {{previous}} → {{next}}", - "serverUpdateVanityUrlAdded": "• **Invitación Personalizada**: No Establecido → {{value}}", - "serverUpdateVanityUrlRemoved": "• **Invitación Personalizada**: `{{value}}` → No Establecido", - "serverUpdateVanityUrl": "• **Invitación Personalizada**: `{{previous}}` → {{next}}", - "serverUpdateVerificationLevel": "• **Nivel de Verificación**: `{{previous}}` → `{{next}}`", - "serverUpdateWidgetChannelAdded": "• **Canal del Widget**: No Establecido → {{value}}", - "serverUpdateWidgetChannelRemoved": "• **Canal del Widget**: {{value}} → No Establecido", - "serverUpdateWidgetChannel": "• **Canal del Widget**: {{previous}} → {{next}}", - "serverUpdateWidgetEnabled": "• **Widget Habilitado**", - "serverUpdateWidgetDisabled": "• **Widget Deshabilitado**" -} \ No newline at end of file diff --git a/src/languages/es-419/events/guilds-members.json b/src/languages/es-419/events/guilds-members.json deleted file mode 100644 index fdbc73145..000000000 --- a/src/languages/es-419/events/guilds-members.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "guildMemberAdd": "Nuevo Usuario", - "guildMemberAddedRoles_one": "**Rol añadido**: {{addedRoles}}", - "guildMemberAddMute": "Un usuario silenciado se ha unido", - "guildMemberBanned": "Usuario Baneado", - "guildMemberKicked": "Usuario Expulsado", - "guildMemberNoUpdate": "No se han detectado actualizaciones", - "guildMemberRemove": "Un usuario nos ha abandonado", - "guildMemberRemovedRoles_one": "**Rol eliminado**: {{removedRoles}}", - "guildMemberSoftBanned": "Usuario Softbaneado", - "nameUpdateNextWasNotSet": "**Siguiente**: No Establecido", - "nameUpdateNextWasSet": "**Siguiente**: `{{nextName}}`", - "nameUpdatePreviousWasNotSet": "**Anterior**: No Establecido", - "nameUpdatePreviousWasSet": "**Anterior**: `{{previousName}}`", - "nicknameUpdate": "Apodo Editado", - "roleUpdate": "Roles Editados", - "usernameUpdate": "Nombre de Usuario Editado" -} \ No newline at end of file diff --git a/src/languages/es-419/events/messages.json b/src/languages/es-419/events/messages.json deleted file mode 100644 index a0ba55e87..000000000 --- a/src/languages/es-419/events/messages.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "messageDelete": "Mensaje eliminado • {{channel}}", - "messageUpdate": "Mensaje Editado • {{channel}}" -} \ No newline at end of file diff --git a/src/languages/es-419/events/moderation.json b/src/languages/es-419/events/moderation.json deleted file mode 100644 index f44bd29e7..000000000 --- a/src/languages/es-419/events/moderation.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "attachmentFilter": "{{REDCROSS}} Estimado {{user}}, los archivos adjuntos no están permitidos aquí.", - "attachmentFilterFooter": "Demasiados archivos adjuntos", - "attachments": "[Moderación Automática] Se ha activado el filtro de archivos adjuntos, sin umbral.", - "attachmentsWithMaximum": "[Moderación Automática] Se ha activado el filtro de archivos adjuntos, se ha alcanzado {{amount}} de {{maximum}} infracciones.", - "capitals": "[Moderación Automática] Se ha activado el filtro de mayúsculas, sin umbral.", - "capitalsWithMaximum": "[Moderación Automática] Se ha activado el filtro de mayúsculas, se ha alcanzado {{amount}} de {{maximum}} infracciones.", - "capsFilter": "¡{{REDCROSS}} EEEOOOO {{user}}! ¡POR FAVOR NO GRITES EN ESTE LUGAR! ¡HAS ALCANZADO EL LÍMITE DE MAYÚSCULAS!", - "capsFilterDm": "¡Habla más bajo! Sé que necesitas expresar tus pensamientos. Hay un mensaje que borrado:{{message}}", - "capsFilterFooter": "Demasiadas Mayúsculas", - "inviteFilterAlert": "{{REDCROSS}} Estimado {{user}}, los enlaces de invitación no están permitidos aquí.", - "inviteLink": "Enlace de Invitación", - "invites": "[Moderación Automática] Se ha activado el filtro de invitaciones, sin umbral.", - "invitesWithMaximum": "[Moderación Automática] Se ha activado el filtro de invitaciones, se ha alcanzado {{amount}} de {{maximum}} infracciones.", - "link": "Enlace Filtrado", - "links": "[Moderación Automática] Se ha activado el filtro de enlaces, sin umbral.", - "linksWithMaximum": "[Moderación Automática] Se ha activado el filtro de enlaces, se ha alcanzado {{amount}} de {{maximum}} infracciones.", - "messageFilter": "{{REDCROSS}} ¡Oye oye, ¡por favor deja de republicar tanto {{user}}!", - "messageFilterFooter": "Demasiados Mensajes Duplicados", - "messages": "[Moderación Automática] Se ha activado el filtro de mensajes duplicados, sin umbral.", - "messagesWithMaximum": "[Moderación Automática] Se ha activado el filtro de mensajes duplicados, se ha alcanzado {{amount}} de {{maximum}} infracciones.", - "newlineFilter": "{{REDCROSS}} Muro de texto entrante de {{user}}, ¡muro de texto despejado!", - "newlineFilterFooter": "Demasiadas Líneas", - "newlines": "[Moderación Automática] Se ha activado el filtro de líneas, sin umbral.", - "newlinesWithMaximum": "[Moderación Automática] Se ha activado el filtro de líneas, se ha alcanzado {{amount}} de {{maximum}} infracciones.", - "nolink": "{{REDCROSS}} ¡Oye {{user}}, ¡no puedes publicar enlaces aquí!", - "wordFilter": "{{REDCROSS}} Perdona, querido/a {{user}}, has dicho algo que no está permitido en este servidor.", - "wordFilterDm": "¡Shush! ¡Has dicho algunas palabras que no están permitidas en el servidor! Pero puesto que te tomó un momento para escribir el mensaje, lo publicaré aquí:\n{{filtered}}", - "wordFilterFooter": "Palabra Filtrada", - "words": "[Moderación Automática] Se ha activado el filtro de palabras, sin umbral.", - "wordsWithMaximum": "[Moderación Automática] Se ha activado el filtro de palabras, se ha alcanzado {{amount}} de {{maximum}} infracciones." -} \ No newline at end of file diff --git a/src/languages/es-419/events/noMentionSpam.json b/src/languages/es-419/events/noMentionSpam.json deleted file mode 100644 index b0c6ca36a..000000000 --- a/src/languages/es-419/events/noMentionSpam.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "footer": "[NOMENTIONSPAM]", - "alert": "Tenga cuidado de mencionar más, ya que estás a punto de ser baneado por sobrepasar el límite de menciones establecido en este servidor.", - "message": "El martillo de baneo ha aterrizado y ahora el usuario {{userTag}} con id {{userId}} ha sido baneado por el spam de menciones.\n¡No te preocupes! ¡Estoy aquí para ayudarte! 😄", - "modlog": "[NOMENTIONSPAM] Automático: Se ha superado el límite de Spam de Menciones.\nLímite: {{threshold}}." -} \ No newline at end of file diff --git a/src/languages/es-419/events/reactions.json b/src/languages/es-419/events/reactions.json deleted file mode 100644 index 4c916d56b..000000000 --- a/src/languages/es-419/events/reactions.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "filterFooter": "Reacción Filtrada", - "filter": "{{REDCROSS}} Hey {{user}}, ¡por favor no añadas esa reacción!", - "selfRoleHierarchy": "{{REDCROSS}} Mi rol tiene que ser mayor que todos los roles auto-asignables, ¡de lo contrario no puedo concederlos a la gente!" -} \ No newline at end of file diff --git a/src/languages/es-419/fuzzySearch.json b/src/languages/es-419/fuzzySearch.json deleted file mode 100644 index eb3ab8d96..000000000 --- a/src/languages/es-419/fuzzySearch.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "aborted": "Se ha abortado la petición con éxito.", - "invalidIndex": "Ese número estaba fuera de rango, abortando la petición.", - "invalidNumber": "Esperaba que me dieras un número (un dígito) y me diste una patata.", - "matches": "¡He encontrado varias coincidencias! **Por favor, selecciona un número dentro de 0 y {{matches}}**:\n{{codeblock}}\nEscribe **ABORT** si quieres salir de la petición." -} \ No newline at end of file diff --git a/src/languages/es-419/globals.json b/src/languages/es-419/globals.json deleted file mode 100644 index b4e7c13a1..000000000 --- a/src/languages/es-419/globals.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "default": "La clave {{key}} aún no ha sido traducido para es-ES.", - "defaultLanguage": "Idioma predeterminado", - "no": "No", - "none": "Ninguno", - "unknown": "desconocido", - "yes": "Sí", - "paginatedMessagePage": "Página", - "paginatedMessageWrongUserInteractionReply": "Por favor, deje de hacer clic en los botones de este mensaje. Sólo son para {{user}}.", - "durationValue": "{{value, duration}}", - "numberValue": "{{value, number}}", - "numberCompactValue": "{{value, numberCompact}}", - "dateTimeValue": "{{value, dateTime}}", - "orListValue": "{{value, orList}}", - "dateFormat": "DD/MM/YYYY", - "dateFormatExplanation": "Día/Mes/Año" -} \ No newline at end of file diff --git a/src/languages/es-419/guilds.json b/src/languages/es-419/guilds.json deleted file mode 100644 index 9adb5eab3..000000000 --- a/src/languages/es-419/guilds.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "explicitContentFilterDisabled": "Desabilitado", - "explicitContentFilterMembersWithoutRoles": "Miembros sin rol", - "explicitContentFilterAllMembers": "Todos los miembros", - "defaultMessageNotificationsAllMessages": "Todos los Mensajes", - "defaultMessageNotificationsOnlyMentions": "Solo @menciones", - "SuppressJoinNotifications": "Notificaciones de entrada de miembros", - "SuppressJoinNotificationReplies": "Botones de respuesta de sticker de entrada de miembros", - "SuppressPremiumSubscriptions": "Notificaciones de mejora del servidor", - "SuppressGuildReminderNotifications": "Consejos de configuración del servidor", - "SuppressRoleSubscriptionPurchaseNotifications": "Suprimir notificaciones de compra de suscripción de rol", - "SuppressRoleSubscriptionPurchaseNotificationReplies": "Suprimir las respuestas para las notificaciones de compra de suscripción a roles" -} \ No newline at end of file diff --git a/src/languages/es-419/humanLevels.json b/src/languages/es-419/humanLevels.json deleted file mode 100644 index 08c235d6a..000000000 --- a/src/languages/es-419/humanLevels.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "None": "Ninguno", - "Low": "Bajo", - "Medium": "Medio", - "High": "Alta", - "VeryHigh": "Más alto" -} \ No newline at end of file diff --git a/src/languages/es-419/moderation.json b/src/languages/es-419/moderation.json deleted file mode 100644 index 7028a2166..000000000 --- a/src/languages/es-419/moderation.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "caseNotExists_one": "{{REDCROSS}} Lo siento, pero el caso de registro de moderación seleccionado no existe.", - "caseNotExists_other": "{{REDCROSS}} Lo siento, pero ninguno de los registros de moderación seleccionados existe.", - "restrictionNotConfigured": "El rol de restricción debe ser configurado para que esta acción se pueda llevar a cabo", - "success": "Ejecutado el comando con éxito." -} \ No newline at end of file diff --git a/src/languages/es-419/moderationActions.json b/src/languages/es-419/moderationActions.json deleted file mode 100644 index 6a3a9a09f..000000000 --- a/src/languages/es-419/moderationActions.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "actions": { - "addRole": "", - "ban": "Banear", - "kick": "Expulsar", - "mute": "Silenciar", - "removeRole": "", - "restrictedAttachment": "Restricción del archivo adjunto", - "restrictedEmbed": "Restricción de Inserción de Enlaces", - "restrictedEmoji": "", - "restrictedReact": "Restricción de Reacciones", - "restrictedVoice": "Restricción de voz", - "setNickname": "Establecer apodo", - "softban": "Baneo Suave", - "vkick": "Expulsión de voz", - "vmute": "Silenciar voz", - "warning": "" - }, - "actionCannotManageRoles": "", - "actionRoleNotConfigured": "", - "actionRoleHigherPosition": "", - "actionRoleManaged": "", - "applyNoReason": "[Acción] Aplicado {{action}}", - "applyReason": "[Acción] Aplicado {{action}} | Motivo: {{reason}}", - "requiredMember": "El usuario no existe o no está en este servidor.", - "revokeNoReason": "[Acción] Revocado {{action}}", - "revokeReason": "[Acción] Revocado {{action}} | Motivo: {{reason}}", - "setNicknameNoReasonRemoved": "[Acción] Apodo Eliminado.", - "setNicknameNoReasonSet": "[Acción] Cambio de Apodo.", - "setNicknameRemoved": "[Acción] Apodo Eliminado | Motivo: {{reason}}", - "setNicknameSet": "[Acción] Cambio de Apodo | Motivo: {{reason}}", - "setupMuteExists": "**Abortar la creación de rol de silenciado**: Ya hay un rol llamado \"Muted\".", - "setupTooManyRoles": "**Abortando la creación del rol**: Ya hay 250 roles en este servidor, debe borrar uno.", - "sharedRoleSetupAsk": "{{LOADING}} ¿Puedo modificar el canal {{channels}} para aplicar al rol {{role}} el siguiente permiso: {{permissions}}?", - "sharedRoleSetupNoMessage": "No ha mandado un mensaje a tiempo, ¡cancelando la configuración!", - "sharedRoleSetupExisting": "No he podido encontrar un rol configurado. ¿Quieres configurar uno existente?", - "sharedRoleSetupExistingName": "Por favor, dame el nombre del rol que quieres utilizar para otras acciones de este tipo.", - "sharedRoleSetupNew": "¿Quieres que cree un nuevo rol y que lo configure automáticamente?", - "softbanNoReason": "[Acción] Aplicando Softban.", - "softbanReason": "[Acción] Aplicando Softban | Motivo: {{reason}}", - "unSoftbanNoReason": "[Acción] Aplicado Softban.", - "unSoftbanReason": "[Acción] Aplicado Softban | Motivo: {{reason}}" -} \ No newline at end of file diff --git a/src/languages/es-419/permissions.json b/src/languages/es-419/permissions.json deleted file mode 100644 index 999c26993..000000000 --- a/src/languages/es-419/permissions.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "AddReactions": "Añadir Reacciones", - "Administrator": "Administrador", - "AttachFiles": "Adjuntar Archivos", - "BanMembers": "Bloquear Miembros", - "ChangeNickname": "Cambiar Apodo", - "Connect": "Conectar", - "CreateExpressions": "Crear Expresiones", - "CreateInstantInvite": "Crear Invitación Instantánea", - "CreatePrivateThreads": "Crear hilos privados", - "CreatePublicThreads": "Crear hilos públicos", - "DeafenMembers": "Ensordecer Miembros", - "EmbedLinks": "Insertar Enlaces", - "KickMembers": "Expulsar a Miembros", - "ManageChannels": "Gestionar Canales", - "ManageEvents": "Gestionar Eventos", - "ManageGuild": "Gestionar Servidor", - "ManageGuildExpressions": "Gestionar Expresiones", - "ManageMessages": "Gestionar Mensajes", - "ManageNicknames": "Gestionar Apodos", - "ManageRoles": "Gestionar Roles", - "ManageThreads": "Gestionar hilos", - "ManageWebhooks": "Gestionar Webhooks", - "MentionEveryone": "Mencionar a Todos", - "ModerateMembers": "Aislar temporalmente a miembros", - "MoveMembers": "Mover Miembros", - "MuteMembers": "Silenciar Miembros", - "PrioritySpeaker": "Prioridad de Palabra", - "ReadMessageHistory": "Leer el Historial de Mensajes", - "RequestToSpeak": "Solicitud para Hablar", - "SendMessages": "Enviar Mensajes", - "SendMessagesInThreads": "Enviar mensajes en hilos", - "SendTTSMessages": "Enviar Mensajes Texto A Voz", - "SendVoiceMessages": "Enviar mensajes de voz", - "Speak": "Hablar", - "Stream": "Vídeo", - "UseApplicationCommands": "Usar Comandos de Aplicación", - "UseEmbeddedActivities": "Usar Actividades", - "UseExternalEmojis": "Usar Emojis Externos", - "UseExternalSounds": "Usar Sonidos Externos", - "UseExternalStickers": "Usar Stickers Externos", - "UseSoundboard": "Usar panel de sonidos", - "UseVAD": "Usar Actividad de Voz", - "ViewAuditLog": "Ver Registro de Auditoría", - "ViewChannel": "Ver Canales", - "ViewCreatorMonetizationAnalytics": "Ver Análisis de Monetización del Creador", - "ViewGuildInsights": "Ver Información del Servidor" -} \ No newline at end of file diff --git a/src/languages/es-419/preconditions.json b/src/languages/es-419/preconditions.json deleted file mode 100644 index ea39dc97d..000000000 --- a/src/languages/es-419/preconditions.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "clientPermissionsNoClient": "Esto nunca debería ocurrir, no sé quién soy.", - "clientPermissionsNoPermissions": "Esto nunca debería ocurrir, no pude determinar los permisos que tengo.", - "runIn": "Este comando no se puede ejecutar en este tipo de canal.", - "userPermissionsNoPermissions": "Esto nunca debería ocurrir, no pude determinar los permisos que usted tiene.", - "unavailable": "Esto nunca debería ocurrir, no pude encontrar una de las condiciones necesarias para este comando.", - "cooldown": "Acabas de usar este comando. Puedes usarlo de nuevo en {{remaining, duration}}.", - "nsfw": "¡No puedes usar comandos con contenido no apropiado en este canal!", - "missingMessageHandler": "Esto nunca debería ocurrir, una de las condiciones que requiere este comando no tiene un manejador de mensajes.", - "missingChatInputHandler": "Esto nunca debería ocurrir, una de las condiciones que requiere este comando no tiene un manejador de comandos slash.", - "missingContextMenuHandler": "Esto nunca debería ocurrir, una de las condiciones que requiere este comando no tiene un manejador de menú contextual.", - "administrator": "Necesitas privilegios de administrador para ejecutar `{{command.name}}`!", - "disabledGlobal": "Este comando ha sido desactivado globalmente por los propietarios del bot. ¿Quieres saber por qué y averiguar cuándo va a volver? Únete al servidor oficial de WolfStar: ", - "disabledGuild": "¡Este comando ha sido desactivado por un administrador en este servidor!", - "moderator": "Necesitas privilegios de moderador para ejecutar `{{command.name}}`!", - "permissionNodes": "{{REDCROSS}} ¡No tienes permiso para usar este comando!", - "serverOwner": "Necesitas ser el dueño del servidor para ejecutar `{{command.name}}`!", - "dmOnly": "Este comando solo puede ser utilizado en mensajes directos.", - "guildNewsOnly": "Este comando sólo puede utilizarse en canales de anuncios.", - "guildNewsThreadOnly": "Este comando sólo puede utilizarse en los hilos de los canales de anuncios.", - "guildOnly": "Este comando solo puede ser utilizado dentro de un servidor.", - "guildPrivateThreadOnly": "Este comando solo puede ser utilizado en hilos privados.", - "guildPublicThreadOnly": "Este comando sólo puede utilizarse en los hilos públicos.", - "guildTextOnly": "Este comando solo puede ser utilizado en canales de texto.", - "threadOnly": "Este comando sólo puede utilizarse en los hilos." -} \ No newline at end of file diff --git a/src/languages/es-419/selfModeration.json b/src/languages/es-419/selfModeration.json deleted file mode 100644 index 980f7e2f0..000000000 --- a/src/languages/es-419/selfModeration.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "commandDisabled": "{{GREENTICK}} Sub-sistema deshabilitado con éxito.", - "commandEnabled": "{{GREENTICK}} Sub-sistema habilitado con éxito.", - "commandHardAction": "{{GREENTICK}} Castigo establecido con éxito: {{value}}", - "commandHardActionDuration": "{{GREENTICK}} Se eliminó con éxito el temporizador de apelación del castigo.", - "commandHardActionDurationWithValue": "{{GREENTICK}} Se ha establecido correctamente el temporizador de apelación de castigo a: {{value, duration}}", - "commandInvalidHardaction": "{{REDCROSS}} El valor debe ser cualquiera de los siguientes: `none`, `warn`, `mute`, `kick`, `softban`, o `ban`. Consulta `WolfStar, help {{name}}` para más información.", - "commandInvalidMissingAction": "{{REDCROSS}} La acción debe ser cualquieraa de las siguientes: `enable`, `disable`, `action`, `punish`, `punish-duration`, `threshold-maximum`, `threshold-duration` o `show`. Consulta `WolfStar, help {{name}}` para más información.", - "commandInvalidMissingArguments": "{{REDCROSS}} La acción especificada requiere que se pase un argumento extra. Revisa `WolfStar, help {{name}}` para más información.", - "commandInvalidSoftaction": "{{REDCROSS}} El valor debe ser cualquiera de los siguientes: `alert`, `log` o `delete`. Consulta `WolfStar, help {{name}}` para más información.", - "commandShow": "Activado : {{kEnabled}}\nAcción\n - Alerta : {{kAlert}}\n - Registro : {{kLog}}\n - Eliminar : {{kDelete}}\nPuntuación\n - Escribir : {{kHardAction}}\n - Duración : {{hardActionDurationText}}\nUmbral\n - Máximo : {{thresholdMaximumText}}\n - Duración : {{thresholdDurationText}}", - "commandShowDurationPermanent": "Permanente", - "commandShowUnset": "Sin definir", - "commandSoftAction": "{{GREENTICK}} Acciones deshabilitadas con éxito.", - "commandSoftActionWithValue": "{{GREENTICK}} Acciones establecidas con éxito a: `{{value}}`", - "commandThresholdDuration": "{{GREENTICK}} Se ha eliminado correctamente la duración del umbral, los castigos se aplicarán al instante si éste fue establecido.", - "commandThresholdDurationWithValue": "{{GREENTICK}} Se estableció correctamente la duración del umbral a: {{value, duration}}", - "commandThresholdMaximum": "{{GREENTICK}} Se ha eliminado correctamente el umbral máximo, los castigos se aplicarán al instante si éste fue establecido.", - "commandThresholdMaximumWithValue": "{{GREENTICK}} Se estableció correctamente la duración del umbral a: {{value}}", - "hardActionBan": "Banear", - "hardActionKick": "Expulsar", - "hardActionMute": "Silenciar", - "hardActionNone": "Ninguno", - "hardActionSoftban": "SoftBan", - "hardActionWarning": "Advertencia", - "softActionAlert": "Notificación", - "softActionDelete": "Borrar", - "softActionLog": "Informe" -} \ No newline at end of file diff --git a/src/languages/es-419/serializers.json b/src/languages/es-419/serializers.json deleted file mode 100644 index 6ab3701dc..000000000 --- a/src/languages/es-419/serializers.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "disabledCommandChannelsChannelsCommandDoesNotExist": "El comando `{{name}}` no existe.", - "disabledCommandChannelsChannelsDoesNotExist": "Ese canal de chat no existe.", - "invalidBool": "{{name}} debe ser verdadero o falso.", - "invalidChannel": "{{name}} debe ser una etiqueta de canal o un identificador de canal válido.", - "invalidCommand": "{{name}} debe ser un nombre de comando.", - "invalidEmoji": "{{name}} debe ser un emoji válido.", - "invalidFloat": "{{name}} debe ser un número válido.", - "invalidGuild": "{{name}} debe ser un identificador de servidor válido.", - "invalidInt": "{{name}} debe ser un número entero.", - "invalidInvite": "{{name}} debe ser un código de invitación válido.", - "invalidRole": "{{name}} debe ser una mención o identificador de rol.", - "invalidSnowflake": "{{name}} debe ser un identificador válido.", - "invalidUrl": "{{name}} debe ser un enlace válido.", - "invalidUser": "{{name}} debe ser una mención o identificador de usuario.", - "minMaxBothExclusive": "{{name}} debe estar entre {{min}} y {{max}} exclusivamente.", - "minMaxBothInclusive": "{{name}} debe estar entre {{min}} y {{max}} inclusivamente.", - "minMaxExactlyExclusive": "{{name}} debe ser exactamente {{min}}.", - "minMaxExactlyInclusive": "{{name}} debe ser exactamente {{min}}.", - "minMaxMaxExclusive": "{{name}} debe ser menor que {{max}} exclusivamente.", - "minMaxMaxInclusive": "{{name}} debe ser menor que {{max}} inclusivamente", - "minMaxMinExclusive": "{{name}} debe ser mayor que {{min}} exclusivamente.", - "minMaxMinInclusive": "{{name}} debe ser mayor que {{min}} inclusivamente.", - "permissionNodeDuplicatedCommand": "Has establecido `{{command}}` dos veces, o lo permites, o lo niegas.", - "permissionNodeInvalid": "Datos no válidos.", - "permissionNodeInvalidCommand": "El comando `{{command}}` no existe o no es válido.", - "permissionNodeInvalidTarget": "No se pudo encontrar ningún dato del ID.", - "permissionNodeSecurityEveryoneAllows": "Por lo que respecta a la seguridad, el rol everyone no puede tener permisos extras.", - "permissionNodeSecurityGuarded": "Por seguridad y para mi correcto funcionamiento, no se puede negar el uso para el comando `{{command}}`.", - "wordIncluded": "La key `{{name}}` ya incluye la palabra `{{word}}`.", - "permissionNodeSecurityOwner": "No puedes denegar permisos al propietario del servidor.", - "reactionRoleInvalid": "Los datos del rol de reacción no son inválidos.", - "stickyRoleInvalid": "Los datos de rol pegajoso no son válidos.", - "twitchSubscriptionInvalid": "Los datos no son válidos.", - "twitchSubscriptionInvalidStreamer": "Los datos del streamer no son válidos.", - "uniqueRoleSetInvalid": "Los datos del conjunto de roles único no son válidos.", - "unknownChannel": "Canal Desconocido", - "unknownRole": "Rol Desconocido", - "unknownUser": "Usuario Desconocido", - "unsupported": "Esta clave de configuración no puede ser actualizada a través de Discord en este momento, ¡Por favor, usa el panel de control en !" -} \ No newline at end of file diff --git a/src/languages/es-419/settings.json b/src/languages/es-419/settings.json deleted file mode 100644 index 1392c4159..000000000 --- a/src/languages/es-419/settings.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "channelsMediaOnly": "Los canales en los que únicamente se pueden enviar archivos multimedia.", - "channelsIgnoreAll": "Canales que debería ignorar para todos los tipos de registros.", - "channelsIgnoreMessageDelete": "Canales que debería ignorar para los registros de mensajes borrados.", - "channelsIgnoreMessageEdit": "Canales que debería ignorar para los registros de mensajes editados.", - "channelsIgnoreReactionAdd": "Canales que debería ignorar para los registros de reacciones añadidas.", - "channelsLogsChannelCreate": "El canal para los registros de creación de canales en el servidor, si este se establece enviaré un mensaje cuando se cree otro canal.", - "channelsLogsChannelDelete": "El canal para los registros de canales eliminados en el servidor, si este se establece, enviaré un mensaje a este canal cuando se elimine otro canal.", - "channelsLogsChannelUpdate": "El canal para los registros de actualización del canal en el servidor, si este se establece, enviaré un mensaje a este canal cuando cualquier canal (incluyendo este) se actualice de alguna manera. Este mensaje contendrá los cambios realizados en el canal.", - "channelsLogsEmojiCreate": "El canal para los registros de creación de emojis, si este se establece, enviaré un mensaje cuando se haya creado un nuevo emoji.", - "channelsLogsEmojiDelete": "El canal para los registros de emojis eliminados, si este se establece, enviaré un mensaje cuando se haya eliminado emoji.", - "channelsLogsEmojiUpdate": "El canal de los registros de actualizaciones de emojis, si este se establece, enviaré un mensaje cuando un emoji se actualiza de cualquier manera. Este mensaje contendrá los cambios realizados al emoji.", - "channelsLogsImage": "El canal que utilizaré para volver a subir todas las imágenes que vea.", - "channelsLogsMemberAdd": "El canal al cual enviaré un mensaje cuando un miembro se una.", - "channelsLogsMemberRemove": "El canal al cual enviaré un mensaje cuando un miembro se vaya, sea expulsado o prohibido.", - "channelsLogsMemberNickNameUpdate": "El canal al cual enviaré un mensaje cuando un miembro se cambie el apodo.", - "channelsLogsMemberUserNameUpdate": "El canal al cual enviaré un mensaje cuando un miembro se cambie su nombre de usuario.", - "channelsLogsMemberRolesUpdate": "El canal donde enviaré un mensaje cuando un miembro obtiene o pierde un rol.", - "channelsLogsMessageDelete": "El canal al que enviaré un mensaje cuando se elimine un mensaje.", - "channelsLogsMessageDeleteNsfw": "El canal donde enviaré un mensaje cuando se haya eliminado un mensaje de un canal NSFW.", - "channelsLogsMessageUpdate": "El canal al que enviaré un mensaje cuando se elimine un mensaje.", - "channelsLogsMessageUpdateNsfw": "El canal donde enviaré un mensaje cuando se haya actualizado un mensaje de un canal NSFW.", - "channelsLogsModeration": "El canal para los registros de moderación, una vez habilitado, publicaré todos mis casos de moderación allí. Si `events.banRemove` y/o `events.ban-remove` están habilitados, publicaré registros anónimos de forma automática.", - "channelsLogsPrune": "El canal para los registros de mensajes, el mismo requisito que los registros de mensajes normales, pero sólo enviará mensajes de podas de mensajes." -} \ No newline at end of file diff --git a/src/languages/es-419/system.json b/src/languages/es-419/system.json deleted file mode 100644 index 1a5bfbe79..000000000 --- a/src/languages/es-419/system.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "discordAbortError": "Tuve un pequeño error de red al enviar el mensaje a Discord, ¡por favor ejecuta este comando de nuevo!", - "fetchBansFail": "Error al obtener la información de los baneos. ¿Tengo el permiso **{{ADMINISTRATOR, permissions}}**?", - "helpTitles": { - "aliases": "🖇️ | **Aliases**", - "usages": "📝 | **Uso de Comando**", - "extendedHelp": "🔍 | **Ayuda Extendida**", - "explainedUsage": "⚙ | **Uso explicado**", - "possibleFormats": "🔢 | **Formatos posibles**", - "examples": "🔗 | **Ejemplos**", - "reminders": "⏰ | **Recordatorio**" - }, - "jumpTo": "Saltar al Mensaje ►", - "loading": [ - "{{LOADING}} Viendo hámsters correr...", - "{{LOADING}} Buscando personas en el escondite...", - "{{LOADING}} Tratando de averiguar este comando...", - "{{LOADING}} Obteniendo datos desde la nube...", - "{{LOADING}} Calibrando lentes...", - "{{LOADING}} Jugando piedra, papel, tijeras...", - "{{LOADING}} Ajustando a las frecuencias correctas...", - "{{LOADING}} Reticulando curvas..." - ], - "prefixReminder": "El prefijo de este servidor es: `{{prefix}}`" -} \ No newline at end of file diff --git a/src/languages/es-ES/arguments.json b/src/languages/es-ES/arguments.json deleted file mode 100644 index 3b8900cd2..000000000 --- a/src/languages/es-ES/arguments.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "boolean_one": "No pude resolver `{{parameter}}` a un booleano, el único posible valor es: {{possibles}}", - "boolean_other": "No pude resolver `{{parameter}}` a un booleano, los valores posibles son: {{possibles, orList}}", - "booleanError": "No pude resolver `{{parameter}}` a un booleano, el único posible valor es: {{possibles}}", - "booleanDisabled": "Desabilitado", - "booleanEnabled": "Habilitado", - "booleanFalseOptions": [ - "falso", - "f", - "no", - "n", - "apagado", - "desabilitar", - "desabilitado", - "0", - "-" - ], - "booleanTrueOptions": [ - "verdadero", - "v", - "si", - "s", - "encendido", - "habilitar", - "habilitado", - "1", - "+" - ], - "caseNoEntries": "", - "caseUnknownEntry": "", - "caseNotInThisGuild": "", - "caseLatestOptions": [ - "ultimo", - "último" - ], - "categoryChannelError": "No pude resolver `{{parameter}}` a un canal de categoría, ¡por favor asegúrese de que escribió su nombre o ID correctamente!", - "channelError": "No pude resolver `{{parameter}}` a un canal, ¡asegúrate de que escribiste su nombre o ID correctamente!", - "command": "¡No pude resolver `{{parameter}}` a un comando! ¡Asegúrate de que escribiste su nombre o uno de sus alias correctamente!", - "commandMatch": "No pude coincidir `{{parameter}}` con un comando ni categoría, estos son algunos de los formatos válidos:\n\n- `ping` (coincide con el comando ping solamente).\n- `management.*` (coincide con todos los comandos de la categoría **Management**).\n- `management.configuration.*` (coincide con todos los comandos en la subcategoría **Management** > **Configuration**).\n\n> **Pista**: Cuando utilizas `{{commandContext.commandPrefix}}help`, la categoría de cada comando se encuentra en la parte superior de la inserción.", - "dateError": "No pude resolver `{{parameter}}` a una fecha, aquí tiene alguno de los formatos válidos:\n\n$t(arguments:dateFormats)", - "dateFormats": "- `2016-11-24` (AAAA-MM-DD)\n- `2016-11-24T23:56` (AAAA-MM-DDTHH:mm)\n- `2016-11-24T23:56:12` (AAAA-MM-DDTHH:mm:ss)\n- `2016-11-24T23:56:12. 00` (AAAA-MM-DDTHH:mm:sss)\n\n> **Pista**: Los últimos 3 formatos aceptan `Z` al final para marcar la hora como UTC`. Alternativamente, puedes poner la zona horaria añadiendo `+HH:MM`, por ejemplo `+01:00`.", - "dateTooEarly": "El parámetro `{{parameter}}` resuelto a una fecha anterior a {{minimum, dateTime}}, ¡el cual no está permitido!", - "dateTooFar": "El parámetro `{{parameter}}` resuelto a una fecha posterior a {{maximum, dateTime}}, ¡el cual no está permitido!", - "dmChannelError": "No pude resolver `{{parameter}}` a un canal de mensajes directos, ¡asegúrate de que escribiste su nombre o ID correctamente!", - "duration": "No pude resolver `{{parameter}}` a una duración válida, aquí tiene alguno de los formatos válidos:\n\n$t(arguments:durationFormats)", - "durationFormats": "- `4h` (4 horas).\n- `20m5s` (20 minutos y 5 segundos).\n- `\"1w 2d 16h 40m 10s\"` (1 semana, 2 días, 16 horas, 40 minutos y 10 segundos).", - "emojiError": "No pude resolver `{{parameter}}` a un emoji válido, ¿estás seguro de que has usado un twemoji (e.g. 🌊) o un emoji (por ejemplo, {{GREENTICK}})?", - "floatError": "¡No pude resolver `{{parameter}}` a un número!", - "floatTooLarge": "", - "floatTooSmall": "¡El parámetro `{{parameter}}` es demasiado pequeño! ¡Debe ser al menos {{minimum}}!", - "guildChannelError": "No pude resolver `{{parameter}}` a un canal de este servidor, ¡por favor asegúrese de que escribió su nombre o ID correctamente!", - "guildChannelMismatchingError": "El parámetro `{{parameter}}` resuelto a un tipo de canal incompatible en este servidor, ¡por favor prueba otro canal!", - "guildChannelMissingGuildError": "No pude resolver `{{parameter}}` porque este argumento requiere ser ejecutado en un canal de un servidor.", - "guildPrivateThreadChannelError": "No pude resolver `{{parameter}}` a un hilo privado, ¡por favor asegúrese de que escribió su nombre o ID correctamente!", - "guildPublicThreadChannelError": "No pude resolver `{{parameter}}` a un hilo público, ¡por favor asegúrese de que escribió su nombre o ID correctamente!", - "guildStageVoiceChannelError": "No pude resolver `{{parameter}}` a un canal de Stage, ¡por favor asegúrese de que escribió su nombre o ID correctamente!", - "guildTextChannelError": "No pude resolver `{{parameter}}` a un canal de texto, ¡por favor asegúrese de que escribió su nombre o ID correctamente!\n\n> **Consejo**: ¡También puedes mencionarlo!", - "guildThreadChannelError": "No pude resolver `{{parameter}}` a un hilo, ¡por favor asegúrese de que escribió su nombre o ID correctamente!", - "guildVoiceChannelError": "No pude resolver `{{parameter}}` a un canal de voz, ¡por favor asegúrese de que escribió su nombre o ID correctamente!", - "hyperlinkError": "No pude resolver `{{parameter}}` a un enlace, ¡normalmente están formateados de forma similar a `https://discord.com`!", - "integerError": "¡No pude resolver `{{parameter}}` a un entero!", - "integerTooLarge": "", - "integerTooSmall": "¡El parámetro `{{parameter}}` es demasiado pequeño! ¡Debe ser al menos {{minimum}}!", - "invite": "No pude resolver `{{parameter}}` a un enlace de invitación válido, aquí tiene alguno de los formatos válidos:\n\n- `https://discord​.gg/6gakFR2`.\n- `https://discord​.com/invite/6gakFR2`.\n- `https://discordapp​.com/invite/6gakFR2`.\n\n> **Consejo**: Puedes omitir la parte `https://`, `discord​.gg/6gakFR2` también es aceptado como un parámetro válido.", - "language": "", - "memberError": "No pude resolver `{{parameter}}` a un miembro de este servidor, ¡por favor asegúrate de escribir su nombre o ID correctamente!\n\n> **Consejo**: ¡También puedes usar menciones!", - "memberMissingGuild": "No pude resolver `{{parameter}}` porque este argumento requiere ser ejecutado en un canal de un servidor.", - "messageError": "No pude resolver `{{parameter}}` a un mensaje:\n\n- Si usaste un **ID** (p. ej. `{{message.id}}`), asegúrate de que has copiado el ID correcto de este canal (<#{{channel}}>), y no, por ejemplo, el ID del autor.\n- Si usaste un **enlace de mensaje** (ej. `{{message.url}}`), asegúrese de que es de un canal de este servidor, y que ambos tenemos permisos para leerlo.\n- No ha introducido un parámetro válido, en ese caso, ¡compruebe las dos anteriores!", - "missing": "¡Necesitas escribir otro parámetro!\n\n> **Consejo**: puedes hacer `{{commandContext.commandPrefix}}help {{command.name}}` para averiguar cómo usar este comando.", - "newsChannel": "No pude resolver `{{parameter}}` a un canal de anuncios, ¡por favor asegúrese de que escribió su nombre o ID correctamente!\n\n> **Consejo**: ¡También puedes mencionarlo!", - "numberError": "¡No pude resolver `{{parameter}}` a un número!", - "numberTooLarge": "", - "numberTooSmall": "¡El parámetro `{{parameter}}` es demasiado pequeño! ¡Debe ser al menos {{minimum}}!", - "piece": "¡No pude resolver `{{parameter}}` a una pieza! ¡Asegúrate de que escribiste su nombre o uno de sus alias correctamente!", - "rangeInvalid": "`{{parameter}}` debe ser un número o un rango de números.", - "rangeMax_other": "`{{parameter}}` acepta un rango de máximo {{maximum}} números", - "rangeMax_one": "`{{parameter}} acepta un máximo de {{maximum}} número", - "resetPossibles": [ - "apagado", - "restablecer" - ], - "roleError": "No pude resolver `{{parameter}}` a un rol, ¡por favor asegúrate de escribir su nombre o ID correctamente!\n\n> **Consejo**: ¡También puedes mencionarlo!", - "roleMissingGuild": "No pude resolver `{{parameter}}` porque este argumento requiere ser ejecutado en un canal de un servidor.", - "snowflake": "¡No pude resolver `{{parameter}}` a un copo de nieve válido! Son números con 17 a 18 dígitos, por ejemplo, ¡tu mensaje tiene un Snowflake de `{{message.id}}`!", - "store": "", - "stringTooLong": "¡El parámetro `{{parameter}}` es demasiado largo! ¡Debe tener menos de {{maximum}} caracter(es)!", - "stringTooShort": "¡El parámetro `{{parameter}}` es demasiado largo! ¡Debe tener menos de {{minimum}} caracter(es)!", - "time": "¡No pude resolver `{{parameter}}` a un tiempo válido!\n**Pista**: los siguientes formatos son compatibles:\n\n$t(arguments:durationFormats)\n$t(arguments:dateFormats)", - "timeSpan": "No pude resolver `{{parameter}}` a una duración válida, asegúrese de que escribió un entero válido o un valor formateado de duración. Algunos de los formatos válidos son:\n\n- `45` (45 segundos).\n$t(arguments:durationFormats)\n$t(arguments:dateFormats)", - "timeSpanTooBig": "El parámetro `{{parameter}}` resuelto a una duración mayor a {{maximum, duration}}, ¡el cual no está permitido!", - "timeSpanTooSmall": "El parámetro `{{parameter}}` resuelto a una duración menor a {{minimum, duration}}, ¡el cual no está permitido!", - "tooFewWinners": "El parámetro `{{parameter}}` resolvió a un número demasiado bajo, ¡debe ser al menos 1!", - "tooManyWinners": "El parámetro `{{parameter}}` resolvió a un número demasiado alto, ¡debe ser como máximo 20!", - "unavailable": "¡Ups! Parece que no he podido encontrar un analizador para un parámetro, ¡por favor contacta a mis desarrolladores sobre esto!", - "userError": "No pude resolver `{{parameter}}` a un usuario, ¡por favor asegúrate de escribir su nombre o ID correctamente!\n\n> **Consejo**: ¡También puedes mencionarlo!", - "enumEmptyError": "No pude resolver `{{parameter}}` porque la lista de valores posibles está vacía.", - "enumError": "No pude resolver `{{parameter}}` a un valor válido, los valores posibles son: {{possibles, orList}}" -} \ No newline at end of file diff --git a/src/languages/es-ES/assertions.json b/src/languages/es-ES/assertions.json deleted file mode 100644 index eff4222d4..000000000 --- a/src/languages/es-ES/assertions.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "expectedNonThreadChannel": "Se esperaba un canal de texto normal, pero en su lugar recibí el hilo {{channel}}." -} \ No newline at end of file diff --git a/src/languages/es-ES/commands/admin.json b/src/languages/es-ES/commands/admin.json deleted file mode 100644 index 572e8e35c..000000000 --- a/src/languages/es-ES/commands/admin.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "confUpdated": "Se actualizó exitosamente la clave **{{key}}**: `{{response}}", - "confGetNoExt": "La clave **{{key}}** parece no existir.", - "confGet": "El valor para la clave **{{key}}** es: `{{value}}`", - "confReset": "La clave **{{key}}** ha sido restablecida a: `{{value}}`", - "confNochange": "El valor de **{{key}}** ya era de ese valor.", - "confServerDescription": "Define los ajustes por servidor.", - "confServerExtended": { - "usages": [ - "set NombreDeClave Valor para la Clave", - "show", - "show NombreDeClave", - "remove NombreDeClave Valor para la Clave", - "reset NombreDeClave", - "menu" - ], - "extendedHelp": "Te permite configurar WolfStar desde Discord, como una alternativa rápida al [panel de control web](https://wolfstar.rocks).", - "examples": [ - "set language es-ES", - "set channels.moderation-logs #logs-de-moderacion", - "show", - "show channels", - "remove roles.moderator Moderador", - "reset roles.moderator", - "menu" - ], - "reminder": "Hay claves y grupos, claves que están dentro de un grupo son nombradas por `GroupName.KeyName`." - }, - "confServer": "**Configuración del servidor {{key}}**\n{{list}}", - "confDashboardOnlyKey": "`{{key}}` sólo puede configurarse a través del panel web ()", - "confSettingNotSet": "No Establecido", - "rolesetDescription": "Administrar los conjuntos de roles únicos.", - "rolesetExtended": { - "usages": [ - "set NombreDeConjuntoDeRoles Rol1 Rol2 Rol3...", - "remove NombreDeConjuntoDeRoles Rol1 Rol2 Rol3...", - "reset", - "reset NombreDeConjuntoDeRoles", - "list", - "NombreDeConjuntoDeRoles Rol1 Rol2 Rol3" - ], - "extendedHelp": "Un conjunto de roles es un grupo de roles que WolfStar identifica como único para todos los miembros del servidor, por ejemplo. un conjunto de roles llamado `region` podría tener los roles `África`, `America`, `Asia` y `Europa`, y los miembros solo podrán tener uno de ellos. Esto es como una especie de \"regla\" que se aplica en las tres siguientes situaciones:\n\n- Cuando alguien reclama un rol a través del comando `roles`.\n- Cuando alguien reclama un rol a través de roles de reacción.\n- Cuando alguien recibe un rol de forma manual o de otro bot.", - "explainedUsage": [ - [ - "añadir", - "Crea un nuevo conjunto de roles o añade un rol a un conjunto ya existente." - ], - [ - "eliminar", - "Eliminar un rol de un conjunto existente." - ], - [ - "resetear", - "Elimina todos los roles de un rol o, si no se especifica, todos los roles existentes." - ], - [ - "lista", - "Enumera todos los conjuntos de roles." - ], - [ - "automático", - "Añade o elimina un conjunto de roles." - ], - [ - "NombreDeConjuntoDeRoles", - "El nombre del set de roles" - ], - [ - "Rol1 Rol2 Rol3", - "Los roles a añadir al conjunto de roles" - ] - ], - "examples": [ - "add regiones América", - "add regiones África América Asia Europa", - "remove regiones América", - "reset", - "reset regiones", - "list", - "regiones América", - "regiones África América Asia Europa" - ], - "reminder": "Este comando puede agregar y/o eliminar múltiples roles al mismo tiempo." - }, - "rolesetCreated": "", - "rolesetAdded": "", - "rolesetRemoved": "", - "rolesetResetEmpty": "{{REDCROSS}} No existen conjuntos de roles configurados en este servidor.", - "rolesetResetAll": "{{GREENTICK}} Se han eliminado todos los conjuntos de roles con éxito.", - "rolesetResetNotExists": "{{REDCROSS}} The conjunto de roles `{{name}}` no existe en este servidor.", - "rolesetResetGroup": "{{GREENTICK}} Se eliminó correctamente el conjunto de roles `{{name}}` de este servidor.", - "rolesetUpdated": "El conjunto de roles único {{name}} ha sido actualizado.", - "rolesetNoRolesets": "No hay conjuntos de roles.", - "confMenuRenderAtFolder": "Actualmente en: 📁 {{path}}", - "confMenuRenderAtPiece": "Actualmente en: ⚙️ {{path}}", - "confMenuRenderNokeys": "No hay claves configurables para este grupo", - "confMenuRenderSelect": "Por favor ingrese cualquiera de los nombres de las siguientes entradas", - "confMenuRenderUpdate": "• Actualizar Valor → `set `", - "confMenuRenderRemove": "• Eliminar valor → `remove `", - "confMenuRenderReset": "• Restablecer valor → `reset`", - "confMenuRenderUndo": "• Deshacer actualización → `undo`", - "confMenuRenderCvalue": "Valor actual: **``{{value}}``**", - "confMenuRenderBack": "Pulsa ◀ para volver atrás", - "confMenuInvalidKey": "Clave no válida, por favor inténtalo de nuevo con cualquiera de las siguientes opciones.", - "confMenuInvalidAction": "Acción no válida, por favor inténtalo de nuevo con cualquiera de las siguientes opciones.", - "confMenuSaved": "Guardado todos los cambios con éxito." -} \ No newline at end of file diff --git a/src/languages/es-ES/commands/animal.json b/src/languages/es-ES/commands/animal.json deleted file mode 100644 index 4ab50fc35..000000000 --- a/src/languages/es-ES/commands/animal.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "bunnyDescription": "Déjame mostrarte una imagen de un adorable conejito ❤️.", - "bunnyExtended": { - "extendedHelp": "Este comando da una imagen aleatoria de [bunnies.io](https://www.bunnies.io)." - }, - "bunnyEmbedData": { - "title": "Haga clic aquí si la imagen falla al cargar", - "source": "fuente" - }, - "dogDescription": "¡Perritos lindos! ❤", - "dogExtended": { - "extendedHelp": "¿Sabes cuán lindos son los perros? ¡Son tan hermosos!\n¡Este comando usa [dog.ceo](https://dog.ceo) para mostrar imágenes de los cachorros más monos!" - }, - "foxDescription": "¡Permítame mostrarte una imagen de un zorro!", - "foxExtended": { - "extendedHelp": "Este comando da una imagen aleatoria de [randomfox.ca](https://randomfox.ca/)." - }, - "kittyDescription": "¡GATITOS!", - "kittyExtended": { - "extendedHelp": "¿Sabes cuán lindos son los gatitos? ¡Son tan hermosos!\n¡Este comando usa [cataas.com](https://cataas.com/) para mostrar fotos de los gatitos más monos!" - }, - "shibeDescription": "¡Shibas monos!", - "shibeExtended": { - "extendedHelp": "Todo el mundo ama a los shibas, ¡y yo también! Son tan adorables ❤" - } -} \ No newline at end of file diff --git a/src/languages/es-ES/commands/auto-moderation.json b/src/languages/es-ES/commands/auto-moderation.json deleted file mode 100644 index 0ad2e4ea7..000000000 --- a/src/languages/es-ES/commands/auto-moderation.json +++ /dev/null @@ -1,77 +0,0 @@ -{ - "showName": "mostrar", - "showDescription": "Muestra la configuración actual de este servidor", - "editName": "editar", - "editDescription": "Edita la configuración de este servidor", - "resetName": "restablecer", - "resetDescription": "Restablece una opción de configuración a su valor predeterminado", - "addName": "añadir", - "removeName": "eliminar", - "optionsEnabledName": "habilitado", - "optionsEnabledDescription": "Alternar el subsistema", - "optionsActionAlertName": "alerta", - "optionsActionAlertDescription": "Alternar alertas de mensajes en el canal", - "optionsActionLogName": "registro", - "optionsActionLogDescription": "Alterna los registros de mensajes en el canal de registro de moderación, si estuviera definido", - "optionsActionDeleteName": "borrar", - "optionsActionDeleteDescription": "Alterna el borrado de mensajes", - "optionsPunishmentName": "sanción", - "optionsPunishmentDescription": "Establece la acción de moderación a tomar después de que se alcance el umbral", - "optionsPunishmentDurationName": "duración-sanción", - "optionsPunishmentDurationDescription": "Establece la duración de la sanción", - "optionsThresholdName": "umbral", - "optionsThresholdDescription": "Establece la cantidad de infracciones permitidas en el periodo establecido", - "optionsThresholdPeriodName": "periodo-umbral", - "optionsThresholdPeriodDescription": "Establece el tiempo en el que se acumularán las infracciones", - "optionsKeyName": "opción", - "optionsKeyDescription": "La opción a restablecer", - "optionsKeyEnabled": "Habilitado", - "optionsKeyActionAlert": "Mensajes de Alerta", - "optionsKeyActionLog": "Publicar Registros de Moderación", - "optionsKeyActionDelete": "Borrado de Mensajes", - "optionsKeyPunishment": "Sanción", - "optionsKeyPunishmentDuration": "Duración de la Sanción", - "optionsKeyThreshold": "Umbral de la Sanción", - "optionsKeyThresholdPeriod": "Duración del Umbral de la Sanción", - "optionsKeyWords": "Palabras", - "optionsWordName": "palabra", - "optionsWordDescription": "La palabra a añadir o eliminar", - "attachmentsName": "automod-adjuntos", - "attachmentsDescription": "Administra el auto-moderador para archivos adjuntos", - "capitalsName": "automod-mayúsculas", - "capitalsDescription": "Administra el auto-moderador para mayúsculas", - "wordsName": "automod-palabras", - "wordsDescription": "Administra el auto-moderador para el filtro de palabras", - "invitesName": "automod-invitaciones", - "invitesDescription": "Administra el auto-moderador para las invitaciones", - "linksName": "automod-enlaces", - "linksDescription": "Administra el auto-moderador para el filtro de enlaces", - "spamName": "automod-spam", - "spamDescription": "Administra el auto-moderador para el filtro de spam", - "newlinesName": "automod-líneas", - "newlinesDescription": "Administra el auto-moderador para el filtro de líneas", - "reactionsName": "automod-reacciones", - "reactionsDescription": "Administra el auto-moderador para el filtro de reacciones", - "showDisabled": "Auto-moderador inactivo", - "showEnabled": "Auto-moderador activo", - "showReplyActive": "{{emoji}} **Mensajes de Alerta**", - "showReplyInactive": "{{emoji}} ~~Mensajes de Alerta~~", - "showLogActive": "{{emoji}} **Publicar Registros de Moderación**", - "showLogInactive": "{{emoji}} ~~Publicar Registros de Moderación~~", - "showDeleteActive": "{{emoji}} **Borrado de Mensajes**", - "showDeleteInactive": "{{emoji}} ~~Borrado de mensajes~~", - "showPunishmentTitle": "Sanción activa", - "showPunishment": "{{emoji}} **Tipo:** {{name}}", - "showPunishmentTemporary": "{{emoji}} **Tipo:** {{name}} por {{duration}}", - "showPunishmentThreshold": "{{emoji}} **Se aplica tras:** {{threshold, number}} infracciones en {{period}}", - "editSuccess": "Editado con éxito la configuración del auto-moderador.", - "wordAddDescription": "Añade una palabra al filtro", - "wordAddFiltered": "La palabra `{{word}}` ya estaba filtrada.", - "wordRemoveDescription": "Elimina una palabra del filtro", - "wordRemoveNotFiltered": "La palabra `{{word}}` no estaba filtrada.", - "wordShowList": "{{words, list(conjunction)}}", - "wordShowListTitle_one": "Palabra Filtrada ({{count, number}})", - "wordShowListTitle_other": "Palabras Filtradas ({{count, number}})", - "wordShowListEmpty": "Utilice {{command}} para añadir palabras a la lista de filtros.", - "wordShowListTitleEmpty": "No hay palabras filtradas actualmente" -} \ No newline at end of file diff --git a/src/languages/es-ES/commands/case.json b/src/languages/es-ES/commands/case.json deleted file mode 100644 index d99982bea..000000000 --- a/src/languages/es-ES/commands/case.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "name": "caso", - "description": "Gestiona o visualiza casos de moderación.", - "viewName": "visualizar", - "viewDescription": "Muestra la información de un caso de moderación.", - "archiveName": "archivar", - "archiveDescription": "Archiva un caso de moderación.", - "deleteName": "borrar", - "deleteDescription": "Borra un caso de moderación.", - "editName": "editar", - "editDescription": "Edita un caso de moderación.", - "listName": "lista", - "listDescription": "Lista los casos de moderación.", - "optionsCaseName": "caso", - "optionsCaseDescription": "El número del caso de moderación.", - "optionsReasonName": "motivo", - "optionsReasonDescription": "El nuevo motivo para el caso de moderación.", - "optionsDurationName": "duración", - "optionsDurationDescription": "La nueva duración para el caso de moderación.", - "optionsUserName": "usuario", - "optionsUserDescription": "El usuario por el que filtrar los casos de moderación.", - "optionsOverviewName": "resumen", - "optionsOverviewDescription": "Si mostrar un resumen de los casos de moderación.", - "optionsTypeName": "tipo", - "optionsTypeDescription": "El tipo por el que filtrar los casos de moderación.", - "optionsPendingOnlyName": "sólo-pendientes", - "optionsPendingOnlyDescription": "Si mostrar únicamente los casos de moderación pendientes.", - "optionsShowName": "mostrar", - "optionsShowDescription": "Si mostrar o no la respuesta públicamente.", - "timeNotAllowed": "El tipo del caso de moderación (**{{type}}**) no permite una duración.", - "timeNotAllowedInCompletedEntries": "El caso de moderación `{{caseId}}` ya ha sido completado y no puede ser editado.", - "timeEditNotSupported": "El tipo de caso de moderación (**{{type}}**) no permite la edición de la duración.", - "timeTooEarly": "La duración del caso de moderación terminaría antes de que comience ({{time}}). La duración comienza en {{start}}.", - "listEmpty": "No hay casos de moderación con los filtros seleccionados.", - "listDetailsTitle_one": "Hay 1 entrada.", - "listDetailsTitle_other": "Hay {{count}} entradas.", - "listDetailsModerator": "{{emoji}} **Moderador:** {{mention}} ({{userId}})", - "listDetailsUser": "{{emoji}} **Usuario:** {{mention}} ({{userId}})", - "listDetailsExpires": "{{emoji}} **Expira {{time}}**", - "listOverviewFooter": "Este servidor tiene {{warnings}}, {{mutes}}, {{timeouts}}, {{kicks}} y {{bans}}", - "listOverviewFooterUser": "Este usuario tiene {{warnings}}, {{mutes}}, {{timeouts}}, {{kicks}} y {{bans}}", - "listOverviewFooterWarning_one": "{{count}} advertencia", - "listOverviewFooterWarning_other": "{{count}} advertencias", - "listOverviewFooterMutes_one": "{{count}} mute", - "listOverviewFooterMutes_other": "{{count}} mutes", - "listOverviewFooterTimeouts_one": "{{count}} tiempo de espera", - "listOverviewFooterTimeouts_other": "{{count}} tiempos de espera", - "listOverviewFooterKicks_one": "{{count}} expulsión", - "listOverviewFooterKicks_other": "{{count}} expulsiones", - "listOverviewFooterBans_one": "{{count}} baneo", - "listOverviewFooterBans_other": "{{count}} baneos", - "editSuccess": "Se ha editado correctamente el caso {{caseId}}.", - "archiveSuccess": "Se ha archivado correctamente el caso {{caseId}}.", - "deleteSuccess": "Se ha borrado correctamente el caso {{caseId}}." -} \ No newline at end of file diff --git a/src/languages/es-ES/commands/fun.json b/src/languages/es-ES/commands/fun.json deleted file mode 100644 index da7c134c8..000000000 --- a/src/languages/es-ES/commands/fun.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "escaperopeDescription": "Usa la Cuerda Huida de Pokemon.", - "escaperopeExtended": { - "extendedHelp": "**WolfStar** utilizó **Cuerda Huida**." - }, - "escaperopeOutput": "**{{user}}** utilizó **Cuerda Huida**" -} \ No newline at end of file diff --git a/src/languages/es-ES/commands/game.json b/src/languages/es-ES/commands/game.json deleted file mode 100644 index 1a0ec1faa..000000000 --- a/src/languages/es-ES/commands/game.json +++ /dev/null @@ -1,447 +0,0 @@ -{ - "c4Description": "Juega al Conecta Cuatro con alguien.", - "c4Extended": { - "usages": [ - "Usuario" - ], - "extendedHelp": "Este juego se juega mejor en el ordenador.\n\nEl objetivo de Conecta 4 es alinear cuatro fichas sobre un tablero formado por seis filas y siete columnas. Cada jugador dispone de 21 fichas de un color.​ Por turnos, los jugadores deben introducir una ficha en la columna que prefieran (siempre que no esté completa) y ésta caerá a la posición más baja. Gana la partida el primero que consiga alinear cuatro fichas consecutivas de un mismo color en horizontal, vertical o diagonal.​ Si todas las columnas están llenas pero nadie ha hecho una fila válida, hay empate.", - "examples": [ - "WolfStar" - ] - }, - "c4Prompt": "Estimado {{challengee}}. Has sido desafiado por {{challenger}} en una partida de Conecta 4. ¡Haz clic en la reacción to para aceptar!", - "gamesBot": "Lo siento, pero no creo que les gustaría dejar de hacer lo que están haciendo y jugar con los humanos.", - "gamesNoPlayers": "Por favor especifica algunos tributos para jugar a las Partidas del Hambre, así: `{{prefix}}hg Bob, Mark, Jim, Kyra`", - "gamesProgress": "Lo siento, pero hay un juego en curso en este canal, inténtelo de nuevo cuando termine.", - "gamesPromptDeny": "Lo siento, pero el contrincante se negó a jugar.", - "gamesRepeat": "Lo siento, pero un usuario no puede jugar dos veces.", - "gamesSelf": "Debes estar muy triste para jugar contra ti mismo. Inténtalo de nuevo con otro usuario.", - "gamesTooManyOrFew": "Lo siento, pero la cantidad de jugadores es menor que {{min}} o mayor que {{max}}.", - "hgBloodbath": [ - "{1} agarra una pala.", - "{1} toma una mochila y huye.", - "{1} y {2} luchan por una bolsa. {1} abandona y se retira.", - "{1} y {2} luchan por una bolsa. {2} abandona y se retira.", - "{1} encuentra un arco, algunas flechas y una aljaba.", - "{1} corre hacia la cornucopia y se esconde.", - "{1} toma un puñado de cuchillos arrojadizos.", - "{1} le arranca la maza de las manos de {2}.", - "{1} encuentra una cantimplora llena de agua.", - "{1} se queda en la cornucopia para recoger recursos.", - "{1} recolecta tanta comida como puede.", - "{1} agarra una espada.", - "{1} toma una lanza dentro de la cornucopia.", - "{1} encuentra una bolsa llena de explosivos.", - "{1} agarra un kit de primeros auxilios y huye.", - "{1} toma una hoz dentro de la cornucopia.", - "{1}, {2} y {3} trabajan juntos para obtener tantos suministros como sea posible.", - "{1} corre con un mechero y una cuerda.", - "{1} agarra una botella de alcohol y un trapo.", - "{1} encuentra una mochila llena de equipamiento de acampada.", - "{1} agarra una mochila, sin darse cuenta de que está vacía.", - "{1} rompe la nariz de {2} por una cesta de pan.", - "{1}, {2}, {3} y {4} comparten todo lo que recolectaron antes de correr.", - "{1} pilla un tridente dentro de la cornucopia.", - "{1} agarra un tarro de cebo de pesca mientras que {2} obtiene equipamiento de pesca.", - "{1} asusta a {2} de la cornucopia.", - "{1} agarra un escudo de la cornucopia.", - "{1} toma un par de kukris.", - "{1} agarra un solo par de pantalones.", - "{1T} abandona su podio demasiado pronto y explota.", - "{1} tira un cuchillo a la cabeza de {2T}.", - "{1T} pisa accidentalmente en una mina terrestre.", - "{1} pilla a {2T} fuera de guardia y lo mata.", - "{1} y {2} trabajan juntos para ahogar a {3T}.", - "{1} ahoga a {2T} después de una pelea a puños.", - "{1} dispara una flecha a la cabeza de {2T}.", - "{1T} no puede manejar las circunstancias y comete suicidio.", - "{1} golpea la cabeza de {2T} contra una roca varias veces.", - "{1} rompe el cuello de {2T}.", - "{1} decapita a {2T} con una espada.", - "{1} alancea a {2T} en el abdomen.", - "{1} prende fuego a {2T} con un molotov.", - "{1T} cae en un pozo y muere.", - "{1} apuñala a {2T} mientras que estaba de espaldas.", - "{1} hiere severamente a {2T}, pero lo saca de su miseria.", - "{1} hiere severamente a {2T} y le deja morir.", - "{1} rompe la cabeza de {2T} con un mazo.", - "{1} empuja a {2T} de un acantilado durante una pelea de cuchillo.", - "{1} tira un cuchillo a la torso de {2T}.", - "{1T} es incapaz de convencer a {2} de que no le mate.", - "{1} convence a {2T} para que no le mate, solo para matar a {2T} en su lugar.", - "{1T} cae en un lago congelado y se ahoga.", - "{1}, {2} y {3T} empiezan a luchar, pero {2} huye tan pronto como {1} mata a {3T}.", - "{1} mata a {2T} con su propio arma.", - "{1} aplasta a {2T}, matándoles.", - "{1} detona una carga explosiva, matando a {2T}.", - "{1} pone una carga explosiva, matando a {2T} y {3T}.", - "{1} pone una carga explosiva, matando a {2T}, {3T}, {4T}.", - "{1} pone una carga explosiva, matando a {2T}, {3T}, {4T} y {5T}.", - "{1} mata a {2T} mientras que intentaba correr.", - "{1T} y {2T} amenaza con un suicidio doble. Falla y mueren.", - "{1T}, {2T}, {3T} y {4T} forman un pacto de suicidio, matándose a sí mismos.", - "{1} mata a {2T} con un hacha.", - "{1} y {2} luchan contra {3T} y {4T}. {1} y {2} sobreviven.", - "{1T} y {2T} luchan contra {3} y {4}. {3} y {4} sobreviven.", - "{1T} ataca a {2}, pero {3} le protege, matando a {1T}.", - "{1} rebana severamente {2T} con una espada.", - "{1} ahoga a {2T} con una cuerda.", - "{1} mata a {2T} por sus suministros.", - "{1} dispara una flecha a {2}, pero falla y mata a {3T}.", - "{1} dispara un dardo venenoso en el cuello de {2T}, matándolo lentamente.", - "{1} apuñala a {2T} con una rama de árbol.", - "{1} apuñala a {2T} en la espalda con un tridente.", - "{1}, {2T} y {3T} entran en una pelea. {1} mata triunfantemente a ambos.", - "{1T}, {2} y {3T} entran en una pelea. {2} mata triunfantemente a ambos.", - "{1T}, {2T} y {3} entran en una pelea. {3} mata triunfantemente a ambos.", - "{1} encuentra a {2T} escondido en la cornucopia y lo mata.", - "{1T} encuentra a {2} oculto en la cornucopia, pero {2} lo mata.", - "{1} mata a {2T} con una hoz.", - "{1} y {2T} luchan por una bolsa. {1} estrangula a {2T} con las correas y huye.", - "{1T} y {2} luchan por una bolsa. {2} estrangula a {1T} con las correas y huye.", - "{1} apuñala repetidamente con kukris a {2T} hasta morir.", - "{1T} se resbala mientras que corría desde la cornucopia, y es matado por {2}.", - "{1} se resbala mientras que corría de la cornucopia, {2} lo recoge y corren fuera juntos.", - "{1} apunta a una flecha en la cabeza de {2} y dispara, {3T} salta en el camino y sacrifica su vida para salvarle." - ], - "hgDay": [ - "{1} se va de caza.", - "{1} se lesiona a sí mismo.", - "{1} explora la arena.", - "{1} le asusta a {2}.", - "{1} desvía la atención de {2} y huye.", - "{1} acecha a {2}.", - "{1} pesca.", - "{1} se camufla en el arbusto.", - "{1} roba a {2} mientras no estaba mirando.", - "{1} hace una lanza de madera.", - "{1} descubre una cueva.", - "{1} ataca a {2}, pero consigue escapar.", - "{1} persigue a {2}.", - "{1} huye de {2}.", - "{1} recolecta frutos de un árbol.", - "{1} recibe un hacha de un patrocinador desconocido.", - "{1} recibe agua limpia de un patrocinador desconocido.", - "{1} recibe suministros médicos de un patrocinador desconocido.", - "{1} recibe comida fresca de un patrocinador desconocido.", - "{1} busca una fuente de agua.", - "{1} derrota a {2} en una pelea, pero le perdona la vida.", - "{1} y {2} trabajan juntos durante el día.", - "{1} pide a {2} que lo mate. Se niega, dejando a {1} vivo.", - "{1} intenta dormir todo el día.", - "{1}, {2}, {3} y {4} asaltan el campamento de {5} mientras que cazaba.", - "{1} construye una chabola.", - "{1} escucha la conversación de {2} y {3} a distancia.", - "{1} practica su tiro con arco.", - "{1} piensa de su casa.", - "{1} es pinchado por espinas al recoger bayas.", - "{1} intenta alancear peces con un tridente.", - "{1} busca leña.", - "{1} y {2} se dividen para buscar recursos.", - "{1} coge flores.", - "{1} tiende a las heridas de {2}.", - "{1} ve humo en la distancia, pero decide no investigar.", - "{1} se tuece el tobillo mientras huía de {2}.", - "{1} hace un tirachinas.", - "{1} viaja a un terreno más alto.", - "{1} descubre un río.", - "{1} va de caza a por los otros tributos.", - "{1} y {2} van de caza a por los otros tributos.", - "{1}, {2} y {3} van de caza a por los otros tributos.", - "{1}, {2}, {3} y {4} van de caza a por los otros tributos.", - "{1}, {2}, {3}, {4} y {5} van de caza a por los otros tributos.", - "{1} recibe un explosivo de un patrocinador desconocido.", - "{1} cuestiona su cordura.", - "{1} fuerza a {2} a comer un pantalón.", - "{1} fuerza a {2T} a comer un pantalón. {2T} se ahoga y muere.", - "{1} pilla a {2T} fuera de guardia y lo mata.", - "{1} tira un cuchillo a la cabeza de {2T}.", - "{1T} ruega a {2} para que lo mate. Hace el favor y mata a {1T}.", - "{1} y {2} trabajan juntos para ahogar a {3T}.", - "{1} ahoga a {2T} después de una pelea a puños.", - "{1} dispara una flecha a la cabeza de {2T}.", - "{1T} se desangra debido a lesiones no tratadas.", - "{1T} no puede manejar las circunstancias y comete suicidio.", - "{1} golpea la cabeza de {2T} contra una roca varias veces.", - "{1T} consume bayas tóxicas sin saberlo.", - "{1} rompe el cuello de {2T} de forma silenciosa.", - "{1} envenena la comida de {2T}, matándolo.", - "{1} decapita a {2T} con una espada.", - "{1T} muere de una infección.", - "{1} alancea a {2T} en el abdomen.", - "{1} prende fuego a {2T} con un molotov.", - "{1T} cae en un pozo y muere.", - "{1} apuñala a {2T} mientras que estaba de espaldas.", - "{1} hiere severamente a {2T}, pero lo saca de su miseria.", - "{1} hiere severamente a {2T} y le deja morir.", - "{1} rompe la cabeza de {2T} con un mazo.", - "{1T} intenta escalar un árbol, pero se cae y muere.", - "{1} empuja a {2T} de un acantilado durante una pelea de cuchillo.", - "{1} tira un cuchillo al torso de {2T}.", - "La trampa de {1} mata a {2T}.", - "{1} mata a {2T} mientras descansa.", - "{1T} es incapaz de convencer a {2} de que no le mate.", - "{1} convence a {2T} para que no le mate, solo para matar a {2T} en su lugar.", - "{1T} cae en un lago congelado y se ahoga.", - "{1}, {2} y {3T} empiezan a luchar, pero {2} huye tan pronto como {1} mata a {3T}.", - "{1} mata a {2T} con su propio arma.", - "{1} vence a {2T}, matándoles.", - "{1} detona una carga explosiva, matando a {2T}.", - "{1} pone una carga explosiva, matando a {2T} y {3T}.", - "{1} pone una carga explosiva, matando a {2T}, {3T} y {4T}.", - "{1} pone una carga explosiva, matando a {2T}, {3T}, {4T} y {5T}.", - "{1} mata a {2T} mientras que intentaba correr.", - "{1T} y {2T} amenaza con un suicidio doble. Falla y mueren.", - "{1T}, {2T}, {3T} y {4T} forman un pacto de suicidio, matándose a sí mismos.", - "{1T} muere por hipotermia.", - "{1T} muere de hambre.", - "{1T} muere de sed.", - "{1} mata a {2T} con un hacha.", - "{1} y {2} luchan contra {3T} y {4T}. {1} y {2} sobreviven.", - "{1T} y {2T} luchan contra {3} y {4}. {3} y {4} sobreviven.", - "{1T} muere intentando escapar de la arena.", - "{1T} muere de disentería.", - "{1T} detona accidentalmente una mina de tierra mientras intenta armarla.", - "{1T} ataca a {2}, pero {3} le protege, matando a {1T}.", - "{1} embosca a {2T} y lo mata.", - "{1T} pisa accidentalmente en una mina terrestre.", - "{1} rebana severamente {2T} con una espada.", - "{1} ahoga a {2T} con una cuerda.", - "{1} mata a {2T} por sus suministros.", - "{1} dispara una flecha a {2}, pero falla y mata a {3T}.", - "{1} dispara un dardo venenoso en el cuello de {2T}, matándolo lentamente.", - "{1}, {2} y {3} emboscan y matan con éxito a {4T}, {5T} y {6T}.", - "{1T}, {2T} y {3T} emboscan sin éxito a {4}, {5} y {6}, quienes los matan en su lugar.", - "{1} apuñala a {2T} con una rama de árbol.", - "{1} fuerza a {2} a matar o a {3T} o a {4}. Decide matar a {3T}.", - "{1} fuerza a {2} a matar o a {3} o a {4T}. Decide matar a {4T}.", - "{1} fuerza a {2T} a matar a {3} o a {4}. Se niega a matar, así que {1} lo mata en su lugar.", - "{1T} envenena la bebida de {2}, pero la equivoca por su propia y muere.", - "{1} envenena la bebida de {2T}. La bebe y mueren.", - "{1} apuñala a {2T} en la espalda con un tridente.", - "{1T} intenta escalar un árbol, pero se cae en {2T} y ambos mueren.", - "{1}, {2T} y {3T} entran en una pelea. {1} los mata triunfantemente a ambos.", - "{1T}, {2} y {3T} entran en una pelea. {2} los mata triunfantemente a ambos.", - "{1T}, {2T} y {3} entran en una pelea. {3} los mata triunfantemente a ambos.", - "{1} mata a {2T} con una hoz.", - "{1}, {2}, {3}, {4} y {5} buscan y matan a {6T}.", - "{1}, {2}, {3} y {4} buscan y matan a {5T}.", - "{1}, {2} y {3} buscan y matan a {4T}.", - "{1} y {2} buscan y matan a {3T}.", - "{1} busca y mata a {2T}.", - "{1} apuñala repetidamente con una kukris a {2T} hasta matarlo.", - "{1} garabatea en la tierra.", - "{1} persigue a una mariposa.", - "{1T} cae de un acantilado y se ve empalado por un palo.", - "{1} se choca con {2}, deciden crear un equipo.", - "{1} ve {2} a través de los árboles y planea matarle.", - "{1} se acecha detrás de {2T} y rompe su cuello.", - "{1T} desafía a {2} a una pelea, y rápidamente muere.", - "{1} asesina a su compañero, {2T}, para tener más suministros para sí mismo." - ], - "hgNight": [ - "{1} inicia un fuego.", - "{1} instala un campamento para la noche.", - "{1} se ha perdido.", - "{1} sube un árbol para descansar.", - "{1} se va a dormir.", - "{1} y {2} se cuentan historias acerca de sí mismos.", - "{1}, {2}, {3} y {4} se duermen en turnos.", - "{1}, {2} y {3} se duermen en turnos.", - "{1} y {2} se duermen en turnos.", - "{1} tiende a sus heridas.", - "{1} ve un fuego, pero permanece oculto.", - "{1} grita en busca de ayuda.", - "{1} permanece despierto toda la noche.", - "{1} pierde el conocimiento por agotamiento.", - "{1} cocina su comida antes de apagar su fuego.", - "{1} y {2} se encuentran entre sí y deciden hacer tregua por la noche.", - "{1} aleja a {2}, {3} y {4} de su fuego.", - "{1}, {2} y {3} discuten los juegos y lo que podría pasar por la mañana.", - "{1} llora hasta dormir.", - "{1} intenta tratar su infección.", - "{1} y {2} hablan sobre los tributos aún vivos.", - "{1} se despierta por una pesadilla.", - "{1} y {2} se abrazan para mantener el calor.", - "{1} piensa en ganar.", - "{1}, {2}, {3} y {4} se cuentan entre sí historias de fantasmas para mejorar el estado de ánimo.", - "{1} mira al cielo nocturno.", - "{1} derrota a {2} en una pelea, pero le perdona la vida.", - "{1} pide a {2} que lo mate. Se niega, dejando a {1} vivo.", - "{1} destruye los suministros de {2} mientras duerme.", - "{1}, {2}, {3}, {4} y {5} duermen en turnos.", - "{1} permite a {2} entrar en su refugio.", - "{1} recibe un hacha de un patrocinador desconocido.", - "{1} recibe agua limpia de un patrocinador desconocido.", - "{1} recibe suministros médicos de un patrocinador desconocido.", - "{1} recibe comida fresca de un patrocinador desconocido.", - "{1} intenta cantar hasta dormir.", - "{1} intenta iniciar un fuego, pero no tiene éxito.", - "{1} piensa de su casa.", - "{1} tiende a las heridas de {2}.", - "{1} tatarea silenciosamente.", - "{1}, {2} y {3} cantan canciones alegremente juntos.", - "{1} no puede iniciar un fuego y duerme sin calor.", - "{1} y {2} sostienen las manos.", - "{1} convence a {2} para que se pegue con ellos.", - "{1} recibe un explosivo de un patrocinador desconocido.", - "{1} cuestiona su cordura.", - "{1} fuerza a {2} a comer un pantalón.", - "{1} fuerza a {2T} a comer un pantalón. {2T} se ahoga y muere.", - "{1} pilla a {2T} fuera de guardia y lo mata.", - "{1} lanza un cuchillo a la cabeza de {2T}.", - "{1T} ruega a {2} para que lo mate. Hace el favor y mata a {1T}.", - "{1} y {2} trabajan juntos para ahogar a {3T}.", - "{1} ahoga a {2T} después de una pelea a puños.", - "{1} dispara una flecha a la cabeza de {2T}.", - "{1T} se desangra debido a lesiones no tratadas.", - "{1T} no puede manejar las circunstancias y comete suicidio.", - "{1} golpea la cabeza de {2T} contra una roca varias veces.", - "{1T} consume bayas tóxicas sin saberlo.", - "{1} rompe el cuello de {2T} de forma silenciosa.", - "{1} envenena la comida de {2T}, matándolo.", - "{1} decapita a {2T} con una espada.", - "{1T} muere de una infección.", - "{1} alancea a {2T} en el abdomen.", - "{1} prende fuego a {2T} con un molotov.", - "{1T} cae en un pozo y muere.", - "{1} apuñala a {2T} mientras que estaba de espaldas.", - "{1} hiere severamente a {2T}, pero lo saca de su miseria.", - "{1} hiere severamente a {2T} y le deja morir.", - "{1} rompe la cabeza de {2T} con un mazo.", - "{1T} intenta escalar un árbol, pero se cae y muere.", - "{1} empuja a {2T} de un acantilado durante una pelea de cuchillo.", - "{1} lanza un cuchillo al torso de {2T}.", - "La trampa de {1} mata a {2T}.", - "{1} mata a {2T} mientras duerme.", - "{1T} es incapaz de convencer a {2} de que no le mate.", - "{1} convence a {2T} para que no le mate, solo para matar a {2T} en su lugar.", - "{1T} cae en un lago congelado y se ahoga.", - "{1}, {2} y {3T} empiezan a luchar, pero {2} huye tan pronto como {1} mata a {3T}.", - "{1} mata a {2T} con su propio arma.", - "{1} sobrepasa a {2T}, matándoles.", - "{1} detona una carga explosiva, matando a {2T}.", - "{1} pone una carga explosiva, matando a {2T} y {3T}.", - "{1} pone una carga explosiva, matando a {2T}, {3T} y {4T}.", - "{1} pone una carga explosiva, matando a {2T}, {3T}, {4T} y {5T}.", - "{1} mata a {2T} mientras que intentaba correr.", - "{1T} y {2T} amenaza con un suicidio doble. Falla y mueren.", - "{1T}, {2T}, {3T} y {4T} forman un pacto de suicidio, matándose a sí mismos.", - "{1T} muere por hipotermia.", - "{1T} muere de hambre.", - "{1T} muere de sed.", - "{1} mata a {2T} con un hacha.", - "{1} y {2} luchan contra {3T} y {4T}. {1} y {2} sobreviven.", - "{1T} y {2T} luchan contra {3} y {4}. {3} y {4} sobreviven.", - "{1T} muere intentando escapar de la arena.", - "{1T} muere de disentería.", - "{1T} detona accidentalmente una mina de tierra mientras intenta armarla.", - "{1T} ataca a {2}, pero {3} le protege, matando a {1T}.", - "{1} embosca a {2T} y lo mata.", - "{1T} pisa accidentalmente en una mina terrestre.", - "{1} rebana severamente a {2T} con una espada.", - "{1} ahoga a {2T} con una cuerda.", - "{1} mata a {2T} por sus suministros.", - "{1} dispara una flecha a {2}, pero falla y mata a {3T}.", - "{1} dispara un dardo venenoso en el cuello de {2T}, matándolo lentamente.", - "{1}, {2} y {3} emboscan y matan con éxito a {4T}, {5T} y {6T}.", - "{1T}, {2T} y {3T} emboscan sin éxito a {4}, {5} y {6}, quienes los matan en su lugar.", - "{1} apuñala a {2T} con una rama de árbol.", - "{1} fuerza a {2} a matar o a {3T} o a {4}. Decide matar a {3T}.", - "{1} fuerza a {2} a matar o a {3} o a {4T}. Decide matar a {4T}.", - "{1} fuerza a {2T} a matar o a {3} o a {4}. Se niega a matar, así que {1} lo mata en su lugar.", - "{1T} envenena la bebida de {2}, pero la equivoca por su propia y muere.", - "{1} envenena la bebida de {2T}. La bebe y muere.", - "{1} apuñala a {2T} en la espalda con un tridente.", - "{1T} intenta escalar un árbol, pero se cae en {2T} y ambos mueren.", - "{1}, {2T} y {3T} entran en una pelea. {1} los mata triunfantemente a ambos.", - "{1T}, {2} y {3T} entran en una pelea. {2} los mata triunfantemente a ambos.", - "{1T}, {2T} y {3} entran en una pelea. {3} los mata triunfantemente a ambos.", - "{1} mata a {2T} con una hoz.", - "{1}, {2}, {3}, {4} y {5} buscan y matan a {6T}.", - "{1}, {2}, {3} y {4} buscan y matan a {5T}.", - "{1}, {2} y {3} buscan y matan a {4T}.", - "{1} y {2} buscan y matan a {3T}.", - "{1} busca y mata a {2T}.", - "{1} apuñala repetidamente con kukris a {2T} hasta morir.", - "{1} escribe en su diario.", - "{1} mira a {2} sentados en su hoguera, y considera matarle" - ], - "hungerGamesDescription": "¡Juega a los Juegos de Hambre con tus amigos!", - "hungerGamesExtended": { - "usages": [ - "Usuario1 Usuario2 Usuario3...", - "--autofill" - ], - "extendedHelp": "Basta de discusión, ¡que comiencen los juegos del hambre!", - "examples": [ - "WolfStar, Katniss, Peeta, Clove, Cato, Johanna, Brutus, Blight" - ], - "reminder": "Puede especificar `--autoskip` para omitir automáticamente después de algún tiempo." - }, - "hungerGamesResultDeaths_one": "**{{count}} disparo de cañón se puede escuchar en la distancia.**", - "hungerGamesResultDeaths_other": "**{{count}} disparos de cañón se pueden escuchar en la distancia.**", - "hungerGamesResultHeaderBloodbath": "Baño de Sangre", - "hungerGamesResultHeaderMoon": "Noche {{game.turn}}", - "hungerGamesResultHeaderSun": "Día {{game.turn}}", - "hungerGamesResultProceed": "¿Continuar?", - "hungerGamesStop": "¡El juego terminó por elección! ¡Nos vemos más tarde!", - "hungerGamesWinner": "¡Y el ganador es... {{winner}}!", - "ticTacToeDescription": "Juega al Tres en Raya con alguien.", - "ticTacToeDraw": "¡Esta partida concluyó en un **empate**!\n{{board}}", - "ticTacToeExtended": { - "usages": [ - "Usuario" - ], - "extendedHelp": "Tres en Raya es un juego de papel y lápiz para dos jugadores, X y O, que toman turnos marcando los espacios en una cuadrícula de 3×3.\nEl jugador que consigue colocar tres de sus marcas en una fila horizontal, vertical, o diagonal gana el juego.", - "examples": [ - "WolfStar" - ] - }, - "ticTacToePrompt": "Estimado {{challengee}}. Has sido desafiado por {{challenger}} en una partida de Tres en Raya. ¡Haz clic en la reacción to para aceptar!", - "ticTacToeTurn": "({{icon}}) ¡Turno para {{player}}!\n{{board}}", - "ticTacToeWinner": "¡El ganador es... {{winner}}!\n{{board}}", - "triviaActiveGame": "Ya se está jugando una partida de trivia en este canal", - "triviaDescription": "Juega una partida de Trivia.", - "triviaEmbedTitles": { - "difficulty": "Dificultad", - "trivia": "Trivia" - }, - "triviaExtended": { - "usages": [ - "", - "Categoría", - "Categoría multiple/boolean/truefalse", - "multiple easy/medium/hard", - "hard 2m" - ], - "extendedHelp": "Responda a preguntas de trivia aquí, ¡con categorías que van desde los libros hasta la mitología! (alimentado por OpenTDB)\n\n**Categorías**: {{TRIVIA_CATEGORIES}}", - "explainedUsage": [ - [ - "Categoría", - "Las preguntas de la categoría se harán a continuación." - ], - [ - "multiple/boolean/truefalse", - "Si desea una opción múltiple o una pregunta verdadera/falsa." - ], - [ - "easy/medium/hard", - "El nivel de dificultad de las preguntas formuladas." - ], - [ - "Duración", - "La cantidad de tiempo que obtienes para responder. El mínimo es de 1 segundo y el máximo es de 1 minuto" - ] - ], - "examples": [ - "history", - "books multiple easy", - "videogames 45s" - ] - }, - "triviaIncorrect": "Lo siento, pero **{{attempt}}** no es la respuesta correcta. ¡Buena suerte la próxima vez!", - "triviaInvalidCategory": "Categoría no válida: Por favor usa `WolfStar, help trivia` para leer la lista de categorías.", - "triviaNoAnswer": "¡Parece que nadie lo ha conseguido! La respuesta correcta era **{{correctAnswer}}**.", - "triviaWinner": "¡Tenemos un ganador! ¡{{winner}} tuvo una respuesta correcta con **{{correctAnswer}}**!" -} \ No newline at end of file diff --git a/src/languages/es-ES/commands/general.json b/src/languages/es-ES/commands/general.json deleted file mode 100644 index 3ac130146..000000000 --- a/src/languages/es-ES/commands/general.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "helpAllFlag": "Mostrando una categoría por página. ¿Tiene problemas con el incrustado? Ejecute `{{prefix}}help --all` para obtener una lista completa en mensajes directos.", - "helpCommandCount_one": "{{count}} comando", - "helpCommandCount_other": "{{count}} comandos", - "helpData": { - "footer": "Descripción de ayuda para {{footerName}}", - "title": "{{titleDescription}}" - }, - "helpDescription": "Muestra todos los comandos o la descripción de uno.", - "helpExtended": { - "usages": [ - "--cat/--categories", - "--all", - "NombreDeCategoría", - "Página", - "NombreDeComando" - ], - "extendedHelp": "El comando de ayuda muestra una lista paginada de todos los comandos por sus categorías, o la información extendida de un comando si se especifica.\n\nSi utiliza `--categories` o `--cat`, puede obtener la lista de todas las categorías y la cantidad de comandos en cada una de ellas.", - "reminder": "El comando de ayuda **sólo** muestra los comandos que puedes utilizar. Para la lista completa, por favor visita .", - "examples": [ - "--cat", - "--all", - "Moderación", - "12", - "help" - ] - }, - "helpDm": "📥 | La lista de comandos a los que tienes acceso ha sido enviada a tus mensajes directos.", - "helpNodm": "{{REDCROSS}} | Tienes los mensajes directos deshabilitados, por lo que no pude enviarte la lista de comandos.", - "v7Description": "", - "v7Extended": { - "extendedHelp": "" - }, - "v7Message": "", - "v7NayreMessage": "" -} \ No newline at end of file diff --git a/src/languages/es-ES/commands/info.json b/src/languages/es-ES/commands/info.json deleted file mode 100644 index b184beadf..000000000 --- a/src/languages/es-ES/commands/info.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "info", - "description": "Provee la información sobre mí junto a mi enlace de invitación y el del servidor de soporte", - "embedDescription": "[WolfStar](https://wolfstar.rocks) {{VERSION}} es un bot diseñado para ayudarte a moderar tu servidor. Uso [Sapphire Framework](https://sapphirejs.dev) con la [librería Discord.js](https://discord.js.org).\n- [Política de privacidad](https://wolfstar.rocks/privacy) | [Términos de servicio](https://github.com/wolfstar-project/wolfstar/blob/main/.github/TERMS_OF_SERVICE.md).", - "embedFieldApplicationTitle": "Estadísticas", - "embedFieldApplicationValue": "- **Usuarios**: {{users, number}}\n- **Servidores**: {{guilds, number}}\n- **Canales**: {{channels, number}}\n- **Discord.js**: {{versionDiscord}}\n- **Sapphire**: {{versionSapphire}}\n- **Node.js**: {{versionNode}}", - "embedFieldUptimeTitle": "Tiempo de Funcionamiento", - "embedFieldUptimeValue": "- **Servidor**: {{host}}\n- **Cliente**: {{client}}", - "embedFieldServerUsageTitle": "Uso del Servidor", - "embedFieldServerUsageValue": "- **Uso de CPU**: {{cpu}}\n- **Memoria**: {{heapUsed}}MB (Total: {{heapTotal}}MB)", - "buttonInvite": "¡Añádeme a tu servidor!", - "buttonSupport": "Servidor de soporte", - "buttonGitHub": "Repositorio de GitHub", - "buttonDonate": "Donar" -} \ No newline at end of file diff --git a/src/languages/es-ES/commands/management.json b/src/languages/es-ES/commands/management.json deleted file mode 100644 index 1cf7f148d..000000000 --- a/src/languages/es-ES/commands/management.json +++ /dev/null @@ -1,445 +0,0 @@ -{ - "commandHandlerAborted": "Cancelado", - "permissionNodesHigher": "{{REDCROSS}} No puedes modificar ni previsualizar los nodos de permiso para este objetivo.", - "permissionNodesCannotAllowEveryone": "{{REDCROSS}} No puedes habilitar comandos para el rol `@everyone`.", - "permissionNodesInvalidType": "{{REDCROSS}} Tipo inválido, se esperaba ya sea de `allow` o `deny`.", - "permissionNodesAdd": "{{GREENTICK}} Se ha añadido correctamente el comando al nodo de permisos.", - "permissionNodesNodeNotExists": "{{REDCROSS}} El nodo de permiso seleccionado no existe.", - "permissionNodesCommandNotExists": "{{REDCROSS}} El comando seleccionado no existe en el nodo de permiso.", - "permissionNodesRemove": "{{GREENTICK}} Se ha eliminado correctamente el comando del nodo de permisos.", - "permissionNodesReset": "{{GREENTICK}} Se han eliminado correctamente todos los comandos del nodo de permisos.", - "permissionNodesShowName": "Permisos para: __{{name}}__", - "permissionNodesShowAllow": "**Permitidos**: {{allow}}", - "permissionNodesShowDeny": "**Desactivado**: {{deny}}", - "guildInfoTitles": { - "CHANNELS": "", - "MEMBERS": "", - "OTHER": "" - }, - "guildInfoChannels": "", - "guildInfoChannelsAfkChannelText": "", - "guildInfoMembers": "", - "guildInfoOther": "", - "guildInfoBanner": "", - "guildInfoIcon": "", - "guildInfoSplash": "", - "guildInfoDiscoverySplash": "", - "roleInfoTitles": { - "PERMISSIONS": "" - }, - "roleInfoData": "", - "roleInfoAll": "", - "roleInfoNoPermissions": "", - "manageCommandAutoDeleteShowEmpty": "", - "manageCommandAutoDeleteShow": "", - "manageCommandAutoDeleteAdd": "", - "manageCommandAutoDeleteRemove": "", - "manageCommandAutoDeleteRemoveNotset": "", - "manageCommandAutoDeleteReset": "", - "manageCommandChannelShow": "", - "manageCommandChannelShowEmpty": "", - "manageCommandChannelAddAlreadyset": "", - "manageCommandChannelAdd": "", - "manageCommandChannelRemoveNotset": "", - "manageCommandChannelRemove": "", - "manageCommandChannelResetEmpty": "", - "manageCommandChannelReset": "", - "manageReactionRolesShowEmpty": "", - "manageReactionRolesAddChannel": "", - "manageReactionRolesAddPrompt": "", - "manageReactionRolesAddMissing": "", - "manageReactionRolesAdd": "", - "manageReactionRolesRemoveNotExists": "", - "manageReactionRolesRemove": "", - "manageReactionRolesResetEmpty": "", - "manageReactionRolesReset": "", - "configurationEquals": "", - "setIgnoreChannelsSet": "", - "setIgnoreChannelsRemoved": "", - "setImageLogsSet": "", - "setMemberAddLogsSet": "", - "setMemberRemoveLogsSet": "", - "setMessageUpdateLogsSet": "", - "setMessageDeleteLogsSet": "", - "setModLogsSet": "", - "setPrefixSet": "", - "stickyRolesNotExists": "", - "stickyRolesReset": "", - "stickyRolesRemove": "", - "stickyRolesAdd": "", - "stickyRolesShowEmpty": "", - "stickyRolesShowSingle": "", - "createMuteDescription": "", - "createMuteExtended": { - "extendedHelp": "" - }, - "permissionNodesDescription": "Configurar los nodos de permiso para este servidor.", - "permissionNodesExtended": { - "usages": [ - "add Rol/Miembro allow/deny Comando", - "remove Role/Member allow/deny Command", - "reset Rol/Miembro", - "show Rol/Miembro", - "show", - "Rol/Miembro" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "managecommandautodeleteDescription": "", - "managecommandautodeleteExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageCommandChannelDescription": "", - "manageCommandChannelExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageReactionRolesDescription": "", - "manageReactionRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "rolesAdded": "", - "rolesAuditlog": "", - "rolesListEmpty": "", - "rolesListTitle": "", - "rolesNotManageable": "", - "rolesNotPublic": "", - "rolesRemoved": "", - "setIgnoreChannelsDescription": "", - "setIgnoreChannelsExtended": { - "usages": [ - "here/CanalDeTexto" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "canal", - "" - ] - ], - "reminder": "", - "examples": [ - "#general", - "" - ] - }, - "setImageLogsDescription": "", - "setImageLogsExtended": { - "usages": [ - "here/CanalDeTexto" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "#registro-de-imagenes", - "here" - ] - }, - "setMemberAddLogsDescription": "", - "setMemberAddLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMemberRemoveLogsDescription": "", - "setMemberRemoveLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMessageUpdateLogsDescription": "", - "setMessageUpdateLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setMessageDeleteLogsDescription": "", - "setMessageDeleteLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setmodlogsDescription": "", - "setmodlogsExtended": { - "usages": [ - "here/CanalDeTexto" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setprefixDescription": "", - "setprefixExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "guildInfoDescription": "Revise la información del servidor.", - "guildInfoExtended": { - "extendedHelp": "El comando serverinfo muestra información para el servidor en el que el mensaje ha sido enviado.\nMuestra la cantidad de canales, con el recuento para cada categoría, la cantidad de miembros (dada desde la API), el propietario con su id de usuario, la cantidad de roles, región, fecha de creación, nivel de verificación. entre otros." - }, - "roleInfoDescription": "Revise la información de un rol.", - "roleInfoExtended": { - "usages": [ - "Rol", - "" - ], - "extendedHelp": "El comando roleinfo muestra información para un rol, como su id, nombre, color, si está elevado (se muestre por separado), su posición de jerarquía de rol, si mencionable, cuántos miembros tienen dicho el rol y sus permisos.\nEnvía un mensaje incrustado con el color del rol.", - "explainedUsage": [ - [ - "Rol", - "Nombre del rol, mención o id." - ] - ], - "examples": [ - "Administrador", - "Moderador", - "" - ] - }, - "stickyRolesDescription": "", - "stickyRolesExtended": { - "usages": [ - "add Usuario Rol", - "remove Usuario Rol", - "reset Usuario", - "show Usuario", - "Usuario" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "Acción", - "" - ], - [ - "Usuario", - "El usuario objetivo para todas las acciones." - ], - [ - "Rol", - "El rol a añadir o eliminar." - ] - ], - "examples": [ - "add WolfStar Diosa", - "show WolfStar", - "remove WolfStar Diosa", - "reset WolfStar" - ], - "reminder": "" - }, - "rolesDescription": "", - "rolesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/es-ES/commands/misc.json b/src/languages/es-ES/commands/misc.json deleted file mode 100644 index 32f64d584..000000000 --- a/src/languages/es-ES/commands/misc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "snipeEmpty": "", - "snipeTitle": "", - "snipeDescription": "", - "snipeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/es-ES/commands/moderation.json b/src/languages/es-ES/commands/moderation.json deleted file mode 100644 index 815d1c788..000000000 --- a/src/languages/es-ES/commands/moderation.json +++ /dev/null @@ -1,889 +0,0 @@ -{ - "permissions": "", - "permissionsAll": "", - "slowmodeSet": "", - "slowmodeReset": "", - "banNotBannable": "", - "dehoistStarting": "", - "dehoistProgress": "", - "dehoistEmbed": { - "title": "", - "descriptionNoone": "", - "descriptionWithError": "", - "descriptionWithMultipleErrors": "", - "description": "", - "descriptionMultipleMembers": "", - "fieldErrorTitle": "" - }, - "kickNotKickable": "", - "lockdownLock": "", - "lockdownLocking": "", - "lockdownLocked": "", - "lockdownUnlocked": "", - "lockdownOpen": "", - "muteMuted": "", - "muteUserNotMuted": "", - "restrictLowlevel": "", - "pruneAlert_one": "", - "pruneAlert_other": "", - "pruneInvalidPosition": "", - "pruneNoDeletes": "", - "pruneLogHeader": "", - "toggleModerationDmToggledEnabled": "", - "toggleModerationDmToggledDisabled": "", - "moderationOutput_one": "", - "moderationOutput_other": "", - "moderationOutputWithReason_one": "", - "moderationOutputWithReason_other": "", - "moderationFailed_one": "", - "moderationFailed_other": "", - "moderationDmFooter": "", - "moderationDmDescription": "", - "moderationDmDescriptionWithReason": "", - "moderationDmDescriptionWithDuration": "", - "moderationDmDescriptionWithReasonWithDuration": "", - "slowmodeDescription": "", - "slowmodeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "banDescription": "", - "banExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "dehoistDescription": "", - "dehoistExtended": { - "extendedHelp": "", - "reminder": "" - }, - "kickDescription": "", - "kickExtended": { - "usages": [ - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "lockdownDescription": "", - "lockdownExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "muteDescription": "", - "muteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "setNicknameDescription": "", - "setNicknameExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ], - "reminder": "" - }, - "addRoleDescription": "", - "addRoleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "removeroleDescription": "", - "removeroleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "pruneDescription": "", - "pruneExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "permissionsDescription": "", - "permissionsExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ], - "extendedHelp": "" - }, - "restrictAttachmentDescription": "", - "restrictAttachmentExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictEmbedDescription": "", - "restrictEmbedExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictEmojiDescription": "", - "restrictEmojiExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictReactionDescription": "", - "restrictReactionExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictVoiceDescription": "", - "restrictVoiceExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "softBanDescription": "", - "softBanExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "timeoutApplyDescription": "", - "timeoutApplyExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutUndoDescription": "", - "timeoutUndoExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutNotModeratable": "", - "toggleModerationDmDescription": "", - "toggleModerationDmExtended": { - "extendedHelp": "" - }, - "unbanDescription": "", - "unbanExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unmuteDescription": "", - "unmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unrestrictAttachmentDescription": "", - "unrestrictAttachmentExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmbedDescription": "", - "unrestrictEmbedExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmojiDescription": "", - "unrestrictEmojiExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictReactionDescription": "", - "unrestrictReactionExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictVoiceDescription": "", - "unrestrictVoiceExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unwarnDescription": "", - "unwarnExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vmuteDescription": "", - "vmuteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "voiceKickDescription": "", - "voiceKickExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vunmuteDescription": "", - "vunmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "warnDescription": "", - "warnExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/es-ES/commands/shared.json b/src/languages/es-ES/commands/shared.json deleted file mode 100644 index ddbb28e7f..000000000 --- a/src/languages/es-ES/commands/shared.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "deprecatedMessage": "", - "slashOnlyDetailedDescription": { - "extendedHelp": "" - }, - "slashOnlyErrorMessage": "" -} \ No newline at end of file diff --git a/src/languages/es-ES/commands/system.json b/src/languages/es-ES/commands/system.json deleted file mode 100644 index e9cfdeec4..000000000 --- a/src/languages/es-ES/commands/system.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "evalDescription": "", - "evalExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "evalTimeout": "", - "evalError": "", - "dmNotSent": "", - "dmSent": "", - "reboot": "", - "rebootDescription": "", - "rebootExtended": { - "extendedHelp": "", - "reminder": "" - } -} \ No newline at end of file diff --git a/src/languages/es-ES/commands/tools.json b/src/languages/es-ES/commands/tools.json deleted file mode 100644 index 01bd03e25..000000000 --- a/src/languages/es-ES/commands/tools.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "avatarDescription": "", - "avatarExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "" - }, - "avatarNone": "", - "voteDescription": "", - "voteExtended": { - "usages": [ - "" - ], - "examples": [ - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "voteContentNeeded": "", - "voteReactionBlocked": "", - "whoisExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "whoisMemberRoleListAndMore": "" -} \ No newline at end of file diff --git a/src/languages/es-ES/commands/twitch.json b/src/languages/es-ES/commands/twitch.json deleted file mode 100644 index 2f12e1b08..000000000 --- a/src/languages/es-ES/commands/twitch.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "twitchSubscriptionStreamerNotFound": "", - "twitchSubscriptionStatusValues": [ - "", - "" - ], - "twitchSubscriptionInvalidStatus": "", - "twitchSubscriptionAddDuplicated": "", - "twitchSubscriptionAddSuccessOffline": "", - "twitchSubscriptionAddSuccessLive": "", - "twitchSubscriptionAddMessageForOfflineRequired": "", - "twitchSubscriptionRemoveOrResetEmpty": "", - "twitchSubscriptionRemoveStreamerNotSubscribed": "", - "twitchSubscriptionRemoveNotToProvidedChannel": "", - "twitchSubscriptionRemoveStreamerStatusNotMatch": "", - "twitchSubscriptionRemoveSuccessOffline": "", - "twitchSubscriptionRemoveSuccessLive": "", - "twitchSubscriptionResetSuccess_one": "", - "twitchSubscriptionResetSuccess_other": "", - "twitchSubscriptionShowStreamerNotSubscribed": "", - "twitchSubscriptionShowStatus": { - "live": "", - "offline": "" - }, - "twitchSubscriptionShowUnknownUser": "", - "twitchSubscriptionDescription": "", - "twitchSubscriptionExtended": { - "usages": [ - "", - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/es-ES/commands/whois.json b/src/languages/es-ES/commands/whois.json deleted file mode 100644 index 2c9421e3d..000000000 --- a/src/languages/es-ES/commands/whois.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "whois", - "description": "Proporciona información sobre un usuario de Discord", - "contextMenuName": "Obtener Información", - "userName": "usuario", - "userDescription": "El usuario sobre el que obtener información", - "rolesTitle_one": "Rol [1]", - "rolesTitle_other": "Roles [{{count, number}}]", - "permissionsTitle": "Permisos Clave", - "permissionsAll": "Todos los permisos", - "embedDescription": "**Usuario Desde**: {{createdAt}}", - "embedMemberDescription": "**Miembro Desde**: {{joinedAt}}", - "buttonAvatar": "Avatar", - "buttonProfile": "Perfil" -} \ No newline at end of file diff --git a/src/languages/es-ES/constants.ts b/src/languages/es-ES/constants.ts deleted file mode 100644 index 7622b9156..000000000 --- a/src/languages/es-ES/constants.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Handler } from '#lib/i18n/structures/Handler'; -import { TimeTypes } from '@sapphire/time-utilities'; - -export class ExtendedHandler extends Handler { - public constructor() { - super({ - name: 'es-ES', - duration: { - [TimeTypes.Year]: { - 1: 'año', - DEFAULT: 'años' - }, - [TimeTypes.Month]: { - 1: 'mes', - DEFAULT: 'meses' - }, - [TimeTypes.Week]: { - 1: 'semana', - DEFAULT: 'semanas' - }, - [TimeTypes.Day]: { - 1: 'día', - DEFAULT: 'días' - }, - [TimeTypes.Hour]: { - 1: 'hora', - DEFAULT: 'horas' - }, - [TimeTypes.Minute]: { - 1: 'minuto', - DEFAULT: 'minutos' - }, - [TimeTypes.Second]: { - 1: 'segundo', - DEFAULT: 'segundos' - } - } - }); - } -} diff --git a/src/languages/es-ES/errors.json b/src/languages/es-ES/errors.json deleted file mode 100644 index 3f49a437b..000000000 --- a/src/languages/es-ES/errors.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "guildBansEmpty": "No hay baneos registrados en este servidor.", - "guildBansNotFound": "Lo he intentado y no he podido encontrar a este usuario de la lista de baneos. ¿Estás seguro de que este usuario está baneado?", - "guildMemberNotVoicechannel": "No puedo ejecutar esta acción en un miembro que no está conectado a un canal de voz.", - "guildWarnNotFound": "No pude obtener esa advertencia. O bien no existe, o bien no era un aviso, o bien ha sido apelada.", - "modlogTimed": "Este registro de moderación ya está temporizado. Expira en {{remaining, duration}}", - "unexpectedIssue": "¡Se ha producido un error inesperado! Abortando este comando de forma segura...", - "userNotInGuild": "Este usuario no está en este servidor." -} \ No newline at end of file diff --git a/src/languages/es-ES/events/errors.json b/src/languages/es-ES/events/errors.json deleted file mode 100644 index 344ef3398..000000000 --- a/src/languages/es-ES/events/errors.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "string": "{{REDCROSS}} Querido/a {{mention}}, {{message}}", - "unexpectedError": "{{REDCROSS}} He encontrado un error inesperado, ¡por favor informa de los pasos que has dado a mis desarrolladores!", - "unexpectedErrorWithContext": "$t(events/errors:unexpectedError)\nPuede agregar `{{report}}` al informe para que puedan ver qué error fue desencadenado." -} \ No newline at end of file diff --git a/src/languages/es-ES/events/guilds-logs.json b/src/languages/es-ES/events/guilds-logs.json deleted file mode 100644 index 7e3897c06..000000000 --- a/src/languages/es-ES/events/guilds-logs.json +++ /dev/null @@ -1,109 +0,0 @@ -{ - "channelCreate": "Canal Creado", - "channelCreateParent": "• **Categoría**: {{value}}", - "channelCreatePosition": "• **Posición**: `{{value, number}}`", - "channelCreatePermissionsTitle": "• **Permisos para {{value}}**", - "channelCreateNsfw": "• **Establecido como NSFW**", - "channelCreateTopic": "• **Tema**: `{{value}}`", - "channelCreateRateLimit": "• **Modo Pausado**: `{{value, duration}}`", - "channelCreateBitrate": "• **Tasa de Bits**: `{{value}}kbps`", - "channelCreateUserLimit": "• **Límite de Usuarios**: `{{value, number}}`", - "channelDelete": "Canal Eliminado", - "channelUpdate": "Canal Actualizado", - "channelUpdateBitrate": "• **Tasa de Bits**: `{{previous}}kbps` → `{{next}}kbps`", - "channelUpdateName": "• **Nombre**: `{{previous}}` → `{{next}}`", - "channelUpdateNsfw": "• **NSFW**: `{{previous}}` → `{{next}}`", - "channelUpdateParent": "• **Categoría**: {{previous}} → {{next}}", - "channelUpdateParentAdded": "• **Categoría**: No Establecido → {{value}}", - "channelUpdateParentRemoved": "• **Categoría**: {{value}} → No Establecido", - "channelUpdatePosition": "• **Posición**: `{{previous, number}}` → `{{next, number}}`", - "channelUpdateAddedPermissionsTitle": "• **Añadidos los Permisos para {{value}}**", - "channelUpdateDeletedPermissionsTitle": "• **Eliminados los Permisos para {{value}}**", - "channelUpdatePermissionsTitle": "• **Actualizados los Permisos para {{value}}**", - "channelUpdateRateLimit": "• **Modo Pausado**: `{{previous, duration}}` → `{{next, duration}}`", - "channelUpdateRateLimitAdded": "• **Modo Pausado**: No Establecido → `{{value, duration}}`", - "channelUpdateRateLimitRemoved": "• **Modo Pausado**: `{{value, duration}}` → No Establecido", - "channelUpdateTopic": "• **Tema**: `{{previous}}` → `{{next}}`", - "channelUpdateTopicAdded": "• **Tema**: No Establecido → `{{value}}`", - "channelUpdateTopicRemoved": "• **Tema**: `{{value}}` → No Establecido", - "channelUpdateType": "• **Tipo**: `{{previous}}` → `{{next}}`", - "channelUpdateUserLimit": "• **Límite de Usuarios**: `{{previous, number}}` → `{{next, number}}`", - "channelUpdateUserLimitAdded": "• **Límite de Usuarios**: No Establecido → `{{value, number}}`", - "channelUpdateUserLimitRemoved": "• **Límite de Usuarios**: `{{value, number}}` → No Establecido", - "emojiCreate": "Emoji Creado", - "emojiCreateAnimated": "• **Animado**", - "emojiCreateUnAvailable": "• **No Disponible**", - "emojiCreateManaged": "• **Gestionado**", - "emojiCreateRequiresColons": "• **Requiere Dos Puntos**", - "emojiDelete": "Emoji Eliminado", - "emojiUpdate": "Emoji Actualizado", - "emojiUpdateAnimated": "• **Animado**: `{{previous}}` → `{{next}}`", - "emojiUpdateAvailable": "• **Disponible**: `{{previous}}` → `{{next}}`", - "emojiUpdateManaged": "• **Gestionado**: `{{previous}}` → `{{next}}`", - "emojiUpdateName": "• **Nombre**: `{{previous}}` → `{{next}}`", - "emojiUpdateRequiresColons": "• **Requiere Dos Puntos**: `{{previous}}` → `{{next}}`", - "roleCreate": "Rol Creado", - "roleCreateColor": "• **Color**: `{{value}}`", - "roleCreateHoist": "• **Mostrado por Separado**", - "roleCreateMentionable": "• **Mencionable**", - "roleCreatePosition": "• **Posición**: `{{value, number}}`", - "roleDelete": "Rol Eliminado", - "roleUpdate": "Rol Actualizado", - "roleUpdateColor": "• **Color**: `{{previous}}` → `{{next}}`", - "roleUpdateHoist": "• **Mostrado por Separado**: `{{previous}}` → `{{next}}`", - "roleUpdateMentionable": "• **Mencionable**: `{{previous}}` → `{{next}}`", - "roleUpdateName": "• **Nombre**: `{{previous}}` → `{{next}}`", - "roleUpdatePosition": "• **Posición**: `{{previous, number}}` → `{{next, number}}`", - "serverUpdate": "Servidor Actualizado", - "serverUpdateAfkChannelAdded": "**Canal de Inactividad**: No Establecido → {{value}}", - "serverUpdateAfkChannelRemoved": "• **Canal de Inactividad**: {{value}} → No Establecido", - "serverUpdateAfkChannel": "• **Canal de Inactividad**: {{previous}} → {{next}}", - "serverUpdateAfkTimeout": "• **Límite de Tiempo de Inactividad**: `{{previous, duration}}` → `{{next, duration}}`", - "serverUpdateBannerAdded": "• **Banner**: No establecido → [Ahora]({{value}})", - "serverUpdateBannerRemoved": "• **Banner**: [Antes]({{value}}) → No Establecido", - "serverUpdateBanner": "• **Banner**: [Antes]({{previous}}) → [Ahora]({{next}})", - "serverUpdateDefaultMessageNotifications": "• **Notificaciones de Mensajes**: `{{previous, messageNotifications}}` → `{{next, messageNotifications}}`", - "serverUpdateDescriptionAdded": "• **Descripción**: No Establecido → `{{value}}`", - "serverUpdateDescriptionRemoved": "• **Descripción**: `{{value}}` → No Establecido", - "serverUpdateDescription": "• **Descripción**: `{{previous}}` → `{{next}}`", - "serverUpdateDiscoverySplashAdded": "• **Fondo de Invitación**: No Establecido → [Ahora]({{value}})", - "serverUpdateDiscoverySplashRemoved": "• **Fondo de Invitación**: [Antes]({{value}}) → No Establecido", - "serverUpdateDiscoverySplash": "• **Fondo de Invitación**: [Antes]({{previous}}) → [Ahora]({{next}})", - "serverUpdateExplicitContentFilter": "• **Filtro de Contenido Explícito**: `{{previous, explicitContentFilter}}` → `{{next, explicitContentFilter}}`", - "serverUpdateIconAdded": "• **Icono**: No Establecido → [Nuevo]({{value}})", - "serverUpdateIconRemoved": "• **Icono**: [Antes]({{value}}) → No Establecido", - "serverUpdateIcon": "• **Icono**: [Antes]({{previous}}) → [Ahora]({{next}})", - "serverUpdateMaximumMembersAdded": "• **Límite de Usuarios**: No Establecido → `{{value, number}}`", - "serverUpdateMaximumMembersRemoved": "• **Límite de Usuarios**: `{{value, number}}` → No Establecido", - "serverUpdateMaximumMembers": "• **Límite de Usuarios**: `{{previous, number}}` → `{{next, number}}`", - "serverUpdateMfaAdded": "• **Autenticación de Múltiples Factores Añadida**", - "serverUpdateMfaRemoved": "• **Autenticación de Múltiples Factores Eliminada**", - "serverUpdateName": "• **Nombre**: `{{previous}}` → `{{next}}`", - "serverUpdateOwner": "• **Dueño**: {{previous}} → {{next}}", - "serverUpdatePreferredLocale": "• **Idioma Preferido**: `{{previous}}` → `{{next}}`", - "serverUpdatePremiumSubscriptionCountAdded": "• **Mejoras**: No Establecido → `{{value, number}}`", - "serverUpdatePremiumSubscriptionCountRemoved": "• **Mejoras**: `{{value, number}}` → No Establecido", - "serverUpdatePremiumSubscriptionCount": "• **Mejoras**: `{{previous, number}}` → `{{next, number}}`", - "serverUpdatePremiumTier": "• **Nivel de Mejoras**: `{{previous, number}}` → `{{next, number}}`", - "serverUpdatePublicUpdatesChannelAdded": "**Canal de Actualizaciones Públicas**: No Establecido → {{value}}", - "serverUpdatePublicUpdatesChannelRemoved": "• **Canal de Actualizaciones Públicas**: {{value}} → No Establecido", - "serverUpdatePublicUpdatesChannel": "**Canal de Actualizaciones Públicas**: {{previous}} → {{next}}", - "serverUpdateRulesChannelAdded": "• **Canal de Reglas**: No Establecido → {{value}}", - "serverUpdateRulesChannelRemoved": "• **Canal de Reglas**: {{value}} → No Establecido", - "serverUpdateRulesChannel": "• **Canal de Reglas**: {{previous}} → {{next}}", - "serverUpdateSplashAdded": "• **Fondo de Invitación**: No Establecido → [Nuevo]({{value}})", - "serverUpdateSplashRemoved": "• **Fondo de Invitación**: [Antes]({{value}}) → No Establecido", - "serverUpdateSplash": "• **Fondo de Invitación**: [Antes]({{previous}}) → [Ahora]({{next}})", - "serverUpdateSystemChannelAdded": "• **Canal del Sistema**: No Establecido → {{value}}", - "serverUpdateSystemChannelRemoved": "• **Canal del Sistema**: {{value}} → No Establecido", - "serverUpdateSystemChannel": "• **Canal del Sistema**: {{previous}} → {{next}}", - "serverUpdateVanityUrlAdded": "• **Invitación Personalizada**: No Establecido → {{value}}", - "serverUpdateVanityUrlRemoved": "• **Invitación Personalizada**: `{{value}}` → No Establecido", - "serverUpdateVanityUrl": "• **Invitación Personalizada**: `{{previous}}` → {{next}}", - "serverUpdateVerificationLevel": "• **Nivel de Verificación**: `{{previous}}` → `{{next}}`", - "serverUpdateWidgetChannelAdded": "• **Canal del Widget**: No Establecido → {{value}}", - "serverUpdateWidgetChannelRemoved": "• **Canal del Widget**: {{value}} → No Establecido", - "serverUpdateWidgetChannel": "• **Canal del Widget**: {{previous}} → {{next}}", - "serverUpdateWidgetEnabled": "• **Widget Habilitado**", - "serverUpdateWidgetDisabled": "• **Widget Deshabilitado**" -} \ No newline at end of file diff --git a/src/languages/es-ES/events/guilds-members.json b/src/languages/es-ES/events/guilds-members.json deleted file mode 100644 index fdbc73145..000000000 --- a/src/languages/es-ES/events/guilds-members.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "guildMemberAdd": "Nuevo Usuario", - "guildMemberAddedRoles_one": "**Rol añadido**: {{addedRoles}}", - "guildMemberAddMute": "Un usuario silenciado se ha unido", - "guildMemberBanned": "Usuario Baneado", - "guildMemberKicked": "Usuario Expulsado", - "guildMemberNoUpdate": "No se han detectado actualizaciones", - "guildMemberRemove": "Un usuario nos ha abandonado", - "guildMemberRemovedRoles_one": "**Rol eliminado**: {{removedRoles}}", - "guildMemberSoftBanned": "Usuario Softbaneado", - "nameUpdateNextWasNotSet": "**Siguiente**: No Establecido", - "nameUpdateNextWasSet": "**Siguiente**: `{{nextName}}`", - "nameUpdatePreviousWasNotSet": "**Anterior**: No Establecido", - "nameUpdatePreviousWasSet": "**Anterior**: `{{previousName}}`", - "nicknameUpdate": "Apodo Editado", - "roleUpdate": "Roles Editados", - "usernameUpdate": "Nombre de Usuario Editado" -} \ No newline at end of file diff --git a/src/languages/es-ES/events/messages.json b/src/languages/es-ES/events/messages.json deleted file mode 100644 index a0ba55e87..000000000 --- a/src/languages/es-ES/events/messages.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "messageDelete": "Mensaje eliminado • {{channel}}", - "messageUpdate": "Mensaje Editado • {{channel}}" -} \ No newline at end of file diff --git a/src/languages/es-ES/events/moderation.json b/src/languages/es-ES/events/moderation.json deleted file mode 100644 index f44bd29e7..000000000 --- a/src/languages/es-ES/events/moderation.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "attachmentFilter": "{{REDCROSS}} Estimado {{user}}, los archivos adjuntos no están permitidos aquí.", - "attachmentFilterFooter": "Demasiados archivos adjuntos", - "attachments": "[Moderación Automática] Se ha activado el filtro de archivos adjuntos, sin umbral.", - "attachmentsWithMaximum": "[Moderación Automática] Se ha activado el filtro de archivos adjuntos, se ha alcanzado {{amount}} de {{maximum}} infracciones.", - "capitals": "[Moderación Automática] Se ha activado el filtro de mayúsculas, sin umbral.", - "capitalsWithMaximum": "[Moderación Automática] Se ha activado el filtro de mayúsculas, se ha alcanzado {{amount}} de {{maximum}} infracciones.", - "capsFilter": "¡{{REDCROSS}} EEEOOOO {{user}}! ¡POR FAVOR NO GRITES EN ESTE LUGAR! ¡HAS ALCANZADO EL LÍMITE DE MAYÚSCULAS!", - "capsFilterDm": "¡Habla más bajo! Sé que necesitas expresar tus pensamientos. Hay un mensaje que borrado:{{message}}", - "capsFilterFooter": "Demasiadas Mayúsculas", - "inviteFilterAlert": "{{REDCROSS}} Estimado {{user}}, los enlaces de invitación no están permitidos aquí.", - "inviteLink": "Enlace de Invitación", - "invites": "[Moderación Automática] Se ha activado el filtro de invitaciones, sin umbral.", - "invitesWithMaximum": "[Moderación Automática] Se ha activado el filtro de invitaciones, se ha alcanzado {{amount}} de {{maximum}} infracciones.", - "link": "Enlace Filtrado", - "links": "[Moderación Automática] Se ha activado el filtro de enlaces, sin umbral.", - "linksWithMaximum": "[Moderación Automática] Se ha activado el filtro de enlaces, se ha alcanzado {{amount}} de {{maximum}} infracciones.", - "messageFilter": "{{REDCROSS}} ¡Oye oye, ¡por favor deja de republicar tanto {{user}}!", - "messageFilterFooter": "Demasiados Mensajes Duplicados", - "messages": "[Moderación Automática] Se ha activado el filtro de mensajes duplicados, sin umbral.", - "messagesWithMaximum": "[Moderación Automática] Se ha activado el filtro de mensajes duplicados, se ha alcanzado {{amount}} de {{maximum}} infracciones.", - "newlineFilter": "{{REDCROSS}} Muro de texto entrante de {{user}}, ¡muro de texto despejado!", - "newlineFilterFooter": "Demasiadas Líneas", - "newlines": "[Moderación Automática] Se ha activado el filtro de líneas, sin umbral.", - "newlinesWithMaximum": "[Moderación Automática] Se ha activado el filtro de líneas, se ha alcanzado {{amount}} de {{maximum}} infracciones.", - "nolink": "{{REDCROSS}} ¡Oye {{user}}, ¡no puedes publicar enlaces aquí!", - "wordFilter": "{{REDCROSS}} Perdona, querido/a {{user}}, has dicho algo que no está permitido en este servidor.", - "wordFilterDm": "¡Shush! ¡Has dicho algunas palabras que no están permitidas en el servidor! Pero puesto que te tomó un momento para escribir el mensaje, lo publicaré aquí:\n{{filtered}}", - "wordFilterFooter": "Palabra Filtrada", - "words": "[Moderación Automática] Se ha activado el filtro de palabras, sin umbral.", - "wordsWithMaximum": "[Moderación Automática] Se ha activado el filtro de palabras, se ha alcanzado {{amount}} de {{maximum}} infracciones." -} \ No newline at end of file diff --git a/src/languages/es-ES/events/noMentionSpam.json b/src/languages/es-ES/events/noMentionSpam.json deleted file mode 100644 index b0c6ca36a..000000000 --- a/src/languages/es-ES/events/noMentionSpam.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "footer": "[NOMENTIONSPAM]", - "alert": "Tenga cuidado de mencionar más, ya que estás a punto de ser baneado por sobrepasar el límite de menciones establecido en este servidor.", - "message": "El martillo de baneo ha aterrizado y ahora el usuario {{userTag}} con id {{userId}} ha sido baneado por el spam de menciones.\n¡No te preocupes! ¡Estoy aquí para ayudarte! 😄", - "modlog": "[NOMENTIONSPAM] Automático: Se ha superado el límite de Spam de Menciones.\nLímite: {{threshold}}." -} \ No newline at end of file diff --git a/src/languages/es-ES/events/reactions.json b/src/languages/es-ES/events/reactions.json deleted file mode 100644 index 4c916d56b..000000000 --- a/src/languages/es-ES/events/reactions.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "filterFooter": "Reacción Filtrada", - "filter": "{{REDCROSS}} Hey {{user}}, ¡por favor no añadas esa reacción!", - "selfRoleHierarchy": "{{REDCROSS}} Mi rol tiene que ser mayor que todos los roles auto-asignables, ¡de lo contrario no puedo concederlos a la gente!" -} \ No newline at end of file diff --git a/src/languages/es-ES/fuzzySearch.json b/src/languages/es-ES/fuzzySearch.json deleted file mode 100644 index eb3ab8d96..000000000 --- a/src/languages/es-ES/fuzzySearch.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "aborted": "Se ha abortado la petición con éxito.", - "invalidIndex": "Ese número estaba fuera de rango, abortando la petición.", - "invalidNumber": "Esperaba que me dieras un número (un dígito) y me diste una patata.", - "matches": "¡He encontrado varias coincidencias! **Por favor, selecciona un número dentro de 0 y {{matches}}**:\n{{codeblock}}\nEscribe **ABORT** si quieres salir de la petición." -} \ No newline at end of file diff --git a/src/languages/es-ES/globals.json b/src/languages/es-ES/globals.json deleted file mode 100644 index b4e7c13a1..000000000 --- a/src/languages/es-ES/globals.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "default": "La clave {{key}} aún no ha sido traducido para es-ES.", - "defaultLanguage": "Idioma predeterminado", - "no": "No", - "none": "Ninguno", - "unknown": "desconocido", - "yes": "Sí", - "paginatedMessagePage": "Página", - "paginatedMessageWrongUserInteractionReply": "Por favor, deje de hacer clic en los botones de este mensaje. Sólo son para {{user}}.", - "durationValue": "{{value, duration}}", - "numberValue": "{{value, number}}", - "numberCompactValue": "{{value, numberCompact}}", - "dateTimeValue": "{{value, dateTime}}", - "orListValue": "{{value, orList}}", - "dateFormat": "DD/MM/YYYY", - "dateFormatExplanation": "Día/Mes/Año" -} \ No newline at end of file diff --git a/src/languages/es-ES/guilds.json b/src/languages/es-ES/guilds.json deleted file mode 100644 index 9adb5eab3..000000000 --- a/src/languages/es-ES/guilds.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "explicitContentFilterDisabled": "Desabilitado", - "explicitContentFilterMembersWithoutRoles": "Miembros sin rol", - "explicitContentFilterAllMembers": "Todos los miembros", - "defaultMessageNotificationsAllMessages": "Todos los Mensajes", - "defaultMessageNotificationsOnlyMentions": "Solo @menciones", - "SuppressJoinNotifications": "Notificaciones de entrada de miembros", - "SuppressJoinNotificationReplies": "Botones de respuesta de sticker de entrada de miembros", - "SuppressPremiumSubscriptions": "Notificaciones de mejora del servidor", - "SuppressGuildReminderNotifications": "Consejos de configuración del servidor", - "SuppressRoleSubscriptionPurchaseNotifications": "Suprimir notificaciones de compra de suscripción de rol", - "SuppressRoleSubscriptionPurchaseNotificationReplies": "Suprimir las respuestas para las notificaciones de compra de suscripción a roles" -} \ No newline at end of file diff --git a/src/languages/es-ES/humanLevels.json b/src/languages/es-ES/humanLevels.json deleted file mode 100644 index 08c235d6a..000000000 --- a/src/languages/es-ES/humanLevels.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "None": "Ninguno", - "Low": "Bajo", - "Medium": "Medio", - "High": "Alta", - "VeryHigh": "Más alto" -} \ No newline at end of file diff --git a/src/languages/es-ES/moderation.json b/src/languages/es-ES/moderation.json deleted file mode 100644 index 7028a2166..000000000 --- a/src/languages/es-ES/moderation.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "caseNotExists_one": "{{REDCROSS}} Lo siento, pero el caso de registro de moderación seleccionado no existe.", - "caseNotExists_other": "{{REDCROSS}} Lo siento, pero ninguno de los registros de moderación seleccionados existe.", - "restrictionNotConfigured": "El rol de restricción debe ser configurado para que esta acción se pueda llevar a cabo", - "success": "Ejecutado el comando con éxito." -} \ No newline at end of file diff --git a/src/languages/es-ES/moderationActions.json b/src/languages/es-ES/moderationActions.json deleted file mode 100644 index 6a3a9a09f..000000000 --- a/src/languages/es-ES/moderationActions.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "actions": { - "addRole": "", - "ban": "Banear", - "kick": "Expulsar", - "mute": "Silenciar", - "removeRole": "", - "restrictedAttachment": "Restricción del archivo adjunto", - "restrictedEmbed": "Restricción de Inserción de Enlaces", - "restrictedEmoji": "", - "restrictedReact": "Restricción de Reacciones", - "restrictedVoice": "Restricción de voz", - "setNickname": "Establecer apodo", - "softban": "Baneo Suave", - "vkick": "Expulsión de voz", - "vmute": "Silenciar voz", - "warning": "" - }, - "actionCannotManageRoles": "", - "actionRoleNotConfigured": "", - "actionRoleHigherPosition": "", - "actionRoleManaged": "", - "applyNoReason": "[Acción] Aplicado {{action}}", - "applyReason": "[Acción] Aplicado {{action}} | Motivo: {{reason}}", - "requiredMember": "El usuario no existe o no está en este servidor.", - "revokeNoReason": "[Acción] Revocado {{action}}", - "revokeReason": "[Acción] Revocado {{action}} | Motivo: {{reason}}", - "setNicknameNoReasonRemoved": "[Acción] Apodo Eliminado.", - "setNicknameNoReasonSet": "[Acción] Cambio de Apodo.", - "setNicknameRemoved": "[Acción] Apodo Eliminado | Motivo: {{reason}}", - "setNicknameSet": "[Acción] Cambio de Apodo | Motivo: {{reason}}", - "setupMuteExists": "**Abortar la creación de rol de silenciado**: Ya hay un rol llamado \"Muted\".", - "setupTooManyRoles": "**Abortando la creación del rol**: Ya hay 250 roles en este servidor, debe borrar uno.", - "sharedRoleSetupAsk": "{{LOADING}} ¿Puedo modificar el canal {{channels}} para aplicar al rol {{role}} el siguiente permiso: {{permissions}}?", - "sharedRoleSetupNoMessage": "No ha mandado un mensaje a tiempo, ¡cancelando la configuración!", - "sharedRoleSetupExisting": "No he podido encontrar un rol configurado. ¿Quieres configurar uno existente?", - "sharedRoleSetupExistingName": "Por favor, dame el nombre del rol que quieres utilizar para otras acciones de este tipo.", - "sharedRoleSetupNew": "¿Quieres que cree un nuevo rol y que lo configure automáticamente?", - "softbanNoReason": "[Acción] Aplicando Softban.", - "softbanReason": "[Acción] Aplicando Softban | Motivo: {{reason}}", - "unSoftbanNoReason": "[Acción] Aplicado Softban.", - "unSoftbanReason": "[Acción] Aplicado Softban | Motivo: {{reason}}" -} \ No newline at end of file diff --git a/src/languages/es-ES/permissions.json b/src/languages/es-ES/permissions.json deleted file mode 100644 index 999c26993..000000000 --- a/src/languages/es-ES/permissions.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "AddReactions": "Añadir Reacciones", - "Administrator": "Administrador", - "AttachFiles": "Adjuntar Archivos", - "BanMembers": "Bloquear Miembros", - "ChangeNickname": "Cambiar Apodo", - "Connect": "Conectar", - "CreateExpressions": "Crear Expresiones", - "CreateInstantInvite": "Crear Invitación Instantánea", - "CreatePrivateThreads": "Crear hilos privados", - "CreatePublicThreads": "Crear hilos públicos", - "DeafenMembers": "Ensordecer Miembros", - "EmbedLinks": "Insertar Enlaces", - "KickMembers": "Expulsar a Miembros", - "ManageChannels": "Gestionar Canales", - "ManageEvents": "Gestionar Eventos", - "ManageGuild": "Gestionar Servidor", - "ManageGuildExpressions": "Gestionar Expresiones", - "ManageMessages": "Gestionar Mensajes", - "ManageNicknames": "Gestionar Apodos", - "ManageRoles": "Gestionar Roles", - "ManageThreads": "Gestionar hilos", - "ManageWebhooks": "Gestionar Webhooks", - "MentionEveryone": "Mencionar a Todos", - "ModerateMembers": "Aislar temporalmente a miembros", - "MoveMembers": "Mover Miembros", - "MuteMembers": "Silenciar Miembros", - "PrioritySpeaker": "Prioridad de Palabra", - "ReadMessageHistory": "Leer el Historial de Mensajes", - "RequestToSpeak": "Solicitud para Hablar", - "SendMessages": "Enviar Mensajes", - "SendMessagesInThreads": "Enviar mensajes en hilos", - "SendTTSMessages": "Enviar Mensajes Texto A Voz", - "SendVoiceMessages": "Enviar mensajes de voz", - "Speak": "Hablar", - "Stream": "Vídeo", - "UseApplicationCommands": "Usar Comandos de Aplicación", - "UseEmbeddedActivities": "Usar Actividades", - "UseExternalEmojis": "Usar Emojis Externos", - "UseExternalSounds": "Usar Sonidos Externos", - "UseExternalStickers": "Usar Stickers Externos", - "UseSoundboard": "Usar panel de sonidos", - "UseVAD": "Usar Actividad de Voz", - "ViewAuditLog": "Ver Registro de Auditoría", - "ViewChannel": "Ver Canales", - "ViewCreatorMonetizationAnalytics": "Ver Análisis de Monetización del Creador", - "ViewGuildInsights": "Ver Información del Servidor" -} \ No newline at end of file diff --git a/src/languages/es-ES/preconditions.json b/src/languages/es-ES/preconditions.json deleted file mode 100644 index ea39dc97d..000000000 --- a/src/languages/es-ES/preconditions.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "clientPermissionsNoClient": "Esto nunca debería ocurrir, no sé quién soy.", - "clientPermissionsNoPermissions": "Esto nunca debería ocurrir, no pude determinar los permisos que tengo.", - "runIn": "Este comando no se puede ejecutar en este tipo de canal.", - "userPermissionsNoPermissions": "Esto nunca debería ocurrir, no pude determinar los permisos que usted tiene.", - "unavailable": "Esto nunca debería ocurrir, no pude encontrar una de las condiciones necesarias para este comando.", - "cooldown": "Acabas de usar este comando. Puedes usarlo de nuevo en {{remaining, duration}}.", - "nsfw": "¡No puedes usar comandos con contenido no apropiado en este canal!", - "missingMessageHandler": "Esto nunca debería ocurrir, una de las condiciones que requiere este comando no tiene un manejador de mensajes.", - "missingChatInputHandler": "Esto nunca debería ocurrir, una de las condiciones que requiere este comando no tiene un manejador de comandos slash.", - "missingContextMenuHandler": "Esto nunca debería ocurrir, una de las condiciones que requiere este comando no tiene un manejador de menú contextual.", - "administrator": "Necesitas privilegios de administrador para ejecutar `{{command.name}}`!", - "disabledGlobal": "Este comando ha sido desactivado globalmente por los propietarios del bot. ¿Quieres saber por qué y averiguar cuándo va a volver? Únete al servidor oficial de WolfStar: ", - "disabledGuild": "¡Este comando ha sido desactivado por un administrador en este servidor!", - "moderator": "Necesitas privilegios de moderador para ejecutar `{{command.name}}`!", - "permissionNodes": "{{REDCROSS}} ¡No tienes permiso para usar este comando!", - "serverOwner": "Necesitas ser el dueño del servidor para ejecutar `{{command.name}}`!", - "dmOnly": "Este comando solo puede ser utilizado en mensajes directos.", - "guildNewsOnly": "Este comando sólo puede utilizarse en canales de anuncios.", - "guildNewsThreadOnly": "Este comando sólo puede utilizarse en los hilos de los canales de anuncios.", - "guildOnly": "Este comando solo puede ser utilizado dentro de un servidor.", - "guildPrivateThreadOnly": "Este comando solo puede ser utilizado en hilos privados.", - "guildPublicThreadOnly": "Este comando sólo puede utilizarse en los hilos públicos.", - "guildTextOnly": "Este comando solo puede ser utilizado en canales de texto.", - "threadOnly": "Este comando sólo puede utilizarse en los hilos." -} \ No newline at end of file diff --git a/src/languages/es-ES/selfModeration.json b/src/languages/es-ES/selfModeration.json deleted file mode 100644 index 980f7e2f0..000000000 --- a/src/languages/es-ES/selfModeration.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "commandDisabled": "{{GREENTICK}} Sub-sistema deshabilitado con éxito.", - "commandEnabled": "{{GREENTICK}} Sub-sistema habilitado con éxito.", - "commandHardAction": "{{GREENTICK}} Castigo establecido con éxito: {{value}}", - "commandHardActionDuration": "{{GREENTICK}} Se eliminó con éxito el temporizador de apelación del castigo.", - "commandHardActionDurationWithValue": "{{GREENTICK}} Se ha establecido correctamente el temporizador de apelación de castigo a: {{value, duration}}", - "commandInvalidHardaction": "{{REDCROSS}} El valor debe ser cualquiera de los siguientes: `none`, `warn`, `mute`, `kick`, `softban`, o `ban`. Consulta `WolfStar, help {{name}}` para más información.", - "commandInvalidMissingAction": "{{REDCROSS}} La acción debe ser cualquieraa de las siguientes: `enable`, `disable`, `action`, `punish`, `punish-duration`, `threshold-maximum`, `threshold-duration` o `show`. Consulta `WolfStar, help {{name}}` para más información.", - "commandInvalidMissingArguments": "{{REDCROSS}} La acción especificada requiere que se pase un argumento extra. Revisa `WolfStar, help {{name}}` para más información.", - "commandInvalidSoftaction": "{{REDCROSS}} El valor debe ser cualquiera de los siguientes: `alert`, `log` o `delete`. Consulta `WolfStar, help {{name}}` para más información.", - "commandShow": "Activado : {{kEnabled}}\nAcción\n - Alerta : {{kAlert}}\n - Registro : {{kLog}}\n - Eliminar : {{kDelete}}\nPuntuación\n - Escribir : {{kHardAction}}\n - Duración : {{hardActionDurationText}}\nUmbral\n - Máximo : {{thresholdMaximumText}}\n - Duración : {{thresholdDurationText}}", - "commandShowDurationPermanent": "Permanente", - "commandShowUnset": "Sin definir", - "commandSoftAction": "{{GREENTICK}} Acciones deshabilitadas con éxito.", - "commandSoftActionWithValue": "{{GREENTICK}} Acciones establecidas con éxito a: `{{value}}`", - "commandThresholdDuration": "{{GREENTICK}} Se ha eliminado correctamente la duración del umbral, los castigos se aplicarán al instante si éste fue establecido.", - "commandThresholdDurationWithValue": "{{GREENTICK}} Se estableció correctamente la duración del umbral a: {{value, duration}}", - "commandThresholdMaximum": "{{GREENTICK}} Se ha eliminado correctamente el umbral máximo, los castigos se aplicarán al instante si éste fue establecido.", - "commandThresholdMaximumWithValue": "{{GREENTICK}} Se estableció correctamente la duración del umbral a: {{value}}", - "hardActionBan": "Banear", - "hardActionKick": "Expulsar", - "hardActionMute": "Silenciar", - "hardActionNone": "Ninguno", - "hardActionSoftban": "SoftBan", - "hardActionWarning": "Advertencia", - "softActionAlert": "Notificación", - "softActionDelete": "Borrar", - "softActionLog": "Informe" -} \ No newline at end of file diff --git a/src/languages/es-ES/serializers.json b/src/languages/es-ES/serializers.json deleted file mode 100644 index 6ab3701dc..000000000 --- a/src/languages/es-ES/serializers.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "disabledCommandChannelsChannelsCommandDoesNotExist": "El comando `{{name}}` no existe.", - "disabledCommandChannelsChannelsDoesNotExist": "Ese canal de chat no existe.", - "invalidBool": "{{name}} debe ser verdadero o falso.", - "invalidChannel": "{{name}} debe ser una etiqueta de canal o un identificador de canal válido.", - "invalidCommand": "{{name}} debe ser un nombre de comando.", - "invalidEmoji": "{{name}} debe ser un emoji válido.", - "invalidFloat": "{{name}} debe ser un número válido.", - "invalidGuild": "{{name}} debe ser un identificador de servidor válido.", - "invalidInt": "{{name}} debe ser un número entero.", - "invalidInvite": "{{name}} debe ser un código de invitación válido.", - "invalidRole": "{{name}} debe ser una mención o identificador de rol.", - "invalidSnowflake": "{{name}} debe ser un identificador válido.", - "invalidUrl": "{{name}} debe ser un enlace válido.", - "invalidUser": "{{name}} debe ser una mención o identificador de usuario.", - "minMaxBothExclusive": "{{name}} debe estar entre {{min}} y {{max}} exclusivamente.", - "minMaxBothInclusive": "{{name}} debe estar entre {{min}} y {{max}} inclusivamente.", - "minMaxExactlyExclusive": "{{name}} debe ser exactamente {{min}}.", - "minMaxExactlyInclusive": "{{name}} debe ser exactamente {{min}}.", - "minMaxMaxExclusive": "{{name}} debe ser menor que {{max}} exclusivamente.", - "minMaxMaxInclusive": "{{name}} debe ser menor que {{max}} inclusivamente", - "minMaxMinExclusive": "{{name}} debe ser mayor que {{min}} exclusivamente.", - "minMaxMinInclusive": "{{name}} debe ser mayor que {{min}} inclusivamente.", - "permissionNodeDuplicatedCommand": "Has establecido `{{command}}` dos veces, o lo permites, o lo niegas.", - "permissionNodeInvalid": "Datos no válidos.", - "permissionNodeInvalidCommand": "El comando `{{command}}` no existe o no es válido.", - "permissionNodeInvalidTarget": "No se pudo encontrar ningún dato del ID.", - "permissionNodeSecurityEveryoneAllows": "Por lo que respecta a la seguridad, el rol everyone no puede tener permisos extras.", - "permissionNodeSecurityGuarded": "Por seguridad y para mi correcto funcionamiento, no se puede negar el uso para el comando `{{command}}`.", - "wordIncluded": "La key `{{name}}` ya incluye la palabra `{{word}}`.", - "permissionNodeSecurityOwner": "No puedes denegar permisos al propietario del servidor.", - "reactionRoleInvalid": "Los datos del rol de reacción no son inválidos.", - "stickyRoleInvalid": "Los datos de rol pegajoso no son válidos.", - "twitchSubscriptionInvalid": "Los datos no son válidos.", - "twitchSubscriptionInvalidStreamer": "Los datos del streamer no son válidos.", - "uniqueRoleSetInvalid": "Los datos del conjunto de roles único no son válidos.", - "unknownChannel": "Canal Desconocido", - "unknownRole": "Rol Desconocido", - "unknownUser": "Usuario Desconocido", - "unsupported": "Esta clave de configuración no puede ser actualizada a través de Discord en este momento, ¡Por favor, usa el panel de control en !" -} \ No newline at end of file diff --git a/src/languages/es-ES/settings.json b/src/languages/es-ES/settings.json deleted file mode 100644 index 1392c4159..000000000 --- a/src/languages/es-ES/settings.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "channelsMediaOnly": "Los canales en los que únicamente se pueden enviar archivos multimedia.", - "channelsIgnoreAll": "Canales que debería ignorar para todos los tipos de registros.", - "channelsIgnoreMessageDelete": "Canales que debería ignorar para los registros de mensajes borrados.", - "channelsIgnoreMessageEdit": "Canales que debería ignorar para los registros de mensajes editados.", - "channelsIgnoreReactionAdd": "Canales que debería ignorar para los registros de reacciones añadidas.", - "channelsLogsChannelCreate": "El canal para los registros de creación de canales en el servidor, si este se establece enviaré un mensaje cuando se cree otro canal.", - "channelsLogsChannelDelete": "El canal para los registros de canales eliminados en el servidor, si este se establece, enviaré un mensaje a este canal cuando se elimine otro canal.", - "channelsLogsChannelUpdate": "El canal para los registros de actualización del canal en el servidor, si este se establece, enviaré un mensaje a este canal cuando cualquier canal (incluyendo este) se actualice de alguna manera. Este mensaje contendrá los cambios realizados en el canal.", - "channelsLogsEmojiCreate": "El canal para los registros de creación de emojis, si este se establece, enviaré un mensaje cuando se haya creado un nuevo emoji.", - "channelsLogsEmojiDelete": "El canal para los registros de emojis eliminados, si este se establece, enviaré un mensaje cuando se haya eliminado emoji.", - "channelsLogsEmojiUpdate": "El canal de los registros de actualizaciones de emojis, si este se establece, enviaré un mensaje cuando un emoji se actualiza de cualquier manera. Este mensaje contendrá los cambios realizados al emoji.", - "channelsLogsImage": "El canal que utilizaré para volver a subir todas las imágenes que vea.", - "channelsLogsMemberAdd": "El canal al cual enviaré un mensaje cuando un miembro se una.", - "channelsLogsMemberRemove": "El canal al cual enviaré un mensaje cuando un miembro se vaya, sea expulsado o prohibido.", - "channelsLogsMemberNickNameUpdate": "El canal al cual enviaré un mensaje cuando un miembro se cambie el apodo.", - "channelsLogsMemberUserNameUpdate": "El canal al cual enviaré un mensaje cuando un miembro se cambie su nombre de usuario.", - "channelsLogsMemberRolesUpdate": "El canal donde enviaré un mensaje cuando un miembro obtiene o pierde un rol.", - "channelsLogsMessageDelete": "El canal al que enviaré un mensaje cuando se elimine un mensaje.", - "channelsLogsMessageDeleteNsfw": "El canal donde enviaré un mensaje cuando se haya eliminado un mensaje de un canal NSFW.", - "channelsLogsMessageUpdate": "El canal al que enviaré un mensaje cuando se elimine un mensaje.", - "channelsLogsMessageUpdateNsfw": "El canal donde enviaré un mensaje cuando se haya actualizado un mensaje de un canal NSFW.", - "channelsLogsModeration": "El canal para los registros de moderación, una vez habilitado, publicaré todos mis casos de moderación allí. Si `events.banRemove` y/o `events.ban-remove` están habilitados, publicaré registros anónimos de forma automática.", - "channelsLogsPrune": "El canal para los registros de mensajes, el mismo requisito que los registros de mensajes normales, pero sólo enviará mensajes de podas de mensajes." -} \ No newline at end of file diff --git a/src/languages/es-ES/system.json b/src/languages/es-ES/system.json deleted file mode 100644 index 1a5bfbe79..000000000 --- a/src/languages/es-ES/system.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "discordAbortError": "Tuve un pequeño error de red al enviar el mensaje a Discord, ¡por favor ejecuta este comando de nuevo!", - "fetchBansFail": "Error al obtener la información de los baneos. ¿Tengo el permiso **{{ADMINISTRATOR, permissions}}**?", - "helpTitles": { - "aliases": "🖇️ | **Aliases**", - "usages": "📝 | **Uso de Comando**", - "extendedHelp": "🔍 | **Ayuda Extendida**", - "explainedUsage": "⚙ | **Uso explicado**", - "possibleFormats": "🔢 | **Formatos posibles**", - "examples": "🔗 | **Ejemplos**", - "reminders": "⏰ | **Recordatorio**" - }, - "jumpTo": "Saltar al Mensaje ►", - "loading": [ - "{{LOADING}} Viendo hámsters correr...", - "{{LOADING}} Buscando personas en el escondite...", - "{{LOADING}} Tratando de averiguar este comando...", - "{{LOADING}} Obteniendo datos desde la nube...", - "{{LOADING}} Calibrando lentes...", - "{{LOADING}} Jugando piedra, papel, tijeras...", - "{{LOADING}} Ajustando a las frecuencias correctas...", - "{{LOADING}} Reticulando curvas..." - ], - "prefixReminder": "El prefijo de este servidor es: `{{prefix}}`" -} \ No newline at end of file diff --git a/src/languages/fi/arguments.json b/src/languages/fi/arguments.json deleted file mode 100644 index a7befa6f3..000000000 --- a/src/languages/fi/arguments.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "boolean_one": "", - "boolean_other": "", - "booleanError": "", - "booleanDisabled": "", - "booleanEnabled": "", - "booleanFalseOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "booleanTrueOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "caseNoEntries": "", - "caseUnknownEntry": "", - "caseNotInThisGuild": "", - "caseLatestOptions": [ - "", - "" - ], - "categoryChannelError": "", - "channelError": "", - "command": "", - "commandMatch": "", - "dateError": "", - "dateFormats": "", - "dateTooEarly": "", - "dateTooFar": "", - "dmChannelError": "", - "duration": "", - "durationFormats": "", - "emojiError": "", - "floatError": "", - "floatTooLarge": "", - "floatTooSmall": "", - "guildChannelError": "", - "guildChannelMismatchingError": "", - "guildChannelMissingGuildError": "", - "guildPrivateThreadChannelError": "", - "guildPublicThreadChannelError": "", - "guildStageVoiceChannelError": "", - "guildTextChannelError": "", - "guildThreadChannelError": "", - "guildVoiceChannelError": "", - "hyperlinkError": "", - "integerError": "", - "integerTooLarge": "", - "integerTooSmall": "", - "invite": "", - "language": "", - "memberError": "", - "memberMissingGuild": "", - "messageError": "", - "missing": "", - "newsChannel": "", - "numberError": "", - "numberTooLarge": "", - "numberTooSmall": "", - "piece": "", - "rangeInvalid": "", - "rangeMax_other": "", - "rangeMax_one": "", - "resetPossibles": [ - "", - "" - ], - "roleError": "", - "roleMissingGuild": "", - "snowflake": "", - "store": "", - "stringTooLong": "", - "stringTooShort": "", - "time": "", - "timeSpan": "", - "timeSpanTooBig": "", - "timeSpanTooSmall": "", - "tooFewWinners": "", - "tooManyWinners": "", - "unavailable": "", - "userError": "", - "enumEmptyError": "", - "enumError": "" -} \ No newline at end of file diff --git a/src/languages/fi/assertions.json b/src/languages/fi/assertions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fi/assertions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fi/commands/admin.json b/src/languages/fi/commands/admin.json deleted file mode 100644 index 444f39c28..000000000 --- a/src/languages/fi/commands/admin.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "confUpdated": "", - "confGetNoExt": "", - "confGet": "", - "confReset": "", - "confNochange": "", - "confServerDescription": "", - "confServerExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "confServer": "", - "confDashboardOnlyKey": "", - "confSettingNotSet": "", - "rolesetDescription": "", - "rolesetExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesetCreated": "", - "rolesetAdded": "", - "rolesetRemoved": "", - "rolesetResetEmpty": "", - "rolesetResetAll": "", - "rolesetResetNotExists": "", - "rolesetResetGroup": "", - "rolesetUpdated": "", - "rolesetNoRolesets": "", - "confMenuRenderAtFolder": "", - "confMenuRenderAtPiece": "", - "confMenuRenderNokeys": "", - "confMenuRenderSelect": "", - "confMenuRenderUpdate": "", - "confMenuRenderRemove": "", - "confMenuRenderReset": "", - "confMenuRenderUndo": "", - "confMenuRenderCvalue": "", - "confMenuRenderBack": "", - "confMenuInvalidKey": "", - "confMenuInvalidAction": "", - "confMenuSaved": "" -} \ No newline at end of file diff --git a/src/languages/fi/commands/animal.json b/src/languages/fi/commands/animal.json deleted file mode 100644 index 6d00e57af..000000000 --- a/src/languages/fi/commands/animal.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "bunnyDescription": "", - "bunnyExtended": { - "extendedHelp": "" - }, - "bunnyEmbedData": { - "title": "", - "source": "" - }, - "dogDescription": "", - "dogExtended": { - "extendedHelp": "" - }, - "foxDescription": "", - "foxExtended": { - "extendedHelp": "" - }, - "kittyDescription": "", - "kittyExtended": { - "extendedHelp": "" - }, - "shibeDescription": "", - "shibeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/fi/commands/auto-moderation.json b/src/languages/fi/commands/auto-moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fi/commands/auto-moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fi/commands/case.json b/src/languages/fi/commands/case.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fi/commands/case.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fi/commands/fun.json b/src/languages/fi/commands/fun.json deleted file mode 100644 index 7892e327d..000000000 --- a/src/languages/fi/commands/fun.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "escaperopeDescription": "", - "escaperopeExtended": { - "extendedHelp": "" - }, - "escaperopeOutput": "" -} \ No newline at end of file diff --git a/src/languages/fi/commands/game.json b/src/languages/fi/commands/game.json deleted file mode 100644 index 8075ca93c..000000000 --- a/src/languages/fi/commands/game.json +++ /dev/null @@ -1,447 +0,0 @@ -{ - "c4Description": "", - "c4Extended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "c4Prompt": "", - "gamesBot": "", - "gamesNoPlayers": "", - "gamesProgress": "", - "gamesPromptDeny": "", - "gamesRepeat": "", - "gamesSelf": "", - "gamesTooManyOrFew": "", - "hgBloodbath": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgDay": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgNight": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hungerGamesDescription": "", - "hungerGamesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "examples": [ - "" - ], - "reminder": "" - }, - "hungerGamesResultDeaths_one": "", - "hungerGamesResultDeaths_other": "", - "hungerGamesResultHeaderBloodbath": "", - "hungerGamesResultHeaderMoon": "", - "hungerGamesResultHeaderSun": "", - "hungerGamesResultProceed": "", - "hungerGamesStop": "", - "hungerGamesWinner": "", - "ticTacToeDescription": "", - "ticTacToeDraw": "", - "ticTacToeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "ticTacToePrompt": "", - "ticTacToeTurn": "", - "ticTacToeWinner": "", - "triviaActiveGame": "", - "triviaDescription": "", - "triviaEmbedTitles": { - "difficulty": "", - "trivia": "" - }, - "triviaExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "triviaIncorrect": "", - "triviaInvalidCategory": "", - "triviaNoAnswer": "", - "triviaWinner": "" -} \ No newline at end of file diff --git a/src/languages/fi/commands/general.json b/src/languages/fi/commands/general.json deleted file mode 100644 index 5e16f992d..000000000 --- a/src/languages/fi/commands/general.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "helpAllFlag": "", - "helpCommandCount_one": "", - "helpCommandCount_other": "", - "helpData": { - "footer": "", - "title": "" - }, - "helpDescription": "", - "helpExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "reminder": "", - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "helpDm": "", - "helpNodm": "", - "v7Description": "", - "v7Extended": { - "extendedHelp": "" - }, - "v7Message": "", - "v7NayreMessage": "" -} \ No newline at end of file diff --git a/src/languages/fi/commands/info.json b/src/languages/fi/commands/info.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fi/commands/info.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fi/commands/management.json b/src/languages/fi/commands/management.json deleted file mode 100644 index 21ef26ce2..000000000 --- a/src/languages/fi/commands/management.json +++ /dev/null @@ -1,445 +0,0 @@ -{ - "commandHandlerAborted": "", - "permissionNodesHigher": "", - "permissionNodesCannotAllowEveryone": "", - "permissionNodesInvalidType": "", - "permissionNodesAdd": "", - "permissionNodesNodeNotExists": "", - "permissionNodesCommandNotExists": "", - "permissionNodesRemove": "", - "permissionNodesReset": "", - "permissionNodesShowName": "", - "permissionNodesShowAllow": "", - "permissionNodesShowDeny": "", - "guildInfoTitles": { - "CHANNELS": "", - "MEMBERS": "", - "OTHER": "" - }, - "guildInfoChannels": "", - "guildInfoChannelsAfkChannelText": "", - "guildInfoMembers": "", - "guildInfoOther": "", - "guildInfoBanner": "", - "guildInfoIcon": "", - "guildInfoSplash": "", - "guildInfoDiscoverySplash": "", - "roleInfoTitles": { - "PERMISSIONS": "" - }, - "roleInfoData": "", - "roleInfoAll": "", - "roleInfoNoPermissions": "", - "manageCommandAutoDeleteShowEmpty": "", - "manageCommandAutoDeleteShow": "", - "manageCommandAutoDeleteAdd": "", - "manageCommandAutoDeleteRemove": "", - "manageCommandAutoDeleteRemoveNotset": "", - "manageCommandAutoDeleteReset": "", - "manageCommandChannelShow": "", - "manageCommandChannelShowEmpty": "", - "manageCommandChannelAddAlreadyset": "", - "manageCommandChannelAdd": "", - "manageCommandChannelRemoveNotset": "", - "manageCommandChannelRemove": "", - "manageCommandChannelResetEmpty": "", - "manageCommandChannelReset": "", - "manageReactionRolesShowEmpty": "", - "manageReactionRolesAddChannel": "", - "manageReactionRolesAddPrompt": "", - "manageReactionRolesAddMissing": "", - "manageReactionRolesAdd": "", - "manageReactionRolesRemoveNotExists": "", - "manageReactionRolesRemove": "", - "manageReactionRolesResetEmpty": "", - "manageReactionRolesReset": "", - "configurationEquals": "", - "setIgnoreChannelsSet": "", - "setIgnoreChannelsRemoved": "", - "setImageLogsSet": "", - "setMemberAddLogsSet": "", - "setMemberRemoveLogsSet": "", - "setMessageUpdateLogsSet": "", - "setMessageDeleteLogsSet": "", - "setModLogsSet": "", - "setPrefixSet": "", - "stickyRolesNotExists": "", - "stickyRolesReset": "", - "stickyRolesRemove": "", - "stickyRolesAdd": "", - "stickyRolesShowEmpty": "", - "stickyRolesShowSingle": "", - "createMuteDescription": "", - "createMuteExtended": { - "extendedHelp": "" - }, - "permissionNodesDescription": "", - "permissionNodesExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "managecommandautodeleteDescription": "", - "managecommandautodeleteExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageCommandChannelDescription": "", - "manageCommandChannelExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageReactionRolesDescription": "", - "manageReactionRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "rolesAdded": "", - "rolesAuditlog": "", - "rolesListEmpty": "", - "rolesListTitle": "", - "rolesNotManageable": "", - "rolesNotPublic": "", - "rolesRemoved": "", - "setIgnoreChannelsDescription": "", - "setIgnoreChannelsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setImageLogsDescription": "", - "setImageLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "setMemberAddLogsDescription": "", - "setMemberAddLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMemberRemoveLogsDescription": "", - "setMemberRemoveLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMessageUpdateLogsDescription": "", - "setMessageUpdateLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setMessageDeleteLogsDescription": "", - "setMessageDeleteLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setmodlogsDescription": "", - "setmodlogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setprefixDescription": "", - "setprefixExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "guildInfoDescription": "", - "guildInfoExtended": { - "extendedHelp": "" - }, - "roleInfoDescription": "", - "roleInfoExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "stickyRolesDescription": "", - "stickyRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesDescription": "", - "rolesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/fi/commands/misc.json b/src/languages/fi/commands/misc.json deleted file mode 100644 index 32f64d584..000000000 --- a/src/languages/fi/commands/misc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "snipeEmpty": "", - "snipeTitle": "", - "snipeDescription": "", - "snipeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/fi/commands/moderation.json b/src/languages/fi/commands/moderation.json deleted file mode 100644 index 815d1c788..000000000 --- a/src/languages/fi/commands/moderation.json +++ /dev/null @@ -1,889 +0,0 @@ -{ - "permissions": "", - "permissionsAll": "", - "slowmodeSet": "", - "slowmodeReset": "", - "banNotBannable": "", - "dehoistStarting": "", - "dehoistProgress": "", - "dehoistEmbed": { - "title": "", - "descriptionNoone": "", - "descriptionWithError": "", - "descriptionWithMultipleErrors": "", - "description": "", - "descriptionMultipleMembers": "", - "fieldErrorTitle": "" - }, - "kickNotKickable": "", - "lockdownLock": "", - "lockdownLocking": "", - "lockdownLocked": "", - "lockdownUnlocked": "", - "lockdownOpen": "", - "muteMuted": "", - "muteUserNotMuted": "", - "restrictLowlevel": "", - "pruneAlert_one": "", - "pruneAlert_other": "", - "pruneInvalidPosition": "", - "pruneNoDeletes": "", - "pruneLogHeader": "", - "toggleModerationDmToggledEnabled": "", - "toggleModerationDmToggledDisabled": "", - "moderationOutput_one": "", - "moderationOutput_other": "", - "moderationOutputWithReason_one": "", - "moderationOutputWithReason_other": "", - "moderationFailed_one": "", - "moderationFailed_other": "", - "moderationDmFooter": "", - "moderationDmDescription": "", - "moderationDmDescriptionWithReason": "", - "moderationDmDescriptionWithDuration": "", - "moderationDmDescriptionWithReasonWithDuration": "", - "slowmodeDescription": "", - "slowmodeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "banDescription": "", - "banExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "dehoistDescription": "", - "dehoistExtended": { - "extendedHelp": "", - "reminder": "" - }, - "kickDescription": "", - "kickExtended": { - "usages": [ - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "lockdownDescription": "", - "lockdownExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "muteDescription": "", - "muteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "setNicknameDescription": "", - "setNicknameExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ], - "reminder": "" - }, - "addRoleDescription": "", - "addRoleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "removeroleDescription": "", - "removeroleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "pruneDescription": "", - "pruneExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "permissionsDescription": "", - "permissionsExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ], - "extendedHelp": "" - }, - "restrictAttachmentDescription": "", - "restrictAttachmentExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictEmbedDescription": "", - "restrictEmbedExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictEmojiDescription": "", - "restrictEmojiExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictReactionDescription": "", - "restrictReactionExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictVoiceDescription": "", - "restrictVoiceExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "softBanDescription": "", - "softBanExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "timeoutApplyDescription": "", - "timeoutApplyExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutUndoDescription": "", - "timeoutUndoExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutNotModeratable": "", - "toggleModerationDmDescription": "", - "toggleModerationDmExtended": { - "extendedHelp": "" - }, - "unbanDescription": "", - "unbanExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unmuteDescription": "", - "unmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unrestrictAttachmentDescription": "", - "unrestrictAttachmentExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmbedDescription": "", - "unrestrictEmbedExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmojiDescription": "", - "unrestrictEmojiExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictReactionDescription": "", - "unrestrictReactionExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictVoiceDescription": "", - "unrestrictVoiceExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unwarnDescription": "", - "unwarnExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vmuteDescription": "", - "vmuteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "voiceKickDescription": "", - "voiceKickExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vunmuteDescription": "", - "vunmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "warnDescription": "", - "warnExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/fi/commands/shared.json b/src/languages/fi/commands/shared.json deleted file mode 100644 index ddbb28e7f..000000000 --- a/src/languages/fi/commands/shared.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "deprecatedMessage": "", - "slashOnlyDetailedDescription": { - "extendedHelp": "" - }, - "slashOnlyErrorMessage": "" -} \ No newline at end of file diff --git a/src/languages/fi/commands/system.json b/src/languages/fi/commands/system.json deleted file mode 100644 index e9cfdeec4..000000000 --- a/src/languages/fi/commands/system.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "evalDescription": "", - "evalExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "evalTimeout": "", - "evalError": "", - "dmNotSent": "", - "dmSent": "", - "reboot": "", - "rebootDescription": "", - "rebootExtended": { - "extendedHelp": "", - "reminder": "" - } -} \ No newline at end of file diff --git a/src/languages/fi/commands/tools.json b/src/languages/fi/commands/tools.json deleted file mode 100644 index 01bd03e25..000000000 --- a/src/languages/fi/commands/tools.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "avatarDescription": "", - "avatarExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "" - }, - "avatarNone": "", - "voteDescription": "", - "voteExtended": { - "usages": [ - "" - ], - "examples": [ - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "voteContentNeeded": "", - "voteReactionBlocked": "", - "whoisExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "whoisMemberRoleListAndMore": "" -} \ No newline at end of file diff --git a/src/languages/fi/commands/twitch.json b/src/languages/fi/commands/twitch.json deleted file mode 100644 index 2f12e1b08..000000000 --- a/src/languages/fi/commands/twitch.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "twitchSubscriptionStreamerNotFound": "", - "twitchSubscriptionStatusValues": [ - "", - "" - ], - "twitchSubscriptionInvalidStatus": "", - "twitchSubscriptionAddDuplicated": "", - "twitchSubscriptionAddSuccessOffline": "", - "twitchSubscriptionAddSuccessLive": "", - "twitchSubscriptionAddMessageForOfflineRequired": "", - "twitchSubscriptionRemoveOrResetEmpty": "", - "twitchSubscriptionRemoveStreamerNotSubscribed": "", - "twitchSubscriptionRemoveNotToProvidedChannel": "", - "twitchSubscriptionRemoveStreamerStatusNotMatch": "", - "twitchSubscriptionRemoveSuccessOffline": "", - "twitchSubscriptionRemoveSuccessLive": "", - "twitchSubscriptionResetSuccess_one": "", - "twitchSubscriptionResetSuccess_other": "", - "twitchSubscriptionShowStreamerNotSubscribed": "", - "twitchSubscriptionShowStatus": { - "live": "", - "offline": "" - }, - "twitchSubscriptionShowUnknownUser": "", - "twitchSubscriptionDescription": "", - "twitchSubscriptionExtended": { - "usages": [ - "", - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/fi/commands/whois.json b/src/languages/fi/commands/whois.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fi/commands/whois.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fi/errors.json b/src/languages/fi/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fi/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fi/events/errors.json b/src/languages/fi/events/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fi/events/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fi/events/guilds-logs.json b/src/languages/fi/events/guilds-logs.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fi/events/guilds-logs.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fi/events/guilds-members.json b/src/languages/fi/events/guilds-members.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fi/events/guilds-members.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fi/events/messages.json b/src/languages/fi/events/messages.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fi/events/messages.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fi/events/moderation.json b/src/languages/fi/events/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fi/events/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fi/events/noMentionSpam.json b/src/languages/fi/events/noMentionSpam.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fi/events/noMentionSpam.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fi/events/reactions.json b/src/languages/fi/events/reactions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fi/events/reactions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fi/events/twitch.json b/src/languages/fi/events/twitch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fi/events/twitch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fi/fuzzySearch.json b/src/languages/fi/fuzzySearch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fi/fuzzySearch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fi/globals.json b/src/languages/fi/globals.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fi/globals.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fi/guilds.json b/src/languages/fi/guilds.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fi/guilds.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fi/humanLevels.json b/src/languages/fi/humanLevels.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fi/humanLevels.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fi/moderation.json b/src/languages/fi/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fi/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fi/moderationActions.json b/src/languages/fi/moderationActions.json deleted file mode 100644 index 4c440ae54..000000000 --- a/src/languages/fi/moderationActions.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "actions": { - "addRole": "", - "ban": "", - "kick": "", - "mute": "", - "removeRole": "", - "restrictedAttachment": "", - "restrictedEmbed": "", - "restrictedEmoji": "", - "restrictedReact": "", - "restrictedVoice": "", - "setNickname": "", - "softban": "", - "vkick": "", - "vmute": "", - "warning": "" - }, - "actionCannotManageRoles": "", - "actionRoleNotConfigured": "", - "actionRoleHigherPosition": "", - "actionRoleManaged": "", - "applyNoReason": "", - "applyReason": "", - "requiredMember": "", - "revokeNoReason": "", - "revokeReason": "", - "setNicknameNoReasonRemoved": "", - "setNicknameNoReasonSet": "", - "setNicknameRemoved": "", - "setNicknameSet": "", - "setupMuteExists": "", - "setupTooManyRoles": "", - "sharedRoleSetupAsk": "", - "sharedRoleSetupNoMessage": "", - "sharedRoleSetupExisting": "", - "sharedRoleSetupExistingName": "", - "sharedRoleSetupNew": "", - "softbanNoReason": "", - "softbanReason": "", - "unSoftbanNoReason": "", - "unSoftbanReason": "" -} \ No newline at end of file diff --git a/src/languages/fi/permissions.json b/src/languages/fi/permissions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fi/permissions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fi/preconditions.json b/src/languages/fi/preconditions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fi/preconditions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fi/selfModeration.json b/src/languages/fi/selfModeration.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fi/selfModeration.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fi/serializers.json b/src/languages/fi/serializers.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fi/serializers.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fi/settings.json b/src/languages/fi/settings.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fi/settings.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fi/system.json b/src/languages/fi/system.json deleted file mode 100644 index 073b9b683..000000000 --- a/src/languages/fi/system.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "discordAbortError": "", - "fetchBansFail": "", - "helpTitles": { - "aliases": "", - "usages": "", - "extendedHelp": "", - "explainedUsage": "", - "possibleFormats": "", - "examples": "", - "reminders": "" - }, - "jumpTo": "", - "loading": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "prefixReminder": "" -} \ No newline at end of file diff --git a/src/languages/fr/arguments.json b/src/languages/fr/arguments.json deleted file mode 100644 index a7befa6f3..000000000 --- a/src/languages/fr/arguments.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "boolean_one": "", - "boolean_other": "", - "booleanError": "", - "booleanDisabled": "", - "booleanEnabled": "", - "booleanFalseOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "booleanTrueOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "caseNoEntries": "", - "caseUnknownEntry": "", - "caseNotInThisGuild": "", - "caseLatestOptions": [ - "", - "" - ], - "categoryChannelError": "", - "channelError": "", - "command": "", - "commandMatch": "", - "dateError": "", - "dateFormats": "", - "dateTooEarly": "", - "dateTooFar": "", - "dmChannelError": "", - "duration": "", - "durationFormats": "", - "emojiError": "", - "floatError": "", - "floatTooLarge": "", - "floatTooSmall": "", - "guildChannelError": "", - "guildChannelMismatchingError": "", - "guildChannelMissingGuildError": "", - "guildPrivateThreadChannelError": "", - "guildPublicThreadChannelError": "", - "guildStageVoiceChannelError": "", - "guildTextChannelError": "", - "guildThreadChannelError": "", - "guildVoiceChannelError": "", - "hyperlinkError": "", - "integerError": "", - "integerTooLarge": "", - "integerTooSmall": "", - "invite": "", - "language": "", - "memberError": "", - "memberMissingGuild": "", - "messageError": "", - "missing": "", - "newsChannel": "", - "numberError": "", - "numberTooLarge": "", - "numberTooSmall": "", - "piece": "", - "rangeInvalid": "", - "rangeMax_other": "", - "rangeMax_one": "", - "resetPossibles": [ - "", - "" - ], - "roleError": "", - "roleMissingGuild": "", - "snowflake": "", - "store": "", - "stringTooLong": "", - "stringTooShort": "", - "time": "", - "timeSpan": "", - "timeSpanTooBig": "", - "timeSpanTooSmall": "", - "tooFewWinners": "", - "tooManyWinners": "", - "unavailable": "", - "userError": "", - "enumEmptyError": "", - "enumError": "" -} \ No newline at end of file diff --git a/src/languages/fr/assertions.json b/src/languages/fr/assertions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fr/assertions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fr/commands/admin.json b/src/languages/fr/commands/admin.json deleted file mode 100644 index 444f39c28..000000000 --- a/src/languages/fr/commands/admin.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "confUpdated": "", - "confGetNoExt": "", - "confGet": "", - "confReset": "", - "confNochange": "", - "confServerDescription": "", - "confServerExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "confServer": "", - "confDashboardOnlyKey": "", - "confSettingNotSet": "", - "rolesetDescription": "", - "rolesetExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesetCreated": "", - "rolesetAdded": "", - "rolesetRemoved": "", - "rolesetResetEmpty": "", - "rolesetResetAll": "", - "rolesetResetNotExists": "", - "rolesetResetGroup": "", - "rolesetUpdated": "", - "rolesetNoRolesets": "", - "confMenuRenderAtFolder": "", - "confMenuRenderAtPiece": "", - "confMenuRenderNokeys": "", - "confMenuRenderSelect": "", - "confMenuRenderUpdate": "", - "confMenuRenderRemove": "", - "confMenuRenderReset": "", - "confMenuRenderUndo": "", - "confMenuRenderCvalue": "", - "confMenuRenderBack": "", - "confMenuInvalidKey": "", - "confMenuInvalidAction": "", - "confMenuSaved": "" -} \ No newline at end of file diff --git a/src/languages/fr/commands/animal.json b/src/languages/fr/commands/animal.json deleted file mode 100644 index 6d00e57af..000000000 --- a/src/languages/fr/commands/animal.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "bunnyDescription": "", - "bunnyExtended": { - "extendedHelp": "" - }, - "bunnyEmbedData": { - "title": "", - "source": "" - }, - "dogDescription": "", - "dogExtended": { - "extendedHelp": "" - }, - "foxDescription": "", - "foxExtended": { - "extendedHelp": "" - }, - "kittyDescription": "", - "kittyExtended": { - "extendedHelp": "" - }, - "shibeDescription": "", - "shibeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/fr/commands/auto-moderation.json b/src/languages/fr/commands/auto-moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fr/commands/auto-moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fr/commands/case.json b/src/languages/fr/commands/case.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fr/commands/case.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fr/commands/fun.json b/src/languages/fr/commands/fun.json deleted file mode 100644 index 7892e327d..000000000 --- a/src/languages/fr/commands/fun.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "escaperopeDescription": "", - "escaperopeExtended": { - "extendedHelp": "" - }, - "escaperopeOutput": "" -} \ No newline at end of file diff --git a/src/languages/fr/commands/game.json b/src/languages/fr/commands/game.json deleted file mode 100644 index 8075ca93c..000000000 --- a/src/languages/fr/commands/game.json +++ /dev/null @@ -1,447 +0,0 @@ -{ - "c4Description": "", - "c4Extended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "c4Prompt": "", - "gamesBot": "", - "gamesNoPlayers": "", - "gamesProgress": "", - "gamesPromptDeny": "", - "gamesRepeat": "", - "gamesSelf": "", - "gamesTooManyOrFew": "", - "hgBloodbath": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgDay": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgNight": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hungerGamesDescription": "", - "hungerGamesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "examples": [ - "" - ], - "reminder": "" - }, - "hungerGamesResultDeaths_one": "", - "hungerGamesResultDeaths_other": "", - "hungerGamesResultHeaderBloodbath": "", - "hungerGamesResultHeaderMoon": "", - "hungerGamesResultHeaderSun": "", - "hungerGamesResultProceed": "", - "hungerGamesStop": "", - "hungerGamesWinner": "", - "ticTacToeDescription": "", - "ticTacToeDraw": "", - "ticTacToeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "ticTacToePrompt": "", - "ticTacToeTurn": "", - "ticTacToeWinner": "", - "triviaActiveGame": "", - "triviaDescription": "", - "triviaEmbedTitles": { - "difficulty": "", - "trivia": "" - }, - "triviaExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "triviaIncorrect": "", - "triviaInvalidCategory": "", - "triviaNoAnswer": "", - "triviaWinner": "" -} \ No newline at end of file diff --git a/src/languages/fr/commands/general.json b/src/languages/fr/commands/general.json deleted file mode 100644 index 5e16f992d..000000000 --- a/src/languages/fr/commands/general.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "helpAllFlag": "", - "helpCommandCount_one": "", - "helpCommandCount_other": "", - "helpData": { - "footer": "", - "title": "" - }, - "helpDescription": "", - "helpExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "reminder": "", - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "helpDm": "", - "helpNodm": "", - "v7Description": "", - "v7Extended": { - "extendedHelp": "" - }, - "v7Message": "", - "v7NayreMessage": "" -} \ No newline at end of file diff --git a/src/languages/fr/commands/info.json b/src/languages/fr/commands/info.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fr/commands/info.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fr/commands/management.json b/src/languages/fr/commands/management.json deleted file mode 100644 index 21ef26ce2..000000000 --- a/src/languages/fr/commands/management.json +++ /dev/null @@ -1,445 +0,0 @@ -{ - "commandHandlerAborted": "", - "permissionNodesHigher": "", - "permissionNodesCannotAllowEveryone": "", - "permissionNodesInvalidType": "", - "permissionNodesAdd": "", - "permissionNodesNodeNotExists": "", - "permissionNodesCommandNotExists": "", - "permissionNodesRemove": "", - "permissionNodesReset": "", - "permissionNodesShowName": "", - "permissionNodesShowAllow": "", - "permissionNodesShowDeny": "", - "guildInfoTitles": { - "CHANNELS": "", - "MEMBERS": "", - "OTHER": "" - }, - "guildInfoChannels": "", - "guildInfoChannelsAfkChannelText": "", - "guildInfoMembers": "", - "guildInfoOther": "", - "guildInfoBanner": "", - "guildInfoIcon": "", - "guildInfoSplash": "", - "guildInfoDiscoverySplash": "", - "roleInfoTitles": { - "PERMISSIONS": "" - }, - "roleInfoData": "", - "roleInfoAll": "", - "roleInfoNoPermissions": "", - "manageCommandAutoDeleteShowEmpty": "", - "manageCommandAutoDeleteShow": "", - "manageCommandAutoDeleteAdd": "", - "manageCommandAutoDeleteRemove": "", - "manageCommandAutoDeleteRemoveNotset": "", - "manageCommandAutoDeleteReset": "", - "manageCommandChannelShow": "", - "manageCommandChannelShowEmpty": "", - "manageCommandChannelAddAlreadyset": "", - "manageCommandChannelAdd": "", - "manageCommandChannelRemoveNotset": "", - "manageCommandChannelRemove": "", - "manageCommandChannelResetEmpty": "", - "manageCommandChannelReset": "", - "manageReactionRolesShowEmpty": "", - "manageReactionRolesAddChannel": "", - "manageReactionRolesAddPrompt": "", - "manageReactionRolesAddMissing": "", - "manageReactionRolesAdd": "", - "manageReactionRolesRemoveNotExists": "", - "manageReactionRolesRemove": "", - "manageReactionRolesResetEmpty": "", - "manageReactionRolesReset": "", - "configurationEquals": "", - "setIgnoreChannelsSet": "", - "setIgnoreChannelsRemoved": "", - "setImageLogsSet": "", - "setMemberAddLogsSet": "", - "setMemberRemoveLogsSet": "", - "setMessageUpdateLogsSet": "", - "setMessageDeleteLogsSet": "", - "setModLogsSet": "", - "setPrefixSet": "", - "stickyRolesNotExists": "", - "stickyRolesReset": "", - "stickyRolesRemove": "", - "stickyRolesAdd": "", - "stickyRolesShowEmpty": "", - "stickyRolesShowSingle": "", - "createMuteDescription": "", - "createMuteExtended": { - "extendedHelp": "" - }, - "permissionNodesDescription": "", - "permissionNodesExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "managecommandautodeleteDescription": "", - "managecommandautodeleteExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageCommandChannelDescription": "", - "manageCommandChannelExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageReactionRolesDescription": "", - "manageReactionRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "rolesAdded": "", - "rolesAuditlog": "", - "rolesListEmpty": "", - "rolesListTitle": "", - "rolesNotManageable": "", - "rolesNotPublic": "", - "rolesRemoved": "", - "setIgnoreChannelsDescription": "", - "setIgnoreChannelsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setImageLogsDescription": "", - "setImageLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "setMemberAddLogsDescription": "", - "setMemberAddLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMemberRemoveLogsDescription": "", - "setMemberRemoveLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMessageUpdateLogsDescription": "", - "setMessageUpdateLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setMessageDeleteLogsDescription": "", - "setMessageDeleteLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setmodlogsDescription": "", - "setmodlogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setprefixDescription": "", - "setprefixExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "guildInfoDescription": "", - "guildInfoExtended": { - "extendedHelp": "" - }, - "roleInfoDescription": "", - "roleInfoExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "stickyRolesDescription": "", - "stickyRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesDescription": "", - "rolesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/fr/commands/misc.json b/src/languages/fr/commands/misc.json deleted file mode 100644 index 32f64d584..000000000 --- a/src/languages/fr/commands/misc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "snipeEmpty": "", - "snipeTitle": "", - "snipeDescription": "", - "snipeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/fr/commands/moderation.json b/src/languages/fr/commands/moderation.json deleted file mode 100644 index 815d1c788..000000000 --- a/src/languages/fr/commands/moderation.json +++ /dev/null @@ -1,889 +0,0 @@ -{ - "permissions": "", - "permissionsAll": "", - "slowmodeSet": "", - "slowmodeReset": "", - "banNotBannable": "", - "dehoistStarting": "", - "dehoistProgress": "", - "dehoistEmbed": { - "title": "", - "descriptionNoone": "", - "descriptionWithError": "", - "descriptionWithMultipleErrors": "", - "description": "", - "descriptionMultipleMembers": "", - "fieldErrorTitle": "" - }, - "kickNotKickable": "", - "lockdownLock": "", - "lockdownLocking": "", - "lockdownLocked": "", - "lockdownUnlocked": "", - "lockdownOpen": "", - "muteMuted": "", - "muteUserNotMuted": "", - "restrictLowlevel": "", - "pruneAlert_one": "", - "pruneAlert_other": "", - "pruneInvalidPosition": "", - "pruneNoDeletes": "", - "pruneLogHeader": "", - "toggleModerationDmToggledEnabled": "", - "toggleModerationDmToggledDisabled": "", - "moderationOutput_one": "", - "moderationOutput_other": "", - "moderationOutputWithReason_one": "", - "moderationOutputWithReason_other": "", - "moderationFailed_one": "", - "moderationFailed_other": "", - "moderationDmFooter": "", - "moderationDmDescription": "", - "moderationDmDescriptionWithReason": "", - "moderationDmDescriptionWithDuration": "", - "moderationDmDescriptionWithReasonWithDuration": "", - "slowmodeDescription": "", - "slowmodeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "banDescription": "", - "banExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "dehoistDescription": "", - "dehoistExtended": { - "extendedHelp": "", - "reminder": "" - }, - "kickDescription": "", - "kickExtended": { - "usages": [ - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "lockdownDescription": "", - "lockdownExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "muteDescription": "", - "muteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "setNicknameDescription": "", - "setNicknameExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ], - "reminder": "" - }, - "addRoleDescription": "", - "addRoleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "removeroleDescription": "", - "removeroleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "pruneDescription": "", - "pruneExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "permissionsDescription": "", - "permissionsExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ], - "extendedHelp": "" - }, - "restrictAttachmentDescription": "", - "restrictAttachmentExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictEmbedDescription": "", - "restrictEmbedExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictEmojiDescription": "", - "restrictEmojiExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictReactionDescription": "", - "restrictReactionExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictVoiceDescription": "", - "restrictVoiceExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "softBanDescription": "", - "softBanExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "timeoutApplyDescription": "", - "timeoutApplyExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutUndoDescription": "", - "timeoutUndoExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutNotModeratable": "", - "toggleModerationDmDescription": "", - "toggleModerationDmExtended": { - "extendedHelp": "" - }, - "unbanDescription": "", - "unbanExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unmuteDescription": "", - "unmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unrestrictAttachmentDescription": "", - "unrestrictAttachmentExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmbedDescription": "", - "unrestrictEmbedExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmojiDescription": "", - "unrestrictEmojiExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictReactionDescription": "", - "unrestrictReactionExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictVoiceDescription": "", - "unrestrictVoiceExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unwarnDescription": "", - "unwarnExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vmuteDescription": "", - "vmuteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "voiceKickDescription": "", - "voiceKickExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vunmuteDescription": "", - "vunmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "warnDescription": "", - "warnExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/fr/commands/shared.json b/src/languages/fr/commands/shared.json deleted file mode 100644 index ddbb28e7f..000000000 --- a/src/languages/fr/commands/shared.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "deprecatedMessage": "", - "slashOnlyDetailedDescription": { - "extendedHelp": "" - }, - "slashOnlyErrorMessage": "" -} \ No newline at end of file diff --git a/src/languages/fr/commands/system.json b/src/languages/fr/commands/system.json deleted file mode 100644 index e9cfdeec4..000000000 --- a/src/languages/fr/commands/system.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "evalDescription": "", - "evalExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "evalTimeout": "", - "evalError": "", - "dmNotSent": "", - "dmSent": "", - "reboot": "", - "rebootDescription": "", - "rebootExtended": { - "extendedHelp": "", - "reminder": "" - } -} \ No newline at end of file diff --git a/src/languages/fr/commands/tools.json b/src/languages/fr/commands/tools.json deleted file mode 100644 index 01bd03e25..000000000 --- a/src/languages/fr/commands/tools.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "avatarDescription": "", - "avatarExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "" - }, - "avatarNone": "", - "voteDescription": "", - "voteExtended": { - "usages": [ - "" - ], - "examples": [ - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "voteContentNeeded": "", - "voteReactionBlocked": "", - "whoisExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "whoisMemberRoleListAndMore": "" -} \ No newline at end of file diff --git a/src/languages/fr/commands/twitch.json b/src/languages/fr/commands/twitch.json deleted file mode 100644 index 2f12e1b08..000000000 --- a/src/languages/fr/commands/twitch.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "twitchSubscriptionStreamerNotFound": "", - "twitchSubscriptionStatusValues": [ - "", - "" - ], - "twitchSubscriptionInvalidStatus": "", - "twitchSubscriptionAddDuplicated": "", - "twitchSubscriptionAddSuccessOffline": "", - "twitchSubscriptionAddSuccessLive": "", - "twitchSubscriptionAddMessageForOfflineRequired": "", - "twitchSubscriptionRemoveOrResetEmpty": "", - "twitchSubscriptionRemoveStreamerNotSubscribed": "", - "twitchSubscriptionRemoveNotToProvidedChannel": "", - "twitchSubscriptionRemoveStreamerStatusNotMatch": "", - "twitchSubscriptionRemoveSuccessOffline": "", - "twitchSubscriptionRemoveSuccessLive": "", - "twitchSubscriptionResetSuccess_one": "", - "twitchSubscriptionResetSuccess_other": "", - "twitchSubscriptionShowStreamerNotSubscribed": "", - "twitchSubscriptionShowStatus": { - "live": "", - "offline": "" - }, - "twitchSubscriptionShowUnknownUser": "", - "twitchSubscriptionDescription": "", - "twitchSubscriptionExtended": { - "usages": [ - "", - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/fr/commands/whois.json b/src/languages/fr/commands/whois.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fr/commands/whois.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fr/errors.json b/src/languages/fr/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fr/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fr/events/errors.json b/src/languages/fr/events/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fr/events/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fr/events/guilds-logs.json b/src/languages/fr/events/guilds-logs.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fr/events/guilds-logs.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fr/events/guilds-members.json b/src/languages/fr/events/guilds-members.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fr/events/guilds-members.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fr/events/messages.json b/src/languages/fr/events/messages.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fr/events/messages.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fr/events/moderation.json b/src/languages/fr/events/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fr/events/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fr/events/noMentionSpam.json b/src/languages/fr/events/noMentionSpam.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fr/events/noMentionSpam.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fr/events/reactions.json b/src/languages/fr/events/reactions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fr/events/reactions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fr/events/twitch.json b/src/languages/fr/events/twitch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fr/events/twitch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fr/fuzzySearch.json b/src/languages/fr/fuzzySearch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fr/fuzzySearch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fr/globals.json b/src/languages/fr/globals.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fr/globals.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fr/guilds.json b/src/languages/fr/guilds.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fr/guilds.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fr/humanLevels.json b/src/languages/fr/humanLevels.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fr/humanLevels.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fr/moderation.json b/src/languages/fr/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fr/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fr/moderationActions.json b/src/languages/fr/moderationActions.json deleted file mode 100644 index 4c440ae54..000000000 --- a/src/languages/fr/moderationActions.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "actions": { - "addRole": "", - "ban": "", - "kick": "", - "mute": "", - "removeRole": "", - "restrictedAttachment": "", - "restrictedEmbed": "", - "restrictedEmoji": "", - "restrictedReact": "", - "restrictedVoice": "", - "setNickname": "", - "softban": "", - "vkick": "", - "vmute": "", - "warning": "" - }, - "actionCannotManageRoles": "", - "actionRoleNotConfigured": "", - "actionRoleHigherPosition": "", - "actionRoleManaged": "", - "applyNoReason": "", - "applyReason": "", - "requiredMember": "", - "revokeNoReason": "", - "revokeReason": "", - "setNicknameNoReasonRemoved": "", - "setNicknameNoReasonSet": "", - "setNicknameRemoved": "", - "setNicknameSet": "", - "setupMuteExists": "", - "setupTooManyRoles": "", - "sharedRoleSetupAsk": "", - "sharedRoleSetupNoMessage": "", - "sharedRoleSetupExisting": "", - "sharedRoleSetupExistingName": "", - "sharedRoleSetupNew": "", - "softbanNoReason": "", - "softbanReason": "", - "unSoftbanNoReason": "", - "unSoftbanReason": "" -} \ No newline at end of file diff --git a/src/languages/fr/permissions.json b/src/languages/fr/permissions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fr/permissions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fr/preconditions.json b/src/languages/fr/preconditions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fr/preconditions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fr/selfModeration.json b/src/languages/fr/selfModeration.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fr/selfModeration.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fr/serializers.json b/src/languages/fr/serializers.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fr/serializers.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fr/settings.json b/src/languages/fr/settings.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/fr/settings.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/fr/system.json b/src/languages/fr/system.json deleted file mode 100644 index 073b9b683..000000000 --- a/src/languages/fr/system.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "discordAbortError": "", - "fetchBansFail": "", - "helpTitles": { - "aliases": "", - "usages": "", - "extendedHelp": "", - "explainedUsage": "", - "possibleFormats": "", - "examples": "", - "reminders": "" - }, - "jumpTo": "", - "loading": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "prefixReminder": "" -} \ No newline at end of file diff --git a/src/languages/hi/arguments.json b/src/languages/hi/arguments.json deleted file mode 100644 index a7befa6f3..000000000 --- a/src/languages/hi/arguments.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "boolean_one": "", - "boolean_other": "", - "booleanError": "", - "booleanDisabled": "", - "booleanEnabled": "", - "booleanFalseOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "booleanTrueOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "caseNoEntries": "", - "caseUnknownEntry": "", - "caseNotInThisGuild": "", - "caseLatestOptions": [ - "", - "" - ], - "categoryChannelError": "", - "channelError": "", - "command": "", - "commandMatch": "", - "dateError": "", - "dateFormats": "", - "dateTooEarly": "", - "dateTooFar": "", - "dmChannelError": "", - "duration": "", - "durationFormats": "", - "emojiError": "", - "floatError": "", - "floatTooLarge": "", - "floatTooSmall": "", - "guildChannelError": "", - "guildChannelMismatchingError": "", - "guildChannelMissingGuildError": "", - "guildPrivateThreadChannelError": "", - "guildPublicThreadChannelError": "", - "guildStageVoiceChannelError": "", - "guildTextChannelError": "", - "guildThreadChannelError": "", - "guildVoiceChannelError": "", - "hyperlinkError": "", - "integerError": "", - "integerTooLarge": "", - "integerTooSmall": "", - "invite": "", - "language": "", - "memberError": "", - "memberMissingGuild": "", - "messageError": "", - "missing": "", - "newsChannel": "", - "numberError": "", - "numberTooLarge": "", - "numberTooSmall": "", - "piece": "", - "rangeInvalid": "", - "rangeMax_other": "", - "rangeMax_one": "", - "resetPossibles": [ - "", - "" - ], - "roleError": "", - "roleMissingGuild": "", - "snowflake": "", - "store": "", - "stringTooLong": "", - "stringTooShort": "", - "time": "", - "timeSpan": "", - "timeSpanTooBig": "", - "timeSpanTooSmall": "", - "tooFewWinners": "", - "tooManyWinners": "", - "unavailable": "", - "userError": "", - "enumEmptyError": "", - "enumError": "" -} \ No newline at end of file diff --git a/src/languages/hi/assertions.json b/src/languages/hi/assertions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hi/assertions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hi/commands/admin.json b/src/languages/hi/commands/admin.json deleted file mode 100644 index bcefda17e..000000000 --- a/src/languages/hi/commands/admin.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "confUpdated": "", - "confGetNoExt": "{{key}} यह कुंजी मौजूद नहीं है।", - "confGet": "{{key}} इस कुंजी का मूल्य {{value}} के बराबर है।", - "confReset": "{{key}} कुंजी का मूल्य {{value}} के बराबर स्थापित किया गया है।", - "confNochange": "{{key}} कुंजी का मूल्य पहले से दिए गए मूल्य के अनुसार है।", - "confServerDescription": "सर्वर सेटिंग्स के अनुसार निश्चित करे।", - "confServerExtended": { - "usages": [ - "", - "दिखाएँ", - "कुंजी का नाम दिखाएं", - "कुंजी के लिए कुंजी का नाम मूल्य निकालें", - "कुंजी का नाम पुन: प्रस्थापित करे", - "मेन्यू" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "confServer": "**सर्वर सेटिंग्स {{key}}**\n{{list}}", - "confDashboardOnlyKey": "{{key}} केवल वेब डैशबोर्ड () माध्यम से ही इसे रूप दिया जा सकता हैं।", - "confSettingNotSet": "निर्धारित नहीं है", - "rolesetDescription": "विविध किरदार संच का प्रबंध करे।", - "rolesetExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "जोड़े", - "एक नया किरदार संच बनाए अथवा मौजूदा किसी संच में किरदार को जोड़े।" - ], - [ - "हटाएं", - "मौजूदा किरदार संच में से कोई एक किरदार हटाएं।" - ], - [ - "पुन: विस्थापन", - "किसी एक किरदार संच में से सभी किरदार हटाए, अथवा निश्चित ना होने पर, सभी किरदार संच।" - ], - [ - "सूची", - "सभी भूमिकाओं को सूचीबद्ध करता है।" - ], - [ - "स्वत:", - "किसी एक किरदार संच को जोड़ता या फिर हटता है।" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "अमेरिका विभाग को जोड़ता है", - "आफ्रीका अमेरिका आशिया यूरोप विभाग को जोड़ता है।", - "अमेरिका विभाग को हटता है।", - "मूल स्थिति पर लाना", - "विभाग को पुन: स्थापित करे।", - "सूची", - "अमेरिका विभाग", - "आफ्रीका अमेरिका आशिया यूरोप विभाग" - ], - "reminder": "यह आदेश विभिन्न किरदार को जोड़ और/अथवा हटा साकता है।" - }, - "rolesetCreated": "", - "rolesetAdded": "", - "rolesetRemoved": "", - "rolesetResetEmpty": "{{REDCROSS}} इस समूह में कोई किरदार संच परिभाषित नहीं है।", - "rolesetResetAll": "{{GREENTICK}} सभी किरदार सफलापूर्वक हटाएं गए है।", - "rolesetResetNotExists": "{{REDCROSS}} {{name}} यह किरदार संच इस सर्वर मे मौजूद नहीं है।", - "rolesetResetGroup": "{{GREENTICK}} सफला पूर्वक {{name}} किरदार संच हटाया गया है।", - "rolesetUpdated": "{{name}} इस किरदार को सफलता पूर्वक अद्यतन किया गया है।", - "rolesetNoRolesets": "आपके पास कोई भी किरदार संच नहीं है।", - "confMenuRenderAtFolder": "अभी फिलाल {{path}} में है।", - "confMenuRenderAtPiece": "अभी फिलाल ⚙️ {{path}} में है।", - "confMenuRenderNokeys": "इस फोल्डर के लिए कोई भी परिभाषित की नहीं है।", - "confMenuRenderSelect": "कृपया कोई भी प्रविष्टियो का नाम लिखे।", - "confMenuRenderUpdate": "", - "confMenuRenderRemove": "", - "confMenuRenderReset": "", - "confMenuRenderUndo": "", - "confMenuRenderCvalue": "वर्तमान मूल्य: **``{{value}}``**", - "confMenuRenderBack": "पिछे जाने के लिए ◀ दबाए।", - "confMenuInvalidKey": "अवैध की, कृपया दिए गए पर्याय से पुन: प्रयास करें।", - "confMenuInvalidAction": "अवैध कृती, कृपया दिए गए पर्याय से पुन: प्रयास करें।", - "confMenuSaved": "सफलतापूर्वक सभी बदलाव किए जा चुके है।" -} \ No newline at end of file diff --git a/src/languages/hi/commands/animal.json b/src/languages/hi/commands/animal.json deleted file mode 100644 index 07aace335..000000000 --- a/src/languages/hi/commands/animal.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "bunnyDescription": "", - "bunnyExtended": { - "extendedHelp": "" - }, - "bunnyEmbedData": { - "title": "", - "source": "" - }, - "dogDescription": "प्यारे कुत्ते! ❤", - "dogExtended": { - "extendedHelp": "" - }, - "foxDescription": "मैं तुमको एक लोमड़ी का चित्र दिखाता हूं ।", - "foxExtended": { - "extendedHelp": "" - }, - "kittyDescription": "बिलौटा!", - "kittyExtended": { - "extendedHelp": "" - }, - "shibeDescription": "प्यारा कुत्तों!", - "shibeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/hi/commands/auto-moderation.json b/src/languages/hi/commands/auto-moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hi/commands/auto-moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hi/commands/case.json b/src/languages/hi/commands/case.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hi/commands/case.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hi/commands/fun.json b/src/languages/hi/commands/fun.json deleted file mode 100644 index ed3cfc24b..000000000 --- a/src/languages/hi/commands/fun.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "escaperopeDescription": "पोकेमौन कार्यक्रम की \"एस्केप रस्सी\" का उपयोग करें |", - "escaperopeExtended": { - "extendedHelp": "**स्कायरा** ने **भागने-वाली-रस्सी** का उपयोग किया |" - }, - "escaperopeOutput": "**{{user}}** ने **भागने वाली रस्सी** का उपयोग किया |" -} \ No newline at end of file diff --git a/src/languages/hi/commands/game.json b/src/languages/hi/commands/game.json deleted file mode 100644 index 358e298d6..000000000 --- a/src/languages/hi/commands/game.json +++ /dev/null @@ -1,447 +0,0 @@ -{ - "c4Description": "किसी के साथ कनेक्ट-फोर खेलें |", - "c4Extended": { - "usages": [ - "" - ], - "extendedHelp": "यह खेल PC पर सबसे अच्छे से खेला जाता है |\nकनेक्ट-फोर एक खेल है जिसे दो लोग एक समय पर खेल सकते हैं | खिलाड़ी सबसे पहले एक रंग चुनते हैं और बारी बारी से रंगीन गोले एक सात कॉलम और छह पंक्तियों वाली ग्रिड पर रखते हैं |", - "examples": [ - "" - ] - }, - "c4Prompt": "", - "gamesBot": "क्षमा कीजिये, परन्तु मुझे नहीं लगता की वे जो काम कर रहे हैं उसे छोड़कर मनुष्यों के साथ खेलना चाहेंगे |", - "gamesNoPlayers": "'हंगर गेम्स' के लिए कुछ नाम प्रदान करें, जैसे: `{{prefix}}hg अंकित, दिय्यांश, आर्यन, काएरा`", - "gamesProgress": "क्षमा कीजिये, लेकिन इस चैनल में एक खेल प्रगति पर है, कुछ समय पश्चात पुन: प्रयास करें |", - "gamesPromptDeny": "मुझे खेद है, परन्तु प्रतिद्वंदी ने खेलने से इंकार कर दिया |", - "gamesRepeat": "क्षमा कीजिये, लेकिन एक व्यक्ति दो बार नहीं खेल सकता |", - "gamesSelf": "आप काफ़ी निराश होंगे अपने साथ खेलकर | किसी और के साथ खेलने का प्रयास करें |", - "gamesTooManyOrFew": "क्षमा कीजिये परन्तु खिलाड़ियों की संख्या {{min}} से कम या {{max}} से ज्यादा है |", - "hgBloodbath": [ - "{1} ने बेलचा उठा लिया |", - "{1} ने एक बस्ता उठाया और वापसी की |", - "{1} और {2} एक बस्ते के लिए लड़ते हैं | {1} ने हार मान कर मैदान छोड़ दिया |", - "{1} और {2} एक बस्ते के लिए लड़ते हैं | {2} ने हार मान कर मैदान छोड़ दिया |", - "{1} को कुछ तीर, एक कमान और एक तरकस मिला |", - "{1} को कोर्नुकोपिया मिलती है और उसे छुपना पड़ता है |", - "{1} ने मुट्ठी भर खंजर लिए |", - "{1} {2} के हाथों से गदा छीन लेता है |", - "{1} को पानी से भरा जलपान-गृह मिलता है |", - "{1} संसाधनों के लिए कोर्नुकोपिया के पास है |", - "{1} ने जितना हो सका उतना खाना जमा किया |", - "{1} ने तलवार थाम ली |", - "{1} ने कोर्नुकोपिया के भीतर से भाला उठा लिया |", - "{1} को विस्फोटकों के भरा थैला मिलता है |", - "{1} को एक प्राथमिक चिकित्सा की वस्तुओं से भरा बस्ता लेकर भागना पड़ता है |", - "{1} ने कोर्नुकोपिया के भीतर से एक हँसिया उठा ली |", - "{1}, {2} और {3} साथ में काम कर के जितने हो सके उतने संसाधन जुटाते हैं |", - "{1} को एक लाइटर और रस्सी लेकर भागना पड़ता है |", - "{1} को शराब की बोतल और एक कपड़ा मिलता है |", - "{1} को तंबू तथा अन्य सामग्री मिलती है |", - "{1} अनजाने में एक खाली बस्ता लेते हैं |", - "{1} ने ब्रेड की टोकरी लेने के लिए {2} की नाक तोड़ दी |", - "{1}, {2}, {3} और {4} दौड़ने से पहले जमा की हुई वस्तुएं आपस में बाटतें हैं |", - "{1} ने कोर्नुकोपिया के भीतर से त्रिशूल उठा लिया |", - "{1} मछलियों के चारे से भरा डिब्बा उठाते हैं और {2} को बंसी मिलती है |", - "{1} {2} को कोर्नुकोपिया के पास से डरा के भगा देता है |", - "{1} को कोर्नुकोपिया के ऊपर रखी एक ढाल मिलती है |", - "{1} को दो परशु मिलते हैं |", - "{1} को एक पजामा मिलता है |", - "{1T} के मंच से उतरते वक्त वहां धमाका होता है |", - "{1} {2T} के सिर में एक खंजर भोंक देता है |", - "{1T} का पैर अनजाने में एक लैंड-माइन पर पड़ जाता है |", - "{1} के हाथों {2T} की मौत होती है |", - "{1} और {2} साथ में काम कर {3T} को डुबो देते हैं |", - "{1} ने {2T} से हाथा-पाई के बाद उसका गला घोंट दिया |", - "{1} का तीर {2T} के सिर में जा लगा |", - "{1T} ने परिस्थितियों को न संभाल पाने के कारण आत्महत्या कर ली |", - "{1} ने {2T} का सिर पकड़कर उसे पत्थर में मार दिया |", - "{1} ने {2T} की गर्दन झटके के साथ तोड़ दी |", - "{1} ने तलवार से {2T} कर सिर धड़ से अलग कर दिया |", - "{1} ने {2T} के पेट पर भाले से हमला किया |", - "{1} ने {2T} को आग में झोंक दिया |", - "{1T} की गड्ढे में गिरने से मौत हो जाती है |", - "{1} ने {2T} के पीठ पीछे छुरा भोंक दिया |", - "{1} ने {2T} को घायल करने के बाद मौत के घाट उतार दिया |", - "{1} ने {2T} को घायल करने के बाद मरने के लिए छोड़ दिया |", - "{1} ने गदा से {2T} का सिर फोड़ दिया |", - "{1} ने मुठभेड़ के दौरान {2T} को खाई में धकेल दिया |", - "{1} ने {2T} की छाती में खंजर घोंप दिया |", - "{1T} की कोशिश के बावजूद {2} ने उन्हें मार दिया |", - "{1} ने {2T} को धोखा दे उन्हें मौत के घाट उतार दिया |", - "{1T} की बर्फीली झील में डूबने से मौत हो गयी |", - "{1}, {2} और {3T} आपस में लड़ना शुरू करते हैं, {2} भागने में सफल है परन्तु {1} के हाथों {3T} की मौत हो जाती है |", - "{1} ने {2T} को उसके खुद के हथियार से मार दिया |", - "{2T} की मौत {1} के हाथों होती है |", - "{2T} की {1} के द्वारा कराए गए धमाके में मौत हो गयी |", - "{2T} और {3T} की {1} के द्वारा कराए गए धमाके में मौत हो जाती है |", - "{2T}, {3T} और {4T} की {1} के द्वारा कराए गए धमाके में मौत हो जाती है |", - "{2T}, {3T}, {4T} और {5T} की {1} के द्वारा कराए गए धमाके में मौत हो जाती है |", - "{1} ने {2T} को रोक कर मार दिया |", - "{1T} और {2T} साथ में आत्महत्या करने कि धमकी देते हैं | वे असफल होते हैं और दोनों की मौत हो जाती है |", - "{1T}, {2T}, {3T} और {4T} साथ में आत्महत्या कर लेते हैं |", - "{1} ने {2T} की कुल्हाड़ी से हत्या कर दी |", - "{1} और {2} {3T} और {4T} से लड़ते हैं | {3T} और {4T} की मौत हो जाती है |", - "{1T} और {2T} {3} और {4} से लड़ते हैं | {1T} और {2T} की मौत हो जाती है |", - "{1T} ने {2} पर हमला करने कि कोशिश की परन्तु {3} ने बीच में आकर {1T} को मार दिया |", - "{1} ने तलवार से {2T} का सिर धड़ से अलग कर दिया |", - "{1} ने रस्सी के सहारे {2T} को फांसी पर टांग दिया |", - "{1} ने आवश्यक सामग्री लेने के लिए {2T} को मार दिया |", - "{1} ने {2} की ओर तीर छोड़ा, लेकिन वह {3T} को जा लगा और उसकी मौत हो गयी |", - "{1} ने {2T} के गले में विषैला तीर मार दिया, जिससे उसकी तड़प-तड़प कर मौत हो गयी |", - "{1} ने {2T} को पेड़ की टहनी से मार दिया |", - "{1} ने {2T} की पीठ पर त्रिशूल से वार किया |", - "{1}, {2T} और {3T} लड़ते हैं | {1} ने अकेले ही बाकी दोनों को मौत के घाट दिया |", - "{1T}, {2} और {3T} लड़ते हैं | {2} ने अकेले ही बाकी दोनों को मौत के घाट दिया |", - "{1T}, {2T} और {3} लड़ते हैं | {3} ने अकेले ही बाकी दोनों को मौत के घाट दिया |", - "{1} ने {2T} को कोर्नुकोपिया में छुपा पाया और उन्हें मार दिया |", - "{1T} ने {2} को कोर्नुकोपिया में छुपा लेकिन {2} ने उन्हें मार दिया |", - "{1} ने {2T} को दरांती से मार दिया |", - "{1} और {2T} एक बस्ते के ऊपर लड़ते हैं | {1} ने बस्ते की पट्टियों से {2T} का गला घोंट दिया |", - "{1T} और {2} एक बस्ते के ऊपर लड़ते हैं | {2} ने बस्ते की पट्टियों से {1T} का गला घोंट दिया |", - "{1} ने {2T} पर परशु के कई प्रहार किये |", - "{1T} का पैर कोर्नुकोपिया से दूर भागते हुए फिसला, और मौके का फ़ायदा उठा {2} ने उन्हें मौत के घाट उतार दिया |", - "{1} का पैर कोर्नुकोपिया से दूर भागते हुए फिसलता है, लेकिन {2} की सहायता से दोनों वहां से भागने में सफल होते हैं |", - "{1} ने {2} के सिर की ओर तीर छोड़ा, लेकिन {3T} ने बीच में कूद अपनी जान का त्याग कर उन्हें बचा लिया |" - ], - "hgDay": [ - "{1} शिकार करता है।", - "{1} ने खुद को घायल कर लिया |", - "{1} ने रणभूमि का अन्वेषण किया |", - "{1} ने {2} को डरा दिया |", - "{1} ने {2} का ध्यान भटकाया और दौड़ लगा दी |", - "{1} ने {2} का पीछा किया |", - "{1} ने मछलियाँ पकड़ी |", - "{1} ने खुद को झाड़ियों से ढक लिया |", - "{1} ने {2} का सामान चुरा लिया और उन्हें पता भी नहीं चला |", - "{1} ने लकड़ी से भाला बनाया |", - "{1} ने एक गुफा खोज निकाली |", - "{1} ने {2} पर हमला किया, लेकिन हमला असफ़ल रहा |", - "{1} ने {2} का पीछा किया |", - "{1} ने {2} से दूरी बनाई |", - "{1} ने पेड़ से फल इकट्ठे किए |", - "{1} को एक अज्ञात व्यक्ति से कुल्हाड़ी मिलती है |", - "{1} को एक अज्ञात व्यक्ति से साफ़ पानी मिलता है |", - "{1} को एक अज्ञात व्यक्ति से चिकित्सा सामग्री मिलती है |", - "{1} को एक अज्ञात व्यक्ति से गरमा-गरम खाना मिलता है |", - "{1} ने पानी के स्त्रोत की तलाश की |", - "{1} ने {2} को हरा दिया, लेकिन उसकी जान बख्श दी |", - "{1} और {2} एक दिन के लिए साथ में काम करते हैं |", - "{1} ने {2} से मिन्नत की कि उसे मार दिया जाए | उसने ऐसा न कर, {1} को जीवित रखा |", - "{1} ने पूरे दिन सोने की कोशिश की |", - "{1}, {2} और {3}, {4} और {5} के शिविर को उनकी अनुपस्थिति में लूट लेते हैं |", - "{1} ने एक कुटिया का निर्माण किया |", - "{1} ने छिपकर {2} और {3} की बातें सुन ली |", - "{1} ने तीरंदाजी का अभ्यास किया |", - "{1} को घर का ख्याल आता है |", - "बेर चुनते वक्त {1} को कांटे चुभ जाते हैं |", - "{1} ने त्रिशूल से मछलियाँ पकड़ने की कोशिश की |", - "{1} ने आग के लिए लकड़ी की तलाश की |", - "{1} और {2} अलग होकर संसाधनों की तलाश करते हैं |", - "{1} ने फूल चुने |", - "{1} ने {2} के घावों कि मरहम-पट्टी की |", - "{1} ने दूरी में धुआं उठते देखा लेकिन जांच न करने का फैसला किया |", - "{2} से दूर भागने के दौरान {1} के टखनों में मोच आ जाती है |", - "{1} ने गुलेल बनाई |", - "{1} ने किसी ऊँचें स्थान पर पहुचने के लिए सफ़र किया |", - "{1} को एक नदी मिलती है |", - "{1} ने बाकी खिलाड़ियों की तलाश की |", - "{1} और {2} ने बाकी खिलाड़ियों की तलाश की |", - "{1}, {2} और {3} ने बाकी खिलाड़ियों की तलाश की |", - "{1}, {2}, {3} और {4} ने बाकी खिलाड़ियों की तलाश की |", - "{1}, {2}, {3}, {4} और {5} ने बाकी खिलाड़ियों की तलाश की |", - "{1} को एक अज्ञात व्यक्ति से विस्फ़ोटक मिलता है |", - "{1} को अपनी मानसिक दशा की चिंता होती है |", - "{1} ने {2} को पजामा खाने के लिए मजबूर कर दिया |", - "{1} ने {2T} को पजामा खाने के लिए मजबूर कर दिया | दम घुंटने से {2T} की मौत हो गयी |", - "{1} के हाथों {2T} की मौत होती है |", - "{1} ने {2T} के सिर में एक खंजर घोंप दिया |", - "{1T} ने {2} से मिन्नत की कि उसे मार दिया जाए | उन्होंने अनिच्छा से {1T} को मौत के घाट उतार दिया |", - "{1} और {2} साथ में काम कर {3T} को डुबो देते हैं |", - "{1} ने {2T} से हाथा-पाई के बाद उसका गला घोंट दिया |", - "{1} का तीर {2T} के सिर में जा लगा |", - "{1T} के घावों का उपचार न हो पाने के कारण काफी रक्त बह जाता है |", - "{1T} ने परिस्थितियों को न संभाल पाने के कारण आत्महत्या कर ली |", - "{1} ने {2T} का सिर पकड़कर उसे पत्थर में मार दिया |", - "{1T} ने अनजाने में विषैले बेर खा लिए |", - "{1} ने बिना आवाज़ किए {2T} की गर्दन झटके के साथ तोड़ दी |", - "{1} ने {2T} के खाने में विष मिला दिया, जिससे उसकी मौत हो गयी |", - "{1} ने तलवार से {2T} का सिर धड़ से अलग कर दिया |", - "{1T} की संक्रमण से मौत हो जाती है |", - "{1} ने {2T} के पेट पर भाले से हमला किया |", - "{1} ने {2T} को आग में झोंक दिया |", - "{1T} की गड्ढे में गिरने से मौत हो जाती है |", - "{1} ने {2T} के पीठ पीछे छुरा भोंक दिया |", - "{1} ने {2T} को घायल करने के बाद मौत के घाट उतार दिया |", - "{1} ने {2T} को घायल करने के बाद मरने के लिए छोड़ दिया |", - "{1} ने गदा से {2T} का सिर फोड़ दिया |", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgNight": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hungerGamesDescription": "", - "hungerGamesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "examples": [ - "" - ], - "reminder": "" - }, - "hungerGamesResultDeaths_one": "", - "hungerGamesResultDeaths_other": "", - "hungerGamesResultHeaderBloodbath": "", - "hungerGamesResultHeaderMoon": "", - "hungerGamesResultHeaderSun": "", - "hungerGamesResultProceed": "", - "hungerGamesStop": "", - "hungerGamesWinner": "", - "ticTacToeDescription": "", - "ticTacToeDraw": "", - "ticTacToeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "ticTacToePrompt": "", - "ticTacToeTurn": "", - "ticTacToeWinner": "", - "triviaActiveGame": "", - "triviaDescription": "", - "triviaEmbedTitles": { - "difficulty": "", - "trivia": "" - }, - "triviaExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "triviaIncorrect": "", - "triviaInvalidCategory": "", - "triviaNoAnswer": "", - "triviaWinner": "" -} \ No newline at end of file diff --git a/src/languages/hi/commands/general.json b/src/languages/hi/commands/general.json deleted file mode 100644 index 5e16f992d..000000000 --- a/src/languages/hi/commands/general.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "helpAllFlag": "", - "helpCommandCount_one": "", - "helpCommandCount_other": "", - "helpData": { - "footer": "", - "title": "" - }, - "helpDescription": "", - "helpExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "reminder": "", - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "helpDm": "", - "helpNodm": "", - "v7Description": "", - "v7Extended": { - "extendedHelp": "" - }, - "v7Message": "", - "v7NayreMessage": "" -} \ No newline at end of file diff --git a/src/languages/hi/commands/info.json b/src/languages/hi/commands/info.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hi/commands/info.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hi/commands/management.json b/src/languages/hi/commands/management.json deleted file mode 100644 index e3865ca9a..000000000 --- a/src/languages/hi/commands/management.json +++ /dev/null @@ -1,445 +0,0 @@ -{ - "commandHandlerAborted": "", - "permissionNodesHigher": "", - "permissionNodesCannotAllowEveryone": "", - "permissionNodesInvalidType": "", - "permissionNodesAdd": "", - "permissionNodesNodeNotExists": "", - "permissionNodesCommandNotExists": "", - "permissionNodesRemove": "", - "permissionNodesReset": "", - "permissionNodesShowName": "", - "permissionNodesShowAllow": "**अनुमति**:{{allow}}", - "permissionNodesShowDeny": "", - "guildInfoTitles": { - "CHANNELS": "चैनल्स", - "MEMBERS": "सदस्यों", - "OTHER": "अन्य" - }, - "guildInfoChannels": "", - "guildInfoChannelsAfkChannelText": "", - "guildInfoMembers": "", - "guildInfoOther": "", - "guildInfoBanner": "", - "guildInfoIcon": "", - "guildInfoSplash": "", - "guildInfoDiscoverySplash": "", - "roleInfoTitles": { - "PERMISSIONS": "अनुमतियां" - }, - "roleInfoData": "", - "roleInfoAll": "अनुमति दी गयी है |", - "roleInfoNoPermissions": "अनुमतियाँ प्रदान नहीं की गईं है ।", - "manageCommandAutoDeleteShowEmpty": "", - "manageCommandAutoDeleteShow": "", - "manageCommandAutoDeleteAdd": "", - "manageCommandAutoDeleteRemove": "", - "manageCommandAutoDeleteRemoveNotset": "", - "manageCommandAutoDeleteReset": "", - "manageCommandChannelShow": "", - "manageCommandChannelShowEmpty": "", - "manageCommandChannelAddAlreadyset": "", - "manageCommandChannelAdd": "", - "manageCommandChannelRemoveNotset": "", - "manageCommandChannelRemove": "", - "manageCommandChannelResetEmpty": "", - "manageCommandChannelReset": "", - "manageReactionRolesShowEmpty": "", - "manageReactionRolesAddChannel": "", - "manageReactionRolesAddPrompt": "", - "manageReactionRolesAddMissing": "", - "manageReactionRolesAdd": "", - "manageReactionRolesRemoveNotExists": "", - "manageReactionRolesRemove": "", - "manageReactionRolesResetEmpty": "", - "manageReactionRolesReset": "", - "configurationEquals": "", - "setIgnoreChannelsSet": "", - "setIgnoreChannelsRemoved": "", - "setImageLogsSet": "", - "setMemberAddLogsSet": "", - "setMemberRemoveLogsSet": "", - "setMessageUpdateLogsSet": "", - "setMessageDeleteLogsSet": "", - "setModLogsSet": "", - "setPrefixSet": "", - "stickyRolesNotExists": "", - "stickyRolesReset": "", - "stickyRolesRemove": "", - "stickyRolesAdd": "", - "stickyRolesShowEmpty": "", - "stickyRolesShowSingle": "", - "createMuteDescription": "", - "createMuteExtended": { - "extendedHelp": "" - }, - "permissionNodesDescription": "", - "permissionNodesExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "managecommandautodeleteDescription": "", - "managecommandautodeleteExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageCommandChannelDescription": "", - "manageCommandChannelExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageReactionRolesDescription": "", - "manageReactionRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "rolesAdded": "", - "rolesAuditlog": "", - "rolesListEmpty": "", - "rolesListTitle": "", - "rolesNotManageable": "", - "rolesNotPublic": "", - "rolesRemoved": "", - "setIgnoreChannelsDescription": "", - "setIgnoreChannelsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setImageLogsDescription": "", - "setImageLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "setMemberAddLogsDescription": "", - "setMemberAddLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMemberRemoveLogsDescription": "", - "setMemberRemoveLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMessageUpdateLogsDescription": "", - "setMessageUpdateLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setMessageDeleteLogsDescription": "", - "setMessageDeleteLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setmodlogsDescription": "", - "setmodlogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setprefixDescription": "", - "setprefixExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "guildInfoDescription": "", - "guildInfoExtended": { - "extendedHelp": "" - }, - "roleInfoDescription": "", - "roleInfoExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "stickyRolesDescription": "", - "stickyRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesDescription": "", - "rolesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/hi/commands/misc.json b/src/languages/hi/commands/misc.json deleted file mode 100644 index 32f64d584..000000000 --- a/src/languages/hi/commands/misc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "snipeEmpty": "", - "snipeTitle": "", - "snipeDescription": "", - "snipeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/hi/commands/moderation.json b/src/languages/hi/commands/moderation.json deleted file mode 100644 index db503c412..000000000 --- a/src/languages/hi/commands/moderation.json +++ /dev/null @@ -1,889 +0,0 @@ -{ - "permissions": "{{username}} ({{id}}) के लिए अनुमतियाँ", - "permissionsAll": "सब अनुमतियां", - "slowmodeSet": "", - "slowmodeReset": "", - "banNotBannable": "", - "dehoistStarting": "", - "dehoistProgress": "", - "dehoistEmbed": { - "title": "", - "descriptionNoone": "", - "descriptionWithError": "", - "descriptionWithMultipleErrors": "", - "description": "", - "descriptionMultipleMembers": "", - "fieldErrorTitle": "" - }, - "kickNotKickable": "", - "lockdownLock": "", - "lockdownLocking": "", - "lockdownLocked": "", - "lockdownUnlocked": "", - "lockdownOpen": "", - "muteMuted": "", - "muteUserNotMuted": "", - "restrictLowlevel": "", - "pruneAlert_one": "", - "pruneAlert_other": "", - "pruneInvalidPosition": "", - "pruneNoDeletes": "", - "pruneLogHeader": "", - "toggleModerationDmToggledEnabled": "", - "toggleModerationDmToggledDisabled": "", - "moderationOutput_one": "", - "moderationOutput_other": "", - "moderationOutputWithReason_one": "", - "moderationOutputWithReason_other": "", - "moderationFailed_one": "", - "moderationFailed_other": "", - "moderationDmFooter": "", - "moderationDmDescription": "", - "moderationDmDescriptionWithReason": "", - "moderationDmDescriptionWithDuration": "", - "moderationDmDescriptionWithReasonWithDuration": "", - "slowmodeDescription": "", - "slowmodeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "banDescription": "", - "banExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "dehoistDescription": "", - "dehoistExtended": { - "extendedHelp": "", - "reminder": "" - }, - "kickDescription": "", - "kickExtended": { - "usages": [ - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "lockdownDescription": "", - "lockdownExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "muteDescription": "", - "muteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "setNicknameDescription": "", - "setNicknameExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ], - "reminder": "" - }, - "addRoleDescription": "", - "addRoleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "removeroleDescription": "", - "removeroleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "pruneDescription": "", - "pruneExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "permissionsDescription": "", - "permissionsExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ], - "extendedHelp": "" - }, - "restrictAttachmentDescription": "", - "restrictAttachmentExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictEmbedDescription": "", - "restrictEmbedExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictEmojiDescription": "", - "restrictEmojiExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictReactionDescription": "", - "restrictReactionExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictVoiceDescription": "", - "restrictVoiceExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "softBanDescription": "", - "softBanExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "timeoutApplyDescription": "", - "timeoutApplyExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutUndoDescription": "", - "timeoutUndoExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutNotModeratable": "", - "toggleModerationDmDescription": "", - "toggleModerationDmExtended": { - "extendedHelp": "" - }, - "unbanDescription": "", - "unbanExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unmuteDescription": "", - "unmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unrestrictAttachmentDescription": "", - "unrestrictAttachmentExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmbedDescription": "", - "unrestrictEmbedExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmojiDescription": "", - "unrestrictEmojiExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictReactionDescription": "", - "unrestrictReactionExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictVoiceDescription": "", - "unrestrictVoiceExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unwarnDescription": "", - "unwarnExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vmuteDescription": "", - "vmuteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "voiceKickDescription": "", - "voiceKickExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vunmuteDescription": "", - "vunmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "warnDescription": "", - "warnExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/hi/commands/shared.json b/src/languages/hi/commands/shared.json deleted file mode 100644 index ddbb28e7f..000000000 --- a/src/languages/hi/commands/shared.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "deprecatedMessage": "", - "slashOnlyDetailedDescription": { - "extendedHelp": "" - }, - "slashOnlyErrorMessage": "" -} \ No newline at end of file diff --git a/src/languages/hi/commands/system.json b/src/languages/hi/commands/system.json deleted file mode 100644 index e9cfdeec4..000000000 --- a/src/languages/hi/commands/system.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "evalDescription": "", - "evalExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "evalTimeout": "", - "evalError": "", - "dmNotSent": "", - "dmSent": "", - "reboot": "", - "rebootDescription": "", - "rebootExtended": { - "extendedHelp": "", - "reminder": "" - } -} \ No newline at end of file diff --git a/src/languages/hi/commands/tools.json b/src/languages/hi/commands/tools.json deleted file mode 100644 index 2ed7d5295..000000000 --- a/src/languages/hi/commands/tools.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "avatarDescription": "किसी का अवतार पूरे आकार में देखें।", - "avatarExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "" - }, - "avatarNone": "", - "voteDescription": "", - "voteExtended": { - "usages": [ - "" - ], - "examples": [ - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "voteContentNeeded": "", - "voteReactionBlocked": "", - "whoisExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "whoisMemberRoleListAndMore": "" -} \ No newline at end of file diff --git a/src/languages/hi/commands/twitch.json b/src/languages/hi/commands/twitch.json deleted file mode 100644 index 2f12e1b08..000000000 --- a/src/languages/hi/commands/twitch.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "twitchSubscriptionStreamerNotFound": "", - "twitchSubscriptionStatusValues": [ - "", - "" - ], - "twitchSubscriptionInvalidStatus": "", - "twitchSubscriptionAddDuplicated": "", - "twitchSubscriptionAddSuccessOffline": "", - "twitchSubscriptionAddSuccessLive": "", - "twitchSubscriptionAddMessageForOfflineRequired": "", - "twitchSubscriptionRemoveOrResetEmpty": "", - "twitchSubscriptionRemoveStreamerNotSubscribed": "", - "twitchSubscriptionRemoveNotToProvidedChannel": "", - "twitchSubscriptionRemoveStreamerStatusNotMatch": "", - "twitchSubscriptionRemoveSuccessOffline": "", - "twitchSubscriptionRemoveSuccessLive": "", - "twitchSubscriptionResetSuccess_one": "", - "twitchSubscriptionResetSuccess_other": "", - "twitchSubscriptionShowStreamerNotSubscribed": "", - "twitchSubscriptionShowStatus": { - "live": "", - "offline": "" - }, - "twitchSubscriptionShowUnknownUser": "", - "twitchSubscriptionDescription": "", - "twitchSubscriptionExtended": { - "usages": [ - "", - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/hi/commands/whois.json b/src/languages/hi/commands/whois.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hi/commands/whois.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hi/errors.json b/src/languages/hi/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hi/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hi/events/errors.json b/src/languages/hi/events/errors.json deleted file mode 100644 index 22c01bef7..000000000 --- a/src/languages/hi/events/errors.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "string": "{{REDCROSS}} प्रिय {{mention}}, {{message}}", - "unexpectedError": "{{REDCROSS}} मुझे एक अनपेक्षित त्रुटि मिली, कृपया मेरे डेवलपर्स को आपके द्वारा उठाए गए कदमों की रिपोर्ट करें!", - "unexpectedErrorWithContext": "$t(events/errors:unexpectedError)\nआप रिपोर्ट में `{{report}}` जोड़ सकते हैं ताकि वे देख सकें कि किस त्रुटि को ट्रिगर किया गया था।" -} \ No newline at end of file diff --git a/src/languages/hi/events/guilds-logs.json b/src/languages/hi/events/guilds-logs.json deleted file mode 100644 index 477d5c282..000000000 --- a/src/languages/hi/events/guilds-logs.json +++ /dev/null @@ -1,128 +0,0 @@ -{ - "channelCreate": "चैनल बनाया गया", - "channelCreateParent": "• **मूल**: {{value}}", - "channelCreatePosition": "• **पद**: `{{value, number}}`", - "channelCreatePermissionsTitle": "• **{{value}}** के लिए अनुमतियां", - "channelCreatePermissionsAllow_one": "- **अनुमत अनुमति**: {{values}}", - "channelCreatePermissionsDeny_one": "- **अस्वीकृत अनुमति**: {{values}}", - "channelCreateNsfw": "• **NSFW के रूप में सेट करें**", - "channelCreateTopic": "• **विषय**: `{{value}}`", - "channelCreateRateLimit": "• **रेट लिमिट**: `{{value, duration}}`", - "channelCreateBitrate": "• **बिटरेट**: `{{value}}kbps`", - "channelCreateUserLimit": "• **उपयोगकर्ता सीमा**: `{{value, number}}`", - "channelDelete": "चैनल हटा दिया गया", - "channelUpdate": "चैनल अपडेट किया गया", - "channelUpdateBitrate": "**बिटरेट**: `{{previous}}kbps` → `{{next}}kbps`", - "channelUpdateName": "• **नाम**: `{{previous}}` → `{{next}}`", - "channelUpdateNsfw": "• **NSFW**: `{{previous}}` → `{{next}}`", - "channelUpdateParent": "• **मूल**: {{previous}} → {{next}}", - "channelUpdateParentAdded": "• **मूल**: सेट नहीं → {{value}}", - "channelUpdateParentRemoved": "• **मूल**: {{value}} → सेट नहीं", - "channelUpdatePosition": "• **पद**: `{{previous, number}}` → `{{next, number}}`", - "channelUpdateAddedPermissionsAllow_one": "- **जोड़ा गया अनुमत अनुमति**: {{values}}", - "channelUpdateAddedPermissionsDeny_one": "- **अस्वीकृत अनुमति जोड़ा गया**: {{values}}", - "channelUpdateAddedPermissionsTitle": "• **{{value}} के लिए अतिरिक्त अनुमतियां जोड़ी गईं**", - "channelUpdateDeletedPermissionsTitle": "• **{{value}}** के लिए हटाई गई अनुमतियां", - "channelUpdatePermissionsTitle": "• **{{value}}** के लिए अपडेट की गई अनुमतियां", - "channelUpdateRemovedPermissionsAllow_one": "- **हटाई गई अनुमत अनुमति**: {{values}}", - "channelUpdateRemovedPermissionsDeny_one": "- **अस्वीकृत अनुमति हटाई गई**: {{values}}", - "channelUpdateRateLimit": "• **रेट लिमिट**: `{{previous, duration}}` → `{{next, duration}}`", - "channelUpdateRateLimitAdded": "• **रेट लिमिट**: सेट नहीं → `{{value, duration}}`", - "channelUpdateRateLimitRemoved": "• **रेट लिमिट**: `{{value, duration}}` → सेट नहीं", - "channelUpdateTopic": "• **विषय**: `{{previous}}` → `{{next}}`", - "channelUpdateTopicAdded": "• **विषय**: सेट नहीं → `{{value}}`", - "channelUpdateTopicRemoved": "• **विषय**: `{{value}}` → सेट नहीं", - "channelUpdateType": "• **प्ररूप**: `{{previous}}` → `{{next}}`", - "channelUpdateUserLimit": "• **उपयोगकर्ता सीमा**: `{{previous, number}}` → `{{next, number}}`", - "channelUpdateUserLimitAdded": "• **उपयोगकर्ता सीमा**: सेट नहीं → `{{value, number}}`", - "channelUpdateUserLimitRemoved": "• **उपयोगकर्ता सीमा**: `{{value, number}}` → सेट नहीं", - "emojiCreate": "इमोजी बनाया गया", - "emojiCreateAnimated": "• **एनिमेटेड**", - "emojiCreateUnAvailable": "• **उपलब्ध नहीं है**", - "emojiCreateManaged": "• **प्रबन्धित**", - "emojiCreateRequiresColons": "• **कोलन की आवश्यकता है**", - "emojiCreateRoles_one": "• **पद की आवश्यकता है**: {{values}}", - "emojiCreateRoles_other": "• **पदों की आवश्यकता है**: {{values, orList}}", - "emojiDelete": "इमोजी हटा दिया गया", - "emojiUpdate": "इमोजी संपदा किया गया", - "emojiUpdateAnimated": "• **एनिमेटेड**: `{{previous}}` → `{{next}}`", - "emojiUpdateAvailable": "• **उपलब्ध**: `{{previous}}` → `{{next}}`", - "emojiUpdateManaged": "• **प्रबन्धित**: `{{previous}}` → `{{next}}`", - "emojiUpdateName": "• **नाम**: `{{previous}}` → `{{next}}`", - "emojiUpdateRequiresColons": "• **कोलन की आवश्यकता है**: `{{previous}}` → `{{next}}`", - "emojiUpdateRolesAdded_one": "• **जोड़ा गया आवश्यक पद**: {{values}}", - "emojiUpdateRolesRemoved_one": "• **हटाया गया आवश्यक पद**: {{values}}", - "roleCreate": "पद बनाया गया", - "roleCreateColor": "• **रंग**: `{{value}}`", - "roleCreateHoist": "• **होइस्ट**", - "roleCreateMentionable": "• **उल्लेखनीय**", - "roleCreatePermissions_one": "• **अनुमति**: {{values}}", - "roleCreatePosition": "• **पद**: `{{value, number}}`", - "roleDelete": "पद हटाया गया", - "roleUpdate": "पद संपादित किया गया", - "roleUpdateColor": "• **रंग**: `{{previous}}` → `{{next}}`", - "roleUpdateHoist": "• **होइस्ट**: `{{previous}}` → `{{next}}`", - "roleUpdateMentionable": "• **उल्लेखनीय**: `{{previous}}` → `{{next}}`", - "roleUpdateName": "• **नाम**: `{{previous}}` → `{{next}}`", - "roleUpdatePermissionsAdded_one": "• **अतिरिक्त अनुमति**: {{values}}", - "roleUpdatePermissionsRemoved_one": "• **हटाई गई अनुमतियां**: {{values}}", - "roleUpdatePosition": "• **पद**: `{{previous, number}}` → `{{next, number}}`", - "serverUpdate": "सर्वर अपडेट किया गया", - "serverUpdateAfkChannelAdded": "• **AFK चैनल**: सेट नहीं → {{value}}", - "serverUpdateAfkChannelRemoved": "• **AFK चैनल**: {{value}} → सेट नहीं", - "serverUpdateAfkChannel": "• **AFK चैनल**: {{previous}} → {{next}}", - "serverUpdateAfkTimeout": "• **AFK टाइम-आउट**: `{{previous, duration}}` → `{{next, duration}}`", - "serverUpdateBannerAdded": "• **बैनर**: सेट नहीं → [नया]({{value}})", - "serverUpdateBannerRemoved": "• **बैनर**: [पुराना]({{value}}) → सेट नहीं", - "serverUpdateBanner": "• **बैनर**: [पुराना]({{previous}}) → [नया]({{next}})", - "serverUpdateDefaultMessageNotifications": "• **संदेश सूचनाएं**: {{previous, messageNotifications}}` → `{{next, messageNotifications}}`", - "serverUpdateDescriptionAdded": "• **विवरण**: सेट नहीं → `{{value}}`", - "serverUpdateDescriptionRemoved": "• **विवरण**: `{{value}}` → सेट नहीं है", - "serverUpdateDescription": "• **विवरण**: `{{previous}}` → `{{next}}`", - "serverUpdateDiscoverySplashAdded": "• **स्पलैश**: सेट नहीं → [नया]({{value}})", - "serverUpdateDiscoverySplashRemoved": "• **स्पलैश**: [पुराना]({{value}}) → सेट नहीं", - "serverUpdateDiscoverySplash": "• **स्पलैश**: [पुराना]({{previous}}) → [नया]({{next}})", - "serverUpdateExplicitContentFilter": "• **स्पष्ट सामग्री फ़िल्टर**: `{{previous, explicitContentFilter}}` → `{{next, explicitContentFilter}}`", - "serverUpdateFeaturesAdded_one": "• **जोड़ा गया फ़ीचर**: {{values}}", - "serverUpdateFeaturesRemoved_one": "• **हटाई गई सुविधा**: {{values}}", - "serverUpdateIconAdded": "• **आइकन**: सेट नहीं → [नया]({{value}})", - "serverUpdateIconRemoved": "• **आइकन**: [पुराना]({{value}}) → सेट नहीं", - "serverUpdateIcon": "• **आइकन**: [पुराना]({{previous}}) → [नया]({{next}})", - "serverUpdateMaximumMembersAdded": "• **अधिकतम सदस्य**: सेट नहीं → `{{value, number}}`", - "serverUpdateMaximumMembersRemoved": "• **अधिकतम सदस्य**: `{{value, number}}` → सेट नहीं", - "serverUpdateMaximumMembers": "• **अधिकतम सदस्य**: `{{previous, number}}` → `{{next, number}}`", - "serverUpdateMfaAdded": "• **बहु-कारक प्रमाणीकरण जोड़ा गया**", - "serverUpdateMfaRemoved": "• **बहु-कारक प्रमाणीकरण हटाया गया**", - "serverUpdateName": "• **नाम**: `{{previous}}` → `{{next}}`", - "serverUpdateOwner": "• **मालिक**: {{previous}} → {{next}}", - "serverUpdatePreferredLocaleAdded": "• **प्रफर्ड स्थान**: सेट नहीं → `{{value}}`", - "serverUpdatePreferredLocaleRemoved": "• **प्रफर्ड स्थान**: `{{value}}` → सेट नहीं है", - "serverUpdatePreferredLocale": "• **प्रफर्ड स्थान**: `{{previous}}` → `{{next}}`", - "serverUpdatePremiumSubscriptionCountAdded": "• **बूस्टर्स**: सेट नहीं → `{{value, number}}`", - "serverUpdatePremiumSubscriptionCountRemoved": "• **बूस्टर्स**: `{{value, number}}` → सेट नहीं", - "serverUpdatePremiumSubscriptionCount": "• **बूस्टर्स**: `{{previous, number}}` → `{{next, number}}`", - "serverUpdatePremiumTier": "• **प्रीमियम टियर**: `{{previous, number}}` → `{{next, number}}`", - "serverUpdatePublicUpdatesChannelAdded": "• **सार्वजनिक अपडेट चैनल**: सेट नहीं → {{value}}", - "serverUpdatePublicUpdatesChannelRemoved": "• **सार्वजनिक अपडेट चैनल**: {{value}} → सेट नहीं", - "serverUpdatePublicUpdatesChannel": "• **सार्वजनिक अपडेट चैनल**: {{previous}} → {{next}}", - "serverUpdateRulesChannelAdded": "• **नियम चैनल**: सेट नहीं → {{value}}", - "serverUpdateRulesChannelRemoved": "• **नियम चैनल**: {{value}} → सेट नहीं", - "serverUpdateRulesChannel": "• **नियम चैनल**: {{previous}} → {{next}}", - "serverUpdateSplashAdded": "• **स्पलैश**: सेट नहीं → [नया]({{value}})", - "serverUpdateSplashRemoved": "• **स्पलैश**: [पुराना]({{value}}) → सेट नहीं", - "serverUpdateSplash": "• **स्पलैश**: [पुराना]({{previous}}) → [नया]({{next}})", - "serverUpdateSystemChannelFlagsAdded_one": "• **जोड़ा गया सिस्टम चैनल विकल्प**: {{values}}", - "serverUpdateSystemChannelFlagsRemoved_one": "• **हटाया गया सिस्टम चैनल विकल्प**: {{values}}", - "serverUpdateSystemChannelAdded": "• **सिस्टम चैनल**: सेट नहीं → {{value}}", - "serverUpdateSystemChannelRemoved": "• **सिस्टम चैनल**: {{value}} → सेट नहीं", - "serverUpdateSystemChannel": "• **सिस्टम चैनल**: {{previous}} → {{next}}", - "serverUpdateVanityUrlAdded": "• **वैनिटी URL**: सेट नहीं → {{value}}", - "serverUpdateVanityUrlRemoved": "• **वैनिटी URL**: `{{value}}` → सेट नहीं", - "serverUpdateVanityUrl": "• **वैनिटी URL**: `{{previous}}` → {{next}}", - "serverUpdateVerificationLevel": "• **सत्यापन स्तर**: `{{previous}}` → `{{next}}`", - "serverUpdateWidgetChannelAdded": "• **विजेट चैनल**: सेट नहीं → {{value}}", - "serverUpdateWidgetChannelRemoved": "• **विजेट चैनल**: {{value}} → सेट नहीं", - "serverUpdateWidgetChannel": "• **विजेट चैनल**: {{previous}} → {{next}}", - "serverUpdateWidgetEnabled": "• **विजेट सक्षम**", - "serverUpdateWidgetDisabled": "• **विजेट अक्षम**" -} \ No newline at end of file diff --git a/src/languages/hi/events/guilds-members.json b/src/languages/hi/events/guilds-members.json deleted file mode 100644 index b1cd89c53..000000000 --- a/src/languages/hi/events/guilds-members.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "guildMemberAdd": "उपयोगकर्ता जुड़े", - "guildMemberAddedRoles_one": "**पद जोड़े गए**: {{addedRoles}}", - "guildMemberAddMute": "म्यूट किया गया उपयोगकर्ता शामिल हुआ", - "guildMemberBanned": "उपयोगकर्ता प्रतिबंधित", - "guildMemberKicked": "उपयोगकर्ता हटा दिया गया", - "guildMemberNoUpdate": "कोई अपडेट नहीं मिला", - "guildMemberRemove": "उपयोगकर्ता विदा हो गया", - "guildMemberRemovedRoles_one": "**पद हटाए गए**: {{removedRoles}}", - "guildMemberSoftBanned": "उपयोगकर्ता सॉफ्टबैन", - "nameUpdateNextWasNotSet": "**अगला**: सेट नहीं", - "nameUpdateNextWasSet": "**अगला**: `{{nextName}}`", - "nameUpdatePreviousWasNotSet": "**पूर्व**: सेट नहीं", - "nameUpdatePreviousWasSet": "**सेट नहीं**: `{{previousName}}`", - "nicknameUpdate": "उपनाम संपादित किया गया", - "roleUpdate": "पद सम्पादित किया गया", - "usernameUpdate": "किया गया किया गया" -} \ No newline at end of file diff --git a/src/languages/hi/events/messages.json b/src/languages/hi/events/messages.json deleted file mode 100644 index fd5d00c99..000000000 --- a/src/languages/hi/events/messages.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "messageDelete": "संदेश हटाया गया • {{channel}}", - "messageUpdate": "संदेश संपादित किया गया • {{channel}}" -} \ No newline at end of file diff --git a/src/languages/hi/events/moderation.json b/src/languages/hi/events/moderation.json deleted file mode 100644 index 7da8a6a26..000000000 --- a/src/languages/hi/events/moderation.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "attachmentFilter": "{{REDCROSS}} प्रिय {{user}}, यहां फाइल अटैचमेंट की अनुमति नहीं है।", - "attachmentFilterFooter": "बहुत अधिक अटैचमेंट", - "attachments": "[Auto-Moderation] अटैचमेंट फ़िल्टर शुरू हो गया, कोई सीमा नहीं|", - "attachmentsWithMaximum": "[Auto-Moderation] अटैचमेंट फ़िल्टर शुरू हो गया, {{maximum}} उल्लंघनों में से {{amount}} तक पहुंच गया।", - "capitals": "[Auto-Moderation] कैपिटल फ़िल्टर शुरू हो गया, कोई सीमा नहीं|", - "capitalsWithMaximum": "[Auto-Moderation] कैपिटल फ़िल्टर शुरू हो गया, {{maximum}} उल्लंघनों में से {{amount}} तक पहुंच गया।", - "capsFilter": "{{REDCROSS}} ईईईओओओ {{user}}! कृपया इस जगह पर चिल्लाएं नहीं! आपने कैपिटल की सीमा पार कर ली है!", - "capsFilterDm": "नीचे बोलो! मुझे पता है कि आपको अपने विचार व्यक्त करने की जरूरत है। यह संदेश है जिसे मैंने हटा दिया है:{{message}}", - "capsFilterFooter": "बहुत सारे अपरकेस", - "inviteFilterAlert": "{{REDCROSS}} प्रिय {{user}}, यहां आमंत्रण लिंक की अनुमति नहीं है।", - "inviteLink": "आमंत्रण लिंक", - "invites": "[Auto-Moderation] आमंत्रण फ़िल्टर शुरू हो गया, कोई सीमा नहीं|", - "invitesWithMaximum": "[Auto-Moderation] आमंत्रण फ़िल्टर शुरू हो गया, {{maximum}} उल्लंघनों में से {{amount}} तक पहुंच गया।", - "link": "फ़िल्टर्ड लिंक", - "links": "[Auto-Moderation] लिंक फ़िल्टर शुरू हो गया, कोई सीमा नहीं|", - "linksWithMaximum": "[Auto-Moderation] लिंक फ़िल्टर शुरू हो गया, {{maximum}} उल्लंघनों में से {{amount}} तक पहुंच गया।", - "messageFilter": "{{REDCROSS}} वाह वाह वाह, कृपया इतनी अधिक पुनः पोस्ट करना बंद करें {{user}}!", - "messageFilterFooter": "बहुत अधिक संदेश डुप्लिकेट", - "messages": "[Auto-Moderation] डुप्लीकेट संदेश फ़िल्टर शुरू हो गया, कोई सीमा नहीं|", - "messagesWithMaximum": "[Auto-Moderation] डुप्लीकेट संदेश शुरू हो गया, {{maximum}} उल्लंघनों में से {{amount}} तक पहुंच गया।", - "newlineFilter": "{{REDCROSS}} संदेश की दीवार {{user}} से आ रही है, संदेश की दीवार नीचे ले जाया गया!", - "newlineFilterFooter": "बहुत सारी पंक्तियाँ", - "newlines": "[Auto-Moderation] नई पंक्ति फ़िल्टर शुरू हो गया, कोई सीमा नहीं|", - "newlinesWithMaximum": "[Auto-Moderation] नई पंक्ति शुरू हो गया, {{maximum}} उल्लंघनों में से {{amount}} तक पहुंच गया।", - "nolink": "{{REDCROSS}} अरे {{user}}, आपको यहां लिंक भेजने करने की अनुमति नहीं है!", - "wordFilter": "{{REDCROSS}} क्षमा करें, प्रिय {{user}}, आपने कुछ ऐसा कहा है जिसकी इस सर्वर में अनुमति नहीं है।", - "wordFilterDm": "चुप रहो! आपने कुछ ऐसे शब्द कहे हैं जिनकी सर्वर में अनुमति नहीं है! लेकिन चूंकि आपने संदेश लिखने में कुछ समय लिया है, इसलिए मैं इसे यहां पोस्ट करुंगी:\n{{filtered}}", - "wordFilterFooter": "फ़िल्टर किया गया शब्द", - "words": "[Auto-Moderation] शब्द फ़िल्टर शुरू हो गया, कोई सीमा नहीं|", - "wordsWithMaximum": "[Auto-Moderation] शब्द फ़िल्टर शुरू हो गया, {{maximum}} उल्लंघनों में से {{amount}} तक पहुंच गया।" -} \ No newline at end of file diff --git a/src/languages/hi/events/noMentionSpam.json b/src/languages/hi/events/noMentionSpam.json deleted file mode 100644 index 1a2e92809..000000000 --- a/src/languages/hi/events/noMentionSpam.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "footer": "[NOMENTIONSPAM]", - "alert": "किसी और का उल्लेख करने में सावधानी बरतें, क्योंकि आप इस सर्वर की उल्लेख सीमा पार कर चुके है और प्रतिबंधित होने वाले है|", - "modlog": "[NOMENTIONSPAM] स्वचालित: उल्लेख करें कि स्पैम सीमा पार हो गई है।\nसीमा: {{threshold}}|" -} \ No newline at end of file diff --git a/src/languages/hi/events/reactions.json b/src/languages/hi/events/reactions.json deleted file mode 100644 index 2dd0aa0e2..000000000 --- a/src/languages/hi/events/reactions.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "filterFooter": "फ़िल्टर की गई प्रतिक्रिया", - "filter": "{{REDCROSS}} अरे {{user}}, कृपया उस प्रतिक्रिया को न जोड़ें!", - "selfRoleHierarchy": "{{REDCROSS}} मेरी भूमिका सभी स्व-आबंटित भूमिकाओं से अधिक होनी चाहिए, अन्यथा मैं उन्हें लोगों को प्रदान नहीं कर सकती!" -} \ No newline at end of file diff --git a/src/languages/hi/events/twitch.json b/src/languages/hi/events/twitch.json deleted file mode 100644 index d331724d3..000000000 --- a/src/languages/hi/events/twitch.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "embedDescription": "{{userName}} अब लाइव है!", - "embedDescriptionWithGame": "{{userName}} अब लाइव है! - स्ट्रीमिंग {{gameName}}!", - "offlinePostfix": "WolfStar ट्विच सूचनाएं" -} \ No newline at end of file diff --git a/src/languages/hi/fuzzySearch.json b/src/languages/hi/fuzzySearch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hi/fuzzySearch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hi/globals.json b/src/languages/hi/globals.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hi/globals.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hi/guilds.json b/src/languages/hi/guilds.json deleted file mode 100644 index 8e7976ef7..000000000 --- a/src/languages/hi/guilds.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "explicitContentFilterDisabled": "अक्षम", - "explicitContentFilterMembersWithoutRoles": "पदों के बिना सदस्य", - "explicitContentFilterAllMembers": "सभी सदस्य" -} \ No newline at end of file diff --git a/src/languages/hi/humanLevels.json b/src/languages/hi/humanLevels.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hi/humanLevels.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hi/moderation.json b/src/languages/hi/moderation.json deleted file mode 100644 index 0740ca1d9..000000000 --- a/src/languages/hi/moderation.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "caseNotExists_one": "{{REDCROSS}} मुझे खेद है, लेकिन चयनित मॉडरेशन लॉग प्रकरण मौजूद नहीं है।", - "caseNotExists_other": "{{REDCROSS}} मुझे खेद है, लेकिन चयनित मॉडरेशन लॉग प्रकरणों में से कोई भी मौजूद नहीं है।", - "restrictionNotConfigured": "इस क्रिया के होने के लिए प्रतिबंध पद को कॉन्फ़िगर किया जाना चाहिए", - "success": "कमांड को सफलतापूर्वक निष्पादित किया।" -} \ No newline at end of file diff --git a/src/languages/hi/moderationActions.json b/src/languages/hi/moderationActions.json deleted file mode 100644 index 9ae10f977..000000000 --- a/src/languages/hi/moderationActions.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "actions": { - "addRole": "", - "ban": "प्रतिबंध", - "kick": "निकालें", - "mute": "म्यूट", - "removeRole": "", - "restrictedAttachment": "अटैचमेंट प्रतिबंध", - "restrictedEmbed": "एम्बेड प्रतिबंध", - "restrictedEmoji": "", - "restrictedReact": "प्रतिक्रिया प्रतिबंध", - "restrictedVoice": "आवाज़ प्रतिबंध", - "setNickname": "उपनाम रखे", - "softban": "सॉफ्टबैन", - "vkick": "आवाज से हटाना", - "vmute": "आवाज मूक", - "warning": "" - }, - "actionCannotManageRoles": "", - "actionRoleNotConfigured": "", - "actionRoleHigherPosition": "", - "actionRoleManaged": "", - "applyNoReason": "", - "applyReason": "", - "requiredMember": "उपयोगकर्ता मौजूद नहीं है या इस सर्वर में नहीं है।", - "revokeNoReason": "", - "revokeReason": "", - "setNicknameNoReasonRemoved": "", - "setNicknameNoReasonSet": "", - "setNicknameRemoved": "", - "setNicknameSet": "", - "setupMuteExists": "**म्यूट पद बनाना बंद किया गया**: पहले से ही \"Muted\" नामक एक पद है।", - "setupTooManyRoles": "**पद बनाना बंद किया गया**: इस सर्वर में 250 पद हैं, आपको एक पद को हटाना होगा।", - "sharedRoleSetupAsk": "", - "sharedRoleSetupNoMessage": "आपने समय पर संदेश नहीं डाला, सेट अप रद्द कर दिया!", - "sharedRoleSetupExisting": "मुझे कॉन्फ़िगर किया गया पद नहीं मिला। क्या आप किसी मौजूदा को कॉन्फ़िगर करना चाहते हैं?", - "sharedRoleSetupExistingName": "कृपया मुझे उस पद का नाम दें जिसका उपयोग आप इस प्रकार की आगे की कार्रवाइयों के लिए करना चाहते हैं।", - "sharedRoleSetupNew": "क्या आप चाहते हैं कि मैं एक नया पद बनाऊं और इसे स्वचालित रूप से कॉन्फ़िगर करूं?", - "softbanNoReason": "", - "softbanReason": "", - "unSoftbanNoReason": "", - "unSoftbanReason": "" -} \ No newline at end of file diff --git a/src/languages/hi/permissions.json b/src/languages/hi/permissions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hi/permissions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hi/preconditions.json b/src/languages/hi/preconditions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hi/preconditions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hi/selfModeration.json b/src/languages/hi/selfModeration.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hi/selfModeration.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hi/serializers.json b/src/languages/hi/serializers.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hi/serializers.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hi/settings.json b/src/languages/hi/settings.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hi/settings.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hi/system.json b/src/languages/hi/system.json deleted file mode 100644 index 1402e4a04..000000000 --- a/src/languages/hi/system.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "discordAbortError": "डिस्कोर्ड को मैसेज करते समय मेरे पास एक छोटी सी नेटवर्क त्रुटि थी, कृपया इस कमांड को फिर से चलाएं |", - "fetchBansFail": "", - "helpTitles": { - "aliases": "", - "usages": "", - "extendedHelp": "", - "explainedUsage": "", - "possibleFormats": "", - "examples": "", - "reminders": "" - }, - "jumpTo": "", - "loading": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "prefixReminder": "" -} \ No newline at end of file diff --git a/src/languages/hr/arguments.json b/src/languages/hr/arguments.json deleted file mode 100644 index a7befa6f3..000000000 --- a/src/languages/hr/arguments.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "boolean_one": "", - "boolean_other": "", - "booleanError": "", - "booleanDisabled": "", - "booleanEnabled": "", - "booleanFalseOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "booleanTrueOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "caseNoEntries": "", - "caseUnknownEntry": "", - "caseNotInThisGuild": "", - "caseLatestOptions": [ - "", - "" - ], - "categoryChannelError": "", - "channelError": "", - "command": "", - "commandMatch": "", - "dateError": "", - "dateFormats": "", - "dateTooEarly": "", - "dateTooFar": "", - "dmChannelError": "", - "duration": "", - "durationFormats": "", - "emojiError": "", - "floatError": "", - "floatTooLarge": "", - "floatTooSmall": "", - "guildChannelError": "", - "guildChannelMismatchingError": "", - "guildChannelMissingGuildError": "", - "guildPrivateThreadChannelError": "", - "guildPublicThreadChannelError": "", - "guildStageVoiceChannelError": "", - "guildTextChannelError": "", - "guildThreadChannelError": "", - "guildVoiceChannelError": "", - "hyperlinkError": "", - "integerError": "", - "integerTooLarge": "", - "integerTooSmall": "", - "invite": "", - "language": "", - "memberError": "", - "memberMissingGuild": "", - "messageError": "", - "missing": "", - "newsChannel": "", - "numberError": "", - "numberTooLarge": "", - "numberTooSmall": "", - "piece": "", - "rangeInvalid": "", - "rangeMax_other": "", - "rangeMax_one": "", - "resetPossibles": [ - "", - "" - ], - "roleError": "", - "roleMissingGuild": "", - "snowflake": "", - "store": "", - "stringTooLong": "", - "stringTooShort": "", - "time": "", - "timeSpan": "", - "timeSpanTooBig": "", - "timeSpanTooSmall": "", - "tooFewWinners": "", - "tooManyWinners": "", - "unavailable": "", - "userError": "", - "enumEmptyError": "", - "enumError": "" -} \ No newline at end of file diff --git a/src/languages/hr/assertions.json b/src/languages/hr/assertions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hr/assertions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hr/commands/admin.json b/src/languages/hr/commands/admin.json deleted file mode 100644 index 444f39c28..000000000 --- a/src/languages/hr/commands/admin.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "confUpdated": "", - "confGetNoExt": "", - "confGet": "", - "confReset": "", - "confNochange": "", - "confServerDescription": "", - "confServerExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "confServer": "", - "confDashboardOnlyKey": "", - "confSettingNotSet": "", - "rolesetDescription": "", - "rolesetExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesetCreated": "", - "rolesetAdded": "", - "rolesetRemoved": "", - "rolesetResetEmpty": "", - "rolesetResetAll": "", - "rolesetResetNotExists": "", - "rolesetResetGroup": "", - "rolesetUpdated": "", - "rolesetNoRolesets": "", - "confMenuRenderAtFolder": "", - "confMenuRenderAtPiece": "", - "confMenuRenderNokeys": "", - "confMenuRenderSelect": "", - "confMenuRenderUpdate": "", - "confMenuRenderRemove": "", - "confMenuRenderReset": "", - "confMenuRenderUndo": "", - "confMenuRenderCvalue": "", - "confMenuRenderBack": "", - "confMenuInvalidKey": "", - "confMenuInvalidAction": "", - "confMenuSaved": "" -} \ No newline at end of file diff --git a/src/languages/hr/commands/animal.json b/src/languages/hr/commands/animal.json deleted file mode 100644 index 6d00e57af..000000000 --- a/src/languages/hr/commands/animal.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "bunnyDescription": "", - "bunnyExtended": { - "extendedHelp": "" - }, - "bunnyEmbedData": { - "title": "", - "source": "" - }, - "dogDescription": "", - "dogExtended": { - "extendedHelp": "" - }, - "foxDescription": "", - "foxExtended": { - "extendedHelp": "" - }, - "kittyDescription": "", - "kittyExtended": { - "extendedHelp": "" - }, - "shibeDescription": "", - "shibeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/hr/commands/auto-moderation.json b/src/languages/hr/commands/auto-moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hr/commands/auto-moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hr/commands/case.json b/src/languages/hr/commands/case.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hr/commands/case.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hr/commands/fun.json b/src/languages/hr/commands/fun.json deleted file mode 100644 index 7892e327d..000000000 --- a/src/languages/hr/commands/fun.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "escaperopeDescription": "", - "escaperopeExtended": { - "extendedHelp": "" - }, - "escaperopeOutput": "" -} \ No newline at end of file diff --git a/src/languages/hr/commands/game.json b/src/languages/hr/commands/game.json deleted file mode 100644 index 8075ca93c..000000000 --- a/src/languages/hr/commands/game.json +++ /dev/null @@ -1,447 +0,0 @@ -{ - "c4Description": "", - "c4Extended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "c4Prompt": "", - "gamesBot": "", - "gamesNoPlayers": "", - "gamesProgress": "", - "gamesPromptDeny": "", - "gamesRepeat": "", - "gamesSelf": "", - "gamesTooManyOrFew": "", - "hgBloodbath": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgDay": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgNight": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hungerGamesDescription": "", - "hungerGamesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "examples": [ - "" - ], - "reminder": "" - }, - "hungerGamesResultDeaths_one": "", - "hungerGamesResultDeaths_other": "", - "hungerGamesResultHeaderBloodbath": "", - "hungerGamesResultHeaderMoon": "", - "hungerGamesResultHeaderSun": "", - "hungerGamesResultProceed": "", - "hungerGamesStop": "", - "hungerGamesWinner": "", - "ticTacToeDescription": "", - "ticTacToeDraw": "", - "ticTacToeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "ticTacToePrompt": "", - "ticTacToeTurn": "", - "ticTacToeWinner": "", - "triviaActiveGame": "", - "triviaDescription": "", - "triviaEmbedTitles": { - "difficulty": "", - "trivia": "" - }, - "triviaExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "triviaIncorrect": "", - "triviaInvalidCategory": "", - "triviaNoAnswer": "", - "triviaWinner": "" -} \ No newline at end of file diff --git a/src/languages/hr/commands/general.json b/src/languages/hr/commands/general.json deleted file mode 100644 index 5e16f992d..000000000 --- a/src/languages/hr/commands/general.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "helpAllFlag": "", - "helpCommandCount_one": "", - "helpCommandCount_other": "", - "helpData": { - "footer": "", - "title": "" - }, - "helpDescription": "", - "helpExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "reminder": "", - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "helpDm": "", - "helpNodm": "", - "v7Description": "", - "v7Extended": { - "extendedHelp": "" - }, - "v7Message": "", - "v7NayreMessage": "" -} \ No newline at end of file diff --git a/src/languages/hr/commands/info.json b/src/languages/hr/commands/info.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hr/commands/info.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hr/commands/management.json b/src/languages/hr/commands/management.json deleted file mode 100644 index 21ef26ce2..000000000 --- a/src/languages/hr/commands/management.json +++ /dev/null @@ -1,445 +0,0 @@ -{ - "commandHandlerAborted": "", - "permissionNodesHigher": "", - "permissionNodesCannotAllowEveryone": "", - "permissionNodesInvalidType": "", - "permissionNodesAdd": "", - "permissionNodesNodeNotExists": "", - "permissionNodesCommandNotExists": "", - "permissionNodesRemove": "", - "permissionNodesReset": "", - "permissionNodesShowName": "", - "permissionNodesShowAllow": "", - "permissionNodesShowDeny": "", - "guildInfoTitles": { - "CHANNELS": "", - "MEMBERS": "", - "OTHER": "" - }, - "guildInfoChannels": "", - "guildInfoChannelsAfkChannelText": "", - "guildInfoMembers": "", - "guildInfoOther": "", - "guildInfoBanner": "", - "guildInfoIcon": "", - "guildInfoSplash": "", - "guildInfoDiscoverySplash": "", - "roleInfoTitles": { - "PERMISSIONS": "" - }, - "roleInfoData": "", - "roleInfoAll": "", - "roleInfoNoPermissions": "", - "manageCommandAutoDeleteShowEmpty": "", - "manageCommandAutoDeleteShow": "", - "manageCommandAutoDeleteAdd": "", - "manageCommandAutoDeleteRemove": "", - "manageCommandAutoDeleteRemoveNotset": "", - "manageCommandAutoDeleteReset": "", - "manageCommandChannelShow": "", - "manageCommandChannelShowEmpty": "", - "manageCommandChannelAddAlreadyset": "", - "manageCommandChannelAdd": "", - "manageCommandChannelRemoveNotset": "", - "manageCommandChannelRemove": "", - "manageCommandChannelResetEmpty": "", - "manageCommandChannelReset": "", - "manageReactionRolesShowEmpty": "", - "manageReactionRolesAddChannel": "", - "manageReactionRolesAddPrompt": "", - "manageReactionRolesAddMissing": "", - "manageReactionRolesAdd": "", - "manageReactionRolesRemoveNotExists": "", - "manageReactionRolesRemove": "", - "manageReactionRolesResetEmpty": "", - "manageReactionRolesReset": "", - "configurationEquals": "", - "setIgnoreChannelsSet": "", - "setIgnoreChannelsRemoved": "", - "setImageLogsSet": "", - "setMemberAddLogsSet": "", - "setMemberRemoveLogsSet": "", - "setMessageUpdateLogsSet": "", - "setMessageDeleteLogsSet": "", - "setModLogsSet": "", - "setPrefixSet": "", - "stickyRolesNotExists": "", - "stickyRolesReset": "", - "stickyRolesRemove": "", - "stickyRolesAdd": "", - "stickyRolesShowEmpty": "", - "stickyRolesShowSingle": "", - "createMuteDescription": "", - "createMuteExtended": { - "extendedHelp": "" - }, - "permissionNodesDescription": "", - "permissionNodesExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "managecommandautodeleteDescription": "", - "managecommandautodeleteExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageCommandChannelDescription": "", - "manageCommandChannelExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageReactionRolesDescription": "", - "manageReactionRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "rolesAdded": "", - "rolesAuditlog": "", - "rolesListEmpty": "", - "rolesListTitle": "", - "rolesNotManageable": "", - "rolesNotPublic": "", - "rolesRemoved": "", - "setIgnoreChannelsDescription": "", - "setIgnoreChannelsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setImageLogsDescription": "", - "setImageLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "setMemberAddLogsDescription": "", - "setMemberAddLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMemberRemoveLogsDescription": "", - "setMemberRemoveLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMessageUpdateLogsDescription": "", - "setMessageUpdateLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setMessageDeleteLogsDescription": "", - "setMessageDeleteLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setmodlogsDescription": "", - "setmodlogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setprefixDescription": "", - "setprefixExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "guildInfoDescription": "", - "guildInfoExtended": { - "extendedHelp": "" - }, - "roleInfoDescription": "", - "roleInfoExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "stickyRolesDescription": "", - "stickyRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesDescription": "", - "rolesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/hr/commands/misc.json b/src/languages/hr/commands/misc.json deleted file mode 100644 index 32f64d584..000000000 --- a/src/languages/hr/commands/misc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "snipeEmpty": "", - "snipeTitle": "", - "snipeDescription": "", - "snipeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/hr/commands/moderation.json b/src/languages/hr/commands/moderation.json deleted file mode 100644 index 815d1c788..000000000 --- a/src/languages/hr/commands/moderation.json +++ /dev/null @@ -1,889 +0,0 @@ -{ - "permissions": "", - "permissionsAll": "", - "slowmodeSet": "", - "slowmodeReset": "", - "banNotBannable": "", - "dehoistStarting": "", - "dehoistProgress": "", - "dehoistEmbed": { - "title": "", - "descriptionNoone": "", - "descriptionWithError": "", - "descriptionWithMultipleErrors": "", - "description": "", - "descriptionMultipleMembers": "", - "fieldErrorTitle": "" - }, - "kickNotKickable": "", - "lockdownLock": "", - "lockdownLocking": "", - "lockdownLocked": "", - "lockdownUnlocked": "", - "lockdownOpen": "", - "muteMuted": "", - "muteUserNotMuted": "", - "restrictLowlevel": "", - "pruneAlert_one": "", - "pruneAlert_other": "", - "pruneInvalidPosition": "", - "pruneNoDeletes": "", - "pruneLogHeader": "", - "toggleModerationDmToggledEnabled": "", - "toggleModerationDmToggledDisabled": "", - "moderationOutput_one": "", - "moderationOutput_other": "", - "moderationOutputWithReason_one": "", - "moderationOutputWithReason_other": "", - "moderationFailed_one": "", - "moderationFailed_other": "", - "moderationDmFooter": "", - "moderationDmDescription": "", - "moderationDmDescriptionWithReason": "", - "moderationDmDescriptionWithDuration": "", - "moderationDmDescriptionWithReasonWithDuration": "", - "slowmodeDescription": "", - "slowmodeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "banDescription": "", - "banExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "dehoistDescription": "", - "dehoistExtended": { - "extendedHelp": "", - "reminder": "" - }, - "kickDescription": "", - "kickExtended": { - "usages": [ - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "lockdownDescription": "", - "lockdownExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "muteDescription": "", - "muteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "setNicknameDescription": "", - "setNicknameExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ], - "reminder": "" - }, - "addRoleDescription": "", - "addRoleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "removeroleDescription": "", - "removeroleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "pruneDescription": "", - "pruneExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "permissionsDescription": "", - "permissionsExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ], - "extendedHelp": "" - }, - "restrictAttachmentDescription": "", - "restrictAttachmentExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictEmbedDescription": "", - "restrictEmbedExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictEmojiDescription": "", - "restrictEmojiExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictReactionDescription": "", - "restrictReactionExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictVoiceDescription": "", - "restrictVoiceExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "softBanDescription": "", - "softBanExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "timeoutApplyDescription": "", - "timeoutApplyExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutUndoDescription": "", - "timeoutUndoExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutNotModeratable": "", - "toggleModerationDmDescription": "", - "toggleModerationDmExtended": { - "extendedHelp": "" - }, - "unbanDescription": "", - "unbanExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unmuteDescription": "", - "unmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unrestrictAttachmentDescription": "", - "unrestrictAttachmentExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmbedDescription": "", - "unrestrictEmbedExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmojiDescription": "", - "unrestrictEmojiExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictReactionDescription": "", - "unrestrictReactionExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictVoiceDescription": "", - "unrestrictVoiceExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unwarnDescription": "", - "unwarnExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vmuteDescription": "", - "vmuteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "voiceKickDescription": "", - "voiceKickExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vunmuteDescription": "", - "vunmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "warnDescription": "", - "warnExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/hr/commands/shared.json b/src/languages/hr/commands/shared.json deleted file mode 100644 index ddbb28e7f..000000000 --- a/src/languages/hr/commands/shared.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "deprecatedMessage": "", - "slashOnlyDetailedDescription": { - "extendedHelp": "" - }, - "slashOnlyErrorMessage": "" -} \ No newline at end of file diff --git a/src/languages/hr/commands/system.json b/src/languages/hr/commands/system.json deleted file mode 100644 index e9cfdeec4..000000000 --- a/src/languages/hr/commands/system.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "evalDescription": "", - "evalExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "evalTimeout": "", - "evalError": "", - "dmNotSent": "", - "dmSent": "", - "reboot": "", - "rebootDescription": "", - "rebootExtended": { - "extendedHelp": "", - "reminder": "" - } -} \ No newline at end of file diff --git a/src/languages/hr/commands/tools.json b/src/languages/hr/commands/tools.json deleted file mode 100644 index 01bd03e25..000000000 --- a/src/languages/hr/commands/tools.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "avatarDescription": "", - "avatarExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "" - }, - "avatarNone": "", - "voteDescription": "", - "voteExtended": { - "usages": [ - "" - ], - "examples": [ - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "voteContentNeeded": "", - "voteReactionBlocked": "", - "whoisExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "whoisMemberRoleListAndMore": "" -} \ No newline at end of file diff --git a/src/languages/hr/commands/twitch.json b/src/languages/hr/commands/twitch.json deleted file mode 100644 index 2f12e1b08..000000000 --- a/src/languages/hr/commands/twitch.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "twitchSubscriptionStreamerNotFound": "", - "twitchSubscriptionStatusValues": [ - "", - "" - ], - "twitchSubscriptionInvalidStatus": "", - "twitchSubscriptionAddDuplicated": "", - "twitchSubscriptionAddSuccessOffline": "", - "twitchSubscriptionAddSuccessLive": "", - "twitchSubscriptionAddMessageForOfflineRequired": "", - "twitchSubscriptionRemoveOrResetEmpty": "", - "twitchSubscriptionRemoveStreamerNotSubscribed": "", - "twitchSubscriptionRemoveNotToProvidedChannel": "", - "twitchSubscriptionRemoveStreamerStatusNotMatch": "", - "twitchSubscriptionRemoveSuccessOffline": "", - "twitchSubscriptionRemoveSuccessLive": "", - "twitchSubscriptionResetSuccess_one": "", - "twitchSubscriptionResetSuccess_other": "", - "twitchSubscriptionShowStreamerNotSubscribed": "", - "twitchSubscriptionShowStatus": { - "live": "", - "offline": "" - }, - "twitchSubscriptionShowUnknownUser": "", - "twitchSubscriptionDescription": "", - "twitchSubscriptionExtended": { - "usages": [ - "", - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/hr/commands/whois.json b/src/languages/hr/commands/whois.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hr/commands/whois.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hr/errors.json b/src/languages/hr/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hr/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hr/events/errors.json b/src/languages/hr/events/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hr/events/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hr/events/guilds-logs.json b/src/languages/hr/events/guilds-logs.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hr/events/guilds-logs.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hr/events/guilds-members.json b/src/languages/hr/events/guilds-members.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hr/events/guilds-members.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hr/events/messages.json b/src/languages/hr/events/messages.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hr/events/messages.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hr/events/moderation.json b/src/languages/hr/events/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hr/events/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hr/events/noMentionSpam.json b/src/languages/hr/events/noMentionSpam.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hr/events/noMentionSpam.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hr/events/reactions.json b/src/languages/hr/events/reactions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hr/events/reactions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hr/events/twitch.json b/src/languages/hr/events/twitch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hr/events/twitch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hr/fuzzySearch.json b/src/languages/hr/fuzzySearch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hr/fuzzySearch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hr/globals.json b/src/languages/hr/globals.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hr/globals.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hr/guilds.json b/src/languages/hr/guilds.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hr/guilds.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hr/humanLevels.json b/src/languages/hr/humanLevels.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hr/humanLevels.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hr/moderation.json b/src/languages/hr/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hr/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hr/moderationActions.json b/src/languages/hr/moderationActions.json deleted file mode 100644 index 4c440ae54..000000000 --- a/src/languages/hr/moderationActions.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "actions": { - "addRole": "", - "ban": "", - "kick": "", - "mute": "", - "removeRole": "", - "restrictedAttachment": "", - "restrictedEmbed": "", - "restrictedEmoji": "", - "restrictedReact": "", - "restrictedVoice": "", - "setNickname": "", - "softban": "", - "vkick": "", - "vmute": "", - "warning": "" - }, - "actionCannotManageRoles": "", - "actionRoleNotConfigured": "", - "actionRoleHigherPosition": "", - "actionRoleManaged": "", - "applyNoReason": "", - "applyReason": "", - "requiredMember": "", - "revokeNoReason": "", - "revokeReason": "", - "setNicknameNoReasonRemoved": "", - "setNicknameNoReasonSet": "", - "setNicknameRemoved": "", - "setNicknameSet": "", - "setupMuteExists": "", - "setupTooManyRoles": "", - "sharedRoleSetupAsk": "", - "sharedRoleSetupNoMessage": "", - "sharedRoleSetupExisting": "", - "sharedRoleSetupExistingName": "", - "sharedRoleSetupNew": "", - "softbanNoReason": "", - "softbanReason": "", - "unSoftbanNoReason": "", - "unSoftbanReason": "" -} \ No newline at end of file diff --git a/src/languages/hr/permissions.json b/src/languages/hr/permissions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hr/permissions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hr/preconditions.json b/src/languages/hr/preconditions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hr/preconditions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hr/selfModeration.json b/src/languages/hr/selfModeration.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hr/selfModeration.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hr/serializers.json b/src/languages/hr/serializers.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hr/serializers.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hr/settings.json b/src/languages/hr/settings.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hr/settings.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hr/system.json b/src/languages/hr/system.json deleted file mode 100644 index 073b9b683..000000000 --- a/src/languages/hr/system.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "discordAbortError": "", - "fetchBansFail": "", - "helpTitles": { - "aliases": "", - "usages": "", - "extendedHelp": "", - "explainedUsage": "", - "possibleFormats": "", - "examples": "", - "reminders": "" - }, - "jumpTo": "", - "loading": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "prefixReminder": "" -} \ No newline at end of file diff --git a/src/languages/hu/arguments.json b/src/languages/hu/arguments.json deleted file mode 100644 index a7befa6f3..000000000 --- a/src/languages/hu/arguments.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "boolean_one": "", - "boolean_other": "", - "booleanError": "", - "booleanDisabled": "", - "booleanEnabled": "", - "booleanFalseOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "booleanTrueOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "caseNoEntries": "", - "caseUnknownEntry": "", - "caseNotInThisGuild": "", - "caseLatestOptions": [ - "", - "" - ], - "categoryChannelError": "", - "channelError": "", - "command": "", - "commandMatch": "", - "dateError": "", - "dateFormats": "", - "dateTooEarly": "", - "dateTooFar": "", - "dmChannelError": "", - "duration": "", - "durationFormats": "", - "emojiError": "", - "floatError": "", - "floatTooLarge": "", - "floatTooSmall": "", - "guildChannelError": "", - "guildChannelMismatchingError": "", - "guildChannelMissingGuildError": "", - "guildPrivateThreadChannelError": "", - "guildPublicThreadChannelError": "", - "guildStageVoiceChannelError": "", - "guildTextChannelError": "", - "guildThreadChannelError": "", - "guildVoiceChannelError": "", - "hyperlinkError": "", - "integerError": "", - "integerTooLarge": "", - "integerTooSmall": "", - "invite": "", - "language": "", - "memberError": "", - "memberMissingGuild": "", - "messageError": "", - "missing": "", - "newsChannel": "", - "numberError": "", - "numberTooLarge": "", - "numberTooSmall": "", - "piece": "", - "rangeInvalid": "", - "rangeMax_other": "", - "rangeMax_one": "", - "resetPossibles": [ - "", - "" - ], - "roleError": "", - "roleMissingGuild": "", - "snowflake": "", - "store": "", - "stringTooLong": "", - "stringTooShort": "", - "time": "", - "timeSpan": "", - "timeSpanTooBig": "", - "timeSpanTooSmall": "", - "tooFewWinners": "", - "tooManyWinners": "", - "unavailable": "", - "userError": "", - "enumEmptyError": "", - "enumError": "" -} \ No newline at end of file diff --git a/src/languages/hu/assertions.json b/src/languages/hu/assertions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hu/assertions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hu/commands/admin.json b/src/languages/hu/commands/admin.json deleted file mode 100644 index 444f39c28..000000000 --- a/src/languages/hu/commands/admin.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "confUpdated": "", - "confGetNoExt": "", - "confGet": "", - "confReset": "", - "confNochange": "", - "confServerDescription": "", - "confServerExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "confServer": "", - "confDashboardOnlyKey": "", - "confSettingNotSet": "", - "rolesetDescription": "", - "rolesetExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesetCreated": "", - "rolesetAdded": "", - "rolesetRemoved": "", - "rolesetResetEmpty": "", - "rolesetResetAll": "", - "rolesetResetNotExists": "", - "rolesetResetGroup": "", - "rolesetUpdated": "", - "rolesetNoRolesets": "", - "confMenuRenderAtFolder": "", - "confMenuRenderAtPiece": "", - "confMenuRenderNokeys": "", - "confMenuRenderSelect": "", - "confMenuRenderUpdate": "", - "confMenuRenderRemove": "", - "confMenuRenderReset": "", - "confMenuRenderUndo": "", - "confMenuRenderCvalue": "", - "confMenuRenderBack": "", - "confMenuInvalidKey": "", - "confMenuInvalidAction": "", - "confMenuSaved": "" -} \ No newline at end of file diff --git a/src/languages/hu/commands/animal.json b/src/languages/hu/commands/animal.json deleted file mode 100644 index 6d00e57af..000000000 --- a/src/languages/hu/commands/animal.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "bunnyDescription": "", - "bunnyExtended": { - "extendedHelp": "" - }, - "bunnyEmbedData": { - "title": "", - "source": "" - }, - "dogDescription": "", - "dogExtended": { - "extendedHelp": "" - }, - "foxDescription": "", - "foxExtended": { - "extendedHelp": "" - }, - "kittyDescription": "", - "kittyExtended": { - "extendedHelp": "" - }, - "shibeDescription": "", - "shibeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/hu/commands/auto-moderation.json b/src/languages/hu/commands/auto-moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hu/commands/auto-moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hu/commands/case.json b/src/languages/hu/commands/case.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hu/commands/case.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hu/commands/fun.json b/src/languages/hu/commands/fun.json deleted file mode 100644 index 7892e327d..000000000 --- a/src/languages/hu/commands/fun.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "escaperopeDescription": "", - "escaperopeExtended": { - "extendedHelp": "" - }, - "escaperopeOutput": "" -} \ No newline at end of file diff --git a/src/languages/hu/commands/game.json b/src/languages/hu/commands/game.json deleted file mode 100644 index 8075ca93c..000000000 --- a/src/languages/hu/commands/game.json +++ /dev/null @@ -1,447 +0,0 @@ -{ - "c4Description": "", - "c4Extended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "c4Prompt": "", - "gamesBot": "", - "gamesNoPlayers": "", - "gamesProgress": "", - "gamesPromptDeny": "", - "gamesRepeat": "", - "gamesSelf": "", - "gamesTooManyOrFew": "", - "hgBloodbath": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgDay": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgNight": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hungerGamesDescription": "", - "hungerGamesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "examples": [ - "" - ], - "reminder": "" - }, - "hungerGamesResultDeaths_one": "", - "hungerGamesResultDeaths_other": "", - "hungerGamesResultHeaderBloodbath": "", - "hungerGamesResultHeaderMoon": "", - "hungerGamesResultHeaderSun": "", - "hungerGamesResultProceed": "", - "hungerGamesStop": "", - "hungerGamesWinner": "", - "ticTacToeDescription": "", - "ticTacToeDraw": "", - "ticTacToeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "ticTacToePrompt": "", - "ticTacToeTurn": "", - "ticTacToeWinner": "", - "triviaActiveGame": "", - "triviaDescription": "", - "triviaEmbedTitles": { - "difficulty": "", - "trivia": "" - }, - "triviaExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "triviaIncorrect": "", - "triviaInvalidCategory": "", - "triviaNoAnswer": "", - "triviaWinner": "" -} \ No newline at end of file diff --git a/src/languages/hu/commands/general.json b/src/languages/hu/commands/general.json deleted file mode 100644 index 5e16f992d..000000000 --- a/src/languages/hu/commands/general.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "helpAllFlag": "", - "helpCommandCount_one": "", - "helpCommandCount_other": "", - "helpData": { - "footer": "", - "title": "" - }, - "helpDescription": "", - "helpExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "reminder": "", - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "helpDm": "", - "helpNodm": "", - "v7Description": "", - "v7Extended": { - "extendedHelp": "" - }, - "v7Message": "", - "v7NayreMessage": "" -} \ No newline at end of file diff --git a/src/languages/hu/commands/info.json b/src/languages/hu/commands/info.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hu/commands/info.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hu/commands/management.json b/src/languages/hu/commands/management.json deleted file mode 100644 index 21ef26ce2..000000000 --- a/src/languages/hu/commands/management.json +++ /dev/null @@ -1,445 +0,0 @@ -{ - "commandHandlerAborted": "", - "permissionNodesHigher": "", - "permissionNodesCannotAllowEveryone": "", - "permissionNodesInvalidType": "", - "permissionNodesAdd": "", - "permissionNodesNodeNotExists": "", - "permissionNodesCommandNotExists": "", - "permissionNodesRemove": "", - "permissionNodesReset": "", - "permissionNodesShowName": "", - "permissionNodesShowAllow": "", - "permissionNodesShowDeny": "", - "guildInfoTitles": { - "CHANNELS": "", - "MEMBERS": "", - "OTHER": "" - }, - "guildInfoChannels": "", - "guildInfoChannelsAfkChannelText": "", - "guildInfoMembers": "", - "guildInfoOther": "", - "guildInfoBanner": "", - "guildInfoIcon": "", - "guildInfoSplash": "", - "guildInfoDiscoverySplash": "", - "roleInfoTitles": { - "PERMISSIONS": "" - }, - "roleInfoData": "", - "roleInfoAll": "", - "roleInfoNoPermissions": "", - "manageCommandAutoDeleteShowEmpty": "", - "manageCommandAutoDeleteShow": "", - "manageCommandAutoDeleteAdd": "", - "manageCommandAutoDeleteRemove": "", - "manageCommandAutoDeleteRemoveNotset": "", - "manageCommandAutoDeleteReset": "", - "manageCommandChannelShow": "", - "manageCommandChannelShowEmpty": "", - "manageCommandChannelAddAlreadyset": "", - "manageCommandChannelAdd": "", - "manageCommandChannelRemoveNotset": "", - "manageCommandChannelRemove": "", - "manageCommandChannelResetEmpty": "", - "manageCommandChannelReset": "", - "manageReactionRolesShowEmpty": "", - "manageReactionRolesAddChannel": "", - "manageReactionRolesAddPrompt": "", - "manageReactionRolesAddMissing": "", - "manageReactionRolesAdd": "", - "manageReactionRolesRemoveNotExists": "", - "manageReactionRolesRemove": "", - "manageReactionRolesResetEmpty": "", - "manageReactionRolesReset": "", - "configurationEquals": "", - "setIgnoreChannelsSet": "", - "setIgnoreChannelsRemoved": "", - "setImageLogsSet": "", - "setMemberAddLogsSet": "", - "setMemberRemoveLogsSet": "", - "setMessageUpdateLogsSet": "", - "setMessageDeleteLogsSet": "", - "setModLogsSet": "", - "setPrefixSet": "", - "stickyRolesNotExists": "", - "stickyRolesReset": "", - "stickyRolesRemove": "", - "stickyRolesAdd": "", - "stickyRolesShowEmpty": "", - "stickyRolesShowSingle": "", - "createMuteDescription": "", - "createMuteExtended": { - "extendedHelp": "" - }, - "permissionNodesDescription": "", - "permissionNodesExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "managecommandautodeleteDescription": "", - "managecommandautodeleteExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageCommandChannelDescription": "", - "manageCommandChannelExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageReactionRolesDescription": "", - "manageReactionRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "rolesAdded": "", - "rolesAuditlog": "", - "rolesListEmpty": "", - "rolesListTitle": "", - "rolesNotManageable": "", - "rolesNotPublic": "", - "rolesRemoved": "", - "setIgnoreChannelsDescription": "", - "setIgnoreChannelsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setImageLogsDescription": "", - "setImageLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "setMemberAddLogsDescription": "", - "setMemberAddLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMemberRemoveLogsDescription": "", - "setMemberRemoveLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMessageUpdateLogsDescription": "", - "setMessageUpdateLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setMessageDeleteLogsDescription": "", - "setMessageDeleteLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setmodlogsDescription": "", - "setmodlogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setprefixDescription": "", - "setprefixExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "guildInfoDescription": "", - "guildInfoExtended": { - "extendedHelp": "" - }, - "roleInfoDescription": "", - "roleInfoExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "stickyRolesDescription": "", - "stickyRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesDescription": "", - "rolesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/hu/commands/misc.json b/src/languages/hu/commands/misc.json deleted file mode 100644 index 32f64d584..000000000 --- a/src/languages/hu/commands/misc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "snipeEmpty": "", - "snipeTitle": "", - "snipeDescription": "", - "snipeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/hu/commands/moderation.json b/src/languages/hu/commands/moderation.json deleted file mode 100644 index 815d1c788..000000000 --- a/src/languages/hu/commands/moderation.json +++ /dev/null @@ -1,889 +0,0 @@ -{ - "permissions": "", - "permissionsAll": "", - "slowmodeSet": "", - "slowmodeReset": "", - "banNotBannable": "", - "dehoistStarting": "", - "dehoistProgress": "", - "dehoistEmbed": { - "title": "", - "descriptionNoone": "", - "descriptionWithError": "", - "descriptionWithMultipleErrors": "", - "description": "", - "descriptionMultipleMembers": "", - "fieldErrorTitle": "" - }, - "kickNotKickable": "", - "lockdownLock": "", - "lockdownLocking": "", - "lockdownLocked": "", - "lockdownUnlocked": "", - "lockdownOpen": "", - "muteMuted": "", - "muteUserNotMuted": "", - "restrictLowlevel": "", - "pruneAlert_one": "", - "pruneAlert_other": "", - "pruneInvalidPosition": "", - "pruneNoDeletes": "", - "pruneLogHeader": "", - "toggleModerationDmToggledEnabled": "", - "toggleModerationDmToggledDisabled": "", - "moderationOutput_one": "", - "moderationOutput_other": "", - "moderationOutputWithReason_one": "", - "moderationOutputWithReason_other": "", - "moderationFailed_one": "", - "moderationFailed_other": "", - "moderationDmFooter": "", - "moderationDmDescription": "", - "moderationDmDescriptionWithReason": "", - "moderationDmDescriptionWithDuration": "", - "moderationDmDescriptionWithReasonWithDuration": "", - "slowmodeDescription": "", - "slowmodeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "banDescription": "", - "banExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "dehoistDescription": "", - "dehoistExtended": { - "extendedHelp": "", - "reminder": "" - }, - "kickDescription": "", - "kickExtended": { - "usages": [ - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "lockdownDescription": "", - "lockdownExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "muteDescription": "", - "muteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "setNicknameDescription": "", - "setNicknameExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ], - "reminder": "" - }, - "addRoleDescription": "", - "addRoleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "removeroleDescription": "", - "removeroleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "pruneDescription": "", - "pruneExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "permissionsDescription": "", - "permissionsExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ], - "extendedHelp": "" - }, - "restrictAttachmentDescription": "", - "restrictAttachmentExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictEmbedDescription": "", - "restrictEmbedExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictEmojiDescription": "", - "restrictEmojiExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictReactionDescription": "", - "restrictReactionExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictVoiceDescription": "", - "restrictVoiceExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "softBanDescription": "", - "softBanExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "timeoutApplyDescription": "", - "timeoutApplyExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutUndoDescription": "", - "timeoutUndoExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutNotModeratable": "", - "toggleModerationDmDescription": "", - "toggleModerationDmExtended": { - "extendedHelp": "" - }, - "unbanDescription": "", - "unbanExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unmuteDescription": "", - "unmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unrestrictAttachmentDescription": "", - "unrestrictAttachmentExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmbedDescription": "", - "unrestrictEmbedExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmojiDescription": "", - "unrestrictEmojiExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictReactionDescription": "", - "unrestrictReactionExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictVoiceDescription": "", - "unrestrictVoiceExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unwarnDescription": "", - "unwarnExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vmuteDescription": "", - "vmuteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "voiceKickDescription": "", - "voiceKickExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vunmuteDescription": "", - "vunmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "warnDescription": "", - "warnExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/hu/commands/shared.json b/src/languages/hu/commands/shared.json deleted file mode 100644 index ddbb28e7f..000000000 --- a/src/languages/hu/commands/shared.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "deprecatedMessage": "", - "slashOnlyDetailedDescription": { - "extendedHelp": "" - }, - "slashOnlyErrorMessage": "" -} \ No newline at end of file diff --git a/src/languages/hu/commands/system.json b/src/languages/hu/commands/system.json deleted file mode 100644 index e9cfdeec4..000000000 --- a/src/languages/hu/commands/system.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "evalDescription": "", - "evalExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "evalTimeout": "", - "evalError": "", - "dmNotSent": "", - "dmSent": "", - "reboot": "", - "rebootDescription": "", - "rebootExtended": { - "extendedHelp": "", - "reminder": "" - } -} \ No newline at end of file diff --git a/src/languages/hu/commands/tools.json b/src/languages/hu/commands/tools.json deleted file mode 100644 index 01bd03e25..000000000 --- a/src/languages/hu/commands/tools.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "avatarDescription": "", - "avatarExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "" - }, - "avatarNone": "", - "voteDescription": "", - "voteExtended": { - "usages": [ - "" - ], - "examples": [ - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "voteContentNeeded": "", - "voteReactionBlocked": "", - "whoisExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "whoisMemberRoleListAndMore": "" -} \ No newline at end of file diff --git a/src/languages/hu/commands/twitch.json b/src/languages/hu/commands/twitch.json deleted file mode 100644 index 2f12e1b08..000000000 --- a/src/languages/hu/commands/twitch.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "twitchSubscriptionStreamerNotFound": "", - "twitchSubscriptionStatusValues": [ - "", - "" - ], - "twitchSubscriptionInvalidStatus": "", - "twitchSubscriptionAddDuplicated": "", - "twitchSubscriptionAddSuccessOffline": "", - "twitchSubscriptionAddSuccessLive": "", - "twitchSubscriptionAddMessageForOfflineRequired": "", - "twitchSubscriptionRemoveOrResetEmpty": "", - "twitchSubscriptionRemoveStreamerNotSubscribed": "", - "twitchSubscriptionRemoveNotToProvidedChannel": "", - "twitchSubscriptionRemoveStreamerStatusNotMatch": "", - "twitchSubscriptionRemoveSuccessOffline": "", - "twitchSubscriptionRemoveSuccessLive": "", - "twitchSubscriptionResetSuccess_one": "", - "twitchSubscriptionResetSuccess_other": "", - "twitchSubscriptionShowStreamerNotSubscribed": "", - "twitchSubscriptionShowStatus": { - "live": "", - "offline": "" - }, - "twitchSubscriptionShowUnknownUser": "", - "twitchSubscriptionDescription": "", - "twitchSubscriptionExtended": { - "usages": [ - "", - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/hu/commands/whois.json b/src/languages/hu/commands/whois.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hu/commands/whois.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hu/errors.json b/src/languages/hu/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hu/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hu/events/errors.json b/src/languages/hu/events/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hu/events/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hu/events/guilds-logs.json b/src/languages/hu/events/guilds-logs.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hu/events/guilds-logs.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hu/events/guilds-members.json b/src/languages/hu/events/guilds-members.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hu/events/guilds-members.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hu/events/messages.json b/src/languages/hu/events/messages.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hu/events/messages.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hu/events/moderation.json b/src/languages/hu/events/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hu/events/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hu/events/noMentionSpam.json b/src/languages/hu/events/noMentionSpam.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hu/events/noMentionSpam.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hu/events/reactions.json b/src/languages/hu/events/reactions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hu/events/reactions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hu/events/twitch.json b/src/languages/hu/events/twitch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hu/events/twitch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hu/fuzzySearch.json b/src/languages/hu/fuzzySearch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hu/fuzzySearch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hu/globals.json b/src/languages/hu/globals.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hu/globals.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hu/guilds.json b/src/languages/hu/guilds.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hu/guilds.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hu/humanLevels.json b/src/languages/hu/humanLevels.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hu/humanLevels.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hu/moderation.json b/src/languages/hu/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hu/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hu/moderationActions.json b/src/languages/hu/moderationActions.json deleted file mode 100644 index 4c440ae54..000000000 --- a/src/languages/hu/moderationActions.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "actions": { - "addRole": "", - "ban": "", - "kick": "", - "mute": "", - "removeRole": "", - "restrictedAttachment": "", - "restrictedEmbed": "", - "restrictedEmoji": "", - "restrictedReact": "", - "restrictedVoice": "", - "setNickname": "", - "softban": "", - "vkick": "", - "vmute": "", - "warning": "" - }, - "actionCannotManageRoles": "", - "actionRoleNotConfigured": "", - "actionRoleHigherPosition": "", - "actionRoleManaged": "", - "applyNoReason": "", - "applyReason": "", - "requiredMember": "", - "revokeNoReason": "", - "revokeReason": "", - "setNicknameNoReasonRemoved": "", - "setNicknameNoReasonSet": "", - "setNicknameRemoved": "", - "setNicknameSet": "", - "setupMuteExists": "", - "setupTooManyRoles": "", - "sharedRoleSetupAsk": "", - "sharedRoleSetupNoMessage": "", - "sharedRoleSetupExisting": "", - "sharedRoleSetupExistingName": "", - "sharedRoleSetupNew": "", - "softbanNoReason": "", - "softbanReason": "", - "unSoftbanNoReason": "", - "unSoftbanReason": "" -} \ No newline at end of file diff --git a/src/languages/hu/permissions.json b/src/languages/hu/permissions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hu/permissions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hu/preconditions.json b/src/languages/hu/preconditions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hu/preconditions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hu/selfModeration.json b/src/languages/hu/selfModeration.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hu/selfModeration.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hu/serializers.json b/src/languages/hu/serializers.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hu/serializers.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hu/settings.json b/src/languages/hu/settings.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/hu/settings.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/hu/system.json b/src/languages/hu/system.json deleted file mode 100644 index 073b9b683..000000000 --- a/src/languages/hu/system.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "discordAbortError": "", - "fetchBansFail": "", - "helpTitles": { - "aliases": "", - "usages": "", - "extendedHelp": "", - "explainedUsage": "", - "possibleFormats": "", - "examples": "", - "reminders": "" - }, - "jumpTo": "", - "loading": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "prefixReminder": "" -} \ No newline at end of file diff --git a/src/languages/id/arguments.json b/src/languages/id/arguments.json deleted file mode 100644 index a7befa6f3..000000000 --- a/src/languages/id/arguments.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "boolean_one": "", - "boolean_other": "", - "booleanError": "", - "booleanDisabled": "", - "booleanEnabled": "", - "booleanFalseOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "booleanTrueOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "caseNoEntries": "", - "caseUnknownEntry": "", - "caseNotInThisGuild": "", - "caseLatestOptions": [ - "", - "" - ], - "categoryChannelError": "", - "channelError": "", - "command": "", - "commandMatch": "", - "dateError": "", - "dateFormats": "", - "dateTooEarly": "", - "dateTooFar": "", - "dmChannelError": "", - "duration": "", - "durationFormats": "", - "emojiError": "", - "floatError": "", - "floatTooLarge": "", - "floatTooSmall": "", - "guildChannelError": "", - "guildChannelMismatchingError": "", - "guildChannelMissingGuildError": "", - "guildPrivateThreadChannelError": "", - "guildPublicThreadChannelError": "", - "guildStageVoiceChannelError": "", - "guildTextChannelError": "", - "guildThreadChannelError": "", - "guildVoiceChannelError": "", - "hyperlinkError": "", - "integerError": "", - "integerTooLarge": "", - "integerTooSmall": "", - "invite": "", - "language": "", - "memberError": "", - "memberMissingGuild": "", - "messageError": "", - "missing": "", - "newsChannel": "", - "numberError": "", - "numberTooLarge": "", - "numberTooSmall": "", - "piece": "", - "rangeInvalid": "", - "rangeMax_other": "", - "rangeMax_one": "", - "resetPossibles": [ - "", - "" - ], - "roleError": "", - "roleMissingGuild": "", - "snowflake": "", - "store": "", - "stringTooLong": "", - "stringTooShort": "", - "time": "", - "timeSpan": "", - "timeSpanTooBig": "", - "timeSpanTooSmall": "", - "tooFewWinners": "", - "tooManyWinners": "", - "unavailable": "", - "userError": "", - "enumEmptyError": "", - "enumError": "" -} \ No newline at end of file diff --git a/src/languages/id/assertions.json b/src/languages/id/assertions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/id/assertions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/id/commands/admin.json b/src/languages/id/commands/admin.json deleted file mode 100644 index 444f39c28..000000000 --- a/src/languages/id/commands/admin.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "confUpdated": "", - "confGetNoExt": "", - "confGet": "", - "confReset": "", - "confNochange": "", - "confServerDescription": "", - "confServerExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "confServer": "", - "confDashboardOnlyKey": "", - "confSettingNotSet": "", - "rolesetDescription": "", - "rolesetExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesetCreated": "", - "rolesetAdded": "", - "rolesetRemoved": "", - "rolesetResetEmpty": "", - "rolesetResetAll": "", - "rolesetResetNotExists": "", - "rolesetResetGroup": "", - "rolesetUpdated": "", - "rolesetNoRolesets": "", - "confMenuRenderAtFolder": "", - "confMenuRenderAtPiece": "", - "confMenuRenderNokeys": "", - "confMenuRenderSelect": "", - "confMenuRenderUpdate": "", - "confMenuRenderRemove": "", - "confMenuRenderReset": "", - "confMenuRenderUndo": "", - "confMenuRenderCvalue": "", - "confMenuRenderBack": "", - "confMenuInvalidKey": "", - "confMenuInvalidAction": "", - "confMenuSaved": "" -} \ No newline at end of file diff --git a/src/languages/id/commands/animal.json b/src/languages/id/commands/animal.json deleted file mode 100644 index 6d00e57af..000000000 --- a/src/languages/id/commands/animal.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "bunnyDescription": "", - "bunnyExtended": { - "extendedHelp": "" - }, - "bunnyEmbedData": { - "title": "", - "source": "" - }, - "dogDescription": "", - "dogExtended": { - "extendedHelp": "" - }, - "foxDescription": "", - "foxExtended": { - "extendedHelp": "" - }, - "kittyDescription": "", - "kittyExtended": { - "extendedHelp": "" - }, - "shibeDescription": "", - "shibeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/id/commands/auto-moderation.json b/src/languages/id/commands/auto-moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/id/commands/auto-moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/id/commands/case.json b/src/languages/id/commands/case.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/id/commands/case.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/id/commands/fun.json b/src/languages/id/commands/fun.json deleted file mode 100644 index 7892e327d..000000000 --- a/src/languages/id/commands/fun.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "escaperopeDescription": "", - "escaperopeExtended": { - "extendedHelp": "" - }, - "escaperopeOutput": "" -} \ No newline at end of file diff --git a/src/languages/id/commands/game.json b/src/languages/id/commands/game.json deleted file mode 100644 index 8075ca93c..000000000 --- a/src/languages/id/commands/game.json +++ /dev/null @@ -1,447 +0,0 @@ -{ - "c4Description": "", - "c4Extended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "c4Prompt": "", - "gamesBot": "", - "gamesNoPlayers": "", - "gamesProgress": "", - "gamesPromptDeny": "", - "gamesRepeat": "", - "gamesSelf": "", - "gamesTooManyOrFew": "", - "hgBloodbath": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgDay": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgNight": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hungerGamesDescription": "", - "hungerGamesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "examples": [ - "" - ], - "reminder": "" - }, - "hungerGamesResultDeaths_one": "", - "hungerGamesResultDeaths_other": "", - "hungerGamesResultHeaderBloodbath": "", - "hungerGamesResultHeaderMoon": "", - "hungerGamesResultHeaderSun": "", - "hungerGamesResultProceed": "", - "hungerGamesStop": "", - "hungerGamesWinner": "", - "ticTacToeDescription": "", - "ticTacToeDraw": "", - "ticTacToeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "ticTacToePrompt": "", - "ticTacToeTurn": "", - "ticTacToeWinner": "", - "triviaActiveGame": "", - "triviaDescription": "", - "triviaEmbedTitles": { - "difficulty": "", - "trivia": "" - }, - "triviaExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "triviaIncorrect": "", - "triviaInvalidCategory": "", - "triviaNoAnswer": "", - "triviaWinner": "" -} \ No newline at end of file diff --git a/src/languages/id/commands/general.json b/src/languages/id/commands/general.json deleted file mode 100644 index 5e16f992d..000000000 --- a/src/languages/id/commands/general.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "helpAllFlag": "", - "helpCommandCount_one": "", - "helpCommandCount_other": "", - "helpData": { - "footer": "", - "title": "" - }, - "helpDescription": "", - "helpExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "reminder": "", - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "helpDm": "", - "helpNodm": "", - "v7Description": "", - "v7Extended": { - "extendedHelp": "" - }, - "v7Message": "", - "v7NayreMessage": "" -} \ No newline at end of file diff --git a/src/languages/id/commands/info.json b/src/languages/id/commands/info.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/id/commands/info.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/id/commands/management.json b/src/languages/id/commands/management.json deleted file mode 100644 index 21ef26ce2..000000000 --- a/src/languages/id/commands/management.json +++ /dev/null @@ -1,445 +0,0 @@ -{ - "commandHandlerAborted": "", - "permissionNodesHigher": "", - "permissionNodesCannotAllowEveryone": "", - "permissionNodesInvalidType": "", - "permissionNodesAdd": "", - "permissionNodesNodeNotExists": "", - "permissionNodesCommandNotExists": "", - "permissionNodesRemove": "", - "permissionNodesReset": "", - "permissionNodesShowName": "", - "permissionNodesShowAllow": "", - "permissionNodesShowDeny": "", - "guildInfoTitles": { - "CHANNELS": "", - "MEMBERS": "", - "OTHER": "" - }, - "guildInfoChannels": "", - "guildInfoChannelsAfkChannelText": "", - "guildInfoMembers": "", - "guildInfoOther": "", - "guildInfoBanner": "", - "guildInfoIcon": "", - "guildInfoSplash": "", - "guildInfoDiscoverySplash": "", - "roleInfoTitles": { - "PERMISSIONS": "" - }, - "roleInfoData": "", - "roleInfoAll": "", - "roleInfoNoPermissions": "", - "manageCommandAutoDeleteShowEmpty": "", - "manageCommandAutoDeleteShow": "", - "manageCommandAutoDeleteAdd": "", - "manageCommandAutoDeleteRemove": "", - "manageCommandAutoDeleteRemoveNotset": "", - "manageCommandAutoDeleteReset": "", - "manageCommandChannelShow": "", - "manageCommandChannelShowEmpty": "", - "manageCommandChannelAddAlreadyset": "", - "manageCommandChannelAdd": "", - "manageCommandChannelRemoveNotset": "", - "manageCommandChannelRemove": "", - "manageCommandChannelResetEmpty": "", - "manageCommandChannelReset": "", - "manageReactionRolesShowEmpty": "", - "manageReactionRolesAddChannel": "", - "manageReactionRolesAddPrompt": "", - "manageReactionRolesAddMissing": "", - "manageReactionRolesAdd": "", - "manageReactionRolesRemoveNotExists": "", - "manageReactionRolesRemove": "", - "manageReactionRolesResetEmpty": "", - "manageReactionRolesReset": "", - "configurationEquals": "", - "setIgnoreChannelsSet": "", - "setIgnoreChannelsRemoved": "", - "setImageLogsSet": "", - "setMemberAddLogsSet": "", - "setMemberRemoveLogsSet": "", - "setMessageUpdateLogsSet": "", - "setMessageDeleteLogsSet": "", - "setModLogsSet": "", - "setPrefixSet": "", - "stickyRolesNotExists": "", - "stickyRolesReset": "", - "stickyRolesRemove": "", - "stickyRolesAdd": "", - "stickyRolesShowEmpty": "", - "stickyRolesShowSingle": "", - "createMuteDescription": "", - "createMuteExtended": { - "extendedHelp": "" - }, - "permissionNodesDescription": "", - "permissionNodesExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "managecommandautodeleteDescription": "", - "managecommandautodeleteExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageCommandChannelDescription": "", - "manageCommandChannelExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageReactionRolesDescription": "", - "manageReactionRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "rolesAdded": "", - "rolesAuditlog": "", - "rolesListEmpty": "", - "rolesListTitle": "", - "rolesNotManageable": "", - "rolesNotPublic": "", - "rolesRemoved": "", - "setIgnoreChannelsDescription": "", - "setIgnoreChannelsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setImageLogsDescription": "", - "setImageLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "setMemberAddLogsDescription": "", - "setMemberAddLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMemberRemoveLogsDescription": "", - "setMemberRemoveLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMessageUpdateLogsDescription": "", - "setMessageUpdateLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setMessageDeleteLogsDescription": "", - "setMessageDeleteLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setmodlogsDescription": "", - "setmodlogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setprefixDescription": "", - "setprefixExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "guildInfoDescription": "", - "guildInfoExtended": { - "extendedHelp": "" - }, - "roleInfoDescription": "", - "roleInfoExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "stickyRolesDescription": "", - "stickyRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesDescription": "", - "rolesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/id/commands/misc.json b/src/languages/id/commands/misc.json deleted file mode 100644 index 32f64d584..000000000 --- a/src/languages/id/commands/misc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "snipeEmpty": "", - "snipeTitle": "", - "snipeDescription": "", - "snipeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/id/commands/moderation.json b/src/languages/id/commands/moderation.json deleted file mode 100644 index 815d1c788..000000000 --- a/src/languages/id/commands/moderation.json +++ /dev/null @@ -1,889 +0,0 @@ -{ - "permissions": "", - "permissionsAll": "", - "slowmodeSet": "", - "slowmodeReset": "", - "banNotBannable": "", - "dehoistStarting": "", - "dehoistProgress": "", - "dehoistEmbed": { - "title": "", - "descriptionNoone": "", - "descriptionWithError": "", - "descriptionWithMultipleErrors": "", - "description": "", - "descriptionMultipleMembers": "", - "fieldErrorTitle": "" - }, - "kickNotKickable": "", - "lockdownLock": "", - "lockdownLocking": "", - "lockdownLocked": "", - "lockdownUnlocked": "", - "lockdownOpen": "", - "muteMuted": "", - "muteUserNotMuted": "", - "restrictLowlevel": "", - "pruneAlert_one": "", - "pruneAlert_other": "", - "pruneInvalidPosition": "", - "pruneNoDeletes": "", - "pruneLogHeader": "", - "toggleModerationDmToggledEnabled": "", - "toggleModerationDmToggledDisabled": "", - "moderationOutput_one": "", - "moderationOutput_other": "", - "moderationOutputWithReason_one": "", - "moderationOutputWithReason_other": "", - "moderationFailed_one": "", - "moderationFailed_other": "", - "moderationDmFooter": "", - "moderationDmDescription": "", - "moderationDmDescriptionWithReason": "", - "moderationDmDescriptionWithDuration": "", - "moderationDmDescriptionWithReasonWithDuration": "", - "slowmodeDescription": "", - "slowmodeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "banDescription": "", - "banExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "dehoistDescription": "", - "dehoistExtended": { - "extendedHelp": "", - "reminder": "" - }, - "kickDescription": "", - "kickExtended": { - "usages": [ - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "lockdownDescription": "", - "lockdownExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "muteDescription": "", - "muteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "setNicknameDescription": "", - "setNicknameExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ], - "reminder": "" - }, - "addRoleDescription": "", - "addRoleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "removeroleDescription": "", - "removeroleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "pruneDescription": "", - "pruneExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "permissionsDescription": "", - "permissionsExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ], - "extendedHelp": "" - }, - "restrictAttachmentDescription": "", - "restrictAttachmentExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictEmbedDescription": "", - "restrictEmbedExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictEmojiDescription": "", - "restrictEmojiExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictReactionDescription": "", - "restrictReactionExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictVoiceDescription": "", - "restrictVoiceExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "softBanDescription": "", - "softBanExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "timeoutApplyDescription": "", - "timeoutApplyExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutUndoDescription": "", - "timeoutUndoExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutNotModeratable": "", - "toggleModerationDmDescription": "", - "toggleModerationDmExtended": { - "extendedHelp": "" - }, - "unbanDescription": "", - "unbanExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unmuteDescription": "", - "unmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unrestrictAttachmentDescription": "", - "unrestrictAttachmentExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmbedDescription": "", - "unrestrictEmbedExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmojiDescription": "", - "unrestrictEmojiExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictReactionDescription": "", - "unrestrictReactionExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictVoiceDescription": "", - "unrestrictVoiceExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unwarnDescription": "", - "unwarnExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vmuteDescription": "", - "vmuteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "voiceKickDescription": "", - "voiceKickExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vunmuteDescription": "", - "vunmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "warnDescription": "", - "warnExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/id/commands/shared.json b/src/languages/id/commands/shared.json deleted file mode 100644 index ddbb28e7f..000000000 --- a/src/languages/id/commands/shared.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "deprecatedMessage": "", - "slashOnlyDetailedDescription": { - "extendedHelp": "" - }, - "slashOnlyErrorMessage": "" -} \ No newline at end of file diff --git a/src/languages/id/commands/system.json b/src/languages/id/commands/system.json deleted file mode 100644 index e9cfdeec4..000000000 --- a/src/languages/id/commands/system.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "evalDescription": "", - "evalExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "evalTimeout": "", - "evalError": "", - "dmNotSent": "", - "dmSent": "", - "reboot": "", - "rebootDescription": "", - "rebootExtended": { - "extendedHelp": "", - "reminder": "" - } -} \ No newline at end of file diff --git a/src/languages/id/commands/tools.json b/src/languages/id/commands/tools.json deleted file mode 100644 index 01bd03e25..000000000 --- a/src/languages/id/commands/tools.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "avatarDescription": "", - "avatarExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "" - }, - "avatarNone": "", - "voteDescription": "", - "voteExtended": { - "usages": [ - "" - ], - "examples": [ - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "voteContentNeeded": "", - "voteReactionBlocked": "", - "whoisExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "whoisMemberRoleListAndMore": "" -} \ No newline at end of file diff --git a/src/languages/id/commands/twitch.json b/src/languages/id/commands/twitch.json deleted file mode 100644 index 2f12e1b08..000000000 --- a/src/languages/id/commands/twitch.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "twitchSubscriptionStreamerNotFound": "", - "twitchSubscriptionStatusValues": [ - "", - "" - ], - "twitchSubscriptionInvalidStatus": "", - "twitchSubscriptionAddDuplicated": "", - "twitchSubscriptionAddSuccessOffline": "", - "twitchSubscriptionAddSuccessLive": "", - "twitchSubscriptionAddMessageForOfflineRequired": "", - "twitchSubscriptionRemoveOrResetEmpty": "", - "twitchSubscriptionRemoveStreamerNotSubscribed": "", - "twitchSubscriptionRemoveNotToProvidedChannel": "", - "twitchSubscriptionRemoveStreamerStatusNotMatch": "", - "twitchSubscriptionRemoveSuccessOffline": "", - "twitchSubscriptionRemoveSuccessLive": "", - "twitchSubscriptionResetSuccess_one": "", - "twitchSubscriptionResetSuccess_other": "", - "twitchSubscriptionShowStreamerNotSubscribed": "", - "twitchSubscriptionShowStatus": { - "live": "", - "offline": "" - }, - "twitchSubscriptionShowUnknownUser": "", - "twitchSubscriptionDescription": "", - "twitchSubscriptionExtended": { - "usages": [ - "", - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/id/commands/whois.json b/src/languages/id/commands/whois.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/id/commands/whois.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/id/errors.json b/src/languages/id/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/id/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/id/events/errors.json b/src/languages/id/events/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/id/events/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/id/events/guilds-logs.json b/src/languages/id/events/guilds-logs.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/id/events/guilds-logs.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/id/events/guilds-members.json b/src/languages/id/events/guilds-members.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/id/events/guilds-members.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/id/events/messages.json b/src/languages/id/events/messages.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/id/events/messages.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/id/events/moderation.json b/src/languages/id/events/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/id/events/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/id/events/noMentionSpam.json b/src/languages/id/events/noMentionSpam.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/id/events/noMentionSpam.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/id/events/reactions.json b/src/languages/id/events/reactions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/id/events/reactions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/id/events/twitch.json b/src/languages/id/events/twitch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/id/events/twitch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/id/fuzzySearch.json b/src/languages/id/fuzzySearch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/id/fuzzySearch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/id/globals.json b/src/languages/id/globals.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/id/globals.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/id/guilds.json b/src/languages/id/guilds.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/id/guilds.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/id/humanLevels.json b/src/languages/id/humanLevels.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/id/humanLevels.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/id/moderation.json b/src/languages/id/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/id/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/id/moderationActions.json b/src/languages/id/moderationActions.json deleted file mode 100644 index 4c440ae54..000000000 --- a/src/languages/id/moderationActions.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "actions": { - "addRole": "", - "ban": "", - "kick": "", - "mute": "", - "removeRole": "", - "restrictedAttachment": "", - "restrictedEmbed": "", - "restrictedEmoji": "", - "restrictedReact": "", - "restrictedVoice": "", - "setNickname": "", - "softban": "", - "vkick": "", - "vmute": "", - "warning": "" - }, - "actionCannotManageRoles": "", - "actionRoleNotConfigured": "", - "actionRoleHigherPosition": "", - "actionRoleManaged": "", - "applyNoReason": "", - "applyReason": "", - "requiredMember": "", - "revokeNoReason": "", - "revokeReason": "", - "setNicknameNoReasonRemoved": "", - "setNicknameNoReasonSet": "", - "setNicknameRemoved": "", - "setNicknameSet": "", - "setupMuteExists": "", - "setupTooManyRoles": "", - "sharedRoleSetupAsk": "", - "sharedRoleSetupNoMessage": "", - "sharedRoleSetupExisting": "", - "sharedRoleSetupExistingName": "", - "sharedRoleSetupNew": "", - "softbanNoReason": "", - "softbanReason": "", - "unSoftbanNoReason": "", - "unSoftbanReason": "" -} \ No newline at end of file diff --git a/src/languages/id/permissions.json b/src/languages/id/permissions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/id/permissions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/id/preconditions.json b/src/languages/id/preconditions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/id/preconditions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/id/selfModeration.json b/src/languages/id/selfModeration.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/id/selfModeration.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/id/serializers.json b/src/languages/id/serializers.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/id/serializers.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/id/settings.json b/src/languages/id/settings.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/id/settings.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/id/system.json b/src/languages/id/system.json deleted file mode 100644 index 073b9b683..000000000 --- a/src/languages/id/system.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "discordAbortError": "", - "fetchBansFail": "", - "helpTitles": { - "aliases": "", - "usages": "", - "extendedHelp": "", - "explainedUsage": "", - "possibleFormats": "", - "examples": "", - "reminders": "" - }, - "jumpTo": "", - "loading": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "prefixReminder": "" -} \ No newline at end of file diff --git a/src/languages/index.ts b/src/languages/index.ts deleted file mode 100644 index 4db682460..000000000 --- a/src/languages/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -import type { Handler } from '#lib/i18n/structures/Handler'; -import { ExtendedHandler as DeHandler } from '#root/languages/de/constants'; -import { ExtendedHandler as EnGbHandler } from '#root/languages/en-GB/constants'; -import { ExtendedHandler as EnUsHandler } from '#root/languages/en-US/constants'; -import { ExtendedHandler as EsEsHandler } from '#root/languages/es-ES/constants'; -import { ExtendedHandler as NlHandler } from '#root/languages/nl/constants'; -import { Locale } from 'discord.js'; - -export const handlers = new Map([ - [Locale.German, new DeHandler()], - [Locale.EnglishUS, new EnUsHandler()], - [Locale.EnglishGB, new EnGbHandler()], - [Locale.SpanishES, new EsEsHandler()], - [Locale.Dutch, new NlHandler()] -]); - -export function getHandler(name: Locale): Handler { - return handlers.get(name) ?? handlers.get(Locale.EnglishUS)!; -} diff --git a/src/languages/it/arguments.json b/src/languages/it/arguments.json deleted file mode 100644 index a7befa6f3..000000000 --- a/src/languages/it/arguments.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "boolean_one": "", - "boolean_other": "", - "booleanError": "", - "booleanDisabled": "", - "booleanEnabled": "", - "booleanFalseOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "booleanTrueOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "caseNoEntries": "", - "caseUnknownEntry": "", - "caseNotInThisGuild": "", - "caseLatestOptions": [ - "", - "" - ], - "categoryChannelError": "", - "channelError": "", - "command": "", - "commandMatch": "", - "dateError": "", - "dateFormats": "", - "dateTooEarly": "", - "dateTooFar": "", - "dmChannelError": "", - "duration": "", - "durationFormats": "", - "emojiError": "", - "floatError": "", - "floatTooLarge": "", - "floatTooSmall": "", - "guildChannelError": "", - "guildChannelMismatchingError": "", - "guildChannelMissingGuildError": "", - "guildPrivateThreadChannelError": "", - "guildPublicThreadChannelError": "", - "guildStageVoiceChannelError": "", - "guildTextChannelError": "", - "guildThreadChannelError": "", - "guildVoiceChannelError": "", - "hyperlinkError": "", - "integerError": "", - "integerTooLarge": "", - "integerTooSmall": "", - "invite": "", - "language": "", - "memberError": "", - "memberMissingGuild": "", - "messageError": "", - "missing": "", - "newsChannel": "", - "numberError": "", - "numberTooLarge": "", - "numberTooSmall": "", - "piece": "", - "rangeInvalid": "", - "rangeMax_other": "", - "rangeMax_one": "", - "resetPossibles": [ - "", - "" - ], - "roleError": "", - "roleMissingGuild": "", - "snowflake": "", - "store": "", - "stringTooLong": "", - "stringTooShort": "", - "time": "", - "timeSpan": "", - "timeSpanTooBig": "", - "timeSpanTooSmall": "", - "tooFewWinners": "", - "tooManyWinners": "", - "unavailable": "", - "userError": "", - "enumEmptyError": "", - "enumError": "" -} \ No newline at end of file diff --git a/src/languages/it/assertions.json b/src/languages/it/assertions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/it/assertions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/it/commands/admin.json b/src/languages/it/commands/admin.json deleted file mode 100644 index 444f39c28..000000000 --- a/src/languages/it/commands/admin.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "confUpdated": "", - "confGetNoExt": "", - "confGet": "", - "confReset": "", - "confNochange": "", - "confServerDescription": "", - "confServerExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "confServer": "", - "confDashboardOnlyKey": "", - "confSettingNotSet": "", - "rolesetDescription": "", - "rolesetExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesetCreated": "", - "rolesetAdded": "", - "rolesetRemoved": "", - "rolesetResetEmpty": "", - "rolesetResetAll": "", - "rolesetResetNotExists": "", - "rolesetResetGroup": "", - "rolesetUpdated": "", - "rolesetNoRolesets": "", - "confMenuRenderAtFolder": "", - "confMenuRenderAtPiece": "", - "confMenuRenderNokeys": "", - "confMenuRenderSelect": "", - "confMenuRenderUpdate": "", - "confMenuRenderRemove": "", - "confMenuRenderReset": "", - "confMenuRenderUndo": "", - "confMenuRenderCvalue": "", - "confMenuRenderBack": "", - "confMenuInvalidKey": "", - "confMenuInvalidAction": "", - "confMenuSaved": "" -} \ No newline at end of file diff --git a/src/languages/it/commands/animal.json b/src/languages/it/commands/animal.json deleted file mode 100644 index 6d00e57af..000000000 --- a/src/languages/it/commands/animal.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "bunnyDescription": "", - "bunnyExtended": { - "extendedHelp": "" - }, - "bunnyEmbedData": { - "title": "", - "source": "" - }, - "dogDescription": "", - "dogExtended": { - "extendedHelp": "" - }, - "foxDescription": "", - "foxExtended": { - "extendedHelp": "" - }, - "kittyDescription": "", - "kittyExtended": { - "extendedHelp": "" - }, - "shibeDescription": "", - "shibeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/it/commands/auto-moderation.json b/src/languages/it/commands/auto-moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/it/commands/auto-moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/it/commands/case.json b/src/languages/it/commands/case.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/it/commands/case.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/it/commands/fun.json b/src/languages/it/commands/fun.json deleted file mode 100644 index 7892e327d..000000000 --- a/src/languages/it/commands/fun.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "escaperopeDescription": "", - "escaperopeExtended": { - "extendedHelp": "" - }, - "escaperopeOutput": "" -} \ No newline at end of file diff --git a/src/languages/it/commands/game.json b/src/languages/it/commands/game.json deleted file mode 100644 index 8075ca93c..000000000 --- a/src/languages/it/commands/game.json +++ /dev/null @@ -1,447 +0,0 @@ -{ - "c4Description": "", - "c4Extended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "c4Prompt": "", - "gamesBot": "", - "gamesNoPlayers": "", - "gamesProgress": "", - "gamesPromptDeny": "", - "gamesRepeat": "", - "gamesSelf": "", - "gamesTooManyOrFew": "", - "hgBloodbath": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgDay": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgNight": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hungerGamesDescription": "", - "hungerGamesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "examples": [ - "" - ], - "reminder": "" - }, - "hungerGamesResultDeaths_one": "", - "hungerGamesResultDeaths_other": "", - "hungerGamesResultHeaderBloodbath": "", - "hungerGamesResultHeaderMoon": "", - "hungerGamesResultHeaderSun": "", - "hungerGamesResultProceed": "", - "hungerGamesStop": "", - "hungerGamesWinner": "", - "ticTacToeDescription": "", - "ticTacToeDraw": "", - "ticTacToeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "ticTacToePrompt": "", - "ticTacToeTurn": "", - "ticTacToeWinner": "", - "triviaActiveGame": "", - "triviaDescription": "", - "triviaEmbedTitles": { - "difficulty": "", - "trivia": "" - }, - "triviaExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "triviaIncorrect": "", - "triviaInvalidCategory": "", - "triviaNoAnswer": "", - "triviaWinner": "" -} \ No newline at end of file diff --git a/src/languages/it/commands/general.json b/src/languages/it/commands/general.json deleted file mode 100644 index 5e16f992d..000000000 --- a/src/languages/it/commands/general.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "helpAllFlag": "", - "helpCommandCount_one": "", - "helpCommandCount_other": "", - "helpData": { - "footer": "", - "title": "" - }, - "helpDescription": "", - "helpExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "reminder": "", - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "helpDm": "", - "helpNodm": "", - "v7Description": "", - "v7Extended": { - "extendedHelp": "" - }, - "v7Message": "", - "v7NayreMessage": "" -} \ No newline at end of file diff --git a/src/languages/it/commands/info.json b/src/languages/it/commands/info.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/it/commands/info.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/it/commands/management.json b/src/languages/it/commands/management.json deleted file mode 100644 index 21ef26ce2..000000000 --- a/src/languages/it/commands/management.json +++ /dev/null @@ -1,445 +0,0 @@ -{ - "commandHandlerAborted": "", - "permissionNodesHigher": "", - "permissionNodesCannotAllowEveryone": "", - "permissionNodesInvalidType": "", - "permissionNodesAdd": "", - "permissionNodesNodeNotExists": "", - "permissionNodesCommandNotExists": "", - "permissionNodesRemove": "", - "permissionNodesReset": "", - "permissionNodesShowName": "", - "permissionNodesShowAllow": "", - "permissionNodesShowDeny": "", - "guildInfoTitles": { - "CHANNELS": "", - "MEMBERS": "", - "OTHER": "" - }, - "guildInfoChannels": "", - "guildInfoChannelsAfkChannelText": "", - "guildInfoMembers": "", - "guildInfoOther": "", - "guildInfoBanner": "", - "guildInfoIcon": "", - "guildInfoSplash": "", - "guildInfoDiscoverySplash": "", - "roleInfoTitles": { - "PERMISSIONS": "" - }, - "roleInfoData": "", - "roleInfoAll": "", - "roleInfoNoPermissions": "", - "manageCommandAutoDeleteShowEmpty": "", - "manageCommandAutoDeleteShow": "", - "manageCommandAutoDeleteAdd": "", - "manageCommandAutoDeleteRemove": "", - "manageCommandAutoDeleteRemoveNotset": "", - "manageCommandAutoDeleteReset": "", - "manageCommandChannelShow": "", - "manageCommandChannelShowEmpty": "", - "manageCommandChannelAddAlreadyset": "", - "manageCommandChannelAdd": "", - "manageCommandChannelRemoveNotset": "", - "manageCommandChannelRemove": "", - "manageCommandChannelResetEmpty": "", - "manageCommandChannelReset": "", - "manageReactionRolesShowEmpty": "", - "manageReactionRolesAddChannel": "", - "manageReactionRolesAddPrompt": "", - "manageReactionRolesAddMissing": "", - "manageReactionRolesAdd": "", - "manageReactionRolesRemoveNotExists": "", - "manageReactionRolesRemove": "", - "manageReactionRolesResetEmpty": "", - "manageReactionRolesReset": "", - "configurationEquals": "", - "setIgnoreChannelsSet": "", - "setIgnoreChannelsRemoved": "", - "setImageLogsSet": "", - "setMemberAddLogsSet": "", - "setMemberRemoveLogsSet": "", - "setMessageUpdateLogsSet": "", - "setMessageDeleteLogsSet": "", - "setModLogsSet": "", - "setPrefixSet": "", - "stickyRolesNotExists": "", - "stickyRolesReset": "", - "stickyRolesRemove": "", - "stickyRolesAdd": "", - "stickyRolesShowEmpty": "", - "stickyRolesShowSingle": "", - "createMuteDescription": "", - "createMuteExtended": { - "extendedHelp": "" - }, - "permissionNodesDescription": "", - "permissionNodesExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "managecommandautodeleteDescription": "", - "managecommandautodeleteExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageCommandChannelDescription": "", - "manageCommandChannelExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageReactionRolesDescription": "", - "manageReactionRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "rolesAdded": "", - "rolesAuditlog": "", - "rolesListEmpty": "", - "rolesListTitle": "", - "rolesNotManageable": "", - "rolesNotPublic": "", - "rolesRemoved": "", - "setIgnoreChannelsDescription": "", - "setIgnoreChannelsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setImageLogsDescription": "", - "setImageLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "setMemberAddLogsDescription": "", - "setMemberAddLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMemberRemoveLogsDescription": "", - "setMemberRemoveLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMessageUpdateLogsDescription": "", - "setMessageUpdateLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setMessageDeleteLogsDescription": "", - "setMessageDeleteLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setmodlogsDescription": "", - "setmodlogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setprefixDescription": "", - "setprefixExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "guildInfoDescription": "", - "guildInfoExtended": { - "extendedHelp": "" - }, - "roleInfoDescription": "", - "roleInfoExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "stickyRolesDescription": "", - "stickyRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesDescription": "", - "rolesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/it/commands/misc.json b/src/languages/it/commands/misc.json deleted file mode 100644 index 32f64d584..000000000 --- a/src/languages/it/commands/misc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "snipeEmpty": "", - "snipeTitle": "", - "snipeDescription": "", - "snipeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/it/commands/moderation.json b/src/languages/it/commands/moderation.json deleted file mode 100644 index 815d1c788..000000000 --- a/src/languages/it/commands/moderation.json +++ /dev/null @@ -1,889 +0,0 @@ -{ - "permissions": "", - "permissionsAll": "", - "slowmodeSet": "", - "slowmodeReset": "", - "banNotBannable": "", - "dehoistStarting": "", - "dehoistProgress": "", - "dehoistEmbed": { - "title": "", - "descriptionNoone": "", - "descriptionWithError": "", - "descriptionWithMultipleErrors": "", - "description": "", - "descriptionMultipleMembers": "", - "fieldErrorTitle": "" - }, - "kickNotKickable": "", - "lockdownLock": "", - "lockdownLocking": "", - "lockdownLocked": "", - "lockdownUnlocked": "", - "lockdownOpen": "", - "muteMuted": "", - "muteUserNotMuted": "", - "restrictLowlevel": "", - "pruneAlert_one": "", - "pruneAlert_other": "", - "pruneInvalidPosition": "", - "pruneNoDeletes": "", - "pruneLogHeader": "", - "toggleModerationDmToggledEnabled": "", - "toggleModerationDmToggledDisabled": "", - "moderationOutput_one": "", - "moderationOutput_other": "", - "moderationOutputWithReason_one": "", - "moderationOutputWithReason_other": "", - "moderationFailed_one": "", - "moderationFailed_other": "", - "moderationDmFooter": "", - "moderationDmDescription": "", - "moderationDmDescriptionWithReason": "", - "moderationDmDescriptionWithDuration": "", - "moderationDmDescriptionWithReasonWithDuration": "", - "slowmodeDescription": "", - "slowmodeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "banDescription": "", - "banExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "dehoistDescription": "", - "dehoistExtended": { - "extendedHelp": "", - "reminder": "" - }, - "kickDescription": "", - "kickExtended": { - "usages": [ - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "lockdownDescription": "", - "lockdownExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "muteDescription": "", - "muteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "setNicknameDescription": "", - "setNicknameExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ], - "reminder": "" - }, - "addRoleDescription": "", - "addRoleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "removeroleDescription": "", - "removeroleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "pruneDescription": "", - "pruneExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "permissionsDescription": "", - "permissionsExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ], - "extendedHelp": "" - }, - "restrictAttachmentDescription": "", - "restrictAttachmentExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictEmbedDescription": "", - "restrictEmbedExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictEmojiDescription": "", - "restrictEmojiExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictReactionDescription": "", - "restrictReactionExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictVoiceDescription": "", - "restrictVoiceExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "softBanDescription": "", - "softBanExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "timeoutApplyDescription": "", - "timeoutApplyExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutUndoDescription": "", - "timeoutUndoExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutNotModeratable": "", - "toggleModerationDmDescription": "", - "toggleModerationDmExtended": { - "extendedHelp": "" - }, - "unbanDescription": "", - "unbanExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unmuteDescription": "", - "unmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unrestrictAttachmentDescription": "", - "unrestrictAttachmentExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmbedDescription": "", - "unrestrictEmbedExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmojiDescription": "", - "unrestrictEmojiExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictReactionDescription": "", - "unrestrictReactionExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictVoiceDescription": "", - "unrestrictVoiceExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unwarnDescription": "", - "unwarnExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vmuteDescription": "", - "vmuteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "voiceKickDescription": "", - "voiceKickExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vunmuteDescription": "", - "vunmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "warnDescription": "", - "warnExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/it/commands/shared.json b/src/languages/it/commands/shared.json deleted file mode 100644 index ddbb28e7f..000000000 --- a/src/languages/it/commands/shared.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "deprecatedMessage": "", - "slashOnlyDetailedDescription": { - "extendedHelp": "" - }, - "slashOnlyErrorMessage": "" -} \ No newline at end of file diff --git a/src/languages/it/commands/system.json b/src/languages/it/commands/system.json deleted file mode 100644 index e9cfdeec4..000000000 --- a/src/languages/it/commands/system.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "evalDescription": "", - "evalExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "evalTimeout": "", - "evalError": "", - "dmNotSent": "", - "dmSent": "", - "reboot": "", - "rebootDescription": "", - "rebootExtended": { - "extendedHelp": "", - "reminder": "" - } -} \ No newline at end of file diff --git a/src/languages/it/commands/tools.json b/src/languages/it/commands/tools.json deleted file mode 100644 index 01bd03e25..000000000 --- a/src/languages/it/commands/tools.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "avatarDescription": "", - "avatarExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "" - }, - "avatarNone": "", - "voteDescription": "", - "voteExtended": { - "usages": [ - "" - ], - "examples": [ - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "voteContentNeeded": "", - "voteReactionBlocked": "", - "whoisExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "whoisMemberRoleListAndMore": "" -} \ No newline at end of file diff --git a/src/languages/it/commands/twitch.json b/src/languages/it/commands/twitch.json deleted file mode 100644 index 2f12e1b08..000000000 --- a/src/languages/it/commands/twitch.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "twitchSubscriptionStreamerNotFound": "", - "twitchSubscriptionStatusValues": [ - "", - "" - ], - "twitchSubscriptionInvalidStatus": "", - "twitchSubscriptionAddDuplicated": "", - "twitchSubscriptionAddSuccessOffline": "", - "twitchSubscriptionAddSuccessLive": "", - "twitchSubscriptionAddMessageForOfflineRequired": "", - "twitchSubscriptionRemoveOrResetEmpty": "", - "twitchSubscriptionRemoveStreamerNotSubscribed": "", - "twitchSubscriptionRemoveNotToProvidedChannel": "", - "twitchSubscriptionRemoveStreamerStatusNotMatch": "", - "twitchSubscriptionRemoveSuccessOffline": "", - "twitchSubscriptionRemoveSuccessLive": "", - "twitchSubscriptionResetSuccess_one": "", - "twitchSubscriptionResetSuccess_other": "", - "twitchSubscriptionShowStreamerNotSubscribed": "", - "twitchSubscriptionShowStatus": { - "live": "", - "offline": "" - }, - "twitchSubscriptionShowUnknownUser": "", - "twitchSubscriptionDescription": "", - "twitchSubscriptionExtended": { - "usages": [ - "", - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/it/commands/whois.json b/src/languages/it/commands/whois.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/it/commands/whois.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/it/errors.json b/src/languages/it/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/it/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/it/events/errors.json b/src/languages/it/events/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/it/events/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/it/events/guilds-logs.json b/src/languages/it/events/guilds-logs.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/it/events/guilds-logs.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/it/events/guilds-members.json b/src/languages/it/events/guilds-members.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/it/events/guilds-members.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/it/events/messages.json b/src/languages/it/events/messages.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/it/events/messages.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/it/events/moderation.json b/src/languages/it/events/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/it/events/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/it/events/noMentionSpam.json b/src/languages/it/events/noMentionSpam.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/it/events/noMentionSpam.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/it/events/reactions.json b/src/languages/it/events/reactions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/it/events/reactions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/it/events/twitch.json b/src/languages/it/events/twitch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/it/events/twitch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/it/fuzzySearch.json b/src/languages/it/fuzzySearch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/it/fuzzySearch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/it/globals.json b/src/languages/it/globals.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/it/globals.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/it/guilds.json b/src/languages/it/guilds.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/it/guilds.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/it/humanLevels.json b/src/languages/it/humanLevels.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/it/humanLevels.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/it/moderation.json b/src/languages/it/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/it/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/it/moderationActions.json b/src/languages/it/moderationActions.json deleted file mode 100644 index 4c440ae54..000000000 --- a/src/languages/it/moderationActions.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "actions": { - "addRole": "", - "ban": "", - "kick": "", - "mute": "", - "removeRole": "", - "restrictedAttachment": "", - "restrictedEmbed": "", - "restrictedEmoji": "", - "restrictedReact": "", - "restrictedVoice": "", - "setNickname": "", - "softban": "", - "vkick": "", - "vmute": "", - "warning": "" - }, - "actionCannotManageRoles": "", - "actionRoleNotConfigured": "", - "actionRoleHigherPosition": "", - "actionRoleManaged": "", - "applyNoReason": "", - "applyReason": "", - "requiredMember": "", - "revokeNoReason": "", - "revokeReason": "", - "setNicknameNoReasonRemoved": "", - "setNicknameNoReasonSet": "", - "setNicknameRemoved": "", - "setNicknameSet": "", - "setupMuteExists": "", - "setupTooManyRoles": "", - "sharedRoleSetupAsk": "", - "sharedRoleSetupNoMessage": "", - "sharedRoleSetupExisting": "", - "sharedRoleSetupExistingName": "", - "sharedRoleSetupNew": "", - "softbanNoReason": "", - "softbanReason": "", - "unSoftbanNoReason": "", - "unSoftbanReason": "" -} \ No newline at end of file diff --git a/src/languages/it/permissions.json b/src/languages/it/permissions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/it/permissions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/it/preconditions.json b/src/languages/it/preconditions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/it/preconditions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/it/selfModeration.json b/src/languages/it/selfModeration.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/it/selfModeration.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/it/serializers.json b/src/languages/it/serializers.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/it/serializers.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/it/settings.json b/src/languages/it/settings.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/it/settings.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/it/system.json b/src/languages/it/system.json deleted file mode 100644 index 073b9b683..000000000 --- a/src/languages/it/system.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "discordAbortError": "", - "fetchBansFail": "", - "helpTitles": { - "aliases": "", - "usages": "", - "extendedHelp": "", - "explainedUsage": "", - "possibleFormats": "", - "examples": "", - "reminders": "" - }, - "jumpTo": "", - "loading": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "prefixReminder": "" -} \ No newline at end of file diff --git a/src/languages/ja/arguments.json b/src/languages/ja/arguments.json deleted file mode 100644 index a7befa6f3..000000000 --- a/src/languages/ja/arguments.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "boolean_one": "", - "boolean_other": "", - "booleanError": "", - "booleanDisabled": "", - "booleanEnabled": "", - "booleanFalseOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "booleanTrueOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "caseNoEntries": "", - "caseUnknownEntry": "", - "caseNotInThisGuild": "", - "caseLatestOptions": [ - "", - "" - ], - "categoryChannelError": "", - "channelError": "", - "command": "", - "commandMatch": "", - "dateError": "", - "dateFormats": "", - "dateTooEarly": "", - "dateTooFar": "", - "dmChannelError": "", - "duration": "", - "durationFormats": "", - "emojiError": "", - "floatError": "", - "floatTooLarge": "", - "floatTooSmall": "", - "guildChannelError": "", - "guildChannelMismatchingError": "", - "guildChannelMissingGuildError": "", - "guildPrivateThreadChannelError": "", - "guildPublicThreadChannelError": "", - "guildStageVoiceChannelError": "", - "guildTextChannelError": "", - "guildThreadChannelError": "", - "guildVoiceChannelError": "", - "hyperlinkError": "", - "integerError": "", - "integerTooLarge": "", - "integerTooSmall": "", - "invite": "", - "language": "", - "memberError": "", - "memberMissingGuild": "", - "messageError": "", - "missing": "", - "newsChannel": "", - "numberError": "", - "numberTooLarge": "", - "numberTooSmall": "", - "piece": "", - "rangeInvalid": "", - "rangeMax_other": "", - "rangeMax_one": "", - "resetPossibles": [ - "", - "" - ], - "roleError": "", - "roleMissingGuild": "", - "snowflake": "", - "store": "", - "stringTooLong": "", - "stringTooShort": "", - "time": "", - "timeSpan": "", - "timeSpanTooBig": "", - "timeSpanTooSmall": "", - "tooFewWinners": "", - "tooManyWinners": "", - "unavailable": "", - "userError": "", - "enumEmptyError": "", - "enumError": "" -} \ No newline at end of file diff --git a/src/languages/ja/assertions.json b/src/languages/ja/assertions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ja/assertions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ja/commands/admin.json b/src/languages/ja/commands/admin.json deleted file mode 100644 index 444f39c28..000000000 --- a/src/languages/ja/commands/admin.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "confUpdated": "", - "confGetNoExt": "", - "confGet": "", - "confReset": "", - "confNochange": "", - "confServerDescription": "", - "confServerExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "confServer": "", - "confDashboardOnlyKey": "", - "confSettingNotSet": "", - "rolesetDescription": "", - "rolesetExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesetCreated": "", - "rolesetAdded": "", - "rolesetRemoved": "", - "rolesetResetEmpty": "", - "rolesetResetAll": "", - "rolesetResetNotExists": "", - "rolesetResetGroup": "", - "rolesetUpdated": "", - "rolesetNoRolesets": "", - "confMenuRenderAtFolder": "", - "confMenuRenderAtPiece": "", - "confMenuRenderNokeys": "", - "confMenuRenderSelect": "", - "confMenuRenderUpdate": "", - "confMenuRenderRemove": "", - "confMenuRenderReset": "", - "confMenuRenderUndo": "", - "confMenuRenderCvalue": "", - "confMenuRenderBack": "", - "confMenuInvalidKey": "", - "confMenuInvalidAction": "", - "confMenuSaved": "" -} \ No newline at end of file diff --git a/src/languages/ja/commands/animal.json b/src/languages/ja/commands/animal.json deleted file mode 100644 index 6d00e57af..000000000 --- a/src/languages/ja/commands/animal.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "bunnyDescription": "", - "bunnyExtended": { - "extendedHelp": "" - }, - "bunnyEmbedData": { - "title": "", - "source": "" - }, - "dogDescription": "", - "dogExtended": { - "extendedHelp": "" - }, - "foxDescription": "", - "foxExtended": { - "extendedHelp": "" - }, - "kittyDescription": "", - "kittyExtended": { - "extendedHelp": "" - }, - "shibeDescription": "", - "shibeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/ja/commands/auto-moderation.json b/src/languages/ja/commands/auto-moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ja/commands/auto-moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ja/commands/case.json b/src/languages/ja/commands/case.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ja/commands/case.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ja/commands/fun.json b/src/languages/ja/commands/fun.json deleted file mode 100644 index 7892e327d..000000000 --- a/src/languages/ja/commands/fun.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "escaperopeDescription": "", - "escaperopeExtended": { - "extendedHelp": "" - }, - "escaperopeOutput": "" -} \ No newline at end of file diff --git a/src/languages/ja/commands/game.json b/src/languages/ja/commands/game.json deleted file mode 100644 index 8075ca93c..000000000 --- a/src/languages/ja/commands/game.json +++ /dev/null @@ -1,447 +0,0 @@ -{ - "c4Description": "", - "c4Extended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "c4Prompt": "", - "gamesBot": "", - "gamesNoPlayers": "", - "gamesProgress": "", - "gamesPromptDeny": "", - "gamesRepeat": "", - "gamesSelf": "", - "gamesTooManyOrFew": "", - "hgBloodbath": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgDay": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgNight": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hungerGamesDescription": "", - "hungerGamesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "examples": [ - "" - ], - "reminder": "" - }, - "hungerGamesResultDeaths_one": "", - "hungerGamesResultDeaths_other": "", - "hungerGamesResultHeaderBloodbath": "", - "hungerGamesResultHeaderMoon": "", - "hungerGamesResultHeaderSun": "", - "hungerGamesResultProceed": "", - "hungerGamesStop": "", - "hungerGamesWinner": "", - "ticTacToeDescription": "", - "ticTacToeDraw": "", - "ticTacToeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "ticTacToePrompt": "", - "ticTacToeTurn": "", - "ticTacToeWinner": "", - "triviaActiveGame": "", - "triviaDescription": "", - "triviaEmbedTitles": { - "difficulty": "", - "trivia": "" - }, - "triviaExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "triviaIncorrect": "", - "triviaInvalidCategory": "", - "triviaNoAnswer": "", - "triviaWinner": "" -} \ No newline at end of file diff --git a/src/languages/ja/commands/general.json b/src/languages/ja/commands/general.json deleted file mode 100644 index 5e16f992d..000000000 --- a/src/languages/ja/commands/general.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "helpAllFlag": "", - "helpCommandCount_one": "", - "helpCommandCount_other": "", - "helpData": { - "footer": "", - "title": "" - }, - "helpDescription": "", - "helpExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "reminder": "", - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "helpDm": "", - "helpNodm": "", - "v7Description": "", - "v7Extended": { - "extendedHelp": "" - }, - "v7Message": "", - "v7NayreMessage": "" -} \ No newline at end of file diff --git a/src/languages/ja/commands/info.json b/src/languages/ja/commands/info.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ja/commands/info.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ja/commands/management.json b/src/languages/ja/commands/management.json deleted file mode 100644 index 21ef26ce2..000000000 --- a/src/languages/ja/commands/management.json +++ /dev/null @@ -1,445 +0,0 @@ -{ - "commandHandlerAborted": "", - "permissionNodesHigher": "", - "permissionNodesCannotAllowEveryone": "", - "permissionNodesInvalidType": "", - "permissionNodesAdd": "", - "permissionNodesNodeNotExists": "", - "permissionNodesCommandNotExists": "", - "permissionNodesRemove": "", - "permissionNodesReset": "", - "permissionNodesShowName": "", - "permissionNodesShowAllow": "", - "permissionNodesShowDeny": "", - "guildInfoTitles": { - "CHANNELS": "", - "MEMBERS": "", - "OTHER": "" - }, - "guildInfoChannels": "", - "guildInfoChannelsAfkChannelText": "", - "guildInfoMembers": "", - "guildInfoOther": "", - "guildInfoBanner": "", - "guildInfoIcon": "", - "guildInfoSplash": "", - "guildInfoDiscoverySplash": "", - "roleInfoTitles": { - "PERMISSIONS": "" - }, - "roleInfoData": "", - "roleInfoAll": "", - "roleInfoNoPermissions": "", - "manageCommandAutoDeleteShowEmpty": "", - "manageCommandAutoDeleteShow": "", - "manageCommandAutoDeleteAdd": "", - "manageCommandAutoDeleteRemove": "", - "manageCommandAutoDeleteRemoveNotset": "", - "manageCommandAutoDeleteReset": "", - "manageCommandChannelShow": "", - "manageCommandChannelShowEmpty": "", - "manageCommandChannelAddAlreadyset": "", - "manageCommandChannelAdd": "", - "manageCommandChannelRemoveNotset": "", - "manageCommandChannelRemove": "", - "manageCommandChannelResetEmpty": "", - "manageCommandChannelReset": "", - "manageReactionRolesShowEmpty": "", - "manageReactionRolesAddChannel": "", - "manageReactionRolesAddPrompt": "", - "manageReactionRolesAddMissing": "", - "manageReactionRolesAdd": "", - "manageReactionRolesRemoveNotExists": "", - "manageReactionRolesRemove": "", - "manageReactionRolesResetEmpty": "", - "manageReactionRolesReset": "", - "configurationEquals": "", - "setIgnoreChannelsSet": "", - "setIgnoreChannelsRemoved": "", - "setImageLogsSet": "", - "setMemberAddLogsSet": "", - "setMemberRemoveLogsSet": "", - "setMessageUpdateLogsSet": "", - "setMessageDeleteLogsSet": "", - "setModLogsSet": "", - "setPrefixSet": "", - "stickyRolesNotExists": "", - "stickyRolesReset": "", - "stickyRolesRemove": "", - "stickyRolesAdd": "", - "stickyRolesShowEmpty": "", - "stickyRolesShowSingle": "", - "createMuteDescription": "", - "createMuteExtended": { - "extendedHelp": "" - }, - "permissionNodesDescription": "", - "permissionNodesExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "managecommandautodeleteDescription": "", - "managecommandautodeleteExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageCommandChannelDescription": "", - "manageCommandChannelExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageReactionRolesDescription": "", - "manageReactionRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "rolesAdded": "", - "rolesAuditlog": "", - "rolesListEmpty": "", - "rolesListTitle": "", - "rolesNotManageable": "", - "rolesNotPublic": "", - "rolesRemoved": "", - "setIgnoreChannelsDescription": "", - "setIgnoreChannelsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setImageLogsDescription": "", - "setImageLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "setMemberAddLogsDescription": "", - "setMemberAddLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMemberRemoveLogsDescription": "", - "setMemberRemoveLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMessageUpdateLogsDescription": "", - "setMessageUpdateLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setMessageDeleteLogsDescription": "", - "setMessageDeleteLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setmodlogsDescription": "", - "setmodlogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setprefixDescription": "", - "setprefixExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "guildInfoDescription": "", - "guildInfoExtended": { - "extendedHelp": "" - }, - "roleInfoDescription": "", - "roleInfoExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "stickyRolesDescription": "", - "stickyRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesDescription": "", - "rolesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/ja/commands/misc.json b/src/languages/ja/commands/misc.json deleted file mode 100644 index 32f64d584..000000000 --- a/src/languages/ja/commands/misc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "snipeEmpty": "", - "snipeTitle": "", - "snipeDescription": "", - "snipeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/ja/commands/moderation.json b/src/languages/ja/commands/moderation.json deleted file mode 100644 index 815d1c788..000000000 --- a/src/languages/ja/commands/moderation.json +++ /dev/null @@ -1,889 +0,0 @@ -{ - "permissions": "", - "permissionsAll": "", - "slowmodeSet": "", - "slowmodeReset": "", - "banNotBannable": "", - "dehoistStarting": "", - "dehoistProgress": "", - "dehoistEmbed": { - "title": "", - "descriptionNoone": "", - "descriptionWithError": "", - "descriptionWithMultipleErrors": "", - "description": "", - "descriptionMultipleMembers": "", - "fieldErrorTitle": "" - }, - "kickNotKickable": "", - "lockdownLock": "", - "lockdownLocking": "", - "lockdownLocked": "", - "lockdownUnlocked": "", - "lockdownOpen": "", - "muteMuted": "", - "muteUserNotMuted": "", - "restrictLowlevel": "", - "pruneAlert_one": "", - "pruneAlert_other": "", - "pruneInvalidPosition": "", - "pruneNoDeletes": "", - "pruneLogHeader": "", - "toggleModerationDmToggledEnabled": "", - "toggleModerationDmToggledDisabled": "", - "moderationOutput_one": "", - "moderationOutput_other": "", - "moderationOutputWithReason_one": "", - "moderationOutputWithReason_other": "", - "moderationFailed_one": "", - "moderationFailed_other": "", - "moderationDmFooter": "", - "moderationDmDescription": "", - "moderationDmDescriptionWithReason": "", - "moderationDmDescriptionWithDuration": "", - "moderationDmDescriptionWithReasonWithDuration": "", - "slowmodeDescription": "", - "slowmodeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "banDescription": "", - "banExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "dehoistDescription": "", - "dehoistExtended": { - "extendedHelp": "", - "reminder": "" - }, - "kickDescription": "", - "kickExtended": { - "usages": [ - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "lockdownDescription": "", - "lockdownExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "muteDescription": "", - "muteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "setNicknameDescription": "", - "setNicknameExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ], - "reminder": "" - }, - "addRoleDescription": "", - "addRoleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "removeroleDescription": "", - "removeroleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "pruneDescription": "", - "pruneExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "permissionsDescription": "", - "permissionsExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ], - "extendedHelp": "" - }, - "restrictAttachmentDescription": "", - "restrictAttachmentExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictEmbedDescription": "", - "restrictEmbedExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictEmojiDescription": "", - "restrictEmojiExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictReactionDescription": "", - "restrictReactionExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictVoiceDescription": "", - "restrictVoiceExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "softBanDescription": "", - "softBanExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "timeoutApplyDescription": "", - "timeoutApplyExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutUndoDescription": "", - "timeoutUndoExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutNotModeratable": "", - "toggleModerationDmDescription": "", - "toggleModerationDmExtended": { - "extendedHelp": "" - }, - "unbanDescription": "", - "unbanExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unmuteDescription": "", - "unmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unrestrictAttachmentDescription": "", - "unrestrictAttachmentExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmbedDescription": "", - "unrestrictEmbedExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmojiDescription": "", - "unrestrictEmojiExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictReactionDescription": "", - "unrestrictReactionExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictVoiceDescription": "", - "unrestrictVoiceExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unwarnDescription": "", - "unwarnExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vmuteDescription": "", - "vmuteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "voiceKickDescription": "", - "voiceKickExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vunmuteDescription": "", - "vunmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "warnDescription": "", - "warnExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/ja/commands/shared.json b/src/languages/ja/commands/shared.json deleted file mode 100644 index ddbb28e7f..000000000 --- a/src/languages/ja/commands/shared.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "deprecatedMessage": "", - "slashOnlyDetailedDescription": { - "extendedHelp": "" - }, - "slashOnlyErrorMessage": "" -} \ No newline at end of file diff --git a/src/languages/ja/commands/system.json b/src/languages/ja/commands/system.json deleted file mode 100644 index e9cfdeec4..000000000 --- a/src/languages/ja/commands/system.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "evalDescription": "", - "evalExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "evalTimeout": "", - "evalError": "", - "dmNotSent": "", - "dmSent": "", - "reboot": "", - "rebootDescription": "", - "rebootExtended": { - "extendedHelp": "", - "reminder": "" - } -} \ No newline at end of file diff --git a/src/languages/ja/commands/tools.json b/src/languages/ja/commands/tools.json deleted file mode 100644 index 01bd03e25..000000000 --- a/src/languages/ja/commands/tools.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "avatarDescription": "", - "avatarExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "" - }, - "avatarNone": "", - "voteDescription": "", - "voteExtended": { - "usages": [ - "" - ], - "examples": [ - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "voteContentNeeded": "", - "voteReactionBlocked": "", - "whoisExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "whoisMemberRoleListAndMore": "" -} \ No newline at end of file diff --git a/src/languages/ja/commands/twitch.json b/src/languages/ja/commands/twitch.json deleted file mode 100644 index 2f12e1b08..000000000 --- a/src/languages/ja/commands/twitch.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "twitchSubscriptionStreamerNotFound": "", - "twitchSubscriptionStatusValues": [ - "", - "" - ], - "twitchSubscriptionInvalidStatus": "", - "twitchSubscriptionAddDuplicated": "", - "twitchSubscriptionAddSuccessOffline": "", - "twitchSubscriptionAddSuccessLive": "", - "twitchSubscriptionAddMessageForOfflineRequired": "", - "twitchSubscriptionRemoveOrResetEmpty": "", - "twitchSubscriptionRemoveStreamerNotSubscribed": "", - "twitchSubscriptionRemoveNotToProvidedChannel": "", - "twitchSubscriptionRemoveStreamerStatusNotMatch": "", - "twitchSubscriptionRemoveSuccessOffline": "", - "twitchSubscriptionRemoveSuccessLive": "", - "twitchSubscriptionResetSuccess_one": "", - "twitchSubscriptionResetSuccess_other": "", - "twitchSubscriptionShowStreamerNotSubscribed": "", - "twitchSubscriptionShowStatus": { - "live": "", - "offline": "" - }, - "twitchSubscriptionShowUnknownUser": "", - "twitchSubscriptionDescription": "", - "twitchSubscriptionExtended": { - "usages": [ - "", - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/ja/commands/whois.json b/src/languages/ja/commands/whois.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ja/commands/whois.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ja/errors.json b/src/languages/ja/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ja/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ja/events/errors.json b/src/languages/ja/events/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ja/events/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ja/events/guilds-logs.json b/src/languages/ja/events/guilds-logs.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ja/events/guilds-logs.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ja/events/guilds-members.json b/src/languages/ja/events/guilds-members.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ja/events/guilds-members.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ja/events/messages.json b/src/languages/ja/events/messages.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ja/events/messages.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ja/events/moderation.json b/src/languages/ja/events/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ja/events/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ja/events/noMentionSpam.json b/src/languages/ja/events/noMentionSpam.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ja/events/noMentionSpam.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ja/events/reactions.json b/src/languages/ja/events/reactions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ja/events/reactions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ja/events/twitch.json b/src/languages/ja/events/twitch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ja/events/twitch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ja/fuzzySearch.json b/src/languages/ja/fuzzySearch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ja/fuzzySearch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ja/globals.json b/src/languages/ja/globals.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ja/globals.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ja/guilds.json b/src/languages/ja/guilds.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ja/guilds.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ja/humanLevels.json b/src/languages/ja/humanLevels.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ja/humanLevels.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ja/moderation.json b/src/languages/ja/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ja/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ja/moderationActions.json b/src/languages/ja/moderationActions.json deleted file mode 100644 index 4c440ae54..000000000 --- a/src/languages/ja/moderationActions.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "actions": { - "addRole": "", - "ban": "", - "kick": "", - "mute": "", - "removeRole": "", - "restrictedAttachment": "", - "restrictedEmbed": "", - "restrictedEmoji": "", - "restrictedReact": "", - "restrictedVoice": "", - "setNickname": "", - "softban": "", - "vkick": "", - "vmute": "", - "warning": "" - }, - "actionCannotManageRoles": "", - "actionRoleNotConfigured": "", - "actionRoleHigherPosition": "", - "actionRoleManaged": "", - "applyNoReason": "", - "applyReason": "", - "requiredMember": "", - "revokeNoReason": "", - "revokeReason": "", - "setNicknameNoReasonRemoved": "", - "setNicknameNoReasonSet": "", - "setNicknameRemoved": "", - "setNicknameSet": "", - "setupMuteExists": "", - "setupTooManyRoles": "", - "sharedRoleSetupAsk": "", - "sharedRoleSetupNoMessage": "", - "sharedRoleSetupExisting": "", - "sharedRoleSetupExistingName": "", - "sharedRoleSetupNew": "", - "softbanNoReason": "", - "softbanReason": "", - "unSoftbanNoReason": "", - "unSoftbanReason": "" -} \ No newline at end of file diff --git a/src/languages/ja/permissions.json b/src/languages/ja/permissions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ja/permissions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ja/preconditions.json b/src/languages/ja/preconditions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ja/preconditions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ja/selfModeration.json b/src/languages/ja/selfModeration.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ja/selfModeration.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ja/serializers.json b/src/languages/ja/serializers.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ja/serializers.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ja/settings.json b/src/languages/ja/settings.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ja/settings.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ja/system.json b/src/languages/ja/system.json deleted file mode 100644 index 073b9b683..000000000 --- a/src/languages/ja/system.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "discordAbortError": "", - "fetchBansFail": "", - "helpTitles": { - "aliases": "", - "usages": "", - "extendedHelp": "", - "explainedUsage": "", - "possibleFormats": "", - "examples": "", - "reminders": "" - }, - "jumpTo": "", - "loading": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "prefixReminder": "" -} \ No newline at end of file diff --git a/src/languages/ko/arguments.json b/src/languages/ko/arguments.json deleted file mode 100644 index a7befa6f3..000000000 --- a/src/languages/ko/arguments.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "boolean_one": "", - "boolean_other": "", - "booleanError": "", - "booleanDisabled": "", - "booleanEnabled": "", - "booleanFalseOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "booleanTrueOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "caseNoEntries": "", - "caseUnknownEntry": "", - "caseNotInThisGuild": "", - "caseLatestOptions": [ - "", - "" - ], - "categoryChannelError": "", - "channelError": "", - "command": "", - "commandMatch": "", - "dateError": "", - "dateFormats": "", - "dateTooEarly": "", - "dateTooFar": "", - "dmChannelError": "", - "duration": "", - "durationFormats": "", - "emojiError": "", - "floatError": "", - "floatTooLarge": "", - "floatTooSmall": "", - "guildChannelError": "", - "guildChannelMismatchingError": "", - "guildChannelMissingGuildError": "", - "guildPrivateThreadChannelError": "", - "guildPublicThreadChannelError": "", - "guildStageVoiceChannelError": "", - "guildTextChannelError": "", - "guildThreadChannelError": "", - "guildVoiceChannelError": "", - "hyperlinkError": "", - "integerError": "", - "integerTooLarge": "", - "integerTooSmall": "", - "invite": "", - "language": "", - "memberError": "", - "memberMissingGuild": "", - "messageError": "", - "missing": "", - "newsChannel": "", - "numberError": "", - "numberTooLarge": "", - "numberTooSmall": "", - "piece": "", - "rangeInvalid": "", - "rangeMax_other": "", - "rangeMax_one": "", - "resetPossibles": [ - "", - "" - ], - "roleError": "", - "roleMissingGuild": "", - "snowflake": "", - "store": "", - "stringTooLong": "", - "stringTooShort": "", - "time": "", - "timeSpan": "", - "timeSpanTooBig": "", - "timeSpanTooSmall": "", - "tooFewWinners": "", - "tooManyWinners": "", - "unavailable": "", - "userError": "", - "enumEmptyError": "", - "enumError": "" -} \ No newline at end of file diff --git a/src/languages/ko/assertions.json b/src/languages/ko/assertions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ko/assertions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ko/commands/admin.json b/src/languages/ko/commands/admin.json deleted file mode 100644 index 444f39c28..000000000 --- a/src/languages/ko/commands/admin.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "confUpdated": "", - "confGetNoExt": "", - "confGet": "", - "confReset": "", - "confNochange": "", - "confServerDescription": "", - "confServerExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "confServer": "", - "confDashboardOnlyKey": "", - "confSettingNotSet": "", - "rolesetDescription": "", - "rolesetExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesetCreated": "", - "rolesetAdded": "", - "rolesetRemoved": "", - "rolesetResetEmpty": "", - "rolesetResetAll": "", - "rolesetResetNotExists": "", - "rolesetResetGroup": "", - "rolesetUpdated": "", - "rolesetNoRolesets": "", - "confMenuRenderAtFolder": "", - "confMenuRenderAtPiece": "", - "confMenuRenderNokeys": "", - "confMenuRenderSelect": "", - "confMenuRenderUpdate": "", - "confMenuRenderRemove": "", - "confMenuRenderReset": "", - "confMenuRenderUndo": "", - "confMenuRenderCvalue": "", - "confMenuRenderBack": "", - "confMenuInvalidKey": "", - "confMenuInvalidAction": "", - "confMenuSaved": "" -} \ No newline at end of file diff --git a/src/languages/ko/commands/animal.json b/src/languages/ko/commands/animal.json deleted file mode 100644 index 6d00e57af..000000000 --- a/src/languages/ko/commands/animal.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "bunnyDescription": "", - "bunnyExtended": { - "extendedHelp": "" - }, - "bunnyEmbedData": { - "title": "", - "source": "" - }, - "dogDescription": "", - "dogExtended": { - "extendedHelp": "" - }, - "foxDescription": "", - "foxExtended": { - "extendedHelp": "" - }, - "kittyDescription": "", - "kittyExtended": { - "extendedHelp": "" - }, - "shibeDescription": "", - "shibeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/ko/commands/auto-moderation.json b/src/languages/ko/commands/auto-moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ko/commands/auto-moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ko/commands/case.json b/src/languages/ko/commands/case.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ko/commands/case.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ko/commands/fun.json b/src/languages/ko/commands/fun.json deleted file mode 100644 index 7892e327d..000000000 --- a/src/languages/ko/commands/fun.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "escaperopeDescription": "", - "escaperopeExtended": { - "extendedHelp": "" - }, - "escaperopeOutput": "" -} \ No newline at end of file diff --git a/src/languages/ko/commands/game.json b/src/languages/ko/commands/game.json deleted file mode 100644 index 8075ca93c..000000000 --- a/src/languages/ko/commands/game.json +++ /dev/null @@ -1,447 +0,0 @@ -{ - "c4Description": "", - "c4Extended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "c4Prompt": "", - "gamesBot": "", - "gamesNoPlayers": "", - "gamesProgress": "", - "gamesPromptDeny": "", - "gamesRepeat": "", - "gamesSelf": "", - "gamesTooManyOrFew": "", - "hgBloodbath": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgDay": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgNight": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hungerGamesDescription": "", - "hungerGamesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "examples": [ - "" - ], - "reminder": "" - }, - "hungerGamesResultDeaths_one": "", - "hungerGamesResultDeaths_other": "", - "hungerGamesResultHeaderBloodbath": "", - "hungerGamesResultHeaderMoon": "", - "hungerGamesResultHeaderSun": "", - "hungerGamesResultProceed": "", - "hungerGamesStop": "", - "hungerGamesWinner": "", - "ticTacToeDescription": "", - "ticTacToeDraw": "", - "ticTacToeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "ticTacToePrompt": "", - "ticTacToeTurn": "", - "ticTacToeWinner": "", - "triviaActiveGame": "", - "triviaDescription": "", - "triviaEmbedTitles": { - "difficulty": "", - "trivia": "" - }, - "triviaExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "triviaIncorrect": "", - "triviaInvalidCategory": "", - "triviaNoAnswer": "", - "triviaWinner": "" -} \ No newline at end of file diff --git a/src/languages/ko/commands/general.json b/src/languages/ko/commands/general.json deleted file mode 100644 index 5e16f992d..000000000 --- a/src/languages/ko/commands/general.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "helpAllFlag": "", - "helpCommandCount_one": "", - "helpCommandCount_other": "", - "helpData": { - "footer": "", - "title": "" - }, - "helpDescription": "", - "helpExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "reminder": "", - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "helpDm": "", - "helpNodm": "", - "v7Description": "", - "v7Extended": { - "extendedHelp": "" - }, - "v7Message": "", - "v7NayreMessage": "" -} \ No newline at end of file diff --git a/src/languages/ko/commands/info.json b/src/languages/ko/commands/info.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ko/commands/info.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ko/commands/management.json b/src/languages/ko/commands/management.json deleted file mode 100644 index 21ef26ce2..000000000 --- a/src/languages/ko/commands/management.json +++ /dev/null @@ -1,445 +0,0 @@ -{ - "commandHandlerAborted": "", - "permissionNodesHigher": "", - "permissionNodesCannotAllowEveryone": "", - "permissionNodesInvalidType": "", - "permissionNodesAdd": "", - "permissionNodesNodeNotExists": "", - "permissionNodesCommandNotExists": "", - "permissionNodesRemove": "", - "permissionNodesReset": "", - "permissionNodesShowName": "", - "permissionNodesShowAllow": "", - "permissionNodesShowDeny": "", - "guildInfoTitles": { - "CHANNELS": "", - "MEMBERS": "", - "OTHER": "" - }, - "guildInfoChannels": "", - "guildInfoChannelsAfkChannelText": "", - "guildInfoMembers": "", - "guildInfoOther": "", - "guildInfoBanner": "", - "guildInfoIcon": "", - "guildInfoSplash": "", - "guildInfoDiscoverySplash": "", - "roleInfoTitles": { - "PERMISSIONS": "" - }, - "roleInfoData": "", - "roleInfoAll": "", - "roleInfoNoPermissions": "", - "manageCommandAutoDeleteShowEmpty": "", - "manageCommandAutoDeleteShow": "", - "manageCommandAutoDeleteAdd": "", - "manageCommandAutoDeleteRemove": "", - "manageCommandAutoDeleteRemoveNotset": "", - "manageCommandAutoDeleteReset": "", - "manageCommandChannelShow": "", - "manageCommandChannelShowEmpty": "", - "manageCommandChannelAddAlreadyset": "", - "manageCommandChannelAdd": "", - "manageCommandChannelRemoveNotset": "", - "manageCommandChannelRemove": "", - "manageCommandChannelResetEmpty": "", - "manageCommandChannelReset": "", - "manageReactionRolesShowEmpty": "", - "manageReactionRolesAddChannel": "", - "manageReactionRolesAddPrompt": "", - "manageReactionRolesAddMissing": "", - "manageReactionRolesAdd": "", - "manageReactionRolesRemoveNotExists": "", - "manageReactionRolesRemove": "", - "manageReactionRolesResetEmpty": "", - "manageReactionRolesReset": "", - "configurationEquals": "", - "setIgnoreChannelsSet": "", - "setIgnoreChannelsRemoved": "", - "setImageLogsSet": "", - "setMemberAddLogsSet": "", - "setMemberRemoveLogsSet": "", - "setMessageUpdateLogsSet": "", - "setMessageDeleteLogsSet": "", - "setModLogsSet": "", - "setPrefixSet": "", - "stickyRolesNotExists": "", - "stickyRolesReset": "", - "stickyRolesRemove": "", - "stickyRolesAdd": "", - "stickyRolesShowEmpty": "", - "stickyRolesShowSingle": "", - "createMuteDescription": "", - "createMuteExtended": { - "extendedHelp": "" - }, - "permissionNodesDescription": "", - "permissionNodesExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "managecommandautodeleteDescription": "", - "managecommandautodeleteExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageCommandChannelDescription": "", - "manageCommandChannelExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageReactionRolesDescription": "", - "manageReactionRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "rolesAdded": "", - "rolesAuditlog": "", - "rolesListEmpty": "", - "rolesListTitle": "", - "rolesNotManageable": "", - "rolesNotPublic": "", - "rolesRemoved": "", - "setIgnoreChannelsDescription": "", - "setIgnoreChannelsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setImageLogsDescription": "", - "setImageLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "setMemberAddLogsDescription": "", - "setMemberAddLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMemberRemoveLogsDescription": "", - "setMemberRemoveLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMessageUpdateLogsDescription": "", - "setMessageUpdateLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setMessageDeleteLogsDescription": "", - "setMessageDeleteLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setmodlogsDescription": "", - "setmodlogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setprefixDescription": "", - "setprefixExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "guildInfoDescription": "", - "guildInfoExtended": { - "extendedHelp": "" - }, - "roleInfoDescription": "", - "roleInfoExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "stickyRolesDescription": "", - "stickyRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesDescription": "", - "rolesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/ko/commands/misc.json b/src/languages/ko/commands/misc.json deleted file mode 100644 index 32f64d584..000000000 --- a/src/languages/ko/commands/misc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "snipeEmpty": "", - "snipeTitle": "", - "snipeDescription": "", - "snipeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/ko/commands/moderation.json b/src/languages/ko/commands/moderation.json deleted file mode 100644 index 815d1c788..000000000 --- a/src/languages/ko/commands/moderation.json +++ /dev/null @@ -1,889 +0,0 @@ -{ - "permissions": "", - "permissionsAll": "", - "slowmodeSet": "", - "slowmodeReset": "", - "banNotBannable": "", - "dehoistStarting": "", - "dehoistProgress": "", - "dehoistEmbed": { - "title": "", - "descriptionNoone": "", - "descriptionWithError": "", - "descriptionWithMultipleErrors": "", - "description": "", - "descriptionMultipleMembers": "", - "fieldErrorTitle": "" - }, - "kickNotKickable": "", - "lockdownLock": "", - "lockdownLocking": "", - "lockdownLocked": "", - "lockdownUnlocked": "", - "lockdownOpen": "", - "muteMuted": "", - "muteUserNotMuted": "", - "restrictLowlevel": "", - "pruneAlert_one": "", - "pruneAlert_other": "", - "pruneInvalidPosition": "", - "pruneNoDeletes": "", - "pruneLogHeader": "", - "toggleModerationDmToggledEnabled": "", - "toggleModerationDmToggledDisabled": "", - "moderationOutput_one": "", - "moderationOutput_other": "", - "moderationOutputWithReason_one": "", - "moderationOutputWithReason_other": "", - "moderationFailed_one": "", - "moderationFailed_other": "", - "moderationDmFooter": "", - "moderationDmDescription": "", - "moderationDmDescriptionWithReason": "", - "moderationDmDescriptionWithDuration": "", - "moderationDmDescriptionWithReasonWithDuration": "", - "slowmodeDescription": "", - "slowmodeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "banDescription": "", - "banExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "dehoistDescription": "", - "dehoistExtended": { - "extendedHelp": "", - "reminder": "" - }, - "kickDescription": "", - "kickExtended": { - "usages": [ - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "lockdownDescription": "", - "lockdownExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "muteDescription": "", - "muteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "setNicknameDescription": "", - "setNicknameExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ], - "reminder": "" - }, - "addRoleDescription": "", - "addRoleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "removeroleDescription": "", - "removeroleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "pruneDescription": "", - "pruneExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "permissionsDescription": "", - "permissionsExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ], - "extendedHelp": "" - }, - "restrictAttachmentDescription": "", - "restrictAttachmentExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictEmbedDescription": "", - "restrictEmbedExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictEmojiDescription": "", - "restrictEmojiExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictReactionDescription": "", - "restrictReactionExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictVoiceDescription": "", - "restrictVoiceExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "softBanDescription": "", - "softBanExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "timeoutApplyDescription": "", - "timeoutApplyExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutUndoDescription": "", - "timeoutUndoExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutNotModeratable": "", - "toggleModerationDmDescription": "", - "toggleModerationDmExtended": { - "extendedHelp": "" - }, - "unbanDescription": "", - "unbanExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unmuteDescription": "", - "unmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unrestrictAttachmentDescription": "", - "unrestrictAttachmentExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmbedDescription": "", - "unrestrictEmbedExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmojiDescription": "", - "unrestrictEmojiExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictReactionDescription": "", - "unrestrictReactionExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictVoiceDescription": "", - "unrestrictVoiceExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unwarnDescription": "", - "unwarnExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vmuteDescription": "", - "vmuteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "voiceKickDescription": "", - "voiceKickExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vunmuteDescription": "", - "vunmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "warnDescription": "", - "warnExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/ko/commands/shared.json b/src/languages/ko/commands/shared.json deleted file mode 100644 index ddbb28e7f..000000000 --- a/src/languages/ko/commands/shared.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "deprecatedMessage": "", - "slashOnlyDetailedDescription": { - "extendedHelp": "" - }, - "slashOnlyErrorMessage": "" -} \ No newline at end of file diff --git a/src/languages/ko/commands/system.json b/src/languages/ko/commands/system.json deleted file mode 100644 index e9cfdeec4..000000000 --- a/src/languages/ko/commands/system.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "evalDescription": "", - "evalExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "evalTimeout": "", - "evalError": "", - "dmNotSent": "", - "dmSent": "", - "reboot": "", - "rebootDescription": "", - "rebootExtended": { - "extendedHelp": "", - "reminder": "" - } -} \ No newline at end of file diff --git a/src/languages/ko/commands/tools.json b/src/languages/ko/commands/tools.json deleted file mode 100644 index 01bd03e25..000000000 --- a/src/languages/ko/commands/tools.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "avatarDescription": "", - "avatarExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "" - }, - "avatarNone": "", - "voteDescription": "", - "voteExtended": { - "usages": [ - "" - ], - "examples": [ - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "voteContentNeeded": "", - "voteReactionBlocked": "", - "whoisExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "whoisMemberRoleListAndMore": "" -} \ No newline at end of file diff --git a/src/languages/ko/commands/twitch.json b/src/languages/ko/commands/twitch.json deleted file mode 100644 index 2f12e1b08..000000000 --- a/src/languages/ko/commands/twitch.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "twitchSubscriptionStreamerNotFound": "", - "twitchSubscriptionStatusValues": [ - "", - "" - ], - "twitchSubscriptionInvalidStatus": "", - "twitchSubscriptionAddDuplicated": "", - "twitchSubscriptionAddSuccessOffline": "", - "twitchSubscriptionAddSuccessLive": "", - "twitchSubscriptionAddMessageForOfflineRequired": "", - "twitchSubscriptionRemoveOrResetEmpty": "", - "twitchSubscriptionRemoveStreamerNotSubscribed": "", - "twitchSubscriptionRemoveNotToProvidedChannel": "", - "twitchSubscriptionRemoveStreamerStatusNotMatch": "", - "twitchSubscriptionRemoveSuccessOffline": "", - "twitchSubscriptionRemoveSuccessLive": "", - "twitchSubscriptionResetSuccess_one": "", - "twitchSubscriptionResetSuccess_other": "", - "twitchSubscriptionShowStreamerNotSubscribed": "", - "twitchSubscriptionShowStatus": { - "live": "", - "offline": "" - }, - "twitchSubscriptionShowUnknownUser": "", - "twitchSubscriptionDescription": "", - "twitchSubscriptionExtended": { - "usages": [ - "", - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/ko/commands/whois.json b/src/languages/ko/commands/whois.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ko/commands/whois.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ko/errors.json b/src/languages/ko/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ko/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ko/events/errors.json b/src/languages/ko/events/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ko/events/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ko/events/guilds-logs.json b/src/languages/ko/events/guilds-logs.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ko/events/guilds-logs.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ko/events/guilds-members.json b/src/languages/ko/events/guilds-members.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ko/events/guilds-members.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ko/events/messages.json b/src/languages/ko/events/messages.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ko/events/messages.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ko/events/moderation.json b/src/languages/ko/events/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ko/events/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ko/events/noMentionSpam.json b/src/languages/ko/events/noMentionSpam.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ko/events/noMentionSpam.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ko/events/reactions.json b/src/languages/ko/events/reactions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ko/events/reactions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ko/events/twitch.json b/src/languages/ko/events/twitch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ko/events/twitch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ko/fuzzySearch.json b/src/languages/ko/fuzzySearch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ko/fuzzySearch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ko/globals.json b/src/languages/ko/globals.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ko/globals.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ko/guilds.json b/src/languages/ko/guilds.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ko/guilds.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ko/humanLevels.json b/src/languages/ko/humanLevels.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ko/humanLevels.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ko/moderation.json b/src/languages/ko/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ko/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ko/moderationActions.json b/src/languages/ko/moderationActions.json deleted file mode 100644 index 4c440ae54..000000000 --- a/src/languages/ko/moderationActions.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "actions": { - "addRole": "", - "ban": "", - "kick": "", - "mute": "", - "removeRole": "", - "restrictedAttachment": "", - "restrictedEmbed": "", - "restrictedEmoji": "", - "restrictedReact": "", - "restrictedVoice": "", - "setNickname": "", - "softban": "", - "vkick": "", - "vmute": "", - "warning": "" - }, - "actionCannotManageRoles": "", - "actionRoleNotConfigured": "", - "actionRoleHigherPosition": "", - "actionRoleManaged": "", - "applyNoReason": "", - "applyReason": "", - "requiredMember": "", - "revokeNoReason": "", - "revokeReason": "", - "setNicknameNoReasonRemoved": "", - "setNicknameNoReasonSet": "", - "setNicknameRemoved": "", - "setNicknameSet": "", - "setupMuteExists": "", - "setupTooManyRoles": "", - "sharedRoleSetupAsk": "", - "sharedRoleSetupNoMessage": "", - "sharedRoleSetupExisting": "", - "sharedRoleSetupExistingName": "", - "sharedRoleSetupNew": "", - "softbanNoReason": "", - "softbanReason": "", - "unSoftbanNoReason": "", - "unSoftbanReason": "" -} \ No newline at end of file diff --git a/src/languages/ko/permissions.json b/src/languages/ko/permissions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ko/permissions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ko/preconditions.json b/src/languages/ko/preconditions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ko/preconditions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ko/selfModeration.json b/src/languages/ko/selfModeration.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ko/selfModeration.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ko/serializers.json b/src/languages/ko/serializers.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ko/serializers.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ko/settings.json b/src/languages/ko/settings.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ko/settings.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ko/system.json b/src/languages/ko/system.json deleted file mode 100644 index 073b9b683..000000000 --- a/src/languages/ko/system.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "discordAbortError": "", - "fetchBansFail": "", - "helpTitles": { - "aliases": "", - "usages": "", - "extendedHelp": "", - "explainedUsage": "", - "possibleFormats": "", - "examples": "", - "reminders": "" - }, - "jumpTo": "", - "loading": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "prefixReminder": "" -} \ No newline at end of file diff --git a/src/languages/lt/arguments.json b/src/languages/lt/arguments.json deleted file mode 100644 index a7befa6f3..000000000 --- a/src/languages/lt/arguments.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "boolean_one": "", - "boolean_other": "", - "booleanError": "", - "booleanDisabled": "", - "booleanEnabled": "", - "booleanFalseOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "booleanTrueOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "caseNoEntries": "", - "caseUnknownEntry": "", - "caseNotInThisGuild": "", - "caseLatestOptions": [ - "", - "" - ], - "categoryChannelError": "", - "channelError": "", - "command": "", - "commandMatch": "", - "dateError": "", - "dateFormats": "", - "dateTooEarly": "", - "dateTooFar": "", - "dmChannelError": "", - "duration": "", - "durationFormats": "", - "emojiError": "", - "floatError": "", - "floatTooLarge": "", - "floatTooSmall": "", - "guildChannelError": "", - "guildChannelMismatchingError": "", - "guildChannelMissingGuildError": "", - "guildPrivateThreadChannelError": "", - "guildPublicThreadChannelError": "", - "guildStageVoiceChannelError": "", - "guildTextChannelError": "", - "guildThreadChannelError": "", - "guildVoiceChannelError": "", - "hyperlinkError": "", - "integerError": "", - "integerTooLarge": "", - "integerTooSmall": "", - "invite": "", - "language": "", - "memberError": "", - "memberMissingGuild": "", - "messageError": "", - "missing": "", - "newsChannel": "", - "numberError": "", - "numberTooLarge": "", - "numberTooSmall": "", - "piece": "", - "rangeInvalid": "", - "rangeMax_other": "", - "rangeMax_one": "", - "resetPossibles": [ - "", - "" - ], - "roleError": "", - "roleMissingGuild": "", - "snowflake": "", - "store": "", - "stringTooLong": "", - "stringTooShort": "", - "time": "", - "timeSpan": "", - "timeSpanTooBig": "", - "timeSpanTooSmall": "", - "tooFewWinners": "", - "tooManyWinners": "", - "unavailable": "", - "userError": "", - "enumEmptyError": "", - "enumError": "" -} \ No newline at end of file diff --git a/src/languages/lt/assertions.json b/src/languages/lt/assertions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/lt/assertions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/lt/commands/admin.json b/src/languages/lt/commands/admin.json deleted file mode 100644 index 444f39c28..000000000 --- a/src/languages/lt/commands/admin.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "confUpdated": "", - "confGetNoExt": "", - "confGet": "", - "confReset": "", - "confNochange": "", - "confServerDescription": "", - "confServerExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "confServer": "", - "confDashboardOnlyKey": "", - "confSettingNotSet": "", - "rolesetDescription": "", - "rolesetExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesetCreated": "", - "rolesetAdded": "", - "rolesetRemoved": "", - "rolesetResetEmpty": "", - "rolesetResetAll": "", - "rolesetResetNotExists": "", - "rolesetResetGroup": "", - "rolesetUpdated": "", - "rolesetNoRolesets": "", - "confMenuRenderAtFolder": "", - "confMenuRenderAtPiece": "", - "confMenuRenderNokeys": "", - "confMenuRenderSelect": "", - "confMenuRenderUpdate": "", - "confMenuRenderRemove": "", - "confMenuRenderReset": "", - "confMenuRenderUndo": "", - "confMenuRenderCvalue": "", - "confMenuRenderBack": "", - "confMenuInvalidKey": "", - "confMenuInvalidAction": "", - "confMenuSaved": "" -} \ No newline at end of file diff --git a/src/languages/lt/commands/animal.json b/src/languages/lt/commands/animal.json deleted file mode 100644 index 6d00e57af..000000000 --- a/src/languages/lt/commands/animal.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "bunnyDescription": "", - "bunnyExtended": { - "extendedHelp": "" - }, - "bunnyEmbedData": { - "title": "", - "source": "" - }, - "dogDescription": "", - "dogExtended": { - "extendedHelp": "" - }, - "foxDescription": "", - "foxExtended": { - "extendedHelp": "" - }, - "kittyDescription": "", - "kittyExtended": { - "extendedHelp": "" - }, - "shibeDescription": "", - "shibeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/lt/commands/auto-moderation.json b/src/languages/lt/commands/auto-moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/lt/commands/auto-moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/lt/commands/case.json b/src/languages/lt/commands/case.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/lt/commands/case.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/lt/commands/fun.json b/src/languages/lt/commands/fun.json deleted file mode 100644 index 7892e327d..000000000 --- a/src/languages/lt/commands/fun.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "escaperopeDescription": "", - "escaperopeExtended": { - "extendedHelp": "" - }, - "escaperopeOutput": "" -} \ No newline at end of file diff --git a/src/languages/lt/commands/game.json b/src/languages/lt/commands/game.json deleted file mode 100644 index 8075ca93c..000000000 --- a/src/languages/lt/commands/game.json +++ /dev/null @@ -1,447 +0,0 @@ -{ - "c4Description": "", - "c4Extended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "c4Prompt": "", - "gamesBot": "", - "gamesNoPlayers": "", - "gamesProgress": "", - "gamesPromptDeny": "", - "gamesRepeat": "", - "gamesSelf": "", - "gamesTooManyOrFew": "", - "hgBloodbath": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgDay": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgNight": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hungerGamesDescription": "", - "hungerGamesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "examples": [ - "" - ], - "reminder": "" - }, - "hungerGamesResultDeaths_one": "", - "hungerGamesResultDeaths_other": "", - "hungerGamesResultHeaderBloodbath": "", - "hungerGamesResultHeaderMoon": "", - "hungerGamesResultHeaderSun": "", - "hungerGamesResultProceed": "", - "hungerGamesStop": "", - "hungerGamesWinner": "", - "ticTacToeDescription": "", - "ticTacToeDraw": "", - "ticTacToeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "ticTacToePrompt": "", - "ticTacToeTurn": "", - "ticTacToeWinner": "", - "triviaActiveGame": "", - "triviaDescription": "", - "triviaEmbedTitles": { - "difficulty": "", - "trivia": "" - }, - "triviaExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "triviaIncorrect": "", - "triviaInvalidCategory": "", - "triviaNoAnswer": "", - "triviaWinner": "" -} \ No newline at end of file diff --git a/src/languages/lt/commands/general.json b/src/languages/lt/commands/general.json deleted file mode 100644 index 5e16f992d..000000000 --- a/src/languages/lt/commands/general.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "helpAllFlag": "", - "helpCommandCount_one": "", - "helpCommandCount_other": "", - "helpData": { - "footer": "", - "title": "" - }, - "helpDescription": "", - "helpExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "reminder": "", - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "helpDm": "", - "helpNodm": "", - "v7Description": "", - "v7Extended": { - "extendedHelp": "" - }, - "v7Message": "", - "v7NayreMessage": "" -} \ No newline at end of file diff --git a/src/languages/lt/commands/info.json b/src/languages/lt/commands/info.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/lt/commands/info.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/lt/commands/management.json b/src/languages/lt/commands/management.json deleted file mode 100644 index 21ef26ce2..000000000 --- a/src/languages/lt/commands/management.json +++ /dev/null @@ -1,445 +0,0 @@ -{ - "commandHandlerAborted": "", - "permissionNodesHigher": "", - "permissionNodesCannotAllowEveryone": "", - "permissionNodesInvalidType": "", - "permissionNodesAdd": "", - "permissionNodesNodeNotExists": "", - "permissionNodesCommandNotExists": "", - "permissionNodesRemove": "", - "permissionNodesReset": "", - "permissionNodesShowName": "", - "permissionNodesShowAllow": "", - "permissionNodesShowDeny": "", - "guildInfoTitles": { - "CHANNELS": "", - "MEMBERS": "", - "OTHER": "" - }, - "guildInfoChannels": "", - "guildInfoChannelsAfkChannelText": "", - "guildInfoMembers": "", - "guildInfoOther": "", - "guildInfoBanner": "", - "guildInfoIcon": "", - "guildInfoSplash": "", - "guildInfoDiscoverySplash": "", - "roleInfoTitles": { - "PERMISSIONS": "" - }, - "roleInfoData": "", - "roleInfoAll": "", - "roleInfoNoPermissions": "", - "manageCommandAutoDeleteShowEmpty": "", - "manageCommandAutoDeleteShow": "", - "manageCommandAutoDeleteAdd": "", - "manageCommandAutoDeleteRemove": "", - "manageCommandAutoDeleteRemoveNotset": "", - "manageCommandAutoDeleteReset": "", - "manageCommandChannelShow": "", - "manageCommandChannelShowEmpty": "", - "manageCommandChannelAddAlreadyset": "", - "manageCommandChannelAdd": "", - "manageCommandChannelRemoveNotset": "", - "manageCommandChannelRemove": "", - "manageCommandChannelResetEmpty": "", - "manageCommandChannelReset": "", - "manageReactionRolesShowEmpty": "", - "manageReactionRolesAddChannel": "", - "manageReactionRolesAddPrompt": "", - "manageReactionRolesAddMissing": "", - "manageReactionRolesAdd": "", - "manageReactionRolesRemoveNotExists": "", - "manageReactionRolesRemove": "", - "manageReactionRolesResetEmpty": "", - "manageReactionRolesReset": "", - "configurationEquals": "", - "setIgnoreChannelsSet": "", - "setIgnoreChannelsRemoved": "", - "setImageLogsSet": "", - "setMemberAddLogsSet": "", - "setMemberRemoveLogsSet": "", - "setMessageUpdateLogsSet": "", - "setMessageDeleteLogsSet": "", - "setModLogsSet": "", - "setPrefixSet": "", - "stickyRolesNotExists": "", - "stickyRolesReset": "", - "stickyRolesRemove": "", - "stickyRolesAdd": "", - "stickyRolesShowEmpty": "", - "stickyRolesShowSingle": "", - "createMuteDescription": "", - "createMuteExtended": { - "extendedHelp": "" - }, - "permissionNodesDescription": "", - "permissionNodesExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "managecommandautodeleteDescription": "", - "managecommandautodeleteExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageCommandChannelDescription": "", - "manageCommandChannelExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageReactionRolesDescription": "", - "manageReactionRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "rolesAdded": "", - "rolesAuditlog": "", - "rolesListEmpty": "", - "rolesListTitle": "", - "rolesNotManageable": "", - "rolesNotPublic": "", - "rolesRemoved": "", - "setIgnoreChannelsDescription": "", - "setIgnoreChannelsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setImageLogsDescription": "", - "setImageLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "setMemberAddLogsDescription": "", - "setMemberAddLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMemberRemoveLogsDescription": "", - "setMemberRemoveLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMessageUpdateLogsDescription": "", - "setMessageUpdateLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setMessageDeleteLogsDescription": "", - "setMessageDeleteLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setmodlogsDescription": "", - "setmodlogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setprefixDescription": "", - "setprefixExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "guildInfoDescription": "", - "guildInfoExtended": { - "extendedHelp": "" - }, - "roleInfoDescription": "", - "roleInfoExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "stickyRolesDescription": "", - "stickyRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesDescription": "", - "rolesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/lt/commands/misc.json b/src/languages/lt/commands/misc.json deleted file mode 100644 index 32f64d584..000000000 --- a/src/languages/lt/commands/misc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "snipeEmpty": "", - "snipeTitle": "", - "snipeDescription": "", - "snipeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/lt/commands/moderation.json b/src/languages/lt/commands/moderation.json deleted file mode 100644 index 815d1c788..000000000 --- a/src/languages/lt/commands/moderation.json +++ /dev/null @@ -1,889 +0,0 @@ -{ - "permissions": "", - "permissionsAll": "", - "slowmodeSet": "", - "slowmodeReset": "", - "banNotBannable": "", - "dehoistStarting": "", - "dehoistProgress": "", - "dehoistEmbed": { - "title": "", - "descriptionNoone": "", - "descriptionWithError": "", - "descriptionWithMultipleErrors": "", - "description": "", - "descriptionMultipleMembers": "", - "fieldErrorTitle": "" - }, - "kickNotKickable": "", - "lockdownLock": "", - "lockdownLocking": "", - "lockdownLocked": "", - "lockdownUnlocked": "", - "lockdownOpen": "", - "muteMuted": "", - "muteUserNotMuted": "", - "restrictLowlevel": "", - "pruneAlert_one": "", - "pruneAlert_other": "", - "pruneInvalidPosition": "", - "pruneNoDeletes": "", - "pruneLogHeader": "", - "toggleModerationDmToggledEnabled": "", - "toggleModerationDmToggledDisabled": "", - "moderationOutput_one": "", - "moderationOutput_other": "", - "moderationOutputWithReason_one": "", - "moderationOutputWithReason_other": "", - "moderationFailed_one": "", - "moderationFailed_other": "", - "moderationDmFooter": "", - "moderationDmDescription": "", - "moderationDmDescriptionWithReason": "", - "moderationDmDescriptionWithDuration": "", - "moderationDmDescriptionWithReasonWithDuration": "", - "slowmodeDescription": "", - "slowmodeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "banDescription": "", - "banExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "dehoistDescription": "", - "dehoistExtended": { - "extendedHelp": "", - "reminder": "" - }, - "kickDescription": "", - "kickExtended": { - "usages": [ - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "lockdownDescription": "", - "lockdownExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "muteDescription": "", - "muteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "setNicknameDescription": "", - "setNicknameExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ], - "reminder": "" - }, - "addRoleDescription": "", - "addRoleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "removeroleDescription": "", - "removeroleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "pruneDescription": "", - "pruneExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "permissionsDescription": "", - "permissionsExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ], - "extendedHelp": "" - }, - "restrictAttachmentDescription": "", - "restrictAttachmentExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictEmbedDescription": "", - "restrictEmbedExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictEmojiDescription": "", - "restrictEmojiExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictReactionDescription": "", - "restrictReactionExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictVoiceDescription": "", - "restrictVoiceExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "softBanDescription": "", - "softBanExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "timeoutApplyDescription": "", - "timeoutApplyExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutUndoDescription": "", - "timeoutUndoExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutNotModeratable": "", - "toggleModerationDmDescription": "", - "toggleModerationDmExtended": { - "extendedHelp": "" - }, - "unbanDescription": "", - "unbanExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unmuteDescription": "", - "unmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unrestrictAttachmentDescription": "", - "unrestrictAttachmentExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmbedDescription": "", - "unrestrictEmbedExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmojiDescription": "", - "unrestrictEmojiExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictReactionDescription": "", - "unrestrictReactionExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictVoiceDescription": "", - "unrestrictVoiceExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unwarnDescription": "", - "unwarnExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vmuteDescription": "", - "vmuteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "voiceKickDescription": "", - "voiceKickExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vunmuteDescription": "", - "vunmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "warnDescription": "", - "warnExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/lt/commands/shared.json b/src/languages/lt/commands/shared.json deleted file mode 100644 index ddbb28e7f..000000000 --- a/src/languages/lt/commands/shared.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "deprecatedMessage": "", - "slashOnlyDetailedDescription": { - "extendedHelp": "" - }, - "slashOnlyErrorMessage": "" -} \ No newline at end of file diff --git a/src/languages/lt/commands/system.json b/src/languages/lt/commands/system.json deleted file mode 100644 index e9cfdeec4..000000000 --- a/src/languages/lt/commands/system.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "evalDescription": "", - "evalExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "evalTimeout": "", - "evalError": "", - "dmNotSent": "", - "dmSent": "", - "reboot": "", - "rebootDescription": "", - "rebootExtended": { - "extendedHelp": "", - "reminder": "" - } -} \ No newline at end of file diff --git a/src/languages/lt/commands/tools.json b/src/languages/lt/commands/tools.json deleted file mode 100644 index 01bd03e25..000000000 --- a/src/languages/lt/commands/tools.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "avatarDescription": "", - "avatarExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "" - }, - "avatarNone": "", - "voteDescription": "", - "voteExtended": { - "usages": [ - "" - ], - "examples": [ - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "voteContentNeeded": "", - "voteReactionBlocked": "", - "whoisExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "whoisMemberRoleListAndMore": "" -} \ No newline at end of file diff --git a/src/languages/lt/commands/twitch.json b/src/languages/lt/commands/twitch.json deleted file mode 100644 index 2f12e1b08..000000000 --- a/src/languages/lt/commands/twitch.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "twitchSubscriptionStreamerNotFound": "", - "twitchSubscriptionStatusValues": [ - "", - "" - ], - "twitchSubscriptionInvalidStatus": "", - "twitchSubscriptionAddDuplicated": "", - "twitchSubscriptionAddSuccessOffline": "", - "twitchSubscriptionAddSuccessLive": "", - "twitchSubscriptionAddMessageForOfflineRequired": "", - "twitchSubscriptionRemoveOrResetEmpty": "", - "twitchSubscriptionRemoveStreamerNotSubscribed": "", - "twitchSubscriptionRemoveNotToProvidedChannel": "", - "twitchSubscriptionRemoveStreamerStatusNotMatch": "", - "twitchSubscriptionRemoveSuccessOffline": "", - "twitchSubscriptionRemoveSuccessLive": "", - "twitchSubscriptionResetSuccess_one": "", - "twitchSubscriptionResetSuccess_other": "", - "twitchSubscriptionShowStreamerNotSubscribed": "", - "twitchSubscriptionShowStatus": { - "live": "", - "offline": "" - }, - "twitchSubscriptionShowUnknownUser": "", - "twitchSubscriptionDescription": "", - "twitchSubscriptionExtended": { - "usages": [ - "", - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/lt/commands/whois.json b/src/languages/lt/commands/whois.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/lt/commands/whois.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/lt/errors.json b/src/languages/lt/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/lt/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/lt/events/errors.json b/src/languages/lt/events/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/lt/events/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/lt/events/guilds-logs.json b/src/languages/lt/events/guilds-logs.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/lt/events/guilds-logs.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/lt/events/guilds-members.json b/src/languages/lt/events/guilds-members.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/lt/events/guilds-members.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/lt/events/messages.json b/src/languages/lt/events/messages.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/lt/events/messages.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/lt/events/moderation.json b/src/languages/lt/events/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/lt/events/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/lt/events/noMentionSpam.json b/src/languages/lt/events/noMentionSpam.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/lt/events/noMentionSpam.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/lt/events/reactions.json b/src/languages/lt/events/reactions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/lt/events/reactions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/lt/events/twitch.json b/src/languages/lt/events/twitch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/lt/events/twitch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/lt/fuzzySearch.json b/src/languages/lt/fuzzySearch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/lt/fuzzySearch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/lt/globals.json b/src/languages/lt/globals.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/lt/globals.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/lt/guilds.json b/src/languages/lt/guilds.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/lt/guilds.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/lt/humanLevels.json b/src/languages/lt/humanLevels.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/lt/humanLevels.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/lt/moderation.json b/src/languages/lt/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/lt/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/lt/moderationActions.json b/src/languages/lt/moderationActions.json deleted file mode 100644 index 4c440ae54..000000000 --- a/src/languages/lt/moderationActions.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "actions": { - "addRole": "", - "ban": "", - "kick": "", - "mute": "", - "removeRole": "", - "restrictedAttachment": "", - "restrictedEmbed": "", - "restrictedEmoji": "", - "restrictedReact": "", - "restrictedVoice": "", - "setNickname": "", - "softban": "", - "vkick": "", - "vmute": "", - "warning": "" - }, - "actionCannotManageRoles": "", - "actionRoleNotConfigured": "", - "actionRoleHigherPosition": "", - "actionRoleManaged": "", - "applyNoReason": "", - "applyReason": "", - "requiredMember": "", - "revokeNoReason": "", - "revokeReason": "", - "setNicknameNoReasonRemoved": "", - "setNicknameNoReasonSet": "", - "setNicknameRemoved": "", - "setNicknameSet": "", - "setupMuteExists": "", - "setupTooManyRoles": "", - "sharedRoleSetupAsk": "", - "sharedRoleSetupNoMessage": "", - "sharedRoleSetupExisting": "", - "sharedRoleSetupExistingName": "", - "sharedRoleSetupNew": "", - "softbanNoReason": "", - "softbanReason": "", - "unSoftbanNoReason": "", - "unSoftbanReason": "" -} \ No newline at end of file diff --git a/src/languages/lt/permissions.json b/src/languages/lt/permissions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/lt/permissions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/lt/preconditions.json b/src/languages/lt/preconditions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/lt/preconditions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/lt/selfModeration.json b/src/languages/lt/selfModeration.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/lt/selfModeration.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/lt/serializers.json b/src/languages/lt/serializers.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/lt/serializers.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/lt/settings.json b/src/languages/lt/settings.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/lt/settings.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/lt/system.json b/src/languages/lt/system.json deleted file mode 100644 index 073b9b683..000000000 --- a/src/languages/lt/system.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "discordAbortError": "", - "fetchBansFail": "", - "helpTitles": { - "aliases": "", - "usages": "", - "extendedHelp": "", - "explainedUsage": "", - "possibleFormats": "", - "examples": "", - "reminders": "" - }, - "jumpTo": "", - "loading": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "prefixReminder": "" -} \ No newline at end of file diff --git a/src/languages/nl/arguments.json b/src/languages/nl/arguments.json deleted file mode 100644 index a7befa6f3..000000000 --- a/src/languages/nl/arguments.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "boolean_one": "", - "boolean_other": "", - "booleanError": "", - "booleanDisabled": "", - "booleanEnabled": "", - "booleanFalseOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "booleanTrueOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "caseNoEntries": "", - "caseUnknownEntry": "", - "caseNotInThisGuild": "", - "caseLatestOptions": [ - "", - "" - ], - "categoryChannelError": "", - "channelError": "", - "command": "", - "commandMatch": "", - "dateError": "", - "dateFormats": "", - "dateTooEarly": "", - "dateTooFar": "", - "dmChannelError": "", - "duration": "", - "durationFormats": "", - "emojiError": "", - "floatError": "", - "floatTooLarge": "", - "floatTooSmall": "", - "guildChannelError": "", - "guildChannelMismatchingError": "", - "guildChannelMissingGuildError": "", - "guildPrivateThreadChannelError": "", - "guildPublicThreadChannelError": "", - "guildStageVoiceChannelError": "", - "guildTextChannelError": "", - "guildThreadChannelError": "", - "guildVoiceChannelError": "", - "hyperlinkError": "", - "integerError": "", - "integerTooLarge": "", - "integerTooSmall": "", - "invite": "", - "language": "", - "memberError": "", - "memberMissingGuild": "", - "messageError": "", - "missing": "", - "newsChannel": "", - "numberError": "", - "numberTooLarge": "", - "numberTooSmall": "", - "piece": "", - "rangeInvalid": "", - "rangeMax_other": "", - "rangeMax_one": "", - "resetPossibles": [ - "", - "" - ], - "roleError": "", - "roleMissingGuild": "", - "snowflake": "", - "store": "", - "stringTooLong": "", - "stringTooShort": "", - "time": "", - "timeSpan": "", - "timeSpanTooBig": "", - "timeSpanTooSmall": "", - "tooFewWinners": "", - "tooManyWinners": "", - "unavailable": "", - "userError": "", - "enumEmptyError": "", - "enumError": "" -} \ No newline at end of file diff --git a/src/languages/nl/assertions.json b/src/languages/nl/assertions.json deleted file mode 100644 index 5367391bb..000000000 --- a/src/languages/nl/assertions.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "expectedNonThreadChannel": "Ik verwachte een normaal tekstkanaal, maar in plaats daarvan kreeg ik het threads kanaal {{channel}}." -} \ No newline at end of file diff --git a/src/languages/nl/commands/admin.json b/src/languages/nl/commands/admin.json deleted file mode 100644 index dad57eb00..000000000 --- a/src/languages/nl/commands/admin.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "confUpdated": "", - "confGetNoExt": "De sleutel **{{key}}** lijkt niet te bestaan.", - "confGet": "De waarde voor **{{key}}** is: `{{value}}`", - "confReset": "**{{key}}** is gereset naar: `{{value}}`", - "confNochange": "De waarde voor **{{key}}** is hetzelfde gebleven.", - "confServerDescription": "Definieer instellingen per server.", - "confServerExtended": { - "usages": [ - "set NameOfKey ValueForKey", - "show", - "show NameOfKey", - "remove NameOfKey ValueForKey", - "reset NameOfKey", - "menu" - ], - "extendedHelp": "", - "examples": [ - "set language en-GB", - "set channel.moderation-logs #moderation-logs", - "show", - "show channels", - "remove roles.moderator Moderator", - "reset roles.moderator", - "menu" - ], - "reminder": "Er zijn groepen en sleutels en sleutels die onderdeel zijn van een groep worden gerefereerd als `GroepNaam.SleutelNaam`." - }, - "confServer": "**Server Instelling {{key}}**\n{{list}}", - "confDashboardOnlyKey": "`{{key}}` kan alleen worden geconfigureerd via het web dashboard ()", - "confSettingNotSet": "Niet ingesteld", - "rolesetDescription": "Beheer unieke rolesets.", - "rolesetExtended": { - "usages": [ - "set RoleSetNaam Role1 Role2 Role3...", - "set RoleSetNaam Role1 Role2 Role3...", - "reset", - "reset RoleSetNaam", - "list", - "RoleSetNaam Role1 Role2 Role3" - ], - "extendedHelp": "Een set van rollen beschouw die ik als uniek voor alle leden op de server, dat wil zeggen, een roleset genaamd `region` zou de rollen `Afrika`, `America`, `Azië`, en `Europe` kunnen hebben, en leden kunnen zullen dan altijd maar één deze rollen kunnen hebben. Dit is als een soort \"regel\" dat wordt toegepast in de drie volgende situaties:\n\n- Wanneer iemand een rol claimt via het commando `rollen`.\n- Wanneer iemand een rol opeist via reactie rollen.\n- Wanneer iemand een rol handmatig of van een andere bot ontvangt.", - "explainedUsage": [ - [ - "toevoegen", - "Maak een nieuwe rol groep of voeg een bestaande toe." - ], - [ - "verwijderen", - "Een rol van een bestaande rol groep verwijderen." - ], - [ - "reset", - "Verwijder alle rollen van een rol groep of, wanneer niet gespecificeerd, alle bestaande rol groepen." - ], - [ - "lijst", - "Geeft alle rollen weer." - ], - [ - "automatisch", - "Voeg rol groep to of verwijder een rol groep." - ], - [ - "RoleSetNaam", - "De naam van de roleset" - ], - [ - "Role1 Role2 Role3", - "De rollen om toe te voegen aan de roleset" - ] - ], - "examples": [ - "add regions Amerika", - "add regions Afrika Amerika Azië Europa", - "remove regions Amerika", - "reset", - "reset regions", - "lijst", - "regions Amerika", - "regions Afrika Amerika Azië Europe" - ], - "reminder": "Dit commando kan meerdere rollen tegelijkertijd toevoegen en/of verwijderen." - }, - "rolesetCreated": "", - "rolesetAdded": "", - "rolesetRemoved": "", - "rolesetResetEmpty": "{{REDCROSS}} Er zijn geen rollen geconfigureerd in deze set.", - "rolesetResetAll": "{{GREENTICK}} Alle rollen sets zijn verwijderd.", - "rolesetResetNotExists": "{{REDCROSS}} De set van rollen met de naam `{{name}}` bestaat niet in deze server.", - "rolesetResetGroup": "{{GREENTICK}} De set van rollen met de naam `{{name}}` is succesvol verwijderd van de server.", - "rolesetUpdated": "De set van rollen met de naam {{name}} is bijgewerkt.", - "rolesetNoRolesets": "Je hebt geen rolesets.", - "confMenuRenderAtFolder": "Momenteel in: 📁 {{path}}", - "confMenuRenderAtPiece": "Momenteel bij: ⚙️ {{path}}", - "confMenuRenderNokeys": "Er zijn geen configureerbare opties in deze map", - "confMenuRenderSelect": "Typ een van de volgende invoernamen in", - "confMenuRenderUpdate": "• Update Waarde → `set `", - "confMenuRenderRemove": "• Verwijder Waarde → `remove `", - "confMenuRenderReset": "• Reset Waarde → `reset`", - "confMenuRenderUndo": "• Update ongedaan maken → `undo`", - "confMenuRenderCvalue": "Huidige waarde: **``{{value}}``**", - "confMenuRenderBack": "Druk op ◀ om terug te gaan", - "confMenuInvalidKey": "Ongeldige sleutel, probeer het opnieuw met een van de volgende opties:", - "confMenuInvalidAction": "Ongeldige actie, probeer het opnieuw met een van de volgende opties:", - "confMenuSaved": "Wijzigingen zijn succesvol opgeslagen." -} \ No newline at end of file diff --git a/src/languages/nl/commands/animal.json b/src/languages/nl/commands/animal.json deleted file mode 100644 index 0cce0082c..000000000 --- a/src/languages/nl/commands/animal.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "bunnyDescription": "", - "bunnyExtended": { - "extendedHelp": "" - }, - "bunnyEmbedData": { - "title": "", - "source": "" - }, - "dogDescription": "Schattige hondjes! ❤", - "dogExtended": { - "extendedHelp": "" - }, - "foxDescription": "Laat me je een foto van een vos tonen!", - "foxExtended": { - "extendedHelp": "" - }, - "kittyDescription": "KITTENS!", - "kittyExtended": { - "extendedHelp": "" - }, - "shibeDescription": "Schattige shibas!", - "shibeExtended": { - "extendedHelp": "Iedereen houdt van shibas, dus ik ook! Ze zijn zo schattig ❤" - } -} \ No newline at end of file diff --git a/src/languages/nl/commands/auto-moderation.json b/src/languages/nl/commands/auto-moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/nl/commands/auto-moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/nl/commands/case.json b/src/languages/nl/commands/case.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/nl/commands/case.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/nl/commands/fun.json b/src/languages/nl/commands/fun.json deleted file mode 100644 index 7892e327d..000000000 --- a/src/languages/nl/commands/fun.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "escaperopeDescription": "", - "escaperopeExtended": { - "extendedHelp": "" - }, - "escaperopeOutput": "" -} \ No newline at end of file diff --git a/src/languages/nl/commands/game.json b/src/languages/nl/commands/game.json deleted file mode 100644 index 8075ca93c..000000000 --- a/src/languages/nl/commands/game.json +++ /dev/null @@ -1,447 +0,0 @@ -{ - "c4Description": "", - "c4Extended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "c4Prompt": "", - "gamesBot": "", - "gamesNoPlayers": "", - "gamesProgress": "", - "gamesPromptDeny": "", - "gamesRepeat": "", - "gamesSelf": "", - "gamesTooManyOrFew": "", - "hgBloodbath": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgDay": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgNight": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hungerGamesDescription": "", - "hungerGamesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "examples": [ - "" - ], - "reminder": "" - }, - "hungerGamesResultDeaths_one": "", - "hungerGamesResultDeaths_other": "", - "hungerGamesResultHeaderBloodbath": "", - "hungerGamesResultHeaderMoon": "", - "hungerGamesResultHeaderSun": "", - "hungerGamesResultProceed": "", - "hungerGamesStop": "", - "hungerGamesWinner": "", - "ticTacToeDescription": "", - "ticTacToeDraw": "", - "ticTacToeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "ticTacToePrompt": "", - "ticTacToeTurn": "", - "ticTacToeWinner": "", - "triviaActiveGame": "", - "triviaDescription": "", - "triviaEmbedTitles": { - "difficulty": "", - "trivia": "" - }, - "triviaExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "triviaIncorrect": "", - "triviaInvalidCategory": "", - "triviaNoAnswer": "", - "triviaWinner": "" -} \ No newline at end of file diff --git a/src/languages/nl/commands/general.json b/src/languages/nl/commands/general.json deleted file mode 100644 index 5e16f992d..000000000 --- a/src/languages/nl/commands/general.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "helpAllFlag": "", - "helpCommandCount_one": "", - "helpCommandCount_other": "", - "helpData": { - "footer": "", - "title": "" - }, - "helpDescription": "", - "helpExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "reminder": "", - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "helpDm": "", - "helpNodm": "", - "v7Description": "", - "v7Extended": { - "extendedHelp": "" - }, - "v7Message": "", - "v7NayreMessage": "" -} \ No newline at end of file diff --git a/src/languages/nl/commands/info.json b/src/languages/nl/commands/info.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/nl/commands/info.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/nl/commands/management.json b/src/languages/nl/commands/management.json deleted file mode 100644 index 21ef26ce2..000000000 --- a/src/languages/nl/commands/management.json +++ /dev/null @@ -1,445 +0,0 @@ -{ - "commandHandlerAborted": "", - "permissionNodesHigher": "", - "permissionNodesCannotAllowEveryone": "", - "permissionNodesInvalidType": "", - "permissionNodesAdd": "", - "permissionNodesNodeNotExists": "", - "permissionNodesCommandNotExists": "", - "permissionNodesRemove": "", - "permissionNodesReset": "", - "permissionNodesShowName": "", - "permissionNodesShowAllow": "", - "permissionNodesShowDeny": "", - "guildInfoTitles": { - "CHANNELS": "", - "MEMBERS": "", - "OTHER": "" - }, - "guildInfoChannels": "", - "guildInfoChannelsAfkChannelText": "", - "guildInfoMembers": "", - "guildInfoOther": "", - "guildInfoBanner": "", - "guildInfoIcon": "", - "guildInfoSplash": "", - "guildInfoDiscoverySplash": "", - "roleInfoTitles": { - "PERMISSIONS": "" - }, - "roleInfoData": "", - "roleInfoAll": "", - "roleInfoNoPermissions": "", - "manageCommandAutoDeleteShowEmpty": "", - "manageCommandAutoDeleteShow": "", - "manageCommandAutoDeleteAdd": "", - "manageCommandAutoDeleteRemove": "", - "manageCommandAutoDeleteRemoveNotset": "", - "manageCommandAutoDeleteReset": "", - "manageCommandChannelShow": "", - "manageCommandChannelShowEmpty": "", - "manageCommandChannelAddAlreadyset": "", - "manageCommandChannelAdd": "", - "manageCommandChannelRemoveNotset": "", - "manageCommandChannelRemove": "", - "manageCommandChannelResetEmpty": "", - "manageCommandChannelReset": "", - "manageReactionRolesShowEmpty": "", - "manageReactionRolesAddChannel": "", - "manageReactionRolesAddPrompt": "", - "manageReactionRolesAddMissing": "", - "manageReactionRolesAdd": "", - "manageReactionRolesRemoveNotExists": "", - "manageReactionRolesRemove": "", - "manageReactionRolesResetEmpty": "", - "manageReactionRolesReset": "", - "configurationEquals": "", - "setIgnoreChannelsSet": "", - "setIgnoreChannelsRemoved": "", - "setImageLogsSet": "", - "setMemberAddLogsSet": "", - "setMemberRemoveLogsSet": "", - "setMessageUpdateLogsSet": "", - "setMessageDeleteLogsSet": "", - "setModLogsSet": "", - "setPrefixSet": "", - "stickyRolesNotExists": "", - "stickyRolesReset": "", - "stickyRolesRemove": "", - "stickyRolesAdd": "", - "stickyRolesShowEmpty": "", - "stickyRolesShowSingle": "", - "createMuteDescription": "", - "createMuteExtended": { - "extendedHelp": "" - }, - "permissionNodesDescription": "", - "permissionNodesExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "managecommandautodeleteDescription": "", - "managecommandautodeleteExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageCommandChannelDescription": "", - "manageCommandChannelExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageReactionRolesDescription": "", - "manageReactionRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "rolesAdded": "", - "rolesAuditlog": "", - "rolesListEmpty": "", - "rolesListTitle": "", - "rolesNotManageable": "", - "rolesNotPublic": "", - "rolesRemoved": "", - "setIgnoreChannelsDescription": "", - "setIgnoreChannelsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setImageLogsDescription": "", - "setImageLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "setMemberAddLogsDescription": "", - "setMemberAddLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMemberRemoveLogsDescription": "", - "setMemberRemoveLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMessageUpdateLogsDescription": "", - "setMessageUpdateLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setMessageDeleteLogsDescription": "", - "setMessageDeleteLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setmodlogsDescription": "", - "setmodlogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setprefixDescription": "", - "setprefixExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "guildInfoDescription": "", - "guildInfoExtended": { - "extendedHelp": "" - }, - "roleInfoDescription": "", - "roleInfoExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "stickyRolesDescription": "", - "stickyRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesDescription": "", - "rolesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/nl/commands/misc.json b/src/languages/nl/commands/misc.json deleted file mode 100644 index 32f64d584..000000000 --- a/src/languages/nl/commands/misc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "snipeEmpty": "", - "snipeTitle": "", - "snipeDescription": "", - "snipeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/nl/commands/moderation.json b/src/languages/nl/commands/moderation.json deleted file mode 100644 index 815d1c788..000000000 --- a/src/languages/nl/commands/moderation.json +++ /dev/null @@ -1,889 +0,0 @@ -{ - "permissions": "", - "permissionsAll": "", - "slowmodeSet": "", - "slowmodeReset": "", - "banNotBannable": "", - "dehoistStarting": "", - "dehoistProgress": "", - "dehoistEmbed": { - "title": "", - "descriptionNoone": "", - "descriptionWithError": "", - "descriptionWithMultipleErrors": "", - "description": "", - "descriptionMultipleMembers": "", - "fieldErrorTitle": "" - }, - "kickNotKickable": "", - "lockdownLock": "", - "lockdownLocking": "", - "lockdownLocked": "", - "lockdownUnlocked": "", - "lockdownOpen": "", - "muteMuted": "", - "muteUserNotMuted": "", - "restrictLowlevel": "", - "pruneAlert_one": "", - "pruneAlert_other": "", - "pruneInvalidPosition": "", - "pruneNoDeletes": "", - "pruneLogHeader": "", - "toggleModerationDmToggledEnabled": "", - "toggleModerationDmToggledDisabled": "", - "moderationOutput_one": "", - "moderationOutput_other": "", - "moderationOutputWithReason_one": "", - "moderationOutputWithReason_other": "", - "moderationFailed_one": "", - "moderationFailed_other": "", - "moderationDmFooter": "", - "moderationDmDescription": "", - "moderationDmDescriptionWithReason": "", - "moderationDmDescriptionWithDuration": "", - "moderationDmDescriptionWithReasonWithDuration": "", - "slowmodeDescription": "", - "slowmodeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "banDescription": "", - "banExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "dehoistDescription": "", - "dehoistExtended": { - "extendedHelp": "", - "reminder": "" - }, - "kickDescription": "", - "kickExtended": { - "usages": [ - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "lockdownDescription": "", - "lockdownExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "muteDescription": "", - "muteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "setNicknameDescription": "", - "setNicknameExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ], - "reminder": "" - }, - "addRoleDescription": "", - "addRoleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "removeroleDescription": "", - "removeroleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "pruneDescription": "", - "pruneExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "permissionsDescription": "", - "permissionsExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ], - "extendedHelp": "" - }, - "restrictAttachmentDescription": "", - "restrictAttachmentExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictEmbedDescription": "", - "restrictEmbedExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictEmojiDescription": "", - "restrictEmojiExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictReactionDescription": "", - "restrictReactionExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictVoiceDescription": "", - "restrictVoiceExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "softBanDescription": "", - "softBanExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "timeoutApplyDescription": "", - "timeoutApplyExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutUndoDescription": "", - "timeoutUndoExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutNotModeratable": "", - "toggleModerationDmDescription": "", - "toggleModerationDmExtended": { - "extendedHelp": "" - }, - "unbanDescription": "", - "unbanExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unmuteDescription": "", - "unmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unrestrictAttachmentDescription": "", - "unrestrictAttachmentExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmbedDescription": "", - "unrestrictEmbedExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmojiDescription": "", - "unrestrictEmojiExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictReactionDescription": "", - "unrestrictReactionExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictVoiceDescription": "", - "unrestrictVoiceExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unwarnDescription": "", - "unwarnExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vmuteDescription": "", - "vmuteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "voiceKickDescription": "", - "voiceKickExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vunmuteDescription": "", - "vunmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "warnDescription": "", - "warnExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/nl/commands/shared.json b/src/languages/nl/commands/shared.json deleted file mode 100644 index ddbb28e7f..000000000 --- a/src/languages/nl/commands/shared.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "deprecatedMessage": "", - "slashOnlyDetailedDescription": { - "extendedHelp": "" - }, - "slashOnlyErrorMessage": "" -} \ No newline at end of file diff --git a/src/languages/nl/commands/system.json b/src/languages/nl/commands/system.json deleted file mode 100644 index e9cfdeec4..000000000 --- a/src/languages/nl/commands/system.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "evalDescription": "", - "evalExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "evalTimeout": "", - "evalError": "", - "dmNotSent": "", - "dmSent": "", - "reboot": "", - "rebootDescription": "", - "rebootExtended": { - "extendedHelp": "", - "reminder": "" - } -} \ No newline at end of file diff --git a/src/languages/nl/commands/tools.json b/src/languages/nl/commands/tools.json deleted file mode 100644 index 01bd03e25..000000000 --- a/src/languages/nl/commands/tools.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "avatarDescription": "", - "avatarExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "" - }, - "avatarNone": "", - "voteDescription": "", - "voteExtended": { - "usages": [ - "" - ], - "examples": [ - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "voteContentNeeded": "", - "voteReactionBlocked": "", - "whoisExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "whoisMemberRoleListAndMore": "" -} \ No newline at end of file diff --git a/src/languages/nl/commands/twitch.json b/src/languages/nl/commands/twitch.json deleted file mode 100644 index 2f12e1b08..000000000 --- a/src/languages/nl/commands/twitch.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "twitchSubscriptionStreamerNotFound": "", - "twitchSubscriptionStatusValues": [ - "", - "" - ], - "twitchSubscriptionInvalidStatus": "", - "twitchSubscriptionAddDuplicated": "", - "twitchSubscriptionAddSuccessOffline": "", - "twitchSubscriptionAddSuccessLive": "", - "twitchSubscriptionAddMessageForOfflineRequired": "", - "twitchSubscriptionRemoveOrResetEmpty": "", - "twitchSubscriptionRemoveStreamerNotSubscribed": "", - "twitchSubscriptionRemoveNotToProvidedChannel": "", - "twitchSubscriptionRemoveStreamerStatusNotMatch": "", - "twitchSubscriptionRemoveSuccessOffline": "", - "twitchSubscriptionRemoveSuccessLive": "", - "twitchSubscriptionResetSuccess_one": "", - "twitchSubscriptionResetSuccess_other": "", - "twitchSubscriptionShowStreamerNotSubscribed": "", - "twitchSubscriptionShowStatus": { - "live": "", - "offline": "" - }, - "twitchSubscriptionShowUnknownUser": "", - "twitchSubscriptionDescription": "", - "twitchSubscriptionExtended": { - "usages": [ - "", - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/nl/commands/whois.json b/src/languages/nl/commands/whois.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/nl/commands/whois.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/nl/constants.ts b/src/languages/nl/constants.ts deleted file mode 100644 index 93dd05faa..000000000 --- a/src/languages/nl/constants.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Handler } from '#lib/i18n/structures/Handler'; -import { TimeTypes } from '@sapphire/time-utilities'; - -export class ExtendedHandler extends Handler { - public constructor() { - super({ - name: 'nl', - duration: { - [TimeTypes.Year]: { - 1: 'jaar', - DEFAULT: 'jaren' - }, - [TimeTypes.Month]: { - 1: 'maand', - DEFAULT: 'maanden' - }, - [TimeTypes.Week]: { - 1: 'week', - DEFAULT: 'weken' - }, - [TimeTypes.Day]: { - 1: 'dag', - DEFAULT: 'dagen' - }, - [TimeTypes.Hour]: { - 1: 'uur', - DEFAULT: 'uren' - }, - [TimeTypes.Minute]: { - 1: 'minuut', - DEFAULT: 'minuten' - }, - [TimeTypes.Second]: { - 1: 'seconde', - DEFAULT: 'seconden' - } - } - }); - } -} diff --git a/src/languages/nl/errors.json b/src/languages/nl/errors.json deleted file mode 100644 index 923d932e4..000000000 --- a/src/languages/nl/errors.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "guildBansEmpty": "Er zijn geen verbanningen geregistreerd in deze server.", - "guildBansNotFound": "Ik heb geprobeerd en het is niet gelukt om deze gebruiker uit de bloklijst te vinden. Weet je zeker dat deze gebruiker geblokkeerd is?", - "guildMemberNotVoicechannel": "Ik kan deze actie niet uitvoeren op een lid dat niet verbonden is met een spraakkanaal.", - "guildWarnNotFound": "Het is me niet gelukt om die waarschuwing op te halen. De waarschuwing bestaat niet, het is geen waarschuwing, of hij is al teruggedraaid.", - "modlogTimed": "Deze moderatie log is al tijdelijk gezet. Deze verloopt in {{remaining, duration}}", - "unexpectedIssue": "Er is een onverwachte fout opgetreden! Deze opdracht wordt gestopt...", - "userNotInGuild": "Deze gebruiker is niet in deze server." -} \ No newline at end of file diff --git a/src/languages/nl/events/errors.json b/src/languages/nl/events/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/nl/events/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/nl/events/guilds-logs.json b/src/languages/nl/events/guilds-logs.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/nl/events/guilds-logs.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/nl/events/guilds-members.json b/src/languages/nl/events/guilds-members.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/nl/events/guilds-members.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/nl/events/messages.json b/src/languages/nl/events/messages.json deleted file mode 100644 index bd1a57a16..000000000 --- a/src/languages/nl/events/messages.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "messageDelete": "Bericht verwijderd • {{channel}}", - "messageUpdate": "Bericht bewerkt • {{channel}}" -} \ No newline at end of file diff --git a/src/languages/nl/events/moderation.json b/src/languages/nl/events/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/nl/events/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/nl/events/noMentionSpam.json b/src/languages/nl/events/noMentionSpam.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/nl/events/noMentionSpam.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/nl/events/reactions.json b/src/languages/nl/events/reactions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/nl/events/reactions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/nl/events/twitch.json b/src/languages/nl/events/twitch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/nl/events/twitch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/nl/fuzzySearch.json b/src/languages/nl/fuzzySearch.json deleted file mode 100644 index d591ddc44..000000000 --- a/src/languages/nl/fuzzySearch.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "aborted": "De vraag is succesvol afgebroken.", - "invalidIndex": "Dat nummer was buiten bereik, vraag wordt gestopt.", - "invalidNumber": "Ik verwachtte dat je me een (één cijfer) nummer zou geven, maar ik kreeg een aardappel.", - "matches": "Meerdere overeenkomsten zijn gevonden. **Selecteer een nummer tussen 0 en {{matches}}**:\n{{codeblock}}\nSchrijf **ABORT** als je wil stoppen met de vraag." -} \ No newline at end of file diff --git a/src/languages/nl/globals.json b/src/languages/nl/globals.json deleted file mode 100644 index 829101643..000000000 --- a/src/languages/nl/globals.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "default": "{{key}} is nog niet gelokaliseerd voor nl-NL.", - "defaultLanguage": "Standaard taal", - "no": "Nee", - "none": "Geen", - "unknown": "onbekend", - "yes": "Ja", - "paginatedMessagePage": "Pagina", - "paginatedMessageWrongUserInteractionReply": "Stop met het klikken op de knoppen voor dit bericht. Ze zijn alleen voor {{user}}.", - "durationValue": "{{value, duration}}", - "numberValue": "{{value, number}}", - "numberCompactValue": "{{value, numberCompact}}", - "dateTimeValue": "{{value, dateTime}}", - "orListValue": "{{value, orList}}", - "dateFormat": "MM/DD/JJJJ", - "dateFormatExplanation": "Maand/Dag/Jaar" -} \ No newline at end of file diff --git a/src/languages/nl/guilds.json b/src/languages/nl/guilds.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/nl/guilds.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/nl/humanLevels.json b/src/languages/nl/humanLevels.json deleted file mode 100644 index f8e8e8e3a..000000000 --- a/src/languages/nl/humanLevels.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "None": "Geen", - "Low": "Laag", - "Medium": "Gemiddeld", - "High": "Hoog", - "VeryHigh": "Hoogste" -} \ No newline at end of file diff --git a/src/languages/nl/moderation.json b/src/languages/nl/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/nl/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/nl/moderationActions.json b/src/languages/nl/moderationActions.json deleted file mode 100644 index 4c440ae54..000000000 --- a/src/languages/nl/moderationActions.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "actions": { - "addRole": "", - "ban": "", - "kick": "", - "mute": "", - "removeRole": "", - "restrictedAttachment": "", - "restrictedEmbed": "", - "restrictedEmoji": "", - "restrictedReact": "", - "restrictedVoice": "", - "setNickname": "", - "softban": "", - "vkick": "", - "vmute": "", - "warning": "" - }, - "actionCannotManageRoles": "", - "actionRoleNotConfigured": "", - "actionRoleHigherPosition": "", - "actionRoleManaged": "", - "applyNoReason": "", - "applyReason": "", - "requiredMember": "", - "revokeNoReason": "", - "revokeReason": "", - "setNicknameNoReasonRemoved": "", - "setNicknameNoReasonSet": "", - "setNicknameRemoved": "", - "setNicknameSet": "", - "setupMuteExists": "", - "setupTooManyRoles": "", - "sharedRoleSetupAsk": "", - "sharedRoleSetupNoMessage": "", - "sharedRoleSetupExisting": "", - "sharedRoleSetupExistingName": "", - "sharedRoleSetupNew": "", - "softbanNoReason": "", - "softbanReason": "", - "unSoftbanNoReason": "", - "unSoftbanReason": "" -} \ No newline at end of file diff --git a/src/languages/nl/permissions.json b/src/languages/nl/permissions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/nl/permissions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/nl/preconditions.json b/src/languages/nl/preconditions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/nl/preconditions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/nl/selfModeration.json b/src/languages/nl/selfModeration.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/nl/selfModeration.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/nl/serializers.json b/src/languages/nl/serializers.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/nl/serializers.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/nl/settings.json b/src/languages/nl/settings.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/nl/settings.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/nl/system.json b/src/languages/nl/system.json deleted file mode 100644 index ffc7ff94c..000000000 --- a/src/languages/nl/system.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "discordAbortError": "Er is een kleine netwerkfout opgetreden bij het versturen van Discord, voer deze opdracht alstublieft opnieuw uit!", - "fetchBansFail": "Mislukt om ban's op te halen. Heb ik de **{{ADMINISTRATOR, permissions}}** permissie?", - "helpTitles": { - "aliases": "🖇️ ・**Aliases**", - "usages": "📝 ľ**Command Gebruik**", - "extendedHelp": "🔍 | **Uitgebreide Hulp**", - "explainedUsage": "⚙ | **Uitgelegd gebruik**", - "possibleFormats": "🔢 | **Mogelijke formaten**", - "examples": "🔗 | **Voorbeelden**", - "reminders": "⏰ | **Herinnering**" - }, - "jumpTo": "Link naar bericht ►", - "loading": [ - "{{LOADING}} hamsters bekijken...", - "{{LOADING}} mensen vinden in verstoppertje...", - "{{LOADING}} uitzoeken van dit commando...", - "{{LOADING}} Gegevens ophalen uit de cloud...", - "{{LOADING}} Lenzen schoonmaken...", - "{{LOADING}} Steen, papier, schaar spelen...", - "{{LOADING}} Opzoeken van de correcte frequentie...", - "{{LOADING}} Wacht op antwoord..." - ], - "prefixReminder": "De prefix in deze server is ingesteld op: `{{prefix}}`" -} \ No newline at end of file diff --git a/src/languages/no/arguments.json b/src/languages/no/arguments.json deleted file mode 100644 index a7befa6f3..000000000 --- a/src/languages/no/arguments.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "boolean_one": "", - "boolean_other": "", - "booleanError": "", - "booleanDisabled": "", - "booleanEnabled": "", - "booleanFalseOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "booleanTrueOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "caseNoEntries": "", - "caseUnknownEntry": "", - "caseNotInThisGuild": "", - "caseLatestOptions": [ - "", - "" - ], - "categoryChannelError": "", - "channelError": "", - "command": "", - "commandMatch": "", - "dateError": "", - "dateFormats": "", - "dateTooEarly": "", - "dateTooFar": "", - "dmChannelError": "", - "duration": "", - "durationFormats": "", - "emojiError": "", - "floatError": "", - "floatTooLarge": "", - "floatTooSmall": "", - "guildChannelError": "", - "guildChannelMismatchingError": "", - "guildChannelMissingGuildError": "", - "guildPrivateThreadChannelError": "", - "guildPublicThreadChannelError": "", - "guildStageVoiceChannelError": "", - "guildTextChannelError": "", - "guildThreadChannelError": "", - "guildVoiceChannelError": "", - "hyperlinkError": "", - "integerError": "", - "integerTooLarge": "", - "integerTooSmall": "", - "invite": "", - "language": "", - "memberError": "", - "memberMissingGuild": "", - "messageError": "", - "missing": "", - "newsChannel": "", - "numberError": "", - "numberTooLarge": "", - "numberTooSmall": "", - "piece": "", - "rangeInvalid": "", - "rangeMax_other": "", - "rangeMax_one": "", - "resetPossibles": [ - "", - "" - ], - "roleError": "", - "roleMissingGuild": "", - "snowflake": "", - "store": "", - "stringTooLong": "", - "stringTooShort": "", - "time": "", - "timeSpan": "", - "timeSpanTooBig": "", - "timeSpanTooSmall": "", - "tooFewWinners": "", - "tooManyWinners": "", - "unavailable": "", - "userError": "", - "enumEmptyError": "", - "enumError": "" -} \ No newline at end of file diff --git a/src/languages/no/assertions.json b/src/languages/no/assertions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/no/assertions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/no/commands/admin.json b/src/languages/no/commands/admin.json deleted file mode 100644 index 444f39c28..000000000 --- a/src/languages/no/commands/admin.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "confUpdated": "", - "confGetNoExt": "", - "confGet": "", - "confReset": "", - "confNochange": "", - "confServerDescription": "", - "confServerExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "confServer": "", - "confDashboardOnlyKey": "", - "confSettingNotSet": "", - "rolesetDescription": "", - "rolesetExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesetCreated": "", - "rolesetAdded": "", - "rolesetRemoved": "", - "rolesetResetEmpty": "", - "rolesetResetAll": "", - "rolesetResetNotExists": "", - "rolesetResetGroup": "", - "rolesetUpdated": "", - "rolesetNoRolesets": "", - "confMenuRenderAtFolder": "", - "confMenuRenderAtPiece": "", - "confMenuRenderNokeys": "", - "confMenuRenderSelect": "", - "confMenuRenderUpdate": "", - "confMenuRenderRemove": "", - "confMenuRenderReset": "", - "confMenuRenderUndo": "", - "confMenuRenderCvalue": "", - "confMenuRenderBack": "", - "confMenuInvalidKey": "", - "confMenuInvalidAction": "", - "confMenuSaved": "" -} \ No newline at end of file diff --git a/src/languages/no/commands/animal.json b/src/languages/no/commands/animal.json deleted file mode 100644 index 6d00e57af..000000000 --- a/src/languages/no/commands/animal.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "bunnyDescription": "", - "bunnyExtended": { - "extendedHelp": "" - }, - "bunnyEmbedData": { - "title": "", - "source": "" - }, - "dogDescription": "", - "dogExtended": { - "extendedHelp": "" - }, - "foxDescription": "", - "foxExtended": { - "extendedHelp": "" - }, - "kittyDescription": "", - "kittyExtended": { - "extendedHelp": "" - }, - "shibeDescription": "", - "shibeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/no/commands/auto-moderation.json b/src/languages/no/commands/auto-moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/no/commands/auto-moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/no/commands/case.json b/src/languages/no/commands/case.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/no/commands/case.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/no/commands/fun.json b/src/languages/no/commands/fun.json deleted file mode 100644 index 7892e327d..000000000 --- a/src/languages/no/commands/fun.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "escaperopeDescription": "", - "escaperopeExtended": { - "extendedHelp": "" - }, - "escaperopeOutput": "" -} \ No newline at end of file diff --git a/src/languages/no/commands/game.json b/src/languages/no/commands/game.json deleted file mode 100644 index 8075ca93c..000000000 --- a/src/languages/no/commands/game.json +++ /dev/null @@ -1,447 +0,0 @@ -{ - "c4Description": "", - "c4Extended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "c4Prompt": "", - "gamesBot": "", - "gamesNoPlayers": "", - "gamesProgress": "", - "gamesPromptDeny": "", - "gamesRepeat": "", - "gamesSelf": "", - "gamesTooManyOrFew": "", - "hgBloodbath": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgDay": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgNight": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hungerGamesDescription": "", - "hungerGamesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "examples": [ - "" - ], - "reminder": "" - }, - "hungerGamesResultDeaths_one": "", - "hungerGamesResultDeaths_other": "", - "hungerGamesResultHeaderBloodbath": "", - "hungerGamesResultHeaderMoon": "", - "hungerGamesResultHeaderSun": "", - "hungerGamesResultProceed": "", - "hungerGamesStop": "", - "hungerGamesWinner": "", - "ticTacToeDescription": "", - "ticTacToeDraw": "", - "ticTacToeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "ticTacToePrompt": "", - "ticTacToeTurn": "", - "ticTacToeWinner": "", - "triviaActiveGame": "", - "triviaDescription": "", - "triviaEmbedTitles": { - "difficulty": "", - "trivia": "" - }, - "triviaExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "triviaIncorrect": "", - "triviaInvalidCategory": "", - "triviaNoAnswer": "", - "triviaWinner": "" -} \ No newline at end of file diff --git a/src/languages/no/commands/general.json b/src/languages/no/commands/general.json deleted file mode 100644 index 5e16f992d..000000000 --- a/src/languages/no/commands/general.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "helpAllFlag": "", - "helpCommandCount_one": "", - "helpCommandCount_other": "", - "helpData": { - "footer": "", - "title": "" - }, - "helpDescription": "", - "helpExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "reminder": "", - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "helpDm": "", - "helpNodm": "", - "v7Description": "", - "v7Extended": { - "extendedHelp": "" - }, - "v7Message": "", - "v7NayreMessage": "" -} \ No newline at end of file diff --git a/src/languages/no/commands/info.json b/src/languages/no/commands/info.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/no/commands/info.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/no/commands/management.json b/src/languages/no/commands/management.json deleted file mode 100644 index 21ef26ce2..000000000 --- a/src/languages/no/commands/management.json +++ /dev/null @@ -1,445 +0,0 @@ -{ - "commandHandlerAborted": "", - "permissionNodesHigher": "", - "permissionNodesCannotAllowEveryone": "", - "permissionNodesInvalidType": "", - "permissionNodesAdd": "", - "permissionNodesNodeNotExists": "", - "permissionNodesCommandNotExists": "", - "permissionNodesRemove": "", - "permissionNodesReset": "", - "permissionNodesShowName": "", - "permissionNodesShowAllow": "", - "permissionNodesShowDeny": "", - "guildInfoTitles": { - "CHANNELS": "", - "MEMBERS": "", - "OTHER": "" - }, - "guildInfoChannels": "", - "guildInfoChannelsAfkChannelText": "", - "guildInfoMembers": "", - "guildInfoOther": "", - "guildInfoBanner": "", - "guildInfoIcon": "", - "guildInfoSplash": "", - "guildInfoDiscoverySplash": "", - "roleInfoTitles": { - "PERMISSIONS": "" - }, - "roleInfoData": "", - "roleInfoAll": "", - "roleInfoNoPermissions": "", - "manageCommandAutoDeleteShowEmpty": "", - "manageCommandAutoDeleteShow": "", - "manageCommandAutoDeleteAdd": "", - "manageCommandAutoDeleteRemove": "", - "manageCommandAutoDeleteRemoveNotset": "", - "manageCommandAutoDeleteReset": "", - "manageCommandChannelShow": "", - "manageCommandChannelShowEmpty": "", - "manageCommandChannelAddAlreadyset": "", - "manageCommandChannelAdd": "", - "manageCommandChannelRemoveNotset": "", - "manageCommandChannelRemove": "", - "manageCommandChannelResetEmpty": "", - "manageCommandChannelReset": "", - "manageReactionRolesShowEmpty": "", - "manageReactionRolesAddChannel": "", - "manageReactionRolesAddPrompt": "", - "manageReactionRolesAddMissing": "", - "manageReactionRolesAdd": "", - "manageReactionRolesRemoveNotExists": "", - "manageReactionRolesRemove": "", - "manageReactionRolesResetEmpty": "", - "manageReactionRolesReset": "", - "configurationEquals": "", - "setIgnoreChannelsSet": "", - "setIgnoreChannelsRemoved": "", - "setImageLogsSet": "", - "setMemberAddLogsSet": "", - "setMemberRemoveLogsSet": "", - "setMessageUpdateLogsSet": "", - "setMessageDeleteLogsSet": "", - "setModLogsSet": "", - "setPrefixSet": "", - "stickyRolesNotExists": "", - "stickyRolesReset": "", - "stickyRolesRemove": "", - "stickyRolesAdd": "", - "stickyRolesShowEmpty": "", - "stickyRolesShowSingle": "", - "createMuteDescription": "", - "createMuteExtended": { - "extendedHelp": "" - }, - "permissionNodesDescription": "", - "permissionNodesExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "managecommandautodeleteDescription": "", - "managecommandautodeleteExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageCommandChannelDescription": "", - "manageCommandChannelExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageReactionRolesDescription": "", - "manageReactionRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "rolesAdded": "", - "rolesAuditlog": "", - "rolesListEmpty": "", - "rolesListTitle": "", - "rolesNotManageable": "", - "rolesNotPublic": "", - "rolesRemoved": "", - "setIgnoreChannelsDescription": "", - "setIgnoreChannelsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setImageLogsDescription": "", - "setImageLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "setMemberAddLogsDescription": "", - "setMemberAddLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMemberRemoveLogsDescription": "", - "setMemberRemoveLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMessageUpdateLogsDescription": "", - "setMessageUpdateLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setMessageDeleteLogsDescription": "", - "setMessageDeleteLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setmodlogsDescription": "", - "setmodlogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setprefixDescription": "", - "setprefixExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "guildInfoDescription": "", - "guildInfoExtended": { - "extendedHelp": "" - }, - "roleInfoDescription": "", - "roleInfoExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "stickyRolesDescription": "", - "stickyRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesDescription": "", - "rolesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/no/commands/misc.json b/src/languages/no/commands/misc.json deleted file mode 100644 index 32f64d584..000000000 --- a/src/languages/no/commands/misc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "snipeEmpty": "", - "snipeTitle": "", - "snipeDescription": "", - "snipeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/no/commands/moderation.json b/src/languages/no/commands/moderation.json deleted file mode 100644 index 815d1c788..000000000 --- a/src/languages/no/commands/moderation.json +++ /dev/null @@ -1,889 +0,0 @@ -{ - "permissions": "", - "permissionsAll": "", - "slowmodeSet": "", - "slowmodeReset": "", - "banNotBannable": "", - "dehoistStarting": "", - "dehoistProgress": "", - "dehoistEmbed": { - "title": "", - "descriptionNoone": "", - "descriptionWithError": "", - "descriptionWithMultipleErrors": "", - "description": "", - "descriptionMultipleMembers": "", - "fieldErrorTitle": "" - }, - "kickNotKickable": "", - "lockdownLock": "", - "lockdownLocking": "", - "lockdownLocked": "", - "lockdownUnlocked": "", - "lockdownOpen": "", - "muteMuted": "", - "muteUserNotMuted": "", - "restrictLowlevel": "", - "pruneAlert_one": "", - "pruneAlert_other": "", - "pruneInvalidPosition": "", - "pruneNoDeletes": "", - "pruneLogHeader": "", - "toggleModerationDmToggledEnabled": "", - "toggleModerationDmToggledDisabled": "", - "moderationOutput_one": "", - "moderationOutput_other": "", - "moderationOutputWithReason_one": "", - "moderationOutputWithReason_other": "", - "moderationFailed_one": "", - "moderationFailed_other": "", - "moderationDmFooter": "", - "moderationDmDescription": "", - "moderationDmDescriptionWithReason": "", - "moderationDmDescriptionWithDuration": "", - "moderationDmDescriptionWithReasonWithDuration": "", - "slowmodeDescription": "", - "slowmodeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "banDescription": "", - "banExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "dehoistDescription": "", - "dehoistExtended": { - "extendedHelp": "", - "reminder": "" - }, - "kickDescription": "", - "kickExtended": { - "usages": [ - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "lockdownDescription": "", - "lockdownExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "muteDescription": "", - "muteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "setNicknameDescription": "", - "setNicknameExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ], - "reminder": "" - }, - "addRoleDescription": "", - "addRoleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "removeroleDescription": "", - "removeroleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "pruneDescription": "", - "pruneExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "permissionsDescription": "", - "permissionsExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ], - "extendedHelp": "" - }, - "restrictAttachmentDescription": "", - "restrictAttachmentExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictEmbedDescription": "", - "restrictEmbedExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictEmojiDescription": "", - "restrictEmojiExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictReactionDescription": "", - "restrictReactionExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictVoiceDescription": "", - "restrictVoiceExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "softBanDescription": "", - "softBanExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "timeoutApplyDescription": "", - "timeoutApplyExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutUndoDescription": "", - "timeoutUndoExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutNotModeratable": "", - "toggleModerationDmDescription": "", - "toggleModerationDmExtended": { - "extendedHelp": "" - }, - "unbanDescription": "", - "unbanExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unmuteDescription": "", - "unmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unrestrictAttachmentDescription": "", - "unrestrictAttachmentExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmbedDescription": "", - "unrestrictEmbedExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmojiDescription": "", - "unrestrictEmojiExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictReactionDescription": "", - "unrestrictReactionExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictVoiceDescription": "", - "unrestrictVoiceExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unwarnDescription": "", - "unwarnExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vmuteDescription": "", - "vmuteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "voiceKickDescription": "", - "voiceKickExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vunmuteDescription": "", - "vunmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "warnDescription": "", - "warnExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/no/commands/shared.json b/src/languages/no/commands/shared.json deleted file mode 100644 index ddbb28e7f..000000000 --- a/src/languages/no/commands/shared.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "deprecatedMessage": "", - "slashOnlyDetailedDescription": { - "extendedHelp": "" - }, - "slashOnlyErrorMessage": "" -} \ No newline at end of file diff --git a/src/languages/no/commands/system.json b/src/languages/no/commands/system.json deleted file mode 100644 index e9cfdeec4..000000000 --- a/src/languages/no/commands/system.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "evalDescription": "", - "evalExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "evalTimeout": "", - "evalError": "", - "dmNotSent": "", - "dmSent": "", - "reboot": "", - "rebootDescription": "", - "rebootExtended": { - "extendedHelp": "", - "reminder": "" - } -} \ No newline at end of file diff --git a/src/languages/no/commands/tools.json b/src/languages/no/commands/tools.json deleted file mode 100644 index 01bd03e25..000000000 --- a/src/languages/no/commands/tools.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "avatarDescription": "", - "avatarExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "" - }, - "avatarNone": "", - "voteDescription": "", - "voteExtended": { - "usages": [ - "" - ], - "examples": [ - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "voteContentNeeded": "", - "voteReactionBlocked": "", - "whoisExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "whoisMemberRoleListAndMore": "" -} \ No newline at end of file diff --git a/src/languages/no/commands/twitch.json b/src/languages/no/commands/twitch.json deleted file mode 100644 index 2f12e1b08..000000000 --- a/src/languages/no/commands/twitch.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "twitchSubscriptionStreamerNotFound": "", - "twitchSubscriptionStatusValues": [ - "", - "" - ], - "twitchSubscriptionInvalidStatus": "", - "twitchSubscriptionAddDuplicated": "", - "twitchSubscriptionAddSuccessOffline": "", - "twitchSubscriptionAddSuccessLive": "", - "twitchSubscriptionAddMessageForOfflineRequired": "", - "twitchSubscriptionRemoveOrResetEmpty": "", - "twitchSubscriptionRemoveStreamerNotSubscribed": "", - "twitchSubscriptionRemoveNotToProvidedChannel": "", - "twitchSubscriptionRemoveStreamerStatusNotMatch": "", - "twitchSubscriptionRemoveSuccessOffline": "", - "twitchSubscriptionRemoveSuccessLive": "", - "twitchSubscriptionResetSuccess_one": "", - "twitchSubscriptionResetSuccess_other": "", - "twitchSubscriptionShowStreamerNotSubscribed": "", - "twitchSubscriptionShowStatus": { - "live": "", - "offline": "" - }, - "twitchSubscriptionShowUnknownUser": "", - "twitchSubscriptionDescription": "", - "twitchSubscriptionExtended": { - "usages": [ - "", - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/no/commands/whois.json b/src/languages/no/commands/whois.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/no/commands/whois.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/no/errors.json b/src/languages/no/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/no/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/no/events/errors.json b/src/languages/no/events/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/no/events/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/no/events/guilds-logs.json b/src/languages/no/events/guilds-logs.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/no/events/guilds-logs.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/no/events/guilds-members.json b/src/languages/no/events/guilds-members.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/no/events/guilds-members.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/no/events/messages.json b/src/languages/no/events/messages.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/no/events/messages.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/no/events/moderation.json b/src/languages/no/events/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/no/events/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/no/events/noMentionSpam.json b/src/languages/no/events/noMentionSpam.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/no/events/noMentionSpam.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/no/events/reactions.json b/src/languages/no/events/reactions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/no/events/reactions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/no/events/twitch.json b/src/languages/no/events/twitch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/no/events/twitch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/no/fuzzySearch.json b/src/languages/no/fuzzySearch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/no/fuzzySearch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/no/globals.json b/src/languages/no/globals.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/no/globals.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/no/guilds.json b/src/languages/no/guilds.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/no/guilds.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/no/humanLevels.json b/src/languages/no/humanLevels.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/no/humanLevels.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/no/moderation.json b/src/languages/no/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/no/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/no/moderationActions.json b/src/languages/no/moderationActions.json deleted file mode 100644 index 4c440ae54..000000000 --- a/src/languages/no/moderationActions.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "actions": { - "addRole": "", - "ban": "", - "kick": "", - "mute": "", - "removeRole": "", - "restrictedAttachment": "", - "restrictedEmbed": "", - "restrictedEmoji": "", - "restrictedReact": "", - "restrictedVoice": "", - "setNickname": "", - "softban": "", - "vkick": "", - "vmute": "", - "warning": "" - }, - "actionCannotManageRoles": "", - "actionRoleNotConfigured": "", - "actionRoleHigherPosition": "", - "actionRoleManaged": "", - "applyNoReason": "", - "applyReason": "", - "requiredMember": "", - "revokeNoReason": "", - "revokeReason": "", - "setNicknameNoReasonRemoved": "", - "setNicknameNoReasonSet": "", - "setNicknameRemoved": "", - "setNicknameSet": "", - "setupMuteExists": "", - "setupTooManyRoles": "", - "sharedRoleSetupAsk": "", - "sharedRoleSetupNoMessage": "", - "sharedRoleSetupExisting": "", - "sharedRoleSetupExistingName": "", - "sharedRoleSetupNew": "", - "softbanNoReason": "", - "softbanReason": "", - "unSoftbanNoReason": "", - "unSoftbanReason": "" -} \ No newline at end of file diff --git a/src/languages/no/permissions.json b/src/languages/no/permissions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/no/permissions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/no/preconditions.json b/src/languages/no/preconditions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/no/preconditions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/no/selfModeration.json b/src/languages/no/selfModeration.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/no/selfModeration.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/no/serializers.json b/src/languages/no/serializers.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/no/serializers.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/no/settings.json b/src/languages/no/settings.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/no/settings.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/no/system.json b/src/languages/no/system.json deleted file mode 100644 index 073b9b683..000000000 --- a/src/languages/no/system.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "discordAbortError": "", - "fetchBansFail": "", - "helpTitles": { - "aliases": "", - "usages": "", - "extendedHelp": "", - "explainedUsage": "", - "possibleFormats": "", - "examples": "", - "reminders": "" - }, - "jumpTo": "", - "loading": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "prefixReminder": "" -} \ No newline at end of file diff --git a/src/languages/pl/arguments.json b/src/languages/pl/arguments.json deleted file mode 100644 index a7befa6f3..000000000 --- a/src/languages/pl/arguments.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "boolean_one": "", - "boolean_other": "", - "booleanError": "", - "booleanDisabled": "", - "booleanEnabled": "", - "booleanFalseOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "booleanTrueOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "caseNoEntries": "", - "caseUnknownEntry": "", - "caseNotInThisGuild": "", - "caseLatestOptions": [ - "", - "" - ], - "categoryChannelError": "", - "channelError": "", - "command": "", - "commandMatch": "", - "dateError": "", - "dateFormats": "", - "dateTooEarly": "", - "dateTooFar": "", - "dmChannelError": "", - "duration": "", - "durationFormats": "", - "emojiError": "", - "floatError": "", - "floatTooLarge": "", - "floatTooSmall": "", - "guildChannelError": "", - "guildChannelMismatchingError": "", - "guildChannelMissingGuildError": "", - "guildPrivateThreadChannelError": "", - "guildPublicThreadChannelError": "", - "guildStageVoiceChannelError": "", - "guildTextChannelError": "", - "guildThreadChannelError": "", - "guildVoiceChannelError": "", - "hyperlinkError": "", - "integerError": "", - "integerTooLarge": "", - "integerTooSmall": "", - "invite": "", - "language": "", - "memberError": "", - "memberMissingGuild": "", - "messageError": "", - "missing": "", - "newsChannel": "", - "numberError": "", - "numberTooLarge": "", - "numberTooSmall": "", - "piece": "", - "rangeInvalid": "", - "rangeMax_other": "", - "rangeMax_one": "", - "resetPossibles": [ - "", - "" - ], - "roleError": "", - "roleMissingGuild": "", - "snowflake": "", - "store": "", - "stringTooLong": "", - "stringTooShort": "", - "time": "", - "timeSpan": "", - "timeSpanTooBig": "", - "timeSpanTooSmall": "", - "tooFewWinners": "", - "tooManyWinners": "", - "unavailable": "", - "userError": "", - "enumEmptyError": "", - "enumError": "" -} \ No newline at end of file diff --git a/src/languages/pl/assertions.json b/src/languages/pl/assertions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pl/assertions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pl/commands/admin.json b/src/languages/pl/commands/admin.json deleted file mode 100644 index 444f39c28..000000000 --- a/src/languages/pl/commands/admin.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "confUpdated": "", - "confGetNoExt": "", - "confGet": "", - "confReset": "", - "confNochange": "", - "confServerDescription": "", - "confServerExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "confServer": "", - "confDashboardOnlyKey": "", - "confSettingNotSet": "", - "rolesetDescription": "", - "rolesetExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesetCreated": "", - "rolesetAdded": "", - "rolesetRemoved": "", - "rolesetResetEmpty": "", - "rolesetResetAll": "", - "rolesetResetNotExists": "", - "rolesetResetGroup": "", - "rolesetUpdated": "", - "rolesetNoRolesets": "", - "confMenuRenderAtFolder": "", - "confMenuRenderAtPiece": "", - "confMenuRenderNokeys": "", - "confMenuRenderSelect": "", - "confMenuRenderUpdate": "", - "confMenuRenderRemove": "", - "confMenuRenderReset": "", - "confMenuRenderUndo": "", - "confMenuRenderCvalue": "", - "confMenuRenderBack": "", - "confMenuInvalidKey": "", - "confMenuInvalidAction": "", - "confMenuSaved": "" -} \ No newline at end of file diff --git a/src/languages/pl/commands/animal.json b/src/languages/pl/commands/animal.json deleted file mode 100644 index 6d00e57af..000000000 --- a/src/languages/pl/commands/animal.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "bunnyDescription": "", - "bunnyExtended": { - "extendedHelp": "" - }, - "bunnyEmbedData": { - "title": "", - "source": "" - }, - "dogDescription": "", - "dogExtended": { - "extendedHelp": "" - }, - "foxDescription": "", - "foxExtended": { - "extendedHelp": "" - }, - "kittyDescription": "", - "kittyExtended": { - "extendedHelp": "" - }, - "shibeDescription": "", - "shibeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/pl/commands/auto-moderation.json b/src/languages/pl/commands/auto-moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pl/commands/auto-moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pl/commands/case.json b/src/languages/pl/commands/case.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pl/commands/case.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pl/commands/fun.json b/src/languages/pl/commands/fun.json deleted file mode 100644 index 7892e327d..000000000 --- a/src/languages/pl/commands/fun.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "escaperopeDescription": "", - "escaperopeExtended": { - "extendedHelp": "" - }, - "escaperopeOutput": "" -} \ No newline at end of file diff --git a/src/languages/pl/commands/game.json b/src/languages/pl/commands/game.json deleted file mode 100644 index 8075ca93c..000000000 --- a/src/languages/pl/commands/game.json +++ /dev/null @@ -1,447 +0,0 @@ -{ - "c4Description": "", - "c4Extended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "c4Prompt": "", - "gamesBot": "", - "gamesNoPlayers": "", - "gamesProgress": "", - "gamesPromptDeny": "", - "gamesRepeat": "", - "gamesSelf": "", - "gamesTooManyOrFew": "", - "hgBloodbath": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgDay": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgNight": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hungerGamesDescription": "", - "hungerGamesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "examples": [ - "" - ], - "reminder": "" - }, - "hungerGamesResultDeaths_one": "", - "hungerGamesResultDeaths_other": "", - "hungerGamesResultHeaderBloodbath": "", - "hungerGamesResultHeaderMoon": "", - "hungerGamesResultHeaderSun": "", - "hungerGamesResultProceed": "", - "hungerGamesStop": "", - "hungerGamesWinner": "", - "ticTacToeDescription": "", - "ticTacToeDraw": "", - "ticTacToeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "ticTacToePrompt": "", - "ticTacToeTurn": "", - "ticTacToeWinner": "", - "triviaActiveGame": "", - "triviaDescription": "", - "triviaEmbedTitles": { - "difficulty": "", - "trivia": "" - }, - "triviaExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "triviaIncorrect": "", - "triviaInvalidCategory": "", - "triviaNoAnswer": "", - "triviaWinner": "" -} \ No newline at end of file diff --git a/src/languages/pl/commands/general.json b/src/languages/pl/commands/general.json deleted file mode 100644 index 5e16f992d..000000000 --- a/src/languages/pl/commands/general.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "helpAllFlag": "", - "helpCommandCount_one": "", - "helpCommandCount_other": "", - "helpData": { - "footer": "", - "title": "" - }, - "helpDescription": "", - "helpExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "reminder": "", - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "helpDm": "", - "helpNodm": "", - "v7Description": "", - "v7Extended": { - "extendedHelp": "" - }, - "v7Message": "", - "v7NayreMessage": "" -} \ No newline at end of file diff --git a/src/languages/pl/commands/info.json b/src/languages/pl/commands/info.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pl/commands/info.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pl/commands/management.json b/src/languages/pl/commands/management.json deleted file mode 100644 index 21ef26ce2..000000000 --- a/src/languages/pl/commands/management.json +++ /dev/null @@ -1,445 +0,0 @@ -{ - "commandHandlerAborted": "", - "permissionNodesHigher": "", - "permissionNodesCannotAllowEveryone": "", - "permissionNodesInvalidType": "", - "permissionNodesAdd": "", - "permissionNodesNodeNotExists": "", - "permissionNodesCommandNotExists": "", - "permissionNodesRemove": "", - "permissionNodesReset": "", - "permissionNodesShowName": "", - "permissionNodesShowAllow": "", - "permissionNodesShowDeny": "", - "guildInfoTitles": { - "CHANNELS": "", - "MEMBERS": "", - "OTHER": "" - }, - "guildInfoChannels": "", - "guildInfoChannelsAfkChannelText": "", - "guildInfoMembers": "", - "guildInfoOther": "", - "guildInfoBanner": "", - "guildInfoIcon": "", - "guildInfoSplash": "", - "guildInfoDiscoverySplash": "", - "roleInfoTitles": { - "PERMISSIONS": "" - }, - "roleInfoData": "", - "roleInfoAll": "", - "roleInfoNoPermissions": "", - "manageCommandAutoDeleteShowEmpty": "", - "manageCommandAutoDeleteShow": "", - "manageCommandAutoDeleteAdd": "", - "manageCommandAutoDeleteRemove": "", - "manageCommandAutoDeleteRemoveNotset": "", - "manageCommandAutoDeleteReset": "", - "manageCommandChannelShow": "", - "manageCommandChannelShowEmpty": "", - "manageCommandChannelAddAlreadyset": "", - "manageCommandChannelAdd": "", - "manageCommandChannelRemoveNotset": "", - "manageCommandChannelRemove": "", - "manageCommandChannelResetEmpty": "", - "manageCommandChannelReset": "", - "manageReactionRolesShowEmpty": "", - "manageReactionRolesAddChannel": "", - "manageReactionRolesAddPrompt": "", - "manageReactionRolesAddMissing": "", - "manageReactionRolesAdd": "", - "manageReactionRolesRemoveNotExists": "", - "manageReactionRolesRemove": "", - "manageReactionRolesResetEmpty": "", - "manageReactionRolesReset": "", - "configurationEquals": "", - "setIgnoreChannelsSet": "", - "setIgnoreChannelsRemoved": "", - "setImageLogsSet": "", - "setMemberAddLogsSet": "", - "setMemberRemoveLogsSet": "", - "setMessageUpdateLogsSet": "", - "setMessageDeleteLogsSet": "", - "setModLogsSet": "", - "setPrefixSet": "", - "stickyRolesNotExists": "", - "stickyRolesReset": "", - "stickyRolesRemove": "", - "stickyRolesAdd": "", - "stickyRolesShowEmpty": "", - "stickyRolesShowSingle": "", - "createMuteDescription": "", - "createMuteExtended": { - "extendedHelp": "" - }, - "permissionNodesDescription": "", - "permissionNodesExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "managecommandautodeleteDescription": "", - "managecommandautodeleteExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageCommandChannelDescription": "", - "manageCommandChannelExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageReactionRolesDescription": "", - "manageReactionRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "rolesAdded": "", - "rolesAuditlog": "", - "rolesListEmpty": "", - "rolesListTitle": "", - "rolesNotManageable": "", - "rolesNotPublic": "", - "rolesRemoved": "", - "setIgnoreChannelsDescription": "", - "setIgnoreChannelsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setImageLogsDescription": "", - "setImageLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "setMemberAddLogsDescription": "", - "setMemberAddLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMemberRemoveLogsDescription": "", - "setMemberRemoveLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMessageUpdateLogsDescription": "", - "setMessageUpdateLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setMessageDeleteLogsDescription": "", - "setMessageDeleteLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setmodlogsDescription": "", - "setmodlogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setprefixDescription": "", - "setprefixExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "guildInfoDescription": "", - "guildInfoExtended": { - "extendedHelp": "" - }, - "roleInfoDescription": "", - "roleInfoExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "stickyRolesDescription": "", - "stickyRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesDescription": "", - "rolesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/pl/commands/misc.json b/src/languages/pl/commands/misc.json deleted file mode 100644 index 32f64d584..000000000 --- a/src/languages/pl/commands/misc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "snipeEmpty": "", - "snipeTitle": "", - "snipeDescription": "", - "snipeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/pl/commands/moderation.json b/src/languages/pl/commands/moderation.json deleted file mode 100644 index 815d1c788..000000000 --- a/src/languages/pl/commands/moderation.json +++ /dev/null @@ -1,889 +0,0 @@ -{ - "permissions": "", - "permissionsAll": "", - "slowmodeSet": "", - "slowmodeReset": "", - "banNotBannable": "", - "dehoistStarting": "", - "dehoistProgress": "", - "dehoistEmbed": { - "title": "", - "descriptionNoone": "", - "descriptionWithError": "", - "descriptionWithMultipleErrors": "", - "description": "", - "descriptionMultipleMembers": "", - "fieldErrorTitle": "" - }, - "kickNotKickable": "", - "lockdownLock": "", - "lockdownLocking": "", - "lockdownLocked": "", - "lockdownUnlocked": "", - "lockdownOpen": "", - "muteMuted": "", - "muteUserNotMuted": "", - "restrictLowlevel": "", - "pruneAlert_one": "", - "pruneAlert_other": "", - "pruneInvalidPosition": "", - "pruneNoDeletes": "", - "pruneLogHeader": "", - "toggleModerationDmToggledEnabled": "", - "toggleModerationDmToggledDisabled": "", - "moderationOutput_one": "", - "moderationOutput_other": "", - "moderationOutputWithReason_one": "", - "moderationOutputWithReason_other": "", - "moderationFailed_one": "", - "moderationFailed_other": "", - "moderationDmFooter": "", - "moderationDmDescription": "", - "moderationDmDescriptionWithReason": "", - "moderationDmDescriptionWithDuration": "", - "moderationDmDescriptionWithReasonWithDuration": "", - "slowmodeDescription": "", - "slowmodeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "banDescription": "", - "banExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "dehoistDescription": "", - "dehoistExtended": { - "extendedHelp": "", - "reminder": "" - }, - "kickDescription": "", - "kickExtended": { - "usages": [ - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "lockdownDescription": "", - "lockdownExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "muteDescription": "", - "muteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "setNicknameDescription": "", - "setNicknameExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ], - "reminder": "" - }, - "addRoleDescription": "", - "addRoleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "removeroleDescription": "", - "removeroleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "pruneDescription": "", - "pruneExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "permissionsDescription": "", - "permissionsExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ], - "extendedHelp": "" - }, - "restrictAttachmentDescription": "", - "restrictAttachmentExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictEmbedDescription": "", - "restrictEmbedExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictEmojiDescription": "", - "restrictEmojiExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictReactionDescription": "", - "restrictReactionExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictVoiceDescription": "", - "restrictVoiceExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "softBanDescription": "", - "softBanExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "timeoutApplyDescription": "", - "timeoutApplyExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutUndoDescription": "", - "timeoutUndoExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutNotModeratable": "", - "toggleModerationDmDescription": "", - "toggleModerationDmExtended": { - "extendedHelp": "" - }, - "unbanDescription": "", - "unbanExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unmuteDescription": "", - "unmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unrestrictAttachmentDescription": "", - "unrestrictAttachmentExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmbedDescription": "", - "unrestrictEmbedExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmojiDescription": "", - "unrestrictEmojiExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictReactionDescription": "", - "unrestrictReactionExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictVoiceDescription": "", - "unrestrictVoiceExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unwarnDescription": "", - "unwarnExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vmuteDescription": "", - "vmuteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "voiceKickDescription": "", - "voiceKickExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vunmuteDescription": "", - "vunmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "warnDescription": "", - "warnExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/pl/commands/shared.json b/src/languages/pl/commands/shared.json deleted file mode 100644 index ddbb28e7f..000000000 --- a/src/languages/pl/commands/shared.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "deprecatedMessage": "", - "slashOnlyDetailedDescription": { - "extendedHelp": "" - }, - "slashOnlyErrorMessage": "" -} \ No newline at end of file diff --git a/src/languages/pl/commands/system.json b/src/languages/pl/commands/system.json deleted file mode 100644 index e9cfdeec4..000000000 --- a/src/languages/pl/commands/system.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "evalDescription": "", - "evalExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "evalTimeout": "", - "evalError": "", - "dmNotSent": "", - "dmSent": "", - "reboot": "", - "rebootDescription": "", - "rebootExtended": { - "extendedHelp": "", - "reminder": "" - } -} \ No newline at end of file diff --git a/src/languages/pl/commands/tools.json b/src/languages/pl/commands/tools.json deleted file mode 100644 index 01bd03e25..000000000 --- a/src/languages/pl/commands/tools.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "avatarDescription": "", - "avatarExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "" - }, - "avatarNone": "", - "voteDescription": "", - "voteExtended": { - "usages": [ - "" - ], - "examples": [ - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "voteContentNeeded": "", - "voteReactionBlocked": "", - "whoisExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "whoisMemberRoleListAndMore": "" -} \ No newline at end of file diff --git a/src/languages/pl/commands/twitch.json b/src/languages/pl/commands/twitch.json deleted file mode 100644 index 2f12e1b08..000000000 --- a/src/languages/pl/commands/twitch.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "twitchSubscriptionStreamerNotFound": "", - "twitchSubscriptionStatusValues": [ - "", - "" - ], - "twitchSubscriptionInvalidStatus": "", - "twitchSubscriptionAddDuplicated": "", - "twitchSubscriptionAddSuccessOffline": "", - "twitchSubscriptionAddSuccessLive": "", - "twitchSubscriptionAddMessageForOfflineRequired": "", - "twitchSubscriptionRemoveOrResetEmpty": "", - "twitchSubscriptionRemoveStreamerNotSubscribed": "", - "twitchSubscriptionRemoveNotToProvidedChannel": "", - "twitchSubscriptionRemoveStreamerStatusNotMatch": "", - "twitchSubscriptionRemoveSuccessOffline": "", - "twitchSubscriptionRemoveSuccessLive": "", - "twitchSubscriptionResetSuccess_one": "", - "twitchSubscriptionResetSuccess_other": "", - "twitchSubscriptionShowStreamerNotSubscribed": "", - "twitchSubscriptionShowStatus": { - "live": "", - "offline": "" - }, - "twitchSubscriptionShowUnknownUser": "", - "twitchSubscriptionDescription": "", - "twitchSubscriptionExtended": { - "usages": [ - "", - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/pl/commands/whois.json b/src/languages/pl/commands/whois.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pl/commands/whois.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pl/errors.json b/src/languages/pl/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pl/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pl/events/errors.json b/src/languages/pl/events/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pl/events/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pl/events/guilds-logs.json b/src/languages/pl/events/guilds-logs.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pl/events/guilds-logs.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pl/events/guilds-members.json b/src/languages/pl/events/guilds-members.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pl/events/guilds-members.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pl/events/messages.json b/src/languages/pl/events/messages.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pl/events/messages.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pl/events/moderation.json b/src/languages/pl/events/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pl/events/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pl/events/noMentionSpam.json b/src/languages/pl/events/noMentionSpam.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pl/events/noMentionSpam.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pl/events/reactions.json b/src/languages/pl/events/reactions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pl/events/reactions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pl/events/twitch.json b/src/languages/pl/events/twitch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pl/events/twitch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pl/fuzzySearch.json b/src/languages/pl/fuzzySearch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pl/fuzzySearch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pl/globals.json b/src/languages/pl/globals.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pl/globals.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pl/guilds.json b/src/languages/pl/guilds.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pl/guilds.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pl/humanLevels.json b/src/languages/pl/humanLevels.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pl/humanLevels.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pl/moderation.json b/src/languages/pl/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pl/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pl/moderationActions.json b/src/languages/pl/moderationActions.json deleted file mode 100644 index 4c440ae54..000000000 --- a/src/languages/pl/moderationActions.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "actions": { - "addRole": "", - "ban": "", - "kick": "", - "mute": "", - "removeRole": "", - "restrictedAttachment": "", - "restrictedEmbed": "", - "restrictedEmoji": "", - "restrictedReact": "", - "restrictedVoice": "", - "setNickname": "", - "softban": "", - "vkick": "", - "vmute": "", - "warning": "" - }, - "actionCannotManageRoles": "", - "actionRoleNotConfigured": "", - "actionRoleHigherPosition": "", - "actionRoleManaged": "", - "applyNoReason": "", - "applyReason": "", - "requiredMember": "", - "revokeNoReason": "", - "revokeReason": "", - "setNicknameNoReasonRemoved": "", - "setNicknameNoReasonSet": "", - "setNicknameRemoved": "", - "setNicknameSet": "", - "setupMuteExists": "", - "setupTooManyRoles": "", - "sharedRoleSetupAsk": "", - "sharedRoleSetupNoMessage": "", - "sharedRoleSetupExisting": "", - "sharedRoleSetupExistingName": "", - "sharedRoleSetupNew": "", - "softbanNoReason": "", - "softbanReason": "", - "unSoftbanNoReason": "", - "unSoftbanReason": "" -} \ No newline at end of file diff --git a/src/languages/pl/permissions.json b/src/languages/pl/permissions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pl/permissions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pl/preconditions.json b/src/languages/pl/preconditions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pl/preconditions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pl/selfModeration.json b/src/languages/pl/selfModeration.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pl/selfModeration.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pl/serializers.json b/src/languages/pl/serializers.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pl/serializers.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pl/settings.json b/src/languages/pl/settings.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pl/settings.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pl/system.json b/src/languages/pl/system.json deleted file mode 100644 index 073b9b683..000000000 --- a/src/languages/pl/system.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "discordAbortError": "", - "fetchBansFail": "", - "helpTitles": { - "aliases": "", - "usages": "", - "extendedHelp": "", - "explainedUsage": "", - "possibleFormats": "", - "examples": "", - "reminders": "" - }, - "jumpTo": "", - "loading": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "prefixReminder": "" -} \ No newline at end of file diff --git a/src/languages/pt-BR/arguments.json b/src/languages/pt-BR/arguments.json deleted file mode 100644 index a7befa6f3..000000000 --- a/src/languages/pt-BR/arguments.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "boolean_one": "", - "boolean_other": "", - "booleanError": "", - "booleanDisabled": "", - "booleanEnabled": "", - "booleanFalseOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "booleanTrueOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "caseNoEntries": "", - "caseUnknownEntry": "", - "caseNotInThisGuild": "", - "caseLatestOptions": [ - "", - "" - ], - "categoryChannelError": "", - "channelError": "", - "command": "", - "commandMatch": "", - "dateError": "", - "dateFormats": "", - "dateTooEarly": "", - "dateTooFar": "", - "dmChannelError": "", - "duration": "", - "durationFormats": "", - "emojiError": "", - "floatError": "", - "floatTooLarge": "", - "floatTooSmall": "", - "guildChannelError": "", - "guildChannelMismatchingError": "", - "guildChannelMissingGuildError": "", - "guildPrivateThreadChannelError": "", - "guildPublicThreadChannelError": "", - "guildStageVoiceChannelError": "", - "guildTextChannelError": "", - "guildThreadChannelError": "", - "guildVoiceChannelError": "", - "hyperlinkError": "", - "integerError": "", - "integerTooLarge": "", - "integerTooSmall": "", - "invite": "", - "language": "", - "memberError": "", - "memberMissingGuild": "", - "messageError": "", - "missing": "", - "newsChannel": "", - "numberError": "", - "numberTooLarge": "", - "numberTooSmall": "", - "piece": "", - "rangeInvalid": "", - "rangeMax_other": "", - "rangeMax_one": "", - "resetPossibles": [ - "", - "" - ], - "roleError": "", - "roleMissingGuild": "", - "snowflake": "", - "store": "", - "stringTooLong": "", - "stringTooShort": "", - "time": "", - "timeSpan": "", - "timeSpanTooBig": "", - "timeSpanTooSmall": "", - "tooFewWinners": "", - "tooManyWinners": "", - "unavailable": "", - "userError": "", - "enumEmptyError": "", - "enumError": "" -} \ No newline at end of file diff --git a/src/languages/pt-BR/assertions.json b/src/languages/pt-BR/assertions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pt-BR/assertions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pt-BR/commands/admin.json b/src/languages/pt-BR/commands/admin.json deleted file mode 100644 index 444f39c28..000000000 --- a/src/languages/pt-BR/commands/admin.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "confUpdated": "", - "confGetNoExt": "", - "confGet": "", - "confReset": "", - "confNochange": "", - "confServerDescription": "", - "confServerExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "confServer": "", - "confDashboardOnlyKey": "", - "confSettingNotSet": "", - "rolesetDescription": "", - "rolesetExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesetCreated": "", - "rolesetAdded": "", - "rolesetRemoved": "", - "rolesetResetEmpty": "", - "rolesetResetAll": "", - "rolesetResetNotExists": "", - "rolesetResetGroup": "", - "rolesetUpdated": "", - "rolesetNoRolesets": "", - "confMenuRenderAtFolder": "", - "confMenuRenderAtPiece": "", - "confMenuRenderNokeys": "", - "confMenuRenderSelect": "", - "confMenuRenderUpdate": "", - "confMenuRenderRemove": "", - "confMenuRenderReset": "", - "confMenuRenderUndo": "", - "confMenuRenderCvalue": "", - "confMenuRenderBack": "", - "confMenuInvalidKey": "", - "confMenuInvalidAction": "", - "confMenuSaved": "" -} \ No newline at end of file diff --git a/src/languages/pt-BR/commands/animal.json b/src/languages/pt-BR/commands/animal.json deleted file mode 100644 index 6d00e57af..000000000 --- a/src/languages/pt-BR/commands/animal.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "bunnyDescription": "", - "bunnyExtended": { - "extendedHelp": "" - }, - "bunnyEmbedData": { - "title": "", - "source": "" - }, - "dogDescription": "", - "dogExtended": { - "extendedHelp": "" - }, - "foxDescription": "", - "foxExtended": { - "extendedHelp": "" - }, - "kittyDescription": "", - "kittyExtended": { - "extendedHelp": "" - }, - "shibeDescription": "", - "shibeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/pt-BR/commands/auto-moderation.json b/src/languages/pt-BR/commands/auto-moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pt-BR/commands/auto-moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pt-BR/commands/case.json b/src/languages/pt-BR/commands/case.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pt-BR/commands/case.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pt-BR/commands/fun.json b/src/languages/pt-BR/commands/fun.json deleted file mode 100644 index 7892e327d..000000000 --- a/src/languages/pt-BR/commands/fun.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "escaperopeDescription": "", - "escaperopeExtended": { - "extendedHelp": "" - }, - "escaperopeOutput": "" -} \ No newline at end of file diff --git a/src/languages/pt-BR/commands/game.json b/src/languages/pt-BR/commands/game.json deleted file mode 100644 index 8075ca93c..000000000 --- a/src/languages/pt-BR/commands/game.json +++ /dev/null @@ -1,447 +0,0 @@ -{ - "c4Description": "", - "c4Extended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "c4Prompt": "", - "gamesBot": "", - "gamesNoPlayers": "", - "gamesProgress": "", - "gamesPromptDeny": "", - "gamesRepeat": "", - "gamesSelf": "", - "gamesTooManyOrFew": "", - "hgBloodbath": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgDay": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgNight": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hungerGamesDescription": "", - "hungerGamesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "examples": [ - "" - ], - "reminder": "" - }, - "hungerGamesResultDeaths_one": "", - "hungerGamesResultDeaths_other": "", - "hungerGamesResultHeaderBloodbath": "", - "hungerGamesResultHeaderMoon": "", - "hungerGamesResultHeaderSun": "", - "hungerGamesResultProceed": "", - "hungerGamesStop": "", - "hungerGamesWinner": "", - "ticTacToeDescription": "", - "ticTacToeDraw": "", - "ticTacToeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "ticTacToePrompt": "", - "ticTacToeTurn": "", - "ticTacToeWinner": "", - "triviaActiveGame": "", - "triviaDescription": "", - "triviaEmbedTitles": { - "difficulty": "", - "trivia": "" - }, - "triviaExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "triviaIncorrect": "", - "triviaInvalidCategory": "", - "triviaNoAnswer": "", - "triviaWinner": "" -} \ No newline at end of file diff --git a/src/languages/pt-BR/commands/general.json b/src/languages/pt-BR/commands/general.json deleted file mode 100644 index 5e16f992d..000000000 --- a/src/languages/pt-BR/commands/general.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "helpAllFlag": "", - "helpCommandCount_one": "", - "helpCommandCount_other": "", - "helpData": { - "footer": "", - "title": "" - }, - "helpDescription": "", - "helpExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "reminder": "", - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "helpDm": "", - "helpNodm": "", - "v7Description": "", - "v7Extended": { - "extendedHelp": "" - }, - "v7Message": "", - "v7NayreMessage": "" -} \ No newline at end of file diff --git a/src/languages/pt-BR/commands/info.json b/src/languages/pt-BR/commands/info.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pt-BR/commands/info.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pt-BR/commands/management.json b/src/languages/pt-BR/commands/management.json deleted file mode 100644 index 21ef26ce2..000000000 --- a/src/languages/pt-BR/commands/management.json +++ /dev/null @@ -1,445 +0,0 @@ -{ - "commandHandlerAborted": "", - "permissionNodesHigher": "", - "permissionNodesCannotAllowEveryone": "", - "permissionNodesInvalidType": "", - "permissionNodesAdd": "", - "permissionNodesNodeNotExists": "", - "permissionNodesCommandNotExists": "", - "permissionNodesRemove": "", - "permissionNodesReset": "", - "permissionNodesShowName": "", - "permissionNodesShowAllow": "", - "permissionNodesShowDeny": "", - "guildInfoTitles": { - "CHANNELS": "", - "MEMBERS": "", - "OTHER": "" - }, - "guildInfoChannels": "", - "guildInfoChannelsAfkChannelText": "", - "guildInfoMembers": "", - "guildInfoOther": "", - "guildInfoBanner": "", - "guildInfoIcon": "", - "guildInfoSplash": "", - "guildInfoDiscoverySplash": "", - "roleInfoTitles": { - "PERMISSIONS": "" - }, - "roleInfoData": "", - "roleInfoAll": "", - "roleInfoNoPermissions": "", - "manageCommandAutoDeleteShowEmpty": "", - "manageCommandAutoDeleteShow": "", - "manageCommandAutoDeleteAdd": "", - "manageCommandAutoDeleteRemove": "", - "manageCommandAutoDeleteRemoveNotset": "", - "manageCommandAutoDeleteReset": "", - "manageCommandChannelShow": "", - "manageCommandChannelShowEmpty": "", - "manageCommandChannelAddAlreadyset": "", - "manageCommandChannelAdd": "", - "manageCommandChannelRemoveNotset": "", - "manageCommandChannelRemove": "", - "manageCommandChannelResetEmpty": "", - "manageCommandChannelReset": "", - "manageReactionRolesShowEmpty": "", - "manageReactionRolesAddChannel": "", - "manageReactionRolesAddPrompt": "", - "manageReactionRolesAddMissing": "", - "manageReactionRolesAdd": "", - "manageReactionRolesRemoveNotExists": "", - "manageReactionRolesRemove": "", - "manageReactionRolesResetEmpty": "", - "manageReactionRolesReset": "", - "configurationEquals": "", - "setIgnoreChannelsSet": "", - "setIgnoreChannelsRemoved": "", - "setImageLogsSet": "", - "setMemberAddLogsSet": "", - "setMemberRemoveLogsSet": "", - "setMessageUpdateLogsSet": "", - "setMessageDeleteLogsSet": "", - "setModLogsSet": "", - "setPrefixSet": "", - "stickyRolesNotExists": "", - "stickyRolesReset": "", - "stickyRolesRemove": "", - "stickyRolesAdd": "", - "stickyRolesShowEmpty": "", - "stickyRolesShowSingle": "", - "createMuteDescription": "", - "createMuteExtended": { - "extendedHelp": "" - }, - "permissionNodesDescription": "", - "permissionNodesExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "managecommandautodeleteDescription": "", - "managecommandautodeleteExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageCommandChannelDescription": "", - "manageCommandChannelExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageReactionRolesDescription": "", - "manageReactionRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "rolesAdded": "", - "rolesAuditlog": "", - "rolesListEmpty": "", - "rolesListTitle": "", - "rolesNotManageable": "", - "rolesNotPublic": "", - "rolesRemoved": "", - "setIgnoreChannelsDescription": "", - "setIgnoreChannelsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setImageLogsDescription": "", - "setImageLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "setMemberAddLogsDescription": "", - "setMemberAddLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMemberRemoveLogsDescription": "", - "setMemberRemoveLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMessageUpdateLogsDescription": "", - "setMessageUpdateLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setMessageDeleteLogsDescription": "", - "setMessageDeleteLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setmodlogsDescription": "", - "setmodlogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setprefixDescription": "", - "setprefixExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "guildInfoDescription": "", - "guildInfoExtended": { - "extendedHelp": "" - }, - "roleInfoDescription": "", - "roleInfoExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "stickyRolesDescription": "", - "stickyRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesDescription": "", - "rolesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/pt-BR/commands/misc.json b/src/languages/pt-BR/commands/misc.json deleted file mode 100644 index 32f64d584..000000000 --- a/src/languages/pt-BR/commands/misc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "snipeEmpty": "", - "snipeTitle": "", - "snipeDescription": "", - "snipeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/pt-BR/commands/moderation.json b/src/languages/pt-BR/commands/moderation.json deleted file mode 100644 index 815d1c788..000000000 --- a/src/languages/pt-BR/commands/moderation.json +++ /dev/null @@ -1,889 +0,0 @@ -{ - "permissions": "", - "permissionsAll": "", - "slowmodeSet": "", - "slowmodeReset": "", - "banNotBannable": "", - "dehoistStarting": "", - "dehoistProgress": "", - "dehoistEmbed": { - "title": "", - "descriptionNoone": "", - "descriptionWithError": "", - "descriptionWithMultipleErrors": "", - "description": "", - "descriptionMultipleMembers": "", - "fieldErrorTitle": "" - }, - "kickNotKickable": "", - "lockdownLock": "", - "lockdownLocking": "", - "lockdownLocked": "", - "lockdownUnlocked": "", - "lockdownOpen": "", - "muteMuted": "", - "muteUserNotMuted": "", - "restrictLowlevel": "", - "pruneAlert_one": "", - "pruneAlert_other": "", - "pruneInvalidPosition": "", - "pruneNoDeletes": "", - "pruneLogHeader": "", - "toggleModerationDmToggledEnabled": "", - "toggleModerationDmToggledDisabled": "", - "moderationOutput_one": "", - "moderationOutput_other": "", - "moderationOutputWithReason_one": "", - "moderationOutputWithReason_other": "", - "moderationFailed_one": "", - "moderationFailed_other": "", - "moderationDmFooter": "", - "moderationDmDescription": "", - "moderationDmDescriptionWithReason": "", - "moderationDmDescriptionWithDuration": "", - "moderationDmDescriptionWithReasonWithDuration": "", - "slowmodeDescription": "", - "slowmodeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "banDescription": "", - "banExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "dehoistDescription": "", - "dehoistExtended": { - "extendedHelp": "", - "reminder": "" - }, - "kickDescription": "", - "kickExtended": { - "usages": [ - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "lockdownDescription": "", - "lockdownExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "muteDescription": "", - "muteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "setNicknameDescription": "", - "setNicknameExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ], - "reminder": "" - }, - "addRoleDescription": "", - "addRoleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "removeroleDescription": "", - "removeroleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "pruneDescription": "", - "pruneExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "permissionsDescription": "", - "permissionsExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ], - "extendedHelp": "" - }, - "restrictAttachmentDescription": "", - "restrictAttachmentExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictEmbedDescription": "", - "restrictEmbedExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictEmojiDescription": "", - "restrictEmojiExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictReactionDescription": "", - "restrictReactionExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictVoiceDescription": "", - "restrictVoiceExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "softBanDescription": "", - "softBanExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "timeoutApplyDescription": "", - "timeoutApplyExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutUndoDescription": "", - "timeoutUndoExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutNotModeratable": "", - "toggleModerationDmDescription": "", - "toggleModerationDmExtended": { - "extendedHelp": "" - }, - "unbanDescription": "", - "unbanExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unmuteDescription": "", - "unmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unrestrictAttachmentDescription": "", - "unrestrictAttachmentExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmbedDescription": "", - "unrestrictEmbedExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmojiDescription": "", - "unrestrictEmojiExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictReactionDescription": "", - "unrestrictReactionExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictVoiceDescription": "", - "unrestrictVoiceExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unwarnDescription": "", - "unwarnExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vmuteDescription": "", - "vmuteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "voiceKickDescription": "", - "voiceKickExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vunmuteDescription": "", - "vunmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "warnDescription": "", - "warnExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/pt-BR/commands/shared.json b/src/languages/pt-BR/commands/shared.json deleted file mode 100644 index ddbb28e7f..000000000 --- a/src/languages/pt-BR/commands/shared.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "deprecatedMessage": "", - "slashOnlyDetailedDescription": { - "extendedHelp": "" - }, - "slashOnlyErrorMessage": "" -} \ No newline at end of file diff --git a/src/languages/pt-BR/commands/system.json b/src/languages/pt-BR/commands/system.json deleted file mode 100644 index e9cfdeec4..000000000 --- a/src/languages/pt-BR/commands/system.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "evalDescription": "", - "evalExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "evalTimeout": "", - "evalError": "", - "dmNotSent": "", - "dmSent": "", - "reboot": "", - "rebootDescription": "", - "rebootExtended": { - "extendedHelp": "", - "reminder": "" - } -} \ No newline at end of file diff --git a/src/languages/pt-BR/commands/tools.json b/src/languages/pt-BR/commands/tools.json deleted file mode 100644 index 01bd03e25..000000000 --- a/src/languages/pt-BR/commands/tools.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "avatarDescription": "", - "avatarExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "" - }, - "avatarNone": "", - "voteDescription": "", - "voteExtended": { - "usages": [ - "" - ], - "examples": [ - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "voteContentNeeded": "", - "voteReactionBlocked": "", - "whoisExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "whoisMemberRoleListAndMore": "" -} \ No newline at end of file diff --git a/src/languages/pt-BR/commands/twitch.json b/src/languages/pt-BR/commands/twitch.json deleted file mode 100644 index 2f12e1b08..000000000 --- a/src/languages/pt-BR/commands/twitch.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "twitchSubscriptionStreamerNotFound": "", - "twitchSubscriptionStatusValues": [ - "", - "" - ], - "twitchSubscriptionInvalidStatus": "", - "twitchSubscriptionAddDuplicated": "", - "twitchSubscriptionAddSuccessOffline": "", - "twitchSubscriptionAddSuccessLive": "", - "twitchSubscriptionAddMessageForOfflineRequired": "", - "twitchSubscriptionRemoveOrResetEmpty": "", - "twitchSubscriptionRemoveStreamerNotSubscribed": "", - "twitchSubscriptionRemoveNotToProvidedChannel": "", - "twitchSubscriptionRemoveStreamerStatusNotMatch": "", - "twitchSubscriptionRemoveSuccessOffline": "", - "twitchSubscriptionRemoveSuccessLive": "", - "twitchSubscriptionResetSuccess_one": "", - "twitchSubscriptionResetSuccess_other": "", - "twitchSubscriptionShowStreamerNotSubscribed": "", - "twitchSubscriptionShowStatus": { - "live": "", - "offline": "" - }, - "twitchSubscriptionShowUnknownUser": "", - "twitchSubscriptionDescription": "", - "twitchSubscriptionExtended": { - "usages": [ - "", - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/pt-BR/commands/whois.json b/src/languages/pt-BR/commands/whois.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pt-BR/commands/whois.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pt-BR/errors.json b/src/languages/pt-BR/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pt-BR/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pt-BR/events/errors.json b/src/languages/pt-BR/events/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pt-BR/events/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pt-BR/events/guilds-logs.json b/src/languages/pt-BR/events/guilds-logs.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pt-BR/events/guilds-logs.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pt-BR/events/guilds-members.json b/src/languages/pt-BR/events/guilds-members.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pt-BR/events/guilds-members.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pt-BR/events/messages.json b/src/languages/pt-BR/events/messages.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pt-BR/events/messages.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pt-BR/events/moderation.json b/src/languages/pt-BR/events/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pt-BR/events/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pt-BR/events/noMentionSpam.json b/src/languages/pt-BR/events/noMentionSpam.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pt-BR/events/noMentionSpam.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pt-BR/events/reactions.json b/src/languages/pt-BR/events/reactions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pt-BR/events/reactions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pt-BR/events/twitch.json b/src/languages/pt-BR/events/twitch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pt-BR/events/twitch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pt-BR/fuzzySearch.json b/src/languages/pt-BR/fuzzySearch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pt-BR/fuzzySearch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pt-BR/globals.json b/src/languages/pt-BR/globals.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pt-BR/globals.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pt-BR/guilds.json b/src/languages/pt-BR/guilds.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pt-BR/guilds.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pt-BR/humanLevels.json b/src/languages/pt-BR/humanLevels.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pt-BR/humanLevels.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pt-BR/moderation.json b/src/languages/pt-BR/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pt-BR/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pt-BR/moderationActions.json b/src/languages/pt-BR/moderationActions.json deleted file mode 100644 index 4c440ae54..000000000 --- a/src/languages/pt-BR/moderationActions.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "actions": { - "addRole": "", - "ban": "", - "kick": "", - "mute": "", - "removeRole": "", - "restrictedAttachment": "", - "restrictedEmbed": "", - "restrictedEmoji": "", - "restrictedReact": "", - "restrictedVoice": "", - "setNickname": "", - "softban": "", - "vkick": "", - "vmute": "", - "warning": "" - }, - "actionCannotManageRoles": "", - "actionRoleNotConfigured": "", - "actionRoleHigherPosition": "", - "actionRoleManaged": "", - "applyNoReason": "", - "applyReason": "", - "requiredMember": "", - "revokeNoReason": "", - "revokeReason": "", - "setNicknameNoReasonRemoved": "", - "setNicknameNoReasonSet": "", - "setNicknameRemoved": "", - "setNicknameSet": "", - "setupMuteExists": "", - "setupTooManyRoles": "", - "sharedRoleSetupAsk": "", - "sharedRoleSetupNoMessage": "", - "sharedRoleSetupExisting": "", - "sharedRoleSetupExistingName": "", - "sharedRoleSetupNew": "", - "softbanNoReason": "", - "softbanReason": "", - "unSoftbanNoReason": "", - "unSoftbanReason": "" -} \ No newline at end of file diff --git a/src/languages/pt-BR/permissions.json b/src/languages/pt-BR/permissions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pt-BR/permissions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pt-BR/preconditions.json b/src/languages/pt-BR/preconditions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pt-BR/preconditions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pt-BR/selfModeration.json b/src/languages/pt-BR/selfModeration.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pt-BR/selfModeration.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pt-BR/serializers.json b/src/languages/pt-BR/serializers.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pt-BR/serializers.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pt-BR/settings.json b/src/languages/pt-BR/settings.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/pt-BR/settings.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/pt-BR/system.json b/src/languages/pt-BR/system.json deleted file mode 100644 index 073b9b683..000000000 --- a/src/languages/pt-BR/system.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "discordAbortError": "", - "fetchBansFail": "", - "helpTitles": { - "aliases": "", - "usages": "", - "extendedHelp": "", - "explainedUsage": "", - "possibleFormats": "", - "examples": "", - "reminders": "" - }, - "jumpTo": "", - "loading": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "prefixReminder": "" -} \ No newline at end of file diff --git a/src/languages/ro/arguments.json b/src/languages/ro/arguments.json deleted file mode 100644 index a7befa6f3..000000000 --- a/src/languages/ro/arguments.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "boolean_one": "", - "boolean_other": "", - "booleanError": "", - "booleanDisabled": "", - "booleanEnabled": "", - "booleanFalseOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "booleanTrueOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "caseNoEntries": "", - "caseUnknownEntry": "", - "caseNotInThisGuild": "", - "caseLatestOptions": [ - "", - "" - ], - "categoryChannelError": "", - "channelError": "", - "command": "", - "commandMatch": "", - "dateError": "", - "dateFormats": "", - "dateTooEarly": "", - "dateTooFar": "", - "dmChannelError": "", - "duration": "", - "durationFormats": "", - "emojiError": "", - "floatError": "", - "floatTooLarge": "", - "floatTooSmall": "", - "guildChannelError": "", - "guildChannelMismatchingError": "", - "guildChannelMissingGuildError": "", - "guildPrivateThreadChannelError": "", - "guildPublicThreadChannelError": "", - "guildStageVoiceChannelError": "", - "guildTextChannelError": "", - "guildThreadChannelError": "", - "guildVoiceChannelError": "", - "hyperlinkError": "", - "integerError": "", - "integerTooLarge": "", - "integerTooSmall": "", - "invite": "", - "language": "", - "memberError": "", - "memberMissingGuild": "", - "messageError": "", - "missing": "", - "newsChannel": "", - "numberError": "", - "numberTooLarge": "", - "numberTooSmall": "", - "piece": "", - "rangeInvalid": "", - "rangeMax_other": "", - "rangeMax_one": "", - "resetPossibles": [ - "", - "" - ], - "roleError": "", - "roleMissingGuild": "", - "snowflake": "", - "store": "", - "stringTooLong": "", - "stringTooShort": "", - "time": "", - "timeSpan": "", - "timeSpanTooBig": "", - "timeSpanTooSmall": "", - "tooFewWinners": "", - "tooManyWinners": "", - "unavailable": "", - "userError": "", - "enumEmptyError": "", - "enumError": "" -} \ No newline at end of file diff --git a/src/languages/ro/assertions.json b/src/languages/ro/assertions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ro/assertions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ro/commands/admin.json b/src/languages/ro/commands/admin.json deleted file mode 100644 index 9a836a630..000000000 --- a/src/languages/ro/commands/admin.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "confUpdated": "", - "confGetNoExt": "Cheia **{{key}}** nu pare să existe.", - "confGet": "Valoarea cheii **{{key}}** este: `{{value}}`", - "confReset": "Cheia **{{key}}** a fost resetată la: `{{value}}`", - "confNochange": "Cheia **{{key}}** are deja această valoare.", - "confServerDescription": "Definiți setările per-server.", - "confServerExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "confServer": "**Setarea {{key}} a server-ului**\n{{list}}", - "confDashboardOnlyKey": "`{{key}}` poate fi configurat doar prin intermediul panoului web ()", - "confSettingNotSet": "Nu este setat", - "rolesetDescription": "Gestionați seturi de roluri unice.", - "rolesetExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "Un set de roluri este un grup de roluri pe care WolfStar le identifică ca fiind unice pentru toți membrii din server, ca de exemplu un roleset numit `regiune` ar putea avea rolurile `Africa`, `America`, `Asia` şi `Europa`, iar membrii vor putea avea doar unul dintre ele. Este ca un fel de \"regulă\" care se aplică în următoarele trei situaţii:\n\n- Când cineva revendică un rol prin comanda `roles`.\n- Când cineva revendică un rol prin roluri de reacție.\n- Când cineva primește un rol fie manual, fie de la un alt bot.", - "explainedUsage": [ - [ - "add", - "Creați un nou roleset sau adăugați un rol la unul existent." - ], - [ - "remove", - "Elimină un rol dintr-un roleset existent." - ], - [ - "reset", - "Elimină toate rolurile dintr-un roleset sau, dacă nu este specificat, toate roleset-urile existente." - ], - [ - "list", - "Listează toate seturile de role-uri." - ], - [ - "auto", - "Adaugă sau elimină un set de roluri." - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "add regions America", - "add regions Africa America Asia Europa", - "remove regions America", - "reset", - "reset regions", - "list", - "regions America", - "regions Africa America Asia Europa" - ], - "reminder": "Această comandă poate adăuga și/sau elimina mai multe roluri în același timp." - }, - "rolesetCreated": "", - "rolesetAdded": "", - "rolesetRemoved": "", - "rolesetResetEmpty": "{{REDCROSS}} Nu există rolurset-uri configurate în acest grup.", - "rolesetResetAll": "{{GREENTICK}} Toate roleset-urile au fost eliminate cu succes.", - "rolesetResetNotExists": "{{REDCROSS}} Roleset-ul `{{name}}` nu există pe acest server.", - "rolesetResetGroup": "{{GREENTICK}} Roleset-ul `{{name}}` a fost eliminat cu success de pe acest server.", - "rolesetUpdated": "Roleset-ul {{name}} a fost actualizat.", - "rolesetNoRolesets": "Nu aveți nici un roleset.", - "confMenuRenderAtFolder": "Momentan la: 📁 {{path}}", - "confMenuRenderAtPiece": "Momentan la: ⚙️ {{path}}", - "confMenuRenderNokeys": "Nu există chei configurabile pentru acest dosar", - "confMenuRenderSelect": "Vă rugăm să introduceți oricare dintre următoarele intrări", - "confMenuRenderUpdate": "• Actualizează Valoarea → `set `", - "confMenuRenderRemove": "• Elimină Valoarea → `remove `", - "confMenuRenderReset": "• Resetează Valoarea → `reset`", - "confMenuRenderUndo": "• Anulează Actualizarea → `undo`", - "confMenuRenderCvalue": "Valoarea actuală: **``{{value}}``**", - "confMenuRenderBack": "Apăsați ◀ pentru a merge înapoi", - "confMenuInvalidKey": "Cheie invalidă, te rugăm să încerci din nou cu oricare dintre următoarele opțiuni.", - "confMenuInvalidAction": "Acțiune invalidă, vă rugăm să încercați din nou cu oricare dintre următoarele opțiuni.", - "confMenuSaved": "Salvare reuşită a tuturor modificărilor." -} \ No newline at end of file diff --git a/src/languages/ro/commands/animal.json b/src/languages/ro/commands/animal.json deleted file mode 100644 index d02c58a2a..000000000 --- a/src/languages/ro/commands/animal.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "bunnyDescription": "", - "bunnyExtended": { - "extendedHelp": "" - }, - "bunnyEmbedData": { - "title": "", - "source": "" - }, - "dogDescription": "Câini drăguți! ❤", - "dogExtended": { - "extendedHelp": "" - }, - "foxDescription": "Lasă-mă să îți arăt o imagine cu o vulpe!", - "foxExtended": { - "extendedHelp": "" - }, - "kittyDescription": "PISICUȚE!", - "kittyExtended": { - "extendedHelp": "" - }, - "shibeDescription": "Shiba-uri drăguți!", - "shibeExtended": { - "extendedHelp": "Toată lumea iubește shiba-uri, și eu o să îi iubesc! Sunt atât de adorabili ❤" - } -} \ No newline at end of file diff --git a/src/languages/ro/commands/auto-moderation.json b/src/languages/ro/commands/auto-moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ro/commands/auto-moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ro/commands/case.json b/src/languages/ro/commands/case.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ro/commands/case.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ro/commands/fun.json b/src/languages/ro/commands/fun.json deleted file mode 100644 index 7892e327d..000000000 --- a/src/languages/ro/commands/fun.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "escaperopeDescription": "", - "escaperopeExtended": { - "extendedHelp": "" - }, - "escaperopeOutput": "" -} \ No newline at end of file diff --git a/src/languages/ro/commands/game.json b/src/languages/ro/commands/game.json deleted file mode 100644 index 8075ca93c..000000000 --- a/src/languages/ro/commands/game.json +++ /dev/null @@ -1,447 +0,0 @@ -{ - "c4Description": "", - "c4Extended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "c4Prompt": "", - "gamesBot": "", - "gamesNoPlayers": "", - "gamesProgress": "", - "gamesPromptDeny": "", - "gamesRepeat": "", - "gamesSelf": "", - "gamesTooManyOrFew": "", - "hgBloodbath": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgDay": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgNight": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hungerGamesDescription": "", - "hungerGamesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "examples": [ - "" - ], - "reminder": "" - }, - "hungerGamesResultDeaths_one": "", - "hungerGamesResultDeaths_other": "", - "hungerGamesResultHeaderBloodbath": "", - "hungerGamesResultHeaderMoon": "", - "hungerGamesResultHeaderSun": "", - "hungerGamesResultProceed": "", - "hungerGamesStop": "", - "hungerGamesWinner": "", - "ticTacToeDescription": "", - "ticTacToeDraw": "", - "ticTacToeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "ticTacToePrompt": "", - "ticTacToeTurn": "", - "ticTacToeWinner": "", - "triviaActiveGame": "", - "triviaDescription": "", - "triviaEmbedTitles": { - "difficulty": "", - "trivia": "" - }, - "triviaExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "triviaIncorrect": "", - "triviaInvalidCategory": "", - "triviaNoAnswer": "", - "triviaWinner": "" -} \ No newline at end of file diff --git a/src/languages/ro/commands/general.json b/src/languages/ro/commands/general.json deleted file mode 100644 index 5e16f992d..000000000 --- a/src/languages/ro/commands/general.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "helpAllFlag": "", - "helpCommandCount_one": "", - "helpCommandCount_other": "", - "helpData": { - "footer": "", - "title": "" - }, - "helpDescription": "", - "helpExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "reminder": "", - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "helpDm": "", - "helpNodm": "", - "v7Description": "", - "v7Extended": { - "extendedHelp": "" - }, - "v7Message": "", - "v7NayreMessage": "" -} \ No newline at end of file diff --git a/src/languages/ro/commands/info.json b/src/languages/ro/commands/info.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ro/commands/info.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ro/commands/management.json b/src/languages/ro/commands/management.json deleted file mode 100644 index 21ef26ce2..000000000 --- a/src/languages/ro/commands/management.json +++ /dev/null @@ -1,445 +0,0 @@ -{ - "commandHandlerAborted": "", - "permissionNodesHigher": "", - "permissionNodesCannotAllowEveryone": "", - "permissionNodesInvalidType": "", - "permissionNodesAdd": "", - "permissionNodesNodeNotExists": "", - "permissionNodesCommandNotExists": "", - "permissionNodesRemove": "", - "permissionNodesReset": "", - "permissionNodesShowName": "", - "permissionNodesShowAllow": "", - "permissionNodesShowDeny": "", - "guildInfoTitles": { - "CHANNELS": "", - "MEMBERS": "", - "OTHER": "" - }, - "guildInfoChannels": "", - "guildInfoChannelsAfkChannelText": "", - "guildInfoMembers": "", - "guildInfoOther": "", - "guildInfoBanner": "", - "guildInfoIcon": "", - "guildInfoSplash": "", - "guildInfoDiscoverySplash": "", - "roleInfoTitles": { - "PERMISSIONS": "" - }, - "roleInfoData": "", - "roleInfoAll": "", - "roleInfoNoPermissions": "", - "manageCommandAutoDeleteShowEmpty": "", - "manageCommandAutoDeleteShow": "", - "manageCommandAutoDeleteAdd": "", - "manageCommandAutoDeleteRemove": "", - "manageCommandAutoDeleteRemoveNotset": "", - "manageCommandAutoDeleteReset": "", - "manageCommandChannelShow": "", - "manageCommandChannelShowEmpty": "", - "manageCommandChannelAddAlreadyset": "", - "manageCommandChannelAdd": "", - "manageCommandChannelRemoveNotset": "", - "manageCommandChannelRemove": "", - "manageCommandChannelResetEmpty": "", - "manageCommandChannelReset": "", - "manageReactionRolesShowEmpty": "", - "manageReactionRolesAddChannel": "", - "manageReactionRolesAddPrompt": "", - "manageReactionRolesAddMissing": "", - "manageReactionRolesAdd": "", - "manageReactionRolesRemoveNotExists": "", - "manageReactionRolesRemove": "", - "manageReactionRolesResetEmpty": "", - "manageReactionRolesReset": "", - "configurationEquals": "", - "setIgnoreChannelsSet": "", - "setIgnoreChannelsRemoved": "", - "setImageLogsSet": "", - "setMemberAddLogsSet": "", - "setMemberRemoveLogsSet": "", - "setMessageUpdateLogsSet": "", - "setMessageDeleteLogsSet": "", - "setModLogsSet": "", - "setPrefixSet": "", - "stickyRolesNotExists": "", - "stickyRolesReset": "", - "stickyRolesRemove": "", - "stickyRolesAdd": "", - "stickyRolesShowEmpty": "", - "stickyRolesShowSingle": "", - "createMuteDescription": "", - "createMuteExtended": { - "extendedHelp": "" - }, - "permissionNodesDescription": "", - "permissionNodesExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "managecommandautodeleteDescription": "", - "managecommandautodeleteExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageCommandChannelDescription": "", - "manageCommandChannelExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageReactionRolesDescription": "", - "manageReactionRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "rolesAdded": "", - "rolesAuditlog": "", - "rolesListEmpty": "", - "rolesListTitle": "", - "rolesNotManageable": "", - "rolesNotPublic": "", - "rolesRemoved": "", - "setIgnoreChannelsDescription": "", - "setIgnoreChannelsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setImageLogsDescription": "", - "setImageLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "setMemberAddLogsDescription": "", - "setMemberAddLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMemberRemoveLogsDescription": "", - "setMemberRemoveLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMessageUpdateLogsDescription": "", - "setMessageUpdateLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setMessageDeleteLogsDescription": "", - "setMessageDeleteLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setmodlogsDescription": "", - "setmodlogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setprefixDescription": "", - "setprefixExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "guildInfoDescription": "", - "guildInfoExtended": { - "extendedHelp": "" - }, - "roleInfoDescription": "", - "roleInfoExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "stickyRolesDescription": "", - "stickyRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesDescription": "", - "rolesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/ro/commands/misc.json b/src/languages/ro/commands/misc.json deleted file mode 100644 index 32f64d584..000000000 --- a/src/languages/ro/commands/misc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "snipeEmpty": "", - "snipeTitle": "", - "snipeDescription": "", - "snipeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/ro/commands/moderation.json b/src/languages/ro/commands/moderation.json deleted file mode 100644 index 815d1c788..000000000 --- a/src/languages/ro/commands/moderation.json +++ /dev/null @@ -1,889 +0,0 @@ -{ - "permissions": "", - "permissionsAll": "", - "slowmodeSet": "", - "slowmodeReset": "", - "banNotBannable": "", - "dehoistStarting": "", - "dehoistProgress": "", - "dehoistEmbed": { - "title": "", - "descriptionNoone": "", - "descriptionWithError": "", - "descriptionWithMultipleErrors": "", - "description": "", - "descriptionMultipleMembers": "", - "fieldErrorTitle": "" - }, - "kickNotKickable": "", - "lockdownLock": "", - "lockdownLocking": "", - "lockdownLocked": "", - "lockdownUnlocked": "", - "lockdownOpen": "", - "muteMuted": "", - "muteUserNotMuted": "", - "restrictLowlevel": "", - "pruneAlert_one": "", - "pruneAlert_other": "", - "pruneInvalidPosition": "", - "pruneNoDeletes": "", - "pruneLogHeader": "", - "toggleModerationDmToggledEnabled": "", - "toggleModerationDmToggledDisabled": "", - "moderationOutput_one": "", - "moderationOutput_other": "", - "moderationOutputWithReason_one": "", - "moderationOutputWithReason_other": "", - "moderationFailed_one": "", - "moderationFailed_other": "", - "moderationDmFooter": "", - "moderationDmDescription": "", - "moderationDmDescriptionWithReason": "", - "moderationDmDescriptionWithDuration": "", - "moderationDmDescriptionWithReasonWithDuration": "", - "slowmodeDescription": "", - "slowmodeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "banDescription": "", - "banExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "dehoistDescription": "", - "dehoistExtended": { - "extendedHelp": "", - "reminder": "" - }, - "kickDescription": "", - "kickExtended": { - "usages": [ - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "lockdownDescription": "", - "lockdownExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "muteDescription": "", - "muteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "setNicknameDescription": "", - "setNicknameExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ], - "reminder": "" - }, - "addRoleDescription": "", - "addRoleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "removeroleDescription": "", - "removeroleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "pruneDescription": "", - "pruneExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "permissionsDescription": "", - "permissionsExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ], - "extendedHelp": "" - }, - "restrictAttachmentDescription": "", - "restrictAttachmentExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictEmbedDescription": "", - "restrictEmbedExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictEmojiDescription": "", - "restrictEmojiExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictReactionDescription": "", - "restrictReactionExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictVoiceDescription": "", - "restrictVoiceExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "softBanDescription": "", - "softBanExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "timeoutApplyDescription": "", - "timeoutApplyExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutUndoDescription": "", - "timeoutUndoExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutNotModeratable": "", - "toggleModerationDmDescription": "", - "toggleModerationDmExtended": { - "extendedHelp": "" - }, - "unbanDescription": "", - "unbanExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unmuteDescription": "", - "unmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unrestrictAttachmentDescription": "", - "unrestrictAttachmentExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmbedDescription": "", - "unrestrictEmbedExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmojiDescription": "", - "unrestrictEmojiExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictReactionDescription": "", - "unrestrictReactionExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictVoiceDescription": "", - "unrestrictVoiceExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unwarnDescription": "", - "unwarnExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vmuteDescription": "", - "vmuteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "voiceKickDescription": "", - "voiceKickExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vunmuteDescription": "", - "vunmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "warnDescription": "", - "warnExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/ro/commands/shared.json b/src/languages/ro/commands/shared.json deleted file mode 100644 index ddbb28e7f..000000000 --- a/src/languages/ro/commands/shared.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "deprecatedMessage": "", - "slashOnlyDetailedDescription": { - "extendedHelp": "" - }, - "slashOnlyErrorMessage": "" -} \ No newline at end of file diff --git a/src/languages/ro/commands/system.json b/src/languages/ro/commands/system.json deleted file mode 100644 index e9cfdeec4..000000000 --- a/src/languages/ro/commands/system.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "evalDescription": "", - "evalExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "evalTimeout": "", - "evalError": "", - "dmNotSent": "", - "dmSent": "", - "reboot": "", - "rebootDescription": "", - "rebootExtended": { - "extendedHelp": "", - "reminder": "" - } -} \ No newline at end of file diff --git a/src/languages/ro/commands/tools.json b/src/languages/ro/commands/tools.json deleted file mode 100644 index 01bd03e25..000000000 --- a/src/languages/ro/commands/tools.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "avatarDescription": "", - "avatarExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "" - }, - "avatarNone": "", - "voteDescription": "", - "voteExtended": { - "usages": [ - "" - ], - "examples": [ - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "voteContentNeeded": "", - "voteReactionBlocked": "", - "whoisExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "whoisMemberRoleListAndMore": "" -} \ No newline at end of file diff --git a/src/languages/ro/commands/twitch.json b/src/languages/ro/commands/twitch.json deleted file mode 100644 index 2f12e1b08..000000000 --- a/src/languages/ro/commands/twitch.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "twitchSubscriptionStreamerNotFound": "", - "twitchSubscriptionStatusValues": [ - "", - "" - ], - "twitchSubscriptionInvalidStatus": "", - "twitchSubscriptionAddDuplicated": "", - "twitchSubscriptionAddSuccessOffline": "", - "twitchSubscriptionAddSuccessLive": "", - "twitchSubscriptionAddMessageForOfflineRequired": "", - "twitchSubscriptionRemoveOrResetEmpty": "", - "twitchSubscriptionRemoveStreamerNotSubscribed": "", - "twitchSubscriptionRemoveNotToProvidedChannel": "", - "twitchSubscriptionRemoveStreamerStatusNotMatch": "", - "twitchSubscriptionRemoveSuccessOffline": "", - "twitchSubscriptionRemoveSuccessLive": "", - "twitchSubscriptionResetSuccess_one": "", - "twitchSubscriptionResetSuccess_other": "", - "twitchSubscriptionShowStreamerNotSubscribed": "", - "twitchSubscriptionShowStatus": { - "live": "", - "offline": "" - }, - "twitchSubscriptionShowUnknownUser": "", - "twitchSubscriptionDescription": "", - "twitchSubscriptionExtended": { - "usages": [ - "", - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/ro/commands/whois.json b/src/languages/ro/commands/whois.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ro/commands/whois.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ro/errors.json b/src/languages/ro/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ro/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ro/events/errors.json b/src/languages/ro/events/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ro/events/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ro/events/guilds-logs.json b/src/languages/ro/events/guilds-logs.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ro/events/guilds-logs.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ro/events/guilds-members.json b/src/languages/ro/events/guilds-members.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ro/events/guilds-members.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ro/events/messages.json b/src/languages/ro/events/messages.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ro/events/messages.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ro/events/moderation.json b/src/languages/ro/events/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ro/events/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ro/events/noMentionSpam.json b/src/languages/ro/events/noMentionSpam.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ro/events/noMentionSpam.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ro/events/reactions.json b/src/languages/ro/events/reactions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ro/events/reactions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ro/events/twitch.json b/src/languages/ro/events/twitch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ro/events/twitch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ro/fuzzySearch.json b/src/languages/ro/fuzzySearch.json deleted file mode 100644 index 8820e8b53..000000000 --- a/src/languages/ro/fuzzySearch.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "aborted": "Cerere anulată cu succes.", - "invalidIndex": "Acest număr a fost în afara razei de acțiune, anulăm cererea.", - "invalidNumber": "Mă aşteptam să-mi dai un număr (o singură cifră), am primit un cartof.", - "matches": "Am găsit mai multe potriviri! **Vă rugăm să selectați un număr în 0 și {{matches}}**:\n{{codeblock}}\nScrieți **ABORT** dacă doriți să ieșiți din cerere." -} \ No newline at end of file diff --git a/src/languages/ro/globals.json b/src/languages/ro/globals.json deleted file mode 100644 index 4ac4f5e69..000000000 --- a/src/languages/ro/globals.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "default": "{{key}} nu a fost localizat încă pentru ro-RO.", - "defaultLanguage": "Limba implicită", - "no": "Nu", - "none": "Nici unul", - "unknown": "necunoscut", - "yes": "Da", - "durationValue": "{{value, duration}}", - "numberValue": "{{value, number}}", - "numberCompactValue": "{{value, numberCompact}}", - "dateTimeValue": "{{value, dateTime}}", - "orListValue": "{{value, orList}}" -} \ No newline at end of file diff --git a/src/languages/ro/guilds.json b/src/languages/ro/guilds.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ro/guilds.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ro/humanLevels.json b/src/languages/ro/humanLevels.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ro/humanLevels.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ro/moderation.json b/src/languages/ro/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ro/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ro/moderationActions.json b/src/languages/ro/moderationActions.json deleted file mode 100644 index 4c440ae54..000000000 --- a/src/languages/ro/moderationActions.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "actions": { - "addRole": "", - "ban": "", - "kick": "", - "mute": "", - "removeRole": "", - "restrictedAttachment": "", - "restrictedEmbed": "", - "restrictedEmoji": "", - "restrictedReact": "", - "restrictedVoice": "", - "setNickname": "", - "softban": "", - "vkick": "", - "vmute": "", - "warning": "" - }, - "actionCannotManageRoles": "", - "actionRoleNotConfigured": "", - "actionRoleHigherPosition": "", - "actionRoleManaged": "", - "applyNoReason": "", - "applyReason": "", - "requiredMember": "", - "revokeNoReason": "", - "revokeReason": "", - "setNicknameNoReasonRemoved": "", - "setNicknameNoReasonSet": "", - "setNicknameRemoved": "", - "setNicknameSet": "", - "setupMuteExists": "", - "setupTooManyRoles": "", - "sharedRoleSetupAsk": "", - "sharedRoleSetupNoMessage": "", - "sharedRoleSetupExisting": "", - "sharedRoleSetupExistingName": "", - "sharedRoleSetupNew": "", - "softbanNoReason": "", - "softbanReason": "", - "unSoftbanNoReason": "", - "unSoftbanReason": "" -} \ No newline at end of file diff --git a/src/languages/ro/permissions.json b/src/languages/ro/permissions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ro/permissions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ro/preconditions.json b/src/languages/ro/preconditions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ro/preconditions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ro/selfModeration.json b/src/languages/ro/selfModeration.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ro/selfModeration.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ro/serializers.json b/src/languages/ro/serializers.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ro/serializers.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ro/settings.json b/src/languages/ro/settings.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ro/settings.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ro/system.json b/src/languages/ro/system.json deleted file mode 100644 index 073b9b683..000000000 --- a/src/languages/ro/system.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "discordAbortError": "", - "fetchBansFail": "", - "helpTitles": { - "aliases": "", - "usages": "", - "extendedHelp": "", - "explainedUsage": "", - "possibleFormats": "", - "examples": "", - "reminders": "" - }, - "jumpTo": "", - "loading": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "prefixReminder": "" -} \ No newline at end of file diff --git a/src/languages/ru/arguments.json b/src/languages/ru/arguments.json deleted file mode 100644 index a7befa6f3..000000000 --- a/src/languages/ru/arguments.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "boolean_one": "", - "boolean_other": "", - "booleanError": "", - "booleanDisabled": "", - "booleanEnabled": "", - "booleanFalseOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "booleanTrueOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "caseNoEntries": "", - "caseUnknownEntry": "", - "caseNotInThisGuild": "", - "caseLatestOptions": [ - "", - "" - ], - "categoryChannelError": "", - "channelError": "", - "command": "", - "commandMatch": "", - "dateError": "", - "dateFormats": "", - "dateTooEarly": "", - "dateTooFar": "", - "dmChannelError": "", - "duration": "", - "durationFormats": "", - "emojiError": "", - "floatError": "", - "floatTooLarge": "", - "floatTooSmall": "", - "guildChannelError": "", - "guildChannelMismatchingError": "", - "guildChannelMissingGuildError": "", - "guildPrivateThreadChannelError": "", - "guildPublicThreadChannelError": "", - "guildStageVoiceChannelError": "", - "guildTextChannelError": "", - "guildThreadChannelError": "", - "guildVoiceChannelError": "", - "hyperlinkError": "", - "integerError": "", - "integerTooLarge": "", - "integerTooSmall": "", - "invite": "", - "language": "", - "memberError": "", - "memberMissingGuild": "", - "messageError": "", - "missing": "", - "newsChannel": "", - "numberError": "", - "numberTooLarge": "", - "numberTooSmall": "", - "piece": "", - "rangeInvalid": "", - "rangeMax_other": "", - "rangeMax_one": "", - "resetPossibles": [ - "", - "" - ], - "roleError": "", - "roleMissingGuild": "", - "snowflake": "", - "store": "", - "stringTooLong": "", - "stringTooShort": "", - "time": "", - "timeSpan": "", - "timeSpanTooBig": "", - "timeSpanTooSmall": "", - "tooFewWinners": "", - "tooManyWinners": "", - "unavailable": "", - "userError": "", - "enumEmptyError": "", - "enumError": "" -} \ No newline at end of file diff --git a/src/languages/ru/assertions.json b/src/languages/ru/assertions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ru/assertions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ru/commands/admin.json b/src/languages/ru/commands/admin.json deleted file mode 100644 index 101b106a7..000000000 --- a/src/languages/ru/commands/admin.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "confUpdated": "", - "confGetNoExt": "Кажется, ключа **{{key}}** не существует.", - "confGet": "Значение ключа **{{key}}**: `{{value}}`", - "confReset": "", - "confNochange": "Значение **{{key}}** уже соответствует этому значению.", - "confServerDescription": "Определить параметры для сервера.", - "confServerExtended": { - "usages": [ - "", - "show", - "show НазваниеКлюча", - "", - "reset НазваниеКлюча", - "menu" - ], - "extendedHelp": "", - "examples": [ - "set language ru-RU", - "", - "show", - "show channels", - "remove roles.moderator Модератор", - "reset roles.moderator", - "menu" - ], - "reminder": "" - }, - "confServer": "**Настройки сервера {{key}}**\n{{list}}", - "confDashboardOnlyKey": "`{{key}}` можно настроить только через веб-панель инструментов ()", - "confSettingNotSet": "Не задано", - "rolesetDescription": "Управляйте наборами уникальных ролей.", - "rolesetExtended": { - "usages": [ - "set НазваниеНабораРолей Роль1 Роль2 Роль3...", - "remove НазваниеНабораРолей Роль1 Роль2 Роль3...", - "reset", - "reset НазваниеНабораРолей", - "list", - "НазваниеНабораРолей Роль1 Роль2 Роль3" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "добавить", - "Создать новый набор ролей или добавить роль к уже существующему." - ], - [ - "удалить", - "Удалить роль из существующего набора ролей." - ], - [ - "сбросить", - "Удаляет все роли из набора ролей или, если не указано, все существующие наборы ролей." - ], - [ - "список", - "Перечисляет все наборы ролей." - ], - [ - "авто", - "Добавляет или удаляет набор ролей." - ], - [ - "НазваниеНабораРолей", - "Название набора ролей" - ], - [ - "Роль1 Роль2 Роль3", - "" - ] - ], - "examples": [ - "add регионы Америка", - "add регионы Африка Америка Азия Европа", - "remove регионы Америка", - "reset", - "reset регионы", - "list", - "регионы Америка", - "регионы Африка Америка Азия Европа" - ], - "reminder": "Эта команда может добавить и/или удалить несколько ролей одновременно." - }, - "rolesetCreated": "", - "rolesetAdded": "", - "rolesetRemoved": "", - "rolesetResetEmpty": "", - "rolesetResetAll": "{{GREENTICK}} Все наборы ролей успешно удалены.", - "rolesetResetNotExists": "{{REDCROSS}} На этом сервере не существует набора ролей `{{name}}`.", - "rolesetResetGroup": "{{GREENTICK}} Набор ролей `{{name}}` успешно удалён с этого сервера.", - "rolesetUpdated": "Набор уникальных ролей {{name}} обновлён.", - "rolesetNoRolesets": "У вас нет наборов ролей.", - "confMenuRenderAtFolder": "", - "confMenuRenderAtPiece": "", - "confMenuRenderNokeys": "", - "confMenuRenderSelect": "", - "confMenuRenderUpdate": "• Обновить значение → `set `", - "confMenuRenderRemove": "• Удалить значение → `remove `", - "confMenuRenderReset": "• Сбросить значение → `reset`", - "confMenuRenderUndo": "• Отменить обновление → `undo`", - "confMenuRenderCvalue": "Текущее значение: **``{{value}}``**", - "confMenuRenderBack": "", - "confMenuInvalidKey": "", - "confMenuInvalidAction": "", - "confMenuSaved": "Все изменения успешно сохранены." -} \ No newline at end of file diff --git a/src/languages/ru/commands/animal.json b/src/languages/ru/commands/animal.json deleted file mode 100644 index 2e469996e..000000000 --- a/src/languages/ru/commands/animal.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "bunnyDescription": "", - "bunnyExtended": { - "extendedHelp": "" - }, - "bunnyEmbedData": { - "title": "", - "source": "" - }, - "dogDescription": "Милые собачки! ❤", - "dogExtended": { - "extendedHelp": "**Вы** знаете, насколько собаки милые? Они такие красивые!\nЭта команда использует [dog.ceo](https://dog.ceo), чтобы показать изображения самых милых собачек!" - }, - "foxDescription": "Позвольте мне показать вам изображение лисицы!", - "foxExtended": { - "extendedHelp": "Эта команда выдаёт случайное изображение с [randomfox.ca](https://randomfox.ca/)." - }, - "kittyDescription": "КОТЯТА!", - "kittyExtended": { - "extendedHelp": "**Вы** знаете, насколько котята милые? Они такие красивые!\nЭта команда использует [random.cat](https://aws.random.cat/), чтобы показать изображения самых милых кошек!" - }, - "shibeDescription": "Милые сибы!", - "shibeExtended": { - "extendedHelp": "Все любят сиба-ину, я тоже буду их любить! Они такие очаровательные ❤" - } -} \ No newline at end of file diff --git a/src/languages/ru/commands/auto-moderation.json b/src/languages/ru/commands/auto-moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ru/commands/auto-moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ru/commands/case.json b/src/languages/ru/commands/case.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ru/commands/case.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ru/commands/fun.json b/src/languages/ru/commands/fun.json deleted file mode 100644 index 7892e327d..000000000 --- a/src/languages/ru/commands/fun.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "escaperopeDescription": "", - "escaperopeExtended": { - "extendedHelp": "" - }, - "escaperopeOutput": "" -} \ No newline at end of file diff --git a/src/languages/ru/commands/game.json b/src/languages/ru/commands/game.json deleted file mode 100644 index 663fb1240..000000000 --- a/src/languages/ru/commands/game.json +++ /dev/null @@ -1,447 +0,0 @@ -{ - "c4Description": "", - "c4Extended": { - "usages": [ - "Пользователь" - ], - "extendedHelp": "В эту игру лучше всего играть на ПК.\nСоедини 4 (Четыре в ряд) - это игра на двоих, в которой игроки сначала выбирают цвет, а затем ходят по очереди, бросая фишки в ячейки вертикально расположенной решётки. Решётка состоит из семи столбцов, каждый из которых содержит шесть ячеек. Выигрывает тот, кто первым выстроит ряд из четырёх фишек своего цвета по горизонтали, по вертикали или по диагонали.", - "examples": [ - "WolfStar" - ] - }, - "c4Prompt": "", - "gamesBot": "", - "gamesNoPlayers": "", - "gamesProgress": "", - "gamesPromptDeny": "Сожалею, но соперник отказался играть.", - "gamesRepeat": "", - "gamesSelf": "", - "gamesTooManyOrFew": "", - "hgBloodbath": [ - "{1} хватает лопату.", - "{1} хватает рюкзак и отступает.", - "{1} и {2} сражаются за сумку. {1} сдаётся и отступает.", - "{1} и {2} сражаются за сумку. {2} сдаётся и отступает.", - "{1} находит лук, несколько стрел и колчан.", - "", - "{1} берёт горсть метательных ножей.", - "{1} вырывает булаву из рук {2}.", - "{1} находит флягу, полную воды.", - "", - "{1} собирает столько еды, сколько может.", - "{1} хватает меч.", - "{1} берёт копьё из Рога изобилия.", - "{1} находит сумку, наполненную взрывчаткой.", - "", - "{1} берёт серп из Рога изобилия.", - "", - "{1} убегает с зажигалкой и верёвкой.", - "", - "", - "{1} хватает рюкзак, не понимая, что он пуст.", - "{1} ломает {2} нос за корзину хлеба.", - "", - "{1} забирает трезубец из Рога изобилия.", - "", - "{1} отпугивает {2} от Рога изобилия.", - "{1} хватает щит, прислонённый к Рогу изобилия.", - "", - "", - "", - "{1} бросает нож в голову {2T}.", - "{1T} случайно наступает на мину.", - "{1} застаёт {2T} врасплох и убивает его/её.", - "{1} и {2} действуют сообща для того, чтобы утопить {3T}.", - "{1} душит {2T} после кулачного боя.", - "{1} выпускает стрелу в голову {2T}.", - "{1T} не может справиться с обстоятельствами и совершает самоубийство.", - "{1} ударяет {2T} головой о камень несколько раз.", - "{1} сворачивает {2T} шею.", - "{1} обезглавливает {2T} мечом.", - "{1} вонзает копьё в живот {2T}.", - "{1} поджигает {2T} с помощью «коктейля Молотова».", - "{1T} падает в яму и умирает.", - "", - "{1} тяжело ранит {2T}, но избавляет его/её от мучений.", - "{1} тяжело ранит {2T} и оставляет его/её умирать.", - "{1} разбивает голову {2T} булавой.", - "{1} сталкивает {2T} со скалы во время боя на ножах.", - "{1} бросает нож в грудь {2T}.", - "{1T} не может убедить {2} не убивать его/её.", - "", - "{1T} падает в замёрзшее озеро и тонет.", - "{1}, {2} и {3T} начинают сражаться, но {2} убегает, когда {1} убивает {3T}.", - "{1} убивает {2T} его/её же собственным оружием.", - "", - "{1} приводит в действие взрывчатку, убивая {2T}.", - "{1} приводит в действие взрывчатку, убивая {2T} и {3T}.", - "{1} приводит в действие взрывчатку, убивая {2T}, {3T} и {4T}.", - "{1} приводит в действие взрывчатку, убивая {2T}, {3T}, {4T} и {5T}.", - "", - "{1T} и {2T} угрожают двойным самоубийством. Это не срабатывает, и они умирают.", - "", - "{1} убивает {2T} топором.", - "{1} и {2} сражаются с {3T} и {4T}. {1} и {2} выживают.", - "{1T} и {2T} сражаются с {3} и {4}. {3} и {4} выживают.", - "{1T} атакует {2}, но {3} защищает его/её, убивая {1T}.", - "", - "{1} душит {2T} верёвкой.", - "{1} убивает {2T} за его/её припасы.", - "{1} пускает стрелу в {2}, но промахивается и убивает {3T}.", - "", - "{1} вонзает в {2T} ветку дерева.", - "{1} вонзает трезубец в спину {2T}.", - "{1}, {2T} и {3T} затевают драку. {1} торжествующе убивает остальных.", - "{1T}, {2} и {3T} затевают драку. {2} торжествующе убивает остальных.", - "{1T}, {2T} и {3} затевают драку. {3} торжествующе убивает остальных.", - "{1} обнаруживает, что {2T} прячется в Роге изобилия, и убивает его/её.", - "{1T} обнаруживает, что {2} прячется в Роге изобилия, но {2} убивает его/её.", - "{1} убивает {2T} серпом.", - "{1} и {2T} сражаются за сумку. {1} душит {2T} ремнями и убегает.", - "{1T} и {2} сражаются за сумку. {2} душит {1T} ремнями и убегает.", - "", - "", - "", - "" - ], - "hgDay": [ - "{1} идёт на охоту.", - "", - "{1} исследует арену.", - "", - "{1} отвлекает внимание {2} и убегает.", - "{1} преследует {2}.", - "{1} рыбачит.", - "{1} маскируется в кустах.", - "", - "{1} делает деревянное копьё.", - "{1} обнаруживает пещеру.", - "{1} атакует {2}, но ему/ей удаётся сбежать.", - "", - "{1} убегает от {2}.", - "{1} собирает фрукты с дерева.", - "{1} получает топор от неизвестного спонсора.", - "{1} получает чистую воду от неизвестного спонсора.", - "{1} получает медикаменты от неизвестного спонсора.", - "{1} получает свежую пищу от неизвестного спонсора.", - "{1} ищет источник воды.", - "{1} побеждает {2} в бою, но сохраняет ему/ей жизнь.", - "", - "{1} умоляет {2} убить его/её. Он/а отказывается, оставляя {1} в живых.", - "{1} пытается проспать весь день.", - "{1}, {2}, {3} и {4} совершают набег на лагерь {5}, пока он/а охотится.", - "{1} строит хижину.", - "", - "{1} практикуется в стрельбе из лука.", - "{1} думает о доме.", - "", - "{1} пытается ловить рыбу трезубцем.", - "{1} ищет хворост.", - "{1} и {2} разделяются для поиска ресурсов.", - "{1} собирает цветы.", - "{1} занимается ранами {2}.", - "", - "", - "{1} делает рогатку.", - "", - "{1} обнаруживает реку.", - "{1} охотится за другими трибутами.", - "{1} и {2} охотятся за другими трибутами.", - "{1}, {2} и {3} охотятся за другими трибутами.", - "{1}, {2}, {3} и {4} охотятся за другими трибутами.", - "{1}, {2}, {3}, {4} и {5} охотятся за другими трибутами.", - "{1} получает взрывчатку от неизвестного спонсора.", - "{1} подвергает сомнению своё здравомыслие.", - "{1} заставляет {2} есть штаны.", - "{1} заставляет {2T} есть штаны. {2T} давится и умирает.", - "{1} застаёт {2T} врасплох и убивает его/её.", - "{1} бросает нож в голову {2T}.", - "", - "{1} и {2} действуют сообща для того, чтобы утопить {3T}.", - "{1} душит {2T} после кулачного боя.", - "{1} выпускает стрелу в голову {2T}.", - "{1T} истекает кровью из-за необработанных ран.", - "{1T} не может справиться с обстоятельствами и совершает самоубийство.", - "{1} ударяет {2T} головой о камень несколько раз.", - "{1T} по незнанию съедает ядовитые ягоды.", - "", - "", - "{1} обезглавливает {2T} мечом.", - "{1T} умирает от инфекции.", - "{1} вонзает копьё в живот {2T}.", - "{1} поджигает {2T} с помощью «коктейля Молотова».", - "{1T} падает в яму и умирает.", - "", - "{1} тяжело ранит {2T}, но избавляет его/её от мучений.", - "{1} тяжело ранит {2T} и оставляет его/её умирать.", - "{1} разбивает голову {2T} булавой.", - "{1T} пытается забраться на дерево, но разбивается насмерть.", - "{1} сталкивает {2T} со скалы во время боя на ножах.", - "{1} бросает нож в грудь {2T}.", - "Ловушка {1} убивает {2T}.", - "", - "{1T} не может убедить {2} не убивать его/её.", - "", - "{1T} падает в замёрзшее озеро и тонет.", - "{1}, {2} и {3T} начинают сражаться, но {2} убегает, когда {1} убивает {3T}.", - "{1} убивает {2T} его/её же собственным оружием.", - "", - "{1} приводит в действие взрывчатку, убивая {2T}.", - "{1} приводит в действие взрывчатку, убивая {2T} и {3T}.", - "{1} приводит в действие взрывчатку, убивая {2T}, {3T} и {4T}.", - "{1} приводит в действие взрывчатку, убивая {2T}, {3T}, {4T} и {5T}.", - "", - "{1T} и {2T} угрожают двойным самоубийством. Это не срабатывает, и они умирают.", - "", - "{1T} умирает от переохлаждения.", - "{1T} умирает от голода.", - "{1T} умирает от жажды.", - "{1} убивает {2T} топором.", - "{1} и {2} сражаются с {3T} и {4T}. {1} и {2} выживают.", - "{1T} и {2T} сражаются с {3} и {4}. {3} и {4} выживают.", - "{1T} погибает, пытаясь сбежать с арены.", - "{1T} умирает от дизентерии.", - "", - "{1T} атакует {2}, но {3} защищает его/её, убивая {1T}.", - "", - "{1T} случайно наступает на мину.", - "", - "{1} душит {2T} верёвкой.", - "{1} убивает {2T} за его/её припасы.", - "{1} пускает стрелу в {2}, но промахивается и убивает {3T}.", - "", - "", - "", - "{1} вонзает в {2T} ветку дерева.", - "{1} заставляет {2} убить {3T} или {4}. Он/а решает убить {3T}.", - "{1} заставляет {2} убить {3} или {4T}. Он/а решает убить {4T}.", - "", - "", - "{1} подмешивает яд в напиток {2T}. Он/а выпивает его и умирает.", - "{1} вонзает трезубец в спину {2T}.", - "", - "{1}, {2T} и {3T} затевают драку. {1} торжествующе убивает остальных.", - "{1T}, {2} и {3T} затевают драку. {2} торжествующе убивает остальных.", - "{1T}, {2T} и {3} затевают драку. {3} торжествующе убивает остальных.", - "{1} убивает {2T} серпом.", - "{1}, {2}, {3}, {4} и {5} выслеживают и убивают {6T}.", - "{1}, {2}, {3} и {4} выслеживают и убивают {5T}.", - "{1}, {2} и {3} выслеживают и убивают {4T}.", - "{1} и {2} выслеживают и убивают {3T}.", - "{1} выслеживает и убивает {2T}.", - "", - "", - "{1} гоняется за бабочкой.", - "", - "{1} сталкивается с {2}, они решают объединиться.", - "{1} видит {2} сквозь деревья и планирует убить его/её.", - "{1} подкрадывается к {2T} сзади и сворачивает ему/ей шею.", - "{1T} вызывает {2} на бой и быстро погибает.", - "" - ], - "hgNight": [ - "{1} разжигает огонь.", - "{1} разбивает лагерь на ночь.", - "", - "{1} забирается на дерево, чтобы отдохнуть.", - "", - "{1} и {2} рассказывают друг другу истории о себе.", - "{1}, {2}, {3} и {4} спят по очереди.", - "{1}, {2} и {3} спят по очереди.", - "{1} и {2} спят по очереди.", - "{1} занимается своими ранами.", - "", - "{1} кричит о помощи.", - "{1} бодрствует всю ночь.", - "{1} теряет сознание от истощения.", - "", - "", - "", - "{1}, {2} и {3} обсуждают Игры и то, что может произойти утром.", - "", - "", - "{1} и {2} разговаривают о трибутах, которые ещё живы.", - "{1} просыпается из-за ночных кошмаров.", - "", - "{1} думает о победе.", - "{1}, {2}, {3} и {4} рассказывают друг другу истории о привидениях, чтобы поднять настроение.", - "{1} смотрит на ночное небо.", - "{1} побеждает {2} в бою, но сохраняет ему/ей жизнь.", - "{1} умоляет {2} убить его/её. Он/а отказывается, оставляя {1} в живых.", - "{1} уничтожает припасы {2}, пока он/а спит.", - "{1}, {2}, {3}, {4} и {5} спят по очереди.", - "", - "{1} получает топор от неизвестного спонсора.", - "{1} получает чистую воду от неизвестного спонсора.", - "{1} получает медикаменты от неизвестного спонсора.", - "{1} получает свежую пищу от неизвестного спонсора.", - "", - "{1} пытается разжечь огонь, но безуспешно.", - "{1} думает о доме.", - "{1} занимается ранами {2}.", - "", - "", - "", - "{1} и {2} держатся за руки.", - "{1} убеждает {2} прижаться к нему/ней.", - "{1} получает взрывчатку от неизвестного спонсора.", - "{1} подвергает сомнению своё здравомыслие.", - "{1} заставляет {2} есть штаны.", - "{1} заставляет {2T} есть штаны. {2T} давится и умирает.", - "{1} застаёт {2T} врасплох и убивает его/её.", - "{1} бросает нож в голову {2T}.", - "", - "{1} и {2} действуют сообща для того, чтобы утопить {3T}.", - "{1} душит {2T} после кулачного боя.", - "{1} выпускает стрелу в голову {2T}.", - "{1T} истекает кровью из-за необработанных ран.", - "{1T} не может справиться с обстоятельствами и совершает самоубийство.", - "{1} ударяет {2T} головой о камень несколько раз.", - "{1T} по незнанию съедает ядовитые ягоды.", - "", - "", - "{1} обезглавливает {2T} мечом.", - "{1T} умирает от инфекции.", - "{1} вонзает копьё в живот {2T}.", - "{1} поджигает {2T} с помощью «коктейля Молотова».", - "{1T} падает в яму и умирает.", - "", - "{1} тяжело ранит {2T}, но избавляет его/её от мучений.", - "{1} тяжело ранит {2T} и оставляет его/её умирать.", - "{1} разбивает голову {2T} булавой.", - "{1T} пытается забраться на дерево, но разбивается насмерть.", - "{1} сталкивает {2T} со скалы во время боя на ножах.", - "{1} бросает нож в грудь {2T}.", - "Ловушка {1} убивает {2T}.", - "", - "{1T} не может убедить {2} не убивать его/её.", - "", - "{1T} падает в замёрзшее озеро и тонет.", - "{1}, {2} и {3T} начинают сражаться, но {2} убегает, когда {1} убивает {3T}.", - "{1} убивает {2T} его/её же собственным оружием.", - "", - "{1} приводит в действие взрывчатку, убивая {2T}.", - "{1} приводит в действие взрывчатку, убивая {2T} и {3T}.", - "{1} приводит в действие взрывчатку, убивая {2T}, {3T} и {4T}.", - "{1} приводит в действие взрывчатку, убивая {2T}, {3T}, {4T} и {5T}.", - "", - "{1T} и {2T} угрожают двойным самоубийством. Это не срабатывает, и они умирают.", - "", - "{1T} умирает от переохлаждения.", - "{1T} умирает от голода.", - "{1T} умирает от жажды.", - "{1} убивает {2T} топором.", - "{1} и {2} сражаются с {3T} и {4T}. {1} и {2} выживают.", - "{1T} и {2T} сражаются с {3} и {4}. {3} и {4} выживают.", - "{1T} погибает, пытаясь сбежать с арены.", - "{1T} умирает от дизентерии.", - "", - "{1T} атакует {2}, но {3} защищает его/её, убивая {1T}.", - "", - "{1T} случайно наступает на мину.", - "", - "{1} душит {2T} верёвкой.", - "{1} убивает {2T} за его/её припасы.", - "{1} пускает стрелу в {2}, но промахивается и убивает {3T}.", - "", - "", - "", - "{1} вонзает в {2T} ветку дерева.", - "{1} заставляет {2} убить {3T} или {4}. Он/а решает убить {3T}.", - "{1} заставляет {2} убить {3} или {4T}. Он/а решает убить {4T}.", - "", - "", - "{1} подмешивает яд в напиток {2T}. Он/а выпивает его и умирает.", - "{1} вонзает трезубец в спину {2T}.", - "", - "{1}, {2T} и {3T} затевают драку. {1} торжествующе убивает остальных.", - "{1T}, {2} и {3T} затевают драку. {2} торжествующе убивает остальных.", - "{1T}, {2T} и {3} затевают драку. {3} торжествующе убивает остальных.", - "{1} убивает {2T} серпом.", - "{1}, {2}, {3}, {4} и {5} выслеживают и убивают {6T}.", - "{1}, {2}, {3} и {4} выслеживают и убивают {5T}.", - "{1}, {2} и {3} выслеживают и убивают {4T}.", - "{1} и {2} выслеживают и убивают {3T}.", - "{1} выслеживает и убивает {2T}.", - "", - "", - "" - ], - "hungerGamesDescription": "", - "hungerGamesExtended": { - "usages": [ - "Пользователь1 Пользователь2 Пользователь3...", - "--autofill" - ], - "extendedHelp": "", - "examples": [ - "" - ], - "reminder": "" - }, - "hungerGamesResultDeaths_one": "", - "hungerGamesResultDeaths_other": "", - "hungerGamesResultHeaderBloodbath": "", - "hungerGamesResultHeaderMoon": "Ночь {{game.turn}}", - "hungerGamesResultHeaderSun": "День {{game.turn}}", - "hungerGamesResultProceed": "Продолжить?", - "hungerGamesStop": "", - "hungerGamesWinner": "И победитель... {{winner}}!", - "ticTacToeDescription": "", - "ticTacToeDraw": "Этот матч завершился **ничьей**!\n{{board}}", - "ticTacToeExtended": { - "usages": [ - "Пользователь" - ], - "extendedHelp": "", - "examples": [ - "WolfStar" - ] - }, - "ticTacToePrompt": "", - "ticTacToeTurn": "", - "ticTacToeWinner": "Победитель... {{winner}}!\n{{board}}", - "triviaActiveGame": "", - "triviaDescription": "", - "triviaEmbedTitles": { - "difficulty": "Сложность", - "trivia": "" - }, - "triviaExtended": { - "usages": [ - "", - "Категория", - "Категория multiple/boolean/truefalse", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "Категория", - "Категория, из которой задаются вопросы." - ], - [ - "multiple/boolean/truefalse", - "" - ], - [ - "easy/medium/hard", - "Уровень сложности задаваемых вопросов." - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "triviaIncorrect": "", - "triviaInvalidCategory": "", - "triviaNoAnswer": "", - "triviaWinner": "" -} \ No newline at end of file diff --git a/src/languages/ru/commands/general.json b/src/languages/ru/commands/general.json deleted file mode 100644 index 5e16f992d..000000000 --- a/src/languages/ru/commands/general.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "helpAllFlag": "", - "helpCommandCount_one": "", - "helpCommandCount_other": "", - "helpData": { - "footer": "", - "title": "" - }, - "helpDescription": "", - "helpExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "reminder": "", - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "helpDm": "", - "helpNodm": "", - "v7Description": "", - "v7Extended": { - "extendedHelp": "" - }, - "v7Message": "", - "v7NayreMessage": "" -} \ No newline at end of file diff --git a/src/languages/ru/commands/info.json b/src/languages/ru/commands/info.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ru/commands/info.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ru/commands/management.json b/src/languages/ru/commands/management.json deleted file mode 100644 index ba7b82762..000000000 --- a/src/languages/ru/commands/management.json +++ /dev/null @@ -1,445 +0,0 @@ -{ - "commandHandlerAborted": "", - "permissionNodesHigher": "", - "permissionNodesCannotAllowEveryone": "", - "permissionNodesInvalidType": "", - "permissionNodesAdd": "", - "permissionNodesNodeNotExists": "", - "permissionNodesCommandNotExists": "", - "permissionNodesRemove": "", - "permissionNodesReset": "", - "permissionNodesShowName": "Разрешения для: __{{name}}__", - "permissionNodesShowAllow": "", - "permissionNodesShowDeny": "", - "guildInfoTitles": { - "CHANNELS": "Каналы", - "MEMBERS": "", - "OTHER": "" - }, - "guildInfoChannels": "", - "guildInfoChannelsAfkChannelText": "", - "guildInfoMembers": "", - "guildInfoOther": "", - "guildInfoBanner": "", - "guildInfoIcon": "", - "guildInfoSplash": "", - "guildInfoDiscoverySplash": "", - "roleInfoTitles": { - "PERMISSIONS": "Разрешения" - }, - "roleInfoData": "", - "roleInfoAll": "Все разрешения предоставлены.", - "roleInfoNoPermissions": "Разрешения не предоставлены.", - "manageCommandAutoDeleteShowEmpty": "", - "manageCommandAutoDeleteShow": "", - "manageCommandAutoDeleteAdd": "", - "manageCommandAutoDeleteRemove": "{{GREENTICK}} Успешно! Команды в {{channel}} больше не будут автоматически удаляться!", - "manageCommandAutoDeleteRemoveNotset": "", - "manageCommandAutoDeleteReset": "", - "manageCommandChannelShow": "", - "manageCommandChannelShowEmpty": "", - "manageCommandChannelAddAlreadyset": "", - "manageCommandChannelAdd": "", - "manageCommandChannelRemoveNotset": "Команда, которую вы пытаетесь включить, не была отключена для {{channel}}.", - "manageCommandChannelRemove": "", - "manageCommandChannelResetEmpty": "", - "manageCommandChannelReset": "", - "manageReactionRolesShowEmpty": "", - "manageReactionRolesAddChannel": "", - "manageReactionRolesAddPrompt": "", - "manageReactionRolesAddMissing": "", - "manageReactionRolesAdd": "", - "manageReactionRolesRemoveNotExists": "", - "manageReactionRolesRemove": "", - "manageReactionRolesResetEmpty": "", - "manageReactionRolesReset": "", - "configurationEquals": "", - "setIgnoreChannelsSet": "", - "setIgnoreChannelsRemoved": "", - "setImageLogsSet": "", - "setMemberAddLogsSet": "", - "setMemberRemoveLogsSet": "", - "setMessageUpdateLogsSet": "", - "setMessageDeleteLogsSet": "", - "setModLogsSet": "", - "setPrefixSet": "", - "stickyRolesNotExists": "", - "stickyRolesReset": "", - "stickyRolesRemove": "", - "stickyRolesAdd": "", - "stickyRolesShowEmpty": "", - "stickyRolesShowSingle": "", - "createMuteDescription": "", - "createMuteExtended": { - "extendedHelp": "" - }, - "permissionNodesDescription": "", - "permissionNodesExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "managecommandautodeleteDescription": "", - "managecommandautodeleteExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageCommandChannelDescription": "", - "manageCommandChannelExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageReactionRolesDescription": "", - "manageReactionRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "rolesAdded": "", - "rolesAuditlog": "", - "rolesListEmpty": "", - "rolesListTitle": "", - "rolesNotManageable": "", - "rolesNotPublic": "", - "rolesRemoved": "", - "setIgnoreChannelsDescription": "", - "setIgnoreChannelsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "канал", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setImageLogsDescription": "", - "setImageLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "setMemberAddLogsDescription": "", - "setMemberAddLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMemberRemoveLogsDescription": "", - "setMemberRemoveLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMessageUpdateLogsDescription": "", - "setMessageUpdateLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setMessageDeleteLogsDescription": "", - "setMessageDeleteLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setmodlogsDescription": "", - "setmodlogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "канал", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setprefixDescription": "", - "setprefixExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "guildInfoDescription": "", - "guildInfoExtended": { - "extendedHelp": "" - }, - "roleInfoDescription": "", - "roleInfoExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "stickyRolesDescription": "", - "stickyRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesDescription": "", - "rolesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "роли", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/ru/commands/misc.json b/src/languages/ru/commands/misc.json deleted file mode 100644 index 32f64d584..000000000 --- a/src/languages/ru/commands/misc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "snipeEmpty": "", - "snipeTitle": "", - "snipeDescription": "", - "snipeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/ru/commands/moderation.json b/src/languages/ru/commands/moderation.json deleted file mode 100644 index 6c435ae0d..000000000 --- a/src/languages/ru/commands/moderation.json +++ /dev/null @@ -1,889 +0,0 @@ -{ - "permissions": "Разрешения для {{username}} ({{id}})", - "permissionsAll": "Все разрешения", - "slowmodeSet": "", - "slowmodeReset": "", - "banNotBannable": "", - "dehoistStarting": "", - "dehoistProgress": "", - "dehoistEmbed": { - "title": "", - "descriptionNoone": "", - "descriptionWithError": "", - "descriptionWithMultipleErrors": "", - "description": "", - "descriptionMultipleMembers": "", - "fieldErrorTitle": "" - }, - "kickNotKickable": "", - "lockdownLock": "", - "lockdownLocking": "", - "lockdownLocked": "", - "lockdownUnlocked": "", - "lockdownOpen": "", - "muteMuted": "", - "muteUserNotMuted": "", - "restrictLowlevel": "", - "pruneAlert_one": "", - "pruneAlert_other": "", - "pruneInvalidPosition": "", - "pruneNoDeletes": "", - "pruneLogHeader": "", - "toggleModerationDmToggledEnabled": "", - "toggleModerationDmToggledDisabled": "", - "moderationOutput_one": "", - "moderationOutput_other": "", - "moderationOutputWithReason_one": "", - "moderationOutputWithReason_other": "", - "moderationFailed_one": "", - "moderationFailed_other": "", - "moderationDmFooter": "", - "moderationDmDescription": "", - "moderationDmDescriptionWithReason": "", - "moderationDmDescriptionWithDuration": "", - "moderationDmDescriptionWithReasonWithDuration": "", - "slowmodeDescription": "", - "slowmodeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "banDescription": "Ударьте кого-нибудь банхаммером.", - "banExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "dehoistDescription": "", - "dehoistExtended": { - "extendedHelp": "", - "reminder": "" - }, - "kickDescription": "", - "kickExtended": { - "usages": [ - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "lockdownDescription": "", - "lockdownExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "muteDescription": "", - "muteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "setNicknameDescription": "Измените никнейм пользователя.", - "setNicknameExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ], - "reminder": "" - }, - "addRoleDescription": "", - "addRoleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "removeroleDescription": "", - "removeroleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "pruneDescription": "", - "pruneExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "permissionsDescription": "", - "permissionsExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ], - "extendedHelp": "" - }, - "restrictAttachmentDescription": "", - "restrictAttachmentExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictEmbedDescription": "", - "restrictEmbedExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictEmojiDescription": "", - "restrictEmojiExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictReactionDescription": "", - "restrictReactionExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictVoiceDescription": "", - "restrictVoiceExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "softBanDescription": "", - "softBanExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "timeoutApplyDescription": "", - "timeoutApplyExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutUndoDescription": "", - "timeoutUndoExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutNotModeratable": "", - "toggleModerationDmDescription": "", - "toggleModerationDmExtended": { - "extendedHelp": "" - }, - "unbanDescription": "", - "unbanExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unmuteDescription": "", - "unmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unrestrictAttachmentDescription": "", - "unrestrictAttachmentExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmbedDescription": "", - "unrestrictEmbedExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmojiDescription": "", - "unrestrictEmojiExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictReactionDescription": "", - "unrestrictReactionExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictVoiceDescription": "", - "unrestrictVoiceExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unwarnDescription": "", - "unwarnExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vmuteDescription": "", - "vmuteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "voiceKickDescription": "", - "voiceKickExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vunmuteDescription": "", - "vunmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "warnDescription": "", - "warnExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/ru/commands/shared.json b/src/languages/ru/commands/shared.json deleted file mode 100644 index ddbb28e7f..000000000 --- a/src/languages/ru/commands/shared.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "deprecatedMessage": "", - "slashOnlyDetailedDescription": { - "extendedHelp": "" - }, - "slashOnlyErrorMessage": "" -} \ No newline at end of file diff --git a/src/languages/ru/commands/system.json b/src/languages/ru/commands/system.json deleted file mode 100644 index 83b4dbe2d..000000000 --- a/src/languages/ru/commands/system.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "evalDescription": "", - "evalExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "evalTimeout": "", - "evalError": "**Ошибка**:{{output}}\n**Тип**:{{type}}\n{{time}}", - "dmNotSent": "", - "dmSent": "Я отправила вам личное сообщение.", - "reboot": "", - "rebootDescription": "Перезагружает бота.", - "rebootExtended": { - "extendedHelp": "", - "reminder": "" - } -} \ No newline at end of file diff --git a/src/languages/ru/commands/tools.json b/src/languages/ru/commands/tools.json deleted file mode 100644 index 8f745b3f2..000000000 --- a/src/languages/ru/commands/tools.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "avatarDescription": "Просмотрите чей-либо аватар в полном размере.", - "avatarExtended": { - "usages": [ - "", - "Пользователь" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "Пользователь", - "" - ] - ], - "reminder": "" - }, - "avatarNone": "", - "voteDescription": "", - "voteExtended": { - "usages": [ - "Вопрос" - ], - "examples": [ - "" - ], - "explainedUsage": [ - [ - "Вопрос", - "" - ] - ] - }, - "voteContentNeeded": "", - "voteReactionBlocked": "", - "whoisExtended": { - "usages": [ - "", - "Пользователь" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "Пользователь", - "" - ] - ] - }, - "whoisMemberRoleListAndMore": "" -} \ No newline at end of file diff --git a/src/languages/ru/commands/twitch.json b/src/languages/ru/commands/twitch.json deleted file mode 100644 index 2f12e1b08..000000000 --- a/src/languages/ru/commands/twitch.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "twitchSubscriptionStreamerNotFound": "", - "twitchSubscriptionStatusValues": [ - "", - "" - ], - "twitchSubscriptionInvalidStatus": "", - "twitchSubscriptionAddDuplicated": "", - "twitchSubscriptionAddSuccessOffline": "", - "twitchSubscriptionAddSuccessLive": "", - "twitchSubscriptionAddMessageForOfflineRequired": "", - "twitchSubscriptionRemoveOrResetEmpty": "", - "twitchSubscriptionRemoveStreamerNotSubscribed": "", - "twitchSubscriptionRemoveNotToProvidedChannel": "", - "twitchSubscriptionRemoveStreamerStatusNotMatch": "", - "twitchSubscriptionRemoveSuccessOffline": "", - "twitchSubscriptionRemoveSuccessLive": "", - "twitchSubscriptionResetSuccess_one": "", - "twitchSubscriptionResetSuccess_other": "", - "twitchSubscriptionShowStreamerNotSubscribed": "", - "twitchSubscriptionShowStatus": { - "live": "", - "offline": "" - }, - "twitchSubscriptionShowUnknownUser": "", - "twitchSubscriptionDescription": "", - "twitchSubscriptionExtended": { - "usages": [ - "", - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/ru/commands/whois.json b/src/languages/ru/commands/whois.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ru/commands/whois.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ru/errors.json b/src/languages/ru/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ru/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ru/events/errors.json b/src/languages/ru/events/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ru/events/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ru/events/guilds-logs.json b/src/languages/ru/events/guilds-logs.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ru/events/guilds-logs.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ru/events/guilds-members.json b/src/languages/ru/events/guilds-members.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ru/events/guilds-members.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ru/events/messages.json b/src/languages/ru/events/messages.json deleted file mode 100644 index 905c8d548..000000000 --- a/src/languages/ru/events/messages.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "messageDelete": "Сообщение удалено • {{channel}}", - "messageUpdate": "Сообщение изменено • {{channel}}" -} \ No newline at end of file diff --git a/src/languages/ru/events/moderation.json b/src/languages/ru/events/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ru/events/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ru/events/noMentionSpam.json b/src/languages/ru/events/noMentionSpam.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ru/events/noMentionSpam.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ru/events/reactions.json b/src/languages/ru/events/reactions.json deleted file mode 100644 index 58325cd66..000000000 --- a/src/languages/ru/events/reactions.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "filterFooter": "Отфильтрованная реакция", - "filter": "{{REDCROSS}} Эй, {{user}}, пожалуйста, не добавляйте эту реакцию!" -} \ No newline at end of file diff --git a/src/languages/ru/events/twitch.json b/src/languages/ru/events/twitch.json deleted file mode 100644 index 095cb8ada..000000000 --- a/src/languages/ru/events/twitch.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "embedDescription": "{{userName}} сейчас в эфире!", - "embedDescriptionWithGame": "{{userName}} сейчас в эфире - Стримит {{gameName}}!" -} \ No newline at end of file diff --git a/src/languages/ru/fuzzySearch.json b/src/languages/ru/fuzzySearch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ru/fuzzySearch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ru/globals.json b/src/languages/ru/globals.json deleted file mode 100644 index 7677dfd3f..000000000 --- a/src/languages/ru/globals.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "defaultLanguage": "Язык по умолчанию", - "no": "Нет", - "yes": "Да", - "durationValue": "{{value, duration}}", - "numberValue": "{{value, number}}", - "numberCompactValue": "{{value, numberCompact}}", - "dateTimeValue": "{{value, dateTime}}", - "orListValue": "{{value, orList}}" -} \ No newline at end of file diff --git a/src/languages/ru/guilds.json b/src/languages/ru/guilds.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ru/guilds.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ru/humanLevels.json b/src/languages/ru/humanLevels.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ru/humanLevels.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ru/moderation.json b/src/languages/ru/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ru/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ru/moderationActions.json b/src/languages/ru/moderationActions.json deleted file mode 100644 index 4c440ae54..000000000 --- a/src/languages/ru/moderationActions.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "actions": { - "addRole": "", - "ban": "", - "kick": "", - "mute": "", - "removeRole": "", - "restrictedAttachment": "", - "restrictedEmbed": "", - "restrictedEmoji": "", - "restrictedReact": "", - "restrictedVoice": "", - "setNickname": "", - "softban": "", - "vkick": "", - "vmute": "", - "warning": "" - }, - "actionCannotManageRoles": "", - "actionRoleNotConfigured": "", - "actionRoleHigherPosition": "", - "actionRoleManaged": "", - "applyNoReason": "", - "applyReason": "", - "requiredMember": "", - "revokeNoReason": "", - "revokeReason": "", - "setNicknameNoReasonRemoved": "", - "setNicknameNoReasonSet": "", - "setNicknameRemoved": "", - "setNicknameSet": "", - "setupMuteExists": "", - "setupTooManyRoles": "", - "sharedRoleSetupAsk": "", - "sharedRoleSetupNoMessage": "", - "sharedRoleSetupExisting": "", - "sharedRoleSetupExistingName": "", - "sharedRoleSetupNew": "", - "softbanNoReason": "", - "softbanReason": "", - "unSoftbanNoReason": "", - "unSoftbanReason": "" -} \ No newline at end of file diff --git a/src/languages/ru/permissions.json b/src/languages/ru/permissions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ru/permissions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ru/preconditions.json b/src/languages/ru/preconditions.json deleted file mode 100644 index f2dd20167..000000000 --- a/src/languages/ru/preconditions.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "cooldown": "Вы только что использовали эту команду. Вы сможете использовать эту команду снова через {{remaining, duration}}.", - "permissionNodes": "{{REDCROSS}} У вас нет разрешения на использование этой команды!" -} \ No newline at end of file diff --git a/src/languages/ru/selfModeration.json b/src/languages/ru/selfModeration.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ru/selfModeration.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ru/serializers.json b/src/languages/ru/serializers.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ru/serializers.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ru/settings.json b/src/languages/ru/settings.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/ru/settings.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/ru/system.json b/src/languages/ru/system.json deleted file mode 100644 index 94207a5e5..000000000 --- a/src/languages/ru/system.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "discordAbortError": "", - "fetchBansFail": "", - "helpTitles": { - "aliases": "", - "usages": "", - "extendedHelp": "", - "explainedUsage": "", - "possibleFormats": "", - "examples": "", - "reminders": "" - }, - "jumpTo": "Перейти к сообщению ►", - "loading": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "prefixReminder": "" -} \ No newline at end of file diff --git a/src/languages/sv-SE/arguments.json b/src/languages/sv-SE/arguments.json deleted file mode 100644 index a7befa6f3..000000000 --- a/src/languages/sv-SE/arguments.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "boolean_one": "", - "boolean_other": "", - "booleanError": "", - "booleanDisabled": "", - "booleanEnabled": "", - "booleanFalseOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "booleanTrueOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "caseNoEntries": "", - "caseUnknownEntry": "", - "caseNotInThisGuild": "", - "caseLatestOptions": [ - "", - "" - ], - "categoryChannelError": "", - "channelError": "", - "command": "", - "commandMatch": "", - "dateError": "", - "dateFormats": "", - "dateTooEarly": "", - "dateTooFar": "", - "dmChannelError": "", - "duration": "", - "durationFormats": "", - "emojiError": "", - "floatError": "", - "floatTooLarge": "", - "floatTooSmall": "", - "guildChannelError": "", - "guildChannelMismatchingError": "", - "guildChannelMissingGuildError": "", - "guildPrivateThreadChannelError": "", - "guildPublicThreadChannelError": "", - "guildStageVoiceChannelError": "", - "guildTextChannelError": "", - "guildThreadChannelError": "", - "guildVoiceChannelError": "", - "hyperlinkError": "", - "integerError": "", - "integerTooLarge": "", - "integerTooSmall": "", - "invite": "", - "language": "", - "memberError": "", - "memberMissingGuild": "", - "messageError": "", - "missing": "", - "newsChannel": "", - "numberError": "", - "numberTooLarge": "", - "numberTooSmall": "", - "piece": "", - "rangeInvalid": "", - "rangeMax_other": "", - "rangeMax_one": "", - "resetPossibles": [ - "", - "" - ], - "roleError": "", - "roleMissingGuild": "", - "snowflake": "", - "store": "", - "stringTooLong": "", - "stringTooShort": "", - "time": "", - "timeSpan": "", - "timeSpanTooBig": "", - "timeSpanTooSmall": "", - "tooFewWinners": "", - "tooManyWinners": "", - "unavailable": "", - "userError": "", - "enumEmptyError": "", - "enumError": "" -} \ No newline at end of file diff --git a/src/languages/sv-SE/assertions.json b/src/languages/sv-SE/assertions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/sv-SE/assertions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/sv-SE/commands/admin.json b/src/languages/sv-SE/commands/admin.json deleted file mode 100644 index 444f39c28..000000000 --- a/src/languages/sv-SE/commands/admin.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "confUpdated": "", - "confGetNoExt": "", - "confGet": "", - "confReset": "", - "confNochange": "", - "confServerDescription": "", - "confServerExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "confServer": "", - "confDashboardOnlyKey": "", - "confSettingNotSet": "", - "rolesetDescription": "", - "rolesetExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesetCreated": "", - "rolesetAdded": "", - "rolesetRemoved": "", - "rolesetResetEmpty": "", - "rolesetResetAll": "", - "rolesetResetNotExists": "", - "rolesetResetGroup": "", - "rolesetUpdated": "", - "rolesetNoRolesets": "", - "confMenuRenderAtFolder": "", - "confMenuRenderAtPiece": "", - "confMenuRenderNokeys": "", - "confMenuRenderSelect": "", - "confMenuRenderUpdate": "", - "confMenuRenderRemove": "", - "confMenuRenderReset": "", - "confMenuRenderUndo": "", - "confMenuRenderCvalue": "", - "confMenuRenderBack": "", - "confMenuInvalidKey": "", - "confMenuInvalidAction": "", - "confMenuSaved": "" -} \ No newline at end of file diff --git a/src/languages/sv-SE/commands/animal.json b/src/languages/sv-SE/commands/animal.json deleted file mode 100644 index 6d00e57af..000000000 --- a/src/languages/sv-SE/commands/animal.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "bunnyDescription": "", - "bunnyExtended": { - "extendedHelp": "" - }, - "bunnyEmbedData": { - "title": "", - "source": "" - }, - "dogDescription": "", - "dogExtended": { - "extendedHelp": "" - }, - "foxDescription": "", - "foxExtended": { - "extendedHelp": "" - }, - "kittyDescription": "", - "kittyExtended": { - "extendedHelp": "" - }, - "shibeDescription": "", - "shibeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/sv-SE/commands/auto-moderation.json b/src/languages/sv-SE/commands/auto-moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/sv-SE/commands/auto-moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/sv-SE/commands/case.json b/src/languages/sv-SE/commands/case.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/sv-SE/commands/case.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/sv-SE/commands/fun.json b/src/languages/sv-SE/commands/fun.json deleted file mode 100644 index 7892e327d..000000000 --- a/src/languages/sv-SE/commands/fun.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "escaperopeDescription": "", - "escaperopeExtended": { - "extendedHelp": "" - }, - "escaperopeOutput": "" -} \ No newline at end of file diff --git a/src/languages/sv-SE/commands/game.json b/src/languages/sv-SE/commands/game.json deleted file mode 100644 index 8075ca93c..000000000 --- a/src/languages/sv-SE/commands/game.json +++ /dev/null @@ -1,447 +0,0 @@ -{ - "c4Description": "", - "c4Extended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "c4Prompt": "", - "gamesBot": "", - "gamesNoPlayers": "", - "gamesProgress": "", - "gamesPromptDeny": "", - "gamesRepeat": "", - "gamesSelf": "", - "gamesTooManyOrFew": "", - "hgBloodbath": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgDay": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgNight": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hungerGamesDescription": "", - "hungerGamesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "examples": [ - "" - ], - "reminder": "" - }, - "hungerGamesResultDeaths_one": "", - "hungerGamesResultDeaths_other": "", - "hungerGamesResultHeaderBloodbath": "", - "hungerGamesResultHeaderMoon": "", - "hungerGamesResultHeaderSun": "", - "hungerGamesResultProceed": "", - "hungerGamesStop": "", - "hungerGamesWinner": "", - "ticTacToeDescription": "", - "ticTacToeDraw": "", - "ticTacToeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "ticTacToePrompt": "", - "ticTacToeTurn": "", - "ticTacToeWinner": "", - "triviaActiveGame": "", - "triviaDescription": "", - "triviaEmbedTitles": { - "difficulty": "", - "trivia": "" - }, - "triviaExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "triviaIncorrect": "", - "triviaInvalidCategory": "", - "triviaNoAnswer": "", - "triviaWinner": "" -} \ No newline at end of file diff --git a/src/languages/sv-SE/commands/general.json b/src/languages/sv-SE/commands/general.json deleted file mode 100644 index 5e16f992d..000000000 --- a/src/languages/sv-SE/commands/general.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "helpAllFlag": "", - "helpCommandCount_one": "", - "helpCommandCount_other": "", - "helpData": { - "footer": "", - "title": "" - }, - "helpDescription": "", - "helpExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "reminder": "", - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "helpDm": "", - "helpNodm": "", - "v7Description": "", - "v7Extended": { - "extendedHelp": "" - }, - "v7Message": "", - "v7NayreMessage": "" -} \ No newline at end of file diff --git a/src/languages/sv-SE/commands/info.json b/src/languages/sv-SE/commands/info.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/sv-SE/commands/info.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/sv-SE/commands/management.json b/src/languages/sv-SE/commands/management.json deleted file mode 100644 index 21ef26ce2..000000000 --- a/src/languages/sv-SE/commands/management.json +++ /dev/null @@ -1,445 +0,0 @@ -{ - "commandHandlerAborted": "", - "permissionNodesHigher": "", - "permissionNodesCannotAllowEveryone": "", - "permissionNodesInvalidType": "", - "permissionNodesAdd": "", - "permissionNodesNodeNotExists": "", - "permissionNodesCommandNotExists": "", - "permissionNodesRemove": "", - "permissionNodesReset": "", - "permissionNodesShowName": "", - "permissionNodesShowAllow": "", - "permissionNodesShowDeny": "", - "guildInfoTitles": { - "CHANNELS": "", - "MEMBERS": "", - "OTHER": "" - }, - "guildInfoChannels": "", - "guildInfoChannelsAfkChannelText": "", - "guildInfoMembers": "", - "guildInfoOther": "", - "guildInfoBanner": "", - "guildInfoIcon": "", - "guildInfoSplash": "", - "guildInfoDiscoverySplash": "", - "roleInfoTitles": { - "PERMISSIONS": "" - }, - "roleInfoData": "", - "roleInfoAll": "", - "roleInfoNoPermissions": "", - "manageCommandAutoDeleteShowEmpty": "", - "manageCommandAutoDeleteShow": "", - "manageCommandAutoDeleteAdd": "", - "manageCommandAutoDeleteRemove": "", - "manageCommandAutoDeleteRemoveNotset": "", - "manageCommandAutoDeleteReset": "", - "manageCommandChannelShow": "", - "manageCommandChannelShowEmpty": "", - "manageCommandChannelAddAlreadyset": "", - "manageCommandChannelAdd": "", - "manageCommandChannelRemoveNotset": "", - "manageCommandChannelRemove": "", - "manageCommandChannelResetEmpty": "", - "manageCommandChannelReset": "", - "manageReactionRolesShowEmpty": "", - "manageReactionRolesAddChannel": "", - "manageReactionRolesAddPrompt": "", - "manageReactionRolesAddMissing": "", - "manageReactionRolesAdd": "", - "manageReactionRolesRemoveNotExists": "", - "manageReactionRolesRemove": "", - "manageReactionRolesResetEmpty": "", - "manageReactionRolesReset": "", - "configurationEquals": "", - "setIgnoreChannelsSet": "", - "setIgnoreChannelsRemoved": "", - "setImageLogsSet": "", - "setMemberAddLogsSet": "", - "setMemberRemoveLogsSet": "", - "setMessageUpdateLogsSet": "", - "setMessageDeleteLogsSet": "", - "setModLogsSet": "", - "setPrefixSet": "", - "stickyRolesNotExists": "", - "stickyRolesReset": "", - "stickyRolesRemove": "", - "stickyRolesAdd": "", - "stickyRolesShowEmpty": "", - "stickyRolesShowSingle": "", - "createMuteDescription": "", - "createMuteExtended": { - "extendedHelp": "" - }, - "permissionNodesDescription": "", - "permissionNodesExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "managecommandautodeleteDescription": "", - "managecommandautodeleteExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageCommandChannelDescription": "", - "manageCommandChannelExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageReactionRolesDescription": "", - "manageReactionRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "rolesAdded": "", - "rolesAuditlog": "", - "rolesListEmpty": "", - "rolesListTitle": "", - "rolesNotManageable": "", - "rolesNotPublic": "", - "rolesRemoved": "", - "setIgnoreChannelsDescription": "", - "setIgnoreChannelsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setImageLogsDescription": "", - "setImageLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "setMemberAddLogsDescription": "", - "setMemberAddLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMemberRemoveLogsDescription": "", - "setMemberRemoveLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMessageUpdateLogsDescription": "", - "setMessageUpdateLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setMessageDeleteLogsDescription": "", - "setMessageDeleteLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setmodlogsDescription": "", - "setmodlogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setprefixDescription": "", - "setprefixExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "guildInfoDescription": "", - "guildInfoExtended": { - "extendedHelp": "" - }, - "roleInfoDescription": "", - "roleInfoExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "stickyRolesDescription": "", - "stickyRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesDescription": "", - "rolesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/sv-SE/commands/misc.json b/src/languages/sv-SE/commands/misc.json deleted file mode 100644 index 32f64d584..000000000 --- a/src/languages/sv-SE/commands/misc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "snipeEmpty": "", - "snipeTitle": "", - "snipeDescription": "", - "snipeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/sv-SE/commands/moderation.json b/src/languages/sv-SE/commands/moderation.json deleted file mode 100644 index 815d1c788..000000000 --- a/src/languages/sv-SE/commands/moderation.json +++ /dev/null @@ -1,889 +0,0 @@ -{ - "permissions": "", - "permissionsAll": "", - "slowmodeSet": "", - "slowmodeReset": "", - "banNotBannable": "", - "dehoistStarting": "", - "dehoistProgress": "", - "dehoistEmbed": { - "title": "", - "descriptionNoone": "", - "descriptionWithError": "", - "descriptionWithMultipleErrors": "", - "description": "", - "descriptionMultipleMembers": "", - "fieldErrorTitle": "" - }, - "kickNotKickable": "", - "lockdownLock": "", - "lockdownLocking": "", - "lockdownLocked": "", - "lockdownUnlocked": "", - "lockdownOpen": "", - "muteMuted": "", - "muteUserNotMuted": "", - "restrictLowlevel": "", - "pruneAlert_one": "", - "pruneAlert_other": "", - "pruneInvalidPosition": "", - "pruneNoDeletes": "", - "pruneLogHeader": "", - "toggleModerationDmToggledEnabled": "", - "toggleModerationDmToggledDisabled": "", - "moderationOutput_one": "", - "moderationOutput_other": "", - "moderationOutputWithReason_one": "", - "moderationOutputWithReason_other": "", - "moderationFailed_one": "", - "moderationFailed_other": "", - "moderationDmFooter": "", - "moderationDmDescription": "", - "moderationDmDescriptionWithReason": "", - "moderationDmDescriptionWithDuration": "", - "moderationDmDescriptionWithReasonWithDuration": "", - "slowmodeDescription": "", - "slowmodeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "banDescription": "", - "banExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "dehoistDescription": "", - "dehoistExtended": { - "extendedHelp": "", - "reminder": "" - }, - "kickDescription": "", - "kickExtended": { - "usages": [ - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "lockdownDescription": "", - "lockdownExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "muteDescription": "", - "muteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "setNicknameDescription": "", - "setNicknameExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ], - "reminder": "" - }, - "addRoleDescription": "", - "addRoleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "removeroleDescription": "", - "removeroleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "pruneDescription": "", - "pruneExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "permissionsDescription": "", - "permissionsExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ], - "extendedHelp": "" - }, - "restrictAttachmentDescription": "", - "restrictAttachmentExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictEmbedDescription": "", - "restrictEmbedExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictEmojiDescription": "", - "restrictEmojiExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictReactionDescription": "", - "restrictReactionExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictVoiceDescription": "", - "restrictVoiceExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "softBanDescription": "", - "softBanExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "timeoutApplyDescription": "", - "timeoutApplyExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutUndoDescription": "", - "timeoutUndoExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutNotModeratable": "", - "toggleModerationDmDescription": "", - "toggleModerationDmExtended": { - "extendedHelp": "" - }, - "unbanDescription": "", - "unbanExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unmuteDescription": "", - "unmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unrestrictAttachmentDescription": "", - "unrestrictAttachmentExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmbedDescription": "", - "unrestrictEmbedExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmojiDescription": "", - "unrestrictEmojiExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictReactionDescription": "", - "unrestrictReactionExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictVoiceDescription": "", - "unrestrictVoiceExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unwarnDescription": "", - "unwarnExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vmuteDescription": "", - "vmuteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "voiceKickDescription": "", - "voiceKickExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vunmuteDescription": "", - "vunmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "warnDescription": "", - "warnExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/sv-SE/commands/shared.json b/src/languages/sv-SE/commands/shared.json deleted file mode 100644 index ddbb28e7f..000000000 --- a/src/languages/sv-SE/commands/shared.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "deprecatedMessage": "", - "slashOnlyDetailedDescription": { - "extendedHelp": "" - }, - "slashOnlyErrorMessage": "" -} \ No newline at end of file diff --git a/src/languages/sv-SE/commands/system.json b/src/languages/sv-SE/commands/system.json deleted file mode 100644 index e9cfdeec4..000000000 --- a/src/languages/sv-SE/commands/system.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "evalDescription": "", - "evalExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "evalTimeout": "", - "evalError": "", - "dmNotSent": "", - "dmSent": "", - "reboot": "", - "rebootDescription": "", - "rebootExtended": { - "extendedHelp": "", - "reminder": "" - } -} \ No newline at end of file diff --git a/src/languages/sv-SE/commands/tools.json b/src/languages/sv-SE/commands/tools.json deleted file mode 100644 index 01bd03e25..000000000 --- a/src/languages/sv-SE/commands/tools.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "avatarDescription": "", - "avatarExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "" - }, - "avatarNone": "", - "voteDescription": "", - "voteExtended": { - "usages": [ - "" - ], - "examples": [ - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "voteContentNeeded": "", - "voteReactionBlocked": "", - "whoisExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "whoisMemberRoleListAndMore": "" -} \ No newline at end of file diff --git a/src/languages/sv-SE/commands/twitch.json b/src/languages/sv-SE/commands/twitch.json deleted file mode 100644 index 2f12e1b08..000000000 --- a/src/languages/sv-SE/commands/twitch.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "twitchSubscriptionStreamerNotFound": "", - "twitchSubscriptionStatusValues": [ - "", - "" - ], - "twitchSubscriptionInvalidStatus": "", - "twitchSubscriptionAddDuplicated": "", - "twitchSubscriptionAddSuccessOffline": "", - "twitchSubscriptionAddSuccessLive": "", - "twitchSubscriptionAddMessageForOfflineRequired": "", - "twitchSubscriptionRemoveOrResetEmpty": "", - "twitchSubscriptionRemoveStreamerNotSubscribed": "", - "twitchSubscriptionRemoveNotToProvidedChannel": "", - "twitchSubscriptionRemoveStreamerStatusNotMatch": "", - "twitchSubscriptionRemoveSuccessOffline": "", - "twitchSubscriptionRemoveSuccessLive": "", - "twitchSubscriptionResetSuccess_one": "", - "twitchSubscriptionResetSuccess_other": "", - "twitchSubscriptionShowStreamerNotSubscribed": "", - "twitchSubscriptionShowStatus": { - "live": "", - "offline": "" - }, - "twitchSubscriptionShowUnknownUser": "", - "twitchSubscriptionDescription": "", - "twitchSubscriptionExtended": { - "usages": [ - "", - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/sv-SE/commands/whois.json b/src/languages/sv-SE/commands/whois.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/sv-SE/commands/whois.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/sv-SE/errors.json b/src/languages/sv-SE/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/sv-SE/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/sv-SE/events/errors.json b/src/languages/sv-SE/events/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/sv-SE/events/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/sv-SE/events/guilds-logs.json b/src/languages/sv-SE/events/guilds-logs.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/sv-SE/events/guilds-logs.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/sv-SE/events/guilds-members.json b/src/languages/sv-SE/events/guilds-members.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/sv-SE/events/guilds-members.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/sv-SE/events/messages.json b/src/languages/sv-SE/events/messages.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/sv-SE/events/messages.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/sv-SE/events/moderation.json b/src/languages/sv-SE/events/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/sv-SE/events/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/sv-SE/events/noMentionSpam.json b/src/languages/sv-SE/events/noMentionSpam.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/sv-SE/events/noMentionSpam.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/sv-SE/events/reactions.json b/src/languages/sv-SE/events/reactions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/sv-SE/events/reactions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/sv-SE/events/twitch.json b/src/languages/sv-SE/events/twitch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/sv-SE/events/twitch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/sv-SE/fuzzySearch.json b/src/languages/sv-SE/fuzzySearch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/sv-SE/fuzzySearch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/sv-SE/globals.json b/src/languages/sv-SE/globals.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/sv-SE/globals.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/sv-SE/guilds.json b/src/languages/sv-SE/guilds.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/sv-SE/guilds.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/sv-SE/humanLevels.json b/src/languages/sv-SE/humanLevels.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/sv-SE/humanLevels.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/sv-SE/moderation.json b/src/languages/sv-SE/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/sv-SE/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/sv-SE/moderationActions.json b/src/languages/sv-SE/moderationActions.json deleted file mode 100644 index 4c440ae54..000000000 --- a/src/languages/sv-SE/moderationActions.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "actions": { - "addRole": "", - "ban": "", - "kick": "", - "mute": "", - "removeRole": "", - "restrictedAttachment": "", - "restrictedEmbed": "", - "restrictedEmoji": "", - "restrictedReact": "", - "restrictedVoice": "", - "setNickname": "", - "softban": "", - "vkick": "", - "vmute": "", - "warning": "" - }, - "actionCannotManageRoles": "", - "actionRoleNotConfigured": "", - "actionRoleHigherPosition": "", - "actionRoleManaged": "", - "applyNoReason": "", - "applyReason": "", - "requiredMember": "", - "revokeNoReason": "", - "revokeReason": "", - "setNicknameNoReasonRemoved": "", - "setNicknameNoReasonSet": "", - "setNicknameRemoved": "", - "setNicknameSet": "", - "setupMuteExists": "", - "setupTooManyRoles": "", - "sharedRoleSetupAsk": "", - "sharedRoleSetupNoMessage": "", - "sharedRoleSetupExisting": "", - "sharedRoleSetupExistingName": "", - "sharedRoleSetupNew": "", - "softbanNoReason": "", - "softbanReason": "", - "unSoftbanNoReason": "", - "unSoftbanReason": "" -} \ No newline at end of file diff --git a/src/languages/sv-SE/permissions.json b/src/languages/sv-SE/permissions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/sv-SE/permissions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/sv-SE/preconditions.json b/src/languages/sv-SE/preconditions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/sv-SE/preconditions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/sv-SE/selfModeration.json b/src/languages/sv-SE/selfModeration.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/sv-SE/selfModeration.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/sv-SE/serializers.json b/src/languages/sv-SE/serializers.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/sv-SE/serializers.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/sv-SE/settings.json b/src/languages/sv-SE/settings.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/sv-SE/settings.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/sv-SE/system.json b/src/languages/sv-SE/system.json deleted file mode 100644 index 073b9b683..000000000 --- a/src/languages/sv-SE/system.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "discordAbortError": "", - "fetchBansFail": "", - "helpTitles": { - "aliases": "", - "usages": "", - "extendedHelp": "", - "explainedUsage": "", - "possibleFormats": "", - "examples": "", - "reminders": "" - }, - "jumpTo": "", - "loading": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "prefixReminder": "" -} \ No newline at end of file diff --git a/src/languages/th/arguments.json b/src/languages/th/arguments.json deleted file mode 100644 index a7befa6f3..000000000 --- a/src/languages/th/arguments.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "boolean_one": "", - "boolean_other": "", - "booleanError": "", - "booleanDisabled": "", - "booleanEnabled": "", - "booleanFalseOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "booleanTrueOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "caseNoEntries": "", - "caseUnknownEntry": "", - "caseNotInThisGuild": "", - "caseLatestOptions": [ - "", - "" - ], - "categoryChannelError": "", - "channelError": "", - "command": "", - "commandMatch": "", - "dateError": "", - "dateFormats": "", - "dateTooEarly": "", - "dateTooFar": "", - "dmChannelError": "", - "duration": "", - "durationFormats": "", - "emojiError": "", - "floatError": "", - "floatTooLarge": "", - "floatTooSmall": "", - "guildChannelError": "", - "guildChannelMismatchingError": "", - "guildChannelMissingGuildError": "", - "guildPrivateThreadChannelError": "", - "guildPublicThreadChannelError": "", - "guildStageVoiceChannelError": "", - "guildTextChannelError": "", - "guildThreadChannelError": "", - "guildVoiceChannelError": "", - "hyperlinkError": "", - "integerError": "", - "integerTooLarge": "", - "integerTooSmall": "", - "invite": "", - "language": "", - "memberError": "", - "memberMissingGuild": "", - "messageError": "", - "missing": "", - "newsChannel": "", - "numberError": "", - "numberTooLarge": "", - "numberTooSmall": "", - "piece": "", - "rangeInvalid": "", - "rangeMax_other": "", - "rangeMax_one": "", - "resetPossibles": [ - "", - "" - ], - "roleError": "", - "roleMissingGuild": "", - "snowflake": "", - "store": "", - "stringTooLong": "", - "stringTooShort": "", - "time": "", - "timeSpan": "", - "timeSpanTooBig": "", - "timeSpanTooSmall": "", - "tooFewWinners": "", - "tooManyWinners": "", - "unavailable": "", - "userError": "", - "enumEmptyError": "", - "enumError": "" -} \ No newline at end of file diff --git a/src/languages/th/assertions.json b/src/languages/th/assertions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/th/assertions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/th/commands/admin.json b/src/languages/th/commands/admin.json deleted file mode 100644 index 444f39c28..000000000 --- a/src/languages/th/commands/admin.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "confUpdated": "", - "confGetNoExt": "", - "confGet": "", - "confReset": "", - "confNochange": "", - "confServerDescription": "", - "confServerExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "confServer": "", - "confDashboardOnlyKey": "", - "confSettingNotSet": "", - "rolesetDescription": "", - "rolesetExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesetCreated": "", - "rolesetAdded": "", - "rolesetRemoved": "", - "rolesetResetEmpty": "", - "rolesetResetAll": "", - "rolesetResetNotExists": "", - "rolesetResetGroup": "", - "rolesetUpdated": "", - "rolesetNoRolesets": "", - "confMenuRenderAtFolder": "", - "confMenuRenderAtPiece": "", - "confMenuRenderNokeys": "", - "confMenuRenderSelect": "", - "confMenuRenderUpdate": "", - "confMenuRenderRemove": "", - "confMenuRenderReset": "", - "confMenuRenderUndo": "", - "confMenuRenderCvalue": "", - "confMenuRenderBack": "", - "confMenuInvalidKey": "", - "confMenuInvalidAction": "", - "confMenuSaved": "" -} \ No newline at end of file diff --git a/src/languages/th/commands/animal.json b/src/languages/th/commands/animal.json deleted file mode 100644 index 6d00e57af..000000000 --- a/src/languages/th/commands/animal.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "bunnyDescription": "", - "bunnyExtended": { - "extendedHelp": "" - }, - "bunnyEmbedData": { - "title": "", - "source": "" - }, - "dogDescription": "", - "dogExtended": { - "extendedHelp": "" - }, - "foxDescription": "", - "foxExtended": { - "extendedHelp": "" - }, - "kittyDescription": "", - "kittyExtended": { - "extendedHelp": "" - }, - "shibeDescription": "", - "shibeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/th/commands/auto-moderation.json b/src/languages/th/commands/auto-moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/th/commands/auto-moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/th/commands/case.json b/src/languages/th/commands/case.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/th/commands/case.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/th/commands/fun.json b/src/languages/th/commands/fun.json deleted file mode 100644 index 7892e327d..000000000 --- a/src/languages/th/commands/fun.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "escaperopeDescription": "", - "escaperopeExtended": { - "extendedHelp": "" - }, - "escaperopeOutput": "" -} \ No newline at end of file diff --git a/src/languages/th/commands/game.json b/src/languages/th/commands/game.json deleted file mode 100644 index 8075ca93c..000000000 --- a/src/languages/th/commands/game.json +++ /dev/null @@ -1,447 +0,0 @@ -{ - "c4Description": "", - "c4Extended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "c4Prompt": "", - "gamesBot": "", - "gamesNoPlayers": "", - "gamesProgress": "", - "gamesPromptDeny": "", - "gamesRepeat": "", - "gamesSelf": "", - "gamesTooManyOrFew": "", - "hgBloodbath": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgDay": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgNight": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hungerGamesDescription": "", - "hungerGamesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "examples": [ - "" - ], - "reminder": "" - }, - "hungerGamesResultDeaths_one": "", - "hungerGamesResultDeaths_other": "", - "hungerGamesResultHeaderBloodbath": "", - "hungerGamesResultHeaderMoon": "", - "hungerGamesResultHeaderSun": "", - "hungerGamesResultProceed": "", - "hungerGamesStop": "", - "hungerGamesWinner": "", - "ticTacToeDescription": "", - "ticTacToeDraw": "", - "ticTacToeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "ticTacToePrompt": "", - "ticTacToeTurn": "", - "ticTacToeWinner": "", - "triviaActiveGame": "", - "triviaDescription": "", - "triviaEmbedTitles": { - "difficulty": "", - "trivia": "" - }, - "triviaExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "triviaIncorrect": "", - "triviaInvalidCategory": "", - "triviaNoAnswer": "", - "triviaWinner": "" -} \ No newline at end of file diff --git a/src/languages/th/commands/general.json b/src/languages/th/commands/general.json deleted file mode 100644 index 5e16f992d..000000000 --- a/src/languages/th/commands/general.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "helpAllFlag": "", - "helpCommandCount_one": "", - "helpCommandCount_other": "", - "helpData": { - "footer": "", - "title": "" - }, - "helpDescription": "", - "helpExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "reminder": "", - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "helpDm": "", - "helpNodm": "", - "v7Description": "", - "v7Extended": { - "extendedHelp": "" - }, - "v7Message": "", - "v7NayreMessage": "" -} \ No newline at end of file diff --git a/src/languages/th/commands/info.json b/src/languages/th/commands/info.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/th/commands/info.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/th/commands/management.json b/src/languages/th/commands/management.json deleted file mode 100644 index 21ef26ce2..000000000 --- a/src/languages/th/commands/management.json +++ /dev/null @@ -1,445 +0,0 @@ -{ - "commandHandlerAborted": "", - "permissionNodesHigher": "", - "permissionNodesCannotAllowEveryone": "", - "permissionNodesInvalidType": "", - "permissionNodesAdd": "", - "permissionNodesNodeNotExists": "", - "permissionNodesCommandNotExists": "", - "permissionNodesRemove": "", - "permissionNodesReset": "", - "permissionNodesShowName": "", - "permissionNodesShowAllow": "", - "permissionNodesShowDeny": "", - "guildInfoTitles": { - "CHANNELS": "", - "MEMBERS": "", - "OTHER": "" - }, - "guildInfoChannels": "", - "guildInfoChannelsAfkChannelText": "", - "guildInfoMembers": "", - "guildInfoOther": "", - "guildInfoBanner": "", - "guildInfoIcon": "", - "guildInfoSplash": "", - "guildInfoDiscoverySplash": "", - "roleInfoTitles": { - "PERMISSIONS": "" - }, - "roleInfoData": "", - "roleInfoAll": "", - "roleInfoNoPermissions": "", - "manageCommandAutoDeleteShowEmpty": "", - "manageCommandAutoDeleteShow": "", - "manageCommandAutoDeleteAdd": "", - "manageCommandAutoDeleteRemove": "", - "manageCommandAutoDeleteRemoveNotset": "", - "manageCommandAutoDeleteReset": "", - "manageCommandChannelShow": "", - "manageCommandChannelShowEmpty": "", - "manageCommandChannelAddAlreadyset": "", - "manageCommandChannelAdd": "", - "manageCommandChannelRemoveNotset": "", - "manageCommandChannelRemove": "", - "manageCommandChannelResetEmpty": "", - "manageCommandChannelReset": "", - "manageReactionRolesShowEmpty": "", - "manageReactionRolesAddChannel": "", - "manageReactionRolesAddPrompt": "", - "manageReactionRolesAddMissing": "", - "manageReactionRolesAdd": "", - "manageReactionRolesRemoveNotExists": "", - "manageReactionRolesRemove": "", - "manageReactionRolesResetEmpty": "", - "manageReactionRolesReset": "", - "configurationEquals": "", - "setIgnoreChannelsSet": "", - "setIgnoreChannelsRemoved": "", - "setImageLogsSet": "", - "setMemberAddLogsSet": "", - "setMemberRemoveLogsSet": "", - "setMessageUpdateLogsSet": "", - "setMessageDeleteLogsSet": "", - "setModLogsSet": "", - "setPrefixSet": "", - "stickyRolesNotExists": "", - "stickyRolesReset": "", - "stickyRolesRemove": "", - "stickyRolesAdd": "", - "stickyRolesShowEmpty": "", - "stickyRolesShowSingle": "", - "createMuteDescription": "", - "createMuteExtended": { - "extendedHelp": "" - }, - "permissionNodesDescription": "", - "permissionNodesExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "managecommandautodeleteDescription": "", - "managecommandautodeleteExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageCommandChannelDescription": "", - "manageCommandChannelExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageReactionRolesDescription": "", - "manageReactionRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "rolesAdded": "", - "rolesAuditlog": "", - "rolesListEmpty": "", - "rolesListTitle": "", - "rolesNotManageable": "", - "rolesNotPublic": "", - "rolesRemoved": "", - "setIgnoreChannelsDescription": "", - "setIgnoreChannelsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setImageLogsDescription": "", - "setImageLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "setMemberAddLogsDescription": "", - "setMemberAddLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMemberRemoveLogsDescription": "", - "setMemberRemoveLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMessageUpdateLogsDescription": "", - "setMessageUpdateLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setMessageDeleteLogsDescription": "", - "setMessageDeleteLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setmodlogsDescription": "", - "setmodlogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setprefixDescription": "", - "setprefixExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "guildInfoDescription": "", - "guildInfoExtended": { - "extendedHelp": "" - }, - "roleInfoDescription": "", - "roleInfoExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "stickyRolesDescription": "", - "stickyRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesDescription": "", - "rolesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/th/commands/misc.json b/src/languages/th/commands/misc.json deleted file mode 100644 index 32f64d584..000000000 --- a/src/languages/th/commands/misc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "snipeEmpty": "", - "snipeTitle": "", - "snipeDescription": "", - "snipeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/th/commands/moderation.json b/src/languages/th/commands/moderation.json deleted file mode 100644 index 815d1c788..000000000 --- a/src/languages/th/commands/moderation.json +++ /dev/null @@ -1,889 +0,0 @@ -{ - "permissions": "", - "permissionsAll": "", - "slowmodeSet": "", - "slowmodeReset": "", - "banNotBannable": "", - "dehoistStarting": "", - "dehoistProgress": "", - "dehoistEmbed": { - "title": "", - "descriptionNoone": "", - "descriptionWithError": "", - "descriptionWithMultipleErrors": "", - "description": "", - "descriptionMultipleMembers": "", - "fieldErrorTitle": "" - }, - "kickNotKickable": "", - "lockdownLock": "", - "lockdownLocking": "", - "lockdownLocked": "", - "lockdownUnlocked": "", - "lockdownOpen": "", - "muteMuted": "", - "muteUserNotMuted": "", - "restrictLowlevel": "", - "pruneAlert_one": "", - "pruneAlert_other": "", - "pruneInvalidPosition": "", - "pruneNoDeletes": "", - "pruneLogHeader": "", - "toggleModerationDmToggledEnabled": "", - "toggleModerationDmToggledDisabled": "", - "moderationOutput_one": "", - "moderationOutput_other": "", - "moderationOutputWithReason_one": "", - "moderationOutputWithReason_other": "", - "moderationFailed_one": "", - "moderationFailed_other": "", - "moderationDmFooter": "", - "moderationDmDescription": "", - "moderationDmDescriptionWithReason": "", - "moderationDmDescriptionWithDuration": "", - "moderationDmDescriptionWithReasonWithDuration": "", - "slowmodeDescription": "", - "slowmodeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "banDescription": "", - "banExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "dehoistDescription": "", - "dehoistExtended": { - "extendedHelp": "", - "reminder": "" - }, - "kickDescription": "", - "kickExtended": { - "usages": [ - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "lockdownDescription": "", - "lockdownExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "muteDescription": "", - "muteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "setNicknameDescription": "", - "setNicknameExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ], - "reminder": "" - }, - "addRoleDescription": "", - "addRoleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "removeroleDescription": "", - "removeroleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "pruneDescription": "", - "pruneExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "permissionsDescription": "", - "permissionsExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ], - "extendedHelp": "" - }, - "restrictAttachmentDescription": "", - "restrictAttachmentExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictEmbedDescription": "", - "restrictEmbedExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictEmojiDescription": "", - "restrictEmojiExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictReactionDescription": "", - "restrictReactionExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictVoiceDescription": "", - "restrictVoiceExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "softBanDescription": "", - "softBanExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "timeoutApplyDescription": "", - "timeoutApplyExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutUndoDescription": "", - "timeoutUndoExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutNotModeratable": "", - "toggleModerationDmDescription": "", - "toggleModerationDmExtended": { - "extendedHelp": "" - }, - "unbanDescription": "", - "unbanExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unmuteDescription": "", - "unmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unrestrictAttachmentDescription": "", - "unrestrictAttachmentExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmbedDescription": "", - "unrestrictEmbedExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmojiDescription": "", - "unrestrictEmojiExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictReactionDescription": "", - "unrestrictReactionExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictVoiceDescription": "", - "unrestrictVoiceExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unwarnDescription": "", - "unwarnExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vmuteDescription": "", - "vmuteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "voiceKickDescription": "", - "voiceKickExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vunmuteDescription": "", - "vunmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "warnDescription": "", - "warnExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/th/commands/shared.json b/src/languages/th/commands/shared.json deleted file mode 100644 index ddbb28e7f..000000000 --- a/src/languages/th/commands/shared.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "deprecatedMessage": "", - "slashOnlyDetailedDescription": { - "extendedHelp": "" - }, - "slashOnlyErrorMessage": "" -} \ No newline at end of file diff --git a/src/languages/th/commands/system.json b/src/languages/th/commands/system.json deleted file mode 100644 index e9cfdeec4..000000000 --- a/src/languages/th/commands/system.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "evalDescription": "", - "evalExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "evalTimeout": "", - "evalError": "", - "dmNotSent": "", - "dmSent": "", - "reboot": "", - "rebootDescription": "", - "rebootExtended": { - "extendedHelp": "", - "reminder": "" - } -} \ No newline at end of file diff --git a/src/languages/th/commands/tools.json b/src/languages/th/commands/tools.json deleted file mode 100644 index 01bd03e25..000000000 --- a/src/languages/th/commands/tools.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "avatarDescription": "", - "avatarExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "" - }, - "avatarNone": "", - "voteDescription": "", - "voteExtended": { - "usages": [ - "" - ], - "examples": [ - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "voteContentNeeded": "", - "voteReactionBlocked": "", - "whoisExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "whoisMemberRoleListAndMore": "" -} \ No newline at end of file diff --git a/src/languages/th/commands/twitch.json b/src/languages/th/commands/twitch.json deleted file mode 100644 index 2f12e1b08..000000000 --- a/src/languages/th/commands/twitch.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "twitchSubscriptionStreamerNotFound": "", - "twitchSubscriptionStatusValues": [ - "", - "" - ], - "twitchSubscriptionInvalidStatus": "", - "twitchSubscriptionAddDuplicated": "", - "twitchSubscriptionAddSuccessOffline": "", - "twitchSubscriptionAddSuccessLive": "", - "twitchSubscriptionAddMessageForOfflineRequired": "", - "twitchSubscriptionRemoveOrResetEmpty": "", - "twitchSubscriptionRemoveStreamerNotSubscribed": "", - "twitchSubscriptionRemoveNotToProvidedChannel": "", - "twitchSubscriptionRemoveStreamerStatusNotMatch": "", - "twitchSubscriptionRemoveSuccessOffline": "", - "twitchSubscriptionRemoveSuccessLive": "", - "twitchSubscriptionResetSuccess_one": "", - "twitchSubscriptionResetSuccess_other": "", - "twitchSubscriptionShowStreamerNotSubscribed": "", - "twitchSubscriptionShowStatus": { - "live": "", - "offline": "" - }, - "twitchSubscriptionShowUnknownUser": "", - "twitchSubscriptionDescription": "", - "twitchSubscriptionExtended": { - "usages": [ - "", - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/th/commands/whois.json b/src/languages/th/commands/whois.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/th/commands/whois.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/th/errors.json b/src/languages/th/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/th/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/th/events/errors.json b/src/languages/th/events/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/th/events/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/th/events/guilds-logs.json b/src/languages/th/events/guilds-logs.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/th/events/guilds-logs.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/th/events/guilds-members.json b/src/languages/th/events/guilds-members.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/th/events/guilds-members.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/th/events/messages.json b/src/languages/th/events/messages.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/th/events/messages.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/th/events/moderation.json b/src/languages/th/events/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/th/events/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/th/events/noMentionSpam.json b/src/languages/th/events/noMentionSpam.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/th/events/noMentionSpam.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/th/events/reactions.json b/src/languages/th/events/reactions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/th/events/reactions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/th/events/twitch.json b/src/languages/th/events/twitch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/th/events/twitch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/th/fuzzySearch.json b/src/languages/th/fuzzySearch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/th/fuzzySearch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/th/globals.json b/src/languages/th/globals.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/th/globals.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/th/guilds.json b/src/languages/th/guilds.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/th/guilds.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/th/humanLevels.json b/src/languages/th/humanLevels.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/th/humanLevels.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/th/moderation.json b/src/languages/th/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/th/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/th/moderationActions.json b/src/languages/th/moderationActions.json deleted file mode 100644 index 4c440ae54..000000000 --- a/src/languages/th/moderationActions.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "actions": { - "addRole": "", - "ban": "", - "kick": "", - "mute": "", - "removeRole": "", - "restrictedAttachment": "", - "restrictedEmbed": "", - "restrictedEmoji": "", - "restrictedReact": "", - "restrictedVoice": "", - "setNickname": "", - "softban": "", - "vkick": "", - "vmute": "", - "warning": "" - }, - "actionCannotManageRoles": "", - "actionRoleNotConfigured": "", - "actionRoleHigherPosition": "", - "actionRoleManaged": "", - "applyNoReason": "", - "applyReason": "", - "requiredMember": "", - "revokeNoReason": "", - "revokeReason": "", - "setNicknameNoReasonRemoved": "", - "setNicknameNoReasonSet": "", - "setNicknameRemoved": "", - "setNicknameSet": "", - "setupMuteExists": "", - "setupTooManyRoles": "", - "sharedRoleSetupAsk": "", - "sharedRoleSetupNoMessage": "", - "sharedRoleSetupExisting": "", - "sharedRoleSetupExistingName": "", - "sharedRoleSetupNew": "", - "softbanNoReason": "", - "softbanReason": "", - "unSoftbanNoReason": "", - "unSoftbanReason": "" -} \ No newline at end of file diff --git a/src/languages/th/permissions.json b/src/languages/th/permissions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/th/permissions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/th/preconditions.json b/src/languages/th/preconditions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/th/preconditions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/th/selfModeration.json b/src/languages/th/selfModeration.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/th/selfModeration.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/th/serializers.json b/src/languages/th/serializers.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/th/serializers.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/th/settings.json b/src/languages/th/settings.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/th/settings.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/th/system.json b/src/languages/th/system.json deleted file mode 100644 index 073b9b683..000000000 --- a/src/languages/th/system.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "discordAbortError": "", - "fetchBansFail": "", - "helpTitles": { - "aliases": "", - "usages": "", - "extendedHelp": "", - "explainedUsage": "", - "possibleFormats": "", - "examples": "", - "reminders": "" - }, - "jumpTo": "", - "loading": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "prefixReminder": "" -} \ No newline at end of file diff --git a/src/languages/tr/arguments.json b/src/languages/tr/arguments.json deleted file mode 100644 index a7befa6f3..000000000 --- a/src/languages/tr/arguments.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "boolean_one": "", - "boolean_other": "", - "booleanError": "", - "booleanDisabled": "", - "booleanEnabled": "", - "booleanFalseOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "booleanTrueOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "caseNoEntries": "", - "caseUnknownEntry": "", - "caseNotInThisGuild": "", - "caseLatestOptions": [ - "", - "" - ], - "categoryChannelError": "", - "channelError": "", - "command": "", - "commandMatch": "", - "dateError": "", - "dateFormats": "", - "dateTooEarly": "", - "dateTooFar": "", - "dmChannelError": "", - "duration": "", - "durationFormats": "", - "emojiError": "", - "floatError": "", - "floatTooLarge": "", - "floatTooSmall": "", - "guildChannelError": "", - "guildChannelMismatchingError": "", - "guildChannelMissingGuildError": "", - "guildPrivateThreadChannelError": "", - "guildPublicThreadChannelError": "", - "guildStageVoiceChannelError": "", - "guildTextChannelError": "", - "guildThreadChannelError": "", - "guildVoiceChannelError": "", - "hyperlinkError": "", - "integerError": "", - "integerTooLarge": "", - "integerTooSmall": "", - "invite": "", - "language": "", - "memberError": "", - "memberMissingGuild": "", - "messageError": "", - "missing": "", - "newsChannel": "", - "numberError": "", - "numberTooLarge": "", - "numberTooSmall": "", - "piece": "", - "rangeInvalid": "", - "rangeMax_other": "", - "rangeMax_one": "", - "resetPossibles": [ - "", - "" - ], - "roleError": "", - "roleMissingGuild": "", - "snowflake": "", - "store": "", - "stringTooLong": "", - "stringTooShort": "", - "time": "", - "timeSpan": "", - "timeSpanTooBig": "", - "timeSpanTooSmall": "", - "tooFewWinners": "", - "tooManyWinners": "", - "unavailable": "", - "userError": "", - "enumEmptyError": "", - "enumError": "" -} \ No newline at end of file diff --git a/src/languages/tr/assertions.json b/src/languages/tr/assertions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/tr/assertions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/tr/commands/admin.json b/src/languages/tr/commands/admin.json deleted file mode 100644 index e9447a473..000000000 --- a/src/languages/tr/commands/admin.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "confUpdated": "", - "confGetNoExt": "**{{key}}** anahtarı mevcut görünmüyor.", - "confGet": "**{{key}}** anahtarının değeri: `{{value}}`", - "confReset": "**{{key}}** anahtarı şuna sıfırlandı: `{{value}}`", - "confNochange": "**{{key}}** değeri zaten buydu.", - "confServerDescription": "Sunucuların ayarlarını düzenleyin.", - "confServerExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "confServer": "**Sunucu Ayarı {{key}}**\n {{list}}", - "confDashboardOnlyKey": "`{{key}}` yalnızca web kontrol paneli () üzerinden yapılandırılabilir", - "confSettingNotSet": "Ayarlanmamış", - "rolesetDescription": "", - "rolesetExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesetCreated": "", - "rolesetAdded": "", - "rolesetRemoved": "", - "rolesetResetEmpty": "", - "rolesetResetAll": "", - "rolesetResetNotExists": "", - "rolesetResetGroup": "", - "rolesetUpdated": "", - "rolesetNoRolesets": "", - "confMenuRenderAtFolder": "", - "confMenuRenderAtPiece": "", - "confMenuRenderNokeys": "", - "confMenuRenderSelect": "", - "confMenuRenderUpdate": "", - "confMenuRenderRemove": "", - "confMenuRenderReset": "", - "confMenuRenderUndo": "", - "confMenuRenderCvalue": "", - "confMenuRenderBack": "", - "confMenuInvalidKey": "", - "confMenuInvalidAction": "", - "confMenuSaved": "" -} \ No newline at end of file diff --git a/src/languages/tr/commands/animal.json b/src/languages/tr/commands/animal.json deleted file mode 100644 index 6d00e57af..000000000 --- a/src/languages/tr/commands/animal.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "bunnyDescription": "", - "bunnyExtended": { - "extendedHelp": "" - }, - "bunnyEmbedData": { - "title": "", - "source": "" - }, - "dogDescription": "", - "dogExtended": { - "extendedHelp": "" - }, - "foxDescription": "", - "foxExtended": { - "extendedHelp": "" - }, - "kittyDescription": "", - "kittyExtended": { - "extendedHelp": "" - }, - "shibeDescription": "", - "shibeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/tr/commands/auto-moderation.json b/src/languages/tr/commands/auto-moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/tr/commands/auto-moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/tr/commands/case.json b/src/languages/tr/commands/case.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/tr/commands/case.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/tr/commands/fun.json b/src/languages/tr/commands/fun.json deleted file mode 100644 index 7892e327d..000000000 --- a/src/languages/tr/commands/fun.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "escaperopeDescription": "", - "escaperopeExtended": { - "extendedHelp": "" - }, - "escaperopeOutput": "" -} \ No newline at end of file diff --git a/src/languages/tr/commands/game.json b/src/languages/tr/commands/game.json deleted file mode 100644 index 8075ca93c..000000000 --- a/src/languages/tr/commands/game.json +++ /dev/null @@ -1,447 +0,0 @@ -{ - "c4Description": "", - "c4Extended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "c4Prompt": "", - "gamesBot": "", - "gamesNoPlayers": "", - "gamesProgress": "", - "gamesPromptDeny": "", - "gamesRepeat": "", - "gamesSelf": "", - "gamesTooManyOrFew": "", - "hgBloodbath": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgDay": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgNight": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hungerGamesDescription": "", - "hungerGamesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "examples": [ - "" - ], - "reminder": "" - }, - "hungerGamesResultDeaths_one": "", - "hungerGamesResultDeaths_other": "", - "hungerGamesResultHeaderBloodbath": "", - "hungerGamesResultHeaderMoon": "", - "hungerGamesResultHeaderSun": "", - "hungerGamesResultProceed": "", - "hungerGamesStop": "", - "hungerGamesWinner": "", - "ticTacToeDescription": "", - "ticTacToeDraw": "", - "ticTacToeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "ticTacToePrompt": "", - "ticTacToeTurn": "", - "ticTacToeWinner": "", - "triviaActiveGame": "", - "triviaDescription": "", - "triviaEmbedTitles": { - "difficulty": "", - "trivia": "" - }, - "triviaExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "triviaIncorrect": "", - "triviaInvalidCategory": "", - "triviaNoAnswer": "", - "triviaWinner": "" -} \ No newline at end of file diff --git a/src/languages/tr/commands/general.json b/src/languages/tr/commands/general.json deleted file mode 100644 index 5e16f992d..000000000 --- a/src/languages/tr/commands/general.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "helpAllFlag": "", - "helpCommandCount_one": "", - "helpCommandCount_other": "", - "helpData": { - "footer": "", - "title": "" - }, - "helpDescription": "", - "helpExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "reminder": "", - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "helpDm": "", - "helpNodm": "", - "v7Description": "", - "v7Extended": { - "extendedHelp": "" - }, - "v7Message": "", - "v7NayreMessage": "" -} \ No newline at end of file diff --git a/src/languages/tr/commands/info.json b/src/languages/tr/commands/info.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/tr/commands/info.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/tr/commands/management.json b/src/languages/tr/commands/management.json deleted file mode 100644 index 21ef26ce2..000000000 --- a/src/languages/tr/commands/management.json +++ /dev/null @@ -1,445 +0,0 @@ -{ - "commandHandlerAborted": "", - "permissionNodesHigher": "", - "permissionNodesCannotAllowEveryone": "", - "permissionNodesInvalidType": "", - "permissionNodesAdd": "", - "permissionNodesNodeNotExists": "", - "permissionNodesCommandNotExists": "", - "permissionNodesRemove": "", - "permissionNodesReset": "", - "permissionNodesShowName": "", - "permissionNodesShowAllow": "", - "permissionNodesShowDeny": "", - "guildInfoTitles": { - "CHANNELS": "", - "MEMBERS": "", - "OTHER": "" - }, - "guildInfoChannels": "", - "guildInfoChannelsAfkChannelText": "", - "guildInfoMembers": "", - "guildInfoOther": "", - "guildInfoBanner": "", - "guildInfoIcon": "", - "guildInfoSplash": "", - "guildInfoDiscoverySplash": "", - "roleInfoTitles": { - "PERMISSIONS": "" - }, - "roleInfoData": "", - "roleInfoAll": "", - "roleInfoNoPermissions": "", - "manageCommandAutoDeleteShowEmpty": "", - "manageCommandAutoDeleteShow": "", - "manageCommandAutoDeleteAdd": "", - "manageCommandAutoDeleteRemove": "", - "manageCommandAutoDeleteRemoveNotset": "", - "manageCommandAutoDeleteReset": "", - "manageCommandChannelShow": "", - "manageCommandChannelShowEmpty": "", - "manageCommandChannelAddAlreadyset": "", - "manageCommandChannelAdd": "", - "manageCommandChannelRemoveNotset": "", - "manageCommandChannelRemove": "", - "manageCommandChannelResetEmpty": "", - "manageCommandChannelReset": "", - "manageReactionRolesShowEmpty": "", - "manageReactionRolesAddChannel": "", - "manageReactionRolesAddPrompt": "", - "manageReactionRolesAddMissing": "", - "manageReactionRolesAdd": "", - "manageReactionRolesRemoveNotExists": "", - "manageReactionRolesRemove": "", - "manageReactionRolesResetEmpty": "", - "manageReactionRolesReset": "", - "configurationEquals": "", - "setIgnoreChannelsSet": "", - "setIgnoreChannelsRemoved": "", - "setImageLogsSet": "", - "setMemberAddLogsSet": "", - "setMemberRemoveLogsSet": "", - "setMessageUpdateLogsSet": "", - "setMessageDeleteLogsSet": "", - "setModLogsSet": "", - "setPrefixSet": "", - "stickyRolesNotExists": "", - "stickyRolesReset": "", - "stickyRolesRemove": "", - "stickyRolesAdd": "", - "stickyRolesShowEmpty": "", - "stickyRolesShowSingle": "", - "createMuteDescription": "", - "createMuteExtended": { - "extendedHelp": "" - }, - "permissionNodesDescription": "", - "permissionNodesExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "managecommandautodeleteDescription": "", - "managecommandautodeleteExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageCommandChannelDescription": "", - "manageCommandChannelExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageReactionRolesDescription": "", - "manageReactionRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "rolesAdded": "", - "rolesAuditlog": "", - "rolesListEmpty": "", - "rolesListTitle": "", - "rolesNotManageable": "", - "rolesNotPublic": "", - "rolesRemoved": "", - "setIgnoreChannelsDescription": "", - "setIgnoreChannelsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setImageLogsDescription": "", - "setImageLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "setMemberAddLogsDescription": "", - "setMemberAddLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMemberRemoveLogsDescription": "", - "setMemberRemoveLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMessageUpdateLogsDescription": "", - "setMessageUpdateLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setMessageDeleteLogsDescription": "", - "setMessageDeleteLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setmodlogsDescription": "", - "setmodlogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setprefixDescription": "", - "setprefixExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "guildInfoDescription": "", - "guildInfoExtended": { - "extendedHelp": "" - }, - "roleInfoDescription": "", - "roleInfoExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "stickyRolesDescription": "", - "stickyRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesDescription": "", - "rolesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/tr/commands/misc.json b/src/languages/tr/commands/misc.json deleted file mode 100644 index 32f64d584..000000000 --- a/src/languages/tr/commands/misc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "snipeEmpty": "", - "snipeTitle": "", - "snipeDescription": "", - "snipeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/tr/commands/moderation.json b/src/languages/tr/commands/moderation.json deleted file mode 100644 index 815d1c788..000000000 --- a/src/languages/tr/commands/moderation.json +++ /dev/null @@ -1,889 +0,0 @@ -{ - "permissions": "", - "permissionsAll": "", - "slowmodeSet": "", - "slowmodeReset": "", - "banNotBannable": "", - "dehoistStarting": "", - "dehoistProgress": "", - "dehoistEmbed": { - "title": "", - "descriptionNoone": "", - "descriptionWithError": "", - "descriptionWithMultipleErrors": "", - "description": "", - "descriptionMultipleMembers": "", - "fieldErrorTitle": "" - }, - "kickNotKickable": "", - "lockdownLock": "", - "lockdownLocking": "", - "lockdownLocked": "", - "lockdownUnlocked": "", - "lockdownOpen": "", - "muteMuted": "", - "muteUserNotMuted": "", - "restrictLowlevel": "", - "pruneAlert_one": "", - "pruneAlert_other": "", - "pruneInvalidPosition": "", - "pruneNoDeletes": "", - "pruneLogHeader": "", - "toggleModerationDmToggledEnabled": "", - "toggleModerationDmToggledDisabled": "", - "moderationOutput_one": "", - "moderationOutput_other": "", - "moderationOutputWithReason_one": "", - "moderationOutputWithReason_other": "", - "moderationFailed_one": "", - "moderationFailed_other": "", - "moderationDmFooter": "", - "moderationDmDescription": "", - "moderationDmDescriptionWithReason": "", - "moderationDmDescriptionWithDuration": "", - "moderationDmDescriptionWithReasonWithDuration": "", - "slowmodeDescription": "", - "slowmodeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "banDescription": "", - "banExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "dehoistDescription": "", - "dehoistExtended": { - "extendedHelp": "", - "reminder": "" - }, - "kickDescription": "", - "kickExtended": { - "usages": [ - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "lockdownDescription": "", - "lockdownExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "muteDescription": "", - "muteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "setNicknameDescription": "", - "setNicknameExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ], - "reminder": "" - }, - "addRoleDescription": "", - "addRoleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "removeroleDescription": "", - "removeroleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "pruneDescription": "", - "pruneExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "permissionsDescription": "", - "permissionsExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ], - "extendedHelp": "" - }, - "restrictAttachmentDescription": "", - "restrictAttachmentExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictEmbedDescription": "", - "restrictEmbedExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictEmojiDescription": "", - "restrictEmojiExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictReactionDescription": "", - "restrictReactionExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictVoiceDescription": "", - "restrictVoiceExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "softBanDescription": "", - "softBanExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "timeoutApplyDescription": "", - "timeoutApplyExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutUndoDescription": "", - "timeoutUndoExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutNotModeratable": "", - "toggleModerationDmDescription": "", - "toggleModerationDmExtended": { - "extendedHelp": "" - }, - "unbanDescription": "", - "unbanExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unmuteDescription": "", - "unmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unrestrictAttachmentDescription": "", - "unrestrictAttachmentExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmbedDescription": "", - "unrestrictEmbedExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmojiDescription": "", - "unrestrictEmojiExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictReactionDescription": "", - "unrestrictReactionExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictVoiceDescription": "", - "unrestrictVoiceExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unwarnDescription": "", - "unwarnExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vmuteDescription": "", - "vmuteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "voiceKickDescription": "", - "voiceKickExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vunmuteDescription": "", - "vunmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "warnDescription": "", - "warnExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/tr/commands/shared.json b/src/languages/tr/commands/shared.json deleted file mode 100644 index ddbb28e7f..000000000 --- a/src/languages/tr/commands/shared.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "deprecatedMessage": "", - "slashOnlyDetailedDescription": { - "extendedHelp": "" - }, - "slashOnlyErrorMessage": "" -} \ No newline at end of file diff --git a/src/languages/tr/commands/system.json b/src/languages/tr/commands/system.json deleted file mode 100644 index e9cfdeec4..000000000 --- a/src/languages/tr/commands/system.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "evalDescription": "", - "evalExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "evalTimeout": "", - "evalError": "", - "dmNotSent": "", - "dmSent": "", - "reboot": "", - "rebootDescription": "", - "rebootExtended": { - "extendedHelp": "", - "reminder": "" - } -} \ No newline at end of file diff --git a/src/languages/tr/commands/tools.json b/src/languages/tr/commands/tools.json deleted file mode 100644 index 01bd03e25..000000000 --- a/src/languages/tr/commands/tools.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "avatarDescription": "", - "avatarExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "" - }, - "avatarNone": "", - "voteDescription": "", - "voteExtended": { - "usages": [ - "" - ], - "examples": [ - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "voteContentNeeded": "", - "voteReactionBlocked": "", - "whoisExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "whoisMemberRoleListAndMore": "" -} \ No newline at end of file diff --git a/src/languages/tr/commands/twitch.json b/src/languages/tr/commands/twitch.json deleted file mode 100644 index 2f12e1b08..000000000 --- a/src/languages/tr/commands/twitch.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "twitchSubscriptionStreamerNotFound": "", - "twitchSubscriptionStatusValues": [ - "", - "" - ], - "twitchSubscriptionInvalidStatus": "", - "twitchSubscriptionAddDuplicated": "", - "twitchSubscriptionAddSuccessOffline": "", - "twitchSubscriptionAddSuccessLive": "", - "twitchSubscriptionAddMessageForOfflineRequired": "", - "twitchSubscriptionRemoveOrResetEmpty": "", - "twitchSubscriptionRemoveStreamerNotSubscribed": "", - "twitchSubscriptionRemoveNotToProvidedChannel": "", - "twitchSubscriptionRemoveStreamerStatusNotMatch": "", - "twitchSubscriptionRemoveSuccessOffline": "", - "twitchSubscriptionRemoveSuccessLive": "", - "twitchSubscriptionResetSuccess_one": "", - "twitchSubscriptionResetSuccess_other": "", - "twitchSubscriptionShowStreamerNotSubscribed": "", - "twitchSubscriptionShowStatus": { - "live": "", - "offline": "" - }, - "twitchSubscriptionShowUnknownUser": "", - "twitchSubscriptionDescription": "", - "twitchSubscriptionExtended": { - "usages": [ - "", - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/tr/commands/whois.json b/src/languages/tr/commands/whois.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/tr/commands/whois.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/tr/errors.json b/src/languages/tr/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/tr/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/tr/events/errors.json b/src/languages/tr/events/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/tr/events/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/tr/events/guilds-logs.json b/src/languages/tr/events/guilds-logs.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/tr/events/guilds-logs.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/tr/events/guilds-members.json b/src/languages/tr/events/guilds-members.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/tr/events/guilds-members.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/tr/events/messages.json b/src/languages/tr/events/messages.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/tr/events/messages.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/tr/events/moderation.json b/src/languages/tr/events/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/tr/events/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/tr/events/noMentionSpam.json b/src/languages/tr/events/noMentionSpam.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/tr/events/noMentionSpam.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/tr/events/reactions.json b/src/languages/tr/events/reactions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/tr/events/reactions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/tr/events/twitch.json b/src/languages/tr/events/twitch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/tr/events/twitch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/tr/fuzzySearch.json b/src/languages/tr/fuzzySearch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/tr/fuzzySearch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/tr/globals.json b/src/languages/tr/globals.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/tr/globals.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/tr/guilds.json b/src/languages/tr/guilds.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/tr/guilds.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/tr/humanLevels.json b/src/languages/tr/humanLevels.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/tr/humanLevels.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/tr/moderation.json b/src/languages/tr/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/tr/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/tr/moderationActions.json b/src/languages/tr/moderationActions.json deleted file mode 100644 index 4c440ae54..000000000 --- a/src/languages/tr/moderationActions.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "actions": { - "addRole": "", - "ban": "", - "kick": "", - "mute": "", - "removeRole": "", - "restrictedAttachment": "", - "restrictedEmbed": "", - "restrictedEmoji": "", - "restrictedReact": "", - "restrictedVoice": "", - "setNickname": "", - "softban": "", - "vkick": "", - "vmute": "", - "warning": "" - }, - "actionCannotManageRoles": "", - "actionRoleNotConfigured": "", - "actionRoleHigherPosition": "", - "actionRoleManaged": "", - "applyNoReason": "", - "applyReason": "", - "requiredMember": "", - "revokeNoReason": "", - "revokeReason": "", - "setNicknameNoReasonRemoved": "", - "setNicknameNoReasonSet": "", - "setNicknameRemoved": "", - "setNicknameSet": "", - "setupMuteExists": "", - "setupTooManyRoles": "", - "sharedRoleSetupAsk": "", - "sharedRoleSetupNoMessage": "", - "sharedRoleSetupExisting": "", - "sharedRoleSetupExistingName": "", - "sharedRoleSetupNew": "", - "softbanNoReason": "", - "softbanReason": "", - "unSoftbanNoReason": "", - "unSoftbanReason": "" -} \ No newline at end of file diff --git a/src/languages/tr/permissions.json b/src/languages/tr/permissions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/tr/permissions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/tr/preconditions.json b/src/languages/tr/preconditions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/tr/preconditions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/tr/selfModeration.json b/src/languages/tr/selfModeration.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/tr/selfModeration.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/tr/serializers.json b/src/languages/tr/serializers.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/tr/serializers.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/tr/settings.json b/src/languages/tr/settings.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/tr/settings.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/tr/system.json b/src/languages/tr/system.json deleted file mode 100644 index 073b9b683..000000000 --- a/src/languages/tr/system.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "discordAbortError": "", - "fetchBansFail": "", - "helpTitles": { - "aliases": "", - "usages": "", - "extendedHelp": "", - "explainedUsage": "", - "possibleFormats": "", - "examples": "", - "reminders": "" - }, - "jumpTo": "", - "loading": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "prefixReminder": "" -} \ No newline at end of file diff --git a/src/languages/uk/arguments.json b/src/languages/uk/arguments.json deleted file mode 100644 index a7befa6f3..000000000 --- a/src/languages/uk/arguments.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "boolean_one": "", - "boolean_other": "", - "booleanError": "", - "booleanDisabled": "", - "booleanEnabled": "", - "booleanFalseOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "booleanTrueOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "caseNoEntries": "", - "caseUnknownEntry": "", - "caseNotInThisGuild": "", - "caseLatestOptions": [ - "", - "" - ], - "categoryChannelError": "", - "channelError": "", - "command": "", - "commandMatch": "", - "dateError": "", - "dateFormats": "", - "dateTooEarly": "", - "dateTooFar": "", - "dmChannelError": "", - "duration": "", - "durationFormats": "", - "emojiError": "", - "floatError": "", - "floatTooLarge": "", - "floatTooSmall": "", - "guildChannelError": "", - "guildChannelMismatchingError": "", - "guildChannelMissingGuildError": "", - "guildPrivateThreadChannelError": "", - "guildPublicThreadChannelError": "", - "guildStageVoiceChannelError": "", - "guildTextChannelError": "", - "guildThreadChannelError": "", - "guildVoiceChannelError": "", - "hyperlinkError": "", - "integerError": "", - "integerTooLarge": "", - "integerTooSmall": "", - "invite": "", - "language": "", - "memberError": "", - "memberMissingGuild": "", - "messageError": "", - "missing": "", - "newsChannel": "", - "numberError": "", - "numberTooLarge": "", - "numberTooSmall": "", - "piece": "", - "rangeInvalid": "", - "rangeMax_other": "", - "rangeMax_one": "", - "resetPossibles": [ - "", - "" - ], - "roleError": "", - "roleMissingGuild": "", - "snowflake": "", - "store": "", - "stringTooLong": "", - "stringTooShort": "", - "time": "", - "timeSpan": "", - "timeSpanTooBig": "", - "timeSpanTooSmall": "", - "tooFewWinners": "", - "tooManyWinners": "", - "unavailable": "", - "userError": "", - "enumEmptyError": "", - "enumError": "" -} \ No newline at end of file diff --git a/src/languages/uk/assertions.json b/src/languages/uk/assertions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/uk/assertions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/uk/commands/admin.json b/src/languages/uk/commands/admin.json deleted file mode 100644 index 444f39c28..000000000 --- a/src/languages/uk/commands/admin.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "confUpdated": "", - "confGetNoExt": "", - "confGet": "", - "confReset": "", - "confNochange": "", - "confServerDescription": "", - "confServerExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "confServer": "", - "confDashboardOnlyKey": "", - "confSettingNotSet": "", - "rolesetDescription": "", - "rolesetExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesetCreated": "", - "rolesetAdded": "", - "rolesetRemoved": "", - "rolesetResetEmpty": "", - "rolesetResetAll": "", - "rolesetResetNotExists": "", - "rolesetResetGroup": "", - "rolesetUpdated": "", - "rolesetNoRolesets": "", - "confMenuRenderAtFolder": "", - "confMenuRenderAtPiece": "", - "confMenuRenderNokeys": "", - "confMenuRenderSelect": "", - "confMenuRenderUpdate": "", - "confMenuRenderRemove": "", - "confMenuRenderReset": "", - "confMenuRenderUndo": "", - "confMenuRenderCvalue": "", - "confMenuRenderBack": "", - "confMenuInvalidKey": "", - "confMenuInvalidAction": "", - "confMenuSaved": "" -} \ No newline at end of file diff --git a/src/languages/uk/commands/animal.json b/src/languages/uk/commands/animal.json deleted file mode 100644 index 6d00e57af..000000000 --- a/src/languages/uk/commands/animal.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "bunnyDescription": "", - "bunnyExtended": { - "extendedHelp": "" - }, - "bunnyEmbedData": { - "title": "", - "source": "" - }, - "dogDescription": "", - "dogExtended": { - "extendedHelp": "" - }, - "foxDescription": "", - "foxExtended": { - "extendedHelp": "" - }, - "kittyDescription": "", - "kittyExtended": { - "extendedHelp": "" - }, - "shibeDescription": "", - "shibeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/uk/commands/auto-moderation.json b/src/languages/uk/commands/auto-moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/uk/commands/auto-moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/uk/commands/case.json b/src/languages/uk/commands/case.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/uk/commands/case.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/uk/commands/fun.json b/src/languages/uk/commands/fun.json deleted file mode 100644 index 7892e327d..000000000 --- a/src/languages/uk/commands/fun.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "escaperopeDescription": "", - "escaperopeExtended": { - "extendedHelp": "" - }, - "escaperopeOutput": "" -} \ No newline at end of file diff --git a/src/languages/uk/commands/game.json b/src/languages/uk/commands/game.json deleted file mode 100644 index 8075ca93c..000000000 --- a/src/languages/uk/commands/game.json +++ /dev/null @@ -1,447 +0,0 @@ -{ - "c4Description": "", - "c4Extended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "c4Prompt": "", - "gamesBot": "", - "gamesNoPlayers": "", - "gamesProgress": "", - "gamesPromptDeny": "", - "gamesRepeat": "", - "gamesSelf": "", - "gamesTooManyOrFew": "", - "hgBloodbath": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgDay": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgNight": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hungerGamesDescription": "", - "hungerGamesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "examples": [ - "" - ], - "reminder": "" - }, - "hungerGamesResultDeaths_one": "", - "hungerGamesResultDeaths_other": "", - "hungerGamesResultHeaderBloodbath": "", - "hungerGamesResultHeaderMoon": "", - "hungerGamesResultHeaderSun": "", - "hungerGamesResultProceed": "", - "hungerGamesStop": "", - "hungerGamesWinner": "", - "ticTacToeDescription": "", - "ticTacToeDraw": "", - "ticTacToeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "ticTacToePrompt": "", - "ticTacToeTurn": "", - "ticTacToeWinner": "", - "triviaActiveGame": "", - "triviaDescription": "", - "triviaEmbedTitles": { - "difficulty": "", - "trivia": "" - }, - "triviaExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "triviaIncorrect": "", - "triviaInvalidCategory": "", - "triviaNoAnswer": "", - "triviaWinner": "" -} \ No newline at end of file diff --git a/src/languages/uk/commands/general.json b/src/languages/uk/commands/general.json deleted file mode 100644 index 5e16f992d..000000000 --- a/src/languages/uk/commands/general.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "helpAllFlag": "", - "helpCommandCount_one": "", - "helpCommandCount_other": "", - "helpData": { - "footer": "", - "title": "" - }, - "helpDescription": "", - "helpExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "reminder": "", - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "helpDm": "", - "helpNodm": "", - "v7Description": "", - "v7Extended": { - "extendedHelp": "" - }, - "v7Message": "", - "v7NayreMessage": "" -} \ No newline at end of file diff --git a/src/languages/uk/commands/info.json b/src/languages/uk/commands/info.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/uk/commands/info.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/uk/commands/management.json b/src/languages/uk/commands/management.json deleted file mode 100644 index 21ef26ce2..000000000 --- a/src/languages/uk/commands/management.json +++ /dev/null @@ -1,445 +0,0 @@ -{ - "commandHandlerAborted": "", - "permissionNodesHigher": "", - "permissionNodesCannotAllowEveryone": "", - "permissionNodesInvalidType": "", - "permissionNodesAdd": "", - "permissionNodesNodeNotExists": "", - "permissionNodesCommandNotExists": "", - "permissionNodesRemove": "", - "permissionNodesReset": "", - "permissionNodesShowName": "", - "permissionNodesShowAllow": "", - "permissionNodesShowDeny": "", - "guildInfoTitles": { - "CHANNELS": "", - "MEMBERS": "", - "OTHER": "" - }, - "guildInfoChannels": "", - "guildInfoChannelsAfkChannelText": "", - "guildInfoMembers": "", - "guildInfoOther": "", - "guildInfoBanner": "", - "guildInfoIcon": "", - "guildInfoSplash": "", - "guildInfoDiscoverySplash": "", - "roleInfoTitles": { - "PERMISSIONS": "" - }, - "roleInfoData": "", - "roleInfoAll": "", - "roleInfoNoPermissions": "", - "manageCommandAutoDeleteShowEmpty": "", - "manageCommandAutoDeleteShow": "", - "manageCommandAutoDeleteAdd": "", - "manageCommandAutoDeleteRemove": "", - "manageCommandAutoDeleteRemoveNotset": "", - "manageCommandAutoDeleteReset": "", - "manageCommandChannelShow": "", - "manageCommandChannelShowEmpty": "", - "manageCommandChannelAddAlreadyset": "", - "manageCommandChannelAdd": "", - "manageCommandChannelRemoveNotset": "", - "manageCommandChannelRemove": "", - "manageCommandChannelResetEmpty": "", - "manageCommandChannelReset": "", - "manageReactionRolesShowEmpty": "", - "manageReactionRolesAddChannel": "", - "manageReactionRolesAddPrompt": "", - "manageReactionRolesAddMissing": "", - "manageReactionRolesAdd": "", - "manageReactionRolesRemoveNotExists": "", - "manageReactionRolesRemove": "", - "manageReactionRolesResetEmpty": "", - "manageReactionRolesReset": "", - "configurationEquals": "", - "setIgnoreChannelsSet": "", - "setIgnoreChannelsRemoved": "", - "setImageLogsSet": "", - "setMemberAddLogsSet": "", - "setMemberRemoveLogsSet": "", - "setMessageUpdateLogsSet": "", - "setMessageDeleteLogsSet": "", - "setModLogsSet": "", - "setPrefixSet": "", - "stickyRolesNotExists": "", - "stickyRolesReset": "", - "stickyRolesRemove": "", - "stickyRolesAdd": "", - "stickyRolesShowEmpty": "", - "stickyRolesShowSingle": "", - "createMuteDescription": "", - "createMuteExtended": { - "extendedHelp": "" - }, - "permissionNodesDescription": "", - "permissionNodesExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "managecommandautodeleteDescription": "", - "managecommandautodeleteExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageCommandChannelDescription": "", - "manageCommandChannelExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageReactionRolesDescription": "", - "manageReactionRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "rolesAdded": "", - "rolesAuditlog": "", - "rolesListEmpty": "", - "rolesListTitle": "", - "rolesNotManageable": "", - "rolesNotPublic": "", - "rolesRemoved": "", - "setIgnoreChannelsDescription": "", - "setIgnoreChannelsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setImageLogsDescription": "", - "setImageLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "setMemberAddLogsDescription": "", - "setMemberAddLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMemberRemoveLogsDescription": "", - "setMemberRemoveLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMessageUpdateLogsDescription": "", - "setMessageUpdateLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setMessageDeleteLogsDescription": "", - "setMessageDeleteLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setmodlogsDescription": "", - "setmodlogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setprefixDescription": "", - "setprefixExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "guildInfoDescription": "", - "guildInfoExtended": { - "extendedHelp": "" - }, - "roleInfoDescription": "", - "roleInfoExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "stickyRolesDescription": "", - "stickyRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesDescription": "", - "rolesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/uk/commands/misc.json b/src/languages/uk/commands/misc.json deleted file mode 100644 index 32f64d584..000000000 --- a/src/languages/uk/commands/misc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "snipeEmpty": "", - "snipeTitle": "", - "snipeDescription": "", - "snipeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/uk/commands/moderation.json b/src/languages/uk/commands/moderation.json deleted file mode 100644 index 815d1c788..000000000 --- a/src/languages/uk/commands/moderation.json +++ /dev/null @@ -1,889 +0,0 @@ -{ - "permissions": "", - "permissionsAll": "", - "slowmodeSet": "", - "slowmodeReset": "", - "banNotBannable": "", - "dehoistStarting": "", - "dehoistProgress": "", - "dehoistEmbed": { - "title": "", - "descriptionNoone": "", - "descriptionWithError": "", - "descriptionWithMultipleErrors": "", - "description": "", - "descriptionMultipleMembers": "", - "fieldErrorTitle": "" - }, - "kickNotKickable": "", - "lockdownLock": "", - "lockdownLocking": "", - "lockdownLocked": "", - "lockdownUnlocked": "", - "lockdownOpen": "", - "muteMuted": "", - "muteUserNotMuted": "", - "restrictLowlevel": "", - "pruneAlert_one": "", - "pruneAlert_other": "", - "pruneInvalidPosition": "", - "pruneNoDeletes": "", - "pruneLogHeader": "", - "toggleModerationDmToggledEnabled": "", - "toggleModerationDmToggledDisabled": "", - "moderationOutput_one": "", - "moderationOutput_other": "", - "moderationOutputWithReason_one": "", - "moderationOutputWithReason_other": "", - "moderationFailed_one": "", - "moderationFailed_other": "", - "moderationDmFooter": "", - "moderationDmDescription": "", - "moderationDmDescriptionWithReason": "", - "moderationDmDescriptionWithDuration": "", - "moderationDmDescriptionWithReasonWithDuration": "", - "slowmodeDescription": "", - "slowmodeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "banDescription": "", - "banExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "dehoistDescription": "", - "dehoistExtended": { - "extendedHelp": "", - "reminder": "" - }, - "kickDescription": "", - "kickExtended": { - "usages": [ - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "lockdownDescription": "", - "lockdownExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "muteDescription": "", - "muteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "setNicknameDescription": "", - "setNicknameExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ], - "reminder": "" - }, - "addRoleDescription": "", - "addRoleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "removeroleDescription": "", - "removeroleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "pruneDescription": "", - "pruneExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "permissionsDescription": "", - "permissionsExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ], - "extendedHelp": "" - }, - "restrictAttachmentDescription": "", - "restrictAttachmentExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictEmbedDescription": "", - "restrictEmbedExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictEmojiDescription": "", - "restrictEmojiExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictReactionDescription": "", - "restrictReactionExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictVoiceDescription": "", - "restrictVoiceExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "softBanDescription": "", - "softBanExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "timeoutApplyDescription": "", - "timeoutApplyExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutUndoDescription": "", - "timeoutUndoExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutNotModeratable": "", - "toggleModerationDmDescription": "", - "toggleModerationDmExtended": { - "extendedHelp": "" - }, - "unbanDescription": "", - "unbanExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unmuteDescription": "", - "unmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unrestrictAttachmentDescription": "", - "unrestrictAttachmentExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmbedDescription": "", - "unrestrictEmbedExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmojiDescription": "", - "unrestrictEmojiExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictReactionDescription": "", - "unrestrictReactionExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictVoiceDescription": "", - "unrestrictVoiceExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unwarnDescription": "", - "unwarnExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vmuteDescription": "", - "vmuteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "voiceKickDescription": "", - "voiceKickExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vunmuteDescription": "", - "vunmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "warnDescription": "", - "warnExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/uk/commands/shared.json b/src/languages/uk/commands/shared.json deleted file mode 100644 index ddbb28e7f..000000000 --- a/src/languages/uk/commands/shared.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "deprecatedMessage": "", - "slashOnlyDetailedDescription": { - "extendedHelp": "" - }, - "slashOnlyErrorMessage": "" -} \ No newline at end of file diff --git a/src/languages/uk/commands/system.json b/src/languages/uk/commands/system.json deleted file mode 100644 index e9cfdeec4..000000000 --- a/src/languages/uk/commands/system.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "evalDescription": "", - "evalExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "evalTimeout": "", - "evalError": "", - "dmNotSent": "", - "dmSent": "", - "reboot": "", - "rebootDescription": "", - "rebootExtended": { - "extendedHelp": "", - "reminder": "" - } -} \ No newline at end of file diff --git a/src/languages/uk/commands/tools.json b/src/languages/uk/commands/tools.json deleted file mode 100644 index 01bd03e25..000000000 --- a/src/languages/uk/commands/tools.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "avatarDescription": "", - "avatarExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "" - }, - "avatarNone": "", - "voteDescription": "", - "voteExtended": { - "usages": [ - "" - ], - "examples": [ - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "voteContentNeeded": "", - "voteReactionBlocked": "", - "whoisExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "whoisMemberRoleListAndMore": "" -} \ No newline at end of file diff --git a/src/languages/uk/commands/twitch.json b/src/languages/uk/commands/twitch.json deleted file mode 100644 index 2f12e1b08..000000000 --- a/src/languages/uk/commands/twitch.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "twitchSubscriptionStreamerNotFound": "", - "twitchSubscriptionStatusValues": [ - "", - "" - ], - "twitchSubscriptionInvalidStatus": "", - "twitchSubscriptionAddDuplicated": "", - "twitchSubscriptionAddSuccessOffline": "", - "twitchSubscriptionAddSuccessLive": "", - "twitchSubscriptionAddMessageForOfflineRequired": "", - "twitchSubscriptionRemoveOrResetEmpty": "", - "twitchSubscriptionRemoveStreamerNotSubscribed": "", - "twitchSubscriptionRemoveNotToProvidedChannel": "", - "twitchSubscriptionRemoveStreamerStatusNotMatch": "", - "twitchSubscriptionRemoveSuccessOffline": "", - "twitchSubscriptionRemoveSuccessLive": "", - "twitchSubscriptionResetSuccess_one": "", - "twitchSubscriptionResetSuccess_other": "", - "twitchSubscriptionShowStreamerNotSubscribed": "", - "twitchSubscriptionShowStatus": { - "live": "", - "offline": "" - }, - "twitchSubscriptionShowUnknownUser": "", - "twitchSubscriptionDescription": "", - "twitchSubscriptionExtended": { - "usages": [ - "", - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/uk/commands/whois.json b/src/languages/uk/commands/whois.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/uk/commands/whois.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/uk/errors.json b/src/languages/uk/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/uk/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/uk/events/errors.json b/src/languages/uk/events/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/uk/events/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/uk/events/guilds-logs.json b/src/languages/uk/events/guilds-logs.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/uk/events/guilds-logs.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/uk/events/guilds-members.json b/src/languages/uk/events/guilds-members.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/uk/events/guilds-members.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/uk/events/messages.json b/src/languages/uk/events/messages.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/uk/events/messages.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/uk/events/moderation.json b/src/languages/uk/events/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/uk/events/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/uk/events/noMentionSpam.json b/src/languages/uk/events/noMentionSpam.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/uk/events/noMentionSpam.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/uk/events/reactions.json b/src/languages/uk/events/reactions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/uk/events/reactions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/uk/events/twitch.json b/src/languages/uk/events/twitch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/uk/events/twitch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/uk/fuzzySearch.json b/src/languages/uk/fuzzySearch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/uk/fuzzySearch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/uk/globals.json b/src/languages/uk/globals.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/uk/globals.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/uk/guilds.json b/src/languages/uk/guilds.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/uk/guilds.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/uk/humanLevels.json b/src/languages/uk/humanLevels.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/uk/humanLevels.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/uk/moderation.json b/src/languages/uk/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/uk/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/uk/moderationActions.json b/src/languages/uk/moderationActions.json deleted file mode 100644 index 4c440ae54..000000000 --- a/src/languages/uk/moderationActions.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "actions": { - "addRole": "", - "ban": "", - "kick": "", - "mute": "", - "removeRole": "", - "restrictedAttachment": "", - "restrictedEmbed": "", - "restrictedEmoji": "", - "restrictedReact": "", - "restrictedVoice": "", - "setNickname": "", - "softban": "", - "vkick": "", - "vmute": "", - "warning": "" - }, - "actionCannotManageRoles": "", - "actionRoleNotConfigured": "", - "actionRoleHigherPosition": "", - "actionRoleManaged": "", - "applyNoReason": "", - "applyReason": "", - "requiredMember": "", - "revokeNoReason": "", - "revokeReason": "", - "setNicknameNoReasonRemoved": "", - "setNicknameNoReasonSet": "", - "setNicknameRemoved": "", - "setNicknameSet": "", - "setupMuteExists": "", - "setupTooManyRoles": "", - "sharedRoleSetupAsk": "", - "sharedRoleSetupNoMessage": "", - "sharedRoleSetupExisting": "", - "sharedRoleSetupExistingName": "", - "sharedRoleSetupNew": "", - "softbanNoReason": "", - "softbanReason": "", - "unSoftbanNoReason": "", - "unSoftbanReason": "" -} \ No newline at end of file diff --git a/src/languages/uk/permissions.json b/src/languages/uk/permissions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/uk/permissions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/uk/preconditions.json b/src/languages/uk/preconditions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/uk/preconditions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/uk/selfModeration.json b/src/languages/uk/selfModeration.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/uk/selfModeration.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/uk/serializers.json b/src/languages/uk/serializers.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/uk/serializers.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/uk/settings.json b/src/languages/uk/settings.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/uk/settings.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/uk/system.json b/src/languages/uk/system.json deleted file mode 100644 index 073b9b683..000000000 --- a/src/languages/uk/system.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "discordAbortError": "", - "fetchBansFail": "", - "helpTitles": { - "aliases": "", - "usages": "", - "extendedHelp": "", - "explainedUsage": "", - "possibleFormats": "", - "examples": "", - "reminders": "" - }, - "jumpTo": "", - "loading": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "prefixReminder": "" -} \ No newline at end of file diff --git a/src/languages/vi/arguments.json b/src/languages/vi/arguments.json deleted file mode 100644 index a7befa6f3..000000000 --- a/src/languages/vi/arguments.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "boolean_one": "", - "boolean_other": "", - "booleanError": "", - "booleanDisabled": "", - "booleanEnabled": "", - "booleanFalseOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "booleanTrueOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "caseNoEntries": "", - "caseUnknownEntry": "", - "caseNotInThisGuild": "", - "caseLatestOptions": [ - "", - "" - ], - "categoryChannelError": "", - "channelError": "", - "command": "", - "commandMatch": "", - "dateError": "", - "dateFormats": "", - "dateTooEarly": "", - "dateTooFar": "", - "dmChannelError": "", - "duration": "", - "durationFormats": "", - "emojiError": "", - "floatError": "", - "floatTooLarge": "", - "floatTooSmall": "", - "guildChannelError": "", - "guildChannelMismatchingError": "", - "guildChannelMissingGuildError": "", - "guildPrivateThreadChannelError": "", - "guildPublicThreadChannelError": "", - "guildStageVoiceChannelError": "", - "guildTextChannelError": "", - "guildThreadChannelError": "", - "guildVoiceChannelError": "", - "hyperlinkError": "", - "integerError": "", - "integerTooLarge": "", - "integerTooSmall": "", - "invite": "", - "language": "", - "memberError": "", - "memberMissingGuild": "", - "messageError": "", - "missing": "", - "newsChannel": "", - "numberError": "", - "numberTooLarge": "", - "numberTooSmall": "", - "piece": "", - "rangeInvalid": "", - "rangeMax_other": "", - "rangeMax_one": "", - "resetPossibles": [ - "", - "" - ], - "roleError": "", - "roleMissingGuild": "", - "snowflake": "", - "store": "", - "stringTooLong": "", - "stringTooShort": "", - "time": "", - "timeSpan": "", - "timeSpanTooBig": "", - "timeSpanTooSmall": "", - "tooFewWinners": "", - "tooManyWinners": "", - "unavailable": "", - "userError": "", - "enumEmptyError": "", - "enumError": "" -} \ No newline at end of file diff --git a/src/languages/vi/assertions.json b/src/languages/vi/assertions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/vi/assertions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/vi/commands/admin.json b/src/languages/vi/commands/admin.json deleted file mode 100644 index 444f39c28..000000000 --- a/src/languages/vi/commands/admin.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "confUpdated": "", - "confGetNoExt": "", - "confGet": "", - "confReset": "", - "confNochange": "", - "confServerDescription": "", - "confServerExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "confServer": "", - "confDashboardOnlyKey": "", - "confSettingNotSet": "", - "rolesetDescription": "", - "rolesetExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesetCreated": "", - "rolesetAdded": "", - "rolesetRemoved": "", - "rolesetResetEmpty": "", - "rolesetResetAll": "", - "rolesetResetNotExists": "", - "rolesetResetGroup": "", - "rolesetUpdated": "", - "rolesetNoRolesets": "", - "confMenuRenderAtFolder": "", - "confMenuRenderAtPiece": "", - "confMenuRenderNokeys": "", - "confMenuRenderSelect": "", - "confMenuRenderUpdate": "", - "confMenuRenderRemove": "", - "confMenuRenderReset": "", - "confMenuRenderUndo": "", - "confMenuRenderCvalue": "", - "confMenuRenderBack": "", - "confMenuInvalidKey": "", - "confMenuInvalidAction": "", - "confMenuSaved": "" -} \ No newline at end of file diff --git a/src/languages/vi/commands/animal.json b/src/languages/vi/commands/animal.json deleted file mode 100644 index 6d00e57af..000000000 --- a/src/languages/vi/commands/animal.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "bunnyDescription": "", - "bunnyExtended": { - "extendedHelp": "" - }, - "bunnyEmbedData": { - "title": "", - "source": "" - }, - "dogDescription": "", - "dogExtended": { - "extendedHelp": "" - }, - "foxDescription": "", - "foxExtended": { - "extendedHelp": "" - }, - "kittyDescription": "", - "kittyExtended": { - "extendedHelp": "" - }, - "shibeDescription": "", - "shibeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/vi/commands/auto-moderation.json b/src/languages/vi/commands/auto-moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/vi/commands/auto-moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/vi/commands/case.json b/src/languages/vi/commands/case.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/vi/commands/case.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/vi/commands/fun.json b/src/languages/vi/commands/fun.json deleted file mode 100644 index 7892e327d..000000000 --- a/src/languages/vi/commands/fun.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "escaperopeDescription": "", - "escaperopeExtended": { - "extendedHelp": "" - }, - "escaperopeOutput": "" -} \ No newline at end of file diff --git a/src/languages/vi/commands/game.json b/src/languages/vi/commands/game.json deleted file mode 100644 index 8075ca93c..000000000 --- a/src/languages/vi/commands/game.json +++ /dev/null @@ -1,447 +0,0 @@ -{ - "c4Description": "", - "c4Extended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "c4Prompt": "", - "gamesBot": "", - "gamesNoPlayers": "", - "gamesProgress": "", - "gamesPromptDeny": "", - "gamesRepeat": "", - "gamesSelf": "", - "gamesTooManyOrFew": "", - "hgBloodbath": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgDay": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgNight": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hungerGamesDescription": "", - "hungerGamesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "examples": [ - "" - ], - "reminder": "" - }, - "hungerGamesResultDeaths_one": "", - "hungerGamesResultDeaths_other": "", - "hungerGamesResultHeaderBloodbath": "", - "hungerGamesResultHeaderMoon": "", - "hungerGamesResultHeaderSun": "", - "hungerGamesResultProceed": "", - "hungerGamesStop": "", - "hungerGamesWinner": "", - "ticTacToeDescription": "", - "ticTacToeDraw": "", - "ticTacToeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "ticTacToePrompt": "", - "ticTacToeTurn": "", - "ticTacToeWinner": "", - "triviaActiveGame": "", - "triviaDescription": "", - "triviaEmbedTitles": { - "difficulty": "", - "trivia": "" - }, - "triviaExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "triviaIncorrect": "", - "triviaInvalidCategory": "", - "triviaNoAnswer": "", - "triviaWinner": "" -} \ No newline at end of file diff --git a/src/languages/vi/commands/general.json b/src/languages/vi/commands/general.json deleted file mode 100644 index 5e16f992d..000000000 --- a/src/languages/vi/commands/general.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "helpAllFlag": "", - "helpCommandCount_one": "", - "helpCommandCount_other": "", - "helpData": { - "footer": "", - "title": "" - }, - "helpDescription": "", - "helpExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "reminder": "", - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "helpDm": "", - "helpNodm": "", - "v7Description": "", - "v7Extended": { - "extendedHelp": "" - }, - "v7Message": "", - "v7NayreMessage": "" -} \ No newline at end of file diff --git a/src/languages/vi/commands/info.json b/src/languages/vi/commands/info.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/vi/commands/info.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/vi/commands/management.json b/src/languages/vi/commands/management.json deleted file mode 100644 index 21ef26ce2..000000000 --- a/src/languages/vi/commands/management.json +++ /dev/null @@ -1,445 +0,0 @@ -{ - "commandHandlerAborted": "", - "permissionNodesHigher": "", - "permissionNodesCannotAllowEveryone": "", - "permissionNodesInvalidType": "", - "permissionNodesAdd": "", - "permissionNodesNodeNotExists": "", - "permissionNodesCommandNotExists": "", - "permissionNodesRemove": "", - "permissionNodesReset": "", - "permissionNodesShowName": "", - "permissionNodesShowAllow": "", - "permissionNodesShowDeny": "", - "guildInfoTitles": { - "CHANNELS": "", - "MEMBERS": "", - "OTHER": "" - }, - "guildInfoChannels": "", - "guildInfoChannelsAfkChannelText": "", - "guildInfoMembers": "", - "guildInfoOther": "", - "guildInfoBanner": "", - "guildInfoIcon": "", - "guildInfoSplash": "", - "guildInfoDiscoverySplash": "", - "roleInfoTitles": { - "PERMISSIONS": "" - }, - "roleInfoData": "", - "roleInfoAll": "", - "roleInfoNoPermissions": "", - "manageCommandAutoDeleteShowEmpty": "", - "manageCommandAutoDeleteShow": "", - "manageCommandAutoDeleteAdd": "", - "manageCommandAutoDeleteRemove": "", - "manageCommandAutoDeleteRemoveNotset": "", - "manageCommandAutoDeleteReset": "", - "manageCommandChannelShow": "", - "manageCommandChannelShowEmpty": "", - "manageCommandChannelAddAlreadyset": "", - "manageCommandChannelAdd": "", - "manageCommandChannelRemoveNotset": "", - "manageCommandChannelRemove": "", - "manageCommandChannelResetEmpty": "", - "manageCommandChannelReset": "", - "manageReactionRolesShowEmpty": "", - "manageReactionRolesAddChannel": "", - "manageReactionRolesAddPrompt": "", - "manageReactionRolesAddMissing": "", - "manageReactionRolesAdd": "", - "manageReactionRolesRemoveNotExists": "", - "manageReactionRolesRemove": "", - "manageReactionRolesResetEmpty": "", - "manageReactionRolesReset": "", - "configurationEquals": "", - "setIgnoreChannelsSet": "", - "setIgnoreChannelsRemoved": "", - "setImageLogsSet": "", - "setMemberAddLogsSet": "", - "setMemberRemoveLogsSet": "", - "setMessageUpdateLogsSet": "", - "setMessageDeleteLogsSet": "", - "setModLogsSet": "", - "setPrefixSet": "", - "stickyRolesNotExists": "", - "stickyRolesReset": "", - "stickyRolesRemove": "", - "stickyRolesAdd": "", - "stickyRolesShowEmpty": "", - "stickyRolesShowSingle": "", - "createMuteDescription": "", - "createMuteExtended": { - "extendedHelp": "" - }, - "permissionNodesDescription": "", - "permissionNodesExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "managecommandautodeleteDescription": "", - "managecommandautodeleteExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageCommandChannelDescription": "", - "manageCommandChannelExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageReactionRolesDescription": "", - "manageReactionRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "rolesAdded": "", - "rolesAuditlog": "", - "rolesListEmpty": "", - "rolesListTitle": "", - "rolesNotManageable": "", - "rolesNotPublic": "", - "rolesRemoved": "", - "setIgnoreChannelsDescription": "", - "setIgnoreChannelsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setImageLogsDescription": "", - "setImageLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "setMemberAddLogsDescription": "", - "setMemberAddLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMemberRemoveLogsDescription": "", - "setMemberRemoveLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMessageUpdateLogsDescription": "", - "setMessageUpdateLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setMessageDeleteLogsDescription": "", - "setMessageDeleteLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setmodlogsDescription": "", - "setmodlogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setprefixDescription": "", - "setprefixExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "guildInfoDescription": "", - "guildInfoExtended": { - "extendedHelp": "" - }, - "roleInfoDescription": "", - "roleInfoExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "stickyRolesDescription": "", - "stickyRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesDescription": "", - "rolesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/vi/commands/misc.json b/src/languages/vi/commands/misc.json deleted file mode 100644 index 32f64d584..000000000 --- a/src/languages/vi/commands/misc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "snipeEmpty": "", - "snipeTitle": "", - "snipeDescription": "", - "snipeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/vi/commands/moderation.json b/src/languages/vi/commands/moderation.json deleted file mode 100644 index 815d1c788..000000000 --- a/src/languages/vi/commands/moderation.json +++ /dev/null @@ -1,889 +0,0 @@ -{ - "permissions": "", - "permissionsAll": "", - "slowmodeSet": "", - "slowmodeReset": "", - "banNotBannable": "", - "dehoistStarting": "", - "dehoistProgress": "", - "dehoistEmbed": { - "title": "", - "descriptionNoone": "", - "descriptionWithError": "", - "descriptionWithMultipleErrors": "", - "description": "", - "descriptionMultipleMembers": "", - "fieldErrorTitle": "" - }, - "kickNotKickable": "", - "lockdownLock": "", - "lockdownLocking": "", - "lockdownLocked": "", - "lockdownUnlocked": "", - "lockdownOpen": "", - "muteMuted": "", - "muteUserNotMuted": "", - "restrictLowlevel": "", - "pruneAlert_one": "", - "pruneAlert_other": "", - "pruneInvalidPosition": "", - "pruneNoDeletes": "", - "pruneLogHeader": "", - "toggleModerationDmToggledEnabled": "", - "toggleModerationDmToggledDisabled": "", - "moderationOutput_one": "", - "moderationOutput_other": "", - "moderationOutputWithReason_one": "", - "moderationOutputWithReason_other": "", - "moderationFailed_one": "", - "moderationFailed_other": "", - "moderationDmFooter": "", - "moderationDmDescription": "", - "moderationDmDescriptionWithReason": "", - "moderationDmDescriptionWithDuration": "", - "moderationDmDescriptionWithReasonWithDuration": "", - "slowmodeDescription": "", - "slowmodeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "banDescription": "", - "banExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "dehoistDescription": "", - "dehoistExtended": { - "extendedHelp": "", - "reminder": "" - }, - "kickDescription": "", - "kickExtended": { - "usages": [ - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "lockdownDescription": "", - "lockdownExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "muteDescription": "", - "muteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "setNicknameDescription": "", - "setNicknameExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ], - "reminder": "" - }, - "addRoleDescription": "", - "addRoleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "removeroleDescription": "", - "removeroleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "pruneDescription": "", - "pruneExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "permissionsDescription": "", - "permissionsExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ], - "extendedHelp": "" - }, - "restrictAttachmentDescription": "", - "restrictAttachmentExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictEmbedDescription": "", - "restrictEmbedExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictEmojiDescription": "", - "restrictEmojiExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictReactionDescription": "", - "restrictReactionExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictVoiceDescription": "", - "restrictVoiceExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "softBanDescription": "", - "softBanExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "timeoutApplyDescription": "", - "timeoutApplyExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutUndoDescription": "", - "timeoutUndoExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutNotModeratable": "", - "toggleModerationDmDescription": "", - "toggleModerationDmExtended": { - "extendedHelp": "" - }, - "unbanDescription": "", - "unbanExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unmuteDescription": "", - "unmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unrestrictAttachmentDescription": "", - "unrestrictAttachmentExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmbedDescription": "", - "unrestrictEmbedExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmojiDescription": "", - "unrestrictEmojiExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictReactionDescription": "", - "unrestrictReactionExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictVoiceDescription": "", - "unrestrictVoiceExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unwarnDescription": "", - "unwarnExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vmuteDescription": "", - "vmuteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "voiceKickDescription": "", - "voiceKickExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vunmuteDescription": "", - "vunmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "warnDescription": "", - "warnExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/vi/commands/shared.json b/src/languages/vi/commands/shared.json deleted file mode 100644 index ddbb28e7f..000000000 --- a/src/languages/vi/commands/shared.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "deprecatedMessage": "", - "slashOnlyDetailedDescription": { - "extendedHelp": "" - }, - "slashOnlyErrorMessage": "" -} \ No newline at end of file diff --git a/src/languages/vi/commands/system.json b/src/languages/vi/commands/system.json deleted file mode 100644 index e9cfdeec4..000000000 --- a/src/languages/vi/commands/system.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "evalDescription": "", - "evalExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "evalTimeout": "", - "evalError": "", - "dmNotSent": "", - "dmSent": "", - "reboot": "", - "rebootDescription": "", - "rebootExtended": { - "extendedHelp": "", - "reminder": "" - } -} \ No newline at end of file diff --git a/src/languages/vi/commands/tools.json b/src/languages/vi/commands/tools.json deleted file mode 100644 index 01bd03e25..000000000 --- a/src/languages/vi/commands/tools.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "avatarDescription": "", - "avatarExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "" - }, - "avatarNone": "", - "voteDescription": "", - "voteExtended": { - "usages": [ - "" - ], - "examples": [ - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "voteContentNeeded": "", - "voteReactionBlocked": "", - "whoisExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "whoisMemberRoleListAndMore": "" -} \ No newline at end of file diff --git a/src/languages/vi/commands/twitch.json b/src/languages/vi/commands/twitch.json deleted file mode 100644 index 2f12e1b08..000000000 --- a/src/languages/vi/commands/twitch.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "twitchSubscriptionStreamerNotFound": "", - "twitchSubscriptionStatusValues": [ - "", - "" - ], - "twitchSubscriptionInvalidStatus": "", - "twitchSubscriptionAddDuplicated": "", - "twitchSubscriptionAddSuccessOffline": "", - "twitchSubscriptionAddSuccessLive": "", - "twitchSubscriptionAddMessageForOfflineRequired": "", - "twitchSubscriptionRemoveOrResetEmpty": "", - "twitchSubscriptionRemoveStreamerNotSubscribed": "", - "twitchSubscriptionRemoveNotToProvidedChannel": "", - "twitchSubscriptionRemoveStreamerStatusNotMatch": "", - "twitchSubscriptionRemoveSuccessOffline": "", - "twitchSubscriptionRemoveSuccessLive": "", - "twitchSubscriptionResetSuccess_one": "", - "twitchSubscriptionResetSuccess_other": "", - "twitchSubscriptionShowStreamerNotSubscribed": "", - "twitchSubscriptionShowStatus": { - "live": "", - "offline": "" - }, - "twitchSubscriptionShowUnknownUser": "", - "twitchSubscriptionDescription": "", - "twitchSubscriptionExtended": { - "usages": [ - "", - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/vi/commands/whois.json b/src/languages/vi/commands/whois.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/vi/commands/whois.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/vi/errors.json b/src/languages/vi/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/vi/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/vi/events/errors.json b/src/languages/vi/events/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/vi/events/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/vi/events/guilds-logs.json b/src/languages/vi/events/guilds-logs.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/vi/events/guilds-logs.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/vi/events/guilds-members.json b/src/languages/vi/events/guilds-members.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/vi/events/guilds-members.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/vi/events/messages.json b/src/languages/vi/events/messages.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/vi/events/messages.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/vi/events/moderation.json b/src/languages/vi/events/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/vi/events/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/vi/events/noMentionSpam.json b/src/languages/vi/events/noMentionSpam.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/vi/events/noMentionSpam.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/vi/events/reactions.json b/src/languages/vi/events/reactions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/vi/events/reactions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/vi/events/twitch.json b/src/languages/vi/events/twitch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/vi/events/twitch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/vi/fuzzySearch.json b/src/languages/vi/fuzzySearch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/vi/fuzzySearch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/vi/globals.json b/src/languages/vi/globals.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/vi/globals.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/vi/guilds.json b/src/languages/vi/guilds.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/vi/guilds.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/vi/humanLevels.json b/src/languages/vi/humanLevels.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/vi/humanLevels.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/vi/moderation.json b/src/languages/vi/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/vi/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/vi/moderationActions.json b/src/languages/vi/moderationActions.json deleted file mode 100644 index 4c440ae54..000000000 --- a/src/languages/vi/moderationActions.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "actions": { - "addRole": "", - "ban": "", - "kick": "", - "mute": "", - "removeRole": "", - "restrictedAttachment": "", - "restrictedEmbed": "", - "restrictedEmoji": "", - "restrictedReact": "", - "restrictedVoice": "", - "setNickname": "", - "softban": "", - "vkick": "", - "vmute": "", - "warning": "" - }, - "actionCannotManageRoles": "", - "actionRoleNotConfigured": "", - "actionRoleHigherPosition": "", - "actionRoleManaged": "", - "applyNoReason": "", - "applyReason": "", - "requiredMember": "", - "revokeNoReason": "", - "revokeReason": "", - "setNicknameNoReasonRemoved": "", - "setNicknameNoReasonSet": "", - "setNicknameRemoved": "", - "setNicknameSet": "", - "setupMuteExists": "", - "setupTooManyRoles": "", - "sharedRoleSetupAsk": "", - "sharedRoleSetupNoMessage": "", - "sharedRoleSetupExisting": "", - "sharedRoleSetupExistingName": "", - "sharedRoleSetupNew": "", - "softbanNoReason": "", - "softbanReason": "", - "unSoftbanNoReason": "", - "unSoftbanReason": "" -} \ No newline at end of file diff --git a/src/languages/vi/permissions.json b/src/languages/vi/permissions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/vi/permissions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/vi/preconditions.json b/src/languages/vi/preconditions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/vi/preconditions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/vi/selfModeration.json b/src/languages/vi/selfModeration.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/vi/selfModeration.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/vi/serializers.json b/src/languages/vi/serializers.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/vi/serializers.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/vi/settings.json b/src/languages/vi/settings.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/vi/settings.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/vi/system.json b/src/languages/vi/system.json deleted file mode 100644 index 073b9b683..000000000 --- a/src/languages/vi/system.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "discordAbortError": "", - "fetchBansFail": "", - "helpTitles": { - "aliases": "", - "usages": "", - "extendedHelp": "", - "explainedUsage": "", - "possibleFormats": "", - "examples": "", - "reminders": "" - }, - "jumpTo": "", - "loading": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "prefixReminder": "" -} \ No newline at end of file diff --git a/src/languages/zh-CN/arguments.json b/src/languages/zh-CN/arguments.json deleted file mode 100644 index a7befa6f3..000000000 --- a/src/languages/zh-CN/arguments.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "boolean_one": "", - "boolean_other": "", - "booleanError": "", - "booleanDisabled": "", - "booleanEnabled": "", - "booleanFalseOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "booleanTrueOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "caseNoEntries": "", - "caseUnknownEntry": "", - "caseNotInThisGuild": "", - "caseLatestOptions": [ - "", - "" - ], - "categoryChannelError": "", - "channelError": "", - "command": "", - "commandMatch": "", - "dateError": "", - "dateFormats": "", - "dateTooEarly": "", - "dateTooFar": "", - "dmChannelError": "", - "duration": "", - "durationFormats": "", - "emojiError": "", - "floatError": "", - "floatTooLarge": "", - "floatTooSmall": "", - "guildChannelError": "", - "guildChannelMismatchingError": "", - "guildChannelMissingGuildError": "", - "guildPrivateThreadChannelError": "", - "guildPublicThreadChannelError": "", - "guildStageVoiceChannelError": "", - "guildTextChannelError": "", - "guildThreadChannelError": "", - "guildVoiceChannelError": "", - "hyperlinkError": "", - "integerError": "", - "integerTooLarge": "", - "integerTooSmall": "", - "invite": "", - "language": "", - "memberError": "", - "memberMissingGuild": "", - "messageError": "", - "missing": "", - "newsChannel": "", - "numberError": "", - "numberTooLarge": "", - "numberTooSmall": "", - "piece": "", - "rangeInvalid": "", - "rangeMax_other": "", - "rangeMax_one": "", - "resetPossibles": [ - "", - "" - ], - "roleError": "", - "roleMissingGuild": "", - "snowflake": "", - "store": "", - "stringTooLong": "", - "stringTooShort": "", - "time": "", - "timeSpan": "", - "timeSpanTooBig": "", - "timeSpanTooSmall": "", - "tooFewWinners": "", - "tooManyWinners": "", - "unavailable": "", - "userError": "", - "enumEmptyError": "", - "enumError": "" -} \ No newline at end of file diff --git a/src/languages/zh-CN/assertions.json b/src/languages/zh-CN/assertions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-CN/assertions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-CN/commands/admin.json b/src/languages/zh-CN/commands/admin.json deleted file mode 100644 index 444f39c28..000000000 --- a/src/languages/zh-CN/commands/admin.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "confUpdated": "", - "confGetNoExt": "", - "confGet": "", - "confReset": "", - "confNochange": "", - "confServerDescription": "", - "confServerExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "confServer": "", - "confDashboardOnlyKey": "", - "confSettingNotSet": "", - "rolesetDescription": "", - "rolesetExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesetCreated": "", - "rolesetAdded": "", - "rolesetRemoved": "", - "rolesetResetEmpty": "", - "rolesetResetAll": "", - "rolesetResetNotExists": "", - "rolesetResetGroup": "", - "rolesetUpdated": "", - "rolesetNoRolesets": "", - "confMenuRenderAtFolder": "", - "confMenuRenderAtPiece": "", - "confMenuRenderNokeys": "", - "confMenuRenderSelect": "", - "confMenuRenderUpdate": "", - "confMenuRenderRemove": "", - "confMenuRenderReset": "", - "confMenuRenderUndo": "", - "confMenuRenderCvalue": "", - "confMenuRenderBack": "", - "confMenuInvalidKey": "", - "confMenuInvalidAction": "", - "confMenuSaved": "" -} \ No newline at end of file diff --git a/src/languages/zh-CN/commands/animal.json b/src/languages/zh-CN/commands/animal.json deleted file mode 100644 index 6d00e57af..000000000 --- a/src/languages/zh-CN/commands/animal.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "bunnyDescription": "", - "bunnyExtended": { - "extendedHelp": "" - }, - "bunnyEmbedData": { - "title": "", - "source": "" - }, - "dogDescription": "", - "dogExtended": { - "extendedHelp": "" - }, - "foxDescription": "", - "foxExtended": { - "extendedHelp": "" - }, - "kittyDescription": "", - "kittyExtended": { - "extendedHelp": "" - }, - "shibeDescription": "", - "shibeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/zh-CN/commands/auto-moderation.json b/src/languages/zh-CN/commands/auto-moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-CN/commands/auto-moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-CN/commands/case.json b/src/languages/zh-CN/commands/case.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-CN/commands/case.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-CN/commands/fun.json b/src/languages/zh-CN/commands/fun.json deleted file mode 100644 index 7892e327d..000000000 --- a/src/languages/zh-CN/commands/fun.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "escaperopeDescription": "", - "escaperopeExtended": { - "extendedHelp": "" - }, - "escaperopeOutput": "" -} \ No newline at end of file diff --git a/src/languages/zh-CN/commands/game.json b/src/languages/zh-CN/commands/game.json deleted file mode 100644 index 8075ca93c..000000000 --- a/src/languages/zh-CN/commands/game.json +++ /dev/null @@ -1,447 +0,0 @@ -{ - "c4Description": "", - "c4Extended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "c4Prompt": "", - "gamesBot": "", - "gamesNoPlayers": "", - "gamesProgress": "", - "gamesPromptDeny": "", - "gamesRepeat": "", - "gamesSelf": "", - "gamesTooManyOrFew": "", - "hgBloodbath": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgDay": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgNight": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hungerGamesDescription": "", - "hungerGamesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "examples": [ - "" - ], - "reminder": "" - }, - "hungerGamesResultDeaths_one": "", - "hungerGamesResultDeaths_other": "", - "hungerGamesResultHeaderBloodbath": "", - "hungerGamesResultHeaderMoon": "", - "hungerGamesResultHeaderSun": "", - "hungerGamesResultProceed": "", - "hungerGamesStop": "", - "hungerGamesWinner": "", - "ticTacToeDescription": "", - "ticTacToeDraw": "", - "ticTacToeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "ticTacToePrompt": "", - "ticTacToeTurn": "", - "ticTacToeWinner": "", - "triviaActiveGame": "", - "triviaDescription": "", - "triviaEmbedTitles": { - "difficulty": "", - "trivia": "" - }, - "triviaExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "triviaIncorrect": "", - "triviaInvalidCategory": "", - "triviaNoAnswer": "", - "triviaWinner": "" -} \ No newline at end of file diff --git a/src/languages/zh-CN/commands/general.json b/src/languages/zh-CN/commands/general.json deleted file mode 100644 index 5e16f992d..000000000 --- a/src/languages/zh-CN/commands/general.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "helpAllFlag": "", - "helpCommandCount_one": "", - "helpCommandCount_other": "", - "helpData": { - "footer": "", - "title": "" - }, - "helpDescription": "", - "helpExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "reminder": "", - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "helpDm": "", - "helpNodm": "", - "v7Description": "", - "v7Extended": { - "extendedHelp": "" - }, - "v7Message": "", - "v7NayreMessage": "" -} \ No newline at end of file diff --git a/src/languages/zh-CN/commands/info.json b/src/languages/zh-CN/commands/info.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-CN/commands/info.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-CN/commands/management.json b/src/languages/zh-CN/commands/management.json deleted file mode 100644 index 21ef26ce2..000000000 --- a/src/languages/zh-CN/commands/management.json +++ /dev/null @@ -1,445 +0,0 @@ -{ - "commandHandlerAborted": "", - "permissionNodesHigher": "", - "permissionNodesCannotAllowEveryone": "", - "permissionNodesInvalidType": "", - "permissionNodesAdd": "", - "permissionNodesNodeNotExists": "", - "permissionNodesCommandNotExists": "", - "permissionNodesRemove": "", - "permissionNodesReset": "", - "permissionNodesShowName": "", - "permissionNodesShowAllow": "", - "permissionNodesShowDeny": "", - "guildInfoTitles": { - "CHANNELS": "", - "MEMBERS": "", - "OTHER": "" - }, - "guildInfoChannels": "", - "guildInfoChannelsAfkChannelText": "", - "guildInfoMembers": "", - "guildInfoOther": "", - "guildInfoBanner": "", - "guildInfoIcon": "", - "guildInfoSplash": "", - "guildInfoDiscoverySplash": "", - "roleInfoTitles": { - "PERMISSIONS": "" - }, - "roleInfoData": "", - "roleInfoAll": "", - "roleInfoNoPermissions": "", - "manageCommandAutoDeleteShowEmpty": "", - "manageCommandAutoDeleteShow": "", - "manageCommandAutoDeleteAdd": "", - "manageCommandAutoDeleteRemove": "", - "manageCommandAutoDeleteRemoveNotset": "", - "manageCommandAutoDeleteReset": "", - "manageCommandChannelShow": "", - "manageCommandChannelShowEmpty": "", - "manageCommandChannelAddAlreadyset": "", - "manageCommandChannelAdd": "", - "manageCommandChannelRemoveNotset": "", - "manageCommandChannelRemove": "", - "manageCommandChannelResetEmpty": "", - "manageCommandChannelReset": "", - "manageReactionRolesShowEmpty": "", - "manageReactionRolesAddChannel": "", - "manageReactionRolesAddPrompt": "", - "manageReactionRolesAddMissing": "", - "manageReactionRolesAdd": "", - "manageReactionRolesRemoveNotExists": "", - "manageReactionRolesRemove": "", - "manageReactionRolesResetEmpty": "", - "manageReactionRolesReset": "", - "configurationEquals": "", - "setIgnoreChannelsSet": "", - "setIgnoreChannelsRemoved": "", - "setImageLogsSet": "", - "setMemberAddLogsSet": "", - "setMemberRemoveLogsSet": "", - "setMessageUpdateLogsSet": "", - "setMessageDeleteLogsSet": "", - "setModLogsSet": "", - "setPrefixSet": "", - "stickyRolesNotExists": "", - "stickyRolesReset": "", - "stickyRolesRemove": "", - "stickyRolesAdd": "", - "stickyRolesShowEmpty": "", - "stickyRolesShowSingle": "", - "createMuteDescription": "", - "createMuteExtended": { - "extendedHelp": "" - }, - "permissionNodesDescription": "", - "permissionNodesExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "managecommandautodeleteDescription": "", - "managecommandautodeleteExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageCommandChannelDescription": "", - "manageCommandChannelExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageReactionRolesDescription": "", - "manageReactionRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "rolesAdded": "", - "rolesAuditlog": "", - "rolesListEmpty": "", - "rolesListTitle": "", - "rolesNotManageable": "", - "rolesNotPublic": "", - "rolesRemoved": "", - "setIgnoreChannelsDescription": "", - "setIgnoreChannelsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setImageLogsDescription": "", - "setImageLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "setMemberAddLogsDescription": "", - "setMemberAddLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMemberRemoveLogsDescription": "", - "setMemberRemoveLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMessageUpdateLogsDescription": "", - "setMessageUpdateLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setMessageDeleteLogsDescription": "", - "setMessageDeleteLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setmodlogsDescription": "", - "setmodlogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setprefixDescription": "", - "setprefixExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "guildInfoDescription": "", - "guildInfoExtended": { - "extendedHelp": "" - }, - "roleInfoDescription": "", - "roleInfoExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "stickyRolesDescription": "", - "stickyRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesDescription": "", - "rolesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/zh-CN/commands/misc.json b/src/languages/zh-CN/commands/misc.json deleted file mode 100644 index 32f64d584..000000000 --- a/src/languages/zh-CN/commands/misc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "snipeEmpty": "", - "snipeTitle": "", - "snipeDescription": "", - "snipeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/zh-CN/commands/moderation.json b/src/languages/zh-CN/commands/moderation.json deleted file mode 100644 index 815d1c788..000000000 --- a/src/languages/zh-CN/commands/moderation.json +++ /dev/null @@ -1,889 +0,0 @@ -{ - "permissions": "", - "permissionsAll": "", - "slowmodeSet": "", - "slowmodeReset": "", - "banNotBannable": "", - "dehoistStarting": "", - "dehoistProgress": "", - "dehoistEmbed": { - "title": "", - "descriptionNoone": "", - "descriptionWithError": "", - "descriptionWithMultipleErrors": "", - "description": "", - "descriptionMultipleMembers": "", - "fieldErrorTitle": "" - }, - "kickNotKickable": "", - "lockdownLock": "", - "lockdownLocking": "", - "lockdownLocked": "", - "lockdownUnlocked": "", - "lockdownOpen": "", - "muteMuted": "", - "muteUserNotMuted": "", - "restrictLowlevel": "", - "pruneAlert_one": "", - "pruneAlert_other": "", - "pruneInvalidPosition": "", - "pruneNoDeletes": "", - "pruneLogHeader": "", - "toggleModerationDmToggledEnabled": "", - "toggleModerationDmToggledDisabled": "", - "moderationOutput_one": "", - "moderationOutput_other": "", - "moderationOutputWithReason_one": "", - "moderationOutputWithReason_other": "", - "moderationFailed_one": "", - "moderationFailed_other": "", - "moderationDmFooter": "", - "moderationDmDescription": "", - "moderationDmDescriptionWithReason": "", - "moderationDmDescriptionWithDuration": "", - "moderationDmDescriptionWithReasonWithDuration": "", - "slowmodeDescription": "", - "slowmodeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "banDescription": "", - "banExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "dehoistDescription": "", - "dehoistExtended": { - "extendedHelp": "", - "reminder": "" - }, - "kickDescription": "", - "kickExtended": { - "usages": [ - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "lockdownDescription": "", - "lockdownExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "muteDescription": "", - "muteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "setNicknameDescription": "", - "setNicknameExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ], - "reminder": "" - }, - "addRoleDescription": "", - "addRoleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "removeroleDescription": "", - "removeroleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "pruneDescription": "", - "pruneExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "permissionsDescription": "", - "permissionsExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ], - "extendedHelp": "" - }, - "restrictAttachmentDescription": "", - "restrictAttachmentExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictEmbedDescription": "", - "restrictEmbedExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictEmojiDescription": "", - "restrictEmojiExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictReactionDescription": "", - "restrictReactionExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictVoiceDescription": "", - "restrictVoiceExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "softBanDescription": "", - "softBanExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "timeoutApplyDescription": "", - "timeoutApplyExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutUndoDescription": "", - "timeoutUndoExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutNotModeratable": "", - "toggleModerationDmDescription": "", - "toggleModerationDmExtended": { - "extendedHelp": "" - }, - "unbanDescription": "", - "unbanExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unmuteDescription": "", - "unmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unrestrictAttachmentDescription": "", - "unrestrictAttachmentExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmbedDescription": "", - "unrestrictEmbedExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmojiDescription": "", - "unrestrictEmojiExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictReactionDescription": "", - "unrestrictReactionExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictVoiceDescription": "", - "unrestrictVoiceExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unwarnDescription": "", - "unwarnExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vmuteDescription": "", - "vmuteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "voiceKickDescription": "", - "voiceKickExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vunmuteDescription": "", - "vunmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "warnDescription": "", - "warnExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/zh-CN/commands/shared.json b/src/languages/zh-CN/commands/shared.json deleted file mode 100644 index ddbb28e7f..000000000 --- a/src/languages/zh-CN/commands/shared.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "deprecatedMessage": "", - "slashOnlyDetailedDescription": { - "extendedHelp": "" - }, - "slashOnlyErrorMessage": "" -} \ No newline at end of file diff --git a/src/languages/zh-CN/commands/system.json b/src/languages/zh-CN/commands/system.json deleted file mode 100644 index e9cfdeec4..000000000 --- a/src/languages/zh-CN/commands/system.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "evalDescription": "", - "evalExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "evalTimeout": "", - "evalError": "", - "dmNotSent": "", - "dmSent": "", - "reboot": "", - "rebootDescription": "", - "rebootExtended": { - "extendedHelp": "", - "reminder": "" - } -} \ No newline at end of file diff --git a/src/languages/zh-CN/commands/tools.json b/src/languages/zh-CN/commands/tools.json deleted file mode 100644 index 01bd03e25..000000000 --- a/src/languages/zh-CN/commands/tools.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "avatarDescription": "", - "avatarExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "" - }, - "avatarNone": "", - "voteDescription": "", - "voteExtended": { - "usages": [ - "" - ], - "examples": [ - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "voteContentNeeded": "", - "voteReactionBlocked": "", - "whoisExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "whoisMemberRoleListAndMore": "" -} \ No newline at end of file diff --git a/src/languages/zh-CN/commands/twitch.json b/src/languages/zh-CN/commands/twitch.json deleted file mode 100644 index 2f12e1b08..000000000 --- a/src/languages/zh-CN/commands/twitch.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "twitchSubscriptionStreamerNotFound": "", - "twitchSubscriptionStatusValues": [ - "", - "" - ], - "twitchSubscriptionInvalidStatus": "", - "twitchSubscriptionAddDuplicated": "", - "twitchSubscriptionAddSuccessOffline": "", - "twitchSubscriptionAddSuccessLive": "", - "twitchSubscriptionAddMessageForOfflineRequired": "", - "twitchSubscriptionRemoveOrResetEmpty": "", - "twitchSubscriptionRemoveStreamerNotSubscribed": "", - "twitchSubscriptionRemoveNotToProvidedChannel": "", - "twitchSubscriptionRemoveStreamerStatusNotMatch": "", - "twitchSubscriptionRemoveSuccessOffline": "", - "twitchSubscriptionRemoveSuccessLive": "", - "twitchSubscriptionResetSuccess_one": "", - "twitchSubscriptionResetSuccess_other": "", - "twitchSubscriptionShowStreamerNotSubscribed": "", - "twitchSubscriptionShowStatus": { - "live": "", - "offline": "" - }, - "twitchSubscriptionShowUnknownUser": "", - "twitchSubscriptionDescription": "", - "twitchSubscriptionExtended": { - "usages": [ - "", - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/zh-CN/commands/whois.json b/src/languages/zh-CN/commands/whois.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-CN/commands/whois.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-CN/errors.json b/src/languages/zh-CN/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-CN/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-CN/events/errors.json b/src/languages/zh-CN/events/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-CN/events/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-CN/events/guilds-logs.json b/src/languages/zh-CN/events/guilds-logs.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-CN/events/guilds-logs.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-CN/events/guilds-members.json b/src/languages/zh-CN/events/guilds-members.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-CN/events/guilds-members.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-CN/events/messages.json b/src/languages/zh-CN/events/messages.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-CN/events/messages.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-CN/events/moderation.json b/src/languages/zh-CN/events/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-CN/events/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-CN/events/noMentionSpam.json b/src/languages/zh-CN/events/noMentionSpam.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-CN/events/noMentionSpam.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-CN/events/reactions.json b/src/languages/zh-CN/events/reactions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-CN/events/reactions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-CN/events/twitch.json b/src/languages/zh-CN/events/twitch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-CN/events/twitch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-CN/fuzzySearch.json b/src/languages/zh-CN/fuzzySearch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-CN/fuzzySearch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-CN/globals.json b/src/languages/zh-CN/globals.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-CN/globals.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-CN/guilds.json b/src/languages/zh-CN/guilds.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-CN/guilds.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-CN/humanLevels.json b/src/languages/zh-CN/humanLevels.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-CN/humanLevels.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-CN/moderation.json b/src/languages/zh-CN/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-CN/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-CN/moderationActions.json b/src/languages/zh-CN/moderationActions.json deleted file mode 100644 index 4c440ae54..000000000 --- a/src/languages/zh-CN/moderationActions.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "actions": { - "addRole": "", - "ban": "", - "kick": "", - "mute": "", - "removeRole": "", - "restrictedAttachment": "", - "restrictedEmbed": "", - "restrictedEmoji": "", - "restrictedReact": "", - "restrictedVoice": "", - "setNickname": "", - "softban": "", - "vkick": "", - "vmute": "", - "warning": "" - }, - "actionCannotManageRoles": "", - "actionRoleNotConfigured": "", - "actionRoleHigherPosition": "", - "actionRoleManaged": "", - "applyNoReason": "", - "applyReason": "", - "requiredMember": "", - "revokeNoReason": "", - "revokeReason": "", - "setNicknameNoReasonRemoved": "", - "setNicknameNoReasonSet": "", - "setNicknameRemoved": "", - "setNicknameSet": "", - "setupMuteExists": "", - "setupTooManyRoles": "", - "sharedRoleSetupAsk": "", - "sharedRoleSetupNoMessage": "", - "sharedRoleSetupExisting": "", - "sharedRoleSetupExistingName": "", - "sharedRoleSetupNew": "", - "softbanNoReason": "", - "softbanReason": "", - "unSoftbanNoReason": "", - "unSoftbanReason": "" -} \ No newline at end of file diff --git a/src/languages/zh-CN/permissions.json b/src/languages/zh-CN/permissions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-CN/permissions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-CN/preconditions.json b/src/languages/zh-CN/preconditions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-CN/preconditions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-CN/selfModeration.json b/src/languages/zh-CN/selfModeration.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-CN/selfModeration.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-CN/serializers.json b/src/languages/zh-CN/serializers.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-CN/serializers.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-CN/settings.json b/src/languages/zh-CN/settings.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-CN/settings.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-CN/system.json b/src/languages/zh-CN/system.json deleted file mode 100644 index 073b9b683..000000000 --- a/src/languages/zh-CN/system.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "discordAbortError": "", - "fetchBansFail": "", - "helpTitles": { - "aliases": "", - "usages": "", - "extendedHelp": "", - "explainedUsage": "", - "possibleFormats": "", - "examples": "", - "reminders": "" - }, - "jumpTo": "", - "loading": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "prefixReminder": "" -} \ No newline at end of file diff --git a/src/languages/zh-TW/arguments.json b/src/languages/zh-TW/arguments.json deleted file mode 100644 index a7befa6f3..000000000 --- a/src/languages/zh-TW/arguments.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "boolean_one": "", - "boolean_other": "", - "booleanError": "", - "booleanDisabled": "", - "booleanEnabled": "", - "booleanFalseOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "booleanTrueOptions": [ - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "caseNoEntries": "", - "caseUnknownEntry": "", - "caseNotInThisGuild": "", - "caseLatestOptions": [ - "", - "" - ], - "categoryChannelError": "", - "channelError": "", - "command": "", - "commandMatch": "", - "dateError": "", - "dateFormats": "", - "dateTooEarly": "", - "dateTooFar": "", - "dmChannelError": "", - "duration": "", - "durationFormats": "", - "emojiError": "", - "floatError": "", - "floatTooLarge": "", - "floatTooSmall": "", - "guildChannelError": "", - "guildChannelMismatchingError": "", - "guildChannelMissingGuildError": "", - "guildPrivateThreadChannelError": "", - "guildPublicThreadChannelError": "", - "guildStageVoiceChannelError": "", - "guildTextChannelError": "", - "guildThreadChannelError": "", - "guildVoiceChannelError": "", - "hyperlinkError": "", - "integerError": "", - "integerTooLarge": "", - "integerTooSmall": "", - "invite": "", - "language": "", - "memberError": "", - "memberMissingGuild": "", - "messageError": "", - "missing": "", - "newsChannel": "", - "numberError": "", - "numberTooLarge": "", - "numberTooSmall": "", - "piece": "", - "rangeInvalid": "", - "rangeMax_other": "", - "rangeMax_one": "", - "resetPossibles": [ - "", - "" - ], - "roleError": "", - "roleMissingGuild": "", - "snowflake": "", - "store": "", - "stringTooLong": "", - "stringTooShort": "", - "time": "", - "timeSpan": "", - "timeSpanTooBig": "", - "timeSpanTooSmall": "", - "tooFewWinners": "", - "tooManyWinners": "", - "unavailable": "", - "userError": "", - "enumEmptyError": "", - "enumError": "" -} \ No newline at end of file diff --git a/src/languages/zh-TW/assertions.json b/src/languages/zh-TW/assertions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-TW/assertions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-TW/commands/admin.json b/src/languages/zh-TW/commands/admin.json deleted file mode 100644 index 444f39c28..000000000 --- a/src/languages/zh-TW/commands/admin.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "confUpdated": "", - "confGetNoExt": "", - "confGet": "", - "confReset": "", - "confNochange": "", - "confServerDescription": "", - "confServerExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "confServer": "", - "confDashboardOnlyKey": "", - "confSettingNotSet": "", - "rolesetDescription": "", - "rolesetExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesetCreated": "", - "rolesetAdded": "", - "rolesetRemoved": "", - "rolesetResetEmpty": "", - "rolesetResetAll": "", - "rolesetResetNotExists": "", - "rolesetResetGroup": "", - "rolesetUpdated": "", - "rolesetNoRolesets": "", - "confMenuRenderAtFolder": "", - "confMenuRenderAtPiece": "", - "confMenuRenderNokeys": "", - "confMenuRenderSelect": "", - "confMenuRenderUpdate": "", - "confMenuRenderRemove": "", - "confMenuRenderReset": "", - "confMenuRenderUndo": "", - "confMenuRenderCvalue": "", - "confMenuRenderBack": "", - "confMenuInvalidKey": "", - "confMenuInvalidAction": "", - "confMenuSaved": "" -} \ No newline at end of file diff --git a/src/languages/zh-TW/commands/animal.json b/src/languages/zh-TW/commands/animal.json deleted file mode 100644 index 6d00e57af..000000000 --- a/src/languages/zh-TW/commands/animal.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "bunnyDescription": "", - "bunnyExtended": { - "extendedHelp": "" - }, - "bunnyEmbedData": { - "title": "", - "source": "" - }, - "dogDescription": "", - "dogExtended": { - "extendedHelp": "" - }, - "foxDescription": "", - "foxExtended": { - "extendedHelp": "" - }, - "kittyDescription": "", - "kittyExtended": { - "extendedHelp": "" - }, - "shibeDescription": "", - "shibeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/zh-TW/commands/auto-moderation.json b/src/languages/zh-TW/commands/auto-moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-TW/commands/auto-moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-TW/commands/case.json b/src/languages/zh-TW/commands/case.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-TW/commands/case.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-TW/commands/fun.json b/src/languages/zh-TW/commands/fun.json deleted file mode 100644 index 7892e327d..000000000 --- a/src/languages/zh-TW/commands/fun.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "escaperopeDescription": "", - "escaperopeExtended": { - "extendedHelp": "" - }, - "escaperopeOutput": "" -} \ No newline at end of file diff --git a/src/languages/zh-TW/commands/game.json b/src/languages/zh-TW/commands/game.json deleted file mode 100644 index 8075ca93c..000000000 --- a/src/languages/zh-TW/commands/game.json +++ /dev/null @@ -1,447 +0,0 @@ -{ - "c4Description": "", - "c4Extended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "c4Prompt": "", - "gamesBot": "", - "gamesNoPlayers": "", - "gamesProgress": "", - "gamesPromptDeny": "", - "gamesRepeat": "", - "gamesSelf": "", - "gamesTooManyOrFew": "", - "hgBloodbath": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgDay": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hgNight": [ - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "" - ], - "hungerGamesDescription": "", - "hungerGamesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "examples": [ - "" - ], - "reminder": "" - }, - "hungerGamesResultDeaths_one": "", - "hungerGamesResultDeaths_other": "", - "hungerGamesResultHeaderBloodbath": "", - "hungerGamesResultHeaderMoon": "", - "hungerGamesResultHeaderSun": "", - "hungerGamesResultProceed": "", - "hungerGamesStop": "", - "hungerGamesWinner": "", - "ticTacToeDescription": "", - "ticTacToeDraw": "", - "ticTacToeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "ticTacToePrompt": "", - "ticTacToeTurn": "", - "ticTacToeWinner": "", - "triviaActiveGame": "", - "triviaDescription": "", - "triviaEmbedTitles": { - "difficulty": "", - "trivia": "" - }, - "triviaExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "triviaIncorrect": "", - "triviaInvalidCategory": "", - "triviaNoAnswer": "", - "triviaWinner": "" -} \ No newline at end of file diff --git a/src/languages/zh-TW/commands/general.json b/src/languages/zh-TW/commands/general.json deleted file mode 100644 index 5e16f992d..000000000 --- a/src/languages/zh-TW/commands/general.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "helpAllFlag": "", - "helpCommandCount_one": "", - "helpCommandCount_other": "", - "helpData": { - "footer": "", - "title": "" - }, - "helpDescription": "", - "helpExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "reminder": "", - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "helpDm": "", - "helpNodm": "", - "v7Description": "", - "v7Extended": { - "extendedHelp": "" - }, - "v7Message": "", - "v7NayreMessage": "" -} \ No newline at end of file diff --git a/src/languages/zh-TW/commands/info.json b/src/languages/zh-TW/commands/info.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-TW/commands/info.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-TW/commands/management.json b/src/languages/zh-TW/commands/management.json deleted file mode 100644 index 21ef26ce2..000000000 --- a/src/languages/zh-TW/commands/management.json +++ /dev/null @@ -1,445 +0,0 @@ -{ - "commandHandlerAborted": "", - "permissionNodesHigher": "", - "permissionNodesCannotAllowEveryone": "", - "permissionNodesInvalidType": "", - "permissionNodesAdd": "", - "permissionNodesNodeNotExists": "", - "permissionNodesCommandNotExists": "", - "permissionNodesRemove": "", - "permissionNodesReset": "", - "permissionNodesShowName": "", - "permissionNodesShowAllow": "", - "permissionNodesShowDeny": "", - "guildInfoTitles": { - "CHANNELS": "", - "MEMBERS": "", - "OTHER": "" - }, - "guildInfoChannels": "", - "guildInfoChannelsAfkChannelText": "", - "guildInfoMembers": "", - "guildInfoOther": "", - "guildInfoBanner": "", - "guildInfoIcon": "", - "guildInfoSplash": "", - "guildInfoDiscoverySplash": "", - "roleInfoTitles": { - "PERMISSIONS": "" - }, - "roleInfoData": "", - "roleInfoAll": "", - "roleInfoNoPermissions": "", - "manageCommandAutoDeleteShowEmpty": "", - "manageCommandAutoDeleteShow": "", - "manageCommandAutoDeleteAdd": "", - "manageCommandAutoDeleteRemove": "", - "manageCommandAutoDeleteRemoveNotset": "", - "manageCommandAutoDeleteReset": "", - "manageCommandChannelShow": "", - "manageCommandChannelShowEmpty": "", - "manageCommandChannelAddAlreadyset": "", - "manageCommandChannelAdd": "", - "manageCommandChannelRemoveNotset": "", - "manageCommandChannelRemove": "", - "manageCommandChannelResetEmpty": "", - "manageCommandChannelReset": "", - "manageReactionRolesShowEmpty": "", - "manageReactionRolesAddChannel": "", - "manageReactionRolesAddPrompt": "", - "manageReactionRolesAddMissing": "", - "manageReactionRolesAdd": "", - "manageReactionRolesRemoveNotExists": "", - "manageReactionRolesRemove": "", - "manageReactionRolesResetEmpty": "", - "manageReactionRolesReset": "", - "configurationEquals": "", - "setIgnoreChannelsSet": "", - "setIgnoreChannelsRemoved": "", - "setImageLogsSet": "", - "setMemberAddLogsSet": "", - "setMemberRemoveLogsSet": "", - "setMessageUpdateLogsSet": "", - "setMessageDeleteLogsSet": "", - "setModLogsSet": "", - "setPrefixSet": "", - "stickyRolesNotExists": "", - "stickyRolesReset": "", - "stickyRolesRemove": "", - "stickyRolesAdd": "", - "stickyRolesShowEmpty": "", - "stickyRolesShowSingle": "", - "createMuteDescription": "", - "createMuteExtended": { - "extendedHelp": "" - }, - "permissionNodesDescription": "", - "permissionNodesExtended": { - "usages": [ - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "managecommandautodeleteDescription": "", - "managecommandautodeleteExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageCommandChannelDescription": "", - "manageCommandChannelExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "", - "", - "" - ] - }, - "manageReactionRolesDescription": "", - "manageReactionRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ] - }, - "rolesAdded": "", - "rolesAuditlog": "", - "rolesListEmpty": "", - "rolesListTitle": "", - "rolesNotManageable": "", - "rolesNotPublic": "", - "rolesRemoved": "", - "setIgnoreChannelsDescription": "", - "setIgnoreChannelsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setImageLogsDescription": "", - "setImageLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "setMemberAddLogsDescription": "", - "setMemberAddLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMemberRemoveLogsDescription": "", - "setMemberRemoveLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "setMessageUpdateLogsDescription": "", - "setMessageUpdateLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setMessageDeleteLogsDescription": "", - "setMessageDeleteLogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setmodlogsDescription": "", - "setmodlogsExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "setprefixDescription": "", - "setprefixExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - }, - "guildInfoDescription": "", - "guildInfoExtended": { - "extendedHelp": "" - }, - "roleInfoDescription": "", - "roleInfoExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "" - ] - }, - "stickyRolesDescription": "", - "stickyRolesExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "" - ], - "reminder": "" - }, - "rolesDescription": "", - "rolesExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "", - "examples": [ - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/zh-TW/commands/misc.json b/src/languages/zh-TW/commands/misc.json deleted file mode 100644 index 32f64d584..000000000 --- a/src/languages/zh-TW/commands/misc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "snipeEmpty": "", - "snipeTitle": "", - "snipeDescription": "", - "snipeExtended": { - "extendedHelp": "" - } -} \ No newline at end of file diff --git a/src/languages/zh-TW/commands/moderation.json b/src/languages/zh-TW/commands/moderation.json deleted file mode 100644 index 815d1c788..000000000 --- a/src/languages/zh-TW/commands/moderation.json +++ /dev/null @@ -1,889 +0,0 @@ -{ - "permissions": "", - "permissionsAll": "", - "slowmodeSet": "", - "slowmodeReset": "", - "banNotBannable": "", - "dehoistStarting": "", - "dehoistProgress": "", - "dehoistEmbed": { - "title": "", - "descriptionNoone": "", - "descriptionWithError": "", - "descriptionWithMultipleErrors": "", - "description": "", - "descriptionMultipleMembers": "", - "fieldErrorTitle": "" - }, - "kickNotKickable": "", - "lockdownLock": "", - "lockdownLocking": "", - "lockdownLocked": "", - "lockdownUnlocked": "", - "lockdownOpen": "", - "muteMuted": "", - "muteUserNotMuted": "", - "restrictLowlevel": "", - "pruneAlert_one": "", - "pruneAlert_other": "", - "pruneInvalidPosition": "", - "pruneNoDeletes": "", - "pruneLogHeader": "", - "toggleModerationDmToggledEnabled": "", - "toggleModerationDmToggledDisabled": "", - "moderationOutput_one": "", - "moderationOutput_other": "", - "moderationOutputWithReason_one": "", - "moderationOutputWithReason_other": "", - "moderationFailed_one": "", - "moderationFailed_other": "", - "moderationDmFooter": "", - "moderationDmDescription": "", - "moderationDmDescriptionWithReason": "", - "moderationDmDescriptionWithDuration": "", - "moderationDmDescriptionWithReasonWithDuration": "", - "slowmodeDescription": "", - "slowmodeExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "banDescription": "", - "banExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "dehoistDescription": "", - "dehoistExtended": { - "extendedHelp": "", - "reminder": "" - }, - "kickDescription": "", - "kickExtended": { - "usages": [ - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "lockdownDescription": "", - "lockdownExtended": { - "usages": [ - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "muteDescription": "", - "muteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "setNicknameDescription": "", - "setNicknameExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ], - "reminder": "" - }, - "addRoleDescription": "", - "addRoleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "removeroleDescription": "", - "removeroleExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "pruneDescription": "", - "pruneExtended": { - "usages": [ - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "" - ], - "reminder": "" - }, - "permissionsDescription": "", - "permissionsExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ], - "extendedHelp": "" - }, - "restrictAttachmentDescription": "", - "restrictAttachmentExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictEmbedDescription": "", - "restrictEmbedExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictEmojiDescription": "", - "restrictEmojiExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ], - "reminder": "" - }, - "restrictReactionDescription": "", - "restrictReactionExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "restrictVoiceDescription": "", - "restrictVoiceExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "softBanDescription": "", - "softBanExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "timeoutApplyDescription": "", - "timeoutApplyExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutUndoDescription": "", - "timeoutUndoExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ] - }, - "timeoutNotModeratable": "", - "toggleModerationDmDescription": "", - "toggleModerationDmExtended": { - "extendedHelp": "" - }, - "unbanDescription": "", - "unbanExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unmuteDescription": "", - "unmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "unrestrictAttachmentDescription": "", - "unrestrictAttachmentExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmbedDescription": "", - "unrestrictEmbedExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictEmojiDescription": "", - "unrestrictEmojiExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictReactionDescription": "", - "unrestrictReactionExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unrestrictVoiceDescription": "", - "unrestrictVoiceExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - }, - "unwarnDescription": "", - "unwarnExtended": { - "usages": [ - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vmuteDescription": "", - "vmuteExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "", - "" - ] - }, - "voiceKickDescription": "", - "voiceKickExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "vunmuteDescription": "", - "vunmuteExtended": { - "usages": [ - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "", - "" - ] - }, - "warnDescription": "", - "warnExtended": { - "usages": [ - "", - "", - "", - "" - ], - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "extendedHelp": "", - "examples": [ - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/zh-TW/commands/shared.json b/src/languages/zh-TW/commands/shared.json deleted file mode 100644 index ddbb28e7f..000000000 --- a/src/languages/zh-TW/commands/shared.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "deprecatedMessage": "", - "slashOnlyDetailedDescription": { - "extendedHelp": "" - }, - "slashOnlyErrorMessage": "" -} \ No newline at end of file diff --git a/src/languages/zh-TW/commands/system.json b/src/languages/zh-TW/commands/system.json deleted file mode 100644 index e9cfdeec4..000000000 --- a/src/languages/zh-TW/commands/system.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "evalDescription": "", - "evalExtended": { - "usages": [ - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "examples": [ - "", - "" - ], - "reminder": "" - }, - "evalTimeout": "", - "evalError": "", - "dmNotSent": "", - "dmSent": "", - "reboot": "", - "rebootDescription": "", - "rebootExtended": { - "extendedHelp": "", - "reminder": "" - } -} \ No newline at end of file diff --git a/src/languages/zh-TW/commands/tools.json b/src/languages/zh-TW/commands/tools.json deleted file mode 100644 index 01bd03e25..000000000 --- a/src/languages/zh-TW/commands/tools.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "avatarDescription": "", - "avatarExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ], - "reminder": "" - }, - "avatarNone": "", - "voteDescription": "", - "voteExtended": { - "usages": [ - "" - ], - "examples": [ - "" - ], - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "voteContentNeeded": "", - "voteReactionBlocked": "", - "whoisExtended": { - "usages": [ - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ] - ] - }, - "whoisMemberRoleListAndMore": "" -} \ No newline at end of file diff --git a/src/languages/zh-TW/commands/twitch.json b/src/languages/zh-TW/commands/twitch.json deleted file mode 100644 index 2f12e1b08..000000000 --- a/src/languages/zh-TW/commands/twitch.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "twitchSubscriptionStreamerNotFound": "", - "twitchSubscriptionStatusValues": [ - "", - "" - ], - "twitchSubscriptionInvalidStatus": "", - "twitchSubscriptionAddDuplicated": "", - "twitchSubscriptionAddSuccessOffline": "", - "twitchSubscriptionAddSuccessLive": "", - "twitchSubscriptionAddMessageForOfflineRequired": "", - "twitchSubscriptionRemoveOrResetEmpty": "", - "twitchSubscriptionRemoveStreamerNotSubscribed": "", - "twitchSubscriptionRemoveNotToProvidedChannel": "", - "twitchSubscriptionRemoveStreamerStatusNotMatch": "", - "twitchSubscriptionRemoveSuccessOffline": "", - "twitchSubscriptionRemoveSuccessLive": "", - "twitchSubscriptionResetSuccess_one": "", - "twitchSubscriptionResetSuccess_other": "", - "twitchSubscriptionShowStreamerNotSubscribed": "", - "twitchSubscriptionShowStatus": { - "live": "", - "offline": "" - }, - "twitchSubscriptionShowUnknownUser": "", - "twitchSubscriptionDescription": "", - "twitchSubscriptionExtended": { - "usages": [ - "", - "", - "", - "", - "", - "", - "" - ], - "extendedHelp": "", - "explainedUsage": [ - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ], - [ - "", - "" - ] - ], - "examples": [ - "", - "", - "", - "", - "", - "", - "" - ] - } -} \ No newline at end of file diff --git a/src/languages/zh-TW/commands/whois.json b/src/languages/zh-TW/commands/whois.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-TW/commands/whois.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-TW/errors.json b/src/languages/zh-TW/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-TW/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-TW/events/errors.json b/src/languages/zh-TW/events/errors.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-TW/events/errors.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-TW/events/guilds-logs.json b/src/languages/zh-TW/events/guilds-logs.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-TW/events/guilds-logs.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-TW/events/guilds-members.json b/src/languages/zh-TW/events/guilds-members.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-TW/events/guilds-members.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-TW/events/messages.json b/src/languages/zh-TW/events/messages.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-TW/events/messages.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-TW/events/moderation.json b/src/languages/zh-TW/events/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-TW/events/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-TW/events/noMentionSpam.json b/src/languages/zh-TW/events/noMentionSpam.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-TW/events/noMentionSpam.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-TW/events/reactions.json b/src/languages/zh-TW/events/reactions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-TW/events/reactions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-TW/events/twitch.json b/src/languages/zh-TW/events/twitch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-TW/events/twitch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-TW/fuzzySearch.json b/src/languages/zh-TW/fuzzySearch.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-TW/fuzzySearch.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-TW/globals.json b/src/languages/zh-TW/globals.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-TW/globals.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-TW/guilds.json b/src/languages/zh-TW/guilds.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-TW/guilds.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-TW/humanLevels.json b/src/languages/zh-TW/humanLevels.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-TW/humanLevels.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-TW/moderation.json b/src/languages/zh-TW/moderation.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-TW/moderation.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-TW/moderationActions.json b/src/languages/zh-TW/moderationActions.json deleted file mode 100644 index 4c440ae54..000000000 --- a/src/languages/zh-TW/moderationActions.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "actions": { - "addRole": "", - "ban": "", - "kick": "", - "mute": "", - "removeRole": "", - "restrictedAttachment": "", - "restrictedEmbed": "", - "restrictedEmoji": "", - "restrictedReact": "", - "restrictedVoice": "", - "setNickname": "", - "softban": "", - "vkick": "", - "vmute": "", - "warning": "" - }, - "actionCannotManageRoles": "", - "actionRoleNotConfigured": "", - "actionRoleHigherPosition": "", - "actionRoleManaged": "", - "applyNoReason": "", - "applyReason": "", - "requiredMember": "", - "revokeNoReason": "", - "revokeReason": "", - "setNicknameNoReasonRemoved": "", - "setNicknameNoReasonSet": "", - "setNicknameRemoved": "", - "setNicknameSet": "", - "setupMuteExists": "", - "setupTooManyRoles": "", - "sharedRoleSetupAsk": "", - "sharedRoleSetupNoMessage": "", - "sharedRoleSetupExisting": "", - "sharedRoleSetupExistingName": "", - "sharedRoleSetupNew": "", - "softbanNoReason": "", - "softbanReason": "", - "unSoftbanNoReason": "", - "unSoftbanReason": "" -} \ No newline at end of file diff --git a/src/languages/zh-TW/permissions.json b/src/languages/zh-TW/permissions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-TW/permissions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-TW/preconditions.json b/src/languages/zh-TW/preconditions.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-TW/preconditions.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-TW/selfModeration.json b/src/languages/zh-TW/selfModeration.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-TW/selfModeration.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-TW/serializers.json b/src/languages/zh-TW/serializers.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-TW/serializers.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-TW/settings.json b/src/languages/zh-TW/settings.json deleted file mode 100644 index 0637a088a..000000000 --- a/src/languages/zh-TW/settings.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/src/languages/zh-TW/system.json b/src/languages/zh-TW/system.json deleted file mode 100644 index 073b9b683..000000000 --- a/src/languages/zh-TW/system.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "discordAbortError": "", - "fetchBansFail": "", - "helpTitles": { - "aliases": "", - "usages": "", - "extendedHelp": "", - "explainedUsage": "", - "possibleFormats": "", - "examples": "", - "reminders": "" - }, - "jumpTo": "", - "loading": [ - "", - "", - "", - "", - "", - "", - "", - "" - ], - "prefixReminder": "" -} \ No newline at end of file diff --git a/src/lib/WolfClient.ts b/src/lib/WolfClient.ts deleted file mode 100644 index f0572e51c..000000000 --- a/src/lib/WolfClient.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { SerializerStore } from '#lib/database'; -import { readSettings } from '#lib/database/settings/functions'; -import { GuildMemberFetchQueue } from '#lib/discord/GuildMemberFetchQueue'; -import { WorkerManager } from '#lib/moderation/workers/WorkerManager'; -import { ScheduleManager, TaskStore } from '#lib/schedule'; -import { AnalyticsData, InviteStore } from '#lib/structures'; -import type { LongLivingInteractionCollector } from '#lib/util/LongLivingInteractionCollector'; -import type { LongLivingReactionCollector } from '#lib/util/LongLivingReactionCollector'; -import { CLIENT_OPTIONS, WEBHOOK_ERROR } from '#root/config'; -import { isGuildMessage } from '#utils/common'; -import { Enumerable } from '@sapphire/decorators'; -import { SapphireClient, container } from '@sapphire/framework'; -import type { InternationalizationContext } from '@sapphire/plugin-i18next'; -import { envParseBoolean } from '@skyra/env-utilities'; -import { WebhookClient, type Message } from 'discord.js'; - -export class WolfClient extends SapphireClient { - @Enumerable(false) - public override dev = process.env.NODE_ENV !== 'production'; - - /** - * The Schedule manager - */ - @Enumerable(false) - public override schedules: ScheduleManager; - - /** - * The webhook to use for the error event - */ - @Enumerable(false) - public override webhookError: WebhookClient | null = WEBHOOK_ERROR ? new WebhookClient(WEBHOOK_ERROR) : null; - - /** - * The invite store - */ - @Enumerable(false) - public override invites = new InviteStore(); - - @Enumerable(false) - public override readonly analytics: AnalyticsData | null; - - @Enumerable(false) - public override readonly guildMemberFetchQueue = new GuildMemberFetchQueue(); - - @Enumerable(false) - public override llrCollectors = new Set(); - - @Enumerable(false) - public override lliCollectors = new Set(); - - public constructor() { - super(CLIENT_OPTIONS); - - container.stores.register(new SerializerStore()); - container.stores.register(new TaskStore()); - - // Workers - container.workers = new WorkerManager(); - - // Analytics - this.schedules = new ScheduleManager(); - container.schedule = this.schedules; - - this.analytics = envParseBoolean('INFLUX_ENABLED') ? new AnalyticsData() : null; - } - - public override async login(token?: string) { - await container.workers.start(); - const loginResponse = await super.login(token); - await this.schedules.init(); - return loginResponse; - } - - public override async destroy() { - await container.workers.destroy(); - this.guildMemberFetchQueue.destroy(); - this.invites.destroy(); - this.schedules.destroy(); - return super.destroy(); - } - - /** - * Retrieves the prefix for the guild. - * @param message The message that gives context. - */ - public override fetchPrefix = async (message: Message) => { - if (isGuildMessage(message)) { - return (await readSettings(message.guild)).prefix; - } - return [process.env.CLIENT_PREFIX, ''] as readonly string[]; - }; - - /** - * Retrieves the language key for the message. - * @param message The message that gives context. - */ - public fetchLanguage = async (message: InternationalizationContext) => { - return message.guild ? (await readSettings(message.guild)).language : 'en-US'; - }; -} diff --git a/src/lib/api/ApiTransformers.ts b/src/lib/api/ApiTransformers.ts deleted file mode 100644 index a633eab12..000000000 --- a/src/lib/api/ApiTransformers.ts +++ /dev/null @@ -1,365 +0,0 @@ -import { - isDMChannel, - isGuildBasedChannelByGuildKey, - isNewsChannel, - isTextChannel, - isThreadChannel, - isVoiceChannel -} from '@sapphire/discord.js-utilities'; -import type { - Channel, - ChannelType, - DMChannel, - Guild, - GuildChannel, - GuildMember, - NewsChannel, - PermissionOverwrites, - Role, - TextChannel, - ThreadChannel, - ThreadChannelType, - User, - VoiceChannel -} from 'discord.js'; - -// #region Guild - -export function flattenGuild(guild: Guild): FlattenedGuild { - return { - afkChannelId: guild.afkChannelId, - afkTimeout: guild.afkTimeout, - applicationId: guild.applicationId, - approximateMemberCount: guild.approximateMemberCount, - approximatePresenceCount: guild.approximatePresenceCount, - available: guild.available, - banner: guild.banner, - channels: guild.channels.cache.map(flattenChannel) as FlattenedGuildChannel[], - defaultMessageNotifications: guild.defaultMessageNotifications, - description: guild.description, - widgetEnabled: guild.widgetEnabled, - explicitContentFilter: guild.explicitContentFilter, - features: guild.features, - icon: guild.icon, - id: guild.id, - joinedTimestamp: guild.joinedTimestamp, - mfaLevel: guild.mfaLevel, - name: guild.name, - ownerId: guild.ownerId, - partnered: guild.partnered, - preferredLocale: guild.preferredLocale, - premiumSubscriptionCount: guild.premiumSubscriptionCount, - premiumTier: guild.premiumTier, - roles: guild.roles.cache.map(flattenRole), - splash: guild.splash, - systemChannelId: guild.systemChannelId, - vanityURLCode: guild.vanityURLCode, - verificationLevel: guild.verificationLevel, - verified: guild.verified - }; -} - -export interface FlattenedGuild extends Pick< - Guild, - | 'afkChannelId' - | 'afkTimeout' - | 'applicationId' - | 'approximateMemberCount' - | 'approximatePresenceCount' - | 'available' - | 'banner' - | 'defaultMessageNotifications' - | 'description' - | 'widgetEnabled' - | 'explicitContentFilter' - | 'features' - | 'icon' - | 'id' - | 'joinedTimestamp' - | 'mfaLevel' - | 'name' - | 'ownerId' - | 'partnered' - | 'preferredLocale' - | 'premiumSubscriptionCount' - | 'premiumTier' - | 'splash' - | 'systemChannelId' - | 'vanityURLCode' - | 'verificationLevel' - | 'verified' -> { - channels: FlattenedGuildChannel[]; - - roles: FlattenedRole[]; -} - -// #endregion Guild - -// #region Role - -export function flattenRole(role: Role): FlattenedRole { - return { - id: role.id, - guildId: role.guild.id, - name: role.name, - color: role.color, - hoist: role.hoist, - rawPosition: role.rawPosition, - permissions: role.permissions.bitfield.toString(), - managed: role.managed, - mentionable: role.mentionable - }; -} - -export interface FlattenedRole { - color: number; - - guildId: string; - - hoist: boolean; - - id: string; - - managed: boolean; - - mentionable: boolean; - - name: string; - - permissions: string; - - rawPosition: number; -} - -// #endregion Role - -// #region Channel - -export function flattenChannel(channel: NewsChannel): FlattenedNewsChannel; -export function flattenChannel(channel: TextChannel): FlattenedTextChannel; -export function flattenChannel(channel: VoiceChannel): FlattenedVoiceChannel; -export function flattenChannel(channel: DMChannel): FlattenedDMChannel; -export function flattenChannel(channel: ThreadChannel): FlattenedThreadChannel; -export function flattenChannel(channel: Channel): FlattenedChannel; -export function flattenChannel(channel: Channel | ThreadChannel) { - if (isThreadChannel(channel)) return flattenChannelThread(channel as ThreadChannel); - if (isNewsChannel(channel)) return flattenChannelNews(channel as NewsChannel); - if (isTextChannel(channel)) return flattenChannelText(channel as TextChannel); - if (isVoiceChannel(channel)) return flattenChannelVoice(channel as VoiceChannel); - if (isGuildBasedChannelByGuildKey(channel)) return flattenChannelGuild(channel as GuildChannel); - if (isDMChannel(channel)) return flattenChannelDM(channel as DMChannel); - return flattenChannelFallback(channel); -} - -function flattenChannelNews(channel: NewsChannel): FlattenedNewsChannel { - return { - id: channel.id, - type: channel.type, - guildId: channel.guild.id, - name: channel.name, - rawPosition: channel.rawPosition, - parentId: channel.parentId, - permissionOverwrites: [...channel.permissionOverwrites.cache.entries()], - topic: channel.topic, - nsfw: channel.nsfw, - createdTimestamp: channel.createdTimestamp - }; -} - -function flattenChannelText(channel: TextChannel): FlattenedTextChannel { - return { - id: channel.id, - type: channel.type as FlattenedTextChannel['type'], - guildId: channel.guild.id, - name: channel.name, - rawPosition: channel.rawPosition, - parentId: channel.parentId, - permissionOverwrites: [...channel.permissionOverwrites.cache.entries()], - topic: channel.topic, - nsfw: channel.nsfw, - rateLimitPerUser: channel.rateLimitPerUser, - createdTimestamp: channel.createdTimestamp - }; -} - -function flattenChannelVoice(channel: VoiceChannel): FlattenedVoiceChannel { - return { - id: channel.id, - type: channel.type as FlattenedVoiceChannel['type'], - guildId: channel.guild.id, - name: channel.name, - rawPosition: channel.rawPosition, - parentId: channel.parentId, - permissionOverwrites: [...channel.permissionOverwrites.cache.entries()], - bitrate: channel.bitrate, - userLimit: channel.userLimit, - createdTimestamp: channel.createdTimestamp - }; -} - -function flattenChannelGuild(channel: GuildChannel): FlattenedGuildChannel { - return { - id: channel.id, - type: channel.type as FlattenedGuildChannel['type'], - guildId: channel.guild.id, - name: channel.name, - rawPosition: channel.rawPosition, - parentId: channel.parentId, - permissionOverwrites: [...channel.permissionOverwrites.cache.entries()], - createdTimestamp: channel.createdTimestamp - }; -} - -function flattenChannelDM(channel: DMChannel): FlattenedDMChannel { - return { - id: channel.id, - type: channel.type as FlattenedDMChannel['type'], - recipient: channel.recipient?.id ?? null, - createdTimestamp: channel.createdTimestamp ?? 0 - }; -} - -function flattenChannelThread(channel: ThreadChannel): FlattenedThreadChannel { - return { - id: channel.id, - type: channel.type, - archived: channel.archived ?? false, - archivedTimestamp: channel.archiveTimestamp, - createdTimestamp: channel.createdTimestamp ?? 0, - guildId: channel.guildId, - name: channel.name, - parentId: channel.parentId, - permissionOverwrites: [...(channel.parent?.permissionOverwrites.cache.entries() ?? [])], - rawPosition: channel.parent?.rawPosition ?? null, - rateLimitPerUser: channel.rateLimitPerUser - }; -} - -function flattenChannelFallback(channel: Channel): FlattenedChannel { - return { - id: channel.id, - type: channel.type as FlattenedChannel['type'], - createdTimestamp: channel.createdTimestamp ?? 0 - }; -} - -export interface FlattenedChannel { - id: string; - type: ChannelType; - createdTimestamp: number; -} - -export interface FlattenedGuildChannel extends FlattenedChannel { - type: ChannelType; - guildId: string; - name: string; - parentId: string | null; - permissionOverwrites: [string, PermissionOverwrites][]; - rawPosition: number; -} - -export interface FlattenedNewsChannel extends FlattenedGuildChannel { - type: ChannelType.GuildAnnouncement; - nsfw: boolean; - topic: string | null; -} - -export interface FlattenedTextChannel extends FlattenedGuildChannel { - type: ChannelType.GuildText; - nsfw: boolean; - rateLimitPerUser: number; - topic: string | null; -} - -export interface FlattenedThreadChannel extends Pick { - type: ThreadChannelType; - archived: boolean; - archivedTimestamp: number | null; - guildId: string; - name: string; - parentId: string | null; - permissionOverwrites: [string, PermissionOverwrites][]; - rateLimitPerUser: number | null; - rawPosition: number | null; -} - -export interface FlattenedNewsThreadChannel extends FlattenedChannel { - type: ChannelType.AnnouncementThread; -} - -export interface FlattenedPublicThreadChannel extends FlattenedChannel { - type: ChannelType.PublicThread; -} - -export interface FlattenedPrivateThreadChannel extends FlattenedChannel { - type: ChannelType.PrivateThread; -} - -export interface FlattenedVoiceChannel extends FlattenedGuildChannel { - type: ChannelType.GuildVoice; - bitrate: number; - userLimit: number; -} - -export interface FlattenedDMChannel extends FlattenedChannel { - type: ChannelType.DM; - recipient: string | null; -} - -// #endregion Channel - -// #region User - -export function flattenUser(user: User): FlattenedUser { - return { - id: user.id, - bot: user.bot, - username: user.username, - discriminator: user.discriminator, - avatar: user.avatar - }; -} - -export interface FlattenedUser { - avatar: string | null; - - bot: boolean; - - discriminator: string; - - id: string; - - username: string; -} - -// #endregion User - -// #region Member - -export function flattenMember(member: GuildMember): FlattenedMember { - return { - id: member.id, - guildId: member.guild.id, - user: flattenUser(member.user), - joinedTimestamp: member.joinedTimestamp, - premiumSinceTimestamp: member.premiumSinceTimestamp, - roles: member.roles.cache.map(flattenRole) - }; -} - -export interface FlattenedMember { - guildId: string; - - id: string; - - joinedTimestamp: number | null; - - premiumSinceTimestamp: number | null; - - roles: FlattenedRole[]; - - user: FlattenedUser; -} - -// #endregion Member diff --git a/src/lib/api/types.ts b/src/lib/api/types.ts deleted file mode 100644 index b0e41488d..000000000 --- a/src/lib/api/types.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { FlattenedGuild, FlattenedUser } from '#lib/api/ApiTransformers'; -import type { LoginData } from '@sapphire/plugin-api'; - -export interface PartialOauthFlattenedGuild extends Omit { - joinedTimestamp: FlattenedGuild['joinedTimestamp'] | null; - ownerId: FlattenedGuild['ownerId'] | null; -} - -export interface OauthFlattenedGuild extends PartialOauthFlattenedGuild { - permissions: string; - manageable: boolean; - wolfstarIsIn: boolean; -} - -export interface OauthFlattenedUser { - user: FlattenedUser; - guilds: OauthFlattenedGuild[]; -} - -export interface TransformedLoginData extends LoginData { - transformedGuilds?: OauthFlattenedGuild[]; -} diff --git a/src/lib/api/utils.ts b/src/lib/api/utils.ts deleted file mode 100644 index 49a192c43..000000000 --- a/src/lib/api/utils.ts +++ /dev/null @@ -1,140 +0,0 @@ -import { flattenGuild } from '#lib/api/ApiTransformers'; -import type { OauthFlattenedGuild, PartialOauthFlattenedGuild, TransformedLoginData } from '#lib/api/types'; -import { readSettings, readSettingsPermissionNodes } from '#lib/database/settings'; -import type { WolfCommand } from '#lib/structures'; -import { PermissionsBits } from '#lib/util/bits'; -import { createFunctionPrecondition } from '@sapphire/decorators'; -import { container } from '@sapphire/framework'; -import { ApiRequest, ApiResponse, HttpCodes, type LoginData } from '@sapphire/plugin-api'; -import { RateLimitManager } from '@sapphire/ratelimits'; -import { hasAtLeastOneKeyInMap } from '@sapphire/utilities'; -import { - GuildDefaultMessageNotifications, - GuildExplicitContentFilter, - GuildMFALevel, - GuildPremiumTier, - GuildVerificationLevel, - Locale, - PermissionFlagsBits, - type Client, - type Guild, - type GuildMember, - type RESTAPIPartialCurrentUserGuild -} from 'discord.js'; - -function isAdmin(member: GuildMember, roles: readonly string[]): boolean { - return roles.length === 0 ? member.permissions.has(PermissionFlagsBits.ManageGuild) : hasAtLeastOneKeyInMap(member.roles.cache, roles); -} - -export const authenticated = () => - createFunctionPrecondition( - (request: ApiRequest) => Boolean(request.auth?.token), - (_request: ApiRequest, response: ApiResponse) => response.error(HttpCodes.Unauthorized) - ); - -/** - * @param time The amount of milliseconds for the ratelimits from this manager to expire. - * @param limit The amount of times a {@link RateLimit} can drip before it's limited. - * @param auth Whether or not this should be auth-limited - */ -export function ratelimit(time: number, limit = 1, auth = false) { - const manager = new RateLimitManager(time, limit); - const xRateLimitLimit = time; - return createFunctionPrecondition( - (request: ApiRequest, response: ApiResponse) => { - const id = (auth ? request.auth!.id : request.headers['x-forwarded-for'] || request.socket.remoteAddress) as string; - const bucket = manager.acquire(id); - - response.setHeader('Date', new Date().toUTCString()); - if (bucket.limited) { - response.setHeader('Retry-After', bucket.remainingTime.toString()); - return false; - } - - try { - bucket.consume(); - } catch {} - - response.setHeader('X-RateLimit-Limit', xRateLimitLimit); - response.setHeader('X-RateLimit-Remaining', bucket.remaining.toString()); - response.setHeader('X-RateLimit-Reset', bucket.remainingTime.toString()); - - return true; - }, - (_request: ApiRequest, response: ApiResponse) => { - response.error(HttpCodes.TooManyRequests); - } - ); -} - -export async function canManage(guild: Guild, member: GuildMember): Promise { - if (guild.ownerId === member.id) return true; - - const settings = await readSettings(guild); - const nodes = readSettingsPermissionNodes(settings); - return isAdmin(member, settings.rolesAdmin) && (nodes.run(member, container.stores.get('commands').get('conf') as WolfCommand) ?? true); -} - -async function getManageable(id: string, oauthGuild: RESTAPIPartialCurrentUserGuild, guild: Guild | undefined): Promise { - if (oauthGuild.owner) return true; - if (typeof guild === 'undefined') return PermissionsBits.has(BigInt(oauthGuild.permissions), PermissionFlagsBits.ManageGuild); - - const member = await guild.members.fetch(id).catch(() => null); - if (!member) return false; - - return canManage(guild, member); -} - -async function transformGuild(client: Client, userId: string, data: RESTAPIPartialCurrentUserGuild): Promise { - const guild = client.guilds.cache.get(data.id); - const serialized: PartialOauthFlattenedGuild = - typeof guild === 'undefined' - ? { - afkChannelId: null, - afkTimeout: 0, - applicationId: null, - approximateMemberCount: null, - approximatePresenceCount: null, - available: true, - banner: null, - channels: [], - defaultMessageNotifications: GuildDefaultMessageNotifications.OnlyMentions, - description: null, - widgetEnabled: false, - explicitContentFilter: GuildExplicitContentFilter.Disabled, - icon: data.icon, - id: data.id, - joinedTimestamp: null, - mfaLevel: GuildMFALevel.None, - name: data.name, - ownerId: data.owner ? userId : null, - partnered: false, - preferredLocale: Locale.EnglishUS, - premiumSubscriptionCount: null, - premiumTier: GuildPremiumTier.None, - roles: [], - splash: null, - systemChannelId: null, - vanityURLCode: null, - verificationLevel: GuildVerificationLevel.None, - verified: false - } - : flattenGuild(guild); - - return { - ...serialized, - permissions: data.permissions, - manageable: await getManageable(userId, data, guild), - wolfstarIsIn: typeof guild !== 'undefined' - }; -} - -export async function transformOauthGuildsAndUser({ user, guilds }: LoginData): Promise { - if (!user || !guilds) return { user, guilds }; - - const { client } = container; - const userId = user.id; - - const transformedGuilds = await Promise.all(guilds.map((guild) => transformGuild(client, userId, guild))); - return { user, transformedGuilds }; -} diff --git a/src/lib/database/index.ts b/src/lib/database/index.ts deleted file mode 100644 index 0402d7766..000000000 --- a/src/lib/database/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from '#lib/database/settings'; -export * from '#lib/database/utils/matchers/index'; diff --git a/src/lib/database/settings/Utils.ts b/src/lib/database/settings/Utils.ts deleted file mode 100644 index 4b365cba4..000000000 --- a/src/lib/database/settings/Utils.ts +++ /dev/null @@ -1,65 +0,0 @@ -import type { ISchemaValue } from '#lib/database/settings/base/ISchemaValue'; -import type { SchemaGroup } from '#lib/database/settings/schema/SchemaGroup'; -import type { SchemaKey } from '#lib/database/settings/schema/SchemaKey'; -import type { GuildData, ReadonlyGuildData } from '#lib/database/settings/types'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import type { WolfArgs } from '#lib/structures'; -import { UserError } from '@sapphire/framework'; - -export function isSchemaGroup(groupOrKey: ISchemaValue): groupOrKey is SchemaGroup { - return groupOrKey.type === 'Group'; -} - -export function isSchemaKey(groupOrKey: ISchemaValue): groupOrKey is SchemaKey { - return groupOrKey.type !== 'Group'; -} - -export async function set(settings: ReadonlyGuildData, key: SchemaKey, args: WolfArgs): Promise> { - const parsed = await key.parse(settings, args); - const { serializer } = key; - - if (key.array) { - const values = settings[key.property] as any[]; - const index = values.findIndex((value) => serializer.equals(value, parsed)); - - return index === -1 // - ? { [key.property]: values.concat(parsed) } - : { [key.property]: values.with(index, parsed) }; - } - - if (serializer.equals(settings[key.property], parsed)) { - throw new UserError({ - identifier: LanguageKeys.Settings.Gateway.DuplicateValue, - context: { - path: key.name, - value: key.stringify(settings, args.t, parsed) - } - }); - } - - return { [key.property]: parsed }; -} - -export async function remove(settings: ReadonlyGuildData, key: SchemaKey, args: WolfArgs): Promise> { - const parsed = await key.parse(settings, args); - if (key.array) { - const { serializer } = key; - const values = settings[key.property] as any[]; - - const index = values.findIndex((value) => serializer.equals(value, parsed)); - if (index === -1) { - throw new UserError({ - identifier: LanguageKeys.Settings.Gateway.MissingValue, - context: { path: key.name, value: key.stringify(settings, args.t, parsed) } - }); - } - - return { [key.property]: values.toSpliced(index, 1) }; - } - - return { [key.property]: key.default }; -} - -export function reset(key: SchemaKey): Partial { - return { [key.property]: key.default }; -} diff --git a/src/lib/database/settings/auditActions.ts b/src/lib/database/settings/auditActions.ts deleted file mode 100644 index bd787443a..000000000 --- a/src/lib/database/settings/auditActions.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { DashboardAuditAction } from '#lib/database/settings/types'; - -export const DASHBOARD_AUDIT_ACTIONS = [ - 'guild.settings.update', - 'guild.settings.access-denied', - 'guild.settings.add', - 'guild.settings.remove', - 'guild.command.execute' -] as const satisfies readonly DashboardAuditAction[]; - -export const guildSettingsUpdate = 'guild.settings.update' satisfies DashboardAuditAction; -export const guildSettingsAdd = 'guild.settings.add' satisfies DashboardAuditAction; -export const guildSettingsRemove = 'guild.settings.remove' satisfies DashboardAuditAction; -export const guildSettingsAccessDenied = 'guild.settings.access-denied' satisfies DashboardAuditAction; -export const guildCommandExecute = 'guild.command.execute' satisfies DashboardAuditAction; diff --git a/src/lib/database/settings/base/ISchemaValue.ts b/src/lib/database/settings/base/ISchemaValue.ts deleted file mode 100644 index 2776ae06e..000000000 --- a/src/lib/database/settings/base/ISchemaValue.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { SchemaGroup } from '#lib/database/settings/schema/SchemaGroup'; -import type { ReadonlyGuildData } from '#lib/database/settings/types'; -import type { TFunction } from '@sapphire/plugin-i18next'; - -export interface ISchemaValue { - readonly type: string; - readonly name: string; - readonly dashboardOnly: boolean; - readonly parent: SchemaGroup | null; - display(settings: ReadonlyGuildData, language: TFunction): string; -} diff --git a/src/lib/database/settings/configuration.ts b/src/lib/database/settings/configuration.ts deleted file mode 100644 index 64c526698..000000000 --- a/src/lib/database/settings/configuration.ts +++ /dev/null @@ -1,1051 +0,0 @@ -import { SchemaGroup, type NonEmptyArray } from '#lib/database/settings/schema/SchemaGroup'; -import { SchemaKey, type ConfigurableKeyValueOptions } from '#lib/database/settings/schema/SchemaKey'; -import type { GuildDataKey } from '#lib/database/settings/types'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { years } from '#utils/common'; -import { objectEntries } from '@sapphire/utilities'; -import { envParseString } from '@skyra/env-utilities'; -import { Collection } from 'discord.js'; - -export type SchemaDataKey = Exclude; - -const configurableKeys = new Collection(); -const configurableGroups = new SchemaGroup('::ROOT::'); - -export function getConfigurableKeys(): Collection { - getConfiguration(); - return configurableKeys; -} - -export function getConfigurableGroups(): SchemaGroup { - getConfiguration(); - return configurableGroups; -} - -let cachedConfiguration: Record | null = null; -export function getConfiguration() { - cachedConfiguration ??= makeKeys({ - prefix: { - type: 'string', - description: LanguageKeys.Settings.Prefix, - minimum: 1, - maximum: 10, - default: envParseString('CLIENT_PREFIX') - }, - language: { - type: 'language', - description: LanguageKeys.Settings.Language, - default: 'en-US' - }, - disableNaturalPrefix: { - name: 'disable-natural-prefix', - type: 'boolean', - description: LanguageKeys.Settings.DisableNaturalPrefix, - default: false - }, - disabledCommands: { - name: 'disabled-commands', - // @ts-expect-error Serializer 'commandmatch' exists but is not camel cased. - type: 'commandmatch', - description: LanguageKeys.Settings.DisabledCommands, - maximum: 32, - array: true - }, - permissionsUsers: { - type: 'permissionNode', - name: 'permissions.users', - description: LanguageKeys.Settings.DashboardOnlyKey, - array: true, - dashboardOnly: true - }, - permissionsRoles: { - type: 'permissionNode', - name: 'permissions.roles', - description: LanguageKeys.Settings.DashboardOnlyKey, - array: true, - dashboardOnly: true - }, - channelsMediaOnly: { - type: 'guildTextChannel', - name: 'channels.media-only', - description: LanguageKeys.Settings.Channels.MediaOnly, - array: true - }, - channelsLogsModeration: { - type: 'guildTextChannel', - name: 'channels.logs.moderation', - description: LanguageKeys.Settings.Channels.Logs.Moderation - }, - channelsLogsImage: { - type: 'guildTextChannel', - name: 'channels.logs.image', - description: LanguageKeys.Settings.Channels.Logs.Image - }, - channelsLogsMemberAdd: { - type: 'guildTextChannel', - name: 'channels.logs.member-add', - description: LanguageKeys.Settings.Channels.Logs.MemberAdd - }, - channelsLogsMemberRemove: { - type: 'guildTextChannel', - name: 'channels.logs.member-remove', - description: LanguageKeys.Settings.Channels.Logs.MemberRemove - }, - channelsLogsMemberNicknameUpdate: { - type: 'guildTextChannel', - name: 'channels.logs.member-nickname-update', - description: LanguageKeys.Settings.Channels.Logs.MemberNickNameUpdate - }, - channelsLogsMemberUsernameUpdate: { - type: 'guildTextChannel', - name: 'channels.logs.member-username-update', - description: LanguageKeys.Settings.Channels.Logs.MemberUserNameUpdate - }, - channelsLogsMemberRolesUpdate: { - type: 'guildTextChannel', - name: 'channels.logs.member-roles-update', - description: LanguageKeys.Settings.Channels.Logs.MemberRoleUpdate - }, - channelsLogsMessageDelete: { - type: 'guildTextChannel', - name: 'channels.logs.message-delete', - description: LanguageKeys.Settings.Channels.Logs.MessageDelete - }, - channelsLogsMessageDeleteNsfw: { - type: 'guildTextChannel', - name: 'channels.logs.message-delete-nsfw', - description: LanguageKeys.Settings.Channels.Logs.MessageDeleteNsfw - }, - channelsLogsMessageUpdate: { - type: 'guildTextChannel', - name: 'channels.logs.message-update', - description: LanguageKeys.Settings.Channels.Logs.MessageUpdate - }, - channelsLogsMessageUpdateNsfw: { - type: 'guildTextChannel', - name: 'channels.logs.message-update-nsfw', - description: LanguageKeys.Settings.Channels.Logs.MessageUpdateNsfw - }, - channelsLogsPrune: { - type: 'guildTextChannel', - name: 'channels.logs.prune', - description: LanguageKeys.Settings.Channels.Logs.Prune - }, - channelsLogsReaction: { - type: 'guildTextChannel', - name: 'channels.logs.reaction', - description: LanguageKeys.Settings.Channels.Logs.Reaction - }, - channelsLogsRoleCreate: { - type: 'guildTextChannel', - name: 'channels.logs.role-create', - description: LanguageKeys.Settings.Channels.Logs.RoleCreate - }, - channelsLogsRoleUpdate: { - type: 'guildTextChannel', - name: 'channels.logs.role-update', - description: LanguageKeys.Settings.Channels.Logs.RoleUpdate - }, - channelsLogsRoleDelete: { - type: 'guildTextChannel', - name: 'channels.logs.role-delete', - description: LanguageKeys.Settings.Channels.Logs.RoleDelete - }, - channelsLogsChannelCreate: { - type: 'guildTextChannel', - name: 'channels.logs.channel-create', - description: LanguageKeys.Settings.Channels.Logs.ChannelCreate - }, - channelsLogsChannelUpdate: { - type: 'guildTextChannel', - name: 'channels.logs.channel-update', - description: LanguageKeys.Settings.Channels.Logs.ChannelUpdate - }, - channelsLogsChannelDelete: { - type: 'guildTextChannel', - name: 'channels.logs.channel-delete', - description: LanguageKeys.Settings.Channels.Logs.ChannelDelete - }, - channelsLogsEmojiCreate: { - type: 'guildTextChannel', - name: 'channels.logs.emoji-create', - description: LanguageKeys.Settings.Channels.Logs.EmojiCreate - }, - channelsLogsEmojiUpdate: { - type: 'guildTextChannel', - name: 'channels.logs.emoji-update', - description: LanguageKeys.Settings.Channels.Logs.EmojiUpdate - }, - channelsLogsEmojiDelete: { - type: 'guildTextChannel', - name: 'channels.logs.emoji-delete', - description: LanguageKeys.Settings.Channels.Logs.EmojiDelete - }, - channelsLogsServerUpdate: { - type: 'guildTextChannel', - name: 'channels.logs.server-update', - description: LanguageKeys.Settings.Channels.Logs.ServerUpdate - }, - channelsLogsVoiceChannel: { - type: 'guildTextChannel', - name: 'channels.logs.voice-activity', - description: LanguageKeys.Settings.Channels.Logs.VoiceActivity - }, - channelsLogsCommand: { - type: 'guildTextChannel', - name: 'channels.logs.audit.command', - description: LanguageKeys.Settings.Channels.Logs.Command - }, - channelsLogsSettings: { - type: 'guildTextChannel', - name: 'channels.logs.audit.settings', - description: LanguageKeys.Settings.Channels.Logs.Settings - }, - channelsIgnoreAll: { - type: 'guildTextChannel', - name: 'channels.ignore.all', - description: LanguageKeys.Settings.Channels.Ignore.All, - array: true - }, - channelsIgnoreMessageEdit: { - type: 'guildTextChannel', - name: 'channels.ignore.message-edit', - description: LanguageKeys.Settings.Channels.Ignore.MessageEdit, - array: true - }, - channelsIgnoreMessageDelete: { - type: 'guildTextChannel', - name: 'channels.ignore.message-delete', - description: LanguageKeys.Settings.Channels.Ignore.MessageDelete, - array: true - }, - channelsIgnoreReactionAdd: { - type: 'guildTextChannel', - name: 'channels.ignore.reaction-add', - description: LanguageKeys.Settings.Channels.Ignore.ReactionAdd, - array: true - }, - channelsIgnoreVoiceActivity: { - type: 'guildVoiceChannel', - name: 'channels.ignore.voice-activity', - description: LanguageKeys.Settings.Channels.Ignore.VoiceActivity, - array: true - }, - commandAutoDelete: { - type: 'notAllowed', - name: 'command-auto-delete', - description: LanguageKeys.Settings.DashboardOnlyKey, - array: true, - dashboardOnly: true - }, - disabledChannels: { - type: 'guildTextChannel', - name: 'disabled-channels', - description: LanguageKeys.Settings.DisabledChannels, - array: true - }, - disabledCommandsChannels: { - type: 'notAllowed', - name: 'disabled-commands-channels', - description: LanguageKeys.Settings.DashboardOnlyKey, - array: true, - dashboardOnly: true - }, - eventsBanAdd: { - type: 'boolean', - name: 'events.ban-add', - description: LanguageKeys.Settings.EventsBanAdd - }, - eventsBanRemove: { - type: 'boolean', - name: 'events.ban-remove', - description: LanguageKeys.Settings.EventsBanRemove - }, - eventsTimeout: { - type: 'boolean', - name: 'events.timeout', - description: LanguageKeys.Settings.EventsTimeout - }, - eventsUnknownMessages: { - type: 'boolean', - name: 'events.unknown-messages', - description: LanguageKeys.Settings.EventsUnknownMessages - }, - eventsTwemojiReactions: { - type: 'boolean', - name: 'events.twemoji-reactions', - description: LanguageKeys.Settings.EventsTwemojiReactions - }, - eventsIncludeBots: { - type: 'boolean', - name: 'events.include-bots', - description: LanguageKeys.Settings.EventsIncludeBots - }, - messagesIgnoreChannels: { - type: 'guildTextChannel', - name: 'messages.ignore-channels', - description: LanguageKeys.Settings.MessagesIgnoreChannels, - array: true - }, - messagesModerationDm: { - type: 'boolean', - name: 'messages.moderation-dm', - description: LanguageKeys.Settings.MessagesModerationDM - }, - messagesModerationReasonDisplay: { - type: 'boolean', - name: 'messages.moderation-reason-display', - description: LanguageKeys.Settings.MessagesModerationReasonDisplay, - default: true - }, - messagesModerationMessageDisplay: { - type: 'boolean', - name: 'messages.moderation-message-display', - description: LanguageKeys.Settings.MessagesModerationMessageDisplay, - default: true - }, - messagesModerationAutoDelete: { - type: 'boolean', - name: 'messages.moderation-auto-delete', - description: LanguageKeys.Settings.MessagesModerationAutoDelete, - default: false - }, - messagesModeratorNameDisplay: { - type: 'boolean', - name: 'messages.moderator-name-display', - description: LanguageKeys.Settings.MessagesModeratorNameDisplay, - default: true - }, - messagesAutoDeleteIgnoredAll: { - type: 'boolean', - name: 'messages.auto-delete.ignored-all', - description: LanguageKeys.Settings.MessagesAutoDeleteIgnoredAll, - default: false - }, - messagesAutoDeleteIgnoredRoles: { - type: 'role', - name: 'messages.auto-delete.ignored-roles', - description: LanguageKeys.Settings.MessagesAutoDeleteIgnoredRoles, - array: true - }, - messagesAutoDeleteIgnoredChannels: { - type: 'guildTextChannel', - name: 'messages.auto-delete.ignored-channels', - description: LanguageKeys.Settings.MessagesAutoDeleteIgnoredChannels, - array: true - }, - messagesAutoDeleteIgnoredCommands: { - // @ts-expect-error Serializer 'commandmatch' exists but is not camel cased. - type: 'commandmatch', - name: 'messages.auto-delete.ignored-commands', - description: LanguageKeys.Settings.MessagesAutoDeleteIgnoredCommands, - array: true - }, - stickyRoles: { - type: 'notAllowed', - name: 'sticky-roles', - description: LanguageKeys.Settings.DashboardOnlyKey, - array: true, - dashboardOnly: true - }, - reactionRoles: { - type: 'notAllowed', - name: 'reaction-roles', - description: LanguageKeys.Settings.DashboardOnlyKey, - array: true, - dashboardOnly: true - }, - rolesAdmin: { - type: 'role', - name: 'roles.admin', - description: LanguageKeys.Settings.RolesAdmin, - array: true - }, - rolesInitial: { - type: 'role', - name: 'roles.initial', - description: LanguageKeys.Settings.RolesInitial - }, - rolesInitialHumans: { - type: 'role', - name: 'roles.initial-humans', - description: LanguageKeys.Settings.RolesInitialHumans - }, - rolesInitialBots: { - type: 'role', - name: 'roles.initial-bots', - description: LanguageKeys.Settings.RolesInitialBots - }, - rolesModerator: { - type: 'role', - name: 'roles.moderator', - description: LanguageKeys.Settings.RolesModerator, - array: true - }, - rolesMuted: { - type: 'role', - name: 'roles.muted', - description: LanguageKeys.Settings.RolesMuted - }, - rolesRestrictedAttachment: { - type: 'role', - name: 'roles.restricted-attachment', - description: LanguageKeys.Settings.RolesRestrictedAttachment - }, - rolesRestrictedReaction: { - type: 'role', - name: 'roles.restricted-reaction', - description: LanguageKeys.Settings.RolesRestrictedReaction - }, - rolesRestrictedEmbed: { - type: 'role', - name: 'roles.restricted-embed', - description: LanguageKeys.Settings.RolesRestrictedEmbed - }, - rolesRestrictedEmoji: { - type: 'role', - name: 'roles.restricted-emoji', - description: LanguageKeys.Settings.RolesRestrictedEmoji - }, - rolesRestrictedVoice: { - type: 'role', - name: 'roles.restricted-voice', - description: LanguageKeys.Settings.RolesRestrictedVoice - }, - rolesPublic: { - type: 'role', - name: 'roles.public', - description: LanguageKeys.Settings.RolesPublic, - array: true - }, - rolesRemoveInitial: { - type: 'boolean', - name: 'roles.remove-initial', - description: LanguageKeys.Settings.RolesRemoveInitial, - default: false - }, - rolesUniqueRoleSets: { - type: 'notAllowed', - name: 'roles.unique-role-sets', - description: LanguageKeys.Settings.DashboardOnlyKey, - array: true, - dashboardOnly: true - }, - selfmodAttachmentsEnabled: { - type: 'boolean', - name: 'selfmod.attachments.enabled', - description: LanguageKeys.Settings.SelfmodAttachmentsEnabled, - default: false - }, - selfmodAttachmentsIgnoredRoles: { - type: 'role', - name: 'selfmod.attachments.ignored-roles', - description: LanguageKeys.Settings.SelfmodAttachmentsIgnoredRoles, - array: true - }, - selfmodAttachmentsIgnoredChannels: { - type: 'guildTextChannel', - name: 'selfmod.attachments.ignored-channels', - description: LanguageKeys.Settings.SelfmodAttachmentsIgnoredChannels, - array: true - }, - selfmodAttachmentsSoftAction: { - type: 'integer', - name: 'selfmod.attachments.soft-action', - description: LanguageKeys.Settings.DashboardOnlyKey, - default: 0, - dashboardOnly: true - }, - selfmodAttachmentsHardAction: { - type: 'integer', - name: 'selfmod.attachments.hard-action', - description: LanguageKeys.Settings.DashboardOnlyKey, - default: 0, - dashboardOnly: true - }, - selfmodAttachmentsHardActionDuration: { - type: 'timespan', - name: 'selfmod.attachments.hard-action-duration', - description: LanguageKeys.Settings.DashboardOnlyKey, - minimum: 0, - maximum: years(5), - dashboardOnly: true - }, - selfmodAttachmentsThresholdMaximum: { - type: 'integer', - name: 'selfmod.attachments.threshold-maximum', - description: LanguageKeys.Settings.DashboardOnlyKey, - minimum: 0, - maximum: 100, - default: 10, - dashboardOnly: true - }, - selfmodAttachmentsThresholdDuration: { - type: 'timespan', - name: 'selfmod.attachments.threshold-duration', - description: LanguageKeys.Settings.DashboardOnlyKey, - minimum: 0, - maximum: years(5), - default: 60000, - dashboardOnly: true - }, - selfmodCapitalsEnabled: { - type: 'boolean', - name: 'selfmod.capitals.enabled', - description: LanguageKeys.Settings.SelfmodCapitalsEnabled, - default: false - }, - selfmodCapitalsIgnoredRoles: { - type: 'role', - name: 'selfmod.capitals.ignored-roles', - description: LanguageKeys.Settings.SelfmodCapitalsIgnoredRoles, - array: true - }, - selfmodCapitalsIgnoredChannels: { - type: 'guildTextChannel', - name: 'selfmod.capitals.ignored-channels', - description: LanguageKeys.Settings.SelfmodCapitalsIgnoredChannels, - array: true - }, - selfmodCapitalsMinimum: { - type: 'integer', - name: 'selfmod.capitals.minimum', - description: LanguageKeys.Settings.SelfmodCapitalsMinimum, - minimum: 5, - maximum: 2000, - default: 15 - }, - selfmodCapitalsMaximum: { - type: 'integer', - name: 'selfmod.capitals.maximum', - description: LanguageKeys.Settings.SelfmodCapitalsMaximum, - minimum: 10, - maximum: 100, - default: 50 - }, - selfmodCapitalsSoftAction: { - type: 'integer', - name: 'selfmod.capitals.soft-action', - description: LanguageKeys.Settings.DashboardOnlyKey, - default: 0, - dashboardOnly: true - }, - selfmodCapitalsHardAction: { - type: 'integer', - name: 'selfmod.capitals.hard-action', - description: LanguageKeys.Settings.DashboardOnlyKey, - default: 0, - dashboardOnly: true - }, - selfmodCapitalsHardActionDuration: { - type: 'timespan', - name: 'selfmod.capitals.hard-action-duration', - description: LanguageKeys.Settings.DashboardOnlyKey, - minimum: 0, - maximum: years(5), - dashboardOnly: true - }, - selfmodCapitalsThresholdMaximum: { - type: 'integer', - name: 'selfmod.capitals.threshold-maximum', - description: LanguageKeys.Settings.DashboardOnlyKey, - minimum: 0, - maximum: 100, - default: 10, - dashboardOnly: true - }, - selfmodCapitalsThresholdDuration: { - type: 'timespan', - name: 'selfmod.capitals.threshold-duration', - description: LanguageKeys.Settings.DashboardOnlyKey, - minimum: 0, - maximum: years(5), - default: 60000, - dashboardOnly: true - }, - selfmodLinksEnabled: { - type: 'boolean', - name: 'selfmod.links.enabled', - description: LanguageKeys.Settings.SelfmodLinksEnabled, - default: false - }, - selfmodLinksAllowed: { - type: 'string', - name: 'selfmod.links.allowed', - description: LanguageKeys.Settings.SelfmodLinksAllowed, - array: true - }, - selfmodLinksIgnoredRoles: { - type: 'role', - name: 'selfmod.links.ignored-roles', - description: LanguageKeys.Settings.SelfmodLinksIgnoredRoles, - array: true - }, - selfmodLinksIgnoredChannels: { - type: 'guildTextChannel', - name: 'selfmod.links.ignored-channels', - description: LanguageKeys.Settings.SelfmodLinksIgnoredChannels, - array: true - }, - selfmodLinksSoftAction: { - type: 'integer', - name: 'selfmod.links.soft-action', - description: LanguageKeys.Settings.DashboardOnlyKey, - default: 0, - dashboardOnly: true - }, - selfmodLinksHardAction: { - type: 'integer', - name: 'selfmod.links.hard-action', - description: LanguageKeys.Settings.DashboardOnlyKey, - default: 0, - dashboardOnly: true - }, - selfmodLinksHardActionDuration: { - type: 'timespan', - name: 'selfmod.links.hard-action-duration', - description: LanguageKeys.Settings.DashboardOnlyKey, - minimum: 0, - maximum: years(5), - dashboardOnly: true - }, - selfmodLinksThresholdMaximum: { - type: 'integer', - name: 'selfmod.links.threshold-maximum', - description: LanguageKeys.Settings.DashboardOnlyKey, - minimum: 0, - maximum: 100, - default: 10, - dashboardOnly: true - }, - selfmodLinksThresholdDuration: { - type: 'timespan', - name: 'selfmod.links.threshold-duration', - description: LanguageKeys.Settings.DashboardOnlyKey, - minimum: 0, - maximum: years(5), - default: 60000, - dashboardOnly: true - }, - selfmodMessagesEnabled: { - type: 'boolean', - name: 'selfmod.messages.enabled', - description: LanguageKeys.Settings.SelfmodMessagesEnabled, - default: false - }, - selfmodMessagesIgnoredRoles: { - type: 'role', - name: 'selfmod.messages.ignored-roles', - description: LanguageKeys.Settings.SelfmodMessagesIgnoredRoles, - array: true - }, - selfmodMessagesIgnoredChannels: { - type: 'guildTextChannel', - name: 'selfmod.messages.ignored-channels', - description: LanguageKeys.Settings.SelfmodMessagesIgnoredChannels, - array: true - }, - selfmodMessagesMaximum: { - type: 'integer', - name: 'selfmod.messages.maximum', - description: LanguageKeys.Settings.SelfmodMessagesMaximum, - minimum: 2, - maximum: 100, - default: 5 - }, - selfmodMessagesQueueSize: { - type: 'integer', - name: 'selfmod.messages.queue-size', - description: LanguageKeys.Settings.SelfmodMessagesQueueSize, - minimum: 10, - maximum: 100, - default: 50 - }, - selfmodMessagesSoftAction: { - type: 'integer', - name: 'selfmod.messages.soft-action', - description: LanguageKeys.Settings.DashboardOnlyKey, - default: 0, - dashboardOnly: true - }, - selfmodMessagesHardAction: { - type: 'integer', - name: 'selfmod.messages.hard-action', - description: LanguageKeys.Settings.DashboardOnlyKey, - default: 0, - dashboardOnly: true - }, - selfmodMessagesHardActionDuration: { - type: 'timespan', - name: 'selfmod.messages.hard-action-duration', - description: LanguageKeys.Settings.DashboardOnlyKey, - minimum: 0, - maximum: years(5), - dashboardOnly: true - }, - selfmodMessagesThresholdMaximum: { - type: 'integer', - name: 'selfmod.messages.threshold-maximum', - description: LanguageKeys.Settings.DashboardOnlyKey, - minimum: 0, - maximum: 100, - default: 10, - dashboardOnly: true - }, - selfmodMessagesThresholdDuration: { - type: 'timespan', - name: 'selfmod.messages.threshold-duration', - description: LanguageKeys.Settings.DashboardOnlyKey, - minimum: 0, - maximum: years(5), - default: 60000, - dashboardOnly: true - }, - selfmodNewlinesEnabled: { - type: 'boolean', - name: 'selfmod.newlines.enabled', - description: LanguageKeys.Settings.SelfmodNewlinesEnabled, - default: false - }, - selfmodNewlinesIgnoredRoles: { - type: 'role', - name: 'selfmod.newlines.ignored-roles', - description: LanguageKeys.Settings.SelfmodNewlinesIgnoredRoles, - array: true - }, - selfmodNewlinesIgnoredChannels: { - type: 'guildTextChannel', - name: 'selfmod.newlines.ignored-channels', - description: LanguageKeys.Settings.SelfmodNewlinesIgnoredChannels, - array: true - }, - selfmodNewlinesMaximum: { - type: 'integer', - name: 'selfmod.newlines.maximum', - description: LanguageKeys.Settings.SelfmodNewlinesMaximum, - minimum: 10, - maximum: 100, - default: 20 - }, - selfmodNewlinesSoftAction: { - type: 'integer', - name: 'selfmod.newlines.soft-action', - description: LanguageKeys.Settings.DashboardOnlyKey, - default: 0, - dashboardOnly: true - }, - selfmodNewlinesHardAction: { - type: 'integer', - name: 'selfmod.newlines.hard-action', - description: LanguageKeys.Settings.DashboardOnlyKey, - default: 0, - dashboardOnly: true - }, - selfmodNewlinesHardActionDuration: { - type: 'timespan', - name: 'selfmod.newlines.hard-action-duration', - description: LanguageKeys.Settings.DashboardOnlyKey, - minimum: 0, - maximum: years(5), - dashboardOnly: true - }, - selfmodNewlinesThresholdMaximum: { - type: 'integer', - name: 'selfmod.newlines.threshold-maximum', - description: LanguageKeys.Settings.DashboardOnlyKey, - minimum: 0, - maximum: 100, - default: 10, - dashboardOnly: true - }, - selfmodNewlinesThresholdDuration: { - type: 'timespan', - name: 'selfmod.newlines.threshold-duration', - description: LanguageKeys.Settings.DashboardOnlyKey, - minimum: 0, - maximum: years(5), - default: 60000, - dashboardOnly: true - }, - selfmodInvitesEnabled: { - type: 'boolean', - name: 'selfmod.invites.enabled', - description: LanguageKeys.Settings.SelfmodInvitesEnabled, - default: false - }, - selfmodInvitesIgnoredCodes: { - type: 'string', - name: 'selfmod.invites.ignored-codes', - description: LanguageKeys.Settings.SelfmodInvitesIgnoredCodes, - array: true - }, - selfmodInvitesIgnoredGuilds: { - type: 'string', - name: 'selfmod.invites.ignored-guilds', - description: LanguageKeys.Settings.SelfmodInvitesIgnoredGuilds, - array: true - }, - selfmodInvitesIgnoredRoles: { - type: 'role', - name: 'selfmod.invites.ignored-roles', - description: LanguageKeys.Settings.SelfmodInvitesIgnoredRoles, - array: true - }, - selfmodInvitesIgnoredChannels: { - type: 'guildTextChannel', - name: 'selfmod.invites.ignored-channels', - description: LanguageKeys.Settings.SelfmodInvitesIgnoredChannels, - array: true - }, - selfmodInvitesSoftAction: { - type: 'integer', - name: 'selfmod.invites.soft-action', - description: LanguageKeys.Settings.DashboardOnlyKey, - default: 0, - dashboardOnly: true - }, - selfmodInvitesHardAction: { - type: 'integer', - name: 'selfmod.invites.hard-action', - description: LanguageKeys.Settings.DashboardOnlyKey, - default: 0, - dashboardOnly: true - }, - selfmodInvitesHardActionDuration: { - type: 'timespan', - name: 'selfmod.invites.hard-action-duration', - description: LanguageKeys.Settings.DashboardOnlyKey, - minimum: 0, - maximum: years(5), - dashboardOnly: true - }, - selfmodInvitesThresholdMaximum: { - type: 'integer', - name: 'selfmod.invites.threshold-maximum', - description: LanguageKeys.Settings.DashboardOnlyKey, - minimum: 0, - maximum: 100, - default: 10, - dashboardOnly: true - }, - selfmodInvitesThresholdDuration: { - type: 'timespan', - name: 'selfmod.invites.threshold-duration', - description: LanguageKeys.Settings.DashboardOnlyKey, - minimum: 0, - maximum: years(5), - default: 60000, - dashboardOnly: true - }, - selfmodFilterEnabled: { - type: 'boolean', - name: 'selfmod.filter.enabled', - description: LanguageKeys.Settings.SelfmodFilterEnabled, - default: false - }, - selfmodFilterRaw: { - type: 'string', - name: 'selfmod.filter.raw', - description: LanguageKeys.Settings.DashboardOnlyKey, - array: true, - dashboardOnly: true - }, - selfmodFilterIgnoredRoles: { - type: 'role', - name: 'selfmod.filter.ignored-roles', - description: LanguageKeys.Settings.SelfmodFilterIgnoredRoles, - array: true - }, - selfmodFilterIgnoredChannels: { - type: 'guildTextChannel', - name: 'selfmod.filter.ignored-channels', - description: LanguageKeys.Settings.SelfmodFilterIgnoredChannels, - array: true - }, - selfmodFilterSoftAction: { - type: 'integer', - name: 'selfmod.filter.soft-action', - description: LanguageKeys.Settings.DashboardOnlyKey, - default: 0, - dashboardOnly: true - }, - selfmodFilterHardAction: { - type: 'integer', - name: 'selfmod.filter.hard-action', - description: LanguageKeys.Settings.DashboardOnlyKey, - default: 0, - dashboardOnly: true - }, - selfmodFilterHardActionDuration: { - type: 'timespan', - name: 'selfmod.filter.hard-action-duration', - description: LanguageKeys.Settings.DashboardOnlyKey, - minimum: 0, - maximum: years(5), - dashboardOnly: true - }, - selfmodFilterThresholdMaximum: { - type: 'integer', - name: 'selfmod.filter.threshold-maximum', - description: LanguageKeys.Settings.DashboardOnlyKey, - minimum: 0, - maximum: 100, - default: 10, - dashboardOnly: true - }, - selfmodFilterThresholdDuration: { - type: 'timespan', - name: 'selfmod.filter.threshold-duration', - description: LanguageKeys.Settings.DashboardOnlyKey, - minimum: 0, - maximum: years(5), - default: 60000, - dashboardOnly: true - }, - selfmodReactionsEnabled: { - type: 'boolean', - name: 'selfmod.reactions.enabled', - description: LanguageKeys.Settings.SelfmodReactionsEnabled, - default: false - }, - selfmodReactionsIgnoredRoles: { - type: 'role', - name: 'selfmod.reactions.ignored-roles', - description: LanguageKeys.Settings.SelfmodReactionsIgnoredRoles, - array: true - }, - selfmodReactionsIgnoredChannels: { - type: 'guildTextChannel', - name: 'selfmod.reactions.ignored-channels', - description: LanguageKeys.Settings.SelfmodReactionsIgnoredChannels, - array: true - }, - selfmodReactionsMaximum: { - type: 'integer', - name: 'selfmod.reactions.maximum', - description: LanguageKeys.Settings.SelfmodReactionsMaximum, - minimum: 1, - maximum: 100, - default: 10 - }, - selfmodReactionsAllowed: { - type: 'emoji', - name: 'selfmod.reactions.allowed', - description: LanguageKeys.Settings.SelfmodReactionsAllowed, - array: true - }, - selfmodReactionsBlocked: { - type: 'emoji', - name: 'selfmod.reactions.blocked', - description: LanguageKeys.Settings.SelfmodReactionsBlocked, - array: true - }, - selfmodReactionsSoftAction: { - type: 'integer', - name: 'selfmod.reactions.soft-action', - description: LanguageKeys.Settings.DashboardOnlyKey, - default: 0, - dashboardOnly: true - }, - selfmodReactionsHardAction: { - type: 'integer', - name: 'selfmod.reactions.hard-action', - description: LanguageKeys.Settings.DashboardOnlyKey, - default: 0, - dashboardOnly: true - }, - selfmodReactionsHardActionDuration: { - type: 'timespan', - name: 'selfmod.reactions.hard-action-duration', - description: LanguageKeys.Settings.DashboardOnlyKey, - minimum: 0, - maximum: years(5), - dashboardOnly: true - }, - selfmodReactionsThresholdMaximum: { - type: 'integer', - name: 'selfmod.reactions.threshold-maximum', - description: LanguageKeys.Settings.DashboardOnlyKey, - minimum: 0, - maximum: 100, - default: 10, - dashboardOnly: true - }, - selfmodReactionsThresholdDuration: { - type: 'timespan', - name: 'selfmod.reactions.threshold-duration', - description: LanguageKeys.Settings.DashboardOnlyKey, - minimum: 0, - maximum: years(5), - default: 60000, - dashboardOnly: true - }, - selfmodIgnoredChannels: { - type: 'guildTextChannel', - name: 'selfmod.ignored-channels', - description: LanguageKeys.Settings.SelfmodIgnoreChannels, - array: true - }, - noMentionSpamEnabled: { - type: 'boolean', - name: 'no-mention-spam.enabled', - description: LanguageKeys.Settings.NoMentionSpamEnabled, - default: false - }, - noMentionSpamAlerts: { - type: 'boolean', - name: 'no-mention-spam.alerts', - description: LanguageKeys.Settings.NoMentionSpamAlerts, - default: false - }, - noMentionSpamMentionsAllowed: { - type: 'integer', - name: 'no-mention-spam.mentions-allowed', - description: LanguageKeys.Settings.NoMentionSpamMentionsAllowed, - minimum: 0, - default: 20 - }, - noMentionSpamTimePeriod: { - type: 'integer', - name: 'no-mention-spam.time-period', - description: LanguageKeys.Settings.NoMentionSpamTimePeriod, - minimum: 0, - default: 8 - } - }); - - return cachedConfiguration; -} - -function makeKeys(record: Record): Record { - const entries = objectEntries(record).map(([key, value]) => [key, makeKey(key, value)] as const); - return Object.fromEntries(entries) as Record; -} - -function makeKey(property: SchemaDataKey, options: ConfigurableKeyOptions) { - const name = options.name ?? property; - const parts = name.split('.') as NonEmptyArray; - - const value = new SchemaKey({ - ...options, - key: parts.at(-1)!, - name, - property, - array: options.array ?? false, - inclusive: options.inclusive ?? true, - minimum: options.minimum ?? null, - maximum: options.maximum ?? null, - default: options.default ?? (options.array ? [] : options.type === 'boolean' ? false : null), - dashboardOnly: options.dashboardOnly ?? false - }); - - configurableKeys.set(property, value); - value.parent = configurableGroups.add(value.name.split('.') as NonEmptyArray, value); - - return value; -} - -interface ConfigurableKeyOptions - extends - Omit, - Partial> {} diff --git a/src/lib/database/settings/constants.ts b/src/lib/database/settings/constants.ts deleted file mode 100644 index 3d1c5d780..000000000 --- a/src/lib/database/settings/constants.ts +++ /dev/null @@ -1,167 +0,0 @@ -import type { ReadonlyGuildData } from '#lib/database/settings/types'; -import { envParseString } from '@skyra/env-utilities'; - -let cachedDefaultGuildSettings: DefaultGuildData | null = null; - -export function getDefaultGuildSettings() { - cachedDefaultGuildSettings ??= Object.assign(Object.create(null), { - prefix: envParseString('CLIENT_PREFIX'), - language: 'en-US', - disableNaturalPrefix: false, - disabledCommands: [], - permissionsUsers: [], - permissionsRoles: [], - channelsMediaOnly: [], - channelsLogsModeration: null, - channelsLogsImage: null, - channelsLogsMemberAdd: null, - channelsLogsMemberRemove: null, - channelsLogsMemberNicknameUpdate: null, - channelsLogsMemberUsernameUpdate: null, - channelsLogsMemberRolesUpdate: null, - channelsLogsMessageDelete: null, - channelsLogsMessageDeleteNsfw: null, - channelsLogsMessageUpdate: null, - channelsLogsMessageUpdateNsfw: null, - channelsLogsPrune: null, - channelsLogsReaction: null, - channelsLogsRoleCreate: null, - channelsLogsRoleUpdate: null, - channelsLogsRoleDelete: null, - channelsLogsChannelCreate: null, - channelsLogsChannelUpdate: null, - channelsLogsChannelDelete: null, - channelsLogsEmojiCreate: null, - channelsLogsEmojiUpdate: null, - channelsLogsEmojiDelete: null, - channelsLogsServerUpdate: null, - channelsLogsVoiceChannel: null, - channelsLogsCommand: null, - channelsLogsSettings: null, - channelsIgnoreAll: [], - channelsIgnoreMessageEdit: [], - channelsIgnoreMessageDelete: [], - channelsIgnoreReactionAdd: [], - channelsIgnoreVoiceActivity: [], - commandAutoDelete: [], - disabledChannels: [], - disabledCommandsChannels: [], - eventsBanAdd: false, - eventsBanRemove: false, - eventsTimeout: false, - eventsUnknownMessages: false, - eventsTwemojiReactions: false, - eventsIncludeBots: false, - messagesIgnoreChannels: [], - messagesModerationDm: false, - messagesModerationReasonDisplay: true, - messagesModerationMessageDisplay: true, - messagesModerationAutoDelete: false, - messagesModeratorNameDisplay: true, - messagesAutoDeleteIgnoredAll: false, - messagesAutoDeleteIgnoredRoles: [], - messagesAutoDeleteIgnoredChannels: [], - messagesAutoDeleteIgnoredCommands: [], - stickyRoles: [], - reactionRoles: [], - rolesAdmin: [], - rolesInitial: null, - rolesInitialHumans: null, - rolesInitialBots: null, - rolesModerator: [], - rolesMuted: null, - rolesRestrictedReaction: null, - rolesRestrictedEmbed: null, - rolesRestrictedEmoji: null, - rolesRestrictedAttachment: null, - rolesRestrictedVoice: null, - rolesPublic: [], - rolesRemoveInitial: false, - rolesUniqueRoleSets: [], - selfmodAttachmentsEnabled: false, - selfmodAttachmentsIgnoredRoles: [], - selfmodAttachmentsIgnoredChannels: [], - selfmodAttachmentsSoftAction: 0, - selfmodAttachmentsHardAction: 0, - selfmodAttachmentsHardActionDuration: null, - selfmodAttachmentsThresholdMaximum: 10, - selfmodAttachmentsThresholdDuration: 60000, - selfmodCapitalsEnabled: false, - selfmodCapitalsIgnoredRoles: [], - selfmodCapitalsIgnoredChannels: [], - selfmodCapitalsMinimum: 15, - selfmodCapitalsMaximum: 50, - selfmodCapitalsSoftAction: 0, - selfmodCapitalsHardAction: 0, - selfmodCapitalsHardActionDuration: null, - selfmodCapitalsThresholdMaximum: 10, - selfmodCapitalsThresholdDuration: 60000, - selfmodLinksEnabled: false, - selfmodLinksAllowed: [], - selfmodLinksIgnoredRoles: [], - selfmodLinksIgnoredChannels: [], - selfmodLinksSoftAction: 0, - selfmodLinksHardAction: 0, - selfmodLinksHardActionDuration: null, - selfmodLinksThresholdMaximum: 10, - selfmodLinksThresholdDuration: 60000, - selfmodMessagesEnabled: false, - selfmodMessagesIgnoredRoles: [], - selfmodMessagesIgnoredChannels: [], - selfmodMessagesMaximum: 5, - selfmodMessagesQueueSize: 50, - selfmodMessagesSoftAction: 0, - selfmodMessagesHardAction: 0, - selfmodMessagesHardActionDuration: null, - selfmodMessagesThresholdMaximum: 10, - selfmodMessagesThresholdDuration: 60000, - selfmodNewlinesEnabled: false, - selfmodNewlinesIgnoredRoles: [], - selfmodNewlinesIgnoredChannels: [], - selfmodNewlinesMaximum: 20, - selfmodNewlinesSoftAction: 0, - selfmodNewlinesHardAction: 0, - selfmodNewlinesHardActionDuration: null, - selfmodNewlinesThresholdMaximum: 10, - selfmodNewlinesThresholdDuration: 60000, - selfmodInvitesEnabled: false, - selfmodInvitesIgnoredCodes: [], - selfmodInvitesIgnoredGuilds: [], - selfmodInvitesIgnoredRoles: [], - selfmodInvitesIgnoredChannels: [], - selfmodInvitesSoftAction: 0, - selfmodInvitesHardAction: 0, - selfmodInvitesHardActionDuration: null, - selfmodInvitesThresholdMaximum: 10, - selfmodInvitesThresholdDuration: 60000, - selfmodFilterEnabled: false, - selfmodFilterRaw: [], - selfmodFilterIgnoredRoles: [], - selfmodFilterIgnoredChannels: [], - selfmodFilterSoftAction: 0, - selfmodFilterHardAction: 0, - selfmodFilterHardActionDuration: null, - selfmodFilterThresholdMaximum: 10, - selfmodFilterThresholdDuration: 60000, - selfmodReactionsEnabled: false, - selfmodReactionsIgnoredRoles: [], - selfmodReactionsIgnoredChannels: [], - selfmodReactionsMaximum: 10, - selfmodReactionsAllowed: [], - selfmodReactionsBlocked: [], - selfmodReactionsSoftAction: 0, - selfmodReactionsHardAction: 0, - selfmodReactionsHardActionDuration: null, - selfmodReactionsThresholdMaximum: 10, - selfmodReactionsThresholdDuration: 60000, - selfmodIgnoredChannels: [], - noMentionSpamEnabled: false, - noMentionSpamAlerts: false, - noMentionSpamMentionsAllowed: 20, - noMentionSpamTimePeriod: 8 - } as const satisfies DefaultGuildData); - - return cachedDefaultGuildSettings; -} - -export type DefaultGuildData = Omit; diff --git a/src/lib/database/settings/context/SettingsContext.ts b/src/lib/database/settings/context/SettingsContext.ts deleted file mode 100644 index 00b5a2b47..000000000 --- a/src/lib/database/settings/context/SettingsContext.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { AdderManager } from '#lib/database/settings/structures/AdderManager'; -import { PermissionNodeManager } from '#lib/database/settings/structures/PermissionNodeManager'; -import { AuditLogManager } from '#lib/database/settings/structures/AuditLogManager'; -import type { ReadonlyGuildData } from '#lib/database/settings/types'; -import { create } from '#utils/Security/RegexCreator'; -import { RateLimitManager } from '@sapphire/ratelimits'; -import { isNullish, isNullishOrEmpty } from '@sapphire/utilities'; - -export class SettingsContext { - readonly #adders: AdderManager; - readonly #permissionNodes: PermissionNodeManager; - #auditLog: AuditLogManager; - #wordFilterRegExp: RegExp | null; - #noMentionSpam: RateLimitManager; - - public constructor(settings: ReadonlyGuildData) { - this.#adders = new AdderManager(settings); - this.#permissionNodes = new PermissionNodeManager(settings); - this.#auditLog = new AuditLogManager(settings); - this.#wordFilterRegExp = isNullishOrEmpty(settings.selfmodFilterRaw) ? null : new RegExp(create(settings.selfmodFilterRaw), 'gi'); - this.#noMentionSpam = new RateLimitManager(settings.noMentionSpamTimePeriod * 1000, settings.noMentionSpamMentionsAllowed); - } - - public get adders() { - return this.#adders; - } - - public get permissionNodes() { - return this.#permissionNodes; - } - - public get auditLog() { - return this.#auditLog; - } - - public get wordFilterRegExp() { - return this.#wordFilterRegExp; - } - - public get noMentionSpam() { - return this.#noMentionSpam; - } - - public update(settings: ReadonlyGuildData, data: Partial) { - this.#adders.onPatch(settings); - this.#auditLog.onPatch(settings); - - if (!isNullish(data.permissionsRoles) || !isNullish(data.permissionsUsers)) { - this.#permissionNodes.refresh(settings); - } - - if (!isNullish(data.noMentionSpamTimePeriod) || !isNullish(data.noMentionSpamMentionsAllowed)) { - this.#noMentionSpam = new RateLimitManager(settings.noMentionSpamTimePeriod * 1000, settings.noMentionSpamMentionsAllowed); - } - - if (!isNullish(data.selfmodFilterRaw)) { - this.#wordFilterRegExp = isNullishOrEmpty(settings.selfmodFilterRaw) ? null : new RegExp(create(settings.selfmodFilterRaw), 'gi'); - } - } -} diff --git a/src/lib/database/settings/context/functions.ts b/src/lib/database/settings/context/functions.ts deleted file mode 100644 index a2ab04d8b..000000000 --- a/src/lib/database/settings/context/functions.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { SettingsContext } from '#lib/database/settings/context/SettingsContext'; -import type { ReadonlyGuildData } from '#lib/database/settings/types'; -import { Collection, type Snowflake } from 'discord.js'; - -const cache = new Collection(); - -export function getSettingsContextByGuildId(guildId: Snowflake): SettingsContext | null { - return cache.get(guildId) ?? null; -} - -export function getSettingsContext(settings: ReadonlyGuildData): SettingsContext { - return cache.ensure(settings.id, () => new SettingsContext(settings)); -} - -export function updateSettingsContext(settings: ReadonlyGuildData, data: Partial): void { - const existing = cache.get(settings.id); - if (existing) { - existing.update(settings, data); - } else { - const context = new SettingsContext(settings); - cache.set(settings.id, context); - } -} - -export function deleteSettingsContext(guildId: Snowflake) { - cache.delete(guildId); -} diff --git a/src/lib/database/settings/functions.ts b/src/lib/database/settings/functions.ts deleted file mode 100644 index 943d0a652..000000000 --- a/src/lib/database/settings/functions.ts +++ /dev/null @@ -1,234 +0,0 @@ -import { getDefaultGuildSettings } from '#lib/database/settings/constants'; -import { deleteSettingsContext, getSettingsContext, updateSettingsContext } from '#lib/database/settings/context/functions'; -import type { AdderKey } from '#lib/database/settings/structures/AdderManager'; -import type { GuildData, ReadonlyGuildData } from '#lib/database/settings/types'; -import { maybeParseNumber } from '#utils/common'; -import { AsyncQueue } from '@sapphire/async-queue'; -import { container, type Awaitable } from '@sapphire/framework'; -import type { PickByValue } from '@sapphire/utilities'; -import { Collection, type GuildResolvable, type Snowflake } from 'discord.js'; - -const cache = new Collection(); -const queue = new Collection>(); -const locks = new Collection(); -const WeakMapNotInitialized = new WeakSet(); - -const transformers = { - selfmodAttachmentsHardActionDuration: maybeParseNumber, - selfmodCapitalsHardActionDuration: maybeParseNumber, - selfmodFilterHardActionDuration: maybeParseNumber, - selfmodInvitesHardActionDuration: maybeParseNumber, - selfmodLinksHardActionDuration: maybeParseNumber, - selfmodMessagesHardActionDuration: maybeParseNumber, - selfmodNewlinesHardActionDuration: maybeParseNumber, - selfmodReactionsHardActionDuration: maybeParseNumber -} satisfies Record, typeof maybeParseNumber>; - -export function serializeSettings(data: ReadonlyGuildData, space?: string | number) { - return JSON.stringify(data, (key, value) => (key in transformers ? transformers[key as keyof typeof transformers](value) : value), space); -} - -export function deleteSettingsCached(guild: GuildResolvable) { - const id = resolveGuildId(guild); - locks.delete(id); - cache.delete(id); - deleteSettingsContext(id); -} - -export function readSettings(guild: GuildResolvable): Awaitable { - const id = resolveGuildId(guild); - - return cache.get(id) ?? processFetch(id); -} - -export function readSettingsAdder(settings: ReadonlyGuildData, key: AdderKey) { - return getSettingsContext(settings).adders[key]; -} - -export function readSettingsPermissionNodes(settings: ReadonlyGuildData) { - return getSettingsContext(settings).permissionNodes; -} - -export function readSettingsNoMentionSpam(settings: ReadonlyGuildData) { - return getSettingsContext(settings).noMentionSpam; -} - -export function readSettingsWordFilterRegExp(settings: ReadonlyGuildData) { - return getSettingsContext(settings).wordFilterRegExp; -} - -export function readSettingsCached(guild: GuildResolvable): ReadonlyGuildData | null { - return cache.get(resolveGuildId(guild)) ?? null; -} - -export function readSettingsAuditLog(settings: ReadonlyGuildData) { - return getSettingsContext(settings).auditLog; -} - -export async function writeSettings( - guild: GuildResolvable, - data: Partial | ((settings: ReadonlyGuildData) => Awaitable>), - actorId?: string -) { - using trx = await writeSettingsTransaction(guild); - - if (typeof data === 'function') { - data = await data(trx.settings); - } - - if (actorId) { - await trx.write(data).submitWithAudit(actorId); - } else { - await trx.write(data).submit(); - } -} - -export async function writeSettingsTransaction(guild: GuildResolvable) { - const id = resolveGuildId(guild); - const queue = locks.ensure(id, () => new AsyncQueue()); - - // Acquire a write lock: - await queue.wait(); - - // Fetch the entry: - const settings = cache.get(id) ?? (await unlockOnThrow(processFetch(id), queue)); - - return new Transaction(settings, queue); -} - -export class Transaction { - #changes = Object.create(null) as Partial; - #before = Object.create(null) as Record; - #hasChanges = false; - #locking = true; - - public constructor( - public readonly settings: ReadonlyGuildData, - private readonly queue: AsyncQueue - ) {} - - public get hasChanges() { - return this.#hasChanges; - } - - public get locking() { - return this.#locking; - } - - public write(data: Partial) { - for (const key of Object.keys(data)) { - if (!(key in this.#before)) { - (this.#before as Record)[key] = (this.settings as Record)[key]; - } - } - - Object.assign(this.#changes, data); - this.#hasChanges = true; - return this; - } - - public async submitWithAudit(actorId: string) { - if (!this.#hasChanges) return; - const before = { ...this.#before }; - await this.submit(); - const after = Object.fromEntries(Object.keys(before).map((key) => [key, (this.settings as Record)[key]])); - void readSettingsAuditLog(this.settings) - .update(actorId, before, after) - .catch(() => null); - } - - public async submit() { - if (!this.#hasChanges) { - return; - } - - try { - if (WeakMapNotInitialized.has(this.settings)) { - await container.prisma.guild.create({ - // @ts-expect-error readonly - data: { ...this.settings, ...this.#changes } - }); - WeakMapNotInitialized.delete(this.settings); - } else { - await container.prisma.guild.update({ - where: { id: this.settings.id }, - // @ts-expect-error readonly - data: this.#changes - }); - } - - Object.assign(this.settings, this.#changes); - this.#hasChanges = false; - updateSettingsContext(this.settings, this.#changes); - } finally { - this.#changes = Object.create(null); - - if (this.#locking) { - this.queue.shift(); - this.#locking = false; - } - } - } - - public abort() { - if (this.#locking) { - this.queue.shift(); - this.#locking = false; - } - } - - public dispose() { - if (this.#locking) { - this.queue.shift(); - this.#locking = false; - } - } - - public [Symbol.dispose]() { - return this.dispose(); - } -} - -async function unlockOnThrow(promise: Promise, lock: AsyncQueue) { - try { - return await promise; - } catch (error) { - lock.shift(); - throw error; - } -} - -async function processFetch(id: string): Promise { - const previous = queue.get(id); - if (previous) return previous; - - try { - const promise = fetch(id); - queue.set(id, promise); - const value = await promise; - getSettingsContext(value); - return value; - } finally { - queue.delete(id); - } -} - -async function fetch(id: string): Promise { - const { guild } = container.prisma; - const existing = await guild.findUnique({ where: { id } }); - if (existing) { - cache.set(id, existing); - return existing; - } - - const created = Object.assign(Object.create(null), getDefaultGuildSettings(), { id }) as GuildData; - cache.set(id, created); - WeakMapNotInitialized.add(created); - return created; -} - -function resolveGuildId(guild: GuildResolvable): Snowflake { - const resolvedId = container.client.guilds.resolveId(guild); - if (resolvedId === null) throw new TypeError(`Cannot resolve "guild" to a Guild instance.`); - return resolvedId; -} diff --git a/src/lib/database/settings/index.ts b/src/lib/database/settings/index.ts deleted file mode 100644 index c34c08747..000000000 --- a/src/lib/database/settings/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -export * from '#lib/database/settings/configuration'; -export * from '#lib/database/settings/context/functions'; -export * from '#lib/database/settings/functions'; -export * from '#lib/database/settings/schema/SchemaGroup'; -export * from '#lib/database/settings/schema/SchemaKey'; -export * from '#lib/database/settings/structures/AdderManager'; -export * from '#lib/database/settings/structures/PermissionNodeManager'; -export * from '#lib/database/settings/structures/AuditLogManager'; -export * from '#lib/database/settings/structures/AuditLogEnvelope'; -export * from '#lib/database/settings/structures/Serializer'; -export * from '#lib/database/settings/structures/SerializerStore'; -export * from '#lib/database/settings/types'; -export * from '#lib/database/settings/Utils'; -export * from '#lib/database/settings/auditActions'; diff --git a/src/lib/database/settings/schema/SchemaGroup.ts b/src/lib/database/settings/schema/SchemaGroup.ts deleted file mode 100644 index 593cd2301..000000000 --- a/src/lib/database/settings/schema/SchemaGroup.ts +++ /dev/null @@ -1,115 +0,0 @@ -import type { ISchemaValue } from '#lib/database/settings/base/ISchemaValue'; -import type { SchemaKey } from '#lib/database/settings/schema/SchemaKey'; -import { AliasedCollection } from '#lib/database/settings/structures/collections/AliasedCollection'; -import type { ReadonlyGuildData } from '#lib/database/settings/types'; -import type { TFunction } from '@sapphire/plugin-i18next'; -import { codeBlock, isNullish, toTitleCase } from '@sapphire/utilities'; - -export type NonEmptyArray = [T, ...T[]]; - -export class SchemaGroup extends AliasedCollection implements ISchemaValue { - public readonly key: string; - public readonly parent: SchemaGroup | null; - public readonly name: string; - public readonly dashboardOnly = false; - public readonly type = 'Group'; - - public constructor(key: string, name = 'Root', parent: SchemaGroup | null = null) { - super(); - this.key = key; - this.name = name; - this.parent = parent; - } - - public override set(key: string, value: SchemaGroup | SchemaKey) { - // Add auto-alias: - if (key.includes('-')) { - this.aliases.set(key.replaceAll('-', ''), value); - } - - return super.set(key, value); - } - - public add([key, ...tail]: NonEmptyArray, value: SchemaKey): SchemaGroup { - if (tail.length === 0) { - this.set(key, value); - return this; - } - - const previous = this.get(key); - if (previous) { - if (previous instanceof SchemaGroup) { - return previous.add(tail as NonEmptyArray, value); - } - - throw new Error(`You cannot add '${key}' to a non-group entry.`); - } - - const group = new SchemaGroup(key, `${this.name} / ${toTitleCase(key)}`, this); - group.add(tail as NonEmptyArray, value); - this.set(key, group); - return group; - } - - public *childKeys() { - for (const [key, entry] of this) { - if (entry.type !== 'Group') yield key; - } - } - - public *childValues() { - for (const entry of this.values()) { - if (entry.type !== 'Group') yield entry; - } - } - - public getPathArray([key, ...tail]: NonEmptyArray): SchemaGroup | SchemaKey | null { - if (tail.length === 0) { - return key === '' || key === '.' ? this : (this.get(key) ?? null); - } - - const value = this.get(key); - if (isNullish(value)) return null; - if (value instanceof SchemaGroup) return value.getPathArray(tail as NonEmptyArray); - return null; - } - - public getPathString(key: string): SchemaGroup | SchemaKey | null { - return this.getPathArray(key.split('.') as NonEmptyArray); - } - - public display(settings: ReadonlyGuildData, language: TFunction) { - const folders: string[] = []; - const sections = new Map(); - let longest = 0; - for (const [key, value] of this.entries()) { - if (value.dashboardOnly) continue; - if (value.type === 'Group') { - folders.push(`// ${key}`); - } else { - const values = sections.get(value.type) ?? []; - values.push(key); - - if (key.length > longest) longest = key.length; - if (values.length === 1) sections.set(value.type, values); - } - } - - const array: string[] = []; - if (folders.length) array.push('= Folders =', ...folders.sort(), ''); - if (sections.size) { - for (const keyType of [...sections.keys()].sort()) { - array.push( - `= ${toTitleCase(keyType)}s =`, - ...sections - .get(keyType)! - .sort() - .map((key) => `${key.padEnd(longest)} :: ${this.get(key)!.display(settings, language)}`), - '' - ); - } - } - - return codeBlock('asciidoc', array.join('\n')); - } -} diff --git a/src/lib/database/settings/schema/SchemaKey.ts b/src/lib/database/settings/schema/SchemaKey.ts deleted file mode 100644 index 480cfcb8a..000000000 --- a/src/lib/database/settings/schema/SchemaKey.ts +++ /dev/null @@ -1,141 +0,0 @@ -import type { ISchemaValue } from '#lib/database/settings/base/ISchemaValue'; -import type { SchemaGroup } from '#lib/database/settings/schema/SchemaGroup'; -import type { Serializer } from '#lib/database/settings/structures/Serializer'; -import type { GuildDataKey, ReadonlyGuildData } from '#lib/database/settings/types'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import type { WolfArgs } from '#lib/structures'; -import type { TypedT } from '#lib/types'; -import { resolveGuild } from '#utils/common'; -import { container } from '@sapphire/framework'; -import type { TFunction } from '@sapphire/plugin-i18next'; -import { isNullish } from '@sapphire/utilities'; - -export class SchemaKey implements ISchemaValue { - /** - * The key that identifies this configuration key from the parent group. - */ - public readonly key: string; - - /** - * The i18n key for the configuration key. - */ - public readonly description: TypedT; - - /** - * The maximum value for the configuration key. - */ - public readonly maximum: number | null; - - /** - * The minimum value for the configuration key. - */ - public readonly minimum: number | null; - - /** - * Whether or not the range checks are inclusive. - */ - public readonly inclusive: boolean; - - /** - * The visible name of the configuration key. - */ - public readonly name: string; - - /** - * The property from the Prisma entity. - */ - public readonly property: K; - - /** - * The type of the value this property accepts. - */ - public readonly type: Serializer.Name; - - /** - * Whether or not this accepts multiple values. - */ - public readonly array: boolean; - - /** - * The default value for this key. - */ - public readonly default: unknown; - - /** - * Whether this key should only be configurable on the dashboard - */ - public readonly dashboardOnly: boolean; - - /** - * The parent group that holds this key. - */ - public parent: SchemaGroup | null = null; - - public constructor(options: ConfigurableKeyValueOptions) { - this.key = options.key; - this.description = options.description; - this.maximum = options.maximum; - this.minimum = options.minimum; - this.inclusive = options.inclusive ?? false; - this.name = options.name; - this.property = options.property as K; - this.type = options.type; - this.array = options.array; - this.default = options.default; - this.dashboardOnly = options.dashboardOnly ?? false; - } - - public get serializer(): Serializer { - const value = container.stores.get('serializers').get(this.type); - if (typeof value === 'undefined') throw new Error(`The serializer for '${this.type}' does not exist.`); - return value as Serializer; - } - - public async parse(settings: ReadonlyGuildData, args: WolfArgs): Promise { - const { serializer } = this; - const context = this.getContext(settings, args.t); - - const result = await serializer.parse(args, context); - return result.match({ - ok: (value) => value, - err: (error) => { - throw error.message; - } - }); - } - - public stringify(settings: ReadonlyGuildData, t: TFunction, value: ReadonlyGuildData[K]): string { - const { serializer } = this; - const context = this.getContext(settings, t); - return serializer.stringify(value, context); - } - - public display(settings: ReadonlyGuildData, t: TFunction): string { - const { serializer } = this; - const context = this.getContext(settings, t); - - if (this.array) { - const values = settings[this.property] as readonly any[]; - return isNullish(values) || values.length === 0 - ? 'None' - : `[ ${values.map((value) => serializer.stringify(value, context)).join(' | ')} ]`; - } - - const value = settings[this.property]; - return isNullish(value) ? t(LanguageKeys.Commands.Conf.SettingNotSet) : serializer.stringify(value, context); - } - - public getContext(settings: ReadonlyGuildData, language: TFunction): Serializer.UpdateContext { - return { - entity: settings, - guild: resolveGuild(settings.id), - t: language, - entry: this - } satisfies Serializer.UpdateContext; - } -} - -export type ConfigurableKeyValueOptions = Pick< - SchemaKey, - 'key' | 'description' | 'maximum' | 'minimum' | 'inclusive' | 'name' | 'property' | 'type' | 'array' | 'default' | 'dashboardOnly' ->; diff --git a/src/lib/database/settings/structures/AdderManager.ts b/src/lib/database/settings/structures/AdderManager.ts deleted file mode 100644 index 2de56d2f3..000000000 --- a/src/lib/database/settings/structures/AdderManager.ts +++ /dev/null @@ -1,53 +0,0 @@ -import type { ReadonlyGuildData } from '#lib/database/settings/types'; -import { Adder } from '#lib/database/utils/Adder'; -import { isNullishOrZero, type Nullish } from '@sapphire/utilities'; - -export type AdderKey = 'attachments' | 'capitals' | 'links' | 'messages' | 'newlines' | 'invites' | 'words' | 'reactions'; - -export class AdderManager { - public attachments: Adder | null; - public capitals: Adder | null; - public links: Adder | null; - public messages: Adder | null; - public newlines: Adder | null; - public invites: Adder | null; - public words: Adder | null; - public reactions: Adder | null; - - public constructor(settings: ReadonlyGuildData) { - this.attachments = this.makeAdder(settings.selfmodAttachmentsThresholdMaximum, settings.selfmodAttachmentsThresholdDuration); - this.capitals = this.makeAdder(settings.selfmodCapitalsThresholdMaximum, settings.selfmodCapitalsThresholdDuration); - this.links = this.makeAdder(settings.selfmodLinksThresholdMaximum, settings.selfmodLinksThresholdDuration); - this.messages = this.makeAdder(settings.selfmodMessagesThresholdMaximum, settings.selfmodMessagesThresholdDuration); - this.newlines = this.makeAdder(settings.selfmodNewlinesThresholdMaximum, settings.selfmodNewlinesThresholdDuration); - this.invites = this.makeAdder(settings.selfmodInvitesThresholdMaximum, settings.selfmodInvitesThresholdDuration); - this.words = this.makeAdder(settings.selfmodFilterThresholdMaximum, settings.selfmodFilterThresholdDuration); - this.reactions = this.makeAdder(settings.selfmodReactionsThresholdMaximum, settings.selfmodReactionsThresholdDuration); - } - - public onPatch(settings: ReadonlyGuildData): void { - this.attachments = this.updateAdder( - this.attachments, - settings.selfmodAttachmentsThresholdMaximum, - settings.selfmodAttachmentsThresholdDuration - ); - this.capitals = this.updateAdder(this.capitals, settings.selfmodCapitalsThresholdMaximum, settings.selfmodCapitalsThresholdDuration); - this.links = this.updateAdder(this.links, settings.selfmodLinksThresholdMaximum, settings.selfmodLinksThresholdDuration); - this.messages = this.updateAdder(this.messages, settings.selfmodMessagesThresholdMaximum, settings.selfmodMessagesThresholdDuration); - this.newlines = this.updateAdder(this.newlines, settings.selfmodNewlinesThresholdMaximum, settings.selfmodNewlinesThresholdDuration); - this.invites = this.updateAdder(this.invites, settings.selfmodInvitesThresholdMaximum, settings.selfmodInvitesThresholdDuration); - this.words = this.updateAdder(this.words, settings.selfmodFilterThresholdMaximum, settings.selfmodFilterThresholdDuration); - this.reactions = this.updateAdder(this.reactions, settings.selfmodReactionsThresholdMaximum, settings.selfmodReactionsThresholdDuration); - } - - private makeAdder(maximum: number | Nullish, duration: number | Nullish) { - if (isNullishOrZero(maximum) || isNullishOrZero(duration)) return null; - return new Adder(maximum, duration, true); - } - - private updateAdder(adder: Adder | null, maximum: number | Nullish, duration: number | Nullish) { - if (isNullishOrZero(maximum) || isNullishOrZero(duration)) return null; - if (!adder || adder.maximum !== maximum || adder.duration !== duration) return new Adder(maximum, duration, true); - return adder; - } -} diff --git a/src/lib/database/settings/structures/AuditLogEnvelope.ts b/src/lib/database/settings/structures/AuditLogEnvelope.ts deleted file mode 100644 index c7a2ea414..000000000 --- a/src/lib/database/settings/structures/AuditLogEnvelope.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { createHash } from 'node:crypto'; - -export interface AuditEnvelopeInput { - action: string; - actor: { type: 'user'; id: string }; - outcome: 'success' | 'failure' | 'denied'; - tenantId: string; - timestamp: string; - changes: { before?: Record; after?: Record } | null; - reason: string | null; - requestId: string | null; - traceId: string | null; - prevHash: string | null; -} - -/** - * Deterministic JSON stringification with sorted keys. - * Matches evlog's internal stableStringify pattern. - * bigint is serialised as a decimal string for JSON round-trip safety. - */ -export function canonicalize(value: unknown): string { - if (typeof value === 'bigint') return JSON.stringify(value.toString()); - if (value === null || typeof value !== 'object') return JSON.stringify(value); - if (Array.isArray(value)) return `[${(value as unknown[]).map(canonicalize).join(',')}]`; - const keys = Object.keys(value as Record).sort(); - return `{${keys.map((k) => `${JSON.stringify(k)}:${canonicalize((value as Record)[k])}`).join(',')}}`; -} - -export function hashEnvelope(envelope: AuditEnvelopeInput): string { - return createHash('sha256').update(canonicalize(envelope)).digest('hex'); -} diff --git a/src/lib/database/settings/structures/AuditLogManager.ts b/src/lib/database/settings/structures/AuditLogManager.ts deleted file mode 100644 index b5a6a4c06..000000000 --- a/src/lib/database/settings/structures/AuditLogManager.ts +++ /dev/null @@ -1,195 +0,0 @@ -import { Prisma } from '#generated/prisma'; -import { hashEnvelope, type AuditEnvelopeInput } from '#lib/database/settings/structures/AuditLogEnvelope'; -import type { AuditOutcome, ReadonlyGuildData } from '#lib/database/settings/types'; -import { buildCommandExecuteEmbed, buildSettingsChangeEmbed, type CommandExecutePayload } from '#utils/functions/auditLogEmbeds'; -import { container } from '@sapphire/framework'; -import { Events } from '#lib/types'; -import { fetchT } from '@sapphire/plugin-i18next'; - -export class AuditLogManager { - #guildId: string; - #settings: ReadonlyGuildData; - - public constructor(settings: ReadonlyGuildData) { - this.#guildId = settings.id; - this.#settings = settings; - } - - public onPatch(settings: ReadonlyGuildData): void { - this.#guildId = settings.id; - this.#settings = settings; - } - - public update(actorId: string, before: Record, after: Record): Promise { - return this.#write({ - actorId, - action: 'guild.settings.update', - before, - after, - outcome: 'success', - reason: null - }); - } - - public add(actorId: string, key: string, value: unknown): Promise { - return this.#write({ - actorId, - action: 'guild.settings.add', - before: {}, - after: { [key]: value }, - outcome: 'success', - reason: null - }); - } - - public remove(actorId: string, key: string, value: unknown): Promise { - return this.#write({ - actorId, - action: 'guild.settings.remove', - before: { [key]: value }, - after: {}, - outcome: 'success', - reason: null - }); - } - - public accessDenied(actorId: string, reason?: string): Promise { - return this.#write({ - actorId, - action: 'guild.settings.access-denied', - before: {}, - after: {}, - outcome: 'denied', - reason: reason ?? null - }); - } - - public command( - actorId: string, - payload: { commandName: string; commandId?: string; commandType: 'chat-input' | 'context-menu' | 'message'; channelId: string } - ): Promise { - return this.#write({ - actorId, - action: 'guild.command.execute', - before: {}, - after: payload, - outcome: 'success', - reason: null - }); - } - - async #write(params: { - actorId: string; - action: string; - before: Record; - after: Record; - outcome: AuditOutcome; - reason: string | null; - }): Promise { - const { actorId, action, outcome, reason } = params; - const tenantId = this.#guildId; - const timestamp = new Date(); - - const safeBefore = this.#toJsonSafe(params.before) as Record; - const safeAfter = this.#toJsonSafe(params.after) as Record; - const changes = action === 'guild.settings.access-denied' ? null : { before: safeBefore, after: safeAfter }; - - await container.prisma.$transaction(async (tx) => { - // Acquire a global transaction-level advisory lock. - // Namespace 0x4155444C = ASCII 'AUDL' = 1096107084. - // The singleton chain head is shared across all tenants, so all writers - // must be globally serialised. Released automatically on commit/rollback. - await tx.$executeRaw`SELECT pg_advisory_xact_lock(1096107084)`; - - const head = await tx.auditChainHead.findUnique({ where: { id: 'default' } }); - const prevHash = head?.hash ?? null; - - const envelope: AuditEnvelopeInput = { - action, - actor: { type: 'user', id: actorId }, - outcome, - tenantId, - timestamp: timestamp.toISOString(), - changes: changes as AuditEnvelopeInput['changes'], - reason, - requestId: null, - traceId: null, - prevHash - }; - - const hash = hashEnvelope(envelope); - - await tx.auditEvent.create({ - data: { - action, - actorType: 'user', - actorId, - outcome, - tenantId, - reason, - changes: changes ?? Prisma.JsonNull, - timestamp, - prevHash, - hash - } - }); - - await tx.auditChainHead.upsert({ - where: { id: 'default' }, - update: { hash }, - create: { id: 'default', hash } - }); - }); - - void this.#emitChannelLog(action, { actorId, before: safeBefore, after: safeAfter, reason, timestamp }).catch(() => null); - } - - async #emitChannelLog( - action: string, - params: { - actorId: string; - before: Record; - after: Record; - reason: string | null; - timestamp: Date; - } - ): Promise { - const guild = container.client.guilds.cache.get(this.#guildId); - if (!guild) return; - - const channelKey = action === 'guild.command.execute' ? 'channelsLogsCommand' : 'channelsLogsSettings'; - const channelId = this.#settings[channelKey]; - if (!channelId) return; - - const t = await fetchT(guild); - - const makeMessage = - action === 'guild.command.execute' - ? () => - buildCommandExecuteEmbed(t, { - actorId: params.actorId, - ...(params.after as Omit), - timestamp: params.timestamp - }) - : () => - buildSettingsChangeEmbed(t, { - actorId: params.actorId, - action: action as any, - before: params.before, - after: params.after, - reason: params.reason, - timestamp: params.timestamp - }); - - container.client.emit(Events.GuildMessageLog, guild, channelId, channelKey, makeMessage); - } - - #toJsonSafe(value: unknown): unknown { - if (typeof value === 'bigint') return value.toString(); - if (Array.isArray(value)) return value.map((v) => this.#toJsonSafe(v)); - if (value !== null && typeof value === 'object') { - return Object.fromEntries(Object.entries(value as Record).map(([k, v]) => [k, this.#toJsonSafe(v)])); - } - return value; - } -} diff --git a/src/lib/database/settings/structures/PermissionNodeManager.ts b/src/lib/database/settings/structures/PermissionNodeManager.ts deleted file mode 100644 index 43ce209be..000000000 --- a/src/lib/database/settings/structures/PermissionNodeManager.ts +++ /dev/null @@ -1,239 +0,0 @@ -import type { PermissionsNode, ReadonlyGuildData } from '#lib/database/settings/types'; -import { matchAny } from '#lib/database/utils/matchers/Command'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import type { WolfCommand } from '#lib/structures'; -import { resolveGuild } from '#utils/common'; -import { UserError } from '@sapphire/framework'; -import { Collection, Role, type GuildMember, type User } from 'discord.js'; - -export const enum PermissionNodeAction { - Allow, - Deny -} - -type PermissionNodeValueResolvable = Role | GuildMember | User; - -export class PermissionNodeManager { - private sorted = new Collection(); - #cachedRawPermissionRoles: readonly PermissionsNode[] = []; - #cachedRawPermissionUsers: readonly PermissionsNode[] = []; - - public constructor(settings: ReadonlyGuildData) { - this.refresh(settings); - } - - public settingsPropertyFor(target: PermissionNodeValueResolvable) { - return (target instanceof Role ? 'permissionsRoles' : 'permissionsUsers') satisfies keyof ReadonlyGuildData; - } - - public run(member: GuildMember, command: WolfCommand) { - return this.runUser(member, command) ?? this.runRole(member, command); - } - - public has(roleId: string) { - return this.sorted.has(roleId); - } - - public add(target: PermissionNodeValueResolvable, command: string, action: PermissionNodeAction): readonly PermissionsNode[] { - const nodes = this.#getPermissionNodes(target); - - const nodeIndex = nodes.findIndex((n) => n.id === target.id); - if (nodeIndex === -1) { - const node: PermissionsNode = { - id: target.id, - allow: action === PermissionNodeAction.Allow ? [command] : [], - deny: action === PermissionNodeAction.Deny ? [command] : [] - }; - - return nodes.concat(node); - } - - const previous = nodes[nodeIndex]; - if ( - (action === PermissionNodeAction.Allow && previous.allow.includes(command)) || - (action === PermissionNodeAction.Deny && previous.deny.includes(command)) - ) { - throw new UserError({ identifier: LanguageKeys.Serializers.PermissionNodeDuplicatedCommand, context: { command } }); - } - - const node: PermissionsNode = { - id: target.id, - allow: action === PermissionNodeAction.Allow ? previous.allow.concat(command) : previous.allow, - deny: action === PermissionNodeAction.Deny ? previous.deny.concat(command) : previous.deny - }; - - return nodes.with(nodeIndex, node); - } - - public remove(target: PermissionNodeValueResolvable, command: string, action: PermissionNodeAction): readonly PermissionsNode[] { - const nodes = this.#getPermissionNodes(target); - - const nodeIndex = nodes.findIndex((n) => n.id === target.id); - if (nodeIndex === -1) { - throw new UserError({ identifier: LanguageKeys.Commands.Management.PermissionNodesNodeNotExists }); - } - - const property = this.getName(action); - const previous = nodes[nodeIndex]; - const commandIndex = previous[property].indexOf(command); - if (commandIndex === -1) { - throw new UserError({ identifier: LanguageKeys.Commands.Management.PermissionNodesCommandNotExists }); - } - - const node: PermissionsNode = { - id: target.id, - allow: action === PermissionNodeAction.Allow ? previous.allow.toSpliced(commandIndex, 1) : previous.allow, - deny: action === PermissionNodeAction.Deny ? previous.deny.toSpliced(commandIndex, 1) : previous.deny - }; - - return node.allow.length === 0 && node.deny.length === 0 // - ? nodes.toSpliced(nodeIndex, 1) - : nodes.with(nodeIndex, node); - } - - public reset(target: PermissionNodeValueResolvable): readonly PermissionsNode[] { - const nodes = this.#getPermissionNodes(target); - - const nodeIndex = nodes.findIndex((n) => n.id === target.id); - if (nodeIndex === -1) { - throw new UserError({ identifier: LanguageKeys.Commands.Management.PermissionNodesNodeNotExists, context: { target } }); - } - - return nodes.toSpliced(nodeIndex, 1); - } - - public refresh(settings: ReadonlyGuildData): readonly PermissionsNode[] { - const nodes = settings.permissionsRoles; - this.#cachedRawPermissionRoles = nodes; - this.#cachedRawPermissionUsers = settings.permissionsUsers; - - if (nodes.length === 0) { - this.sorted.clear(); - return nodes; - } - - // Generate sorted data and detect useless nodes to remove - const { pendingToAdd, pendingToRemove } = this.generateSorted(settings, nodes); - - // Set up everything - const sorted = new Collection(); - for (const pending of pendingToAdd) { - sorted.set(pending.id, { - allow: new Set(pending.allow), - deny: new Set(pending.deny) - }); - } - - this.sorted = sorted; - - let copy: PermissionsNode[] | null = null; - - // Delete redundant entries - for (const removedItem of pendingToRemove) { - const removedIndex = nodes.findIndex((element) => element.id === removedItem); - if (removedIndex !== -1) { - copy ??= nodes.slice(); - copy.splice(removedIndex, 1); - } - } - - return copy ?? nodes; - } - - private runUser(member: GuildMember, command: WolfCommand) { - // Assume sorted data - const permissionNodeRoles = this.#cachedRawPermissionUsers; - const memberId = member.id; - for (const node of permissionNodeRoles) { - if (node.id !== memberId) continue; - if (matchAny(node.allow, command)) return true; - if (matchAny(node.deny, command)) return false; - } - - return null; - } - - private runRole(member: GuildMember, command: WolfCommand) { - const roles = member.roles.cache; - - // Assume sorted data - for (const [id, node] of this.sorted.entries()) { - if (!roles.has(id)) continue; - if (matchAny(node.allow, command)) return true; - if (matchAny(node.deny, command)) return false; - } - - return null; - } - - private generateSorted(settings: ReadonlyGuildData, nodes: readonly PermissionsNode[]) { - const { pendingToRemove, sortedRoles } = this.getSortedRoles(settings, nodes); - - const sortedNodes: PermissionsNode[] = []; - for (const sortedRole of sortedRoles.values()) { - const node = nodes.find((node) => node.id === sortedRole.id); - if (node === undefined) continue; - - sortedNodes.push(node); - } - - return { - pendingToAdd: sortedNodes, - pendingToRemove - }; - } - - private getSortedRoles(settings: ReadonlyGuildData, rawNodes: readonly PermissionsNode[]) { - const ids = new Set(rawNodes.map((rawNode) => rawNode.id)); - const guild = resolveGuild(settings.id); - - // I know we should never rely on private methods, however, `Guild#_sortedRoles` - // exists in v13 and is called every time the `Role#position` getter is called, - // so to avoid doing a very expensive call for each role, we will call this once - // and then handle whatever it returns. This has a cost of O(n * log(n)), which is - // pretty good. For 255 role permission nodes, this would do 1,413 checks. - // - // An alternative is to filter, then map the roles by their position, but that has - // a cost of O(n) * O(n * log(n)), which is really bad, with a total amount of - // 360,320 checks. - // - // Although that's also theoretical, `Guild#_sortedRoles` calls `Util.discordSort` - // with the role cache, which besides checking for positions, also does up to 4 - // string operations (`String#slice()` and `Number(string)` in each), which is - // already a performance killer. - // - // eslint-disable-next-line @typescript-eslint/dot-notation - const roles = guild['_sortedRoles']() - // Set#delete returns `true` when the entry exists, so we will use this - // to automatically sweep the valid entries and leave the invalid ones out - .filter((role) => ids.delete(role.id)); - - // Guild#_sortedRoles sorts in the inverse order, so we need to turn it into an array and reverse it: - const reversed = [...roles.values()].reverse(); - - return { - pendingToRemove: ids, - sortedRoles: reversed - }; - } - - private getName(type: PermissionNodeAction) { - switch (type) { - case PermissionNodeAction.Allow: - return 'allow'; - case PermissionNodeAction.Deny: - return 'deny'; - default: - throw new Error('Unreachable'); - } - } - - #getPermissionNodes(target: PermissionNodeValueResolvable): readonly PermissionsNode[] { - return target instanceof Role ? this.#cachedRawPermissionRoles : this.#cachedRawPermissionUsers; - } -} - -interface PermissionsManagerNode { - allow: Set; - deny: Set; -} diff --git a/src/lib/database/settings/structures/Serializer.ts b/src/lib/database/settings/structures/Serializer.ts deleted file mode 100644 index b08ec3117..000000000 --- a/src/lib/database/settings/structures/Serializer.ts +++ /dev/null @@ -1,187 +0,0 @@ -import type { SchemaKey } from '#lib/database/settings/schema/SchemaKey'; -import type { ReadonlyGuildData } from '#lib/database/settings/types'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { translate } from '#lib/i18n/translate'; -import type { WolfArgs } from '#lib/structures'; -import { AliasPiece, ArgumentError, UserError } from '@sapphire/framework'; -import type { TFunction } from '@sapphire/plugin-i18next'; -import { Result } from '@sapphire/result'; -import type { Awaitable } from '@sapphire/utilities'; -import type { Guild } from 'discord.js'; - -export type SerializerResult = Result; -export type AsyncSerializerResult = Promise>; - -export abstract class Serializer extends AliasPiece { - /** - * Resolves a string into a value. - * @param value The value to parsed. - * @param context The context for the key. - */ - public abstract parse(args: Serializer.Args, context: Serializer.UpdateContext): SerializerResult | AsyncSerializerResult; - - /** - * Check whether or not the value is valid. - * @param value The value to check. - */ - public abstract isValid(value: T, context: Serializer.UpdateContext): Awaitable; - - /** - * The stringify method to be overwritten in actual Serializers - * @param data The data to stringify - * @param guild The guild given for context in this call - */ - // eslint-disable-next-line @typescript-eslint/no-unused-vars - public stringify(data: Readonly, _context: Serializer.UpdateContext): string { - return String(data); - } - - /** - * Check if two entries are equals. - * @param left The left value to check against. - * @param right The right value to check against. - */ - public equals(left: T, right: T): boolean { - return left === right; - } - - /** - * Returns a SerializerResult from a Result. - * @param args The Args parser. - * @param result The result to handle. - */ - protected result(args: Serializer.Args, result: Result): SerializerResult { - return result.mapErrInto((error) => this.errorFromArgument(args, error)); - } - - /** - * Returns a successful result. - * @param value The value to return. - */ - protected ok(value: T): SerializerResult { - return Result.ok(value); - } - - /** - * Returns an erroneous result. - * @param error The message of the error. - */ - protected error(error: string): SerializerResult { - return Result.err(new Error(error)); - } - - protected errorFromArgument(args: Serializer.Args, error: UserError): SerializerResult; - /** - * Returns an erroneous result given an ArgumentError. - * @param args The Args parser. - * @param error The error returned by the Argument. - */ - protected errorFromArgument(args: Serializer.Args, error: ArgumentError): SerializerResult; - protected errorFromArgument(args: Serializer.Args, error: UserError | ArgumentError): SerializerResult { - const argument = error instanceof ArgumentError ? error.argument.name : 'Unknown'; - const identifier = translate(error.identifier); - return this.error(args.t(identifier, { ...error, ...(error.context as object), argument })); - } - - /** - * Check the boundaries of a key's minimum or maximum. - * @param length The value to check - * @param entry The schema entry that manages the key - * @param language The language that is used for this context - */ - protected minOrMax(value: T, length: number, { entry: { minimum, maximum, inclusive, name }, t }: Serializer.UpdateContext): SerializerResult { - if (minimum !== null && maximum !== null) { - if ((length >= minimum && length <= maximum && inclusive) || (length > minimum && length < maximum && !inclusive)) { - return this.ok(value); - } - - if (minimum === maximum) { - return this.error( - t(inclusive ? LanguageKeys.Serializers.MinMaxExactlyInclusive : LanguageKeys.Serializers.MinMaxExactlyExclusive, { - name, - min: minimum - }) - ); - } - - return this.error( - t(inclusive ? LanguageKeys.Serializers.MinMaxBothInclusive : LanguageKeys.Serializers.MinMaxBothExclusive, { - name, - min: minimum, - max: maximum - }) - ); - } - - if (minimum !== null) { - if ((length >= minimum && inclusive) || (length > minimum && !inclusive)) { - return this.ok(value); - } - - return this.error( - t(inclusive ? LanguageKeys.Serializers.MinMaxMinInclusive : LanguageKeys.Serializers.MinMaxMinExclusive, { - name, - min: minimum - }) - ); - } - - if (maximum !== null) { - if ((length <= maximum && inclusive) || (length < maximum && !inclusive)) { - return this.ok(value); - } - - return this.error( - t(inclusive ? LanguageKeys.Serializers.MinMaxMaxInclusive : LanguageKeys.Serializers.MinMaxMaxExclusive, { - name, - max: maximum - }) - ); - } - - return this.ok(value); - } -} - -export namespace Serializer { - export type Options = AliasPiece.Options; - export type Args = WolfArgs; - export type UpdateContext = SerializerUpdateContext; - - export type Name = - | 'boolean' - | 'categoryOrTextChannel' - | 'guildTextChannel' - | 'guildVoiceChannel' - | 'guildCategoryChannel' - | 'command' - | 'commandAutoDelete' - | 'commandMatch' - | 'disabledCommandChannel' - | 'emoji' - | 'guild' - | 'invite' - | 'language' - | 'notAllowed' - | 'number' - | 'integer' - | 'float' - | 'permissionNode' - | 'reactionRole' - | 'role' - | 'snowflake' - | 'stickyRole' - | 'string' - | 'timespan' - | 'uniqueRoleSet' - | 'url' - | 'user' - | 'word'; -} - -export interface SerializerUpdateContext { - entry: SchemaKey; - entity: ReadonlyGuildData; - guild: Guild; - t: TFunction; -} diff --git a/src/lib/database/settings/structures/SerializerStore.ts b/src/lib/database/settings/structures/SerializerStore.ts deleted file mode 100644 index c7f59a6e6..000000000 --- a/src/lib/database/settings/structures/SerializerStore.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Serializer } from '#lib/database/settings/structures/Serializer'; -import { AliasStore } from '@sapphire/framework'; - -export class SerializerStore extends AliasStore, 'serializers'> { - /** - * Constructs our SerializerStore for use in Wolf. - * @param client The client that instantiates this store - */ - public constructor() { - super(Serializer, { name: 'serializers' }); - } -} diff --git a/src/lib/database/settings/structures/collections/AliasedCollection.ts b/src/lib/database/settings/structures/collections/AliasedCollection.ts deleted file mode 100644 index 8833e018e..000000000 --- a/src/lib/database/settings/structures/collections/AliasedCollection.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Collection } from 'discord.js'; - -export class AliasedCollection extends Collection { - /** - * The aliases for this collection: - */ - public readonly aliases = new Collection(); - - public override get(key: K): V | undefined { - return super.get(key) ?? this.aliases.get(key); - } -} diff --git a/src/lib/database/settings/types.ts b/src/lib/database/settings/types.ts deleted file mode 100644 index 6bc7557cd..000000000 --- a/src/lib/database/settings/types.ts +++ /dev/null @@ -1,77 +0,0 @@ -import type { Guild as GuildData } from '#generated/prisma'; -import type { DeepReadonly, PickByValue } from '@sapphire/utilities'; -import type { APIGuildMember } from 'discord-api-types/v10'; - -export type GuildDataKey = keyof GuildData; -export type GuildDataValue = GuildData[GuildDataKey]; - -export type ReadonlyGuildData = DeepReadonly; -export type ReadonlyGuildDataValue = DeepReadonly; - -export type GuildSettingsOfType = PickByValue; - -import type { SerializedEmoji } from '#utils/functions'; -import type { Snowflake } from 'discord.js'; - -export type { CommandLog as CommandLogData, Guild as GuildData, Moderation as ModerationData, User as UserData } from '#generated/prisma'; - -export type DashboardAuditAction = - | 'guild.settings.update' - | 'guild.settings.add' - | 'guild.settings.remove' - | 'guild.settings.access-denied' - | 'guild.command.execute'; - -export type AuditOutcome = 'success' | 'failure' | 'denied'; - -export interface DashboardAuditChanges { - added?: Record; - removed?: Record; - changed?: Record; -} - -export interface AuditEventChanges { - before?: Record; - after?: Record; -} - -export interface DashboardAuditEntry { - id: string; - guildId: string; - action: DashboardAuditAction; - outcome: AuditOutcome; - member: APIGuildMember; - changes: DashboardAuditChanges; - reason: string | null; - timestamp: string; -} - -export interface PermissionsNode { - allow: readonly Snowflake[]; - deny: readonly Snowflake[]; - id: Snowflake; -} - -export type CommandAutoDelete = readonly [Snowflake, number]; - -export interface DisabledCommandChannel { - channel: Snowflake; - commands: readonly Snowflake[]; -} - -export interface StickyRole { - roles: readonly Snowflake[]; - user: Snowflake; -} - -export interface ReactionRole { - channel: Snowflake; - emoji: SerializedEmoji; - message: Snowflake | null; - role: Snowflake; -} - -export interface UniqueRoleSet { - name: string; - roles: readonly Snowflake[]; -} diff --git a/src/lib/database/utils/Adder.ts b/src/lib/database/utils/Adder.ts deleted file mode 100644 index f88653bec..000000000 --- a/src/lib/database/utils/Adder.ts +++ /dev/null @@ -1,116 +0,0 @@ -export class AdderError extends Error { - /** - * The amount of points the adder reached when it threw this error. - */ - public readonly amount: number; - - /** - * Constructs an AdderError instance. - * @param message The message to be passed to the Error constructor - * @param amount The amount of points the adder reached when it threw this error - */ - public constructor(message: string, amount: number) { - super(message); - this.amount = amount; - } -} - -export class Adder extends Array<{ id: T; end: number }> { - /** - * The maximum amount of entries in this instance. - */ - public maximum: number; - - /** - * The duration for each entry in this instance. - */ - public duration: number; - - /** - * Whether or not the Adder should auto-remove when it reaches its maximum. - */ - public autoRemove: boolean; - - /** - * Constructs a new Adder instance. - * @param maximum The maximum amount of entries that can be stored, this is inclusive. - * @param duration The duration of which entries expire. - * @param autoRemove Whether or not the Adder should automatically remove when a set of items reaches its maximum. - */ - public constructor(maximum: number, duration: number, autoRemove = false) { - super(); - this.maximum = maximum; - this.duration = duration; - this.autoRemove = autoRemove; - } - - /** - * Add a new entry to the adder, throws if it reaches its maximum. - * @param id The element to push - * @param times The amount of times to push it. - * @returns The amount of elements with the same id after the modifications. - */ - public add(id: T, times = 1) { - // Perform a sweep to remove expired elements, then count. - this.sweep(); - const amount = this.count(id) + times; - - // Push the elements to the end. - for (let i = 0; i < times; i++) { - this.push({ id, end: Date.now() + this.duration }); - } - - // If maximum, throw. - if (amount >= this.maximum) { - if (this.autoRemove) this.remove(id); - throw new AdderError('Limit Reached', amount); - } - - return amount; - } - - /** - * Remove all entries matching an ID. - * @param id The ID to remove. - * @returns The amount of elements removed. - */ - public remove(id: T) { - let deleted = 0; - let i = 0; - let entry: { id: T; end: number }; - - while (i < this.length) { - entry = this[i]; - if (entry.id === id) { - this.splice(i, 1); - deleted++; - } else { - i++; - } - } - - return deleted; - } - - /** - * Count all entries with the same ID. - * @param id The ID to match against. - * @returns The amount of entries matching the same ID. - */ - public count(id: T) { - return this.reduce((count, entry) => (entry.id === id ? count + 1 : count), 0); - } - - /** - * Sweep all expired entries. - * @returns The amount of deleted entries. - */ - public sweep() { - const now = Date.now(); - let i = 0; - while (i < this.length && this[i].end <= now) i++; - if (i !== 0) this.splice(0, i); - - return i; - } -} diff --git a/src/lib/database/utils/matchers/Command.ts b/src/lib/database/utils/matchers/Command.ts deleted file mode 100644 index 1ac8992ae..000000000 --- a/src/lib/database/utils/matchers/Command.ts +++ /dev/null @@ -1,120 +0,0 @@ -import type { WolfCommand } from '#lib/structures'; -import { CommandStore, container } from '@sapphire/framework'; -import { isNullish } from '@sapphire/utilities'; - -function getNameSpaceDetails(name: string): readonly [string | null, string] { - const index = name.indexOf('.'); - if (index === -1) return [null, name]; - return [name.substring(0, index), name.substring(index + 1)]; -} - -function matchName(name: string, command: WolfCommand): boolean { - return command.name === name || command.aliases.some((alias) => alias === name); -} - -function matchNameAndCategory(name: string, category: string, command: WolfCommand): boolean { - return command.category === category && matchName(name, command); -} - -function matchNameCategoryAndSubCategory(name: string, category: string, subCategory: string, command: WolfCommand): boolean { - return command.subCategory === subCategory && matchNameAndCategory(name, category, command); -} - -export function matchAny(names: Iterable, command: WolfCommand): boolean { - for (const name of names) { - if (match(name, command)) return true; - } - return false; -} - -export function match(name: string, command: WolfCommand): boolean { - // Match All: - if (name === '*') return true; - - // Match Category: - const [category, categoryRest] = getNameSpaceDetails(name); - if (category === null) return matchName(name, command); - if (category !== command.category) return false; - if (categoryRest === '*') return true; - - // Match Sub-Category: - const [subCategory, subCategoryRest] = getNameSpaceDetails(categoryRest); - if (subCategory === null) return matchNameAndCategory(name, category, command); - if (subCategory !== command.subCategory) return false; - if (subCategoryRest === '*') return true; - - // Match Command: - return matchNameCategoryAndSubCategory(subCategoryRest, category, subCategory, command); -} - -function resolveCategory(commands: CommandStore, category: string): string | null { - const scanned = new Set(); - const lowerCaseCategory = category.toLowerCase(); - - for (const command of commands.values()) { - const value = command.category; - if (isNullish(value)) continue; - if (scanned.has(value)) continue; - if (value.toLowerCase() === lowerCaseCategory) return value; - scanned.add(value); - } - - return null; -} - -function resolveSubCategory(commands: CommandStore, category: string, subCategory: string): string | null { - const scanned = new Set(); - const lowerCaseSubCategory = subCategory.toLowerCase(); - - for (const command of commands.values()) { - if (command.category !== category) continue; - - const { subCategory } = command; - if (isNullish(subCategory)) continue; - - if (scanned.has(subCategory)) continue; - if (subCategory.toLowerCase() === lowerCaseSubCategory) return subCategory; - scanned.add(subCategory); - } - - return null; -} - -function resolveCommandWithCategory(commands: CommandStore, name: string, category: string): string | null { - const command = commands.get(name) as WolfCommand | undefined; - if (command === undefined) return null; - return command.category === category ? command.name : null; -} - -function resolveCommandWithCategoryAndSubCategory(commands: CommandStore, name: string, category: string, subCategory: string): string | null { - const command = commands.get(name) as WolfCommand | undefined; - if (command === undefined) return null; - return command.category === category && command.subCategory === subCategory ? command.name : null; -} - -export function resolve(name: string): string | null { - // Match All: - if (name === '*') return name; - - const parts = name.split('.'); - - // If it's an empty string, or has more than three parts, it is invalid: - if (parts.length === 0 || parts.length > 3) return null; - - const commands = container.stores.get('commands'); - - // Handle `${command}`: - if (parts.length === 1) return commands.get(name.toLowerCase())?.name ?? null; - - // Handle `${category}.${string}`: - const category = resolveCategory(commands, parts[0]); - if (category === null) return null; - if (parts.length === 2) return parts[1] === '*' ? `${category}.*` : resolveCommandWithCategory(commands, parts[1].toLowerCase(), category); - - // Handle `${category}.${category}.${string}`: - const subCategory = resolveSubCategory(commands, category, parts[1]); - if (subCategory === null) return null; - return parts[2] === '*' - ? `${category}.${subCategory}.*` - : resolveCommandWithCategoryAndSubCategory(commands, parts[2].toLowerCase(), category, subCategory); -} diff --git a/src/lib/database/utils/matchers/index.ts b/src/lib/database/utils/matchers/index.ts deleted file mode 100644 index 6d277c8b4..000000000 --- a/src/lib/database/utils/matchers/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * as CommandMatcher from '#lib/database/utils/matchers/Command'; diff --git a/src/lib/discord/Api.ts b/src/lib/discord/Api.ts deleted file mode 100644 index 2bc8a014f..000000000 --- a/src/lib/discord/Api.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { API } from '@discordjs/core/http-only'; -import { container } from '@sapphire/framework'; - -export function api() { - return (container.api ??= new API(container.client.rest as any)); -} diff --git a/src/lib/discord/index.ts b/src/lib/discord/index.ts deleted file mode 100644 index dd28ec944..000000000 --- a/src/lib/discord/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from '#lib/discord/GuildMemberFetchQueue'; diff --git a/src/lib/games/HungerGamesUsage.ts b/src/lib/games/HungerGamesUsage.ts deleted file mode 100644 index 8d1b4b045..000000000 --- a/src/lib/games/HungerGamesUsage.ts +++ /dev/null @@ -1,49 +0,0 @@ -export class HungerGamesUsage { - public tributes = 0; - public deaths: Set = new Set(); - private readonly parts: (string | number)[] = []; - - public constructor(usage: string) { - this.parse(usage); - } - - public display(...values: string[]) { - return this.parts.map((part) => (typeof part === 'number' ? values[part] : part)).join(''); - } - - public parse(usage: string): void { - let current = ''; - for (let i = 0, char; i < usage.length; i++) { - char = usage.charAt(i); - if (char === '{') { - // If there was text, push buffer - if (current) { - this.parts.push(current); - current = ''; - } - - // Parse tag {NT?} - const n = Number(usage.charAt(++i)); - - // If N > tributes, assign tributes to N - if (n > this.tributes) this.tributes = n; - - // If NT, add death - if (usage.charAt(++i) === 'T') { - this.deaths.add(n - 1); - i++; - } - - this.parts.push(n - 1); - } else { - current += char; - } - } - - if (current) this.parts.push(current); - } - - public static create(usage: string): HungerGamesUsage { - return new HungerGamesUsage(usage); - } -} diff --git a/src/lib/games/TriviaManager.ts b/src/lib/games/TriviaManager.ts deleted file mode 100644 index 1c4357d50..000000000 --- a/src/lib/games/TriviaManager.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { fetch, FetchResultTypes } from '@sapphire/fetch'; - -export const enum TriviaResponseCode { - Success, - NoResults, - InvalidParameter, - TokenNotFound, - TokenEmpty -} - -export interface TriviaResultOk { - response_code: TriviaResponseCode; - results: QuestionData[]; -} - -/** - * The question object returned by OpenTDB - */ -export interface QuestionData { - category: string; - type: QuestionType; - difficulty: QuestionDifficulty; - question: string; - correct_answer: string; - incorrect_answers: string[]; -} - -export const enum QuestionType { - Boolean = 'boolean', - Multiple = 'multiple' -} - -export const enum QuestionDifficulty { - Easy = 'easy', - Medium = 'medium', - Hard = 'hard' -} - -export const CATEGORIES = { - general: 9, - books: 10, - film: 11, - music: 12, - theatres: 13, - tv: 14, - videogames: 15, - boardgames: 16, - nature: 17, - computers: 18, - maths: 19, - mythology: 20, - sports: 21, - geography: 22, - history: 23, - politics: 24, - art: 25, - celebrities: 26, - animals: 27, - vehicles: 28, - comics: 29, - gadgets: 30, - manga: 31, - cartoon: 32 -}; - -export async function getQuestion(category: number, difficulty = QuestionDifficulty.Easy, questionType = QuestionType.Multiple) { - const url = new URL('https://opentdb.com/api.php'); - url.searchParams.append('amount', '1'); - url.searchParams.append('category', category.toString()); - url.searchParams.append('difficulty', difficulty); - url.searchParams.append('type', questionType); - - const data = await fetch(url, FetchResultTypes.JSON); - const { response_code, results } = data; - if (response_code === 0 && results.length) return results[0]; - throw new Error('Invalid request'); -} diff --git a/src/lib/games/base/BaseBotController.ts b/src/lib/games/base/BaseBotController.ts deleted file mode 100644 index 3626c214f..000000000 --- a/src/lib/games/base/BaseBotController.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { BaseController } from '#lib/games/base/BaseController'; - -export abstract class BaseBotController extends BaseController { - public constructor() { - super(process.env.CLIENT_NAME); - } - - protected resolveCollectedValidity(): boolean { - return true; - } -} diff --git a/src/lib/games/base/BaseController.ts b/src/lib/games/base/BaseController.ts deleted file mode 100644 index af1ba52a2..000000000 --- a/src/lib/games/base/BaseController.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { BaseGame, GameTurn } from '#lib/games/base/BaseGame'; - -export abstract class BaseController { - public readonly name: string; - - public turn: GameTurn = GameTurn.PlayerA; - public game: BaseGame = null!; - - public constructor(name: string) { - this.name = name; - } - - public setTurn(turn: GameTurn): this { - this.turn = turn; - return this; - } - - public setGame(game: BaseGame): this { - this.game = game; - return this; - } - - public abstract await(): Promise | T; -} diff --git a/src/lib/games/base/BaseGame.ts b/src/lib/games/base/BaseGame.ts deleted file mode 100644 index af0a69c06..000000000 --- a/src/lib/games/base/BaseGame.ts +++ /dev/null @@ -1,85 +0,0 @@ -import type { BaseController } from '#lib/games/base/BaseController'; -import type { TFunction } from '@sapphire/plugin-i18next'; -import { fetchT } from '@sapphire/plugin-i18next'; -import type { Client, Message } from 'discord.js'; - -export const enum GameTurn { - PlayerA, - PlayerB -} - -export const enum GameStatus { - Start, - Update, - End -} - -export abstract class BaseGame { - public message: Message; - public t: TFunction = null!; - public readonly playerA: BaseController; - public readonly playerB: BaseController; - public turn: GameTurn; - - public constructor(message: Message, playerA: BaseController, playerB: BaseController, turn = BaseGame.getTurn()) { - this.message = message; - this.playerA = playerA.setTurn(GameTurn.PlayerA).setGame(this); - this.playerB = playerB.setTurn(GameTurn.PlayerB).setGame(this); - this.turn = turn; - } - - protected abstract get finished(): boolean; - - protected get player(): BaseController { - return this.turn === GameTurn.PlayerA ? this.playerA : this.playerB; - } - - protected get client(): Client { - return this.message.client; - } - - public async run() { - this.t = await fetchT(this.message); - await this.onStart(); - - while (true) { - // Read player's move: - const { player } = this; - const value = await player.await(); - await this.handle(value, player); - - // If finished, break loop: - if (this.finished) break; - - // Query an update and switch player: - this.nextPlayer(); - await this.onUpdate(); - } - - await this.onEnd(); - } - - protected nextPlayer() { - this.turn = this.turn === GameTurn.PlayerA ? GameTurn.PlayerB : GameTurn.PlayerA; - } - - protected abstract handle(value: T, player: BaseController): unknown; - - protected onStart(): Promise { - return this.message.edit({ content: this.render(GameStatus.Start), embeds: [], attachments: [] }); - } - - protected onUpdate(): Promise { - return this.message.edit({ content: this.render(GameStatus.Update), embeds: [], attachments: [] }); - } - - protected onEnd(): Promise { - return this.message.edit({ content: this.render(GameStatus.End), embeds: [], attachments: [] }); - } - - protected abstract render(status: GameStatus): string; - - protected static getTurn(): GameTurn { - return Math.random() < 0.5 ? GameTurn.PlayerA : GameTurn.PlayerB; - } -} diff --git a/src/lib/games/base/BaseReactionController.ts b/src/lib/games/base/BaseReactionController.ts deleted file mode 100644 index c7a6899bf..000000000 --- a/src/lib/games/base/BaseReactionController.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { api } from '#lib/discord/Api'; -import { BaseController } from '#lib/games/base/BaseController'; -import type { BaseReactionGame } from '#lib/games/base/BaseReactionGame'; -import { Events } from '#lib/types'; -import type { LLRCData } from '#utils/LongLivingReactionCollector'; -import { getEmojiReactionFormat, getEmojiString, type SerializedEmoji } from '#utils/functions'; -import { cast } from '#utils/util'; -import { container } from '@sapphire/framework'; -import { DiscordAPIError, RESTJSONErrorCodes } from 'discord.js'; - -export abstract class BaseReactionController extends BaseController { - public readonly userId: string; - - public constructor(name: string, userId: string) { - super(name); - this.userId = userId; - } - - protected async collectAvailableReaction(): Promise { - const game = cast>(this.game); - return new Promise((resolve) => { - game.listener.setTime(game.reactionTime); - game.listener.setListener((data) => { - if (data.userId !== this.userId) return; - if (data.messageId !== game.message.id) return; - - const emoji = getEmojiString(data.emoji); - if (game.reactions.includes(emoji) && this.resolveCollectedValidity(emoji)) { - void this.removeEmoji(data, emoji, this.userId); - game.listener.setListener(null); - game.listener.setTime(-1); - resolve(emoji); - } - }); - - game.listener.setEndListener(() => { - resolve(null); - }); - }); - } - - protected abstract resolveCollectedValidity(collected: string): boolean; - - protected async removeEmoji(reaction: LLRCData, emoji: SerializedEmoji, userId: string): Promise { - try { - await api().channels.deleteUserMessageReaction(reaction.channel.id, reaction.messageId, getEmojiReactionFormat(emoji), userId); - } catch (error) { - if (error instanceof DiscordAPIError) { - if (error.code === RESTJSONErrorCodes.UnknownMessage || error.code === RESTJSONErrorCodes.UnknownEmoji) return; - } - - container.client.emit(Events.Error, error); - } - } -} diff --git a/src/lib/games/base/BaseReactionGame.ts b/src/lib/games/base/BaseReactionGame.ts deleted file mode 100644 index f76b9bc94..000000000 --- a/src/lib/games/base/BaseReactionGame.ts +++ /dev/null @@ -1,48 +0,0 @@ -import type { BaseController } from '#lib/games/base/BaseController'; -import { BaseGame } from '#lib/games/base/BaseGame'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { Events } from '#lib/types'; -import { LongLivingReactionCollector } from '#utils/LongLivingReactionCollector'; -import { sendLoadingMessage } from '#utils/util'; -import { send } from '@sapphire/plugin-editable-commands'; -import type { Message } from 'discord.js'; - -export abstract class BaseReactionGame extends BaseGame { - public readonly reactions: readonly string[]; - public readonly listener: LongLivingReactionCollector; - public readonly reactionTime: number; - - public constructor( - message: Message, - playerA: BaseController, - playerB: BaseController, - reactions: readonly string[], - reactionTime: number, - turn = BaseGame.getTurn() - ) { - super(message, playerA, playerB, turn); - this.reactions = reactions; - this.reactionTime = reactionTime; - this.listener = new LongLivingReactionCollector(); - } - - protected override async onStart(): Promise { - try { - this.message = await sendLoadingMessage(this.message, this.t); - for (const reaction of this.reactions) await this.message.react(reaction); - } catch { - await send(this.message, this.t(LanguageKeys.Misc.UnexpectedIssue)).catch((error) => this.client.emit(Events.Error, error)); - } - - return super.onStart(); - } - - protected get finished(): boolean { - return this.listener.ended; - } - - protected override onEnd(): Promise { - this.listener.end(); - return super.onEnd(); - } -} diff --git a/src/lib/games/connect-four/ConnectFourBotController.ts b/src/lib/games/connect-four/ConnectFourBotController.ts deleted file mode 100644 index 50e7eb151..000000000 --- a/src/lib/games/connect-four/ConnectFourBotController.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { BaseBotController } from '#lib/games/base/BaseBotController'; -import type { ConnectFourGame } from '#lib/games/connect-four/ConnectFourGame'; -import { cast } from '#utils/util'; -import { ConnectFour } from '@skyra/ai'; - -export class ConnectFourBotController extends BaseBotController { - private readonly depth: number; - - public constructor(depth: number) { - super(); - this.depth = depth; - } - - public await(): number { - const game = cast(this.game); - const ai = new ConnectFour(game.board); - return ai.getBestMove(this.depth); - } -} diff --git a/src/lib/games/connect-four/ConnectFourGame.ts b/src/lib/games/connect-four/ConnectFourGame.ts deleted file mode 100644 index 79a134668..000000000 --- a/src/lib/games/connect-four/ConnectFourGame.ts +++ /dev/null @@ -1,307 +0,0 @@ -import type { BaseController } from '#lib/games/base/BaseController'; -import { GameStatus } from '#lib/games/base/BaseGame'; -import { BaseReactionGame } from '#lib/games/base/BaseReactionGame'; -import { Emojis } from '#lib/games/connect-four/lib/constants'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { minutes } from '#utils/common'; -import type { SerializedEmoji } from '#utils/functions'; -import type { Message } from 'discord.js'; - -export enum Cell { - Empty, - PlayerOne, - PlayerTwo, - WinnerPlayerOne, - WinnerPlayerTwo -} - -export const columns = 7; -export const rows = 6; -const renderMargin = ' '.repeat(7); - -export class ConnectFourGame extends BaseReactionGame { - public readonly board = new Uint8Array(columns * rows); - public readonly remaining = new Uint8Array(columns).fill(rows); - private winner: readonly [number, number][] | null = null; - - public constructor(message: Message, playerA: BaseController, playerB: BaseController, turn = ConnectFourGame.getTurn()) { - super(message, playerA, playerB, ConnectFourGame.emojis, minutes(5), turn); - } - - public override get finished() { - return super.finished || this.winner !== null || this.isTableFull(); - } - - protected handle(value: number, player: BaseController): void { - if (value !== -1) { - const y = --this.remaining[value]; - this.setAt(value, y, player.turn + 1); - this.winner = this.check(value, y); - if (this.winner !== null) { - // + 1 is used to show the color, + 2 is used to show the winner - const cell = player.turn + 3; - for (const [x, y] of this.winner) { - this.setAt(x, y, cell); - } - } - } - } - - protected render(status: GameStatus): string { - return status === GameStatus.End ? this.renderOnEnd() : this.renderOnUpdateOrStart(); - } - - protected renderOnEnd() { - return this.winner === null - ? this.t(LanguageKeys.Commands.Games.TicTacToeDraw, { board: this.renderBoard() }) - : this.t(LanguageKeys.Commands.Games.TicTacToeWinner, { - winner: this.player.name, - board: this.renderBoard() - }); - } - - protected renderOnUpdateOrStart(): string { - return this.t(LanguageKeys.Commands.Games.TicTacToeTurn, { - icon: ConnectFourGame.players[this.turn], - player: this.player.name, - board: this.renderBoard() - }); - } - - protected renderBoard(): string { - const output: string[] = []; - for (let y = 0; y < rows; ++y) { - // Render each line - const line: string[] = []; - for (let x = 0; x < columns; ++x) { - line.push(ConnectFourGame.renderCell(this.getAt(x, y))); - } - output.push(line.join(renderMargin)); - } - - return output.join('\n'); - } - - private setAt(x: number, y: number, value: Cell) { - const cell = x + y * columns; - this.board[cell] = value; - } - - private getAt(x: number, y: number) { - const cell = x + y * columns; - return this.board[cell]; - } - - private check(x: number, y: number): readonly [number, number][] | null { - const cell = this.getAt(x, y); - - return ( - this.checkVertical(x, y, cell) || - this.checkHorizontal(x, y, cell) || - this.checkDiagonalTopLeftToBottomRight(x, y, cell) || - this.checkDiagonalBottomLeftToTopRight(x, y, cell) - ); - } - - private isTableFull() { - return this.remaining.every((value) => value === 0); - } - - private checkHorizontal(x: number, y: number, cell: Cell) { - /** - * 00__ 10__ 20__ 30__ 40__ 50__ 60__ - * 01__ 11__ 21__ 31__ 41__ 51__ 61__ - * 02__ 12__ 22__ 32__ 42__ 52__ 62__ - * 03__ 13__ 23__ 33__ 43__ 53__ 63__ - * 04__ 14__ 24_o 34_o 44_o 54__ 64__ - * 05__ 15__ 25_x 35_x 45_x 55_x 65__ - * - * Winning: { 25, 35, 45, 55 } - * Assuming last move as 55. - * - * We retrieve the corner for this move: - * lx = x - 3 - * rx = x + 3 - * - * We iterate from { lx, y } to { rx, y } inclusive, increasing lx by 1. - * - * We will also optimize one case: since this is linear, we don't need to iterate from x - 3 to x + 3, but - * instead, we will iterate from max(x - 3, 0), skipping negatives, to min(x + 3, kColumns - 1), this shortens - * the range from [-3..8] to [0..6]. - */ - - let count = 0; - const rx = Math.min(x + 3, columns - 1); - for (let lx = Math.max(x - 3, 0); lx <= rx; ++lx) { - if (this.getAt(lx, y) === cell) { - if (++count === 4) { - return [ - [lx - 3, y], - [lx - 2, y], - [lx - 1, y], - [lx, y] - ] as [number, number][]; - } - } else { - count = 0; - } - } - - return null; - } - - private checkVertical(x: number, y: number, cell: Cell) { - /** - * 00__ 10__ 20__ 30__ 40__ 50__ 60__ - * 01__ 11__ 21__ 31__ 41__ 51__ 61__ - * 02__ 12__ 22__ 32_x 42__ 52__ 62__ - * 03__ 13__ 23_o 33_x 43__ 53__ 63__ - * 04__ 14__ 24_o 34_x 44__ 54__ 64__ - * 05__ 15__ 25_o 35_x 45__ 55__ 65__ - * - * Winning: { 32, 33, 34, 35 } - * Assuming last move as 32. - * - * Vertical check has one advantage versus the other ways: it needs to check three cells below the used cell, - * and nothing more. This is because cells are filled from bottom to top, so we don't need to check the cells - * in the top as they're always empty, thus saving a lot of computational cost. - * - * We retrieve the corner for this move: - * ty = y + 1 - * by = y + 3 - * - * We will also optimize one case: this needs y + 3 positions to be within the range, so we quickly return null - * when there isn't enough space. - * - * If it has space, we will only check the cells { x, ty } to { x, by } inclusive, { x, y } is not checked - * because it's `cell`'s value. - */ - - // If there aren't enough rows in the same column to qualify, skip early - if (y + 3 >= rows) return null; - - return this.getAt(x, y + 1) === cell && this.getAt(x, y + 2) === cell && this.getAt(x, y + 3) === cell - ? ([ - [x, y], - [x, y + 1], - [x, y + 2], - [x, y + 3] - ] as [number, number][]) - : null; - } - - private checkDiagonalTopLeftToBottomRight(x: number, y: number, cell: Cell) { - /** - * 00__ 10__ 20__ 30__ 40__ 50__ 60__ - * 01__ 11__ 21__ 31__ 41__ 51__ 61__ - * 02_x 12__ 22__ 32__ 42__ 52__ 62__ - * 03_o 13_x 23__ 33__ 43__ 53__ 63__ - * 04_x 14_o 24_x 34_o 44__ 54__ 64__ - * 05_o 15_o 25_o 35_x 45__ 55__ 65__ - * - * Winning: { 02, 13, 24, 35 } - * Assuming last move as 02. - * - * We retrieve the corner for this move: - * clx = x - 3 - * cly = y - 3 - * crx = x + 3 - * cry = y + 3 - * - * We iterate from { clx, cly } to { crx, cry } inclusive, increasing by 1 both numbers. - */ - - let count = 0; - const crx = x + 3; - const cry = y + 3; - for (let clx = x - 3, cly = y - 3; clx <= crx && cly <= cry; ++clx, ++cly) { - // Watch for boundaries, since we are going from top left, we might find cells in our way, we continue. - if (clx < 0 || cly < 0) continue; - - // Watch for boundaries, if one goes to the bottom right, there cannot be more cells, we stop checking. - if (clx === columns || cly === rows) return null; - - if (this.getAt(clx, cly) === cell) { - if (++count === 4) { - return [ - [clx - 3, cly - 3], - [clx - 2, cly - 2], - [clx - 1, cly - 1], - [clx, cly] - ] as [number, number][]; - } - } else { - count = 0; - } - } - - return null; - } - - private checkDiagonalBottomLeftToTopRight(x: number, y: number, cell: Cell) { - /** - * 00__ 10__ 20__ 30__ 40__ 50__ 60__ - * 01__ 11__ 21__ 31__ 41__ 51__ 61__ - * 02__ 12__ 22__ 32__ 42__ 52__ 62_x - * 03__ 13__ 23__ 33__ 43__ 53_x 63_o - * 04__ 14__ 24__ 34__ 44_x 54_o 64_x - * 05__ 15__ 25__ 35_x 45_o 55_o 65_o - * - * Winning: { 35, 44, 53, 62 } - * Assuming last move as 62. - * - * We retrieve the corner for this move: - * clx = x - 3 - * cly = y + 3 - * crx = x + 3 - * cry = y - 3 - * - * We iterate from { clx, cly } to { crx, cry } inclusive, increasing clx by 1 and decreasing cly by 1. - */ - - let count = 0; - const crx = x + 3; - const cry = y + 3; - for (let clx = x - 3, cly = y + 3; clx <= crx && cly <= cry; ++clx, --cly) { - // Watch for boundaries, since we are going from bottom left, we might find cells in our way, we continue. - if (clx < 0 || cly >= rows) continue; - - // Watch for boundaries, if one goes to the bottom right, there cannot be more cells, we stop checking. - if (clx === columns || cly < 0) return null; - - if (this.getAt(clx, cly) === cell) { - if (++count === 4) { - return [ - [clx - 3, cly + 3], - [clx - 2, cly + 2], - [clx - 1, cly + 1], - [clx, cly] - ] as [number, number][]; - } - } else { - count = 0; - } - } - - return null; - } - - private static readonly emojis = ['1️⃣', '2️⃣', '3️⃣', '4️⃣', '5️⃣', '6️⃣', '7️⃣'].map(encodeURIComponent) as SerializedEmoji[]; - - private static readonly players = [Emojis.PlayerOne, Emojis.PlayerTwo] as const; - - private static renderCell(cell: Cell) { - switch (cell) { - case Cell.Empty: - return Emojis.Empty; - case Cell.PlayerOne: - return Emojis.PlayerOne; - case Cell.PlayerTwo: - return Emojis.PlayerTwo; - case Cell.WinnerPlayerOne: - return Emojis.WinnerOne; - case Cell.WinnerPlayerTwo: - return Emojis.WinnerTwo; - } - } -} diff --git a/src/lib/games/connect-four/ConnectFourHumanController.ts b/src/lib/games/connect-four/ConnectFourHumanController.ts deleted file mode 100644 index 4e4f05507..000000000 --- a/src/lib/games/connect-four/ConnectFourHumanController.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { BaseReactionController } from '#lib/games/base/BaseReactionController'; -import type { ConnectFourGame } from '#lib/games/connect-four/ConnectFourGame'; -import { cast } from '#utils/util'; - -export class ConnectFourHumanController extends BaseReactionController { - public async await(): Promise { - const reaction = await this.collectAvailableReaction(); - if (reaction === null) return -1; - - const game = cast(this.game); - return game.reactions.indexOf(reaction); - } - - protected resolveCollectedValidity(collected: string): boolean { - const game = cast(this.game); - const index = game.reactions.indexOf(collected); - return index !== -1 && game.remaining[index] > 0; - } -} diff --git a/src/lib/games/connect-four/lib/constants.ts b/src/lib/games/connect-four/lib/constants.ts deleted file mode 100644 index bb08256ac..000000000 --- a/src/lib/games/connect-four/lib/constants.ts +++ /dev/null @@ -1,7 +0,0 @@ -export const enum Emojis { - Empty = '<:Empty:352403997606412289>', - PlayerOne = '<:PlayerONE:352403997300359169>', - PlayerTwo = '<:PlayerTWO:352404081974968330>', - WinnerOne = '<:PlayerONEWin:352403997761601547>', - WinnerTwo = '<:PlayerTWOWin:352403997958602752>' -} diff --git a/src/lib/games/tic-tac-toe/TicTacToeBotController.ts b/src/lib/games/tic-tac-toe/TicTacToeBotController.ts deleted file mode 100644 index 913eb6a0b..000000000 --- a/src/lib/games/tic-tac-toe/TicTacToeBotController.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { BaseBotController } from '#lib/games/base/BaseBotController'; -import type { TicTacToeGame } from '#lib/games/tic-tac-toe/TicTacToeGame'; -import { cast } from '#utils/util'; -import { TicTacToe } from '@skyra/ai'; - -export class TicTacToeBotController extends BaseBotController { - public await(): number { - const game = cast(this.game); - const ai = new TicTacToe(game.board); - return ai.getBestMove(); - } -} diff --git a/src/lib/games/tic-tac-toe/TicTacToeGame.ts b/src/lib/games/tic-tac-toe/TicTacToeGame.ts deleted file mode 100644 index c199cb58d..000000000 --- a/src/lib/games/tic-tac-toe/TicTacToeGame.ts +++ /dev/null @@ -1,98 +0,0 @@ -import type { BaseController } from '#lib/games/base/BaseController'; -import { GameStatus } from '#lib/games/base/BaseGame'; -import { BaseReactionGame } from '#lib/games/base/BaseReactionGame'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { minutes } from '#utils/common'; -import type { SerializedEmoji } from '#utils/functions'; -import type { Message } from 'discord.js'; - -export class TicTacToeGame extends BaseReactionGame { - public readonly board = new Uint8Array(9); - - public constructor(message: Message, playerA: BaseController, playerB: BaseController, turn = TicTacToeGame.getTurn()) { - super(message, playerA, playerB, TicTacToeGame.emojis, minutes(5), turn); - } - - public override get finished() { - return super.finished || this.board.every((cell) => cell !== 0) || this.check() !== null; - } - - protected handle(value: number, player: BaseController): void { - if (value !== -1) this.board[value] = player.turn + 1; - } - - protected render(status: GameStatus): string { - return status === GameStatus.End ? this.renderOnEnd() : this.renderOnUpdateOrStart(); - } - - protected renderOnEnd() { - const winner = this.check(); - return winner === null - ? this.t(LanguageKeys.Commands.Games.TicTacToeDraw, { board: this.renderBoard() }) - : this.t(LanguageKeys.Commands.Games.TicTacToeWinner, { - winner: this.player.name, - board: this.renderBoard() - }); - } - - protected renderOnUpdateOrStart(): string { - return this.t(LanguageKeys.Commands.Games.TicTacToeTurn, { - icon: TicTacToeGame.player[this.turn], - player: this.player.name, - board: this.renderBoard() - }); - } - - protected renderBoard(): string { - return `${this.renderRow(0)}\n${this.renderRow(1)}\n${this.renderRow(2)}`; - } - - protected renderRow(row: number): string { - const offset = row * 3; - return `${this.renderCell(offset)}${this.renderCell(offset + 1)}${this.renderCell(offset + 2)}`; - } - - protected renderCell(cell: number): string { - const value = this.board[cell]; - return value === 0 ? decodeURIComponent(TicTacToeGame.emojis[cell]) : TicTacToeGame.player[value - 1]; - } - - private equals(a: number, b: number, c: number): boolean { - return a === b && b === c; - } - - private check(): number | null { - // 0 1 2 - // 3 4 5 - // 6 7 8 - - let a = 0; - - // Check rows - for (let i = 0; i < 9; i += 3) { - a = this.board[i]; - if (a !== 0 && this.equals(a, this.board[i + 1], this.board[i + 2])) return a; - } - - // Check columns - for (let i = 0; i < 3; ++i) { - a = this.board[i]; - if (a !== 0 && this.equals(a, this.board[i + 3], this.board[i + 6])) return a; - } - - // Check descending diagonal - // eslint-disable-next-line prefer-destructuring - a = this.board[0]; - if (a !== 0 && this.equals(a, this.board[4], this.board[8])) return a; - - // Check ascending diagonal - // eslint-disable-next-line prefer-destructuring - a = this.board[6]; - if (a !== 0 && this.equals(a, this.board[4], this.board[2])) return a; - - return null; - } - - private static readonly emojis = ['↖', '⬆', '↗', '⬅', '⏺', '➡️', '↙', '⬇', '↘'].map(encodeURIComponent) as SerializedEmoji[]; - private static readonly player = ['⭕', '❌'] as const; -} diff --git a/src/lib/games/tic-tac-toe/TicTacToeHumanController.ts b/src/lib/games/tic-tac-toe/TicTacToeHumanController.ts deleted file mode 100644 index 7614190f2..000000000 --- a/src/lib/games/tic-tac-toe/TicTacToeHumanController.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { BaseReactionController } from '#lib/games/base/BaseReactionController'; -import type { TicTacToeGame } from '#lib/games/tic-tac-toe/TicTacToeGame'; -import { cast } from '#utils/util'; - -export class TicTacToeHumanController extends BaseReactionController { - public async await(): Promise { - const reaction = await this.collectAvailableReaction(); - if (reaction === null) return -1; - - const game = cast(this.game); - return game.reactions.indexOf(reaction); - } - - protected resolveCollectedValidity(collected: string): boolean { - const game = cast(this.game); - const index = game.reactions.indexOf(collected); - return index !== -1 && game.board[index] === 0; - } -} diff --git a/src/lib/i18n/LanguageHelp.ts b/src/lib/i18n/LanguageHelp.ts deleted file mode 100644 index be591e6cb..000000000 --- a/src/lib/i18n/LanguageHelp.ts +++ /dev/null @@ -1,96 +0,0 @@ -export class LanguageHelp { - private aliases: string = null!; - private usages: string = null!; - private extendedHelp: string = null!; - private explainedUsage: string = null!; - private possibleFormats: string = null!; - private examples: string = null!; - private reminder: string = null!; - - public setAliases(text: string) { - this.aliases = text; - return this; - } - - public setUsages(text: string) { - this.usages = text; - return this; - } - - public setExplainedUsage(text: string) { - this.explainedUsage = text; - return this; - } - - public setExtendedHelp(text: string) { - this.extendedHelp = text; - return this; - } - - public setPossibleFormats(text: string) { - this.possibleFormats = text; - return this; - } - - public setExamples(text: string) { - this.examples = text; - return this; - } - - public setReminder(text: string) { - this.reminder = text; - return this; - } - - public display(name: string, aliases: string | null, options: LanguageHelpDisplayOptions, prefixUsed: string) { - const { usages = [], extendedHelp, explainedUsage = [], possibleFormats = [], examples = [], reminder } = options; - const output: string[] = []; - - // Usages - if (usages.length) { - output.push(this.usages, ...usages.map((usage) => `→ ${prefixUsed}${name}${usage.length === 0 ? '' : ` *${usage}*`}`), ''); - } - - if (aliases !== null) { - output.push(`${this.aliases}: ${aliases}`, ''); - } - - // Extended help - if (extendedHelp) { - output.push(this.extendedHelp, extendedHelp, ''); - } - - // Explained usage - if (explainedUsage.length) { - output.push(this.explainedUsage, ...explainedUsage.map(([arg, desc]) => `→ **${arg}**: ${desc}`), ''); - } - - // Possible formats - if (possibleFormats.length) { - output.push(this.possibleFormats, ...possibleFormats.map(([type, example]) => `→ **${type}**: ${example}`), ''); - } - - // Examples - if (examples.length) { - output.push(this.examples, ...examples.map((example) => `→ ${prefixUsed}${name}${example ? ` *${example}*` : ''}`), ''); - } else { - output.push(this.examples, `→ ${prefixUsed}${name}`, ''); - } - - // Reminder - if (reminder) { - output.push(this.reminder, reminder); - } - - return output.join('\n'); - } -} - -export interface LanguageHelpDisplayOptions { - usages?: string[]; - extendedHelp?: string; - explainedUsage?: [string, string][]; - possibleFormats?: [string, string][]; - examples?: (null | string)[]; - reminder?: string; -} diff --git a/src/lib/i18n/index.ts b/src/lib/i18n/index.ts deleted file mode 100644 index ba6f84cff..000000000 --- a/src/lib/i18n/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from '#lib/i18n/translate'; diff --git a/src/lib/i18n/languageKeys/index.ts b/src/lib/i18n/languageKeys/index.ts deleted file mode 100644 index 322bbf4f3..000000000 --- a/src/lib/i18n/languageKeys/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * as LanguageKeys from '#lib/i18n/languageKeys/keys/All'; diff --git a/src/lib/i18n/languageKeys/keys/All.ts b/src/lib/i18n/languageKeys/keys/All.ts deleted file mode 100644 index 9050553d8..000000000 --- a/src/lib/i18n/languageKeys/keys/All.ts +++ /dev/null @@ -1,14 +0,0 @@ -export * as Arguments from '#lib/i18n/languageKeys/keys/Arguments'; -export * as Assertions from '#lib/i18n/languageKeys/keys/Assertions'; -export * as Commands from '#lib/i18n/languageKeys/keys/Commands'; -export * as Errors from '#lib/i18n/languageKeys/keys/Errors'; -export * as FuzzySearch from '#lib/i18n/languageKeys/keys/FuzzySearch'; -export * as Globals from '#lib/i18n/languageKeys/keys/Globals'; -export * as Guilds from '#lib/i18n/languageKeys/keys/Guilds'; -export * as Misc from '#lib/i18n/languageKeys/keys/Misc'; -export * as Moderation from '#lib/i18n/languageKeys/keys/Moderation'; -export * as Preconditions from '#lib/i18n/languageKeys/keys/Preconditions'; -export * as Serializers from '#lib/i18n/languageKeys/keys/Serializers'; -export * as Settings from '#lib/i18n/languageKeys/keys/Settings'; -export * as System from '#lib/i18n/languageKeys/keys/System'; -export * as Events from '#lib/i18n/languageKeys/keys/events/All'; diff --git a/src/lib/i18n/languageKeys/keys/Commands.ts b/src/lib/i18n/languageKeys/keys/Commands.ts deleted file mode 100644 index c510a0e5a..000000000 --- a/src/lib/i18n/languageKeys/keys/Commands.ts +++ /dev/null @@ -1,16 +0,0 @@ -export * as Admin from '#lib/i18n/languageKeys/keys/commands/Admin'; -export * as Conf from '#lib/i18n/languageKeys/keys/commands/Conf'; -export * as Permissions from '#lib/i18n/languageKeys/keys/commands/Permissions'; -export * as AutoModeration from '#lib/i18n/languageKeys/keys/commands/AutoModeration'; -export * as Case from '#lib/i18n/languageKeys/keys/commands/Case'; -export * as Fun from '#lib/i18n/languageKeys/keys/commands/Fun'; -export * as Games from '#lib/i18n/languageKeys/keys/commands/Games'; -export * as General from '#lib/i18n/languageKeys/keys/commands/General'; -export * as Info from '#lib/i18n/languageKeys/keys/commands/Info'; -export * as Management from '#lib/i18n/languageKeys/keys/commands/Management'; -export * as Snipe from '#lib/i18n/languageKeys/keys/commands/Snipe'; -export * as Moderation from '#lib/i18n/languageKeys/keys/commands/Moderation'; -export * as Shared from '#lib/i18n/languageKeys/keys/commands/Shared'; -export * as System from '#lib/i18n/languageKeys/keys/commands/System'; -export * as Tools from '#lib/i18n/languageKeys/keys/commands/Tools'; -export * as Whois from '#lib/i18n/languageKeys/keys/commands/Whois'; diff --git a/src/lib/i18n/languageKeys/keys/CustomCommandSerializer/All.ts b/src/lib/i18n/languageKeys/keys/CustomCommandSerializer/All.ts deleted file mode 100644 index ac336f20d..000000000 --- a/src/lib/i18n/languageKeys/keys/CustomCommandSerializer/All.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { FT, T } from '#lib/types'; - -export const InvalidId = T('serializers:customCommandInvalidId'); -export const InvalidAliases = T('serializers:customCommandInvalidAliases'); -export const InvalidEmbed = T('serializers:customCommandInvalidEmbed'); -export const InvalidColor = T('serializers:customCommandInvalidColor'); -export const InvalidContent = T('serializers:customCommandInvalidContent'); -export const InvalidType = FT<{ possibles: readonly string[]; count: number }, string>('serializers:customCommandInvalidType'); -export const MissingParameter = FT<{ type: string }, string>('serializers:customCommandMissingParameter'); diff --git a/src/lib/i18n/languageKeys/keys/DisabledCommandChannels/All.ts b/src/lib/i18n/languageKeys/keys/DisabledCommandChannels/All.ts deleted file mode 100644 index 36a300186..000000000 --- a/src/lib/i18n/languageKeys/keys/DisabledCommandChannels/All.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { FT, T } from '#lib/types'; - -export const ChannelDoesNotExist = T('serializers:disabledCommandChannelsChannelsDoesNotExist'); -export const CommandDoesNotExist = FT<{ name: string }, string>('serializers:disabledCommandChannelsChannelsCommandDoesNotExist'); diff --git a/src/lib/i18n/languageKeys/keys/Errors.ts b/src/lib/i18n/languageKeys/keys/Errors.ts deleted file mode 100644 index 6bc55f12a..000000000 --- a/src/lib/i18n/languageKeys/keys/Errors.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { T } from '#lib/types'; - -export const GenericUnknownChannel = T('errors:genericUnknownChannel'); -export const GenericUnknownGuild = T('errors:genericUnknownGuild'); -export const GenericUnknownMember = T('errors:genericUnknownMember'); -export const GenericUnknownMessage = T('errors:genericUnknownMessage'); -export const GenericUnknownRole = T('errors:genericUnknownRole'); -export const GenericMissingAccess = T('errors:genericMissingAccess'); -export const GenericDiscordInternalServerError = T('errors:genericDiscordInternalServerError'); -export const GenericDiscordGateway = T('errors:genericDiscordGateway'); -export const GenericDiscordUnavailable = T('errors:genericDiscordUnavailable'); diff --git a/src/lib/i18n/languageKeys/keys/Moderation.ts b/src/lib/i18n/languageKeys/keys/Moderation.ts deleted file mode 100644 index e6b2b9748..000000000 --- a/src/lib/i18n/languageKeys/keys/Moderation.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { FT, T } from '#lib/types'; - -export const TypeBan = T('moderation:typeBan'); -export const TypeKick = T('moderation:typeKick'); -export const TypeMute = T('moderation:typeMute'); -export const TypeRestrictedAttachment = T('moderation:typeRestrictedAttachment'); -export const TypeRestrictedEmbed = T('moderation:typeRestrictedEmbed'); -export const TypeRestrictedEmoji = T('moderation:typeRestrictedEmoji'); -export const TypeRestrictedReaction = T('moderation:typeRestrictedReaction'); -export const TypeRestrictedVoice = T('moderation:typeRestrictedVoice'); -export const TypeRoleAdd = T('moderation:typeRoleAdd'); -export const TypeRoleRemove = T('moderation:typeRoleRemove'); -export const TypeSetNickname = T('moderation:typeSetNickname'); -export const TypeSoftban = T('moderation:typeSoftban'); -export const TypeTimeout = T('moderation:typeTimeout'); -export const TypeVoiceKick = T('moderation:typeVoiceKick'); -export const TypeVoiceMute = T('moderation:typeVoiceMute'); -export const TypeWarning = T('moderation:typeWarning'); - -export const MetadataUndo = FT<{ name: string }>('moderation:metadataUndo'); -export const MetadataTemporary = FT<{ name: string }>('moderation:metadataTemporary'); - -export const EmbedUser = FT<{ tag: string; id: string }>('moderation:embedUser'); -export const EmbedDescription = FT<{ type: string; user: string; reason: string }>('moderation:embedDescription'); -export const EmbedDescriptionTemporary = FT<{ type: string; user: string; time: string; reason: string }>('moderation:embedDescriptionTemporary'); -export const EmbedReasonNotSet = FT<{ command: string; caseId: number }>('moderation:embedReasonNotSet'); -export const EmbedFooter = FT<{ caseId: number }>('moderation:embedFooter'); - -// Action status -export const ActionIsActive = T('moderation:actionIsActive'); -export const ActionIsNotActive = T('moderation:actionIsNotActive'); - -// Action status overrides -export const ActionIsActiveRole = T('moderation:actionIsActiveRole'); -export const ActionIsNotActiveRole = T('moderation:actionIsNotActiveRole'); -export const ActionIsActiveRestrictionRole = T('moderation:actionIsActiveRestrictionRole'); -export const ActionIsNotActiveRestrictionRole = T('moderation:actionIsNotActiveRestrictionRole'); -export const ActionIsActiveNickname = T('moderation:actionIsActiveNickname'); -export const ActionIsNotActiveNickname = T('moderation:actionIsNotActiveNickname'); - -export const ActionTargetSelf = T('moderation:actionTargetSelf'); -export const ActionTargetGuildOwner = T('moderation:actionTargetGuildOwner'); -export const ActionTargetWolf = T('moderation:actionTargetWolf'); -export const ActionTargetHigherHierarchyWolf = T('moderation:actionTargetHigherHierarchyWolf'); -export const ActionTargetHigherHierarchyAuthor = T('moderation:actionTargetHigherHierarchyAuthor'); diff --git a/src/lib/i18n/languageKeys/keys/Preconditions.ts b/src/lib/i18n/languageKeys/keys/Preconditions.ts deleted file mode 100644 index 657d8f260..000000000 --- a/src/lib/i18n/languageKeys/keys/Preconditions.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { FT, T } from '#lib/types'; -import type { Command } from '@sapphire/framework'; -import type { ChannelType } from 'discord.js'; - -// Sapphire built-in: -export const ClientPermissions = FT<{ missing: string[] }>('preconditions:clientPermissions'); -export const ClientPermissionsNoClient = T('preconditions:clientPermissionsNoClient'); -export const ClientPermissionsNoPermissions = T('preconditions:clientPermissionsNoPermissions'); -export const RunIn = FT<{ types: ChannelType[] }>('preconditions:runIn'); -export const UserPermissionsNoPermissions = T('preconditions:userPermissionsNoPermissions'); -export const Unavailable = T('preconditions:unavailable'); -export const Cooldown = FT<{ remaining: number }>('preconditions:cooldown'); -export const DisabledGlobal = T('preconditions:disabledGlobal'); -export const Nsfw = T('preconditions:nsfw'); -export const UserPermissions = FT<{ missing: string[] }>('preconditions:userPermissions'); -export const MissingMessageHandler = T('preconditions:missingMessageHandler'); -export const MissingChatInputHandler = T('preconditions:missingChatInputHandler'); -export const MissingContextMenuHandler = T('preconditions:missingContextMenuHandler'); - -// Sapphire built-in (deprecated): -/** @deprecated */ -export const DmOnly = T('preconditions:dmOnly'); -/** @deprecated */ -export const GuildNewsOnly = T('preconditions:guildNewsOnly'); -/** @deprecated */ -export const GuildNewsThreadOnly = T('preconditions:guildNewsThreadOnly'); -/** @deprecated */ -export const GuildOnly = T('preconditions:guildOnly'); -/** @deprecated */ -export const GuildPrivateThreadOnly = T('preconditions:guildPrivateThreadOnly'); -/** @deprecated */ -export const GuildPublicThreadOnly = T('preconditions:guildPublicThreadOnly'); -/** @deprecated */ -export const GuildTextOnly = T('preconditions:guildTextOnly'); -/** @deprecated */ -export const ThreadOnly = T('preconditions:threadOnly'); - -// Wolf: -export const Administrator = FT<{ command: Command }>('preconditions:administrator'); -export const Moderator = FT<{ command: Command }>('preconditions:moderator'); -export const NewsOnly = T('preconditions:newsOnly'); -export const PermissionNodes = T('preconditions:permissionNodes'); -export const ServerOwner = FT<{ command: Command }>('preconditions:serverOwner'); -export const TextOnly = T('preconditions:textOnly'); diff --git a/src/lib/i18n/languageKeys/keys/System.ts b/src/lib/i18n/languageKeys/keys/System.ts deleted file mode 100644 index 691198b4d..000000000 --- a/src/lib/i18n/languageKeys/keys/System.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { T } from '#lib/types'; - -export const FetchBansFail = T('system:fetchBansFail'); -export const Loading = T('system:loading'); -export const DiscordAbortError = T('system:discordAbortError'); -export const HelpTitles = T<{ - aliases: string; - usages: string; - extendedHelp: string; - explainedUsage: string; - possibleFormats: string; - examples: string; - reminders: string; -}>('system:helpTitles'); diff --git a/src/lib/i18n/languageKeys/keys/commands/Admin.ts b/src/lib/i18n/languageKeys/keys/commands/Admin.ts deleted file mode 100644 index e8e5f3f80..000000000 --- a/src/lib/i18n/languageKeys/keys/commands/Admin.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { LanguageHelpDisplayOptions } from '#lib/i18n/LanguageHelp'; -import { FT, T } from '#lib/types'; - -export const RoleSetAdded = FT<{ name: string; roles: string[] }, string>('commands/admin:rolesetAdded'); -export const RoleSetCreated = FT<{ name: string; roles: string[] }, string>('commands/admin:rolesetCreated'); -export const RoleSetDescription = T('commands/admin:rolesetDescription'); -export const RoleSetExtended = T('commands/admin:rolesetExtended'); -export const RoleSetNoRoleSets = T('commands/admin:rolesetNoRolesets'); -export const RoleSetRemoved = FT<{ name: string; roles: string[] }, string>('commands/admin:rolesetRemoved'); -export const RoleSetResetAll = T('commands/admin:rolesetResetAll'); -export const RoleSetResetEmpty = T('commands/admin:rolesetResetEmpty'); -export const RoleSetResetGroup = FT<{ name: string }, string>('commands/admin:rolesetResetGroup'); -export const RoleSetResetNotExists = FT<{ name: string }, string>('commands/admin:rolesetResetNotExists'); -export const RoleSetUpdated = FT<{ name: string }, string>('commands/admin:rolesetUpdated'); diff --git a/src/lib/i18n/languageKeys/keys/commands/AutoModeration.ts b/src/lib/i18n/languageKeys/keys/commands/AutoModeration.ts deleted file mode 100644 index 9335ef285..000000000 --- a/src/lib/i18n/languageKeys/keys/commands/AutoModeration.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { FT, T } from '#lib/types'; - -export const Show = 'commands/auto-moderation:show'; -export const Edit = 'commands/auto-moderation:edit'; -export const Reset = 'commands/auto-moderation:reset'; -export const AddName = 'commands/auto-moderation:addName'; -export const RemoveName = 'commands/auto-moderation:removeName'; - -export const OptionsEnabled = 'commands/auto-moderation:optionsEnabled'; -export const OptionsActionAlert = 'commands/auto-moderation:optionsActionAlert'; -export const OptionsActionLog = 'commands/auto-moderation:optionsActionLog'; -export const OptionsActionDelete = 'commands/auto-moderation:optionsActionDelete'; -export const OptionsPunishment = 'commands/auto-moderation:optionsPunishment'; -export const OptionsPunishmentDuration = 'commands/auto-moderation:optionsPunishmentDuration'; -export const OptionsThreshold = 'commands/auto-moderation:optionsThreshold'; -export const OptionsThresholdPeriod = 'commands/auto-moderation:optionsThresholdPeriod'; -export const OptionsKey = 'commands/auto-moderation:optionsKey'; -export const OptionsWord = 'commands/auto-moderation:optionsWord'; - -export const OptionsKeyEnabled = T('commands/auto-moderation:optionsKeyEnabled'); -export const OptionsKeyActionAlert = T('commands/auto-moderation:optionsKeyActionAlert'); -export const OptionsKeyActionLog = T('commands/auto-moderation:optionsKeyActionLog'); -export const OptionsKeyActionDelete = T('commands/auto-moderation:optionsKeyActionDelete'); -export const OptionsKeyPunishment = T('commands/auto-moderation:optionsKeyPunishment'); -export const OptionsKeyPunishmentDuration = T('commands/auto-moderation:optionsKeyPunishmentDuration'); -export const OptionsKeyThreshold = T('commands/auto-moderation:optionsKeyThreshold'); -export const OptionsKeyThresholdPeriod = T('commands/auto-moderation:optionsKeyThresholdPeriod'); -export const OptionsKeyWords = T('commands/auto-moderation:optionsKeyWords'); - -export const AttachmentsName = T('commands/auto-moderation:attachmentsName'); -export const AttachmentsDescription = T('commands/auto-moderation:attachmentsDescription'); -export const CapitalsName = T('commands/auto-moderation:capitalsName'); -export const CapitalsDescription = T('commands/auto-moderation:capitalsDescription'); -export const WordsName = T('commands/auto-moderation:wordsName'); -export const WordsDescription = T('commands/auto-moderation:wordsDescription'); -export const InvitesName = T('commands/auto-moderation:invitesName'); -export const InvitesDescription = T('commands/auto-moderation:invitesDescription'); -export const LinksName = T('commands/auto-moderation:linksName'); -export const LinksDescription = T('commands/auto-moderation:linksDescription'); -export const SpamName = T('commands/auto-moderation:spamName'); -export const SpamDescription = T('commands/auto-moderation:spamDescription'); -export const NewlinesName = T('commands/auto-moderation:newlinesName'); -export const NewlinesDescription = T('commands/auto-moderation:newlinesDescription'); -export const ReactionsName = T('commands/auto-moderation:reactionsName'); -export const ReactionsDescription = T('commands/auto-moderation:reactionsDescription'); - -export const ShowDisabled = T('commands/auto-moderation:showDisabled'); -export const ShowEnabled = T('commands/auto-moderation:showEnabled'); -export const ShowReplyActive = FT<{ emoji: string }>('commands/auto-moderation:showReplyActive'); -export const ShowReplyInactive = FT<{ emoji: string }>('commands/auto-moderation:showReplyInactive'); -export const ShowLogActive = FT<{ emoji: string }>('commands/auto-moderation:showLogActive'); -export const ShowLogInactive = FT<{ emoji: string }>('commands/auto-moderation:showLogInactive'); -export const ShowDeleteActive = FT<{ emoji: string }>('commands/auto-moderation:showDeleteActive'); -export const ShowDeleteInactive = FT<{ emoji: string }>('commands/auto-moderation:showDeleteInactive'); -export const ShowPunishmentTitle = T('commands/auto-moderation:showPunishmentTitle'); -export const ShowPunishment = FT<{ name: string; emoji: string }>('commands/auto-moderation:showPunishment'); -export const ShowPunishmentTemporary = FT<{ name: string; emoji: string; duration: string }>('commands/auto-moderation:showPunishmentTemporary'); -export const ShowPunishmentThreshold = FT<{ threshold: number; period: string; emoji: string }>('commands/auto-moderation:showPunishmentThreshold'); - -export const EditSuccess = T('commands/auto-moderation:editSuccess'); - -export const WordAddDescription = T('commands/auto-moderation:wordAddDescription'); -export const WordAddFiltered = FT<{ word: string }>('commands/auto-moderation:wordAddFiltered'); -export const WordRemoveDescription = T('commands/auto-moderation:wordRemoveDescription'); -export const WordRemoveNotFiltered = FT<{ word: string }>('commands/auto-moderation:wordRemoveNotFiltered'); -export const WordShowList = FT<{ words: string[] }>('commands/auto-moderation:wordShowList'); -export const WordShowListTitle = FT<{ count: number }>('commands/auto-moderation:wordShowListTitle'); -export const WordShowListEmpty = FT<{ command: string }>('commands/auto-moderation:wordShowListEmpty'); -export const WordShowListTitleEmpty = T('commands/auto-moderation:wordShowListTitleEmpty'); diff --git a/src/lib/i18n/languageKeys/keys/commands/Case.ts b/src/lib/i18n/languageKeys/keys/commands/Case.ts deleted file mode 100644 index c481a3364..000000000 --- a/src/lib/i18n/languageKeys/keys/commands/Case.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { FT, T } from '#lib/types'; - -// Root -export const Name = T('commands/case:name'); -export const Description = T('commands/case:description'); - -export const View = 'commands/case:view'; -export const Archive = 'commands/case:archive'; -export const Delete = 'commands/case:delete'; -export const Edit = 'commands/case:edit'; -export const List = 'commands/case:list'; - -export const OptionsCase = 'commands/case:optionsCase'; -export const OptionsReason = 'commands/case:optionsReason'; -export const OptionsDuration = 'commands/case:optionsDuration'; -export const OptionsUser = 'commands/case:optionsUser'; -export const OptionsOverview = 'commands/case:optionsOverview'; -export const OptionsType = 'commands/case:optionsType'; -export const OptionsPendingOnly = 'commands/case:optionsPendingOnly'; -export const OptionsShow = 'commands/case:optionsShow'; - -export const TimeNotAllowed = FT<{ type: string }>('commands/case:timeNotAllowed'); -export const TimeNotAllowedInCompletedEntries = FT<{ caseId: number }>('commands/case:timeNotAllowedInCompletedEntries'); -export const TimeEditNotSupported = FT<{ type: string }>('commands/case:timeEditNotSupported'); -export const TimeTooEarly = FT<{ time: string }>('commands/case:timeTooEarly'); -export const ListEmpty = T('commands/case:listEmpty'); -export const ListDetailsTitle = FT<{ count: number }>('commands/case:listDetailsTitle'); -export const ListDetailsModerator = FT<{ emoji: string; mention: string; userId: string }>('commands/case:listDetailsModerator'); -export const ListDetailsUser = FT<{ emoji: string; mention: string; userId: string }>('commands/case:listDetailsUser'); -export const ListDetailsExpires = FT<{ emoji: string; time: string }>('commands/case:listDetailsExpires'); -export const ListOverviewFooter = FT('commands/case:listOverviewFooter'); -export const ListOverviewFooterUser = FT('commands/case:listOverviewFooterUser'); -export const ListOverviewFooterWarning = FT<{ count: number }>('commands/case:listOverviewFooterWarning'); -export const ListOverviewFooterMutes = FT<{ count: number }>('commands/case:listOverviewFooterMutes'); -export const ListOverviewFooterTimeouts = FT<{ count: number }>('commands/case:listOverviewFooterTimeouts'); -export const ListOverviewFooterKicks = FT<{ count: number }>('commands/case:listOverviewFooterKicks'); -export const ListOverviewFooterBans = FT<{ count: number }>('commands/case:listOverviewFooterBans'); -export const EditSuccess = FT<{ caseId: number }>('commands/case:editSuccess'); -export const ArchiveSuccess = FT<{ caseId: number }>('commands/case:archiveSuccess'); -export const DeleteSuccess = FT<{ caseId: number }>('commands/case:deleteSuccess'); - -interface ListOverview { - warnings: string; - mutes: string; - timeouts: string; - kicks: string; - bans: string; -} diff --git a/src/lib/i18n/languageKeys/keys/commands/Conf.ts b/src/lib/i18n/languageKeys/keys/commands/Conf.ts deleted file mode 100644 index 589802dcf..000000000 --- a/src/lib/i18n/languageKeys/keys/commands/Conf.ts +++ /dev/null @@ -1,46 +0,0 @@ -import type { LanguageHelpDisplayOptions } from '#lib/i18n/LanguageHelp'; -import { FT, T } from '#lib/types'; - -// Root -export const Name = T('commands/conf:name'); -export const Description = T('commands/conf:description'); - -export const Menu = T('commands/conf:menuName'); -export const MenuDescription = T('commands/conf:menuDescription'); -export const Show = T('commands/conf:showName'); -export const ShowDescription = T('commands/conf:showDescription'); -export const Set = T('commands/conf:setName'); -export const SetDescription = T('commands/conf:setDescription'); -export const Remove = T('commands/conf:removeName'); -export const RemoveDescription = T('commands/conf:removeDescription'); -export const Reset = T('commands/conf:resetName'); -export const ResetDescription = T('commands/conf:resetDescription'); - -export const OptionKey = T('commands/conf:optionsKeyName'); -export const OptionKeyDescription = T('commands/conf:optionsKeyDescription'); -export const OptionValue = T('commands/conf:optionsValueName'); -export const OptionValueDescription = T('commands/conf:optionsValueDescription'); - -export const Get = FT<{ key: string; value: string }>('commands/conf:get'); -export const GetNoExt = FT<{ key: string }>('commands/conf:getNoExt'); -export const MenuInvalidAction = T('commands/conf:menuInvalidAction'); -export const MenuInvalidKey = T('commands/conf:menuInvalidKey'); -export const MenuRenderAtFolder = FT<{ path: string }>('commands/conf:menuRenderAtFolder'); -export const MenuRenderAtPiece = FT<{ path: string }>('commands/conf:menuRenderAtPiece'); -export const MenuRenderBack = T('commands/conf:menuRenderBack'); -export const MenuRenderCvalue = FT<{ value: string }>('commands/conf:menuRenderCvalue'); -export const MenuRenderNokeys = T('commands/conf:menuRenderNokeys'); -export const MenuRenderRemove = T('commands/conf:menuRenderRemove'); -export const MenuRenderReset = T('commands/conf:menuRenderReset'); -export const MenuRenderSelect = T('commands/conf:menuRenderSelect'); -export const MenuRenderUndo = T('commands/conf:menuRenderUndo'); -export const MenuRenderUpdate = T('commands/conf:menuRenderUpdate'); -export const MenuSaved = T('commands/conf:menuSaved'); -export const Nochange = FT<{ key: string }>('commands/conf:nochange'); -export const ResetSuccess = FT<{ key: string; value: string }>('commands/conf:resetSuccess'); -export const Server = FT<{ key: string; list: string }>('commands/conf:server'); -export const ServerDescription = T('commands/conf:serverDescription'); -export const ServerExtended = T('commands/conf:serverExtended'); -export const SettingNotSet = T('commands/conf:settingNotSet'); -export const Updated = FT<{ key: string; response: string }>('commands/conf:updated'); -export const DashboardOnlyKey = FT<{ key: string }>('commands/conf:dashboardOnlyKey'); diff --git a/src/lib/i18n/languageKeys/keys/commands/Fun.ts b/src/lib/i18n/languageKeys/keys/commands/Fun.ts deleted file mode 100644 index b35d6a40d..000000000 --- a/src/lib/i18n/languageKeys/keys/commands/Fun.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { LanguageHelpDisplayOptions } from '#lib/i18n/LanguageHelp'; -import { FT, T } from '#lib/types'; - -export const EscapeRopeDescription = T('commands/fun:escaperopeDescription'); -export const EscapeRopeExtended = T('commands/fun:escaperopeExtended'); -export const EscapeRopeOutput = FT<{ user: string }, string>('commands/fun:escaperopeOutput'); diff --git a/src/lib/i18n/languageKeys/keys/commands/Games.ts b/src/lib/i18n/languageKeys/keys/commands/Games.ts deleted file mode 100644 index f17fb9df6..000000000 --- a/src/lib/i18n/languageKeys/keys/commands/Games.ts +++ /dev/null @@ -1,40 +0,0 @@ -import type { LanguageHelpDisplayOptions } from '#lib/i18n/LanguageHelp'; -import { FT, T } from '#lib/types'; -import type { HungerGamesGame } from '#root/commands/Games/hungergames'; - -export const GamesBot = T('commands/game:gamesBot'); -export const GamesSelf = T('commands/game:gamesSelf'); -export const GamesProgress = T('commands/game:gamesProgress'); -export const GamesNoPlayers = FT<{ prefix: string }, string>('commands/game:gamesNoPlayers'); -export const GamesTooManyOrFew = FT<{ min: number; max: number }, string>('commands/game:gamesTooManyOrFew'); -export const GamesRepeat = T('commands/game:gamesRepeat'); -export const GamesPromptDeny = T('commands/game:gamesPromptDeny'); -export const C4Description = T('commands/game:c4Description'); -export const C4Extended = T('commands/game:c4Extended'); -export const C4Prompt = FT<{ challenger: string; challengee: string }, string>('commands/game:c4Prompt'); -export const HungerGamesDescription = T('commands/game:hungerGamesDescription'); -export const HungerGamesExtended = T('commands/game:hungerGamesExtended'); -export const HungerGamesResultHeaderBloodbath = FT<{ game: HungerGamesGame }, string>('commands/game:hungerGamesResultHeaderBloodbath'); -export const HungerGamesResultHeaderSun = FT<{ game: HungerGamesGame }, string>('commands/game:hungerGamesResultHeaderSun'); -export const HungerGamesResultHeaderMoon = FT<{ game: HungerGamesGame }, string>('commands/game:hungerGamesResultHeaderMoon'); -export const HungerGamesResultDeaths = FT<{ count: number }, string>('commands/game:hungerGamesResultDeaths'); -export const HungerGamesResultProceed = T('commands/game:hungerGamesResultProceed'); -export const HungerGamesStop = T('commands/game:hungerGamesStop'); -export const HungerGamesWinner = FT<{ winner: string }, string>('commands/game:hungerGamesWinner'); -export const HungerGamesBloodbath = T('commands/game:hgBloodbath'); -export const HungerGamesDay = T('commands/game:hgDay'); -export const HungerGamesNight = T('commands/game:hgNight'); -export const TicTacToeDescription = T('commands/game:ticTacToeDescription'); -export const TicTacToeExtended = T('commands/game:ticTacToeExtended'); -export const TicTacToePrompt = FT<{ challenger: string; challengee: string }, string>('commands/game:ticTacToePrompt'); -export const TicTacToeTurn = FT<{ icon: string; player: string; board: string }, string>('commands/game:ticTacToeTurn'); -export const TicTacToeWinner = FT<{ winner: string; board: string }, string>('commands/game:ticTacToeWinner'); -export const TicTacToeDraw = FT<{ board: string }, string>('commands/game:ticTacToeDraw'); -export const TriviaDescription = T('commands/game:triviaDescription'); -export const TriviaExtended = T('commands/game:triviaExtended'); -export const TriviaInvalidCategory = T('commands/game:triviaInvalidCategory'); -export const TriviaActiveGame = T('commands/game:triviaActiveGame'); -export const TriviaIncorrect = FT<{ attempt: string }, string>('commands/game:triviaIncorrect'); -export const TriviaNoAnswer = FT<{ correctAnswer: string }, string>('commands/game:triviaNoAnswer'); -export const TriviaEmbedTitles = T<{ trivia: string; difficulty: string }>('commands/game:triviaEmbedTitles'); -export const TriviaWinner = FT<{ winner: string; correctAnswer: string }, string>('commands/game:triviaWinner'); diff --git a/src/lib/i18n/languageKeys/keys/commands/General.ts b/src/lib/i18n/languageKeys/keys/commands/General.ts deleted file mode 100644 index 7c81ee40f..000000000 --- a/src/lib/i18n/languageKeys/keys/commands/General.ts +++ /dev/null @@ -1,45 +0,0 @@ -import type { LanguageHelpDisplayOptions } from '#lib/i18n/LanguageHelp'; -import { FT, T } from '#lib/types'; - -export const HelpAllFlag = FT<{ prefix: string }, string>('commands/general:helpAllFlag'); -export const HelpCommandCount = FT<{ count: number }, string>('commands/general:helpCommandCount'); -export const HelpData = FT<{ titleDescription: string; footerName: string }, { title: string; footer: string }>('commands/general:helpData'); -export const HelpDescription = T('commands/general:helpDescription'); -export const HelpDm = T('commands/general:helpDm'); -export const HelpExtended = T('commands/general:helpExtended'); -export const HelpNoDm = T('commands/general:helpNodm'); -export const V7SkyraDescription = T('commands/general:v7SkyraDescription'); -export const V7SkyraExtended = T('commands/general:v7SkyraExtended'); -export const V7SkyraMessage = FT<{ command: string }>('commands/general:v7SkyraMessage'); -export const V7NayreMessage = FT<{ command: string }>('commands/general:v7NayreMessage'); -export const V7Description = T('commands/general:v7SkyraDescription'); -export const V7Extended = T('commands/general:v7SExtended'); -export const V7Message = FT<{ command: string }>('commands/general:v7Message'); - -export interface InfoComponentLabels { - addToServer: string; - supportServer: string; - repository: string; - donate: string; -} - -export interface StatsGeneral { - channels: number; - guilds: number; - nodeJs: string; - users: number; - djsVersion: string; - sapphireVersion: string; -} - -export interface StatsUptime { - client: string; - host: string; - total: string; -} - -export interface StatsUsage { - cpuLoad: string; - ramTotal: number; - ramUsed: number; -} diff --git a/src/lib/i18n/languageKeys/keys/commands/Info.ts b/src/lib/i18n/languageKeys/keys/commands/Info.ts deleted file mode 100644 index ee4e09f4e..000000000 --- a/src/lib/i18n/languageKeys/keys/commands/Info.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { FT, T } from '#lib/types'; - -export const Name = T('commands/info:name'); -export const Description = T('commands/info:description'); - -export const EmbedDescription = T('commands/info:embedDescription'); -export const EmbedFieldApplicationTitle = T('commands/info:embedFieldApplicationTitle'); -export const EmbedFieldApplicationValue = FT<{ - channels: number; - guilds: number; - users: number; - versionDiscord: string; - versionSapphire: string; - versionNode: string; -}>('commands/info:embedFieldApplicationValue'); -export const EmbedFieldUptimeTitle = T('commands/info:embedFieldUptimeTitle'); -export const EmbedFieldUptimeValue = FT<{ host: string; client: string }>('commands/info:embedFieldUptimeValue'); -export const EmbedFieldServerUsageTitle = T('commands/info:embedFieldServerUsageTitle'); -export const EmbedFieldServerUsageValue = FT<{ cpu: string; heapUsed: string; heapTotal: string }>('commands/info:embedFieldServerUsageValue'); -export const ButtonInvite = T('commands/info:buttonInvite'); -export const ButtonSupport = T('commands/info:buttonSupport'); -export const ButtonGitHub = T('commands/info:buttonGitHub'); -export const ButtonDonate = T('commands/info:buttonDonate'); diff --git a/src/lib/i18n/languageKeys/keys/commands/Permissions.ts b/src/lib/i18n/languageKeys/keys/commands/Permissions.ts deleted file mode 100644 index 21528b644..000000000 --- a/src/lib/i18n/languageKeys/keys/commands/Permissions.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { T } from '#lib/types'; - -// Root -export const Name = T('commands/permissions:name'); -export const Description = T('commands/permissions:description'); -export const ContextMenuName = T('commands/permissions:contextMenuName'); - -// Options -export const OptionsUser = 'commands/permissions:optionsUser'; -export const OptionsListAll = 'commands/permissions:optionsListAll'; -export const OptionsListMissing = 'commands/permissions:optionsListMissing'; -export const OptionsShow = 'commands/permissions:optionsShow'; - -export const Title = T('commands/permissions:title'); diff --git a/src/lib/i18n/languageKeys/keys/commands/Shared.ts b/src/lib/i18n/languageKeys/keys/commands/Shared.ts deleted file mode 100644 index 2b38ed81f..000000000 --- a/src/lib/i18n/languageKeys/keys/commands/Shared.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { LanguageHelpDisplayOptions } from '#lib/i18n/LanguageHelp'; -import { FT, T } from '#lib/types'; - -export const DeprecatedMessage = FT<{ command: string }>('commands/shared:deprecatedMessage'); -export const SlashOnlyDetailedDescription = T('commands/shared:slashOnlyDetailedDescription'); -export const SlashOnlyErrorMessage = T('commands/shared:slashOnlyErrorMessage'); diff --git a/src/lib/i18n/languageKeys/keys/commands/Snipe.ts b/src/lib/i18n/languageKeys/keys/commands/Snipe.ts deleted file mode 100644 index 4e8816978..000000000 --- a/src/lib/i18n/languageKeys/keys/commands/Snipe.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { T } from '#lib/types'; - -export const Name = T('commands/snipe:name'); -export const Description = T('commands/snipe:description'); -export const MessageEmpty = T('commands/snipe:messageEmpty'); -export const EmbedTitle = T('commands/snipe:embedTitle'); diff --git a/src/lib/i18n/languageKeys/keys/commands/System.ts b/src/lib/i18n/languageKeys/keys/commands/System.ts deleted file mode 100644 index f02edb10f..000000000 --- a/src/lib/i18n/languageKeys/keys/commands/System.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { LanguageHelpDisplayOptions } from '#lib/i18n/LanguageHelp'; -import { FT, T } from '#lib/types'; - -export const EvalDescription = T('commands/system:evalDescription'); -export const EvalError = FT<{ time: string; output: string; type: string }, string>('commands/system:evalError'); -export const EvalExtended = T('commands/system:evalExtended'); -export const EvalTimeout = FT<{ seconds: number }, string>('commands/system:evalTimeout'); -export const Reboot = T('commands/system:reboot'); -export const RebootDescription = T('commands/system:rebootDescription'); -export const RebootExtended = T('commands/system:rebootExtended'); diff --git a/src/lib/i18n/languageKeys/keys/commands/Tools.ts b/src/lib/i18n/languageKeys/keys/commands/Tools.ts deleted file mode 100644 index 9841bcd85..000000000 --- a/src/lib/i18n/languageKeys/keys/commands/Tools.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { LanguageHelpDisplayOptions } from '#lib/i18n/LanguageHelp'; -import { FT, T } from '#lib/types'; - -export const AvatarDescription = T('commands/tools:avatarDescription'); -export const AvatarExtended = T('commands/tools:avatarExtended'); -export const AvatarNone = T('commands/tools:avatarNone'); -export const VoteDescription = T('commands/tools:voteDescription'); -export const VoteExtended = T('commands/tools:voteExtended'); -export const VoteContentNeeded = T('commands/tools:voteContentNeeded'); -export const VoteReactionBlocked = T('commands/tools:voteReactionBlocked'); -export const WhoisExtended = T('commands/tools:whoisExtended'); -export const WhoisMemberRoleListAndMore = FT<{ count: number }, string>('commands/tools:whoisMemberRoleListAndMore'); diff --git a/src/lib/i18n/languageKeys/keys/commands/Whois.ts b/src/lib/i18n/languageKeys/keys/commands/Whois.ts deleted file mode 100644 index 10a7cb535..000000000 --- a/src/lib/i18n/languageKeys/keys/commands/Whois.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { FT, T, type Value } from '#lib/types'; - -// Root -export const Name = T('commands/whois:name'); -export const Description = T('commands/whois:description'); -export const ContextMenuName = T('commands/whois:contextMenuName'); - -// Options -export const User = 'commands/whois:user'; - -// Embed -export const RolesTitle = FT('commands/whois:rolesTitle'); -export const PermissionsTitle = T('commands/whois:permissionsTitle'); -export const PermissionsAll = T('commands/whois:permissionsAll'); -export const EmbedDescription = FT<{ createdAt: string }>('commands/whois:embedDescription'); -export const EmbedMemberDescription = FT<{ joinedAt: string }>('commands/whois:embedMemberDescription'); - -// Buttons -export const ButtonAvatar = T('commands/whois:buttonAvatar'); -export const ButtonProfile = T('commands/whois:buttonProfile'); diff --git a/src/lib/i18n/languageKeys/keys/events/All.ts b/src/lib/i18n/languageKeys/keys/events/All.ts deleted file mode 100644 index c8111caed..000000000 --- a/src/lib/i18n/languageKeys/keys/events/All.ts +++ /dev/null @@ -1,6 +0,0 @@ -export * as NoMentionSpam from '#lib/i18n/languageKeys/keys/events/NoMentionSpam'; -export * as Errors from '#lib/i18n/languageKeys/keys/events/errors/All'; -export * as Guilds from '#lib/i18n/languageKeys/keys/events/guilds/All'; -export * as Messages from '#lib/i18n/languageKeys/keys/events/messages/All'; -export * as Moderation from '#lib/i18n/languageKeys/keys/events/moderation/All'; -export * as Reactions from '#lib/i18n/languageKeys/keys/events/reactions/All'; diff --git a/src/lib/i18n/languageKeys/keys/events/guilds/All.ts b/src/lib/i18n/languageKeys/keys/events/guilds/All.ts deleted file mode 100644 index 8fc1cad41..000000000 --- a/src/lib/i18n/languageKeys/keys/events/guilds/All.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * as Logs from '#lib/i18n/languageKeys/keys/events/guilds/Logs'; -export * as Members from '#lib/i18n/languageKeys/keys/events/guilds/Members'; diff --git a/src/lib/i18n/languageKeys/keys/events/guilds/Members.ts b/src/lib/i18n/languageKeys/keys/events/guilds/Members.ts deleted file mode 100644 index 4a2b96d52..000000000 --- a/src/lib/i18n/languageKeys/keys/events/guilds/Members.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { FT, T } from '#lib/types'; - -export const GuildMemberAdd = T('events/guilds-members:guildMemberAdd'); -export const GuildMemberAddDescription = FT<{ user: string; relativeTime: string }>('events/guilds-members:guildMemberAddDescription'); -export const GuildMemberAddedRoles = FT<{ addedRoles: string; count: number }>('events/guilds-members:guildMemberAddedRoles'); -export const GuildMemberAddMute = T('events/guilds-members:guildMemberAddMute'); -export const GuildMemberBanned = T('events/guilds-members:guildMemberBanned'); -export const GuildMemberKicked = T('events/guilds-members:guildMemberKicked'); -export const GuildMemberNoUpdate = T('events/guilds-members:guildMemberNoUpdate'); -export const GuildMemberRemove = T('events/guilds-members:guildMemberRemove'); -export const GuildMemberRemoveDescription = FT<{ user: string; relativeTime: string }>('events/guilds-members:guildMemberRemoveDescription'); -export const GuildMemberRemoveDescriptionWithJoinedAt = FT<{ user: string; relativeTime: string }>( - 'events/guilds-members:guildMemberRemoveDescriptionWithJoinedAt' -); -export const GuildMemberRemovedRoles = FT<{ removedRoles: string; count: number }>('events/guilds-members:guildMemberRemovedRoles'); -export const GuildMemberSoftBanned = T('events/guilds-members:guildMemberSoftBanned'); -export const NameUpdateNextWasNotSet = FT<{ nextName: string | null }>('events/guilds-members:nameUpdateNextWasNotSet'); -export const NameUpdateNextWasSet = FT<{ nextName: string | null }>('events/guilds-members:nameUpdateNextWasSet'); -export const NameUpdatePreviousWasNotSet = FT<{ previousName: string | null }>('events/guilds-members:nameUpdatePreviousWasNotSet'); -export const NameUpdatePreviousWasSet = FT<{ previousName: string | null }>('events/guilds-members:nameUpdatePreviousWasSet'); -export const NicknameUpdate = T('events/guilds-members:nicknameUpdate'); -export const RoleUpdate = T('events/guilds-members:roleUpdate'); -export const UsernameUpdate = T('events/guilds-members:usernameUpdate'); diff --git a/src/lib/i18n/languageKeys/keys/events/messages/All.ts b/src/lib/i18n/languageKeys/keys/events/messages/All.ts deleted file mode 100644 index 8a5f56fea..000000000 --- a/src/lib/i18n/languageKeys/keys/events/messages/All.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { FT, T } from '#lib/types'; -import type { ChannelMention, UserMention } from 'discord.js'; - -export const MessageUpdate = FT<{ channel: `#${string}` }>('events/messages:messageUpdate'); -export const MessageUpdateUnknown = FT<{ channel: `#${string}` }>('events/messages:messageUpdateUnknown'); -export const MessageDelete = FT<{ channel: `#${string}` }>('events/messages:messageDelete'); -export const MessageDeleteUnknown = FT<{ channel: `#${string}` }>('events/messages:messageDeleteUnknown'); -export const MessageNotFound = T('events/messages:messageNotFound'); -export const MessageDeleteBulk = FT<{ author: UserMention; channel: ChannelMention; count: number }>('events/messages:messageDeleteBulk'); -export const MessageDeleteBulkUnknown = FT<{ channel: ChannelMention; count: number }>('events/messages:messageDeleteBulkUnknown'); -export const MessageDeleteBulkFooter = T('events/messages:messageDeleteBulkFooter'); -export const VoiceActivityFooter = T('events/messages:voiceActivityFooter'); -export const JumpToContext = T('events/messages:jumpToContext'); diff --git a/src/lib/i18n/languageKeys/keys/events/moderation/All.ts b/src/lib/i18n/languageKeys/keys/events/moderation/All.ts deleted file mode 100644 index 93f6aaf34..000000000 --- a/src/lib/i18n/languageKeys/keys/events/moderation/All.ts +++ /dev/null @@ -1 +0,0 @@ -export * as Messages from '#lib/i18n/languageKeys/keys/events/moderation/Messages'; diff --git a/src/lib/i18n/languageKeys/keys/events/reactions/All.ts b/src/lib/i18n/languageKeys/keys/events/reactions/All.ts deleted file mode 100644 index 1ffed9c40..000000000 --- a/src/lib/i18n/languageKeys/keys/events/reactions/All.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { FT, T } from '#lib/types'; - -export const ReactionDescription = FT<{ emoji: string; message: string }>('events/reactions:reactionDescription'); -export const ReactionFooter = T('events/reactions:reactionFooter'); -export const Filter = FT<{ user: string }>('events/reactions:filter'); -export const FilterFooter = T('events/reactions:filterFooter'); -export const SelfRoleHierarchy = T('events/reactions:selfRoleHierarchy'); diff --git a/src/lib/i18n/languageKeys/keys/settings/Channels.ts b/src/lib/i18n/languageKeys/keys/settings/Channels.ts deleted file mode 100644 index ad17a9160..000000000 --- a/src/lib/i18n/languageKeys/keys/settings/Channels.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { T } from '#lib/types'; - -export * as Ignore from '#lib/i18n/languageKeys/keys/settings/channels/Ignore'; -export * as Logs from '#lib/i18n/languageKeys/keys/settings/channels/Logs'; - -export const MediaOnly = T('settings:channelsMediaOnly'); diff --git a/src/lib/i18n/structures/Handler.ts b/src/lib/i18n/structures/Handler.ts deleted file mode 100644 index eafcf9070..000000000 --- a/src/lib/i18n/structures/Handler.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { DurationFormatter, type DurationFormatAssetsTime } from '@sapphire/time-utilities'; - -export abstract class Handler { - public readonly name: string; - public readonly duration: DurationFormatter; - - public constructor(options: Handler.Options) { - this.name = options.name; - this.duration = new DurationFormatter(options.duration); - } -} - -export namespace Handler { - export interface Options { - name: string; - duration: DurationFormatAssetsTime; - } -} diff --git a/src/lib/i18n/translate.ts b/src/lib/i18n/translate.ts deleted file mode 100644 index b7db5836a..000000000 --- a/src/lib/i18n/translate.ts +++ /dev/null @@ -1,162 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import type { WolfArgs } from '#lib/structures'; -import { DecoratorIdentifiers } from '@sapphire/decorators'; -import { Identifiers, container } from '@sapphire/framework'; -import type { InternationalizationContext, TFunction } from '@sapphire/plugin-i18next'; -import type { Nullish } from '@sapphire/utilities'; -import type { Interaction, Locale } from 'discord.js'; - -export function translate(identifier: string): string { - switch (identifier) { - case Identifiers.ArgsUnavailable: - return LanguageKeys.Arguments.Unavailable; - case Identifiers.ArgsMissing: - return LanguageKeys.Arguments.Missing; - case Identifiers.ArgumentBooleanError: - case Identifiers.ArgumentChannelError: - case Identifiers.ArgumentDateError: - case Identifiers.ArgumentDateTooEarly: - case Identifiers.ArgumentDateTooFar: - case Identifiers.ArgumentDMChannelError: - case Identifiers.ArgumentEmojiError: - case Identifiers.ArgumentFloatError: - case Identifiers.ArgumentFloatTooLarge: - case Identifiers.ArgumentFloatTooSmall: - case Identifiers.ArgumentGuildError: - case Identifiers.ArgumentGuildCategoryChannelError: - case Identifiers.ArgumentGuildChannelError: - case Identifiers.ArgumentGuildChannelMissingGuildError: - case Identifiers.ArgumentGuildNewsChannelError: - case Identifiers.ArgumentGuildNewsThreadChannelError: - case Identifiers.ArgumentGuildPrivateThreadChannelError: - case Identifiers.ArgumentGuildPublicThreadChannelError: - case Identifiers.ArgumentGuildStageVoiceChannelError: - case Identifiers.ArgumentGuildTextChannelError: - case Identifiers.ArgumentGuildThreadChannelError: - case Identifiers.ArgumentGuildVoiceChannelError: - case Identifiers.ArgumentHyperlinkError: - case Identifiers.ArgumentIntegerError: - case Identifiers.ArgumentIntegerTooLarge: - case Identifiers.ArgumentIntegerTooSmall: - case Identifiers.ArgumentMemberError: - case Identifiers.ArgumentMemberMissingGuild: - case Identifiers.ArgumentMessageError: - case Identifiers.ArgumentNumberError: - case Identifiers.ArgumentNumberTooLarge: - case Identifiers.ArgumentNumberTooSmall: - case Identifiers.ArgumentRoleError: - case Identifiers.ArgumentRoleMissingGuild: - case Identifiers.ArgumentStringTooLong: - case Identifiers.ArgumentStringTooShort: - case Identifiers.ArgumentUserError: - case Identifiers.ArgumentEnumEmptyError: - case Identifiers.ArgumentEnumError: - return `arguments:${identifier}`; - - case Identifiers.CommandDisabled: - return LanguageKeys.Preconditions.DisabledGlobal; - case Identifiers.PreconditionCooldown: - return LanguageKeys.Preconditions.Cooldown; - - case Identifiers.PreconditionNSFW: - return LanguageKeys.Preconditions.Nsfw; - case Identifiers.PreconditionClientPermissions: - case DecoratorIdentifiers.RequiresClientPermissionsMissingPermissions: - return LanguageKeys.Preconditions.ClientPermissions; - case Identifiers.PreconditionClientPermissionsNoClient: - return LanguageKeys.Preconditions.ClientPermissionsNoClient; - case Identifiers.PreconditionClientPermissionsNoPermissions: - return LanguageKeys.Preconditions.ClientPermissionsNoPermissions; - case Identifiers.PreconditionRunIn: - return LanguageKeys.Preconditions.RunIn; - case Identifiers.PreconditionUserPermissions: - case DecoratorIdentifiers.RequiresUserPermissionsMissingPermissions: - return LanguageKeys.Preconditions.UserPermissions; - case Identifiers.PreconditionUserPermissionsNoPermissions: - return LanguageKeys.Preconditions.UserPermissionsNoPermissions; - case Identifiers.PreconditionUnavailable: - return LanguageKeys.Preconditions.Unavailable; - case Identifiers.PreconditionMissingMessageHandler: - return LanguageKeys.Preconditions.MissingMessageHandler; - case Identifiers.PreconditionMissingChatInputHandler: - return LanguageKeys.Preconditions.MissingChatInputHandler; - case Identifiers.PreconditionMissingContextMenuHandler: - return LanguageKeys.Preconditions.MissingContextMenuHandler; - case DecoratorIdentifiers.RequiresClientPermissionsGuildOnly: - case DecoratorIdentifiers.RequiresUserPermissionsGuildOnly: - return LanguageKeys.Preconditions.GuildOnly; - - // Sapphire (deprecated) - case Identifiers.PreconditionDMOnly: - return LanguageKeys.Preconditions.DmOnly; - case Identifiers.PreconditionGuildNewsOnly: - return LanguageKeys.Preconditions.GuildNewsOnly; - case Identifiers.PreconditionGuildNewsThreadOnly: - return LanguageKeys.Preconditions.GuildNewsThreadOnly; - case Identifiers.PreconditionGuildOnly: - return LanguageKeys.Preconditions.GuildOnly; - case Identifiers.PreconditionGuildPrivateThreadOnly: - return LanguageKeys.Preconditions.GuildPrivateThreadOnly; - case Identifiers.PreconditionGuildPublicThreadOnly: - return LanguageKeys.Preconditions.GuildPublicThreadOnly; - case Identifiers.PreconditionGuildTextOnly: - return LanguageKeys.Preconditions.GuildTextOnly; - case Identifiers.PreconditionThreadOnly: - return LanguageKeys.Preconditions.ThreadOnly; - - default: - return identifier; - } -} - -export type TResolvable = WolfArgs | TFunction; - -export function resolveT(t: TResolvable): TFunction { - return typeof t === 'function' ? t : t.t; -} - -/** - * Returns a translation function for the specified locale, or the default 'en-US' if none is provided. - * @param locale The locale to get the translation function for. - * @returns The translation function for the specified locale. - */ -export function getT(locale?: Locale | string | Nullish) { - return container.i18n.getT(locale ?? 'en-US'); -} - -export function getSupportedLanguageName(interaction: Interaction): Locale { - if (interaction.guildLocale && container.i18n.languages.has(interaction.guildLocale)) return interaction.guildLocale; - return 'en-US'; -} - -export function getSupportedLanguageT(interaction: Interaction): TFunction { - return getT(getSupportedLanguageName(interaction)); -} - -export function getSupportedUserLanguageName(interaction: Interaction): Locale { - if (container.i18n.languages.has(interaction.locale)) return interaction.locale; - return getSupportedLanguageName(interaction); -} - -export function getSupportedUserLanguageT(interaction: Interaction): TFunction { - return getT(getSupportedUserLanguageName(interaction)); -} - -/** - * Fetches the language for the given {@link InternationalizationContext}. - * If the language cannot be fetched, defaults to 'en-US'. - * @param context The InternationalizationContext to fetch the language for. - * @returns The fetched language as a {@link Locale}. - */ -export async function fetchLanguage(context: InternationalizationContext) { - return (await container.i18n.fetchLanguage(context))! as Locale; -} - -/** - * Fetches the translation function for the given context. - * @param context The internationalization context. - * @returns The translation function. - */ -export async function fetchT(context: InternationalizationContext) { - return getT(await fetchLanguage(context)); -} diff --git a/src/lib/moderation/actions/ModerationActionBan.ts b/src/lib/moderation/actions/ModerationActionBan.ts deleted file mode 100644 index af7d1bc90..000000000 --- a/src/lib/moderation/actions/ModerationActionBan.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { api } from '#lib/discord/Api'; -import { ModerationAction } from '#lib/moderation/actions/base/ModerationAction'; -import { resolveOnErrorCodes } from '#utils/common'; -import { TypeVariation } from '#utils/moderationConstants'; -import { isNullish } from '@sapphire/utilities'; -import { RESTJSONErrorCodes, type Guild, type Snowflake } from 'discord.js'; - -export class ModerationActionBan extends ModerationAction { - public constructor() { - super({ - type: TypeVariation.Ban, - isUndoActionAvailable: true, - logPrefix: 'Moderation => Ban' - }); - } - - public override async isActive(guild: Guild, userId: Snowflake) { - const ban = await resolveOnErrorCodes(guild.bans.fetch({ user: userId, cache: false }), RESTJSONErrorCodes.UnknownBan); - return !isNullish(ban); - } - - protected override async handleApplyPost(guild: Guild, entry: ModerationAction.Entry, data: ModerationAction.Data) { - const reason = await this.getReason(guild, entry.reason); - await api().guilds.banUser(guild.id, entry.userId, { delete_message_seconds: data.context ?? 0 }, { reason }); - - await this.completeLastModerationEntryFromUser({ guild, userId: entry.userId }); - } - - protected override async handleUndoPre(guild: Guild, entry: ModerationAction.Entry) { - const reason = await this.getReason(guild, entry.reason, true); - await api().guilds.unbanUser(guild.id, entry.userId, { reason }); - - await this.completeLastModerationEntryFromUser({ guild, userId: entry.userId }); - } -} diff --git a/src/lib/moderation/actions/ModerationActionKick.ts b/src/lib/moderation/actions/ModerationActionKick.ts deleted file mode 100644 index d473e3879..000000000 --- a/src/lib/moderation/actions/ModerationActionKick.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { api } from '#lib/discord/Api'; -import { ModerationAction } from '#lib/moderation/actions/base/ModerationAction'; -import { TypeVariation } from '#utils/moderationConstants'; -import type { Guild } from 'discord.js'; - -export class ModerationActionKick extends ModerationAction { - public constructor() { - super({ - type: TypeVariation.Kick, - isUndoActionAvailable: false, - logPrefix: 'Moderation => Kick' - }); - } - - protected override async handleApplyPost(guild: Guild, entry: ModerationAction.Entry) { - await api().guilds.removeMember(guild.id, entry.userId, { reason: await this.getReason(guild, entry.reason) }); - } -} diff --git a/src/lib/moderation/actions/ModerationActionRestrictedAll.ts b/src/lib/moderation/actions/ModerationActionRestrictedAll.ts deleted file mode 100644 index 2374d965b..000000000 --- a/src/lib/moderation/actions/ModerationActionRestrictedAll.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { RoleModerationAction } from '#lib/moderation/actions/base/RoleModerationAction'; -import { TypeVariation } from '#utils/moderationConstants'; -import { PermissionFlagsBits } from 'discord.js'; - -export class ModerationActionRestrictedAll extends RoleModerationAction { - public constructor() { - super({ - type: TypeVariation.Mute, - logPrefix: 'Moderation => Mute', - roleKey: RoleModerationAction.RoleKey.All, - roleData: { name: 'Muted', permissions: [], hoist: false, mentionable: false }, - roleOverridesText: - PermissionFlagsBits.SendMessages | - PermissionFlagsBits.SendMessagesInThreads | - PermissionFlagsBits.AddReactions | - PermissionFlagsBits.UseExternalEmojis | - PermissionFlagsBits.UseExternalStickers | - PermissionFlagsBits.UseApplicationCommands | - PermissionFlagsBits.CreatePublicThreads | - PermissionFlagsBits.CreatePrivateThreads, - roleOverridesVoice: PermissionFlagsBits.Connect, - replace: true - }); - } -} diff --git a/src/lib/moderation/actions/ModerationActionRestrictedAttachment.ts b/src/lib/moderation/actions/ModerationActionRestrictedAttachment.ts deleted file mode 100644 index 1d30cb10b..000000000 --- a/src/lib/moderation/actions/ModerationActionRestrictedAttachment.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { RoleModerationAction } from '#lib/moderation/actions/base/RoleModerationAction'; -import { TypeVariation } from '#utils/moderationConstants'; -import { PermissionFlagsBits } from 'discord.js'; - -export class ModerationActionRestrictedAttachment extends RoleModerationAction { - public constructor() { - super({ - type: TypeVariation.RestrictedAttachment, - logPrefix: 'Moderation => RestrictedAttachment', - roleKey: RoleModerationAction.RoleKey.Attachment, - roleData: { name: 'Attachment Restricted', permissions: [], hoist: false, mentionable: false }, - roleOverridesText: PermissionFlagsBits.AttachFiles, - roleOverridesVoice: null - }); - } -} diff --git a/src/lib/moderation/actions/ModerationActionRestrictedEmbed.ts b/src/lib/moderation/actions/ModerationActionRestrictedEmbed.ts deleted file mode 100644 index 80f5764c3..000000000 --- a/src/lib/moderation/actions/ModerationActionRestrictedEmbed.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { RoleModerationAction } from '#lib/moderation/actions/base/RoleModerationAction'; -import { TypeVariation } from '#utils/moderationConstants'; -import { PermissionFlagsBits } from 'discord.js'; - -export class ModerationActionRestrictedEmbed extends RoleModerationAction { - public constructor() { - super({ - type: TypeVariation.RestrictedEmbed, - logPrefix: 'Moderation => RestrictedEmbed', - roleKey: RoleModerationAction.RoleKey.Embed, - roleData: { name: 'Embed Restricted', permissions: [], hoist: false, mentionable: false }, - roleOverridesText: PermissionFlagsBits.EmbedLinks, - roleOverridesVoice: null - }); - } -} diff --git a/src/lib/moderation/actions/ModerationActionRestrictedEmoji.ts b/src/lib/moderation/actions/ModerationActionRestrictedEmoji.ts deleted file mode 100644 index ec6b29e50..000000000 --- a/src/lib/moderation/actions/ModerationActionRestrictedEmoji.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { RoleModerationAction } from '#lib/moderation/actions/base/RoleModerationAction'; -import { TypeVariation } from '#utils/moderationConstants'; -import { PermissionFlagsBits } from 'discord.js'; - -export class ModerationActionRestrictedEmoji extends RoleModerationAction { - public constructor() { - super({ - type: TypeVariation.RestrictedEmoji, - logPrefix: 'Moderation => RestrictedEmoji', - roleKey: RoleModerationAction.RoleKey.Emoji, - roleData: { name: 'Emoji Restricted', permissions: [], hoist: false, mentionable: false }, - roleOverridesText: PermissionFlagsBits.UseExternalEmojis | PermissionFlagsBits.UseExternalStickers, - roleOverridesVoice: null - }); - } -} diff --git a/src/lib/moderation/actions/ModerationActionRestrictedReaction.ts b/src/lib/moderation/actions/ModerationActionRestrictedReaction.ts deleted file mode 100644 index d8809589e..000000000 --- a/src/lib/moderation/actions/ModerationActionRestrictedReaction.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { RoleModerationAction } from '#lib/moderation/actions/base/RoleModerationAction'; -import { TypeVariation } from '#utils/moderationConstants'; -import { PermissionFlagsBits } from 'discord.js'; - -export class ModerationActionRestrictedReaction extends RoleModerationAction { - public constructor() { - super({ - type: TypeVariation.RestrictedReaction, - logPrefix: 'Moderation => RestrictedReaction', - roleKey: RoleModerationAction.RoleKey.Reaction, - roleData: { name: 'Reaction Restricted', permissions: [], hoist: false, mentionable: false }, - roleOverridesText: PermissionFlagsBits.AddReactions, - roleOverridesVoice: null - }); - } -} diff --git a/src/lib/moderation/actions/ModerationActionRestrictedVoice.ts b/src/lib/moderation/actions/ModerationActionRestrictedVoice.ts deleted file mode 100644 index a1e07308a..000000000 --- a/src/lib/moderation/actions/ModerationActionRestrictedVoice.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { RoleModerationAction } from '#lib/moderation/actions/base/RoleModerationAction'; -import { TypeVariation } from '#utils/moderationConstants'; -import { PermissionFlagsBits } from 'discord.js'; - -export class ModerationActionRestrictedVoice extends RoleModerationAction { - public constructor() { - super({ - type: TypeVariation.RestrictedVoice, - logPrefix: 'Moderation => RestrictedVoice', - roleKey: RoleModerationAction.RoleKey.Voice, - roleData: { name: 'Voice Restricted', permissions: [], hoist: false, mentionable: false }, - roleOverridesText: null, - roleOverridesVoice: PermissionFlagsBits.Connect - }); - } -} diff --git a/src/lib/moderation/actions/ModerationActionRoleAdd.ts b/src/lib/moderation/actions/ModerationActionRoleAdd.ts deleted file mode 100644 index ac9d49f94..000000000 --- a/src/lib/moderation/actions/ModerationActionRoleAdd.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { api } from '#lib/discord/Api'; -import { ModerationAction } from '#lib/moderation/actions/base/ModerationAction'; -import { resolveOnErrorCodes } from '#utils/common'; -import { TypeVariation } from '#utils/moderationConstants'; -import { isNullish } from '@sapphire/utilities'; -import { RESTJSONErrorCodes, type Guild, type Role } from 'discord.js'; - -export class ModerationActionRoleAdd extends ModerationAction { - public constructor() { - super({ - type: TypeVariation.RoleAdd, - isUndoActionAvailable: true, - logPrefix: 'Moderation => RoleAdd' - }); - } - - public override async isActive(guild: Guild, userId: string, context: Role) { - const member = await resolveOnErrorCodes(guild.members.fetch(userId), RESTJSONErrorCodes.UnknownMember); - return !isNullish(member) && member.roles.cache.has(context.id); - } - - protected override async handleApplyPre(guild: Guild, entry: ModerationAction.Entry, data: ModerationAction.Data) { - const role = data.context!; - await api().guilds.addRoleToMember(guild.id, entry.userId, role.id, { - reason: await this.getReason(guild, entry.reason) - }); - - await this.completeLastModerationEntryFromUser({ - guild, - userId: entry.userId, - filter: (entry) => entry.extraData?.role === role.id - }); - } - - protected override async handleUndoPre(guild: Guild, entry: ModerationAction.Entry, data: ModerationAction.Data) { - const role = data.context!; - await api().guilds.removeRoleFromMember(guild.id, entry.userId, role.id, { reason: entry.reason ?? undefined }); - - await this.completeLastModerationEntryFromUser({ - guild, - userId: entry.userId, - filter: (entry) => entry.extraData?.role === role.id - }); - } - - protected override resolveOptionsExtraData(_guild: Guild, _options: ModerationAction.PartialOptions, data: ModerationAction.Data) { - return { role: data.context!.id }; - } -} diff --git a/src/lib/moderation/actions/ModerationActionRoleRemove.ts b/src/lib/moderation/actions/ModerationActionRoleRemove.ts deleted file mode 100644 index 2886705ab..000000000 --- a/src/lib/moderation/actions/ModerationActionRoleRemove.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { api } from '#lib/discord/Api'; -import { ModerationAction } from '#lib/moderation/actions/base/ModerationAction'; -import { resolveOnErrorCodes } from '#utils/common'; -import { TypeVariation } from '#utils/moderationConstants'; -import { isNullish } from '@sapphire/utilities'; -import { RESTJSONErrorCodes, type Guild, type Role } from 'discord.js'; - -export class ModerationActionRoleRemove extends ModerationAction { - public constructor() { - super({ - type: TypeVariation.RoleRemove, - isUndoActionAvailable: true, - logPrefix: 'Moderation => RoleRemove' - }); - } - - public override async isActive(guild: Guild, userId: string, context: Role) { - const member = await resolveOnErrorCodes(guild.members.fetch(userId), RESTJSONErrorCodes.UnknownMember); - return !isNullish(member) && !member.roles.cache.has(context.id); - } - - protected override async handleApplyPre(guild: Guild, entry: ModerationAction.Entry, data: ModerationAction.Data) { - const role = data.context!; - await api().guilds.removeRoleFromMember(guild.id, entry.userId, role.id, { - reason: await this.getReason(guild, entry.reason) - }); - - await this.completeLastModerationEntryFromUser({ - guild, - userId: entry.userId, - filter: (log) => log.extraData?.role === role.id - }); - } - - protected override async handleUndoPre(guild: Guild, entry: ModerationAction.Entry, data: ModerationAction.Data) { - const role = data.context!; - await api().guilds.addRoleToMember(guild.id, entry.userId, role.id, { reason: entry.reason ?? undefined }); - - await this.completeLastModerationEntryFromUser({ - guild, - userId: entry.userId, - filter: (log) => log.extraData?.role === role.id - }); - } - - protected override resolveOptionsExtraData(_guild: Guild, _options: ModerationAction.PartialOptions, data: ModerationAction.Data) { - return { role: data.context!.id }; - } -} diff --git a/src/lib/moderation/actions/ModerationActionSetNickname.ts b/src/lib/moderation/actions/ModerationActionSetNickname.ts deleted file mode 100644 index 7e1b9bbc4..000000000 --- a/src/lib/moderation/actions/ModerationActionSetNickname.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { api } from '#lib/discord/Api'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { ModerationAction } from '#lib/moderation/actions/base/ModerationAction'; -import { resolveOnErrorCodes } from '#utils/common'; -import { TypeVariation } from '#utils/moderationConstants'; -import { resolveKey } from '@sapphire/plugin-i18next'; -import { isNullish } from '@sapphire/utilities'; -import { RESTJSONErrorCodes, type Guild } from 'discord.js'; - -const Root = LanguageKeys.Commands.Moderation; - -export class ModerationActionSetNickname extends ModerationAction { - public constructor() { - super({ - type: TypeVariation.SetNickname, - isUndoActionAvailable: true, - logPrefix: 'Moderation => SetNickname' - }); - } - - public override async isActive(guild: Guild, userId: string, context: string | null) { - const member = await resolveOnErrorCodes(guild.members.fetch(userId), RESTJSONErrorCodes.UnknownMember); - return !isNullish(member) && member.nickname === context; - } - - protected override async handleApplyPre(guild: Guild, entry: ModerationAction.Entry, data: ModerationAction.Data) { - const nickname = data.context || null; - const reason = await (entry.reason - ? resolveKey(guild, nickname ? Root.ActionSetNicknameSet : Root.ActionSetNicknameRemoved, { reason: entry.reason }) - : resolveKey(guild, nickname ? Root.ActionSetNicknameNoReasonSet : Root.ActionSetNicknameNoReasonRemoved)); - await api().guilds.editMember(guild.id, entry.userId, { nick: nickname }, { reason }); - - await this.completeLastModerationEntryFromUser({ guild, userId: entry.userId }); - } - - protected override async handleUndoPre(guild: Guild, entry: ModerationAction.Entry, data: ModerationAction.Data) { - const nickname = data.context || null; - await api().guilds.editMember(guild.id, entry.userId, { nick: nickname }, { reason: entry.reason || undefined }); - - await this.completeLastModerationEntryFromUser({ guild, userId: entry.userId }); - } - - protected override async resolveOptionsExtraData(guild: Guild, options: ModerationAction.PartialOptions) { - const member = await guild.members.fetch(options.user); - return { oldName: member.nickname }; - } -} diff --git a/src/lib/moderation/actions/ModerationActionSoftBan.ts b/src/lib/moderation/actions/ModerationActionSoftBan.ts deleted file mode 100644 index 836a16459..000000000 --- a/src/lib/moderation/actions/ModerationActionSoftBan.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { api } from '#lib/discord/Api'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { ModerationAction } from '#lib/moderation/actions/base/ModerationAction'; -import { TypeVariation } from '#utils/moderationConstants'; -import { fetchT, type TFunction } from '@sapphire/plugin-i18next'; -import { isNullishOrEmpty } from '@sapphire/utilities'; -import type { Guild } from 'discord.js'; - -const Root = LanguageKeys.Commands.Moderation; - -export class ModerationActionSoftban extends ModerationAction { - public constructor() { - super({ - type: TypeVariation.Softban, - isUndoActionAvailable: false, - logPrefix: 'Moderation => Softban' - }); - } - - protected override async handleApplyPost(guild: Guild, entry: ModerationAction.Entry, data: ModerationAction.Data) { - const t = await fetchT(guild); - - await api().guilds.banUser(guild.id, entry.userId, { delete_message_seconds: data.context ?? 0 }, this.#getBanReason(t, entry.reason)); - await api().guilds.unbanUser(guild.id, entry.userId, this.#getUnbanReason(t, entry.reason)); - - await this.completeLastModerationEntryFromUser({ guild, userId: entry.userId, type: TypeVariation.Ban }); - } - - #getBanReason(t: TFunction, reason: string | null | undefined) { - return { reason: isNullishOrEmpty(reason) ? t(Root.ActionSoftBanNoReason) : t(Root.ActionSoftBanReason, { reason }) }; - } - - #getUnbanReason(t: TFunction, reason: string | null | undefined) { - return { reason: isNullishOrEmpty(reason) ? t(Root.ActionUnSoftBanNoReason) : t(Root.ActionUnSoftBanReason, { reason }) }; - } -} diff --git a/src/lib/moderation/actions/ModerationActionTimeout.ts b/src/lib/moderation/actions/ModerationActionTimeout.ts deleted file mode 100644 index 2af7cac31..000000000 --- a/src/lib/moderation/actions/ModerationActionTimeout.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { api } from '#lib/discord/Api'; -import { ModerationAction } from '#lib/moderation/actions/base/ModerationAction'; -import { days, resolveOnErrorCodes } from '#utils/common'; -import { getLogger } from '#utils/functions'; -import { TypeVariation } from '#utils/moderationConstants'; -import { isNullish } from '@sapphire/utilities'; -import { RESTJSONErrorCodes, type Guild, type Snowflake } from 'discord.js'; - -export class ModerationActionTimeout extends ModerationAction { - public constructor() { - super({ - type: TypeVariation.Timeout, - isUndoActionAvailable: true, - maximumDuration: days(28), - durationRequired: true, - durationExternal: true, - logPrefix: 'Moderation => Timeout' - }); - } - - public override async isActive(guild: Guild, userId: Snowflake) { - const member = await resolveOnErrorCodes(guild.members.fetch(userId), RESTJSONErrorCodes.UnknownMember); - return !isNullish(member) && member.isCommunicationDisabled(); - } - - protected override async handleApplyPre(guild: Guild, entry: ModerationAction.Entry) { - const reason = await this.getReason(guild, entry.reason); - const time = new Date(Date.now() + entry.duration!).toISOString(); - await api().guilds.editMember(guild.id, entry.userId, { communication_disabled_until: time }, { reason }); - - await this.completeLastModerationEntryFromUser({ guild, userId: entry.userId }); - } - - protected override handleApplyPreOnStart(guild: Guild, entry: ModerationAction.Entry) { - getLogger(guild).timeout.set(entry.userId, { userId: entry.moderatorId, reason: entry.reason }); - } - - protected override handleApplyPreOnError(_error: Error, guild: Guild, entry: ModerationAction.Entry) { - getLogger(guild).timeout.unset(entry.userId); - } - - protected override async handleUndoPre(guild: Guild, entry: ModerationAction.Entry) { - const reason = await this.getReason(guild, entry.reason, true); - await api().guilds.editMember(guild.id, entry.userId, { communication_disabled_until: null }, { reason }); - - await this.completeLastModerationEntryFromUser({ guild, userId: entry.userId }); - } - - protected override handleUndoPreOnStart(guild: Guild, entry: ModerationAction.Entry) { - getLogger(guild).timeout.set(entry.userId, { userId: entry.moderatorId, reason: entry.reason }); - } - - protected override handleUndoPreOnError(_error: Error, guild: Guild, entry: ModerationAction.Entry) { - getLogger(guild).timeout.unset(entry.userId); - } -} diff --git a/src/lib/moderation/actions/ModerationActionVoiceKick.ts b/src/lib/moderation/actions/ModerationActionVoiceKick.ts deleted file mode 100644 index 5a50ff62b..000000000 --- a/src/lib/moderation/actions/ModerationActionVoiceKick.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { api } from '#lib/discord/Api'; -import { ModerationAction } from '#lib/moderation/actions/base/ModerationAction'; -import { TypeVariation } from '#utils/moderationConstants'; -import type { Guild } from 'discord.js'; - -export class ModerationActionVoiceKick extends ModerationAction { - public constructor() { - super({ - type: TypeVariation.VoiceKick, - isUndoActionAvailable: false, - logPrefix: 'Moderation => VoiceKick' - }); - } - - protected override async handleApplyPost(guild: Guild, entry: ModerationAction.Entry) { - const reason = await this.getReason(guild, entry.reason); - await api().guilds.editMember(guild.id, entry.userId, { channel_id: null }, { reason }); - } -} diff --git a/src/lib/moderation/actions/ModerationActionVoiceMute.ts b/src/lib/moderation/actions/ModerationActionVoiceMute.ts deleted file mode 100644 index a41c95a71..000000000 --- a/src/lib/moderation/actions/ModerationActionVoiceMute.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { api } from '#lib/discord/Api'; -import { ModerationAction } from '#lib/moderation/actions/base/ModerationAction'; -import { resolveOnErrorCodes } from '#utils/common'; -import { TypeVariation } from '#utils/moderationConstants'; -import { RESTJSONErrorCodes, type Guild, type Snowflake } from 'discord.js'; - -export class ModerationActionVoiceMute extends ModerationAction { - public constructor() { - super({ - type: TypeVariation.VoiceMute, - isUndoActionAvailable: true, - logPrefix: 'Moderation => VoiceMute' - }); - } - - public override async isActive(guild: Guild, userId: Snowflake) { - const member = await resolveOnErrorCodes(guild.members.fetch(userId), RESTJSONErrorCodes.UnknownMember); - return member?.voice.serverMute ?? false; - } - - protected override async handleApplyPre(guild: Guild, entry: ModerationAction.Entry) { - const reason = await this.getReason(guild, entry.reason); - await api().guilds.editMember(guild.id, entry.userId, { mute: true }, { reason }); - - await this.completeLastModerationEntryFromUser({ guild, userId: entry.userId }); - } - - protected override async handleUndoPre(guild: Guild, entry: ModerationAction.Entry) { - const reason = await this.getReason(guild, entry.reason, true); - await api().guilds.editMember(guild.id, entry.userId, { mute: false }, { reason }); - - await this.completeLastModerationEntryFromUser({ guild, userId: entry.userId }); - } -} diff --git a/src/lib/moderation/actions/ModerationActionWarning.ts b/src/lib/moderation/actions/ModerationActionWarning.ts deleted file mode 100644 index a3a70f080..000000000 --- a/src/lib/moderation/actions/ModerationActionWarning.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { ModerationAction } from '#lib/moderation/actions/base/ModerationAction'; -import { TypeVariation } from '#utils/moderationConstants'; - -export class ModerationActionWarning extends ModerationAction { - public constructor() { - super({ - type: TypeVariation.Warning, - isUndoActionAvailable: false, - logPrefix: 'Moderation => Warning' - }); - } -} diff --git a/src/lib/moderation/actions/base/ModerationAction.ts b/src/lib/moderation/actions/base/ModerationAction.ts deleted file mode 100644 index 6c3d0c55b..000000000 --- a/src/lib/moderation/actions/base/ModerationAction.ts +++ /dev/null @@ -1,430 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { getTitle, getTranslationKey } from '#lib/moderation/common'; -import type { ModerationManager } from '#lib/moderation/managers/ModerationManager'; -import type { TypedT } from '#lib/types'; -import { TypeMetadata, type TypeVariation } from '#lib/util/moderationConstants'; -import { seconds, years } from '#utils/common'; -import { getCodeStyle, getLogPrefix, getModeration } from '#utils/functions'; -import { getFullEmbedAuthor } from '#utils/util'; -import { EmbedBuilder } from '@discordjs/builders'; -import { container } from '@sapphire/framework'; -import { fetchT } from '@sapphire/plugin-i18next'; -import { isNullish, isNullishOrEmpty, isNullishOrZero, type Awaitable } from '@sapphire/utilities'; -import { DiscordAPIError, HTTPError, RESTJSONErrorCodes, type Guild, type Snowflake, type User } from 'discord.js'; - -const Root = LanguageKeys.Commands.Moderation; - -export abstract class ModerationAction { - /** - * Represents the type of moderation action. - */ - public readonly type: Type; - - /** - * The minimum duration for the action. - */ - public readonly minimumDuration: number; - - /** - * The maximum duration for the action. - */ - public readonly maximumDuration: number; - - /** - * Whether or not the action allows undoing. - */ - public readonly isUndoActionAvailable: boolean; - - /** - * Whether or not the action requires a duration. - */ - public readonly durationRequired: boolean; - - /** - * Whether or not the action uses an external timer. This is true for - * actions that are not time-managed by the bot, such as timeouts. - * - * @remarks - * - * If this field is set to `true`, the action will need to be re-applied in - * order to update the duration. - */ - public readonly durationExternal: boolean; - - /** - * The prefix used for logging moderation actions. - */ - protected readonly logPrefix: string; - - /** - * The key of the moderation action. - */ - protected readonly actionKey: TypedT; - - public constructor(options: ModerationAction.ConstructorOptions) { - this.type = options.type; - this.actionKey = getTranslationKey(this.type); - this.logPrefix = getLogPrefix(options.logPrefix); - this.durationRequired = options.durationRequired ?? false; - this.durationExternal = options.durationExternal ?? false; - this.minimumDuration = options.minimumDuration ?? (this.durationRequired ? seconds(5) : 0); - this.maximumDuration = options.maximumDuration ?? years(1); - this.isUndoActionAvailable = options.isUndoActionAvailable; - } - - /** - * Checks if this action is active for a given user in a guild. - * - * @param guild - The guild to check. - * @param userId - The ID of the user. - * @param context - The context for the action. - * @returns A boolean indicating whether the action is active. - */ - public isActive(guild: Guild, userId: Snowflake, context: ContextType): Awaitable; - public isActive() { - return false; - } - - /** - * Cancels the last moderation entry task from a user. - * - * @param options - The options to fetch the moderation entry. - * @returns The canceled moderation entry, or `null` if no entry was found. - */ - public async completeLastModerationEntryFromUser( - options: ModerationAction.ModerationEntryFetchOptions - ): Promise | null> { - const entry = await this.retrieveLastModerationEntryFromUser(options); - if (isNullish(entry)) return null; - - if (!isNullishOrZero(entry.duration) && !entry.isCompleted()) { - await getModeration(options.guild).complete(entry); - } - return entry; - } - - /** - * Retrieves the last moderation entry from a user based on the provided options. - * - * @param options - The options for fetching the moderation entry. - * @returns The last moderation entry from the user, or `null` if no entry is found. - */ - public async retrieveLastModerationEntryFromUser( - options: ModerationAction.ModerationEntryFetchOptions - ): Promise | null> { - // Retrieve all the entries - const entries = await getModeration(options.guild).fetch({ userId: options.userId }); - - const type = options.type ?? this.type; - const metadata = options.metadata ?? null; - const extra = options.filter ?? (() => true); - - for (const entry of entries.values()) { - // If the entry has been archived or has completed, skip it: - if (entry.isArchived() || entry.isCompleted()) continue; - // If the entry is not of the same type, skip it: - if (entry.type !== type) continue; - // If the entry is not of the same metadata, skip it: - if (metadata !== null && entry.metadata !== metadata) continue; - // If the extra check fails, skip it: - if (!extra(entry as ModerationManager.Entry)) continue; - - return entry as ModerationManager.Entry; - } - - return null; - } - - /** - * Applies a moderation action to a user in the specified guild. - * - * @param guild - The guild to apply the moderation action at. - * @param options - The options for the moderation action. - * @param data - The options for sending the direct message. - * @returns A Promise that resolves to the created moderation entry. - */ - public async apply(guild: Guild, options: ModerationAction.PartialOptions, data: ModerationAction.Data = {}) { - const moderation = getModeration(guild); - const entry = moderation.create(await this.resolveOptions(guild, options, data)); - try { - this.handleApplyPreOnStart(guild, entry, data); - await this.handleApplyPre(guild, entry, data); - } catch (error) { - await this.handleApplyPreOnError(error as Error, guild, entry, data); - throw error; - } - await this.sendDirectMessage(guild, entry, data); - await this.handleApplyPost(guild, entry, data); - return moderation.insert(entry); - } - - /** - * Undoes a moderation action to a user in the specified guild. - * - * @param guild - The guild to apply the moderation action at. - * @param options - The options for the moderation action. - * @param data - The data for the action. - * @returns A promise that resolves to the created entry. - */ - public async undo(guild: Guild, options: ModerationAction.PartialOptions, data: ModerationAction.Data = {}) { - const moderation = getModeration(guild); - const entry = moderation.create(await this.resolveAppealOptions(guild, options, data)); - try { - this.handleUndoPreOnStart(guild, entry, data); - await this.handleUndoPre(guild, entry, data); - } catch (error) { - await this.handleUndoPreOnError(error as Error, guild, entry, data); - throw error; - } - await this.sendDirectMessage(guild, entry, data); - await this.handleUndoPost(guild, entry, data); - return moderation.insert(entry); - } - - /** - * Handles the pre-apply of the moderation action. Executed before the moderation entry is created and the user has - * been notified. - * - * @param guild - The guild to apply the moderation action at. - * @param entry - The draft moderation action. - * @param data - The data for the action. - */ - protected handleApplyPre(guild: Guild, entry: ModerationManager.Entry, data: ModerationAction.Data): Awaitable; - protected handleApplyPre() {} - - /** - * Handles a hook that is executed before the moderation action is applied at {@linkcode handleApplyPre}. - * - * @param guild - The guild at which the moderation action is being applied. - * @param entry - The draft moderation action. - * @param data - The data for the action. - */ - protected handleApplyPreOnStart(guild: Guild, entry: ModerationManager.Entry, data: ModerationAction.Data): unknown; - protected handleApplyPreOnStart() {} - - /** - * Handles a hook that is executed when {@linkcode handleApplyPre} threw an error. - * - * @param guild - The guild at which the moderation action is being applied. - * @param entry - The draft moderation action. - * @param data - The data for the action. - */ - protected handleApplyPreOnError( - error: Error, - guild: Guild, - entry: ModerationManager.Entry, - data: ModerationAction.Data - ): unknown; - - protected handleApplyPreOnError() {} - - /** - * Handles the post-apply of the moderation action. Executed after the moderation entry is created and the user has - * been notified. - * - * @param guild - The guild to apply the moderation action at. - * @param entry - The draft moderation action. - * @param data - The data for the action. - */ - protected handleApplyPost(guild: Guild, entry: ModerationManager.Entry, data: ModerationAction.Data): Awaitable; - protected handleApplyPost() {} - - /** - * Handles the pre-undo of the moderation action. Executed before the moderation entry is created and the user has - * been notified. - * - * @param guild - The guild to undo a moderation action at. - * @param entry - The draft moderation action. - * @param data - The data for the action. - */ - protected handleUndoPre(guild: Guild, entry: ModerationManager.Entry, data: ModerationAction.Data): Awaitable; - protected handleUndoPre() {} - - /** - * Handles a hook that is executed before the moderation action is applied at {@linkcode handleUndoPre}. - * - * @param guild - The guild at which the moderation action is being applied. - * @param entry - The draft moderation action. - * @param data - The data for the action. - */ - protected handleUndoPreOnStart(guild: Guild, entry: ModerationManager.Entry, data: ModerationAction.Data): unknown; - protected handleUndoPreOnStart() {} - - /** - * Handles a hook that is executed when {@linkcode handleUndoPre} threw an error. - * - * @param guild - The guild at which the moderation action is being applied. - * @param entry - The draft moderation action. - * @param data - The data for the action. - */ - protected handleUndoPreOnError( - error: Error, - guild: Guild, - entry: ModerationManager.Entry, - data: ModerationAction.Data - ): unknown; - - protected handleUndoPreOnError() {} - - /** - * Handles the post-undo of the moderation action. Executed after the moderation entry is created and the user has - * been notified. - * - * @param guild - The guild to undo a moderation action at. - * @param entry - The draft moderation action. - * @param data - The data for the action. - */ - protected handleUndoPost(guild: Guild, entry: ModerationManager.Entry, data: ModerationAction.Data): Awaitable; - protected handleUndoPost() {} - - protected async resolveOptions( - guild: Guild, - options: ModerationAction.PartialOptions, - data: ModerationAction.Data, - metadata: TypeMetadata = 0 - ): Promise> { - return { - ...options, - duration: options.duration || null, - type: this.type, - metadata, - extraData: options.extraData || (await this.resolveOptionsExtraData(guild, options, data)) - }; - } - - /** - * Resolves the extra data for the moderation action. - * - * @param guild - The guild where the moderation action occurred. - * @param options - The original options for the moderation action. - * @param data - The options for sending the direct message. - */ - protected resolveOptionsExtraData( - guild: Guild, - options: ModerationAction.PartialOptions, - data: ModerationAction.Data - ): Awaitable>; - - protected resolveOptionsExtraData() { - return null as ModerationManager.ExtraData; - } - - /** - * Resolves the options for an appeal. - * - * @param guild - The guild where the moderation action occurred. - * @param options - The original options for the moderation action. - * @param data - The data for the action. - */ - protected async resolveAppealOptions(guild: Guild, options: ModerationAction.PartialOptions, data: ModerationAction.Data) { - return this.resolveOptions(guild, options, data, TypeMetadata.Undo); - } - - /** - * Sends a direct message to the user associated with the moderation entry. - * - * @param guild - The guild where the moderation action occurred. - * @param entry - The moderation entry. - * @param data - The data for the action. - */ - protected async sendDirectMessage(guild: Guild, entry: ModerationManager.Entry, data: ModerationAction.Data) { - if (!data.sendDirectMessage) return; - - try { - const target = await entry.fetchUser(); - const embed = await this.#buildEmbed(guild, entry, data); - await target.send({ embeds: [embed] }); - } catch (error) { - this.#handleDirectMessageError(error as Error); - } - } - - /** - * Retrieves the reason for a moderation action. - * - * @param guild - The guild where the moderation action occurred. - * @param reason - The reason for the moderation action. - * @param undo - Whether the action is an undo action. - * @returns The reason for the moderation action. - */ - protected async getReason(guild: Guild, reason: string | null | undefined, undo = false) { - const t = await fetchT(guild); - const action = t(this.actionKey); - return isNullishOrEmpty(reason) - ? t(undo ? Root.ActionRevokeNoReason : Root.ActionApplyNoReason, { action }) - : t(undo ? Root.ActionRevokeReason : Root.ActionApplyReason, { action, reason }); - } - - async #buildEmbed(guild: Guild, entry: ModerationManager.Entry, data: ModerationAction.Data) { - const descriptionKey = entry.reason - ? entry.duration - ? Root.ModerationDmDescriptionWithReasonWithDuration - : Root.ModerationDmDescriptionWithReason - : entry.duration - ? Root.ModerationDmDescriptionWithDuration - : Root.ModerationDmDescription; - - const t = await fetchT(guild); - const description = t(descriptionKey, { - guild: guild.name, - title: getTitle(t, entry), - reason: entry.reason, - duration: entry.duration - }); - const embed = new EmbedBuilder() // - .setDescription(description) - .setFooter({ text: t(Root.ModerationDmFooter) }); - - if (data.moderator) embed.setAuthor(getFullEmbedAuthor(data.moderator)); - return embed; - } - - #handleDirectMessageError(error: Error) { - if (error instanceof DiscordAPIError) return this.#handleDirectMessageDiscordError(error); - if (error instanceof HTTPError) return this.#handleDirectMessageHTTPError(error); - throw error; - } - - #handleDirectMessageDiscordError(error: DiscordAPIError) { - if (error.code === RESTJSONErrorCodes.CannotSendMessagesToThisUser) return; - - container.logger.error(this.logPrefix, getCodeStyle(error.code), error.url); - throw error; - } - - #handleDirectMessageHTTPError(error: HTTPError) { - container.logger.error(this.logPrefix, getCodeStyle(error.status), error.url); - throw error; - } -} - -export namespace ModerationAction { - export interface ConstructorOptions { - type: Type; - logPrefix: string; - isUndoActionAvailable: boolean; - minimumDuration?: number; - maximumDuration?: number; - durationRequired?: boolean; - durationExternal?: boolean; - } - - export type Options = ModerationManager.CreateData; - export type PartialOptions = Omit, 'type' | 'metadata'>; - - export type Entry = ModerationManager.Entry; - - export interface Data { - context?: ContextType; - sendDirectMessage?: boolean; - moderator?: User | null; - } - - export interface ModerationEntryFetchOptions { - guild: Guild; - userId: Snowflake; - type?: Type; - metadata?: TypeMetadata | null; - filter?: (entry: ModerationManager.Entry) => boolean; - } -} diff --git a/src/lib/moderation/actions/base/RoleModerationAction.ts b/src/lib/moderation/actions/base/RoleModerationAction.ts deleted file mode 100644 index d221f3a06..000000000 --- a/src/lib/moderation/actions/base/RoleModerationAction.ts +++ /dev/null @@ -1,436 +0,0 @@ -import { readSettings, writeSettings, writeSettingsTransaction } from '#lib/database'; -import { getT } from '#lib/i18n'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { ModerationAction } from '#lib/moderation/actions/base/ModerationAction'; -import type { GuildMessage } from '#lib/types'; -import { PermissionsBits } from '#utils/bits'; -import { resolveOnErrorCodes } from '#utils/common'; -import { getCodeStyle, getStickyRoles, promptConfirmation } from '#utils/functions'; -import type { TypeVariation } from '#utils/moderationConstants'; -import { GuildLimits, isCategoryChannel, isTextBasedChannel, isThreadChannel, isVoiceBasedChannel } from '@sapphire/discord.js-utilities'; -import { UserError, container, type Awaitable } from '@sapphire/framework'; -import { isNullish } from '@sapphire/utilities'; -import { - DiscordAPIError, - Guild, - GuildMember, - HTTPError, - PermissionFlagsBits, - RESTJSONErrorCodes, - Role, - inlineCode, - type NonThreadGuildBasedChannel, - type PermissionOverwriteOptions, - type RoleData, - type Snowflake -} from 'discord.js'; - -const Root = LanguageKeys.Commands.Moderation; - -interface Overrides { - bitfield: bigint; - array: readonly (keyof typeof PermissionFlagsBits)[]; - options: PermissionOverwriteOptions; -} - -export abstract class RoleModerationAction extends ModerationAction< - ContextType, - Type -> { - /** - * Represents the key of a role used in a moderation action. - */ - public readonly roleKey: RoleModerationAction.RoleKey; - - /** - * Indicates whether the existing roles should be replaced. - */ - protected readonly replace: boolean; - - /** - * Represents the data of a role for setup purposes. - */ - protected readonly roleData: RoleData; - - /** - * The representation of the role overrides for text-based channels. - */ - protected readonly roleOverridesText: Overrides; - /** - * The representation of the role overrides for voice-based channels. - */ - protected readonly roleOverridesVoice: Overrides; - /** - * The representation of the role overrides for generic and mixed channels. - */ - protected readonly roleOverridesMerged: Overrides; - - public constructor(options: RoleModerationAction.ConstructorOptions) { - super({ isUndoActionAvailable: true, ...options }); - this.replace = options.replace ?? false; - - this.roleKey = options.roleKey; - this.roleData = options.roleData; - - this.roleOverridesText = this.#resolveOverrides(options.roleOverridesText ?? 0n); - this.roleOverridesVoice = this.#resolveOverrides(options.roleOverridesVoice ?? 0n); - this.roleOverridesMerged = this.#resolveOverrides(this.roleOverridesText.bitfield | this.roleOverridesVoice.bitfield); - } - - public override async isActive(guild: Guild, userId: Snowflake) { - const settings = await readSettings(guild); - const roleId = settings[this.roleKey]; - if (isNullish(roleId)) return false; - - const member = await resolveOnErrorCodes(guild.members.fetch(userId), RESTJSONErrorCodes.UnknownMember); - return !isNullish(member) && member.roles.cache.has(roleId); - } - - /** - * Sets up the role moderation action. - * - * @param message - The guild message that triggered the setup. - * @param guild - The guild where the setup is being performed. - * @returns A Promise that resolves once the setup is complete. - * @throws {UserError} If a mute role already exists or if there are too many roles in the guild. - */ - public async setup(message: GuildMessage) { - const { guild } = message; - const settings = await readSettings(guild); - const roleId = settings[this.roleKey]; - if (roleId && guild.roles.cache.has(roleId)) throw new UserError({ identifier: Root.ActionSetupMuteExists }); - if (guild.roles.cache.size >= GuildLimits.MaximumRoles) throw new UserError({ identifier: Root.ActionSetupTooManyRoles }); - - const role = await guild.roles.create({ - ...this.roleData, - reason: `[Role Setup] Authorized by ${message.author.username} (${message.author.id}).` - }); - using trx = await writeSettingsTransaction(guild); - await trx.write({ [this.roleKey]: role.id }).submit(); - - const t = getT(settings.language); - const manageableChannelCount = guild.channels.cache.reduce( - (acc, channel) => (!isThreadChannel(channel) && channel.manageable ? acc + 1 : acc), - 0 - ); - const permissions = this.roleOverridesMerged.array.map((key) => inlineCode(t(`permissions:${key}`))); - const content = t(Root.ActionSharedRoleSetupAsk, { role: role.name, channels: manageableChannelCount, permissions }); - if (await promptConfirmation(message, content)) { - await this.updateChannelsOverrides(guild, role); - } - } - - /** - * Updates the channel overrides for a given guild and role. - * - * This method iterates through all the channels in the guild, excluding threads, and updates the channel overrides - * for the specified role if the bot has the necessary permissions. - * - * @param guild - The guild where the channels are located. - * @param role - The role for which the channel overrides should be updated. - */ - public async updateChannelsOverrides(guild: Guild, role: Role) { - const channels = guild.channels.cache.values(); - for (const channel of channels) { - // Skip threads: - if (isThreadChannel(channel)) continue; - - // Skip if the bot can't manage the channel: - if (!channel.manageable) continue; - - // Update the channel overrides: - await this.updateChannelOverrides(channel, role); - } - } - - /** - * Updates the channel overrides for a given role. - * - * @param channel - The channel to update the overrides for. - * @param role - The role to update the overrides with. - * @returns A promise that resolves to `true` if the overrides were updated successfully, or `false` otherwise. - */ - public async updateChannelOverrides(channel: NonThreadGuildBasedChannel, role: Role) { - const options = this.#getChannelOverrides(channel); - if (options === null) return false; - - await channel.permissionOverwrites.edit(role, options); - return true; - } - - protected override handleApplyPre( - guild: Guild, - entry: ModerationAction.Entry, - data: ModerationAction.Data - ): Awaitable; - - protected override async handleApplyPre(guild: Guild, entry: ModerationAction.Entry) { - const member = await this.#fetchMember(guild, entry); - const role = await this.#fetchRole(guild); - - const me = await guild.members.fetchMe(); - if (!me.permissions.has(PermissionFlagsBits.ManageRoles)) { - throw new UserError({ identifier: Root.ActionCannotManageRoles }); - } - - const { position } = me.roles.highest; - if (role.position >= position) { - throw new UserError({ identifier: Root.ActionRoleHigherPosition }); - } - - await getStickyRoles(guild).add(entry.userId, role.id); - - const reason = await this.getReason(guild, entry.reason); - const data = this.replace - ? await this.#handleApplyPreRolesReplace(member, role, reason, position) - : await this.#handleApplyPreRolesAdd(member, role, reason); - Reflect.set(entry, 'extraData' satisfies keyof typeof entry, data); - } - - protected override handleUndoPre(guild: Guild, entry: ModerationAction.Entry, data: ModerationAction.Data): Awaitable; - - protected override async handleUndoPre(guild: Guild, entry: ModerationAction.Entry) { - const member = await this.#fetchMember(guild, entry); - const role = await this.#fetchRole(guild); - - const me = await guild.members.fetchMe(); - if (!me.permissions.has(PermissionFlagsBits.ManageRoles)) { - throw new UserError({ identifier: Root.ActionCannotManageRoles }); - } - - const { position } = me.roles.highest; - if (role.position >= position) { - throw new UserError({ identifier: Root.ActionRoleHigherPosition }); - } - - await getStickyRoles(guild).remove(entry.userId, role.id); - - const reason = await this.getReason(guild, entry.reason, true); - if (this.replace) { - await this.#handleUndoPreRolesReplace(member, role, reason, position); - } else { - await this.#handleUndoPreRolesRemove(member, role, reason); - } - } - - /** - * Handles the roles replace operation for a given member. - * - * This method extracts the roles from the member, adds the specified role, and updates the member's roles with the - * new set of roles. - * - * @param member - The guild member to apply the operation to. - * @param role - The role to add to the member. - * @param reason - The reason for applying the operation. - * @param position - The position of the role in the hierarchy. - * @returns An array of removed roles. - */ - async #handleApplyPreRolesReplace(member: GuildMember, role: Role, reason: string, position: number) { - const { keepRoles, removedRoles } = this.#extractRoles(member, position); - keepRoles.add(role.id); - - await member.edit({ roles: [...keepRoles], reason }); - return [...removedRoles]; - } - - /** - * Handles the apply action for adding the action role to a member. - * - * @param member - The guild member to apply the roles to. - * @param role - The role to add to the member. - * @param reason - The reason for adding the role. - * @returns A Promise that resolves to `null` when the role addition is complete. - */ - async #handleApplyPreRolesAdd(member: GuildMember, role: Role, reason: string) { - await member.roles.add(role, reason); - return null; - } - - /** - * Handles the undo operation for replacing pre-existing roles for a member. - * - * - If there is no previous moderation entry for the member, the specified role will be removed. - * - If there is a previous moderation entry, the pre-existing roles that are not managed and have a position - * lower than the specified position will be restored for the member. - * - * @param member - The guild member to handle the undo operation for. - * @param role - The role to remove if there is no previous moderation entry. - * @param reason - The reason for the undo operation. - * @param position - The position of the role that triggered the moderation action. - */ - async #handleUndoPreRolesReplace(member: GuildMember, role: Role, reason: string, position: number) { - const { guild } = member; - const entry = await this.completeLastModerationEntryFromUser({ guild, userId: member.id }); - if (isNullish(entry)) { - await member.roles.remove(role, reason); - return; - } - - const roles = new Set(member.roles.cache.keys()); - for (const roleId of Array.isArray(entry.extraData) ? entry.extraData : []) { - const role = member.guild.roles.cache.get(roleId); - // Add the ids that are: - // - In the cache. - // - Lower than Wolf's hierarchy position. - if (!isNullish(role) && !role.managed && role.position < position) roles.add(roleId); - } - - // Remove the action role from the set: - roles.delete(role.id); - - await member.edit({ roles: [...roles], reason }); - } - - /** - * Handles the undo action for removing the action role from a member. - * - * @param member - The guild member to remove the role from. - * @param role - The role to be removed. - * @param reason - The reason for removing the role. - */ - async #handleUndoPreRolesRemove(member: GuildMember, role: Role, reason: string) { - await member.roles.remove(role, reason); - } - - /** - * Retrieves the channel overrides for the given channel. - * If the channel is a category channel, it returns the merged role overrides options. - * If the channel is both a text-based and voice-based channel, it returns the merged role overrides options. - * If the channel is a text-based channel, it returns the text-based role overrides options. - * If the channel is a voice-based channel, it returns the voice-based role overrides options. - * If the channel does not match any of the above conditions, it returns null. - * - * @param channel - The channel to retrieve the overrides for. - * @returns The channel overrides options or null if no overrides are found. - */ - #getChannelOverrides(channel: NonThreadGuildBasedChannel) { - if (isCategoryChannel(channel)) return this.roleOverridesMerged.options; - - const isText = isTextBasedChannel(channel); - const isVoice = isVoiceBasedChannel(channel); - if (isText && isVoice) return this.roleOverridesMerged.options; - if (isText) return this.roleOverridesText.options; - if (isVoice) return this.roleOverridesVoice.options; - return null; - } - - /** - * Resolves the overrides for the given bitfield. - * - * @param bitfield - The bitfield to resolve overrides for. - * @returns The resolved overrides object. - */ - #resolveOverrides(bitfield: bigint): Overrides { - const array = PermissionsBits.toArray(bitfield); - const options = Object.fromEntries(array.map((key) => [key, false])); - return { bitfield, array, options }; - } - - /** - * Fetches the member from the guild using the provided options. - * - * @remarks - * If the member is not found, a {@link UserError} with the identifier {@link Root.ActionRequiredMember} is thrown. - * Otherwise, the error is re-thrown. - * - * @param guild The guild to fetch the member from. - * @param entry The entry containing the user ID. - * @returns A Promise that resolves to the fetched member. - */ - async #fetchMember(guild: Guild, entry: ModerationAction.Entry) { - try { - return await guild.members.fetch(entry.userId); - } catch (error) { - this.#handleFetchMemberError(error as Error); - } - } - - #handleFetchMemberError(error: Error): never { - if (error instanceof DiscordAPIError) this.#handleFetchMemberDiscordError(error); - if (error instanceof HTTPError) this.#handleFetchMemberHttpError(error); - throw error; - } - - #handleFetchMemberDiscordError(error: DiscordAPIError): never { - if (error.code === RESTJSONErrorCodes.UnknownMember) { - throw new UserError({ identifier: Root.ActionRequiredMember }); - } - - throw error; - } - - #handleFetchMemberHttpError(error: HTTPError): never { - container.logger.error(this.logPrefix, getCodeStyle(error.status), error.url); - throw error; - } - - /** - * Fetches the role associated with this moderation action from the guild. - * Throws an error if the role is not configured, doesn't exist, or is a managed role. - * - * @param guild - The guild to fetch the role from. - * @returns The fetched role. - * @throws If the role is not configured or if it is a managed role. - */ - async #fetchRole(guild: Guild) { - const settings = await readSettings(guild); - const roleId = settings[this.roleKey]; - if (isNullish(roleId)) throw new UserError({ identifier: Root.ActionRoleNotConfigured }); - - const role = guild.roles.cache.get(roleId); - if (isNullish(role)) { - await writeSettings(guild, { [this.roleKey]: null }); - throw new UserError({ identifier: Root.ActionRoleNotConfigured }); - } - - if (role.managed) { - throw new UserError({ identifier: Root.ActionRoleManaged }); - } - - return role; - } - - #extractRoles(member: GuildMember, highestPosition: number) { - const keepRoles = new Set(); - const removedRoles = new Set(); - - // Iterate over all the member's roles. - for (const [id, role] of member.roles.cache.entries()) { - // Managed roles cannot be removed. - if (role.managed) keepRoles.add(id); - // Roles with higher hierarchy position cannot be removed. - else if (role.position >= highestPosition) keepRoles.add(id); - // Else it is fine to remove the role. - else removedRoles.add(id); - } - - return { keepRoles, removedRoles }; - } -} - -export namespace RoleModerationAction { - export interface ConstructorOptions extends Omit< - ModerationAction.ConstructorOptions, - 'isUndoActionAvailable' - > { - replace?: boolean; - roleKey: RoleKey; - roleData: RoleData; - roleOverridesText: bigint | null; - roleOverridesVoice: bigint | null; - } - - export type Options = ModerationAction.Options; - export type PartialOptions = ModerationAction.PartialOptions; - - export type Data = ModerationAction.Data; - - export const enum RoleKey { - All = 'rolesMuted', - Reaction = 'rolesRestrictedReaction', - Embed = 'rolesRestrictedEmbed', - Emoji = 'rolesRestrictedEmoji', - Attachment = 'rolesRestrictedAttachment', - Voice = 'rolesRestrictedVoice' - } -} diff --git a/src/lib/moderation/actions/index.ts b/src/lib/moderation/actions/index.ts deleted file mode 100644 index 6fa8c73eb..000000000 --- a/src/lib/moderation/actions/index.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { ModerationActionBan } from '#lib/moderation/actions/ModerationActionBan'; -import { ModerationActionKick } from '#lib/moderation/actions/ModerationActionKick'; -import { ModerationActionRestrictedAll } from '#lib/moderation/actions/ModerationActionRestrictedAll'; -import { ModerationActionRestrictedAttachment } from '#lib/moderation/actions/ModerationActionRestrictedAttachment'; -import { ModerationActionRestrictedEmbed } from '#lib/moderation/actions/ModerationActionRestrictedEmbed'; -import { ModerationActionRestrictedEmoji } from '#lib/moderation/actions/ModerationActionRestrictedEmoji'; -import { ModerationActionRestrictedReaction } from '#lib/moderation/actions/ModerationActionRestrictedReaction'; -import { ModerationActionRestrictedVoice } from '#lib/moderation/actions/ModerationActionRestrictedVoice'; -import { ModerationActionRoleAdd } from '#lib/moderation/actions/ModerationActionRoleAdd'; -import { ModerationActionRoleRemove } from '#lib/moderation/actions/ModerationActionRoleRemove'; -import { ModerationActionSetNickname } from '#lib/moderation/actions/ModerationActionSetNickname'; -import { ModerationActionSoftban } from '#lib/moderation/actions/ModerationActionSoftBan'; -import { ModerationActionTimeout } from '#lib/moderation/actions/ModerationActionTimeout'; -import { ModerationActionVoiceKick } from '#lib/moderation/actions/ModerationActionVoiceKick'; -import { ModerationActionVoiceMute } from '#lib/moderation/actions/ModerationActionVoiceMute'; -import { ModerationActionWarning } from '#lib/moderation/actions/ModerationActionWarning'; -import type { RoleModerationAction } from '#lib/moderation/actions/base/RoleModerationAction'; -import { TypeVariation } from '#utils/moderationConstants'; -import type { ModerationAction } from './base/ModerationAction.js'; - -export const ModerationActions = { - ban: new ModerationActionBan(), - kick: new ModerationActionKick(), - mute: new ModerationActionRestrictedAll(), - timeout: new ModerationActionTimeout(), - restrictedAttachment: new ModerationActionRestrictedAttachment(), - restrictedEmbed: new ModerationActionRestrictedEmbed(), - restrictedEmoji: new ModerationActionRestrictedEmoji(), - restrictedReaction: new ModerationActionRestrictedReaction(), - restrictedVoice: new ModerationActionRestrictedVoice(), - roleAdd: new ModerationActionRoleAdd(), - roleRemove: new ModerationActionRoleRemove(), - setNickname: new ModerationActionSetNickname(), - softban: new ModerationActionSoftban(), - voiceKick: new ModerationActionVoiceKick(), - voiceMute: new ModerationActionVoiceMute(), - warning: new ModerationActionWarning() -} as const; - -export function getAction(type: Type): ActionByType { - return ModerationActions[ActionMappings[type]]; -} - -export type ActionByType = (typeof ModerationActions)[(typeof ActionMappings)[Type]]; -export type GetContextType = - ActionByType extends ModerationAction ? ContextType : never; - -const ActionMappings = { - [TypeVariation.RoleAdd]: 'roleAdd', - [TypeVariation.Ban]: 'ban', - [TypeVariation.Kick]: 'kick', - [TypeVariation.Mute]: 'mute', - [TypeVariation.Timeout]: 'timeout', - [TypeVariation.RoleRemove]: 'roleRemove', - [TypeVariation.RestrictedAttachment]: 'restrictedAttachment', - [TypeVariation.RestrictedEmbed]: 'restrictedEmbed', - [TypeVariation.RestrictedEmoji]: 'restrictedEmoji', - [TypeVariation.RestrictedReaction]: 'restrictedReaction', - [TypeVariation.RestrictedVoice]: 'restrictedVoice', - [TypeVariation.SetNickname]: 'setNickname', - [TypeVariation.Softban]: 'softban', - [TypeVariation.VoiceKick]: 'voiceKick', - [TypeVariation.VoiceMute]: 'voiceMute', - [TypeVariation.Warning]: 'warning' -} as const satisfies Readonly>; - -export type ModerationActionKey = keyof typeof ModerationActions; -export type RoleModerationActionKey = { - [K in ModerationActionKey]: (typeof ModerationActions)[K] extends RoleModerationAction ? K : never; -}[ModerationActionKey]; - -export type RoleTypeVariation = (typeof ModerationActions)[RoleModerationActionKey]['type']; diff --git a/src/lib/moderation/common/constants.ts b/src/lib/moderation/common/constants.ts deleted file mode 100644 index aa607f53c..000000000 --- a/src/lib/moderation/common/constants.ts +++ /dev/null @@ -1,149 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import type { TypedT } from '#lib/types'; -import { Colors } from '#utils/constants'; -import { TypeMetadata, TypeVariation } from '#utils/moderationConstants'; -import { isNullishOrZero } from '@sapphire/utilities'; -import type { ModerationManager } from '../managers/ModerationManager.js'; - -const Root = LanguageKeys.Moderation; - -export const TranslationMappings = { - [TypeVariation.Ban]: Root.TypeBan, - [TypeVariation.Kick]: Root.TypeKick, - [TypeVariation.Mute]: Root.TypeMute, - [TypeVariation.RestrictedAttachment]: Root.TypeRestrictedAttachment, - [TypeVariation.RestrictedEmbed]: Root.TypeRestrictedEmbed, - [TypeVariation.RestrictedEmoji]: Root.TypeRestrictedEmoji, - [TypeVariation.RestrictedReaction]: Root.TypeRestrictedReaction, - [TypeVariation.RestrictedVoice]: Root.TypeRestrictedVoice, - [TypeVariation.RoleAdd]: Root.TypeRoleAdd, - [TypeVariation.RoleRemove]: Root.TypeRoleRemove, - [TypeVariation.SetNickname]: Root.TypeSetNickname, - [TypeVariation.Softban]: Root.TypeSoftban, - [TypeVariation.Timeout]: Root.TypeTimeout, - [TypeVariation.VoiceKick]: Root.TypeVoiceKick, - [TypeVariation.VoiceMute]: Root.TypeVoiceMute, - [TypeVariation.Warning]: Root.TypeWarning -} as const satisfies Readonly>; - -export const UndoTaskNameMappings = { - [TypeVariation.Warning]: 'moderationEndWarning', - [TypeVariation.Mute]: 'moderationEndMute', - [TypeVariation.Ban]: 'moderationEndBan', - [TypeVariation.VoiceMute]: 'moderationEndVoiceMute', - [TypeVariation.Timeout]: 'moderationEndTimeout', - [TypeVariation.RestrictedAttachment]: 'moderationEndRestrictionAttachment', - [TypeVariation.RestrictedReaction]: 'moderationEndRestrictionReaction', - [TypeVariation.RestrictedEmbed]: 'moderationEndRestrictionEmbed', - [TypeVariation.RestrictedEmoji]: 'moderationEndRestrictionEmoji', - [TypeVariation.RestrictedVoice]: 'moderationEndRestrictionVoice', - [TypeVariation.SetNickname]: 'moderationEndSetNickname', - [TypeVariation.RoleAdd]: 'moderationEndAddRole', - [TypeVariation.RoleRemove]: 'moderationEndRemoveRole' -} as const; - -const AllowedMetadataTypes = TypeMetadata.Undo | TypeMetadata.Temporary; -export function combineTypeData(type: TypeVariation, metadata?: TypeMetadata): TypeCodes { - if (isNullishOrZero(metadata)) return type as TypeCodes; - return (((metadata & AllowedMetadataTypes) << 5) | type) as TypeCodes; -} - -const TypeCodes = { - Ban: combineTypeData(TypeVariation.Ban), - Kick: combineTypeData(TypeVariation.Kick), - Mute: combineTypeData(TypeVariation.Mute), - RestrictedAttachment: combineTypeData(TypeVariation.RestrictedAttachment), - RestrictedEmbed: combineTypeData(TypeVariation.RestrictedEmbed), - RestrictedEmoji: combineTypeData(TypeVariation.RestrictedEmoji), - RestrictedReaction: combineTypeData(TypeVariation.RestrictedReaction), - RestrictedVoice: combineTypeData(TypeVariation.RestrictedVoice), - RoleAdd: combineTypeData(TypeVariation.RoleAdd), - RoleRemove: combineTypeData(TypeVariation.RoleRemove), - SetNickname: combineTypeData(TypeVariation.SetNickname), - SoftBan: combineTypeData(TypeVariation.Softban), - Timeout: combineTypeData(TypeVariation.Timeout), - VoiceKick: combineTypeData(TypeVariation.VoiceKick), - VoiceMute: combineTypeData(TypeVariation.VoiceMute), - Warning: combineTypeData(TypeVariation.Warning), - UndoBan: combineTypeData(TypeVariation.Ban, TypeMetadata.Undo), - UndoMute: combineTypeData(TypeVariation.Mute, TypeMetadata.Undo), - UndoRestrictedAttachment: combineTypeData(TypeVariation.RestrictedAttachment, TypeMetadata.Undo), - UndoRestrictedEmbed: combineTypeData(TypeVariation.RestrictedEmbed, TypeMetadata.Undo), - UndoRestrictedEmoji: combineTypeData(TypeVariation.RestrictedEmoji, TypeMetadata.Undo), - UndoRestrictedReaction: combineTypeData(TypeVariation.RestrictedReaction, TypeMetadata.Undo), - UndoRestrictedVoice: combineTypeData(TypeVariation.RestrictedVoice, TypeMetadata.Undo), - UndoRoleAdd: combineTypeData(TypeVariation.RoleAdd, TypeMetadata.Undo), - UndoRoleRemove: combineTypeData(TypeVariation.RoleRemove, TypeMetadata.Undo), - UndoSetNickname: combineTypeData(TypeVariation.SetNickname, TypeMetadata.Undo), - UndoTimeout: combineTypeData(TypeVariation.Timeout, TypeMetadata.Undo), - UndoVoiceMute: combineTypeData(TypeVariation.VoiceMute, TypeMetadata.Undo), - UndoWarning: combineTypeData(TypeVariation.Warning, TypeMetadata.Undo), - TemporaryBan: combineTypeData(TypeVariation.Ban, TypeMetadata.Temporary), - TemporaryMute: combineTypeData(TypeVariation.Mute, TypeMetadata.Temporary), - TemporaryRestrictedAttachment: combineTypeData(TypeVariation.RestrictedAttachment, TypeMetadata.Temporary), - TemporaryRestrictedEmbed: combineTypeData(TypeVariation.RestrictedEmbed, TypeMetadata.Temporary), - TemporaryRestrictedEmoji: combineTypeData(TypeVariation.RestrictedEmoji, TypeMetadata.Temporary), - TemporaryRestrictedReaction: combineTypeData(TypeVariation.RestrictedReaction, TypeMetadata.Temporary), - TemporaryRestrictedVoice: combineTypeData(TypeVariation.RestrictedVoice, TypeMetadata.Temporary), - TemporaryRoleAdd: combineTypeData(TypeVariation.RoleAdd, TypeMetadata.Temporary), - TemporaryRoleRemove: combineTypeData(TypeVariation.RoleRemove, TypeMetadata.Temporary), - TemporarySetNickname: combineTypeData(TypeVariation.SetNickname, TypeMetadata.Temporary), - TemporaryTimeout: combineTypeData(TypeVariation.Timeout, TypeMetadata.Temporary), - TemporaryVoiceMute: combineTypeData(TypeVariation.VoiceMute, TypeMetadata.Temporary), - TemporaryWarning: combineTypeData(TypeVariation.Warning, TypeMetadata.Temporary) -} as const; - -export type TypeCodes = number & { __TYPE__: 'TypeCodes' }; - -export function isValidType(type: TypeVariation, metadata?: TypeMetadata): boolean { - return Metadata.has(combineTypeData(type, metadata)); -} - -export function getColor(entry: ModerationManager.Entry): number { - return Metadata.get(combineTypeData(entry.type, entry.metadata))!; -} - -const Metadata = new Map([ - [TypeCodes.Ban, Colors.Red], - [TypeCodes.Kick, Colors.Orange], - [TypeCodes.Mute, Colors.Amber], - [TypeCodes.RestrictedAttachment, Colors.Lime], - [TypeCodes.RestrictedEmbed, Colors.Lime], - [TypeCodes.RestrictedEmoji, Colors.Lime], - [TypeCodes.RestrictedReaction, Colors.Lime], - [TypeCodes.RestrictedVoice, Colors.Lime], - [TypeCodes.RoleAdd, Colors.Lime], - [TypeCodes.RoleRemove, Colors.Lime], - [TypeCodes.SetNickname, Colors.Lime], - [TypeCodes.SoftBan, Colors.DeepOrange], - [TypeCodes.Timeout, Colors.Amber], - [TypeCodes.VoiceKick, Colors.Orange], - [TypeCodes.VoiceMute, Colors.Amber], - [TypeCodes.Warning, Colors.Yellow], - [TypeCodes.UndoBan, Colors.LightBlue], - [TypeCodes.UndoMute, Colors.LightBlue], - [TypeCodes.UndoRestrictedAttachment, Colors.LightBlue], - [TypeCodes.UndoRestrictedEmbed, Colors.LightBlue], - [TypeCodes.UndoRestrictedEmoji, Colors.LightBlue], - [TypeCodes.UndoRestrictedReaction, Colors.LightBlue], - [TypeCodes.UndoRestrictedVoice, Colors.LightBlue], - [TypeCodes.UndoRoleAdd, Colors.LightBlue], - [TypeCodes.UndoRoleRemove, Colors.LightBlue], - [TypeCodes.UndoSetNickname, Colors.LightBlue], - [TypeCodes.UndoTimeout, Colors.LightBlue], - [TypeCodes.UndoVoiceMute, Colors.LightBlue], - [TypeCodes.UndoWarning, Colors.LightBlue], - [TypeCodes.TemporaryBan, Colors.Red300], - [TypeCodes.TemporaryMute, Colors.Amber300], - [TypeCodes.TemporaryRestrictedAttachment, Colors.Lime300], - [TypeCodes.TemporaryRestrictedEmbed, Colors.Lime300], - [TypeCodes.TemporaryRestrictedEmoji, Colors.Lime300], - [TypeCodes.TemporaryRestrictedReaction, Colors.Lime300], - [TypeCodes.TemporaryRestrictedVoice, Colors.Lime300], - [TypeCodes.TemporaryRoleAdd, Colors.Lime300], - [TypeCodes.TemporaryRoleRemove, Colors.Lime300], - [TypeCodes.TemporarySetNickname, Colors.Lime300], - [TypeCodes.TemporaryTimeout, Colors.Amber], - [TypeCodes.TemporaryVoiceMute, Colors.Amber300], - [TypeCodes.TemporaryWarning, Colors.Yellow300] -]) as ReadonlyMap; diff --git a/src/lib/moderation/common/index.ts b/src/lib/moderation/common/index.ts deleted file mode 100644 index 5936d1d2e..000000000 --- a/src/lib/moderation/common/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from '#lib/moderation/common/constants'; -export * from '#lib/moderation/common/util'; diff --git a/src/lib/moderation/common/util.ts b/src/lib/moderation/common/util.ts deleted file mode 100644 index 69d41892f..000000000 --- a/src/lib/moderation/common/util.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { TranslationMappings, UndoTaskNameMappings, getColor } from '#lib/moderation/common/constants'; -import type { ModerationManager } from '#lib/moderation/managers/ModerationManager'; -import type { WolfCommand } from '#lib/structures'; -import { seconds } from '#utils/common'; -import { TypeVariation } from '#utils/moderationConstants'; -import { getDisplayAvatar, getFullEmbedAuthor, getTag } from '#utils/util'; -import { EmbedBuilder } from '@discordjs/builders'; -import { container } from '@sapphire/framework'; -import type { TFunction } from '@sapphire/plugin-i18next'; -import { isNullishOrZero } from '@sapphire/utilities'; -import { TimestampStyles, chatInputApplicationCommandMention, time, type Snowflake } from 'discord.js'; - -export function getTranslationKey(type: Type): (typeof TranslationMappings)[Type] { - return TranslationMappings[type]; -} - -/** - * Retrieves the task name for the scheduled undo action based on the provided type. - * - * @param type - The type of the variation. - * @returns The undo task name associated with the provided type, or `null` if not found. - */ -export function getUndoTaskName(type: TypeVariation) { - return type in UndoTaskNameMappings ? UndoTaskNameMappings[type as keyof typeof UndoTaskNameMappings] : null; -} - -const Root = LanguageKeys.Moderation; -export function getTitle(t: TFunction, entry: ModerationManager.Entry): string { - const name = t(getTranslationKey(entry.type)); - if (entry.isUndo()) return t(Root.MetadataUndo, { name }); - if (entry.isTemporary()) return t(Root.MetadataTemporary, { name }); - return name; -} - -export async function getEmbed(t: TFunction, entry: ModerationManager.Entry) { - const [description, moderator] = await Promise.all([getEmbedDescription(t, entry), entry.fetchModerator()]); - const embed = new EmbedBuilder() - .setColor(getColor(entry)) - .setAuthor(getFullEmbedAuthor(moderator)) - .setDescription(description) - .setFooter({ - text: t(Root.EmbedFooter, { caseId: entry.id }), - iconURL: getDisplayAvatar(container.client.user!, { size: 128 }) - }) - .setTimestamp(entry.createdAt); - - if (entry.imageURL) embed.setImage(entry.imageURL); - return embed; -} - -async function getEmbedDescription(t: TFunction, entry: ModerationManager.Entry) { - const reason = entry.reason ?? t(Root.EmbedReasonNotSet, { command: getCaseEditMention(), caseId: entry.id }); - - const type = getTitle(t, entry); - const user = t(Root.EmbedUser, { tag: getTag(await entry.fetchUser()), id: entry.userId }); - return isNullishOrZero(entry.duration) - ? t(Root.EmbedDescription, { type, user, reason }) - : t(Root.EmbedDescriptionTemporary, { type, user, time: getEmbedDescriptionTime(entry.expiresTimestamp!), reason }); -} - -function getEmbedDescriptionTime(timestamp: number) { - return time(seconds.fromMilliseconds(timestamp), TimestampStyles.RelativeTime); -} - -let caseCommandId: Snowflake | null = null; -function getCaseEditMention() { - caseCommandId ??= (container.stores.get('commands').get('case') as WolfCommand).getGlobalCommandId(); - return chatInputApplicationCommandMention('case', 'edit', caseCommandId); -} diff --git a/src/lib/moderation/index.ts b/src/lib/moderation/index.ts deleted file mode 100644 index 44a49bbeb..000000000 --- a/src/lib/moderation/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from '#lib/moderation/actions/index'; -export * from '#lib/moderation/managers/index'; -export * from '#lib/moderation/structures/index'; diff --git a/src/lib/moderation/managers/LoggerManager.ts b/src/lib/moderation/managers/LoggerManager.ts deleted file mode 100644 index 8314e2166..000000000 --- a/src/lib/moderation/managers/LoggerManager.ts +++ /dev/null @@ -1,134 +0,0 @@ -import { writeSettings, type GuildSettingsOfType } from '#lib/database'; -import { PruneLoggerTypeManager, TimeoutLoggerTypeManager } from '#lib/moderation/managers/loggers'; -import { toErrorCodeResult } from '#utils/common'; -import { getCodeStyle, getLogPrefix } from '#utils/functions/pieces'; -import { EmbedBuilder } from '@discordjs/builders'; -import { container } from '@sapphire/framework'; -import { isFunction, isNullish, isNullishOrEmpty, type Awaitable, type Nullish } from '@sapphire/utilities'; -import { - PermissionFlagsBits, - RESTJSONErrorCodes, - type Guild, - type GuildBasedChannel, - type GuildTextBasedChannel, - type MessageCreateOptions, - type Snowflake -} from 'discord.js'; - -export class LoggerManager { - public readonly timeout = new TimeoutLoggerTypeManager(this); - public readonly prune = new PruneLoggerTypeManager(this); - public readonly guild: Guild; - - public constructor(guild: Guild) { - this.guild = guild; - } - - /** - * Whether or not the bot can view audit logs. - */ - public get canViewAuditLogs() { - return this.guild.members.me!.permissions.has(PermissionFlagsBits.ViewAuditLog); - } - - /** - * Send a message to the specified channel. - * @param options The options to send the message. - * @returns Whether the message was sent. - */ - public async send(options: LoggerManagerSendOptions): Promise { - if (isNullish(options.channelId) || !this.#resolveSendCondition(options.condition)) { - options.onAbort?.(); - return false; - } - - const result = await toErrorCodeResult(this.guild.channels.fetch(options.channelId)); - return result.match({ - ok: (channel) => this.#sendChannelOk(options, channel), - err: (code) => this.#sendChannelErr(options, code) - }); - } - - async #sendChannelOk(options: LoggerManagerSendOptions, channel: GuildBasedChannel | null) { - // Unsupported channel type, should never happen: - if (isNullish(channel) || !channel.isTextBased()) { - options.onAbort?.(); - return false; - } - - const rawOptions = await options.makeMessage(channel); - if (rawOptions === null) return false; - - const messageOptions = this.#resolveMessageOptions(rawOptions); - - let requiredPermissions = PermissionFlagsBits.SendMessages | PermissionFlagsBits.ViewChannel; - if (!isNullishOrEmpty(messageOptions.embeds)) requiredPermissions |= PermissionFlagsBits.EmbedLinks; - if (!isNullishOrEmpty(messageOptions.files)) requiredPermissions |= PermissionFlagsBits.AttachFiles; - - const hasPermissions = channel.permissionsFor(await this.guild.members.fetchMe()).has(requiredPermissions); - if (!hasPermissions) return false; - - const result = await toErrorCodeResult(channel.send(messageOptions)); - return result // - .inspectErr((code) => this.#logError(code, options.channelId!, 'Failed to send message in')) - .isOk(); - } - - async #sendChannelErr(options: LoggerManagerSendOptions, code: RESTJSONErrorCodes) { - options.onAbort?.(); - - // If the channel was not found, clear the settings: - if (code === RESTJSONErrorCodes.UnknownChannel) { - await writeSettings(this.guild, { [options.key]: null }); - } else { - this.#logError(code, options.channelId!, 'Failed to fetch channel'); - } - - return false; - } - - #resolveSendCondition(condition: boolean | (() => boolean) | Nullish) { - if (isNullish(condition)) return true; - if (isFunction(condition)) return condition(); - return condition; - } - - #resolveMessageOptions(options: NonNullable) { - if (Array.isArray(options)) return { embeds: options }; - if (options instanceof EmbedBuilder) return { embeds: [options] }; - return options; - } - - #logError(code: RESTJSONErrorCodes, channelId: Snowflake, content: string) { - container.logger.error(`${LogPrefix} ${getCodeStyle(code)} ${content} ${channelId}`); - } -} - -export interface LoggerManagerSendOptions { - /** - * The settings key to reset if the channel is not found. - */ - key: GuildSettingsOfType; - /** - * The channel ID to send the message to, if any. - */ - channelId: string | Nullish; - /** - * The condition to check before sending the message, if any. - */ - condition?: boolean | (() => boolean); - /** - * Makes the options for the message to send. - * @returns The message options to send. - */ - makeMessage: (channel: GuildTextBasedChannel) => Awaitable; - /** - * The function to call when the log operation was aborted before calling - * {@linkcode makeMessage}. - */ - onAbort?: () => void; -} - -export type LoggerManagerSendMessageOptions = MessageCreateOptions | EmbedBuilder | EmbedBuilder[] | null; - -const LogPrefix = getLogPrefix('LoggerManager'); diff --git a/src/lib/moderation/managers/ModerationManager.ts b/src/lib/moderation/managers/ModerationManager.ts deleted file mode 100644 index 3283f1bd2..000000000 --- a/src/lib/moderation/managers/ModerationManager.ts +++ /dev/null @@ -1,411 +0,0 @@ -import { readSettings } from '#lib/database/settings'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { ModerationManagerEntry } from '#lib/moderation/managers/ModerationManagerEntry'; -import { SortedCollection } from '#lib/structures/data'; -import { Events } from '#lib/types'; -import { createReferPromise, desc, floatPromise, minutes, orMix, seconds, type BooleanFn, type ReferredPromise } from '#utils/common'; -import { TypeMetadata, TypeVariation } from '#utils/moderationConstants'; -import { AsyncQueue } from '@sapphire/async-queue'; -import type { GuildTextBasedChannelTypes } from '@sapphire/discord.js-utilities'; -import { UserError, container } from '@sapphire/framework'; -import { isNullish } from '@sapphire/utilities'; -import type { Guild, Snowflake } from 'discord.js'; - -enum CacheActions { - None, - Fetch, - Insert -} - -export class ModerationManager { - /** - * The Guild instance that manages this manager - */ - public readonly guild: Guild; - - /** - * The cache of the moderation entries, sorted by their case ID in - * descending order. - */ - readonly #cache = new SortedCollection(undefined, desc); - - /** - * A queue for save tasks, prevents case_id duplication - */ - readonly #saveQueue = new AsyncQueue(); - - /** - * The latest moderation case ID. - */ - #latest: number | null = null; - - /** - * The amount of moderation cases in the database. - */ - #count: number | null = null; - - /** - * The timer that sweeps this manager's entries - */ - #timer: NodeJS.Timeout | null = null; - - /** - * The promise to wait for tasks to complete - */ - readonly #locks: ReferredPromise[] = []; - - private get db() { - return container.prisma; - } - - public constructor(guild: Guild) { - this.guild = guild; - } - - /** - * The channel where messages have to be sent. - */ - public async fetchChannel() { - const settings = await readSettings(this.guild); - const channelId = settings.channelsLogsModeration; - if (isNullish(channelId)) return null; - return (this.guild.channels.cache.get(channelId) ?? null) as GuildTextBasedChannelTypes | null; - } - - /** - * Retrieves the latest recent cached entry for a given user created in the last 30 seconds. - * - * @param userId - The ID of the user. - * @returns The latest recent cached entry for the user, or `null` if no entry is found. - */ - public getLatestRecentCachedEntryForUser(userId: string) { - const minimumTime = Date.now() - seconds(30); - for (const entry of this.#cache.values()) { - if (entry.userId !== userId) continue; - if (entry.createdAt < minimumTime) break; - return entry; - } - - return null; - } - - public create(data: ModerationManager.CreateData): ModerationManager.Entry { - return new ModerationManagerEntry({ - id: -1, - createdAt: -1, - ...data, - duration: data.duration ?? null, - extraData: data.extraData ?? (null as ModerationManager.ExtraData), - guild: this.guild, - moderator: data.moderator ?? process.env.CLIENT_ID, - reason: data.reason ?? null, - imageURL: data.imageURL ?? null, - metadata: data.metadata ?? TypeMetadata.None - }); - } - - public async insert(data: ModerationManager.Entry): Promise { - await this.#saveQueue.wait(); - - try { - const id = (await this.getCurrentId()) + 1; - const entry = new ModerationManagerEntry({ ...data.toData(), id, createdAt: Date.now() }); - await this.#performInsert(entry); - return this.#addToCache(entry, CacheActions.Insert); - } finally { - this.#saveQueue.shift(); - } - } - - /** - * Edits a moderation entry. - * - * @param entryOrId - The entry or ID of the moderation entry to edit. - * @param data - The updated data for the moderation entry. - * @returns The updated moderation entry. - */ - public async edit(entryOrId: ModerationManager.EntryResolvable, data: ModerationManager.UpdateData) { - const entry = await this.#resolveEntry(entryOrId); - return this.#performUpdate(entry, data); - } - - /** - * Edits the {@linkcode ModerationManagerEntry.metadata} field from a moderation entry to set - * {@linkcode TypeMetadata.Archived}. - * - * @param entryOrId - The moderation entry or its ID. - * @returns The updated moderation entry. - */ - public async archive(entryOrId: ModerationManager.EntryResolvable) { - const entry = await this.#resolveEntry(entryOrId); - if (entry.isArchived()) return entry; - return this.#performUpdate(entry, { metadata: entry.metadata | TypeMetadata.Archived }); - } - - /** - * Edits the {@linkcode ModerationManagerEntry.metadata} field from a moderation entry to set - * {@linkcode TypeMetadata.Completed}. - * - * @param entryOrId - The moderation entry or its ID. - * @returns The updated moderation entry. - */ - public async complete(entryOrId: ModerationManager.EntryResolvable) { - const entry = await this.#resolveEntry(entryOrId); - if (entry.isCompleted()) return entry; - return this.#performUpdate(entry, { metadata: entry.metadata | TypeMetadata.Completed }); - } - - /** - * Deletes a moderation entry. - * - * @param entryOrId - The moderation entry or its ID to delete. - * @returns The deleted moderation entry. - */ - public async delete(entryOrId: ModerationManager.EntryResolvable) { - const entry = await this.#resolveEntry(entryOrId); - - // Delete the task if it exists - const { task } = entry; - if (task) await task.delete(); - - // Delete the entry from the DB and the cache - await this.db.moderation.delete({ where: { caseId_guildId: { caseId: entry.id, guildId: entry.guild.id } } }); - this.#cache.delete(entry.id); - - return entry; - } - - /** - * Fetches a moderation entry from the cache or the database. - * - * @remarks - * - * If the entry is not found, it returns null. - * - * @param id - The ID of the moderation entry to fetch. - * @returns The fetched moderation entry, or `null` if it was not found. - */ - public async fetch(id: number): Promise; - /** - * Fetches multiple moderation entries from the cache or the database. - * - * @param options - The options to fetch the moderation entries. - * @returns The fetched moderation entries, sorted by - * {@link ModerationManagerEntry.id} in descending order. - */ - public async fetch(options?: ModerationManager.FetchOptions): Promise>; - public async fetch( - options: number | ModerationManager.FetchOptions = {} - ): Promise | null> { - // Case number - if (typeof options === 'number') { - return this.#getSingle(options) ?? this.#addToCache(await this.#fetchSingle(options), CacheActions.None); - } - - if (options.moderatorId || options.userId) { - return this.#count === this.#cache.size // - ? this.#getMany(options) - : this.#addToCache(await this.#fetchMany(options), CacheActions.None); - } - - if (this.#count !== this.#cache.size) { - this.#addToCache(await this.#fetchAll(), CacheActions.Fetch); - } - - return this.#cache; - } - - public async getCurrentId(): Promise { - if (this.#latest === null) { - const result = await this.db.moderation.getGuildModerationMetadata(this.guild.id); - - this.#count = result.count; - this.#latest = result.latest; - } - - return this.#latest; - } - - public createLock() { - // eslint-disable-next-line @typescript-eslint/no-invalid-void-type - const lock = createReferPromise(); - this.#locks.push(lock); - floatPromise( - lock.promise.finally(() => { - this.#locks.splice(this.#locks.indexOf(lock), 1); - }) - ); - - return () => lock.resolve(); - } - - public releaseLock() { - for (const lock of this.#locks) lock.resolve(); - } - - public waitLock() { - return Promise.all(this.#locks.map((lock) => lock.promise)); - } - - /** - * Checks if a moderation entry has been created for a given type and user - * within the last minute. - * - * @remarks - * - * This is useful to prevent duplicate moderation entries from being created - * when a user is banned, unbanned, or softbanned multiple times in a short. - * - * @param type - The type of moderation action. - * @param userId - The ID of the user. - * @returns A boolean indicating whether a moderation entry has been created. - */ - public checkSimilarEntryHasBeenCreated(type: TypeVariation, userId: Snowflake) { - const minimumTime = Date.now() - minutes(1); - const checkSoftBan = type === TypeVariation.Ban; - for (const entry of this.#cache.values()) { - // If it's not the same user target or if it's at least 1 minute old, skip: - if (userId !== entry.userId || entry.createdAt < minimumTime) continue; - - // If there was a log with the same type in the last minute, return true: - if (type === entry.type) return true; - - // If this log is a ban or an unban, but the user was softbanned recently, return true: - if (checkSoftBan && entry.type === TypeVariation.Softban) return true; - } - - // No similar entry has been created in the last minute: - return false; - } - - #addToCache(entry: ModerationManagerEntry | null, type: CacheActions): ModerationManagerEntry; - #addToCache(entries: ModerationManagerEntry[], type: CacheActions): SortedCollection; - #addToCache( - entries: ModerationManagerEntry | ModerationManagerEntry[] | null, - type: CacheActions - ): SortedCollection | ModerationManagerEntry | null { - if (!entries) return null; - - const parsedEntries = Array.isArray(entries) ? entries : [entries]; - - for (const entry of parsedEntries) { - this.#cache.set(entry.id, entry); - } - - if (type === CacheActions.Insert) { - this.#count! += parsedEntries.length; - this.#latest! += parsedEntries.length; - } - - if (!this.#timer) { - this.#timer = setInterval(() => { - this.#cache.sweep((value) => value.cacheExpired); - if (!this.#cache.size) this.#timer = null; - }, seconds(30)); - } - - return Array.isArray(entries) - ? new SortedCollection( - entries.map((entry) => [entry.id, entry]), - desc - ) - : entries; - } - - async #resolveEntry(entryOrId: ModerationManager.EntryResolvable) { - if (typeof entryOrId === 'number') { - const entry = await this.fetch(entryOrId); - if (isNullish(entry)) { - throw new UserError({ identifier: LanguageKeys.Arguments.CaseUnknownEntry, context: { parameter: entryOrId } }); - } - - return entry; - } - - if (entryOrId.guild.id !== this.guild.id) { - throw new UserError({ identifier: LanguageKeys.Arguments.CaseNotInThisGuild, context: { parameter: entryOrId.id } }); - } - - return entryOrId; - } - - #getSingle(id: number): ModerationManagerEntry | null { - return this.#cache.get(id) ?? null; - } - - async #fetchSingle(id: number): Promise { - const entity = await this.db.moderation.findUnique({ where: { caseId_guildId: { guildId: this.guild.id, caseId: id } } }); - return entity && ModerationManagerEntry.from(this.guild, entity); - } - - #getMany(options: ModerationManager.FetchOptions): SortedCollection { - const fns: BooleanFn<[ModerationManagerEntry]>[] = []; - if (options.userId) fns.push((entry) => entry.userId === options.userId); - if (options.moderatorId) fns.push((entry) => entry.moderatorId === options.moderatorId); - - const fn = orMix(...fns); - return this.#cache.filter((entry) => fn(entry)); - } - - async #fetchMany(options: ModerationManager.FetchOptions): Promise { - const entities = await this.db.moderation.findMany({ - where: { - guildId: this.guild.id, - moderatorId: options.moderatorId, - userId: options.userId - } - }); - return entities.map((entity) => ModerationManagerEntry.from(this.guild, entity)); - } - - async #fetchAll(): Promise { - const entities = await this.db.moderation.findMany({ where: { guildId: this.guild.id } }); - return entities.map((entity) => ModerationManagerEntry.from(this.guild, entity)); - } - - async #performInsert(entry: ModerationManager.Entry) { - await this.db.moderation.create({ - data: { - caseId: entry.id, - createdAt: new Date(entry.createdAt), - duration: entry.duration, - extraData: entry.extraData, - guildId: entry.guild.id, - moderatorId: entry.moderatorId, - userId: entry.userId, - reason: entry.reason, - imageURL: entry.imageURL, - type: entry.type, - metadata: entry.metadata - } - }); - - container.client.emit(Events.ModerationEntryAdd, entry); - return entry; - } - - async #performUpdate(entry: ModerationManager.Entry, data: ModerationManager.UpdateData) { - const result = await this.db.moderation.updateMany({ where: { caseId: entry.id, guildId: entry.guild.id }, data }); - if (result.count === 0) return entry; - - const clone = entry.clone(); - entry.patch(data); - container.client.emit(Events.ModerationEntryEdit, clone, entry); - return entry; - } -} - -export namespace ModerationManager { - export interface FetchOptions { - userId?: Snowflake; - moderatorId?: Snowflake; - } - - export type Entry = Readonly>; - export type EntryResolvable = Entry | number; - - export type CreateData = ModerationManagerEntry.CreateData; - export type UpdateData = ModerationManagerEntry.UpdateData; - - export type ExtraData = ModerationManagerEntry.ExtraData; -} diff --git a/src/lib/moderation/managers/ModerationManagerEntry.ts b/src/lib/moderation/managers/ModerationManagerEntry.ts deleted file mode 100644 index 9d70f9997..000000000 --- a/src/lib/moderation/managers/ModerationManagerEntry.ts +++ /dev/null @@ -1,357 +0,0 @@ -import type { ModerationData } from '#lib/database'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import type { ScheduleEntry } from '#lib/schedule'; -import { minutes } from '#utils/common'; -import { TypeMetadata, type TypeVariation } from '#utils/moderationConstants'; -import { UserError, container } from '@sapphire/framework'; -import { isNullishOrZero } from '@sapphire/utilities'; -import type { Guild, Snowflake, User } from 'discord.js'; - -/** - * Represents a moderation manager entry. - */ -export class ModerationManagerEntry { - /** - * The ID of this moderation entry. - */ - public readonly id: number; - - /** - * The timestamp when the moderation entry was created. - */ - public readonly createdAt: number; - - /** - * The duration of the moderation entry since the creation. - * - * @remarks - * - * The value can be updated to add or remove the duration. - */ - public duration!: number | null; - - /** - * The extra data of the moderation entry. - */ - public readonly extraData: ExtraDataTypes[Type]; - - /** - * The guild where the moderation entry was created. - */ - public readonly guild: Guild; - - /** - * The ID of the moderator who created the moderation entry. - */ - public readonly moderatorId: Snowflake; - - /** - * The ID of the user who is the target of the moderation entry. - */ - public readonly userId: Snowflake; - - /** - * The reason of the action in the moderation entry. - * - * @remarks - * - * The value can be updated to add or remove the reason. - */ - public reason: string | null; - - /** - * The image URL of the moderation entry. - * - * @remarks - * - * The value can be updated to add or remove the image URL. - */ - public imageURL: string | null; - - /** - * The type of the moderation entry. - */ - public readonly type: Type; - - /** - * The metadata of the moderation entry. - * - * @remarks - * - * The metadata is a bitfield that contains the following information: - * - `1 << 0`: The moderation entry is an undo action. - * - `1 << 1`: The moderation entry is temporary. - * - `1 << 3`: The moderation entry is archived. - * - * The value can be updated adding or removing any of the aforementioned - * flags. - */ - public metadata: TypeMetadata; - - #moderator: User | null; - #user: User | null; - #cacheExpiresTimeout = Date.now() + minutes(15); - - /** - * Constructs a new `ModerationManagerEntry` instance. - * - * @param data - The data to initialize the entry. - */ - public constructor(data: ModerationManagerEntry.Data) { - this.id = data.id; - this.createdAt = data.createdAt; - this.extraData = data.extraData; - this.guild = data.guild; - this.reason = data.reason; - this.imageURL = data.imageURL; - this.type = data.type; - this.metadata = data.metadata; - - this.#setDuration(data.duration); - - if (typeof data.moderator === 'string') { - this.#moderator = null; - this.moderatorId = data.moderator; - } else { - this.#moderator = data.moderator; - this.moderatorId = data.moderator.id; - } - - if (typeof data.user === 'string') { - this.#user = null; - this.userId = data.user; - } else { - this.#user = data.user; - this.userId = data.user.id; - } - } - - /** - * Creates a new instance of `ModerationManagerEntry` with the same property values as the current instance. - */ - public clone() { - return new ModerationManagerEntry(this.toData()); - } - - /** - * Updates the moderation entry with the given data. - * - * @remarks - * - * This method does not update the database, it only updates the instance - * with the given data, and updates the cache expiration time. - * - * @param data - The data to update the entry. - */ - public patch(data: ModerationManagerEntry.UpdateData) { - if (data.duration !== undefined) this.#setDuration(data.duration); - if (data.reason !== undefined) this.reason = data.reason; - if (data.imageURL !== undefined) this.imageURL = data.imageURL; - if (data.metadata !== undefined) this.metadata = data.metadata; - - this.#cacheExpiresTimeout = Date.now() + minutes(15); - } - - /** - * The scheduled task for this moderation entry. - */ - public get task() { - return container.client.schedules.queue.find((task) => this.#isMatchingTask(task)) ?? null; - } - - /** - * The timestamp when the moderation entry expires, if any. - * - * @remarks - * - * If {@linkcode duration} is `null` or `0`, this property will be `null`. - */ - public get expiresTimestamp() { - return isNullishOrZero(this.duration) ? null : this.createdAt + this.duration; - } - - /** - * Whether the moderation entry is expired. - * - * @remarks - * - * If {@linkcode expiresTimestamp} is `null`, this property will always be - * `false`. - */ - public get expired() { - const { expiresTimestamp } = this; - return expiresTimestamp !== null && expiresTimestamp < Date.now(); - } - - /** - * Whether the moderation entry is cache expired, after 15 minutes. - * - * @remarks - * - * This property is used to determine if the entry should be removed from - * the cache, and will be updated to extend the cache life when - * {@linkcode patch} is called. - */ - public get cacheExpired() { - return this.#cacheExpiresTimeout < Date.now(); - } - - /** - * Checks if the entry is an undo action. - */ - public isUndo() { - return (this.metadata & TypeMetadata.Undo) === TypeMetadata.Undo; - } - - /** - * Checks if the entry is temporary. - */ - public isTemporary() { - return (this.metadata & TypeMetadata.Temporary) === TypeMetadata.Temporary; - } - - /** - * Checks if the entry is archived. - */ - public isArchived() { - return (this.metadata & TypeMetadata.Archived) === TypeMetadata.Archived; - } - - /** - * Checks if the entry is completed. - */ - public isCompleted() { - return (this.metadata & TypeMetadata.Completed) === TypeMetadata.Completed; - } - - /** - * Fetches the moderator who created the moderation entry. - */ - public async fetchModerator() { - return (this.#moderator ??= await container.client.users.fetch(this.moderatorId)); - } - - /** - * Fetches the target user of the moderation entry. - */ - public async fetchUser() { - return (this.#user ??= await container.client.users.fetch(this.userId)); - } - - /** - * Returns a clone of the data for this moderation manager entry. - */ - public toData(): ModerationManagerEntry.Data { - return { - id: this.id, - createdAt: this.createdAt, - duration: this.duration, - extraData: this.extraData, - guild: this.guild, - moderator: this.moderatorId, - user: this.userId, - reason: this.reason, - imageURL: this.imageURL, - type: this.type, - metadata: this.metadata - }; - } - - public toJSON() { - return { - id: this.id, - createdAt: this.createdAt, - duration: this.duration, - extraData: this.extraData, - guildId: this.guild.id, - moderatorId: this.moderatorId, - userId: this.userId, - reason: this.reason, - imageURL: this.imageURL, - type: this.type, - metadata: this.metadata - }; - } - - #isMatchingTask(task: ScheduleEntry) { - return task.data !== null && task.data.caseID === this.id && task.data.guildID === this.guild.id; - } - - #setDuration(duration: bigint | number | null) { - if (typeof duration === 'bigint') duration = Number(duration); - if (isNullishOrZero(duration)) { - this.duration = null; - this.metadata &= ~TypeMetadata.Temporary; - } else { - this.duration = duration; - this.metadata |= TypeMetadata.Temporary; - } - } - - public static from(guild: Guild, entity: ModerationData) { - if (guild.id !== entity.guildId) { - throw new UserError({ identifier: LanguageKeys.Arguments.CaseNotInThisGuild, context: { parameter: entity.caseId } }); - } - - return new this({ - id: entity.caseId, - createdAt: entity.createdAt ? entity.createdAt.getTime() : Date.now(), - duration: entity.duration, - extraData: entity.extraData as any, - guild, - moderator: entity.moderatorId, - user: entity.userId!, - reason: entity.reason, - imageURL: entity.imageURL, - type: entity.type, - metadata: entity.metadata - }); - } -} - -export namespace ModerationManagerEntry { - export interface Data { - id: number; - createdAt: number; - duration: bigint | number | null; - extraData: ExtraData; - guild: Guild; - moderator: User | Snowflake; - user: User | Snowflake; - reason: string | null; - imageURL: string | null; - type: Type; - metadata: TypeMetadata; - } - - export type CreateData = MakeOptional< - Omit, 'id' | 'guild' | 'createdAt'>, - 'duration' | 'imageURL' | 'extraData' | 'metadata' | 'moderator' | 'reason' - >; - export type UpdateData = Partial< - Omit, 'id' | 'createdAt' | 'extraData' | 'moderator' | 'user' | 'type' | 'guild'> - >; - - export type ExtraData = ExtraDataTypes[Type]; -} - -type MakeOptional = Omit & Partial>; - -interface ExtraDataTypes { - [TypeVariation.Ban]: null; - [TypeVariation.Kick]: null; - [TypeVariation.Mute]: Snowflake[]; - [TypeVariation.Softban]: null; - [TypeVariation.VoiceKick]: null; - [TypeVariation.VoiceMute]: null; - [TypeVariation.Warning]: null; - [TypeVariation.RestrictedReaction]: null; - [TypeVariation.RestrictedEmbed]: null; - [TypeVariation.RestrictedAttachment]: null; - [TypeVariation.RestrictedVoice]: null; - [TypeVariation.SetNickname]: { oldName: string | null }; - [TypeVariation.RoleAdd]: { role: Snowflake }; - [TypeVariation.RoleRemove]: { role: Snowflake }; - [TypeVariation.RestrictedEmoji]: null; - [TypeVariation.Timeout]: null; -} diff --git a/src/lib/moderation/managers/StickyRoleManager.ts b/src/lib/moderation/managers/StickyRoleManager.ts deleted file mode 100644 index 317322b03..000000000 --- a/src/lib/moderation/managers/StickyRoleManager.ts +++ /dev/null @@ -1,161 +0,0 @@ -import { readSettings, writeSettingsTransaction, type StickyRole } from '#lib/database/settings'; -import { isNullish } from '@sapphire/utilities'; -import type { Guild } from 'discord.js'; - -export interface StickyRoleManagerExtraContext { - author: string; -} - -export class StickyRoleManager { - #guild: Guild; - - public constructor(guild: Guild) { - this.#guild = guild; - } - - public async get(userId: string): Promise { - const settings = await readSettings(this.#guild); - return settings.stickyRoles.find((entry) => entry.user === userId)?.roles ?? []; - } - - public async has(userId: string, roleId: string): Promise { - const roles = await this.get(userId); - return roles.includes(roleId); - } - - public async fetch(userId: string): Promise { - // 1.0. If the entry does not exist, return empty array - const settings = await readSettings(this.#guild); - const entry = settings.stickyRoles.find((entry) => entry.user === userId); - if (isNullish(entry)) return []; - - // 2.0. Read the entry and clean the roles: - const roles = [...this.cleanRoles(entry.roles)]; - - // 2.1. If the roles are unchanged (have the same size), return them: - if (entry.roles.length === roles.length) return entry.roles; - - // 2.2. If the roles are changed and leds to an empty array: - if (roles.length === 0) { - // 3.0.a. Then delete the entry from the settings: - await this.clear(userId); - return roles; - } - - // 3.0.b. Make a clone with the userId and the fixed roles array: - using trx = await writeSettingsTransaction(this.#guild); - - const index = settings.stickyRoles.findIndex((entry) => entry.user === userId); - if (index === -1) return []; - - const clone: StickyRole = { user: userId, roles }; - await trx.write({ stickyRoles: settings.stickyRoles.with(index, clone) }).submit(); - - // 4.0. Return the updated roles: - return clone.roles; - } - - public async add(userId: string, roleId: string): Promise { - using trx = await writeSettingsTransaction(this.#guild); - - // 1.0. Get the index for the entry: - const entries = trx.settings.stickyRoles; - const index = entries.findIndex((entry) => entry.user === userId); - - // 2.0. If the entry does not exist: - if (index === -1) { - // 3.0.a. Proceed to create a new sticky roles entry: - const entry: StickyRole = { user: userId, roles: [roleId] }; - await trx.write({ stickyRoles: entries.concat(entry) }).submit(); - - return entry.roles; - } - - // 3. Get the entry and append the role: - const entry = entries[index]; - const roles = [...this.addRole(roleId, entry.roles)]; - - // 4. Write the new roles to the settings: - await trx.write({ stickyRoles: entries.with(index, { user: entry.user, roles }) }).submit(); - - // 5. Return the updated roles: - return roles; - } - - public async remove(userId: string, roleId: string): Promise { - using trx = await writeSettingsTransaction(this.#guild); - - const entries = trx.settings.stickyRoles; - // 1.0. Get the index for the entry: - const index = entries.findIndex((entry) => entry.user === userId); - - // 1.1. If the index is negative, return empty array, as the entry does not exist: - if (index === -1) return []; - - // 2.0. Read the previous entry and patch it by removing the role: - const entry = entries[index]; - const roles = [...this.removeRole(roleId, entry.roles)]; - - if (roles.length === 0) { - // 3.1.a. Then delete the entry from the settings: - trx.write({ stickyRoles: entries.toSpliced(index, 1) }); - } else { - // 3.1.b. Otherwise patch it: - trx.write({ stickyRoles: entries.with(index, { user: entry.user, roles }) }); - } - await trx.submit(); - - // 4.0. Return the updated roles: - return entry.roles; - } - - public async clear(userId: string): Promise { - using trx = await writeSettingsTransaction(this.#guild); - - // 1.0. Get the index for the entry: - const entries = trx.settings.stickyRoles; - const index = entries.findIndex((entry) => entry.user === userId); - - // 1.1. If the index is negative, return empty array, as the entry does not exist: - if (index === -1) return []; - - // 2.0. Read the previous entry: - const entry = entries[index]; - - // 3.0. Remove the entry from the settings: - await trx.write({ stickyRoles: entries.toSpliced(index, 1) }).submit(); - - // 4.0. Return the previous roles: - return entry.roles; - } - - private *addRole(roleId: string, roleIds: readonly string[]) { - const emitted = new Set(); - for (const role of this.cleanRoles(roleIds)) { - if (emitted.has(role)) continue; - - emitted.add(role); - yield role; - } - - if (!emitted.has(roleId)) yield roleId; - } - - private *removeRole(roleId: string, roleIds: readonly string[]) { - const emitted = new Set(); - for (const role of this.cleanRoles(roleIds)) { - if (role === roleId) continue; - if (emitted.has(role)) continue; - - emitted.add(role); - yield role; - } - } - - private *cleanRoles(roleIds: readonly string[]) { - const { roles } = this.#guild; - for (const roleId of roleIds) { - if (roles.cache.has(roleId)) yield roleId; - } - } -} diff --git a/src/lib/moderation/managers/index.ts b/src/lib/moderation/managers/index.ts deleted file mode 100644 index 0a22f25c1..000000000 --- a/src/lib/moderation/managers/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from '#lib/moderation/managers/LoggerManager'; -export * from '#lib/moderation/managers/ModerationManager'; -export * from '#lib/moderation/managers/ModerationManagerEntry'; -export * from '#lib/moderation/managers/StickyRoleManager'; -export * from '#lib/moderation/managers/loggers'; diff --git a/src/lib/moderation/managers/loggers/PruneLoggerTypeManager.ts b/src/lib/moderation/managers/loggers/PruneLoggerTypeManager.ts deleted file mode 100644 index 1aaea87a1..000000000 --- a/src/lib/moderation/managers/loggers/PruneLoggerTypeManager.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { LoggerTypeManager } from '#lib/moderation/managers/loggers/base/LoggerTypeManager'; -import { AuditLogEvent } from 'discord.js'; - -export class PruneLoggerTypeManager extends LoggerTypeManager { - public constructor(manager: LoggerTypeManager.Manager) { - super(manager, AuditLogEvent.MessageBulkDelete); - } -} diff --git a/src/lib/moderation/managers/loggers/TimeoutLoggerTypeManager.ts b/src/lib/moderation/managers/loggers/TimeoutLoggerTypeManager.ts deleted file mode 100644 index 7e8ce3fe3..000000000 --- a/src/lib/moderation/managers/loggers/TimeoutLoggerTypeManager.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { LoggerTypeManager } from '#lib/moderation/managers/loggers/base/LoggerTypeManager'; -import { isNullishOrEmpty } from '@sapphire/utilities'; -import { AuditLogEvent } from 'discord.js'; - -export class TimeoutLoggerTypeManager extends LoggerTypeManager { - public constructor(manager: LoggerTypeManager.Manager) { - super(manager, AuditLogEvent.MemberUpdate); - } - - protected override filterAuditLogEntry(entry: LoggerTypeManager.AuditLogEntry) { - return !isNullishOrEmpty(entry.changes) && entry.changes.some((change) => change.key === 'communication_disabled_until'); - } -} diff --git a/src/lib/moderation/managers/loggers/base/LoggerTypeManager.ts b/src/lib/moderation/managers/loggers/base/LoggerTypeManager.ts deleted file mode 100644 index f09fed888..000000000 --- a/src/lib/moderation/managers/loggers/base/LoggerTypeManager.ts +++ /dev/null @@ -1,199 +0,0 @@ -import { api } from '#lib/discord/Api'; -import type { LoggerManager } from '#lib/moderation/managers/LoggerManager'; -import { createReferPromise, seconds, type ReferredPromise } from '#utils/common'; -import { DiscordSnowflake } from '@sapphire/snowflake'; -import { AuditLogEvent, Collection, type APIAuditLogEntry, type Snowflake } from 'discord.js'; - -const MaximumTimeForAuditLogEntryCreate = seconds(3); -const MaximumTimeForContextRetrieval = seconds(30); -const MaximumTimeForAuditLogRewind = seconds(60); - -/** - * A manager to handle cross-piece data sharing for logs. This structure has two - * main purposes: - * - * - Pass context data from the moderation system to a listener. - * - Pass context data from audit logs to a listener. - * - * The listener will wait for the context data to be set, and either of two - * sources can set the data, resolving the listener's promise. - * - * This manager is designed to have a single consumer and multiple producers, - * therefore, `wait` is called only once. - * - * Wolf's actions will always call the `set` method before an action is taken, - * aborting it with the `unset` method if the action fails. This way, - * information can be passed to the logging listener without wait. - * - * Audit logs will always call the `setFromAuditLogs` method after the action - * has been taken (when `wait` is called), resolving the promise. As such, it is - * important for the consumer to call `wait` as soon as possible. - * - * Consumers may call `unset` to clear the context data if it won't be used due - * to the guild's configuration settings. However, it may not call `wait` twice. - */ -export abstract class LoggerTypeManager { - /** - * The manager that created this instance. - */ - protected readonly manager: LoggerTypeManager.Manager; - - protected readonly auditLogEventType: AuditLogEvent; - - #context = new Collection(); - #promises = new Collection>(); - - public constructor(manager: LoggerTypeManager.Manager, auditLogEventType: AuditLogEvent) { - this.manager = manager; - this.auditLogEventType = auditLogEventType; - } - - /** - * Returns whether or not the context data is set, which will always be true - * when an action was taken by Wolf. - * @param id The ID of the context data to check. - */ - public isSet(id: Snowflake) { - return this.#context.has(id); - } - - /** - * Wait for the context data to be set. - * @param id The ID of the context data to wait for. - */ - public async wait(id: Snowflake, signal?: AbortSignal): Promise { - // 1. If the context data was set beforehand by Wolf, return it - // immediately. - const existing = this.#context.get(id); - if (existing) { - clearTimeout(existing.timeout); - this.#context.delete(id); - return existing.entry; - } - - const existingPromise = this.#promises.get(id); - if (existingPromise) return existingPromise.promise; - - // 2. The action was not taken by Wolf, fallback to audit logs. - // If the bot cannot view audit logs, return null immediately. - if (!this.manager.canViewAuditLogs) return null; - - signal?.throwIfAborted(); - - // 3. Wait for audit logs to set the context data. - const referPromise = createReferPromise(); - const timeout = setTimeout(() => this.#fetch(referPromise, id, signal), MaximumTimeForAuditLogEntryCreate); - signal?.addEventListener('abort', () => referPromise.resolve(null)); - - this.#promises.set(id, referPromise); - try { - return await referPromise.promise; - } finally { - clearTimeout(timeout); - this.#promises.delete(id); - } - } - - /** - * Sets the context data for the given ID, happens before {@linkcode wait} - * is called. - * @param id The ID of the context data to set. - * @param data The context data to set. - */ - public set(id: Snowflake, entry: LoggerTypeContext) { - this.#context.set(id, { - timeout: setTimeout(() => this.#context.delete(id), MaximumTimeForContextRetrieval).unref(), - entry - }); - } - - /** - * Unsets the context data for the given ID, useful when the action failed. - * @param id The ID of the context data to unset. - */ - public unset(id: Snowflake) { - const entry = this.#context.get(id); - if (entry) { - clearTimeout(entry.timeout); - this.#context.delete(id); - } - } - - /** - * Sets the context data from the audit logs, will always happen after - * {@linkcode wait} is called. - * @param id The ID of the context data to set. - * @param data The context data to set. - */ - public setFromAuditLogs(id: Snowflake, data: LoggerTypeContext) { - this.#promises.get(id)?.resolve(data); - } - - /** - * Fetches the audit logs for the given ID. - * - * @param id - The target's user ID to fetch the audit logs for. - * @param signal - The signal to abort the operation. - * @returns The last audit log entry for the given target ID, in the last - * minute, or null if no entry was found for the type. - */ - protected async fetchAuditLogsFor(id: Snowflake, signal?: AbortSignal): Promise { - const entries = await this.fetchAuditLogs(signal); - const oldestTimestamp = Date.now() - MaximumTimeForAuditLogRewind; - for (const entry of entries.audit_log_entries) { - // If the target ID is not the desired one, skip: - if (entry.target_id !== id) continue; - // If the entry is older than the desired one, skip: - if (DiscordSnowflake.timestampFrom(entry.id) < oldestTimestamp) break; - // If the entry is the desired one, return it: - if (this.filterAuditLogEntry(entry)) { - return { userId: entry.user_id!, reason: entry.reason }; - } - } - - return null; - } - - protected filterAuditLogEntry(entry: LoggerTypeManager.AuditLogEntry): boolean; - protected filterAuditLogEntry(): boolean { - return true; - } - - /** - * Fetches the audit logs for a specific type of event. - * - * @param type - The type of audit log event to fetch. - * @param signal - An optional `AbortSignal` to abort the request. - * @returns A promise that resolves to the fetched audit logs. - */ - protected fetchAuditLogs(signal?: AbortSignal) { - return api().guilds.getAuditLogs(this.manager.guild.id, { action_type: this.auditLogEventType }, { signal }); - } - - /** - * Fetches the audit logs for the given ID, resolving or rejecting the - * promise accordingly. - * - * @param referPromise - The promise to resolve or reject. - * @param id - The target's user ID to fetch the audit logs for. - * @param signal - The signal to abort the operation. - */ - async #fetch(referPromise: ReferredPromise, id: Snowflake, signal?: AbortSignal) { - try { - const data = await this.fetchAuditLogsFor(id, signal); - return referPromise.resolve(data); - } catch (error) { - return referPromise.reject(error as Error); - } - } -} - -export namespace LoggerTypeManager { - export type Manager = LoggerManager; - export type AuditLogEntry = APIAuditLogEntry; -} - -export interface LoggerTypeContext { - userId: Snowflake; - reason?: string | null; -} diff --git a/src/lib/moderation/managers/loggers/index.ts b/src/lib/moderation/managers/loggers/index.ts deleted file mode 100644 index 47f6f0d16..000000000 --- a/src/lib/moderation/managers/loggers/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { TimeoutLoggerTypeManager } from '#lib/moderation/managers/loggers/TimeoutLoggerTypeManager'; -export { PruneLoggerTypeManager } from '#lib/moderation/managers/loggers/PruneLoggerTypeManager'; diff --git a/src/lib/moderation/structures/AutoModerationCommand.ts b/src/lib/moderation/structures/AutoModerationCommand.ts deleted file mode 100644 index 8cc98b003..000000000 --- a/src/lib/moderation/structures/AutoModerationCommand.ts +++ /dev/null @@ -1,434 +0,0 @@ -import { - getConfigurableKeys, - readSettings, - readSettingsAdder, - writeSettingsTransaction, - type AdderKey, - type GuildData, - type GuildDataValue, - type GuildSettingsOfType, - type ReadonlyGuildData, - type SchemaDataKey -} from '#lib/database'; -import type { Adder } from '#lib/database/utils/Adder'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { getSupportedUserLanguageT } from '#lib/i18n/translate'; -import { AutoModerationOnInfraction, AutoModerationPunishment } from '#lib/moderation/structures/AutoModerationOnInfraction'; -import { WolfSubcommand } from '#lib/structures'; -import { PermissionLevels, type GuildMessage, type TypedT } from '#lib/types'; -import { Colors, Emojis } from '#utils/constants'; -import { resolveTimeSpan } from '#utils/resolvers'; -import { EmbedBuilder, type SlashCommandBuilder, type SlashCommandSubcommandBuilder } from '@discordjs/builders'; -import { CommandOptionsRunTypeEnum, type ApplicationCommandRegistry } from '@sapphire/framework'; -import { send } from '@sapphire/plugin-editable-commands'; -import { applyLocalizedBuilder, createLocalizedChoice, type TFunction } from '@sapphire/plugin-i18next'; -import { isNullish, isNullishOrEmpty, isNullishOrZero, type Awaitable } from '@sapphire/utilities'; -import { InteractionContextType, MessageFlags, PermissionFlagsBits, chatInputApplicationCommandMention, strikethrough, type Guild } from 'discord.js'; - -const Root = LanguageKeys.Commands.AutoModeration; -const RootModeration = LanguageKeys.Moderation; - -export abstract class AutoModerationCommand extends WolfSubcommand { - protected readonly resetKeys: readonly AutoModerationCommand.OptionsResetKey[]; - protected readonly adderPropertyName: AdderKey; - protected readonly keyEnabled: GuildSettingsOfType; - protected readonly keyOnInfraction: GuildSettingsOfType; - protected readonly keyPunishment: GuildSettingsOfType; - protected readonly keyPunishmentDuration: GuildSettingsOfType; - protected readonly keyPunishmentThreshold: GuildSettingsOfType; - protected readonly keyPunishmentThresholdPeriod: GuildSettingsOfType; - - readonly #localizedNameKey: TypedT; - - readonly #punishmentDurationMinimum: number; - readonly #punishmentDurationMaximum: number; - readonly #punishmentThresholdMinimum: number; - readonly #punishmentThresholdMaximum: number; - readonly #punishmentThresholdDurationMinimum: number; - readonly #punishmentThresholdDurationMaximum: number; - readonly #idHints: string[]; - - protected constructor(context: AutoModerationCommand.LoaderContext, options: AutoModerationCommand.Options) { - super(context, { - detailedDescription: LanguageKeys.Commands.Shared.SlashOnlyDetailedDescription, - permissionLevel: PermissionLevels.Administrator, - runIn: [CommandOptionsRunTypeEnum.GuildAny], - hidden: true, - ...options, - subcommands: [ - { name: 'show', chatInputRun: 'chatInputRunShow', messageRun: 'messageRunShow', default: true }, - { name: 'edit', chatInputRun: 'chatInputRunEdit', messageRun: 'messageRunEdit' }, - { name: 'reset', chatInputRun: 'chatInputRunReset', messageRun: 'messageRunReset' }, - ...(options.subcommands ?? []) - ] - }); - - this.resetKeys = options.resetKeys ?? []; - this.adderPropertyName = options.adderPropertyName; - this.keyEnabled = options.keyEnabled; - this.keyOnInfraction = options.keyOnInfraction; - this.keyPunishment = options.keyPunishment; - this.keyPunishmentDuration = options.keyPunishmentDuration; - this.keyPunishmentThreshold = options.keyPunishmentThreshold; - this.keyPunishmentThresholdPeriod = options.keyPunishmentThresholdPeriod; - this.#idHints = options.idHints ?? []; - - this.#localizedNameKey = options.localizedNameKey; - - const configurableKeys = getConfigurableKeys(); - const punishmentDuration = configurableKeys.get(this.keyPunishmentDuration)!; - this.#punishmentDurationMinimum = punishmentDuration.minimum!; - this.#punishmentDurationMaximum = punishmentDuration.maximum!; - - const punishmentThreshold = configurableKeys.get(this.keyPunishmentThresholdPeriod)!; - this.#punishmentThresholdMinimum = punishmentThreshold.minimum!; - this.#punishmentThresholdMaximum = punishmentThreshold.maximum!; - - const punishmentThresholdDuration = configurableKeys.get(this.keyPunishmentThresholdPeriod)!; - this.#punishmentThresholdDurationMinimum = punishmentThresholdDuration.minimum!; - this.#punishmentThresholdDurationMaximum = punishmentThresholdDuration.maximum!; - } - - public override registerApplicationCommands(registry: ApplicationCommandRegistry) { - registry.registerChatInputCommand( - (builder) => - this.registerSubcommands( - builder // - .setContexts(InteractionContextType.Guild) - .setDefaultMemberPermissions(PermissionFlagsBits.ManageGuild) - ), - { - idHints: this.#idHints - } - ); - } - - /** @deprecated */ - public messageRunShow(message: GuildMessage, args: WolfSubcommand.Args) { - const command = chatInputApplicationCommandMention(this.name, 'show', this.getGlobalCommandId()); - return send(message, args.t(LanguageKeys.Commands.Shared.DeprecatedMessage, { command })); - } - - /** @deprecated */ - public messageRunEdit(message: GuildMessage, args: WolfSubcommand.Args) { - const command = chatInputApplicationCommandMention(this.name, 'edit', this.getGlobalCommandId()); - return send(message, args.t(LanguageKeys.Commands.Shared.DeprecatedMessage, { command })); - } - - /** @deprecated */ - public messageRunReset(message: GuildMessage, args: WolfSubcommand.Args) { - const command = chatInputApplicationCommandMention(this.name, 'reset', this.getGlobalCommandId()); - return send(message, args.t(LanguageKeys.Commands.Shared.DeprecatedMessage, { command })); - } - - public async chatInputRunShow(interaction: AutoModerationCommand.Interaction) { - const settings = await readSettings(interaction.guild); - - const t = getSupportedUserLanguageT(interaction); - const embed = settings[this.keyEnabled] // - ? this.showEnabled(t, settings) - : this.showDisabled(t); - return interaction.reply({ embeds: [embed], flags: MessageFlags.Ephemeral }); - } - - public async chatInputRunEdit(interaction: AutoModerationCommand.Interaction) { - using trx = await writeSettingsTransaction(interaction.guild); - const settings = trx.settings; - - const valueEnabled = interaction.options.getBoolean('enabled'); - const valueOnInfraction = this.#getInfraction(interaction, settings[this.keyOnInfraction]); - const valuePunishment = interaction.options.getInteger('punishment'); - const valuePunishmentDuration = this.#getDuration( - interaction, - 'punishment-duration', - this.#punishmentDurationMinimum, - this.#punishmentDurationMaximum - ); - const valuePunishmentThreshold = interaction.options.getInteger('threshold'); - const valuePunishmentThresholdDuration = this.#getDuration( - interaction, - 'threshold-period', - this.#punishmentThresholdDurationMinimum, - this.#punishmentThresholdDurationMaximum - ); - - const pairs: [SchemaDataKey, GuildDataValue][] = []; - if (!isNullish(valueEnabled)) pairs.push([this.keyEnabled, valueEnabled]); - if (!isNullish(valueOnInfraction)) pairs.push([this.keyOnInfraction, valueOnInfraction]); - if (!isNullish(valuePunishment)) pairs.push([this.keyPunishment, valuePunishment]); - if (!isNullish(valuePunishmentDuration)) pairs.push([this.keyPunishmentDuration, valuePunishmentDuration]); - if (!isNullish(valuePunishmentThreshold)) pairs.push([this.keyPunishmentThreshold, valuePunishmentThreshold]); - if (!isNullish(valuePunishmentThresholdDuration)) pairs.push([this.keyPunishmentThresholdPeriod, valuePunishmentThresholdDuration]); - - await trx.write(Object.fromEntries(pairs) as Partial).submitWithAudit(interaction.user.id); - - const t = getSupportedUserLanguageT(interaction); - const content = t(Root.EditSuccess); - return interaction.reply({ content, flags: MessageFlags.Ephemeral }); - } - - public async chatInputRunReset(interaction: AutoModerationCommand.Interaction) { - const [key, value] = await this.resetGetKeyValuePair(interaction.guild, interaction.options.getString('key', true) as ResetKey); - using trx = await writeSettingsTransaction(interaction.guild); - await trx.write({ [key]: value } as Partial).submitWithAudit(interaction.user.id); - - const t = getSupportedUserLanguageT(interaction); - const content = t(Root.EditSuccess); - return interaction.reply({ content, flags: MessageFlags.Ephemeral }); - } - - protected async resetGetKeyValuePair(guild: Guild, key: ResetKey): Promise { - switch (key) { - case 'enabled': - return [this.keyEnabled, false]; - case 'alert': - return [this.keyOnInfraction, await this.resetGetOnInfractionFlags(guild, AutoModerationOnInfraction.flags.Alert)]; - case 'log': - return [this.keyOnInfraction, await this.resetGetOnInfractionFlags(guild, AutoModerationOnInfraction.flags.Log)]; - case 'delete': - return [this.keyOnInfraction, await this.resetGetOnInfractionFlags(guild, AutoModerationOnInfraction.flags.Delete)]; - case 'punishment': - return [this.keyPunishment, this.resetGetValue(this.keyPunishment)]; - case 'punishment-duration': - return [this.keyPunishmentDuration, this.resetGetValue(this.keyPunishmentDuration)]; - case 'threshold': - return [this.keyPunishmentThreshold, this.resetGetValue(this.keyPunishmentThreshold)]; - case 'threshold-duration': - return [this.keyPunishmentThresholdPeriod, this.resetGetValue(this.keyPunishmentThresholdPeriod)]; - default: - return this.resetGetKeyValuePairFallback(guild, key); - } - } - - protected resetGetKeyValuePairFallback(guild: Guild, key: string): Awaitable; - protected resetGetKeyValuePairFallback(): never { - throw new Error('Unreachable'); - } - - protected resetGetValue(key: Key): GuildData[Key] { - return getConfigurableKeys().get(key)!.default as GuildData[Key]; - } - - protected async resetGetOnInfractionFlags(guild: Guild, bit: number) { - const settings = await readSettings(guild); - const bitfield = settings[this.keyOnInfraction]; - return AutoModerationOnInfraction.difference(bitfield, bit); - } - - protected showDisabled(t: TFunction) { - return new EmbedBuilder() // - .setColor(Colors.Red) - .setTitle(t(Root.ShowDisabled)); - } - - protected showEnabled(t: TFunction, settings: ReadonlyGuildData) { - const embed = new EmbedBuilder() // - .setColor(Colors.Green) - .setTitle(t(Root.ShowEnabled)) - .setDescription(this.showEnabledOnInfraction(t, settings[this.keyOnInfraction])); - - const punishment = settings[this.keyPunishment]; - if (!isNullishOrZero(punishment)) { - embed.addFields({ - name: t(Root.ShowPunishmentTitle), - value: this.showEnabledOnPunishment( - t, - punishment, - settings[this.keyPunishmentDuration], - readSettingsAdder(settings, this.adderPropertyName) - ) - }); - } - - return embed; - } - - protected showEnabledOnInfraction(t: TFunction, value: number) { - const replyLine = AutoModerationOnInfraction.has(value, AutoModerationOnInfraction.flags.Alert) - ? t(Root.ShowReplyActive, { emoji: Emojis.Reply }) - : t(Root.ShowReplyInactive, { emoji: Emojis.ReplyInactive }); - const logLine = AutoModerationOnInfraction.has(value, AutoModerationOnInfraction.flags.Log) - ? t(Root.ShowLogActive, { emoji: Emojis.Flag }) - : t(Root.ShowLogInactive, { emoji: Emojis.FlagInactive }); - const deleteLine = AutoModerationOnInfraction.has(value, AutoModerationOnInfraction.flags.Delete) - ? t(Root.ShowDeleteActive, { emoji: Emojis.Delete }) - : t(Root.ShowDeleteInactive, { emoji: Emojis.DeleteInactive }); - - return `${replyLine}\n${logLine}\n${deleteLine}`; - } - - protected showEnabledOnPunishment( - t: TFunction, - punishment: AutoModerationPunishment, - punishmentDuration: bigint | number | null, - adder: Adder | null - ): string { - const { key, emoji } = this.showEnabledOnPunishmentNameKey(punishment); - const name = t(key); - let line: string; - if (isNullishOrZero(punishmentDuration)) { - line = t(Root.ShowPunishment, { name, emoji }); - // Add strikethrough if the punishment is a timeout and the duration is not set: - if (punishment === AutoModerationPunishment.Timeout) line = strikethrough(line); - } else { - line = t(Root.ShowPunishmentTemporary, { - name, - emoji, - duration: t(LanguageKeys.Globals.DurationValue, { value: Number(punishmentDuration) }) - }); - } - - return isNullish(adder) ? line : `${line}\n${this.showEnabledOnPunishmentThreshold(t, adder)}`; - } - - protected showEnabledOnPunishmentNameKey(punishment: AutoModerationPunishment) { - switch (punishment) { - case AutoModerationPunishment.Ban: - return { key: RootModeration.TypeBan, emoji: Emojis.Ban }; - case AutoModerationPunishment.Kick: - return { key: RootModeration.TypeKick, emoji: Emojis.Kick }; - case AutoModerationPunishment.Timeout: - return { key: RootModeration.TypeTimeout, emoji: Emojis.Timeout }; - case AutoModerationPunishment.Mute: - return { key: RootModeration.TypeMute, emoji: Emojis.Timeout }; - case AutoModerationPunishment.Softban: - return { key: RootModeration.TypeSoftban, emoji: Emojis.Softban }; - case AutoModerationPunishment.Warning: - return { key: RootModeration.TypeWarning, emoji: Emojis.Flag }; - case AutoModerationPunishment.None: - throw new Error('Unreachable'); - } - } - - protected showEnabledOnPunishmentThreshold(t: TFunction, adder: Adder): string { - return t(Root.ShowPunishmentThreshold, { - threshold: adder.maximum, - period: t(LanguageKeys.Globals.DurationValue, { value: adder.duration }), - emoji: Emojis.Bucket - }); - } - - /** - * Registers the subcommands to the builder, calling: - * - {@linkcode registerShowSubcommand} - * - {@linkcode registerEditSubcommand} - * - {@linkcode registerResetSubcommand} - * - * @param builder - The builder to register the subcommands to - * @returns The updated builder - */ - protected registerSubcommands(builder: SlashCommandBuilder) { - return applyLocalizedBuilder(builder, this.#localizedNameKey, this.description) - .addSubcommand((subcommand) => this.registerShowSubcommand(subcommand)) - .addSubcommand((subcommand) => this.registerEditSubcommand(subcommand)) - .addSubcommand((subcommand) => this.registerResetSubcommand(subcommand)); - } - - protected registerShowSubcommand(subcommand: SlashCommandSubcommandBuilder) { - return applyLocalizedBuilder(subcommand, Root.Show); - } - - protected registerEditSubcommand(subcommand: SlashCommandSubcommandBuilder) { - return applyLocalizedBuilder(subcommand, Root.Edit) // - .addBooleanOption((option) => applyLocalizedBuilder(option, Root.OptionsEnabled)) - .addBooleanOption((option) => applyLocalizedBuilder(option, Root.OptionsActionAlert)) - .addBooleanOption((option) => applyLocalizedBuilder(option, Root.OptionsActionLog)) - .addBooleanOption((option) => applyLocalizedBuilder(option, Root.OptionsActionDelete)) - .addIntegerOption((option) => - applyLocalizedBuilder(option, Root.OptionsPunishment) // - .setChoices( - createLocalizedChoice(RootModeration.TypeWarning, { value: AutoModerationPunishment.Warning }), - createLocalizedChoice(RootModeration.TypeTimeout, { value: AutoModerationPunishment.Timeout }), - createLocalizedChoice(RootModeration.TypeMute, { value: AutoModerationPunishment.Mute }), - createLocalizedChoice(RootModeration.TypeKick, { value: AutoModerationPunishment.Kick }), - createLocalizedChoice(RootModeration.TypeSoftban, { value: AutoModerationPunishment.Softban }), - createLocalizedChoice(RootModeration.TypeBan, { value: AutoModerationPunishment.Ban }) - ) - ) - .addStringOption((option) => applyLocalizedBuilder(option, Root.OptionsPunishmentDuration)) - .addIntegerOption((option) => - applyLocalizedBuilder(option, Root.OptionsThreshold) - .setMinValue(this.#punishmentThresholdMinimum) - .setMaxValue(this.#punishmentThresholdMaximum) - ) - .addStringOption((option) => applyLocalizedBuilder(option, Root.OptionsThresholdPeriod)); - } - - protected registerResetSubcommand(subcommand: SlashCommandSubcommandBuilder) { - const choices = [ - createLocalizedChoice(Root.OptionsKeyEnabled, { value: 'enabled' }), - createLocalizedChoice(Root.OptionsKeyActionAlert, { value: 'alert' }), - createLocalizedChoice(Root.OptionsKeyActionLog, { value: 'log' }), - createLocalizedChoice(Root.OptionsKeyActionDelete, { value: 'delete' }), - createLocalizedChoice(Root.OptionsKeyPunishment, { value: 'punishment' }), - createLocalizedChoice(Root.OptionsKeyPunishmentDuration, { value: 'punishment-duration' }), - createLocalizedChoice(Root.OptionsKeyThreshold, { value: 'threshold' }), - createLocalizedChoice(Root.OptionsKeyThresholdPeriod, { value: 'threshold-duration' }) - ]; - - for (const { key: name, value } of this.resetKeys) { - choices.push(createLocalizedChoice(name, { value })); - } - - return applyLocalizedBuilder(subcommand, Root.Reset).addStringOption((option) => - applyLocalizedBuilder(option, Root.OptionsKey) - .setChoices(...choices) - .setRequired(true) - ); - } - - #getInfraction(interaction: AutoModerationCommand.Interaction, existing: number) { - const actionAlert = interaction.options.getBoolean('alert'); - const actionLog = interaction.options.getBoolean('log'); - const actionDelete = interaction.options.getBoolean('delete'); - - const existingActionAlert = AutoModerationOnInfraction.has(existing, AutoModerationOnInfraction.flags.Alert); - const existingActionLog = AutoModerationOnInfraction.has(existing, AutoModerationOnInfraction.flags.Log); - const existingActionDelete = AutoModerationOnInfraction.has(existing, AutoModerationOnInfraction.flags.Delete); - - let bitfield = 0; - if (actionAlert ?? existingActionAlert) bitfield |= AutoModerationOnInfraction.flags.Alert; - if (actionLog ?? existingActionLog) bitfield |= AutoModerationOnInfraction.flags.Log; - if (actionDelete ?? existingActionDelete) bitfield |= AutoModerationOnInfraction.flags.Delete; - - return bitfield; - } - - #getDuration(interaction: AutoModerationCommand.Interaction, option: string, minimum: number, maximum: number) { - const parameter = interaction.options.getString(option); - if (isNullishOrEmpty(parameter)) return null; - - return resolveTimeSpan(parameter, { minimum, maximum }) // - .mapErr((key) => getSupportedUserLanguageT(interaction)(key, { parameter: parameter.toString() })) - .unwrapRaw(); - } -} - -type ResetKey = 'enabled' | 'alert' | 'log' | 'delete' | 'punishment' | 'punishment-duration' | 'threshold' | 'threshold-duration'; - -export namespace AutoModerationCommand { - export type LoaderContext = WolfSubcommand.LoaderContext; - - /** - * The AutoModerationCommand Options - */ - export interface Options extends Omit { - localizedNameKey: TypedT; - adderPropertyName: AdderKey; - keyEnabled: GuildSettingsOfType; - keyOnInfraction: GuildSettingsOfType; - keyPunishment: GuildSettingsOfType; - keyPunishmentDuration: GuildSettingsOfType; - keyPunishmentThreshold: GuildSettingsOfType; - keyPunishmentThresholdPeriod: GuildSettingsOfType; - resetKeys?: readonly OptionsResetKey[]; - idHints?: string[]; - } - - export interface OptionsResetKey { - key: TypedT; - value: string; - } - - export type Interaction = WolfSubcommand.Interaction; -} diff --git a/src/lib/moderation/structures/AutoModerationOnInfraction.ts b/src/lib/moderation/structures/AutoModerationOnInfraction.ts deleted file mode 100644 index 0224f6174..000000000 --- a/src/lib/moderation/structures/AutoModerationOnInfraction.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { BitField } from '@sapphire/bitfield'; - -export const AutoModerationOnInfraction = new BitField({ - Delete: 1 << 0, - Log: 1 << 1, - Alert: 1 << 2 -}); - -export enum AutoModerationPunishment { - None, - Warning, - Kick, - Mute, - Softban, - Ban, - Timeout -} diff --git a/src/lib/moderation/structures/ModerationCommand.ts b/src/lib/moderation/structures/ModerationCommand.ts deleted file mode 100644 index 9eee6f6b7..000000000 --- a/src/lib/moderation/structures/ModerationCommand.ts +++ /dev/null @@ -1,404 +0,0 @@ -import { readSettings } from '#lib/database'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { getAction, type ActionByType, type GetContextType } from '#lib/moderation/actions'; -import type { ModerationAction } from '#lib/moderation/actions/base/ModerationAction'; -import type { ModerationManager } from '#lib/moderation/managers/ModerationManager'; -import { WolfCommand } from '#lib/structures/commands/WolfCommand'; -import { PermissionLevels, type GuildMessage, type TypedT } from '#lib/types'; -import { asc, floatPromise, seconds } from '#utils/common'; -import { deleteMessage, isGuildOwner } from '#utils/functions'; -import type { TypeVariation } from '#utils/moderationConstants'; -import { getImage, getTag, isUserSelf } from '#utils/util'; -import { Args, CommandOptionsRunTypeEnum, type Awaitable } from '@sapphire/framework'; -import { free, send } from '@sapphire/plugin-editable-commands'; -import type { User } from 'discord.js'; - -const Root = LanguageKeys.Moderation; - -export abstract class ModerationCommand extends WolfCommand { - /** - * The moderation action this command applies. - */ - protected readonly action: ActionByType; - - /** - * Whether this command executes an undo action. - */ - protected readonly isUndoAction: boolean; - - /** - * The key for the action is active language key. - */ - protected readonly actionStatusKey: TypedT; - - /** - * Whether this command supports schedules. - */ - protected readonly supportsSchedule: boolean; - - /** - * The minimum duration for this command. - */ - protected readonly minimumDuration: number; - - /** - * The maximum duration for this command. - */ - protected readonly maximumDuration: number; - - /** - * Whether a member is required or not. - */ - protected readonly requiredMember: boolean; - - /** - * Whether a duration is required or not. - */ - protected readonly requiredDuration: boolean; - - protected constructor(context: ModerationCommand.LoaderContext, options: ModerationCommand.Options) { - super(context, { - cooldownDelay: seconds(5), - flags: ['no-author', 'authored', 'no-dm', 'dm'], - permissionLevel: PermissionLevels.Moderator, - requiredMember: false, - runIn: [CommandOptionsRunTypeEnum.GuildAny], - ...options - }); - - this.action = getAction(options.type); - this.isUndoAction = options.isUndoAction ?? false; - this.actionStatusKey = options.actionStatusKey ?? (this.isUndoAction ? Root.ActionIsNotActive : Root.ActionIsActive); - this.supportsSchedule = this.action.isUndoActionAvailable && !this.isUndoAction; - this.minimumDuration = this.action.minimumDuration; - this.maximumDuration = this.action.maximumDuration; - this.requiredMember = options.requiredMember ?? false; - this.requiredDuration = this.action.durationRequired && !this.isUndoAction; - } - - public override messageRun( - message: GuildMessage, - args: ModerationCommand.Args, - context: ModerationCommand.RunContext - ): Promise; - - public override async messageRun(message: GuildMessage, args: ModerationCommand.Args) { - const resolved = await this.resolveParameters(args); - const preHandled = await this.preHandle(message, resolved); - const processed = [] as Array<{ log: ModerationManager.Entry; target: User }>; - const errored = [] as Array<{ error: Error | string; target: User }>; - - const settings = await readSettings(message.guild); - - const { targets, ...handledRaw } = resolved; - for (const target of new Set(targets)) { - try { - const handled = { ...handledRaw, args, target, preHandled }; - await this.checkTargetCanBeModerated(message, handled); - const log = await this.handle(message, handled); - processed.push({ log, target }); - } catch (error) { - errored.push({ error: error as Error | string, target }); - } - } - - try { - await this.postHandle(message, { ...resolved, preHandled }); - } catch { - // noop - } - - // If the server was configured to automatically delete messages, delete the command and return null. - const shouldAutoDelete = settings.messagesModerationAutoDelete; - if (shouldAutoDelete) { - if (message.deletable) floatPromise(deleteMessage(message)); - } - - if (settings.messagesModerationMessageDisplay) { - const output: string[] = []; - if (processed.length) { - const reason = settings.messagesModerationReasonDisplay ? processed[0].log.reason! : null; - const sorted = processed.sort((a, b) => asc(a.log.id, b.log.id)); - const cases = sorted.map(({ log }) => log.id); - const users = sorted.map(({ target }) => `\`${getTag(target)}\``); - const range = cases.length === 1 ? cases[0] : `${cases[0]}..${cases[cases.length - 1]}`; - const key = reason // - ? LanguageKeys.Commands.Moderation.ModerationOutputWithReason - : LanguageKeys.Commands.Moderation.ModerationOutput; - output.push(args.t(key, { count: cases.length, range, users, reason })); - } - - if (errored.length) { - const users = errored.map(({ error, target }) => `- ${getTag(target)} → ${typeof error === 'string' ? error : error.message}`); - output.push(args.t(LanguageKeys.Commands.Moderation.ModerationFailed, { users: users.join('\n'), count: users.length })); - } - - // Else send the message as usual. - const content = output.join('\n'); - const response = await send(message, content); - - // If the server was configured to automatically delete messages, untrack the editable message so it doesn't - // get automatically deleted in the event of race-conditions. `send` + `free` is used over - // `message.channel.send` so it can edit any existing response. - if (shouldAutoDelete) { - free(message); - } - - return response; - } - - return null; - } - - /** - * Handles an action before taking the moderation action. - * - * @param message - The message that triggered the command. - * @param context - The context for the moderation command, shared for all targets. - * @returns The value that will be set in {@linkcode ModerationCommand.HandlerParameters.preHandled}. - */ - protected preHandle(message: GuildMessage, context: ModerationCommand.Parameters): Awaitable; - protected preHandle() { - return null as ValueType; - } - - /** - * Handles the moderation action. - * - * @param message - The message that triggered the command. - * @param context - The context for the moderation command, for a single target. - */ - protected handle( - message: GuildMessage, - context: ModerationCommand.HandlerParameters - ): Promise | ModerationManager.Entry; - - protected async handle(message: GuildMessage, context: ModerationCommand.HandlerParameters) { - const dataContext = this.getHandleDataContext(message, context); - - const options = this.resolveOptions(message, context); - const data = await this.getActionData(message, context.args, context.target, dataContext); - const isActive = await this.isActionActive(message, context, dataContext); - - if (this.isUndoAction) { - // If this command is an undo action, and the action is not active, throw an error. - if (!isActive) { - throw context.args.t(this.getActionStatusKey(context)); - } - - // @ts-expect-error mismatching types due to unions - return this.action.undo(message.guild, options, data); - } - - // If this command is not an undo action, and the action is active, throw an error. - if (isActive) { - throw context.args.t(this.getActionStatusKey(context)); - } - - // @ts-expect-error mismatching types due to unions - return this.action.apply(message.guild, options, data); - } - - /** - * Gets the data context required for some actions, if any. - * - * @param message - The message that triggered the command. - * @param context - The context for the moderation command, for a single target. - */ - protected getHandleDataContext(message: GuildMessage, context: ModerationCommand.HandlerParameters): GetContextType; - protected getHandleDataContext(): GetContextType { - return null as GetContextType; - } - - /** - * Checks if the action is active. - * - * @param message - The message that triggered the command. - * @param context - The context for the moderation command, for a single target. - * @param dataContext - The data context required for some actions, if any. - * @returns - */ - protected isActionActive( - message: GuildMessage, - context: ModerationCommand.HandlerParameters, - dataContext: GetContextType - ): Awaitable { - return this.action.isActive(message.guild, context.target.id, dataContext as never); - } - - /** - * Gets the key for the action status language key. - * - * @remarks - * - * Unless overridden, this method just returns the value of {@linkcode ModerationCommand.actionStatusKey}. - * - * @param context - The context for the moderation command, for a single target. - */ - protected getActionStatusKey(context: ModerationCommand.HandlerParameters): TypedT; - protected getActionStatusKey(): TypedT { - return this.actionStatusKey; - } - - /** - * Handles an action after taking the moderation action. - * - * @param message - The message that triggered the command. - * @param context - The context for the moderation command, shared for all targets. - */ - protected postHandle(message: GuildMessage, context: ModerationCommand.PostHandleParameters): unknown; - protected postHandle() { - return null; - } - - protected async checkTargetCanBeModerated(message: GuildMessage, context: ModerationCommand.HandlerParameters) { - if (context.target.id === message.author.id) { - throw context.args.t(Root.ActionTargetSelf); - } - - if (context.target.id === message.guild.ownerId) { - throw context.args.t(Root.ActionTargetGuildOwner); - } - - if (isUserSelf(context.target.id)) { - throw context.args.t(Root.ActionTargetWolf); - } - - const member = await message.guild.members.fetch(context.target.id).catch(() => { - if (this.requiredMember) throw context.args.t(LanguageKeys.Misc.UserNotInGuild); - return null; - }); - - if (member) { - const targetHighestRolePosition = member.roles.highest.position; - - // Wolf cannot moderate members with higher role position than her: - const me = await message.guild.members.fetchMe(); - if (targetHighestRolePosition >= me.roles.highest.position) { - throw context.args.t(Root.ActionTargetHigherHierarchyWolf); - } - - // A member who isn't a server owner is not allowed to moderate somebody with higher role than them: - if (!isGuildOwner(message.member) && targetHighestRolePosition >= message.member.roles.highest.position) { - throw context.args.t(Root.ActionTargetHigherHierarchyAuthor); - } - } - - return member; - } - - protected async getActionData( - message: GuildMessage, - args: Args, - target: User, - context?: GetContextType - ): Promise>> { - const settings = await readSettings(message.guild); - return { - moderator: args.getFlags('no-author') ? null : args.getFlags('authored') || settings.messagesModeratorNameDisplay ? message.author : null, - sendDirectMessage: - // --no-dm disables - !args.getFlags('no-dm') && - // --dm and enabledDM enable - (args.getFlags('dm') || settings.messagesModerationDm) && - // user settings - (await this.container.prisma.user.fetchModerationDirectMessageEnabled(target.id)), - context - }; - } - - protected resolveOptions(message: GuildMessage, context: ModerationCommand.HandlerParameters): ModerationAction.PartialOptions { - return { - user: context.target, - moderator: message.author, - reason: context.reason, - imageURL: getImage(message), - duration: context.duration - }; - } - - /** - * Resolves the overloads for the moderation command. - * - * @param args - The arguments for the moderation command. - * @returns A promise that resolves to a CommandContext object containing the resolved targets, duration, and reason. - */ - protected async resolveParameters(args: ModerationCommand.Args): Promise { - return { - targets: await this.resolveParametersUser(args), - duration: await this.resolveParametersDuration(args), - reason: await this.resolveParametersReason(args) - }; - } - - /** - * Resolves the value for {@linkcode Parameters.targets}. - * - * @param args - The arguments for the moderation command. - */ - protected resolveParametersUser(args: ModerationCommand.Args): Promise { - return args.repeat('user', { times: 10 }); - } - - /** - * Resolves the value for {@linkcode Parameters.duration}. - * - * @param args - The arguments for the moderation command. - */ - protected async resolveParametersDuration(args: ModerationCommand.Args) { - if (!this.requiredDuration) { - if (args.finished) return null; - if (!this.supportsSchedule) return null; - } - - const result = await args.pickResult('timespan', { minimum: this.minimumDuration, maximum: this.maximumDuration }); - return result.match({ - ok: (value) => value, - err: (error) => { - if (!this.requiredDuration && error.identifier === LanguageKeys.Arguments.TimeSpan) return null; - throw error; - } - }); - } - - /** - * Resolves the value for {@linkcode Parameters.reason}. - * - * @param args - The arguments for the moderation command. - */ - protected resolveParametersReason(args: ModerationCommand.Args): Promise { - return args.finished ? Promise.resolve(null) : args.rest('string'); - } -} - -export namespace ModerationCommand { - /** - * The ModerationCommand Options - */ - export interface Options extends WolfCommand.Options { - type: Type; - isUndoAction?: boolean; - actionStatusKey?: TypedT; - requiredMember?: boolean; - } - - export type Args = WolfCommand.Args; - export type LoaderContext = WolfCommand.LoaderContext; - export type RunContext = WolfCommand.RunContext; - - export interface Parameters { - targets: User[]; - duration: number | null; - reason: string | null; - } - - export interface HandlerParameters extends Omit { - args: Args; - target: User; - preHandled: ValueType; - } - - export interface PostHandleParameters extends Parameters { - preHandled: ValueType; - } -} diff --git a/src/lib/moderation/structures/ModerationListener.ts b/src/lib/moderation/structures/ModerationListener.ts deleted file mode 100644 index 5b2d34c0d..000000000 --- a/src/lib/moderation/structures/ModerationListener.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { readSettings, type GuildSettingsOfType } from '#lib/database'; -import { ModerationActions } from '#lib/moderation/actions/index'; -import { AutoModerationOnInfraction, AutoModerationPunishment } from '#lib/moderation/structures/AutoModerationOnInfraction'; -import type { HardPunishment } from '#lib/moderation/structures/ModerationMessageListener'; -import { days, seconds } from '#utils/common'; -import { getModeration } from '#utils/functions'; -import type { EmbedBuilder } from '@discordjs/builders'; -import { Listener, type Awaitable } from '@sapphire/framework'; -import { isNullishOrZero } from '@sapphire/utilities'; -import type { Guild } from 'discord.js'; - -export abstract class ModerationListener extends Listener { - public abstract override run(...params: V): unknown; - - protected processSoftPunishment(args: Readonly, preProcessed: T, bitfield: number) { - if (AutoModerationOnInfraction.has(bitfield, AutoModerationOnInfraction.flags.Delete)) this.onDelete(args, preProcessed); - if (AutoModerationOnInfraction.has(bitfield, AutoModerationOnInfraction.flags.Alert)) this.onAlert(args, preProcessed); - if (AutoModerationOnInfraction.has(bitfield, AutoModerationOnInfraction.flags.Log)) this.onLog(args, preProcessed); - } - - protected async processHardPunishment(guild: Guild, userId: string, action: AutoModerationPunishment) { - switch (action) { - case AutoModerationPunishment.Warning: - await this.onWarning(guild, userId); - break; - case AutoModerationPunishment.Kick: - await this.onKick(guild, userId); - break; - case AutoModerationPunishment.Timeout: - await this.onTimeout(guild, userId); - break; - case AutoModerationPunishment.Mute: - await this.onMute(guild, userId); - break; - case AutoModerationPunishment.Softban: - await this.onSoftBan(guild, userId); - break; - case AutoModerationPunishment.Ban: - await this.onBan(guild, userId); - break; - case AutoModerationPunishment.None: - break; - } - } - - protected async onWarning(guild: Guild, userId: string) { - const duration = await this.#getPunishmentActionDuration(guild); - await this.createActionAndSend(guild, () => - ModerationActions.warning.apply(guild, { user: userId, reason: '[Auto-Moderation] Threshold Reached.', duration }) - ); - } - - protected async onKick(guild: Guild, userId: string) { - await this.createActionAndSend(guild, () => - ModerationActions.kick.apply(guild, { user: userId, reason: '[Auto-Moderation] Threshold Reached.' }) - ); - } - - protected async onTimeout(guild: Guild, userId: string) { - const duration = await this.#getPunishmentActionDuration(guild); - if (isNullishOrZero(duration)) return; - - await this.createActionAndSend(guild, () => - ModerationActions.timeout.apply(guild, { - user: userId, - reason: '[Auto-Moderation] Threshold Reached.', - duration: Math.min(Number(duration), days(28)) - }) - ); - } - - protected async onMute(guild: Guild, userId: string) { - const duration = await this.#getPunishmentActionDuration(guild); - await this.createActionAndSend(guild, () => - ModerationActions.mute.apply(guild, { user: userId, reason: '[Auto-Moderation] Threshold Reached.', duration }) - ); - } - - protected async onSoftBan(guild: Guild, userId: string) { - await this.createActionAndSend(guild, () => - ModerationActions.softban.apply( - guild, - { user: userId, reason: '[Auto-Moderation] Threshold Reached.' }, - { context: seconds.fromMinutes(5) } - ) - ); - } - - protected async onBan(guild: Guild, userId: string) { - const duration = await this.#getPunishmentActionDuration(guild); - await this.createActionAndSend(guild, () => - ModerationActions.ban.apply(guild, { user: userId, reason: '[Auto-Moderation] Threshold Reached.', duration }) - ); - } - - protected async createActionAndSend(guild: Guild, performAction: () => unknown): Promise { - const unlock = getModeration(guild).createLock(); - await performAction(); - unlock(); - } - - protected abstract keyEnabled: GuildSettingsOfType; - protected abstract softPunishmentPath: GuildSettingsOfType; - protected abstract hardPunishmentPath: HardPunishment; - protected abstract preProcess(args: Readonly): Awaitable; - protected abstract onLog(args: Readonly, value: T): unknown; - protected abstract onDelete(args: Readonly, value: T): unknown; - protected abstract onAlert(args: Readonly, value: T): unknown; - protected abstract onLogMessage(args: Readonly, value: T): Awaitable; - - async #getPunishmentActionDuration(guild: Guild) { - const settings = await readSettings(guild); - return settings[this.hardPunishmentPath.actionDuration]; - } -} - -export namespace ModerationListener { - export type Options = Listener.Options; - export type JSON = Listener.JSON; - export type LoaderContext = Listener.LoaderContext; -} diff --git a/src/lib/moderation/structures/ModerationMessageListener.ts b/src/lib/moderation/structures/ModerationMessageListener.ts deleted file mode 100644 index d603c4e3f..000000000 --- a/src/lib/moderation/structures/ModerationMessageListener.ts +++ /dev/null @@ -1,216 +0,0 @@ -import { readSettings, readSettingsAdder, type AdderKey, type GuildSettingsOfType, type ReadonlyGuildData } from '#lib/database'; -import type { AdderError } from '#lib/database/utils/Adder'; -import { getT } from '#lib/i18n'; -import { ModerationActions } from '#lib/moderation/actions/index'; -import { AutoModerationOnInfraction, AutoModerationPunishment } from '#lib/moderation/structures/AutoModerationOnInfraction'; -import { Events, type GuildMessage, type TypedFT, type TypedT } from '#lib/types'; -import { floatPromise, seconds } from '#utils/common'; -import { getModeration, isModerator } from '#utils/functions'; -import { EmbedBuilder } from '@discordjs/builders'; -import { canSendMessages, type GuildTextBasedChannelTypes } from '@sapphire/discord.js-utilities'; -import { Listener } from '@sapphire/framework'; -import type { TFunction } from '@sapphire/plugin-i18next'; -import { isNullishOrZero, type Awaitable, type Nullish } from '@sapphire/utilities'; -import type { GuildMember } from 'discord.js'; - -export abstract class ModerationMessageListener extends Listener { - private readonly keyEnabled: GuildSettingsOfType; - private readonly ignoredRolesPath: GuildSettingsOfType; - private readonly ignoredChannelsPath: GuildSettingsOfType; - private readonly softPunishmentPath: GuildSettingsOfType; - private readonly hardPunishmentPath: HardPunishment; - private readonly reasonLanguageKey: TypedT; - private readonly reasonLanguageKeyWithMaximum: TypedFT<{ amount: number; maximum: number }, string>; - - public constructor(context: ModerationMessageListener.LoaderContext, options: ModerationMessageListener.Options) { - super(context, { ...options, event: Events.GuildUserMessage }); - - this.keyEnabled = options.keyEnabled; - this.ignoredRolesPath = options.ignoredRolesPath; - this.ignoredChannelsPath = options.ignoredChannelsPath; - this.softPunishmentPath = options.softPunishmentPath; - this.hardPunishmentPath = options.hardPunishmentPath; - this.reasonLanguageKey = options.reasonLanguageKey; - this.reasonLanguageKeyWithMaximum = options.reasonLanguageKeyWithMaximum; - } - - public async run(message: GuildMessage) { - const shouldRun = await this.checkPreRun(message); - if (!shouldRun) return; - - if (await isModerator(message.member)) return; - - const preProcessed = await this.preProcess(message); - if (preProcessed === null) return; - - const settings = await readSettings(message.guild); - - const logChannelId = settings.channelsLogsModeration; - const filter = settings[this.softPunishmentPath]; - const t = getT(settings.language); - this.processSoftPunishment(message, logChannelId, t, filter, preProcessed); - - if (this.hardPunishmentPath === null) return; - - const adder = readSettingsAdder(settings, this.hardPunishmentPath.adder); - if (!adder) return this.processHardPunishment(message, t, 0, 0); - - const points = typeof preProcessed === 'number' ? preProcessed : 1; - try { - adder.add(message.author.id, points); - } catch (error) { - await this.processHardPunishment(message, t, (error as AdderError).amount, adder.maximum); - } - } - - protected processSoftPunishment(message: GuildMessage, logChannelId: string | Nullish, language: TFunction, bitfield: number, preProcessed: T) { - if (AutoModerationOnInfraction.has(bitfield, AutoModerationOnInfraction.flags.Delete) && message.deletable) { - floatPromise(this.onDelete(message, language, preProcessed) as any); - } - - if (AutoModerationOnInfraction.has(bitfield, AutoModerationOnInfraction.flags.Alert) && canSendMessages(message.channel)) { - floatPromise(this.onAlert(message, language, preProcessed) as any); - } - - if (AutoModerationOnInfraction.has(bitfield, AutoModerationOnInfraction.flags.Log)) { - floatPromise(this.onLog(message, logChannelId, language, preProcessed) as any); - } - } - - protected async processHardPunishment(message: GuildMessage, language: TFunction, points: number, maximum: number) { - const settings = await readSettings(message.guild); - const action = settings[this.hardPunishmentPath.action]; - const duration = settings[this.hardPunishmentPath.actionDuration]; - switch (action) { - case AutoModerationPunishment.Warning: - await this.onWarning(message, language, points, maximum, duration); - break; - case AutoModerationPunishment.Kick: - await this.onKick(message, language, points, maximum); - break; - case AutoModerationPunishment.Timeout: - await this.onTimeout(message, language, points, maximum, duration); - break; - case AutoModerationPunishment.Mute: - await this.onMute(message, language, points, maximum, duration); - break; - case AutoModerationPunishment.Softban: - await this.onSoftBan(message, language, points, maximum); - break; - case AutoModerationPunishment.Ban: - await this.onBan(message, language, points, maximum, duration); - break; - } - } - - protected async onWarning(message: GuildMessage, t: TFunction, points: number, maximum: number, duration: bigint | null) { - await this.createActionAndSend(message, () => - ModerationActions.warning.apply(message.guild, { user: message.author, reason: this.#getReason(t, points, maximum), duration }) - ); - } - - protected async onKick(message: GuildMessage, t: TFunction, points: number, maximum: number) { - await this.createActionAndSend(message, () => - ModerationActions.kick.apply(message.guild, { user: message.author, reason: this.#getReason(t, points, maximum) }) - ); - } - - protected async onTimeout(message: GuildMessage, t: TFunction, points: number, maximum: number, duration: bigint | null) { - if (isNullishOrZero(duration)) return; - await this.createActionAndSend(message, () => - ModerationActions.timeout.apply(message.guild, { user: message.author, reason: this.#getReason(t, points, maximum), duration }) - ); - } - - protected async onMute(message: GuildMessage, t: TFunction, points: number, maximum: number, duration: bigint | null) { - await this.createActionAndSend(message, () => - ModerationActions.mute.apply(message.guild, { user: message.author, reason: this.#getReason(t, points, maximum), duration }) - ); - } - - protected async onSoftBan(message: GuildMessage, t: TFunction, points: number, maximum: number) { - await this.createActionAndSend(message, () => - ModerationActions.softban.apply( - message.guild, - { user: message.author, reason: this.#getReason(t, points, maximum) }, - { context: seconds.fromMinutes(5) } - ) - ); - } - - protected async onBan(message: GuildMessage, t: TFunction, points: number, maximum: number, duration: bigint | number | null) { - await this.createActionAndSend(message, () => - ModerationActions.ban.apply(message.guild, { user: message.author, reason: this.#getReason(t, points, maximum), duration }) - ); - } - - protected async createActionAndSend(message: GuildMessage, performAction: () => unknown): Promise { - const unlock = getModeration(message.guild).createLock(); - await performAction(); - unlock(); - } - - protected onLog(message: GuildMessage, logChannelId: string | Nullish, language: TFunction, value: T): Awaitable { - this.container.client.emit( - Events.GuildMessageLog, - message.guild, - logChannelId, - 'channelsLogsModeration', - this.onLogMessage.bind(this, message, language, value) - ); - } - - protected abstract preProcess(message: GuildMessage): Promise | T | null; - protected abstract onDelete(message: GuildMessage, language: TFunction, value: T): Awaitable; - protected abstract onAlert(message: GuildMessage, language: TFunction, value: T): Awaitable; - protected abstract onLogMessage(message: GuildMessage, language: TFunction, value: T): Awaitable; - - private async checkPreRun(message: GuildMessage) { - const settings = await readSettings(message.guild); - return settings[this.keyEnabled] && this.checkMessageChannel(settings, message.channel) && this.checkMemberRoles(settings, message.member); - } - - private checkMessageChannel(settings: ReadonlyGuildData, channel: GuildTextBasedChannelTypes) { - const globalIgnore = settings.selfmodIgnoredChannels; - if (globalIgnore.includes(channel.id)) return false; - - const localIgnore = settings[this.ignoredChannelsPath] as readonly string[]; - if (localIgnore.includes(channel.id)) return false; - - return true; - } - - private checkMemberRoles(settings: ReadonlyGuildData, member: GuildMember | null) { - if (member === null) return false; - - const ignoredRoles = settings[this.ignoredRolesPath]; - if (ignoredRoles.length === 0) return true; - - const { roles } = member; - return !ignoredRoles.some((id) => roles.cache.has(id)); - } - - #getReason(t: TFunction, points: number, maximum: number) { - return maximum === 0 ? t(this.reasonLanguageKey) : t(this.reasonLanguageKeyWithMaximum, { amount: points, maximum }); - } -} - -export interface HardPunishment { - action: GuildSettingsOfType; - actionDuration: GuildSettingsOfType; - adder: AdderKey; -} - -export namespace ModerationMessageListener { - export interface Options extends Listener.Options { - keyEnabled: GuildSettingsOfType; - ignoredRolesPath: GuildSettingsOfType; - ignoredChannelsPath: GuildSettingsOfType; - softPunishmentPath: GuildSettingsOfType; - hardPunishmentPath: HardPunishment; - reasonLanguageKey: TypedT; - reasonLanguageKeyWithMaximum: TypedFT<{ amount: number; maximum: number }, string>; - } - export type JSON = Listener.JSON; - export type LoaderContext = Listener.LoaderContext; -} diff --git a/src/lib/moderation/structures/SetUpModerationCommand.ts b/src/lib/moderation/structures/SetUpModerationCommand.ts deleted file mode 100644 index ed2eff122..000000000 --- a/src/lib/moderation/structures/SetUpModerationCommand.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { readSettings, writeSettingsTransaction } from '#lib/database'; -import { getT } from '#lib/i18n'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import type { RoleTypeVariation } from '#lib/moderation'; -import { ModerationCommand } from '#lib/moderation/structures/ModerationCommand'; -import type { GuildMessage } from '#lib/types'; -import { isAdmin, promptConfirmation, promptForMessage } from '#utils/functions'; -import type { Argument } from '@sapphire/framework'; -import { send } from '@sapphire/plugin-editable-commands'; -import { PermissionFlagsBits, type Role } from 'discord.js'; - -export abstract class SetUpModerationCommand extends ModerationCommand { - public constructor(context: ModerationCommand.LoaderContext, options: SetUpModerationCommand.Options) { - super(context, { - requiredClientPermissions: [PermissionFlagsBits.ManageRoles], - requiredMember: true, - actionStatusKey: options.isUndoAction - ? LanguageKeys.Moderation.ActionIsNotActiveRestrictionRole - : LanguageKeys.Moderation.ActionIsActiveRestrictionRole, - ...options - }); - } - - private get role() { - return this.container.stores.get('arguments').get('role') as Argument; - } - - public override async messageRun( - message: GuildMessage, - args: ModerationCommand.Args, - context: ModerationCommand.RunContext - ): Promise { - await this.inhibit(message, args, context); - return super.messageRun(message, args, context); - } - - protected async inhibit(message: GuildMessage, args: ModerationCommand.Args, context: ModerationCommand.RunContext) { - // If the command messageRun is not this one (potentially help command) or the guild is null, return with no error. - const settings = await readSettings(message.guild); - const roleId = settings[this.action.roleKey]; - - // Verify for role existence. - const role = (roleId && message.guild.roles.cache.get(roleId)) ?? null; - if (role) return undefined; - - // If there - if (!(await isAdmin(message.member))) { - this.error(LanguageKeys.Commands.Moderation.RestrictLowlevel); - } - - const t = getT(settings.language); - if (await promptConfirmation(message, t(LanguageKeys.Commands.Moderation.ActionSharedRoleSetupExisting))) { - const role = (await this.askForRole(message, args, context)).unwrapRaw(); - using trx = await writeSettingsTransaction(message.guild); - await trx.write({ [this.action.roleKey]: role.id } as any).submitWithAudit(message.author.id); - } else if (await promptConfirmation(message, t(LanguageKeys.Commands.Moderation.ActionSharedRoleSetupNew))) { - await this.action.setup(message); - - const content = t(LanguageKeys.Commands.Moderation.Success); - await send(message, content); - } else { - this.error(LanguageKeys.Commands.Management.CommandHandlerAborted); - } - - return undefined; - } - - protected async askForRole(message: GuildMessage, args: SetUpModerationCommand.Args, context: SetUpModerationCommand.RunContext) { - const result = await promptForMessage(message, args.t(LanguageKeys.Commands.Moderation.ActionSharedRoleSetupExistingName)); - if (result === null) this.error(LanguageKeys.Commands.Moderation.ActionSharedRoleSetupNoMessage); - - const argument = this.role; - return argument.run(result, { args, argument, command: this, commandContext: context, message }); - } -} - -export namespace SetUpModerationCommand { - export type Options = ModerationCommand.Options; - - export type Args = ModerationCommand.Args; - export type LoaderContext = ModerationCommand.LoaderContext; - export type RunContext = ModerationCommand.RunContext; - - export type Parameters = ModerationCommand.Parameters; - export type HandlerParameters = ModerationCommand.HandlerParameters; - export type PostHandleParameters = ModerationCommand.PostHandleParameters; -} diff --git a/src/lib/moderation/structures/index.ts b/src/lib/moderation/structures/index.ts deleted file mode 100644 index 9ea26a691..000000000 --- a/src/lib/moderation/structures/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -export * from '#lib/moderation/structures/AutoModerationCommand'; -export * from '#lib/moderation/structures/AutoModerationOnInfraction'; -export * from '#lib/moderation/structures/ModerationCommand'; -export * from '#lib/moderation/structures/ModerationListener'; -export * from '#lib/moderation/structures/ModerationMessageListener'; -export * from '#lib/moderation/structures/ModerationTask'; -export * from '#lib/moderation/structures/SetUpModerationCommand'; diff --git a/src/lib/moderation/workers/index.ts b/src/lib/moderation/workers/index.ts deleted file mode 100644 index 86d29664f..000000000 --- a/src/lib/moderation/workers/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from '#lib/moderation/workers/WorkerHandler'; -export * from '#lib/moderation/workers/WorkerManager'; -export * from '#lib/moderation/workers/WorkerResponseHandler'; -export * from '#lib/moderation/workers/errors/TimeoutError'; -export * from '#lib/moderation/workers/types'; diff --git a/src/lib/schedule/index.ts b/src/lib/schedule/index.ts deleted file mode 100644 index a01402eba..000000000 --- a/src/lib/schedule/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from '#lib/schedule/manager/ScheduleEntry'; -export * from '#lib/schedule/manager/ScheduleManager'; -export * from '#lib/schedule/structures/Task'; -export * from '#lib/schedule/structures/TaskStore'; diff --git a/src/lib/schedule/manager/ScheduleEntry.ts b/src/lib/schedule/manager/ScheduleEntry.ts deleted file mode 100644 index f89ffadcf..000000000 --- a/src/lib/schedule/manager/ScheduleEntry.ts +++ /dev/null @@ -1,168 +0,0 @@ -import type { ModerationManagerEntry } from '#lib/moderation'; -import { Events } from '#lib/types/Enums'; -import type { TypeVariation } from '#utils/moderationConstants'; -import type { Schedule } from '#generated/prisma'; -import { container } from '@sapphire/framework'; -import { Cron } from '@sapphire/time-utilities'; -import { isNullishOrEmpty } from '@sapphire/utilities'; - -export class ScheduleEntry { - public id: number; - public taskId: string; - public time!: Date; - public recurring!: Cron | null; - public catchUp!: boolean; - public data!: ScheduleEntry.TaskData[Type]; - - /** - * Whether or not the entity is running - */ - #running = false; - - /** - * Whether or not the entity is paused - */ - #paused = false; - - public constructor(data: Schedule) { - this.id = data.id; - this.taskId = data.taskId; - this.#patch(data); - } - - public get task() { - return container.stores.get('tasks').get(this.taskId) ?? null; - } - - public get running(): boolean { - return this.#running; - } - - public resume() { - this.#paused = false; - return this; - } - - public pause() { - this.#paused = true; - return this; - } - - public reschedule(time: Date | number) { - return container.schedule.reschedule(this, time); - } - - public delete() { - return container.schedule.remove(this); - } - - public async run(): Promise { - const { task } = this; - if (!task?.enabled || this.#running || this.#paused) return { entry: this, type: ResponseType.Ignore }; - - this.#running = true; - let response: PartialResponseValue | null = null; - try { - response = (await task.run({ ...this.data, id: this.id })) as PartialResponseValue | null; - } catch (error) { - container.client.emit(Events.TaskError, error, { piece: task, entity: this }); - } - - this.#running = false; - - if (response !== null) return { ...response, entry: this }; - - return this.recurring - ? { entry: this, type: ResponseType.Update, value: this.recurring.next() } - : { entry: this, type: ResponseType.Finished }; - } - - public async update(data: ScheduleEntry.UpdateData) { - const entry = await container.prisma.schedule.update({ - where: { id: this.id }, - data - }); - - this.#patch(entry); - } - - public async reload() { - const entry = await container.prisma.schedule.findUnique({ where: { id: this.id } }); - if (entry === null) throw new Error('Failed to reload the entity'); - - this.#patch(entry); - } - - #patch(data: Omit) { - this.time = data.time; - this.recurring = isNullishOrEmpty(data.recurring) ? null : new Cron(data.recurring); - this.catchUp = data.catchUp; - this.data = data.data as ScheduleEntry.TaskData[Type]; - } - - public static async create(data: ScheduleEntry.CreateData): Promise> { - const entry = await container.prisma.schedule.create({ data }); - return new ScheduleEntry(entry); - } -} - -export const enum ResponseType { - Ignore, - Delay, - Update, - Finished -} - -export type PartialResponseValue = - | { type: ResponseType.Ignore | ResponseType.Finished } - | { type: ResponseType.Delay; value: number } - | { type: ResponseType.Update; value: Date }; - -export type ResponseValue = PartialResponseValue & { entry: ScheduleEntry }; - -export namespace ScheduleEntry { - export type TaskId = keyof TaskData; - - export interface TaskData { - poststats: null; - syncResourceAnalytics: null; - moderationEndAddRole: SharedModerationTaskData; - moderationEndBan: SharedModerationTaskData; - moderationEndMute: SharedModerationTaskData; - moderationEndRemoveRole: SharedModerationTaskData; - moderationEndRestrictionAttachment: SharedModerationTaskData; - moderationEndRestrictionEmbed: SharedModerationTaskData; - moderationEndRestrictionEmoji: SharedModerationTaskData; - moderationEndRestrictionReaction: SharedModerationTaskData; - moderationEndRestrictionVoice: SharedModerationTaskData; - moderationEndSetNickname: SharedModerationTaskData; - moderationEndTimeout: SharedModerationTaskData; - moderationEndVoiceMute: SharedModerationTaskData; - moderationEndWarning: SharedModerationTaskData; - } - - interface SharedModerationTaskData { - caseID: number; - userID: string; - guildID: string; - type: Type; - duration: number | null; - extraData: ModerationManagerEntry.ExtraData; - scheduleRetryCount?: number; - } - - export interface CreateData { - taskId: Type; - time: Date; - recurring: string | null; - catchUp: boolean; - data: TaskData[Type]; - } - - export interface UpdateData { - time?: Date; - recurring?: string | null; - catchUp?: boolean; - data?: TaskData[Type]; - } -} diff --git a/src/lib/schedule/manager/ScheduleManager.ts b/src/lib/schedule/manager/ScheduleManager.ts deleted file mode 100644 index 13166b027..000000000 --- a/src/lib/schedule/manager/ScheduleManager.ts +++ /dev/null @@ -1,197 +0,0 @@ -import { ResponseType, ScheduleEntry, type ResponseValue } from '#lib/schedule/manager/ScheduleEntry'; -import { container } from '@sapphire/framework'; -import { Cron } from '@sapphire/time-utilities'; - -export class ScheduleManager { - public queue: ScheduleEntry[] = []; - private interval: NodeJS.Timeout | null = null; - - public destroy() { - this._clearInterval(); - } - - public async init() { - const entries = await container.prisma.schedule.findMany(); - for (const entry of entries) this._insert(new ScheduleEntry(entry)); - this._checkInterval(); - } - - public async add( - taskId: Type, - timeResolvable: TimeResolvable, - options: ScheduleManagerAddOptions - ) { - if (!container.stores.get('tasks').has(taskId)) throw new Error(`The task '${taskId}' does not exist.`); - - const [time, cron] = this._resolveTime(timeResolvable); - const entry = await ScheduleEntry.create({ - taskId, - time, - recurring: cron ? cron.cron : null, - catchUp: options.catchUp ?? true, - data: options.data - }); - - this._insert(entry); - this._checkInterval(); - return entry; - } - - public async reschedule(entityOrId: ScheduleEntry | number, time: Date | number) { - if (typeof entityOrId === 'number') { - entityOrId = this.queue.find((entry) => entry.id === entityOrId)!; - if (!entityOrId) return false; - } - - try { - entityOrId.pause(); - - await entityOrId.update({ time: new Date(time) }); - this._remove(entityOrId); - this._insert(entityOrId); - } finally { - entityOrId.resume(); - } - - return true; - } - - public async remove(entityOrId: ScheduleEntry | number) { - if (typeof entityOrId === 'number') { - entityOrId = this.queue.find((entity) => entity.id === entityOrId)!; - if (!entityOrId) return false; - } - - entityOrId.pause(); - await container.prisma.schedule.delete({ where: { id: entityOrId.id } }); - - this._remove(entityOrId); - this._checkInterval(); - return true; - } - - public async execute() { - if (this.queue.length) { - // Process the active tasks, they're sorted by the time they end - const now = Date.now(); - const execute: Promise[] = []; - for (const entry of this.queue) { - if (entry.time.getTime() > now) break; - execute.push(entry.run()); - } - - // Check if the Schedule has a task to run and run them if they exist - if (!execute.length) return; - await this._handleResponses(await Promise.all(execute)); - } - - this._checkInterval(); - } - - private _insert(entity: ScheduleEntry) { - const index = this.queue.findIndex((entry) => entry.time > entity.time); - if (index === -1) this.queue.push(entity); - else this.queue.splice(index, 0, entity); - - return entity; - } - - private _remove(entity: ScheduleEntry) { - const index = this.queue.indexOf(entity); - if (index !== -1) this.queue.splice(index, 1); - } - - private async _handleResponses(responses: readonly ResponseValue[]) { - const results = await Promise.allSettled(responses.map((response) => this._handleResponse(response))); - for (const result of results) { - if (result.status === 'rejected') container.logger.error(result.reason); - } - } - - private async _handleResponse(response: ResponseValue) { - // 1. If the response is to ignore, do nothing, the entry will be re-run. - if (response.type === ResponseType.Ignore) { - return; - } - - response.entry.pause(); - - // 2. If the response is to finish, remove the entry from the database and the cache. - if (response.type === ResponseType.Finished) { - await container.prisma.schedule.delete({ where: { id: response.entry.id } }); - this._remove(response.entry); - return; - } - - // 3. If the response is to update the time, update the time in the database and the cache. - let time: Date; - if (response.type === ResponseType.Delay) { - time = new Date(response.entry.time.getTime() + response.value); - } else if (response.type === ResponseType.Update) { - time = response.value; - } else { - throw new Error('Unreachable'); - } - - await response.entry.update({ time }); - - const index = this.queue.findIndex((entity) => entity === response.entry); - if (index === -1) return; - - this.queue.splice(index, 1); - this._insert(response.entry); - - // Resume so it can be run again - response.entry.resume(); - } - - /** - * Clear the current interval - */ - private _clearInterval(): void { - if (this.interval) { - clearInterval(this.interval); - this.interval = null; - } - } - - /** - * Sets the interval when needed - */ - private _checkInterval(): void { - if (!this.queue.length) { - this._clearInterval(); - } else if (!this.interval) { - this.interval = setInterval(this.execute.bind(this), container.client.options.schedule?.interval ?? 5000).unref(); - } - } - - /** - * Resolve the time and cron - * @param time The time or Cron pattern - */ - private _resolveTime(time: TimeResolvable): [Date, Cron | null] { - if (time instanceof Date) return [time, null]; - if (time instanceof Cron) return [time.next(), time]; - if (typeof time === 'number') return [new Date(time), null]; - if (typeof time === 'string') { - const cron = new Cron(time); - return [cron.next(), cron]; - } - throw new Error('invalid time passed'); - } -} - -export interface ScheduleManagerAddOptions { - /** - * If the task should try to catch up if the bot is down. - */ - catchUp?: boolean; - - /** - * The data to pass to the Task piece when the ScheduledTask is ready for execution. - */ - data: ScheduleEntry.TaskData[Type]; -} - -export type TimeResolvable = number | Date | string | Cron; diff --git a/src/lib/schedule/structures/Task.ts b/src/lib/schedule/structures/Task.ts deleted file mode 100644 index 93344e1bb..000000000 --- a/src/lib/schedule/structures/Task.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { PartialResponseValue } from '#lib/schedule/manager/ScheduleEntry'; -import { Piece } from '@sapphire/framework'; -import type { Awaitable } from '@sapphire/utilities'; - -export abstract class Task extends Piece { - /** - * The run method to be overwritten in actual Task pieces - * @param data The data - */ - public abstract run(data: unknown): Awaitable; -} - -export namespace Task { - export type Options = Piece.Options; -} diff --git a/src/lib/schedule/structures/TaskStore.ts b/src/lib/schedule/structures/TaskStore.ts deleted file mode 100644 index f4cab3070..000000000 --- a/src/lib/schedule/structures/TaskStore.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Task } from '#lib/schedule/structures/Task'; -import { Store } from '@sapphire/framework'; - -export class TaskStore extends Store { - /** - * Constructs our TaskStore for use in Wolf - * @param client The client that instantiates this store - */ - public constructor() { - super(Task, { name: 'tasks' }); - } -} diff --git a/src/lib/setup/index.ts b/src/lib/setup/index.ts deleted file mode 100644 index 625f9843f..000000000 --- a/src/lib/setup/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -// Config must be the first to be loaded, as it sets the env: -import '#root/config'; - -// Import everything else: -import '#lib/setup/paginated-message'; -import '#lib/setup/inspect'; -import '#lib/setup/prisma'; -import '#utils/Sanitizer/initClean'; -import '@sapphire/plugin-api/register'; -import '@sapphire/plugin-editable-commands/register'; -import '@sapphire/plugin-i18next/register'; -import '@sapphire/plugin-logger/register'; - -import { ApplicationCommandRegistries, RegisterBehavior } from '@sapphire/framework'; - -ApplicationCommandRegistries.setDefaultBehaviorWhenNotIdentical(RegisterBehavior.Overwrite); diff --git a/src/lib/setup/inspect.ts b/src/lib/setup/inspect.ts deleted file mode 100644 index 319df8e94..000000000 --- a/src/lib/setup/inspect.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { inspect } from 'node:util'; - -inspect.defaultOptions.depth = 1; -inspect.defaultOptions.breakLength = 120; diff --git a/src/lib/setup/paginated-message.ts b/src/lib/setup/paginated-message.ts deleted file mode 100644 index 7ead19552..000000000 --- a/src/lib/setup/paginated-message.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { fetchT } from '#lib/i18n/translate'; -import { userMention } from '@discordjs/builders'; -import { PaginatedMessage } from '@sapphire/discord.js-utilities'; -import { MessageFlags } from 'discord.js'; - -PaginatedMessage.selectMenuOptions = async (pageIndex, internationalizationContext) => { - const t = await fetchT(internationalizationContext); - - return { - label: `${t(LanguageKeys.Globals.PaginatedMessagePage, {})} ${pageIndex}` - }; -}; - -PaginatedMessage.wrongUserInteractionReply = async (targetUser, _, internationalizationContext) => { - const t = await fetchT(internationalizationContext); - - return { - content: t(LanguageKeys.Globals.PaginatedMessageWrongUserInteractionReply, { user: userMention(targetUser.id) }), - allowedMentions: { users: [], roles: [] }, - flags: MessageFlags.Ephemeral - }; -}; diff --git a/src/lib/setup/prisma.ts b/src/lib/setup/prisma.ts deleted file mode 100644 index 0e28ac7ec..000000000 --- a/src/lib/setup/prisma.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { PrismaPg } from '@prisma/adapter-pg'; -import { PrismaClient } from '#generated/prisma'; -import { container } from '@sapphire/framework'; - -const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL! }); -const prisma = new PrismaClient({ adapter }).$extends({ - name: 'extensions', - model: { - user: { - async fetchModerationDirectMessageEnabled(userId: string): Promise { - const entry = await prisma.user.findUnique({ where: { id: userId }, select: { moderationDM: true } }); - return entry?.moderationDM ?? true; - }, - async toggleModerationDirectMessageEnabled(userId: string): Promise { - const [entry] = await prisma.$queryRaw<{ moderation_dm: boolean }[]>` - INSERT INTO public.user (id, moderation_dm) - VALUES (${userId}, false) - ON CONFLICT (id) - DO UPDATE SET moderation_dm = NOT public.user.moderation_dm - RETURNING "moderation_dm"; - `; - return entry.moderation_dm; - } - }, - moderation: { - async getGuildModerationMetadata(guildId: string): Promise { - const [entry] = await prisma.$queryRaw<{ latest: number | null; count: bigint }[]>` - SELECT - MAX(case_id) as "latest", - COUNT(*) as "count" - FROM public.moderation - WHERE guild_id = ${guildId}; - `; - - return { latest: entry.latest ?? 0, count: Number(entry.count) }; - } - } - } -}); -container.prisma = prisma; - -declare module '@sapphire/pieces' { - interface Container { - prisma: typeof prisma; - } -} - -interface GuildModerationMetadata { - latest: number; - count: number; -} diff --git a/src/lib/structures/AnalyticsData.ts b/src/lib/structures/AnalyticsData.ts deleted file mode 100644 index 4fd6e6cb2..000000000 --- a/src/lib/structures/AnalyticsData.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { parseAnalytics } from '#root/config'; -import { InfluxDB, type QueryApi, type WriteApi } from '@influxdata/influxdb-client'; -import { envParseString } from '@skyra/env-utilities'; - -export class AnalyticsData { - public readonly influx: InfluxDB = new InfluxDB(parseAnalytics()); - public readonly writeApi: WriteApi; - public readonly queryApi: QueryApi; - - public messageCount = 0; - - public constructor() { - this.writeApi = this.influx.getWriteApi(envParseString('INFLUX_ORG'), envParseString('INFLUX_ORG_ANALYTICS_BUCKET'), 's'); - this.queryApi = this.influx.getQueryApi(envParseString('INFLUX_ORG')); - } -} diff --git a/src/lib/structures/SettingsMenu.ts b/src/lib/structures/SettingsMenu.ts deleted file mode 100644 index d898e7019..000000000 --- a/src/lib/structures/SettingsMenu.ts +++ /dev/null @@ -1,744 +0,0 @@ -import { - getConfigurableGroups, - isSchemaGroup, - readSettings, - remove, - reset, - SchemaGroup, - SchemaKey, - set, - writeSettingsTransaction -} from '#lib/database/settings'; -import { getT } from '#lib/i18n'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { LongLivingInteractionCollector } from '#lib/util/LongLivingInteractionCollector'; -import { WolfArgs, type WolfCommand, type WolfSubcommand } from '#lib/structures'; -import { floatPromise, minutes, stringifyError } from '#utils/common'; -import { ZeroWidthSpace } from '#utils/constants'; -import { getColor, pickRandom } from '#utils/util'; -import { - ButtonBuilder, - ChannelSelectMenuBuilder, - ContainerBuilder, - LabelBuilder, - ModalBuilder, - RoleSelectMenuBuilder, - StringSelectMenuBuilder, - TextInputBuilder -} from '@discordjs/builders'; -import { container, type ChatInputCommand, type MessageCommand } from '@sapphire/framework'; -import { filter, partition } from '@sapphire/iterator-utilities'; -import type { TFunction } from '@sapphire/plugin-i18next'; -import { - ButtonStyle, - ChannelType, - Collection, - DiscordAPIError, - MessageFlags, - RESTJSONErrorCodes, - TextInputStyle, - type Message, - type MessageComponentInteraction -} from 'discord.js'; - -/** - * Sorts a collection alphabetically as based on the keys, rather than the values. - * This is used to ensure that subcategories are listed in the pages right after the main category. - * @param _ The first element for comparison - * @param __ The second element for comparison - * @param firstCategory Key of the first element for comparison - * @param secondCategory Key of the second element for comparison - */ -function sortCommandsAlphabetically(_: WolfCommand[], __: WolfCommand[], firstCategory: string, secondCategory: string): 1 | -1 | 0 { - if (firstCategory > secondCategory) return 1; - if (secondCategory > firstCategory) return -1; - return 0; -} - -const TIMEOUT = minutes(15); - -const CustomIds = { - // Navigation - SELECT: 'conf-select', - BACK: 'conf-back', - STOP: 'conf-stop', - - // Actions - SET: 'conf-set', - REMOVE: 'conf-remove', - RESET: 'conf-reset', - UNDO: 'conf-undo', - - // Input Mode - CANCEL: 'conf-cancel', - INPUT_BOOL_TRUE: 'conf-input-bool-true', - INPUT_BOOL_FALSE: 'conf-input-bool-false', - INPUT_ROLE: 'conf-input-role', - INPUT_CHANNEL: 'conf-input-channel', - INPUT_REMOVE: 'conf-input-remove', - INPUT_CATEGORY: 'conf-input-category', - INPUT_COMMAND: 'conf-input-command', - INPUT_COMMAND_BACK: 'conf-input-command-back', - INPUT_MODAL: 'conf-input-modal' -} as const; - -const enum UpdateType { - Set, - Remove, - Reset, - Replace -} - -export class SettingsMenu { - private readonly interaction: WolfSubcommand.Interaction; - private t: TFunction; - private schema: SchemaKey | SchemaGroup; - private collector: LongLivingInteractionCollector | null = null; - private errorMessage: string | null = null; - private response: Message | null = null; - private oldValue: unknown = undefined; - private inputMode = false; - private inputType: UpdateType = UpdateType.Set; - private selectedCategory: string | null = null; - - public constructor(message: WolfSubcommand.Interaction, language: TFunction) { - this.interaction = message; - this.t = language; - this.schema = getConfigurableGroups(); - } - - public get client() { - return container.client; - } - - private get updatedValue(): boolean { - return this.oldValue !== undefined; - } - - public async init(context: WolfCommand.RunContext): Promise { - // Defer the interaction to prevent timeout - await this.interaction.deferReply(); - - // Show initial loading state - const loadingMessages = this.t(LanguageKeys.System.Loading); - const loadingContainer = new ContainerBuilder() - .setAccentColor(0x5865f2) - .addTextDisplayComponents((textDisplay) => - textDisplay.setContent(pickRandom(Array.isArray(loadingMessages) ? loadingMessages : [loadingMessages])) - ); - - this.response = await this.interaction.editReply({ - components: [loadingContainer], - flags: [MessageFlags.IsComponentsV2] - }); - - // Render the actual menu - await this._renderResponse(); - - this.collector = new LongLivingInteractionCollector(); - this.collector.setListener((interaction) => this.onInteraction(interaction, context)); - this.collector.setEndListener(() => this.stop()); - this.collector.setTime(TIMEOUT); - } - - private async render() { - if (this.inputMode) { - return this.renderInput(); - } - - const description = isSchemaGroup(this.schema) ? this.renderGroup(this.schema) : await this.renderKey(this.schema); - const { parent } = this.schema; - - const container = new ContainerBuilder().setAccentColor(getColor(this.interaction)); - - // Add main content as TextDisplay - container.addTextDisplayComponents((textDisplay) => textDisplay.setContent(description.concat(ZeroWidthSpace).join('\n'))); - - // Select Menu Row - if (isSchemaGroup(this.schema)) { - const selectMenu = new StringSelectMenuBuilder() - .setCustomId(CustomIds.SELECT) - .setPlaceholder(this.t(LanguageKeys.Commands.Conf.MenuRenderSelect)); - - const options = []; - // Collect folders - for (const value of this.schema.values()) { - if (value.dashboardOnly) continue; - if (isSchemaGroup(value)) { - options.push({ - label: value.name, - value: value.key, - emoji: { name: '📁' }, - description: this.t(LanguageKeys.Commands.Conf.MenuRenderAtFolder, { path: value.name }).substring(0, 100) - }); - } - } - // Collect keys - for (const value of this.schema.values()) { - if (value.dashboardOnly) continue; - if (!isSchemaGroup(value)) { - options.push({ - label: value.name, - value: value.key, - emoji: { name: '⚙️' }, - description: this.t(LanguageKeys.Commands.Conf.MenuRenderAtPiece, { path: value.name }).substring(0, 100) - }); - } - } - - if (options.length > 0) { - selectMenu.addOptions(options.slice(0, 25)); - container.addActionRowComponents((actionRow) => actionRow.setComponents(selectMenu)); - } - } - - // Buttons Section - const buttons: ButtonBuilder[] = []; - if (parent) { - buttons.push( - new ButtonBuilder() - .setCustomId(CustomIds.BACK) - .setLabel(this.t(LanguageKeys.Globals.Back)) - .setStyle(ButtonStyle.Secondary) - .setEmoji({ name: '◀️' }) - ); - } - - if (!isSchemaGroup(this.schema)) { - // It is a key - const settings = await readSettings(this.interaction.guild); - const value = settings[this.schema.property]; - - // Set - buttons.push(new ButtonBuilder().setCustomId(CustomIds.SET).setLabel(this.t(LanguageKeys.Globals.Set)).setStyle(ButtonStyle.Primary)); - - // Remove (if array and has elements) - if (this.schema.array && (value as unknown[]).length) { - buttons.push( - new ButtonBuilder().setCustomId(CustomIds.REMOVE).setLabel(this.t(LanguageKeys.Globals.Remove)).setStyle(ButtonStyle.Danger) - ); - } - - // Reset (if changed) - if (value !== this.schema.default) { - buttons.push( - new ButtonBuilder().setCustomId(CustomIds.RESET).setLabel(this.t(LanguageKeys.Globals.Reset)).setStyle(ButtonStyle.Danger) - ); - } - - // Undo (if updated) - if (this.updatedValue) { - buttons.push( - new ButtonBuilder() - .setCustomId(CustomIds.UNDO) - .setLabel(this.t(LanguageKeys.Commands.Conf.MenuRenderUndo)) - .setStyle(ButtonStyle.Secondary) - ); - } - } - - buttons.push( - new ButtonBuilder() - .setCustomId(CustomIds.STOP) - .setLabel(this.t(LanguageKeys.Globals.Stop)) - .setStyle(ButtonStyle.Danger) - .setEmoji({ name: '⏹️' }) - ); - - // Add buttons in groups of 5 (Discord limit per ActionRow) - for (let i = 0; i < buttons.length; i += 5) { - const chunk = buttons.slice(i, i + 5); - container.addActionRowComponents((actionRow) => actionRow.setComponents(...chunk)); - } - - return { components: [container], flags: [MessageFlags.IsComponentsV2] }; - } - - private async renderInput() { - const key = this.schema as SchemaKey; - const container = new ContainerBuilder().setAccentColor(getColor(this.interaction)); - - container.addTextDisplayComponents((textDisplay) => textDisplay.setContent(this.t(LanguageKeys.Commands.Conf.MenuRenderUpdate))); - - // Remove Mode: Show Select Menu with current values to remove - if (this.inputType === UpdateType.Remove) { - const settings = await readSettings(this.interaction.guild); - const values = settings[key.property] as unknown[]; - - if (values.length) { - const selectMenu = new StringSelectMenuBuilder() - .setCustomId(CustomIds.INPUT_REMOVE) - .setPlaceholder(this.t(LanguageKeys.Commands.Conf.MenuRenderSelect)); - const options = await Promise.all( - values.map((val, index) => { - const label = key.stringify(settings, this.t, val as any).substring(0, 100); - // Better: For Roles/Channels, we can use their ID if available. - let valueId = String(val); - if (val && typeof val === 'object' && 'id' in val) { - // @ts-expect-error accessing id - valueId = val.id; - } - - return { - label: label || 'Unknown', - value: valueId.substring(0, 100), - description: String(index) - }; - }) - ); - - selectMenu.addOptions(options.slice(0, 25)); - container.addActionRowComponents((actionRow) => actionRow.setComponents(selectMenu)); - } else { - container.addTextDisplayComponents((textDisplay) => textDisplay.setContent(this.t(LanguageKeys.Globals.None))); - } - } else if (key.property === 'disabledCommands') { - // Special handling for disabled-commands with category navigation - const commandsByCategory = await SettingsMenu.fetchCommands(this.interaction); - - if (this.selectedCategory === null) { - // Show categories - const options = Array.from(commandsByCategory.keys()) - .slice(0, 25) - .map((category) => { - return { - label: category, - value: category - }; - }); - - if (options.length > 0) { - const selectMenu = new StringSelectMenuBuilder() - .setCustomId(CustomIds.INPUT_CATEGORY) - .setPlaceholder(this.t(LanguageKeys.Commands.Conf.MenuRenderSelect)); - - selectMenu.addOptions(options); - container.addActionRowComponents((actionRow) => actionRow.setComponents(selectMenu)); - } else { - container.addTextDisplayComponents((textDisplay) => textDisplay.setContent(this.t(LanguageKeys.Globals.None))); - } - } else { - // Show commands for selected category - const commands = commandsByCategory.get(this.selectedCategory) || []; - const options = commands.slice(0, 25).map((cmd) => ({ - label: cmd.name, - value: cmd.name, - description: this.t(cmd.description) - })); - - if (options.length > 0) { - const selectMenu = new StringSelectMenuBuilder() - .setCustomId(CustomIds.INPUT_COMMAND) - .setPlaceholder(this.t(LanguageKeys.Commands.Conf.MenuRenderSelect)); - - selectMenu.addOptions(options); - container.addActionRowComponents((actionRow) => actionRow.setComponents(selectMenu)); - } else { - container.addTextDisplayComponents((textDisplay) => textDisplay.setContent(this.t(LanguageKeys.Globals.None))); - } - - // Add back button to return to categories - container.addActionRowComponents((actionRow) => - actionRow.setComponents( - new ButtonBuilder() - .setCustomId(CustomIds.INPUT_COMMAND_BACK) - .setLabel(this.t(LanguageKeys.Globals.Back)) - .setStyle(ButtonStyle.Secondary) - .setEmoji({ name: '◀️' }) - ) - ); - } - } - // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check - else - switch (key.type) { - case 'boolean': { - container.addActionRowComponents((actionRow) => - actionRow.setComponents( - new ButtonBuilder() - .setCustomId(CustomIds.INPUT_BOOL_TRUE) - .setLabel(this.t(LanguageKeys.Globals.Yes)) - .setStyle(ButtonStyle.Success), - new ButtonBuilder() - .setCustomId(CustomIds.INPUT_BOOL_FALSE) - .setLabel(this.t(LanguageKeys.Globals.No)) - .setStyle(ButtonStyle.Danger) - ) - ); - break; - } - case 'role': { - const select = new RoleSelectMenuBuilder() - .setCustomId(CustomIds.INPUT_ROLE) - .setPlaceholder(this.t(LanguageKeys.Commands.Conf.MenuRenderSelect)); - container.addActionRowComponents((actionRow) => actionRow.setComponents(select)); - break; - } - case 'guildTextChannel': - case 'guildVoiceChannel': { - const select = new ChannelSelectMenuBuilder() - .setCustomId(CustomIds.INPUT_CHANNEL) - .setPlaceholder(this.t(LanguageKeys.Commands.Conf.MenuRenderSelect)); - - if (key.type === 'guildTextChannel') select.setChannelTypes(ChannelType.GuildText, ChannelType.GuildAnnouncement); - if (key.type === 'guildVoiceChannel') select.setChannelTypes(ChannelType.GuildVoice, ChannelType.GuildStageVoice); - - container.addActionRowComponents((actionRow) => actionRow.setComponents(select)); - break; - } - } - - // Cancel Button - container.addActionRowComponents((actionRow) => - actionRow.setComponents( - new ButtonBuilder().setCustomId(CustomIds.CANCEL).setLabel(this.t(LanguageKeys.Globals.Cancel)).setStyle(ButtonStyle.Secondary) - ) - ); - - return { components: [container], flags: [MessageFlags.IsComponentsV2] }; - } - - private async renderKey(entry: SchemaKey) { - const settings = await readSettings(this.interaction.guild); - - this.t = getT(settings.language); - const { t } = this; - - const description = [t(LanguageKeys.Commands.Conf.MenuRenderAtPiece, { path: this.schema.name })]; - if (this.errorMessage) description.push('', this.errorMessage, ''); - - description.push(t(entry.description)); - - const serialized = entry.display(settings, this.t); - description.push('', t(LanguageKeys.Commands.Conf.MenuRenderCvalue, { value: serialized })); - - return description; - } - - private renderGroup(entry: SchemaGroup) { - const { t } = this; - - const description = [t(LanguageKeys.Commands.Conf.MenuRenderAtFolder, { path: entry.name })]; - if (this.errorMessage) description.push(this.errorMessage); - - const [folders, keys] = partition( - filter(entry.values(), (value) => !value.dashboardOnly), - (value) => isSchemaGroup(value) - ); - - if (!folders.length && !keys.length) { - description.push(t(LanguageKeys.Commands.Conf.MenuRenderNokeys)); - } else { - description.push( - t(LanguageKeys.Commands.Conf.MenuRenderSelect), - '', - ...folders.map(({ key }) => `📁 ${key}`), - ...keys.map(({ key }) => `⚙️ ${key}`) - ); - } - - return description; - } - - private async onInteraction(interaction: MessageComponentInteraction, context: WolfCommand.RunContext) { - if (interaction.message.id !== this.response?.id) return; - if (interaction.user.id !== this.interaction.user.id) return; - this.collector?.setTime(TIMEOUT); - this.errorMessage = null; - - // Handle Select Menu for Navigation - if (interaction.isStringSelectMenu() && interaction.customId === CustomIds.SELECT) { - await interaction.deferUpdate(); - const selectedKey = interaction.values[0]; - if (isSchemaGroup(this.schema)) { - const next = this.schema.get(selectedKey); - if (next) { - this.schema = next; - this.oldValue = undefined; - } - } - await this._renderResponse(); - return; - } - - // Handle Input Mode Interactions - if (this.inputMode) { - if (interaction.customId === CustomIds.CANCEL) { - await interaction.deferUpdate(); - this.inputMode = false; - this.selectedCategory = null; - await this._renderResponse(); - return; - } - - if (interaction.isStringSelectMenu() && interaction.customId === CustomIds.INPUT_CATEGORY) { - await interaction.deferUpdate(); - [this.selectedCategory] = interaction.values; - await this._renderResponse(); - return; - } - - if (interaction.isButton() && interaction.customId === CustomIds.INPUT_COMMAND_BACK) { - await interaction.deferUpdate(); - this.selectedCategory = null; - await this._renderResponse(); - return; - } - - if (interaction.customId === CustomIds.INPUT_BOOL_TRUE) { - await interaction.deferUpdate(); - await this.processUpdate(this.inputType, 'true', context); - return; - } - - if (interaction.customId === CustomIds.INPUT_BOOL_FALSE) { - await interaction.deferUpdate(); - await this.processUpdate(this.inputType, 'false', context); - return; - } - - if (interaction.isRoleSelectMenu() && interaction.customId === CustomIds.INPUT_ROLE) { - await interaction.deferUpdate(); - // Use the first selected role ID - const roleId = interaction.values[0]; - await this.processUpdate(this.inputType, roleId, context); - return; - } - - if (interaction.isChannelSelectMenu() && interaction.customId === CustomIds.INPUT_CHANNEL) { - await interaction.deferUpdate(); - const channelId = interaction.values[0]; - await this.processUpdate(this.inputType, channelId, context); - return; - } - - if (interaction.isStringSelectMenu() && interaction.customId === CustomIds.INPUT_COMMAND) { - await interaction.deferUpdate(); - const commandName = interaction.values[0]; - this.selectedCategory = null; - await this.processUpdate(this.inputType, commandName, context); - return; - } - - if (interaction.isStringSelectMenu() && interaction.customId === CustomIds.INPUT_REMOVE) { - await interaction.deferUpdate(); - const value = interaction.values[0]; - await this.processUpdate(this.inputType, value, context); - return; - } - - if (interaction.customId === CustomIds.INPUT_MODAL) { - // Re-trigger modal - await this.showInputModal(interaction, context, this.inputType); - return; - } - } - - if (interaction.isButton()) { - switch (interaction.customId) { - case CustomIds.BACK: - await interaction.deferUpdate(); - if (this.schema.parent) { - this.schema = this.schema.parent; - this.oldValue = undefined; - } - await this._renderResponse(); - break; - case CustomIds.STOP: - await interaction.deferUpdate(); - this.stop(); - break; - case CustomIds.RESET: - await interaction.deferUpdate(); - await this.tryUpdate(UpdateType.Reset); - await this._renderResponse(); - break; - case CustomIds.UNDO: - await interaction.deferUpdate(); - await this.tryUndo(); - await this._renderResponse(); - break; - case CustomIds.SET: - await this.initiateInput(interaction, context, UpdateType.Set); - break; - case CustomIds.REMOVE: - await this.initiateInput(interaction, context, UpdateType.Remove); - break; - } - } - } - - private async initiateInput(interaction: MessageComponentInteraction, context: WolfCommand.RunContext, type: UpdateType) { - this.inputType = type; - const key = this.schema as SchemaKey; - - // Check if we can use special components - const useComponent = - (type === UpdateType.Set && ['boolean', 'role', 'guildTextChannel', 'guildVoiceChannel'].includes(key.type)) || - (type === UpdateType.Set && key.property === 'disabledCommands') || // Special handling for disabled-commands - (type === UpdateType.Remove && key.array); // For Remove, we use a select menu if array - - if (useComponent) { - this.inputMode = true; - await interaction.deferUpdate(); - await this._renderResponse(); - } else { - // Use Modal - await this.showInputModal(interaction, context, type); - } - } - - private async showInputModal(interaction: MessageComponentInteraction, context: WolfCommand.RunContext, type: UpdateType) { - const modalId = `conf-modal-${Date.now()}`; - const inputId = `conf-input-${Date.now()}`; - - const modal = new ModalBuilder() - .setCustomId(modalId) - .setTitle(this.t(type === UpdateType.Set ? LanguageKeys.Globals.Set : LanguageKeys.Globals.Remove)); - - const key = this.schema as SchemaKey; - - const input = new TextInputBuilder().setCustomId(inputId).setStyle(TextInputStyle.Short).setRequired(true).setPlaceholder(key.name); - const label = new LabelBuilder().setLabel(this.t(LanguageKeys.Globals.Value)).setTextInputComponent(input); - - modal.addLabelComponents(label); - - await interaction.showModal(modal); - - try { - const submission = await interaction.awaitModalSubmit({ - time: minutes(5), - filter: (i) => i.customId === modalId && i.user.id === interaction.user.id - }); - - const value = submission.fields.getTextInputValue(inputId); - await submission.deferUpdate(); - - await this.processUpdate(type, value, context); - } catch (error) { - if ( - error instanceof Error && - (error.name === 'InteractionCollectorError' || - error.name === 'Error [InteractionCollectorError]' || - error.message === 'Collector received no interactions before ending with reason: time') - ) { - // Ignore timeout - } else { - this.errorMessage = stringifyError(this.t, error); - await this._renderResponse(); - } - } - } - - private async processUpdate(type: UpdateType, value: string, context: WolfCommand.RunContext) { - const conf = container.stores.get('commands').get('conf') as MessageCommand; - // Create a minimal message proxy for WolfArgs compatibility - const messageProxy = { - guild: this.interaction.guild, - channel: this.interaction.channel, - author: this.interaction.user, - client: this.interaction.client - } as any; - const args = WolfArgs.from(conf, messageProxy, value, context, this.t); - await this.tryUpdate(type, args); - this.inputMode = false; - await this._renderResponse(); - } - - private async _renderResponse() { - if (!this.response) return; - try { - const payload = await this.render(); - // @ts-expect-error - v2 components are experimental - await this.response.edit(payload); - } catch (error) { - if (error instanceof DiscordAPIError && error.code === RESTJSONErrorCodes.UnknownMessage) { - this.response = null; - this.collector?.end(); - } else { - this.client.emit('error', error as Error); - } - } - } - - private async tryUpdate(action: UpdateType, args: WolfArgs | null = null, value: unknown = null) { - try { - const key = this.schema as SchemaKey; - using trx = await writeSettingsTransaction(this.interaction.guild); - - this.t = getT(trx.settings.language); - this.oldValue = trx.settings[key.property]; - switch (action) { - case UpdateType.Set: { - trx.write(await set(trx.settings, key, args!)); - break; - } - case UpdateType.Remove: { - trx.write(await remove(trx.settings, key, args!)); - break; - } - case UpdateType.Reset: { - trx.write(reset(key)); - break; - } - case UpdateType.Replace: { - trx.write({ [key.property]: value }); - break; - } - } - await trx.submitWithAudit(this.interaction.user.id); - } catch (error) { - this.errorMessage = stringifyError(this.t, error); - this.oldValue = undefined; - } - } - - private async tryUndo() { - if (this.updatedValue) { - await this.tryUpdate(UpdateType.Replace, null, this.oldValue); - this.oldValue = undefined; - } else { - const key = this.schema as SchemaKey; - this.errorMessage = this.t(LanguageKeys.Commands.Conf.Nochange, { key: key.name }); - } - } - - private stop(): void { - if (this.response) { - const content = this.t(LanguageKeys.Commands.Conf.MenuSaved); - const container = new ContainerBuilder() - .setAccentColor(getColor(this.interaction)) - .addTextDisplayComponents((textDisplay) => textDisplay.setContent(content)); - - floatPromise(this.response.edit({ components: [container], flags: [MessageFlags.IsComponentsV2] })); - } - - if (this.collector && !this.collector.ended) { - this.collector.end(); - } - } - - private static async fetchCommands(interaction: WolfSubcommand.Interaction) { - const commands = container.stores.get('commands'); - const filtered = new Collection(); - await Promise.all( - commands.map(async (cmd) => { - const command = cmd as WolfCommand; - if (command.hidden) return; - - const result = await cmd.preconditions.chatInputRun(interaction, command as ChatInputCommand, { command: null! }); - if (result.isErr()) return; - - const category = filtered.get(command.fullCategory.join(' → ')); - if (category) category.push(command); - else filtered.set(command.fullCategory.join(' → '), [command]); - }) - ); - - const sorted = filtered.sort(sortCommandsAlphabetically); - console.log( - `[SettingsMenu] Found ${sorted.size} categories with ${Array.from(sorted.values()).reduce((acc, cmds) => acc + cmds.length, 0)} total commands` - ); - return sorted; - } -} diff --git a/src/lib/structures/commands/ChannelConfigurationCommand.ts b/src/lib/structures/commands/ChannelConfigurationCommand.ts deleted file mode 100644 index cadca9e21..000000000 --- a/src/lib/structures/commands/ChannelConfigurationCommand.ts +++ /dev/null @@ -1,57 +0,0 @@ -import type { GuildSettingsOfType } from '#lib/database'; -import { writeSettingsTransaction } from '#lib/database/settings'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { WolfCommand } from '#lib/structures/commands/WolfCommand'; -import { PermissionLevels, type GuildMessage, type TypedFT } from '#lib/types'; -import { assertNonThread } from '#utils/functions'; -import { Args, Argument, CommandOptionsRunTypeEnum, container } from '@sapphire/framework'; -import { send } from '@sapphire/plugin-editable-commands'; -import type { Nullish } from '@sapphire/utilities'; -import type { TextChannel } from 'discord.js'; - -export abstract class ChannelConfigurationCommand extends WolfCommand { - private readonly responseKey: TypedFT<{ channel: string }, string>; - private readonly settingsKey: GuildSettingsOfType; - - public constructor(context: WolfCommand.LoaderContext, options: ChannelConfigurationCommand.Options) { - super(context, { - permissionLevel: PermissionLevels.Administrator, - runIn: [CommandOptionsRunTypeEnum.GuildAny], - ...options - }); - - this.responseKey = options.responseKey; - this.settingsKey = options.settingsKey; - } - - public override async messageRun(message: GuildMessage, args: WolfCommand.Args) { - const channel = await args.pick(ChannelConfigurationCommand.hereOrTextChannelResolver); - - using trx = await writeSettingsTransaction(message.guild); - if (trx.settings[this.settingsKey] === channel.id) { - this.error(LanguageKeys.Misc.ConfigurationEquals); - } - - await trx.write({ [this.settingsKey]: channel.id }).submitWithAudit(message.author.id); - - const content = args.t(this.responseKey, { channel: channel.toString() }); - return send(message, content); - } - - private static hereOrTextChannelResolver = Args.make((argument, context) => { - if (argument === 'here') return Args.ok(assertNonThread(context.message.channel) as TextChannel); - return (container.stores.get('arguments').get('textChannelName') as Argument).run(argument, context); - }); -} - -export namespace ChannelConfigurationCommand { - /** - * The ChannelConfigurationCommand Options - */ - export type Options = WolfCommand.Options & { - responseKey: TypedFT<{ channel: string }, string>; - settingsKey: GuildSettingsOfType; - }; - - export type Args = WolfCommand.Args; -} diff --git a/src/lib/structures/commands/WolfArgs.ts b/src/lib/structures/commands/WolfArgs.ts deleted file mode 100644 index 5857bdb14..000000000 --- a/src/lib/structures/commands/WolfArgs.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { Args, Result, UserError, type MessageCommand } from '@sapphire/framework'; -import { ArgumentStream, Parser } from '@sapphire/lexure'; -import type { TFunction } from '@sapphire/plugin-i18next'; -import type { Message } from 'discord.js'; - -export class WolfArgs extends Args { - public override t: TFunction; - - public constructor(message: Message, command: MessageCommand, parser: ArgumentStream, context: MessageCommand.RunContext, t: TFunction) { - super(message, command, parser, context); - this.t = t; - } - - /** - * Consumes the entire parser and splits it by the delimiter, filtering out empty values. - * @param delimiter The delimiter to be used, defaults to `,`. - * @returns An array of values. - */ - public nextSplitResult({ delimiter = ',', times = Infinity }: WolfArgs.NextSplitOptions = {}): Result { - if (this.parser.finished) return this.missingArguments(); - - const values: string[] = []; - const parts = this.parser.many(); - if (parts.isNone()) return this.missingArguments(); - - const tokens = parts - .unwrap() - .reduce((acc, token) => `${acc}${token.leading}${token.value}`, '') - .split(delimiter); - for (const part of tokens) { - const trimmed = part.trim(); - if (trimmed.length === 0) continue; - - values.push(trimmed); - if (values.length === times) break; - } - - return values.length > 0 ? Args.ok(values) : this.missingArguments(); - } - - /** - * Consumes the entire parser and splits it by the delimiter, filtering out empty values. - * @param delimiter The delimiter to be used, defaults to `,`. - * @returns An array of values. - */ - public nextSplit(options?: WolfArgs.NextSplitOptions) { - return this.nextSplitResult(options).unwrapRaw(); - } - - public static from(command: MessageCommand, message: Message, parameters: string, context: MessageCommand.RunContext, t: TFunction) { - const parser = new Parser(command.strategy); - // eslint-disable-next-line @typescript-eslint/dot-notation - const args = new ArgumentStream(parser.run(command['lexer'].run(parameters))); - return new WolfArgs(message, command, args, context, t); - } -} - -export namespace WolfArgs { - export interface NextSplitOptions { - /** - * The delimiter to be used. - * @default ',' - */ - delimiter?: string; - - /** - * The maximum amount of entries to be read. - * @default Infinity - */ - times?: number; - } -} - -declare module '@sapphire/framework' { - export interface Args { - t: TFunction; - } -} diff --git a/src/lib/structures/commands/WolfCommand.ts b/src/lib/structures/commands/WolfCommand.ts deleted file mode 100644 index 5d79d5b8b..000000000 --- a/src/lib/structures/commands/WolfCommand.ts +++ /dev/null @@ -1,87 +0,0 @@ -import type { LanguageHelpDisplayOptions } from '#lib/i18n/LanguageHelp'; -import { WolfArgs } from '#lib/structures/commands/WolfArgs'; -import { - WolfCommandConstructorDefaults, - implementWolfCommandError, - implementWolfCommandPaginatedOptions, - implementWolfCommandParseConstructorPreConditionsPermissionLevel, - implementWolfCommandPreParse, - type ExtendOptions -} from '#lib/structures/commands/base/BaseWolfCommandUtilities'; -import { PermissionLevels, type TypedT } from '#lib/types'; -import { Command, UserError, type Awaitable, type MessageCommand } from '@sapphire/framework'; -import { first } from '@sapphire/iterator-utilities/first'; -import { - ChatInputCommandInteraction, - MessageContextMenuCommandInteraction, - UserContextMenuCommandInteraction, - type Message, - type Snowflake -} from 'discord.js'; - -/** - * The base class for all Wolf commands. - * @seealso {@link WolfSubcommand} for subcommand support. - */ -export abstract class WolfCommand extends Command { - public readonly guarded: boolean; - public readonly hidden: boolean; - public readonly permissionLevel: PermissionLevels; - declare public readonly detailedDescription: TypedT; - declare public readonly description: TypedT; - - public constructor(context: Command.LoaderContext, options: WolfCommand.Options) { - super(context, { ...WolfCommandConstructorDefaults, ...options }); - this.guarded = options.guarded ?? WolfCommandConstructorDefaults.guarded; - this.hidden = options.hidden ?? WolfCommandConstructorDefaults.hidden; - this.permissionLevel = options.permissionLevel ?? WolfCommandConstructorDefaults.permissionLevel; - } - - public abstract override messageRun(message: Message, args: WolfCommand.Args, context: MessageCommand.RunContext): Awaitable; - - /** - * The pre-parse method. This method can be overridden by plugins to define their own argument parser. - * @param message The message that triggered the command. - * @param parameters The raw parameters as a single string. - * @param context The command-context used in this execution. - */ - public override messagePreParse(message: Message, parameters: string, context: MessageCommand.RunContext): Promise { - return implementWolfCommandPreParse(this as MessageCommand, message, parameters, context); - } - - /** - * Retrieves the global command id from the application command registry. - * - * @remarks - * - * This method is used for slash commands, and will throw an error if the - * global command ids are empty. - */ - public getGlobalCommandId(): Snowflake { - const ids = this.applicationCommandRegistry.globalChatInputCommandIds; - if (ids.size === 0) throw new Error('The global command ids are empty.'); - return first(ids.values())!; - } - - protected error(identifier: string | UserError, context?: unknown): never { - implementWolfCommandError(identifier, context); - } - - protected override parseConstructorPreConditions(options: WolfCommand.Options): void { - super.parseConstructorPreConditions(options); - implementWolfCommandParseConstructorPreConditionsPermissionLevel(this, options.permissionLevel); - } - - public static readonly PaginatedOptions = implementWolfCommandPaginatedOptions; -} - -export namespace WolfCommand { - export type Options = ExtendOptions; - export type Args = WolfArgs; - export type LoaderContext = Command.LoaderContext; - export type RunContext = MessageCommand.RunContext; - - export type ChatInputInteraction = ChatInputCommandInteraction<'cached'>; - export type UserContextMenuInteraction = UserContextMenuCommandInteraction<'cached'>; - export type MessageContextMenuInteraction = MessageContextMenuCommandInteraction<'cached'>; -} diff --git a/src/lib/structures/commands/WolfSubcommand.ts b/src/lib/structures/commands/WolfSubcommand.ts deleted file mode 100644 index d1db7f39e..000000000 --- a/src/lib/structures/commands/WolfSubcommand.ts +++ /dev/null @@ -1,79 +0,0 @@ -import type { LanguageHelpDisplayOptions } from '#lib/i18n/LanguageHelp'; -import { WolfArgs } from '#lib/structures/commands/WolfArgs'; -import { - WolfCommandConstructorDefaults, - implementWolfCommandError, - implementWolfCommandPaginatedOptions, - implementWolfCommandParseConstructorPreConditionsPermissionLevel, - implementWolfCommandPreParse, - type ExtendOptions -} from '#lib/structures/commands/base/BaseWolfCommandUtilities'; -import { PermissionLevels, type TypedT } from '#lib/types'; -import { Command, UserError, type MessageCommand } from '@sapphire/framework'; -import { first } from '@sapphire/iterator-utilities/first'; -import { Subcommand } from '@sapphire/plugin-subcommands'; -import type { ChatInputCommandInteraction, Message, Snowflake } from 'discord.js'; - -/** - * The base class for all Wolf commands with subcommands. - * @seealso {@link WolfCommand}. - */ -export class WolfSubcommand extends Subcommand { - public readonly guarded: boolean; - public readonly hidden: boolean; - public readonly permissionLevel: PermissionLevels; - declare public readonly detailedDescription: TypedT; - public override readonly description: TypedT; - - public constructor(context: WolfSubcommand.LoaderContext, options: WolfSubcommand.Options) { - super(context, { ...WolfCommandConstructorDefaults, ...options }); - this.guarded = options.guarded ?? WolfCommandConstructorDefaults.guarded; - this.hidden = options.hidden ?? WolfCommandConstructorDefaults.hidden; - this.permissionLevel = options.permissionLevel ?? WolfCommandConstructorDefaults.permissionLevel; - this.description = options.description; - } - - /** - * The pre-parse method. This method can be overridden by plugins to define their own argument parser. - * @param message The message that triggered the command. - * @param parameters The raw parameters as a single string. - * @param context The command-context used in this execution. - */ - public override messagePreParse(message: Message, parameters: string, context: MessageCommand.RunContext): Promise { - return implementWolfCommandPreParse(this as MessageCommand, message, parameters, context); - } - - /** - * Retrieves the global command id from the application command registry. - * - * @remarks - * - * This method is used for slash commands, and will throw an error if the - * global command ids are empty. - */ - public getGlobalCommandId(): Snowflake { - const ids = this.applicationCommandRegistry.globalChatInputCommandIds; - if (ids.size === 0) throw new Error('The global command ids are empty.'); - return first(ids.values())!; - } - - protected error(identifier: string | UserError, context?: unknown): never { - implementWolfCommandError(identifier, context); - } - - protected override parseConstructorPreConditions(options: WolfSubcommand.Options): void { - super.parseConstructorPreConditions(options); - implementWolfCommandParseConstructorPreConditionsPermissionLevel(this, options.permissionLevel); - } - - public static readonly PaginatedOptions = implementWolfCommandPaginatedOptions; -} - -export namespace WolfSubcommand { - export type Options = ExtendOptions; - export type Args = WolfArgs; - export type LoaderContext = Command.LoaderContext; - export type RunContext = MessageCommand.RunContext; - - export type Interaction = ChatInputCommandInteraction<'cached'>; -} diff --git a/src/lib/structures/commands/base/BaseWolfCommandUtilities.ts b/src/lib/structures/commands/base/BaseWolfCommandUtilities.ts deleted file mode 100644 index 94f480dae..000000000 --- a/src/lib/structures/commands/base/BaseWolfCommandUtilities.ts +++ /dev/null @@ -1,79 +0,0 @@ -import type { LanguageHelpDisplayOptions } from '#lib/i18n/LanguageHelp'; -import { WolfArgs } from '#lib/structures/commands/WolfArgs'; -import { PermissionLevels, type TypedT } from '#lib/types'; -import { OWNERS } from '#root/config'; -import { seconds } from '#utils/common'; -import { Command, PreconditionContainerArray, UserError, type MessageCommand } from '@sapphire/framework'; -import { fetchT } from '@sapphire/plugin-i18next'; -import { PermissionFlagsBits, PermissionsBitField, type Message } from 'discord.js'; - -export const WolfCommandConstructorDefaults = { - cooldownDelay: seconds(10), - cooldownLimit: 2, - cooldownFilteredUsers: OWNERS, - generateDashLessAliases: true, - guarded: false, - hidden: false, - permissionLevel: PermissionLevels.Everyone -} satisfies Partial>; - -export async function implementWolfCommandPreParse( - command: MessageCommand, - message: Message, - parameters: string, - context: MessageCommand.RunContext -): Promise { - return WolfArgs.from(command, message, parameters, context, await fetchT(message)); -} - -export function implementWolfCommandError(identifier: string | UserError, context?: unknown): never { - throw typeof identifier === 'string' ? new UserError({ identifier, context }) : identifier; -} - -export function implementWolfCommandParseConstructorPreConditionsPermissionLevel( - command: Command, - permissionLevel: PermissionLevels = PermissionLevels.Everyone -): void { - if (permissionLevel === PermissionLevels.BotOwner) { - command.preconditions.append('BotOwner'); - return; - } - - const container = new PreconditionContainerArray(['BotOwner'], command.preconditions); - switch (permissionLevel) { - case PermissionLevels.Everyone: - container.append('Everyone'); - break; - case PermissionLevels.Moderator: - container.append('Moderator'); - break; - case PermissionLevels.Administrator: - container.append('Administrator'); - break; - case PermissionLevels.ServerOwner: - container.append('ServerOwner'); - break; - default: - throw new Error(`WolfCommand[${command.name}]: "permissionLevel" was specified as an invalid permission level (${permissionLevel}).`); - } - - command.preconditions.append(container); -} - -export function implementWolfCommandPaginatedOptions = ExtendOptions>(options?: T): T { - return { - cooldownDelay: seconds(15), - // Merge in all given options - ...options, - // Add all requiredPermissions set in the command, along EmbedLinks to send EmbedBuilder's - requiredClientPermissions: new PermissionsBitField(options?.requiredClientPermissions).add(PermissionFlagsBits.EmbedLinks) - } as unknown as T; -} - -export type ExtendOptions = T & { - description: TypedT; - detailedDescription: TypedT; - guarded?: boolean; - hidden?: boolean; - permissionLevel?: number; -}; diff --git a/src/lib/structures/commands/index.ts b/src/lib/structures/commands/index.ts deleted file mode 100644 index 679a67ab5..000000000 --- a/src/lib/structures/commands/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from '#lib/structures/commands/ChannelConfigurationCommand'; -export * from '#lib/structures/commands/WolfArgs'; -export * from '#lib/structures/commands/WolfCommand'; -export * from '#lib/structures/commands/WolfSubcommand'; diff --git a/src/lib/structures/data/SortedCollection.ts b/src/lib/structures/data/SortedCollection.ts deleted file mode 100644 index 6564b74d3..000000000 --- a/src/lib/structures/data/SortedCollection.ts +++ /dev/null @@ -1,229 +0,0 @@ -import { asc } from '#utils/common'; -import { isFunction } from '@sapphire/utilities'; - -/** - * Represents a collection of key-value pairs that are sorted by the key. - */ -export class SortedCollection implements Map { - /** - * The entries of this collection. - */ - readonly #entries: [K, V][] = []; - - /** - * The comparator function used to sort the collection. - */ - readonly #comparator: (a: K, b: K) => number; - - public constructor(data?: Iterable<[K, V]>, comparator: (a: K, b: K) => number = asc) { - this.#comparator = comparator; - - if (data) { - this.#entries.push(...data); - this.#entries.sort(([aKey], [bKey]) => this.#comparator(aKey, bKey)); - } - } - - /** - * Gets the number of entries in the collection. - */ - public get size() { - return this.#entries.length; - } - - /** - * Sets the value for the specified key in the collection. - * If the key already exists, the value will be updated. - * If the key does not exist, a new entry will be added to the collection. - * - * @param key - The key to set the value for. - * @param value - The value to set. - * @returns The SortedCollection instance. - */ - public set(key: K, value: V) { - let left = 0; - let right = this.#entries.length - 1; - - while (left <= right) { - const mid = (left + right) >> 1; - const midKey = this.#entries[mid][0]; - const cmp = this.#comparator(midKey, key); - if (cmp === 0) { - this.#entries[mid][1] = value; - return this; - } - - if (cmp < 0) left = mid + 1; - else right = mid - 1; - } - - this.#entries.splice(left, 0, [key, value]); - return this; - } - - /** - * Checks if the collection contains a specific key. - * - * @param key - The key to check for. - * @returns `true` if the collection contains the key, `false` otherwise. - */ - public has(key: K): boolean { - // eslint-disable-next-line unicorn/prefer-includes -- SortedCollection has no includes() method - return this.indexOf(key) !== -1; - } - - /** - * Retrieves the value associated with the specified key. - * - * @param key - The key to retrieve the value for. - * @returns The value associated with the key, or `undefined` if the key is not found. - */ - public get(key: K): V | undefined { - const index = this.indexOf(key); - return index === -1 ? undefined : this.#entries[index][1]; - } - - /** - * Returns the index of the specified key in the sorted collection. - * If the key is not found, it returns -1. - * - * @param key - The key to search for in the collection. - * @returns The index of the key, or -1 if the key is not found. - */ - public indexOf(key: K) { - let left = 0; - let right = this.#entries.length - 1; - while (left <= right) { - const mid = (left + right) >> 1; - const midKey = this.#entries[mid][0]; - const cmp = this.#comparator(midKey, key); - if (cmp === 0) return mid; - - if (cmp < 0) left = mid + 1; - else right = mid - 1; - } - - return -1; - } - - /** - * Deletes an entry from the collection based on the specified key. - * - * @param key The key of the entry to delete. - * @returns `true` if the entry was successfully deleted, `false` otherwise. - */ - public delete(key: K) { - const index = this.indexOf(key); - if (index === -1) return false; - - this.#entries.splice(index, 1); - return true; - } - - /** - * Clears all entries from the collection. - */ - public clear(): void { - this.#entries.splice(0, this.#entries.length); - } - - /** - * Identical to - * {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter | Array.filter()}, - * but returns a Collection instead of an Array. - * - * @param fn - The function to test with (should return boolean) - * @param thisArg - Value to use as `this` when executing function - * @example - * ```ts - * collection.filter(user => user.username === 'Bob'); - * ``` - */ - public filter(fn: (value: V, key: K, collection: this) => key is K2): SortedCollection; - public filter(fn: (value: V, key: K, collection: this) => value is V2): SortedCollection; - public filter(fn: (value: V, key: K, collection: this) => unknown): SortedCollection; - public filter(fn: (this: This, value: V, key: K, collection: this) => key is K2, thisArg: This): SortedCollection; - public filter(fn: (this: This, value: V, key: K, collection: this) => value is V2, thisArg: This): SortedCollection; - public filter(fn: (this: This, value: V, key: K, collection: this) => unknown, thisArg: This): SortedCollection; - public filter(fn: (value: V, key: K, collection: this) => unknown, thisArg?: unknown): SortedCollection { - if (!isFunction(fn)) throw new TypeError(`${fn} is not a function`); - if (thisArg !== undefined) fn = fn.bind(thisArg); - - const results = new SortedCollection(undefined, this.#comparator); - for (const entry of this.#entries) { - if (fn(entry[1], entry[0], this)) results.#entries.push(entry); - } - - return results; - } - - /** - * Removes items that satisfy the provided filter function. - * - * @param fn - Function used to test (should return a boolean) - * @param thisArg - Value to use as `this` when executing function - * @returns The number of removed entries - */ - public sweep(fn: (value: V, key: K, collection: this) => unknown): number; - public sweep(fn: (this: T, value: V, key: K, collection: this) => unknown, thisArg: T): number; - public sweep(fn: (value: V, key: K, collection: this) => unknown, thisArg?: unknown): number { - if (!isFunction(fn)) throw new TypeError(`${fn} is not a function`); - if (thisArg !== undefined) fn = fn.bind(thisArg); - - const previousSize = this.size; - let i = 0; - while (i < this.#entries.length) { - const [key, value] = this.#entries[i]; - if (fn(value, key, this)) this.#entries.splice(i, 1); - else i++; - } - - return previousSize - this.size; - } - - public forEach(fn: (value: V, key: K, map: this) => void, thisArg?: unknown): void { - if (!isFunction(fn)) throw new TypeError(`${fn} is not a function`); - if (thisArg !== undefined) fn = fn.bind(thisArg); - - for (const [key, value] of this.#entries) { - fn(value, key, this); - } - } - - /** - * Returns an iterator that contains all the keys in the collection. - */ - public *keys(): MapIterator { - for (const [key] of this.#entries) { - yield key; - } - } - - /** - * Returns an iterator that yields all the values in the collection. - */ - public *values(): MapIterator { - for (const [, value] of this.#entries) { - yield value; - } - } - - /** - * Returns an iterator that yields all the entries in the collection. - */ - public *entries(): MapIterator<[K, V]> { - yield* this.#entries; - } - - /** - * Returns an iterator that yields all the entries in the collection. - */ - public *[Symbol.iterator](): MapIterator<[K, V]> { - yield* this.#entries; - } - - // eslint-disable-next-line @typescript-eslint/class-literal-property-style - public get [Symbol.toStringTag](): string { - return 'SortedCollection'; - } -} diff --git a/src/lib/structures/data/index.ts b/src/lib/structures/data/index.ts deleted file mode 100644 index f304d6840..000000000 --- a/src/lib/structures/data/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from '#lib/structures/data/SortedCollection'; diff --git a/src/lib/structures/index.ts b/src/lib/structures/index.ts deleted file mode 100644 index 37c7a22d4..000000000 --- a/src/lib/structures/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -export * from '#lib/structures/AnalyticsData'; -export * from '#lib/structures/InviteStore'; -export * from '#lib/structures/SettingsMenu'; -export * from '#lib/structures/commands/index'; -export * from '#lib/structures/listeners/index'; -export * from '#lib/structures/managers'; -export * from '#lib/structures/preconditions/index'; diff --git a/src/lib/structures/listeners/AnalyticsListener.ts b/src/lib/structures/listeners/AnalyticsListener.ts deleted file mode 100644 index d1425b57e..000000000 --- a/src/lib/structures/listeners/AnalyticsListener.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { Tags } from '#lib/types/AnalyticsSchema'; -import type { Point } from '@influxdata/influxdb-client'; -import { Listener } from '@sapphire/framework'; -import { envParseBoolean } from '@skyra/env-utilities'; - -export abstract class AnalyticsListener extends Listener { - public tags: [Tags, string][] = []; - - public constructor(context: Listener.LoaderContext, options?: AnalyticsListener.Options) { - super(context, { ...options, enabled: envParseBoolean('INFLUX_ENABLED') }); - } - - public override onLoad() { - this.initTags(); - return super.onLoad(); - } - - public writePoint(point: Point) { - return this.container.client.analytics!.writeApi.writePoint(this.injectTags(point)); - } - - public writePoints(points: Point[]) { - points = points.map((point) => this.injectTags(point)); - return this.container.client.analytics!.writeApi.writePoints(points); - } - - protected injectTags(point: Point) { - for (const tag of this.tags) { - point.tag(tag[0], tag[1]); - } - return point; - } - - protected initTags() { - this.tags.push([Tags.Client, process.env.CLIENT_ID], [Tags.OriginEvent, this.event as string]); - } -} - -export namespace AnalyticsListener { - export type Options = Omit; -} diff --git a/src/lib/structures/listeners/ShardListener.ts b/src/lib/structures/listeners/ShardListener.ts deleted file mode 100644 index 6a5d51b3f..000000000 --- a/src/lib/structures/listeners/ShardListener.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Listener } from '@sapphire/framework'; -import { bold, magenta } from 'colorette'; - -export abstract class ShardListener extends Listener { - protected abstract readonly title: string; - - protected header(shardId: number): string { - return `${bold(magenta(`[SHARD ${shardId}]`))} ${this.title}`; - } -} diff --git a/src/lib/structures/listeners/index.ts b/src/lib/structures/listeners/index.ts deleted file mode 100644 index a92c9a760..000000000 --- a/src/lib/structures/listeners/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from '#lib/structures/listeners/AnalyticsListener'; -export * from '#lib/structures/listeners/ShardListener'; diff --git a/src/lib/structures/managers/index.ts b/src/lib/structures/managers/index.ts deleted file mode 100644 index 3855d5a1f..000000000 --- a/src/lib/structures/managers/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from '#lib/structures/managers/LockdownManager'; diff --git a/src/lib/structures/preconditions/PermissionsPrecondition.ts b/src/lib/structures/preconditions/PermissionsPrecondition.ts deleted file mode 100644 index 307d7ea80..000000000 --- a/src/lib/structures/preconditions/PermissionsPrecondition.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { readSettings, readSettingsPermissionNodes } from '#lib/database/settings'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import type { WolfCommand } from '#lib/structures'; -import { PermissionLevels, type GuildMessage } from '#lib/types'; -import { isAdmin, isGuildOwner } from '#utils/functions'; -import { AllFlowsPrecondition, Identifiers, Precondition, type PreconditionOptions } from '@sapphire/framework'; - -export abstract class PermissionsPrecondition extends AllFlowsPrecondition { - private readonly guildOnly: boolean; - - public constructor(context: Precondition.LoaderContext, options: PermissionsPrecondition.Options = {}) { - super(context, options); - this.guildOnly = options.guildOnly ?? true; - } - - public override async messageRun(message: GuildMessage, command: WolfCommand, context: Precondition.Context): Precondition.AsyncResult { - // If not in a guild, resolve on an error: - if (message.guild === null || message.member === null) { - return this.guildOnly ? this.error({ identifier: Identifiers.PreconditionGuildOnly }) : this.ok(); - } - - // If it should skip, go directly to handle: - if (await this.shouldRun(message, command)) { - const settings = await readSettings(message.guild); - const nodes = readSettingsPermissionNodes(settings); - const result = nodes.run(message.member, command); - if (result) return this.ok(); - if (result === false) return this.error({ identifier: LanguageKeys.Preconditions.PermissionNodes }); - } - - // Run the specific precondition's logic: - return this.handle(message, command, context); - } - - // Handled by Discord's permissions system: - public override chatInputRun() { - return this.ok(); - } - - // Handled by Discord's permissions system: - public override contextMenuRun() { - return this.ok(); - } - - public abstract handle( - message: GuildMessage, - command: WolfCommand, - context: PermissionsPrecondition.LoaderContext - ): PermissionsPrecondition.Result; - - private async shouldRun(message: GuildMessage, command: WolfCommand) { - // Guarded commands cannot be modified: - if (command.guarded) return false; - // Bot-owner commands cannot be modified: - if (command.permissionLevel === PermissionLevels.BotOwner) return false; - // If the author is owner of the guild, skip: - if (isGuildOwner(message.member)) return false; - // If the author is administrator of the guild, skip: - if (await isAdmin(message.member)) return false; - // In any other case, permission nodes should always run: - return true; - } -} - -export namespace PermissionsPrecondition { - export type LoaderContext = Precondition.Context; - export type Result = Precondition.Result; - export type AsyncResult = Precondition.AsyncResult; - export interface Options extends PreconditionOptions { - guildOnly?: boolean; - } -} diff --git a/src/lib/structures/preconditions/index.ts b/src/lib/structures/preconditions/index.ts deleted file mode 100644 index 0f00c5c8e..000000000 --- a/src/lib/structures/preconditions/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from '#lib/structures/preconditions/PermissionsPrecondition'; diff --git a/src/lib/types/AnalyticsSchema.ts b/src/lib/types/AnalyticsSchema.ts deleted file mode 100644 index c1d04b067..000000000 --- a/src/lib/types/AnalyticsSchema.ts +++ /dev/null @@ -1,27 +0,0 @@ -export const enum Points { - Guilds = 'guilds', - Users = 'users', - Commands = 'commands', - PerCoreCPULoad = 'per_core_cpu_load', - Memory = 'memory', - MessageCount = 'message_count' -} - -export const enum Tags { - Shard = 'shard', - Client = 'client_id', - Action = 'action', - OriginEvent = 'origin_event', - MigrationName = 'migration_name' -} - -export const enum CommandCategoryTypes { - Category = 'category' -} - -export const enum Actions { - Addition = 'addition', - Subtraction = 'subtraction', - Sync = 'sync', - Migration = 'migration' -} diff --git a/src/lib/types/Augments.d.ts b/src/lib/types/Augments.d.ts deleted file mode 100644 index 140ddebe9..000000000 --- a/src/lib/types/Augments.d.ts +++ /dev/null @@ -1,185 +0,0 @@ -/* eslint-disable @typescript-eslint/unified-signatures */ -import type { - CommandAutoDelete, - DisabledCommandChannel, - GuildSettingsOfType, - PermissionsNode, - ReactionRole, - SerializerStore, - StickyRole, - UniqueRoleSet -} from '#lib/database'; -import type { GuildMemberFetchQueue } from '#lib/discord/GuildMemberFetchQueue'; -import type { WorkerManager } from '#lib/moderation/workers/WorkerManager'; -import type { ScheduleManager, TaskStore } from '#lib/schedule'; -import type { AnalyticsData, InviteCodeValidEntry, InviteStore, WolfCommand } from '#lib/structures'; -import type { Events } from '#lib/types'; -import type { TaskErrorPayload } from '#lib/types/Internals'; -import type { TypedFT, TypedT } from '#lib/types/Utils'; -import type { LongLivingInteractionCollector } from '#utils/LongLivingInteractionCollector'; -import type { LLRCData, LongLivingReactionCollector } from '#utils/LongLivingReactionCollector'; -import type { EmojiObject } from '#utils/functions'; -import type { EmbedBuilder } from '@discordjs/builders'; -import type { API } from '@discordjs/core/http-only'; -import type { Piece, Store } from '@sapphire/framework'; -import type { Awaitable, Nullish } from '@sapphire/utilities'; -import type { ArrayString, BooleanString, IntegerString } from '@skyra/env-utilities'; -import type { Guild, GuildChannel, NewsChannel, Role, Snowflake, TextChannel, User } from 'discord.js'; - -declare global { - namespace PrismaJson { - export type PermissionNodeEntries = PermissionsNode[]; - export type CommandAutoDeleteEntries = CommandAutoDelete[]; - export type DisabledCommandChannelEntries = DisabledCommandChannel[]; - export type StickyRoleEntries = StickyRole[]; - export type ReactionRoleEntries = ReactionRole[]; - export type UniqueRoleSetEntries = UniqueRoleSet[]; - export type AuditEventChanges = import('#lib/database').AuditEventChanges; - } -} - -declare module 'discord.js' { - interface Client { - readonly dev: boolean; - readonly analytics: AnalyticsData | null; - readonly guildMemberFetchQueue: GuildMemberFetchQueue; - readonly invites: InviteStore; - readonly lliCollectors: Set; - readonly llrCollectors: Set; - readonly schedules: ScheduleManager; - readonly version: string; - readonly webhookError: WebhookClient | null; - } - - interface ClientOptions { - nms?: { - role?: number; - everyone?: number; - }; - schedule?: { - interval: number; - }; - } -} - -declare module '@sapphire/pieces' { - interface Container { - api?: API; - schedule: ScheduleManager; - workers: WorkerManager; - } - - interface StoreRegistryEntries { - tasks: TaskStore; - serializers: SerializerStore; - } -} - -declare module '@sapphire/framework' { - interface ArgType { - case: number; - channelName: GuildChannel; - cleanString: string; - command: WolfCommand; - commandMatch: string; - commandName: WolfCommand; - duration: Date; - emoji: EmojiObject; - invite: InviteCodeValidEntry; - language: string; - piece: Piece; - range: number[]; - reset: true; - roleName: Role; - snowflake: Snowflake; - store: Store; - textChannelName: TextChannel; - textOrNewsChannelName: TextChannel | NewsChannel; - time: Date; - timespan: number; - userName: User; - } - - interface Preconditions { - Administrator: never; - BotOwner: never; - Everyone: never; - Moderator: never; - ServerOwner: never; - } - - interface SapphireClient { - emit(event: Events.Error, error: Error): boolean; - emit(event: Events.AnalyticsSync, guilds: number, users: number): boolean; - emit(event: Events.CommandUsageAnalytics, command: string, category: string): boolean; - emit( - event: Events.GuildMessageLog, - guild: Guild, - channelId: string | Nullish, - key: GuildSettingsOfType, - makeMessage: () => Awaitable - ): boolean; - emit(event: Events.ReactionBlocked, data: LLRCData, emoji: string): boolean; - emit(event: Events.ResourceAnalyticsSync): boolean; - emit(event: Events.TaskError, error: Error, payload: TaskErrorPayload): boolean; - emit(event: string | symbol, ...args: any[]): boolean; - } -} - -declare module 'i18next' { - export interface TFunction { - lng: string; - ns?: string; - - (key: TypedT): TReturn; - (key: TypedFT, options?: TArgs): TReturn; - } -} - -declare module '@skyra/env-utilities' { - export interface Env { - CLIENT_NAME: string; - CLIENT_VERSION: string; - CLIENT_PREFIX: string; - CLIENT_REGEX_PREFIX: string; - CLIENT_OWNERS: ArrayString; - CLIENT_ID: string; - CLIENT_SHARDS: string; - - CLIENT_PRESENCE_NAME: string; - CLIENT_PRESENCE_TYPE: string; - - API_ENABLED: BooleanString; - API_ORIGIN: string; - API_PORT: IntegerString; - API_PREFIX: string; - API_HOST: string; - - OAUTH_COOKIE: string; - OAUTH_DOMAIN_OVERWRITE: string; - OAUTH_REDIRECT_URI: string; - OAUTH_SCOPE: ArrayString; - OAUTH_SECRET: string; - - INFLUX_ENABLED: BooleanString; - INFLUX_URL: string; - INFLUX_PROXY_URL: string; - INFLUX_TOKEN: string; - INFLUX_ORG: string; - INFLUX_ORG_ANALYTICS_BUCKET: string; - - WEBHOOK_ERROR_ID: string; - WEBHOOK_ERROR_TOKEN: string; - - WORKER_COUNT: IntegerString; - - DISCORD_TOKEN: string; - VOID_BOTS_TOKEN: string; - BOTS_FOR_DISCORD_TOKEN: string; - DISCORD_BOT_LIST_TOKEN: string; - DISCORD_BOTS_TOKEN: string; - SENTRY_URL: string; - TOP_GG_TOKEN: string; - DATABASE_URL: string; - } -} diff --git a/src/lib/types/Discord.ts b/src/lib/types/Discord.ts deleted file mode 100644 index 83d4bf9fb..000000000 --- a/src/lib/types/Discord.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { GuildMember, Message, OmitPartialGroupDMChannel } from 'discord.js'; - -export type GuildMessage = Message & { member: GuildMember }; -export type DMMessage = Message; -export type NonGroupMessage = OmitPartialGroupDMChannel>; diff --git a/src/lib/types/Enums.ts b/src/lib/types/Enums.ts deleted file mode 100644 index cf21fc0ee..000000000 --- a/src/lib/types/Enums.ts +++ /dev/null @@ -1,59 +0,0 @@ -export const enum Events { - AnalyticsSync = 'analyticsSync', - Error = 'error', - PreMessageParsed = 'preMessageParsed', - ArgumentError = 'argumentError', - CommandUsageAnalytics = 'commandUsageAnalytics', - CoreSettingsDelete = 'coreSettingsDelete', - CoreSettingsUpdate = 'coreSettingsUpdate', - Disconnect = 'disconnect', - EventError = 'eventError', - GuildBanAdd = 'guildBanAdd', - GuildBanRemove = 'guildBanRemove', - GuildCreate = 'guildCreate', - GuildDelete = 'guildDelete', - GuildMemberUpdate = 'guildMemberUpdate', - GuildMessageDelete = 'guildMessageDelete', - GuildMessageLog = 'guildMessageLog', - GuildMessageUpdate = 'guildMessageUpdate', - GuildUserMessage = 'guildUserMessage', - GuildUserMessageSocialPointsAddUser = 'guildUserMessageSocialPointsAddUser', - GuildUserMessageSocialPointsAddMember = 'guildUserMessageSocialPointsAddMember', - GuildUserMessageSocialPointsAddMemberReward = 'guildUserMessageSocialPointsAddMemberReward', - MentionSpamExceeded = 'mentionSpamExceeded', - MentionSpamWarning = 'mentionSpamWarning', - MessageCreate = 'messageCreate', - MessageDelete = 'messageDelete', - MessageDeleteBulk = 'messageDeleteBulk', - MessageUpdate = 'messageUpdate', - ModerationEntryAdd = 'moderationEntryAdd', - ModerationEntryEdit = 'moderationEntryEdit', - NotMutedMemberAdd = 'notMutedMemberAdd', - Raw = 'raw', - RawMemberAdd = 'rawMemberAdd', - RawMemberRemove = 'rawMemberRemove', - RawMessageCreate = 'rawMessageCreate', - RawReactionAdd = 'rawReactionAdd', - RawReactionRemove = 'rawReactionRemove', - ReactionBlocked = 'reactionBlocked', - Reconnecting = 'reconnecting', - ResourceAnalyticsSync = 'resourceAnalyticsSync', - SettingsUpdate = 'settingsUpdate', - TaskError = 'taskError', - UnhandledRejection = 'unhandledRejection', - UserMessage = 'userMessage' -} - -export const enum PermissionLevels { - Everyone = 0, - Moderator = 5, - Administrator = 6, - ServerOwner = 7, - BotOwner = 10 -} - -export const enum Schedules { - Poststats = 'poststats', - SyncResourceAnalytics = 'syncResourceAnalytics', - Reminder = 'reminder' -} diff --git a/src/lib/types/Internals.ts b/src/lib/types/Internals.ts deleted file mode 100644 index f8c00b6ee..000000000 --- a/src/lib/types/Internals.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { ScheduleEntry, Task } from '#lib/schedule'; -import type { IPieceError } from '@sapphire/framework'; - -export interface TaskErrorPayload extends IPieceError { - piece: Task; - entry: ScheduleEntry; -} diff --git a/src/lib/types/Utils.ts b/src/lib/types/Utils.ts deleted file mode 100644 index cca099ab7..000000000 --- a/src/lib/types/Utils.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* eslint-disable @typescript-eslint/ban-types */ -export type TypedT = string & { __type__: TCustom }; -export type GetTypedT> = T extends TypedT ? U : never; - -export function T(k: string): TypedT { - return k as TypedT; -} - -export type TypedFT = string & { __args__: TArgs; __return__: TReturn }; -export type GetTypedFTArgs> = T extends TypedFT ? U : never; -export type GetTypedFTReturn> = T extends TypedFT ? U : never; - -export function FT(k: string): TypedFT { - return k as TypedFT; -} - -export interface Value { - value: T; -} - -export interface Values { - values: readonly T[]; - count: number; -} - -export interface Difference { - previous: T; - next: T; -} - -export interface Parameter { - parameter: string; -} diff --git a/src/lib/types/index.ts b/src/lib/types/index.ts deleted file mode 100644 index 76db9bf23..000000000 --- a/src/lib/types/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from '#lib/types/AnalyticsSchema'; -export * from '#lib/types/Discord'; -export * from '#lib/types/Enums'; -export * from '#lib/types/Internals'; -export * from '#lib/types/Utils'; diff --git a/src/lib/util/External/escapeMarkdown.ts b/src/lib/util/External/escapeMarkdown.ts deleted file mode 100644 index e078c0a50..000000000 --- a/src/lib/util/External/escapeMarkdown.ts +++ /dev/null @@ -1,204 +0,0 @@ -/** - * Copyright 2015 - 2020 Amish Shah - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * The escape markdown options. - */ -export interface EscapeMarkdownOptions { - /** - * Whether or not to escape codeblocks - * @default true - */ - codeBlock?: boolean; - - /** - * Whether or not to escape inline codes - * @default true - */ - inlineCode?: boolean; - - /** - * Whether or not to escape bold text - * @default true - */ - bold?: boolean; - - /** - * Whether or not to escape italic text - * @default true - */ - italic?: boolean; - - /** - * Whether or not to escape underline text - * @default true - */ - underline?: boolean; - - /** - * Whether or not to escape strikethrough text - * @default true - */ - strikethrough?: boolean; - - /** - * Whether or not to escape spoiler text - * @default true - */ - spoiler?: boolean; - - /** - * Whether or not to escape codeblock content - * @default true - */ - codeBlockContent?: boolean; - - /** - * Whether or not to escape inline code content - * @default true - */ - inlineCodeContent?: boolean; -} - -/** - * Escapes any Discord-flavour markdown in a string - * @param text Content to escape - * @param options What types of markdown to escape. Any undefined options are defaulted to `true` - */ -export function escapeMarkdown( - text: string, - { - codeBlock = true, - inlineCode = true, - bold = true, - italic = true, - underline = true, - strikethrough = true, - spoiler = true, - codeBlockContent = true, - inlineCodeContent = true - }: Partial = {} -): string { - if (!codeBlockContent) { - return text - .split('```') - .map((subString, index, array) => { - if (index % 2 && index !== array.length - 1) return subString; - return escapeMarkdown(subString, { - inlineCode, - bold, - italic, - underline, - strikethrough, - spoiler, - inlineCodeContent - }); - }) - .join(codeBlock ? '\\`\\`\\`' : '```'); - } - if (!inlineCodeContent) { - return text - .split(/(?<=^|[^`])`(?=[^`]|$)/g) - .map((subString, index, array) => { - if (index % 2 && index !== array.length - 1) return subString; - return escapeMarkdown(subString, { - codeBlock, - bold, - italic, - underline, - strikethrough, - spoiler - }); - }) - .join(inlineCode ? '\\`' : '`'); - } - if (inlineCode) text = escapeInlineCode(text); - if (codeBlock) text = escapeCodeBlock(text); - if (italic) text = escapeItalic(text); - if (bold) text = escapeBold(text); - if (underline) text = escapeUnderline(text); - if (strikethrough) text = escapeStrikethrough(text); - if (spoiler) text = escapeSpoiler(text); - return text; -} - -/** - * Escapes bold markdown in a string - * @param text Content to escape - */ -export function escapeBold(text: string): string { - let i = 0; - return text.replace(/\*\*(\*)?/g, (_, match) => { - if (match) return ++i % 2 ? `${match}\\*\\*` : `\\*\\*${match}`; - return '\\*\\*'; - }); -} - -/** - * Escapes italic markdown in a string - * @param text Content to escape - */ -export function escapeItalic(text: string): string { - let i = 0; - return (text = text.replace(/(?<=^|[^*])\*([^*]|\*\*|$)/g, (_, match) => { - if (match === '**' || match === '__') return ++i % 2 ? `\\*${match}` : `${match}\\*`; - return `\\*${match}`; - })); -} - -/** - * Escapes underline markdown in a string - * @param text Content to escape - */ -export function escapeUnderline(text: string): string { - let i = 0; - return text.replace(/__(_)?/g, (_, match) => { - if (match) return ++i % 2 ? `${match}\\_\\_` : `\\_\\_${match}`; - return '\\_\\_'; - }); -} - -/** - * Escapes inline code markdown in a string - * @param text Content to escape - */ -export function escapeInlineCode(text: string): string { - return text.replace(/(?<=^|[^`])`(?=[^`]|$)/g, '\\`'); -} - -/** - * Escapes spoiler markdown in a string - * @param text Content to escape - */ -export function escapeSpoiler(text: string): string { - return text.replace(/\|\|/g, '\\|\\|'); -} - -/** - * Escapes strikethrough markdown in a string - * @param text Content to escape - */ -export function escapeStrikethrough(text: string): string { - return text.replace(/~~/g, '\\~\\~'); -} - -/** - * Escapes code block markdown in a string - * @param text Content to escape - */ -export function escapeCodeBlock(text: string) { - return text.replace(/```/g, '\\`\\`\\`'); -} diff --git a/src/lib/util/LongLivingInteractionCollector.ts b/src/lib/util/LongLivingInteractionCollector.ts deleted file mode 100644 index 2ada0d5a0..000000000 --- a/src/lib/util/LongLivingInteractionCollector.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { minutes } from '#utils/common'; -import { container } from '@sapphire/framework'; -import { noop } from '@sapphire/utilities'; -import type { MessageComponentInteraction } from 'discord.js'; - -export type LongLivingInteractionCollectorListener = (interaction: MessageComponentInteraction) => void; - -export class LongLivingInteractionCollector { - public listener: LongLivingInteractionCollectorListener | null; - public endListener: (() => void) | null; - - private _timer: NodeJS.Timeout | null = null; - - public constructor(listener: LongLivingInteractionCollectorListener | null = null, endListener: (() => void) | null = null) { - this.listener = listener; - this.endListener = endListener; - container.client.lliCollectors.add(this); - } - - public setListener(listener: LongLivingInteractionCollectorListener | null) { - this.listener = listener; - return this; - } - - public setEndListener(listener: () => void) { - this.endListener = listener; - return this; - } - - public get ended(): boolean { - return !container.client.lliCollectors.has(this); - } - - public send(interaction: MessageComponentInteraction): void { - if (this.listener) this.listener(interaction); - } - - public setTime(time: number) { - if (this._timer) clearTimeout(this._timer); - if (time === -1) this._timer = null; - else this._timer = setTimeout(() => this.end(), time); - return this; - } - - public end() { - if (!container.client.lliCollectors.delete(this)) return this; - - if (this._timer) { - clearTimeout(this._timer); - this._timer = null; - } - if (this.endListener) { - process.nextTick(this.endListener.bind(null)); - this.endListener = null; - } - return this; - } - - public static collectOne({ filter = () => true, time = minutes(5) }: LLICCollectOneOptions = {}) { - return new Promise((resolve) => { - const llic = new LongLivingInteractionCollector( - (interaction) => { - if (filter(interaction)) { - resolve(interaction); - llic.setEndListener(noop).end(); - } - }, - () => { - llic.listener = null; - resolve(null); - } - ).setTime(time); - }); - } -} - -export interface LLICCollectOneOptions { - filter?: (interaction: MessageComponentInteraction) => boolean; - time?: number; -} diff --git a/src/lib/util/LongLivingReactionCollector.ts b/src/lib/util/LongLivingReactionCollector.ts deleted file mode 100644 index c1cb89930..000000000 --- a/src/lib/util/LongLivingReactionCollector.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { minutes } from '#utils/common'; -import type { GuildTextBasedChannelTypes } from '@sapphire/discord.js-utilities'; -import { container } from '@sapphire/framework'; -import { noop } from '@sapphire/utilities'; -import type { Guild, User } from 'discord.js'; - -export type LongLivingReactionCollectorListener = (reaction: LLRCData) => void; - -export class LongLivingReactionCollector { - public listener: LongLivingReactionCollectorListener | null; - public endListener: (() => void) | null; - - private _timer: NodeJS.Timeout | null = null; - - public constructor(listener: LongLivingReactionCollectorListener | null = null, endListener: (() => void) | null = null) { - this.listener = listener; - this.endListener = endListener; - container.client.llrCollectors.add(this); - } - - public setListener(listener: LongLivingReactionCollectorListener | null) { - this.listener = listener; - return this; - } - - public setEndListener(listener: () => void) { - this.endListener = listener; - return this; - } - - public get ended(): boolean { - return !container.client.llrCollectors.has(this); - } - - public send(reaction: LLRCData): void { - if (this.listener) this.listener(reaction); - } - - public setTime(time: number) { - if (this._timer) clearTimeout(this._timer); - if (time === -1) this._timer = null; - else this._timer = setTimeout(() => this.end(), time); - return this; - } - - public end() { - if (!container.client.llrCollectors.delete(this)) return this; - - if (this._timer) { - clearTimeout(this._timer); - this._timer = null; - } - if (this.endListener) { - process.nextTick(this.endListener.bind(null)); - this.endListener = null; - } - return this; - } - - public static collectOne({ filter = () => true, time = minutes(5) }: LLRCCollectOneOptions = {}) { - return new Promise((resolve) => { - const llrc = new LongLivingReactionCollector( - (reaction) => { - if (filter(reaction)) { - resolve(reaction); - llrc.setEndListener(noop).end(); - } - }, - () => { - resolve(null); - } - ).setTime(time); - }); - } -} - -export interface LLRCCollectOneOptions { - filter?: (reaction: LLRCData) => boolean; - time?: number; -} - -export interface LLRCDataEmoji { - animated: boolean; - id: string | null; - managed: boolean | null; - name: string | null; - requireColons: boolean | null; - roles: string[] | null; - user: User | { id: string }; -} - -export interface LLRCData { - channel: GuildTextBasedChannelTypes; - emoji: LLRCDataEmoji; - guild: Guild; - messageId: string; - userId: string; -} diff --git a/src/lib/util/Timers.ts b/src/lib/util/Timers.ts deleted file mode 100644 index e1eb2142b..000000000 --- a/src/lib/util/Timers.ts +++ /dev/null @@ -1,34 +0,0 @@ -export function setAccurateTimeout(fn: (...args: T) => void, delay: number, ...args: T) { - const end = Date.now() + delay; - const context: AccurateTimeout = { - timeout: null!, - fn, - cb(...args: T) { - const remaining = end - Date.now(); - if (remaining < 1) { - fn(...args); - } else { - // eslint-disable-next-line @typescript-eslint/unbound-method - context.timeout = setTimeout(context.cb, delay, ...args).unref(); - } - }, - stop() { - clearAccurateTimeout(context); - } - }; - - // eslint-disable-next-line @typescript-eslint/unbound-method - context.timeout = setTimeout(context.cb, delay, ...args).unref(); - return context; -} - -export function clearAccurateTimeout(context: AccurateTimeout) { - clearTimeout(context.timeout); -} - -export interface AccurateTimeout { - timeout: NodeJS.Timeout; - fn(...args: T): void; - cb(...args: T): void; - stop(): void; -} diff --git a/src/lib/util/bits.ts b/src/lib/util/bits.ts deleted file mode 100644 index 161c0ddb9..000000000 --- a/src/lib/util/bits.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { BitField, enumToObject } from '@sapphire/bitfield'; -import { objectEntries, omitKeysFromObject } from '@sapphire/utilities'; -import { GuildSystemChannelFlags, PermissionFlagsBits } from 'discord.js'; - -export const PermissionsBits = new BitField(omitKeysFromObject(PermissionFlagsBits, 'ManageEmojisAndStickers')); -export const PermissionsBitsList = objectEntries(PermissionsBits.flags); -export function toPermissionsArray(bits: bigint) { - return PermissionsBits.toArray(bits); -} - -export const SystemChannelFlag = new BitField(enumToObject(GuildSystemChannelFlags)); -export const SystemChannelFlagList = objectEntries(SystemChannelFlag.flags); -export function toChannelsArray(bits: number) { - return SystemChannelFlag.toArray(bits); -} diff --git a/src/lib/util/common/error.ts b/src/lib/util/common/error.ts deleted file mode 100644 index 0dbe9654d..000000000 --- a/src/lib/util/common/error.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { ResultError, UserError } from '@sapphire/framework'; -import type { TFunction } from '@sapphire/plugin-i18next'; -import { DiscordAPIError, HTTPError, RESTJSONErrorCodes } from 'discord.js'; -import { exists } from 'i18next'; - -const Root = LanguageKeys.Errors; - -export function stringifyError(t: TFunction, error: unknown): string { - switch (typeof error) { - case 'string': - return stringifyErrorString(t, error); - case 'number': - case 'bigint': - case 'boolean': - case 'undefined': - case 'symbol': - case 'function': - return String(error); - case 'object': - return stringifyErrorObject(t, error); - } -} - -function stringifyErrorString(t: TFunction, error: string): string { - return exists(error) ? (t(error) as string) : error; -} - -function stringifyErrorObject(t: TFunction, error: object | null): string { - return error instanceof Error ? stringifyErrorException(t, error) : String(error); -} - -const isSuppressedError = - typeof SuppressedError === 'undefined' - ? (error: Error): error is SuppressedError => 'error' in error && 'suppressed' in error - : (error: Error): error is SuppressedError => error instanceof SuppressedError; - -function stringifyErrorException(t: TFunction, error: Error): string { - if (error.name === 'AbortError') return t(LanguageKeys.System.DiscordAbortError); - if (error instanceof UserError) return t(error.identifier, error.context as any) as string; - if (error instanceof ResultError) return stringifyError(t, error.value); - if (error instanceof DiscordAPIError) return stringifyDiscordAPIError(t, error); - if (error instanceof HTTPError) return stringifyHTTPError(t, error); - if (error instanceof AggregateError) return error.errors.map((value) => stringifyError(t, value)).join('\n'); - if (isSuppressedError(error)) return stringifyError(t, error.suppressed); - return error.message; -} - -function stringifyDiscordAPIError(t: TFunction, error: DiscordAPIError) { - switch (error.code) { - case RESTJSONErrorCodes.UnknownChannel: - return t(Root.GenericUnknownChannel); - case RESTJSONErrorCodes.UnknownGuild: - return t(Root.GenericUnknownGuild); - case RESTJSONErrorCodes.UnknownMember: - return t(Root.GenericUnknownMember); - case RESTJSONErrorCodes.UnknownMessage: - return t(Root.GenericUnknownMessage); - case RESTJSONErrorCodes.UnknownRole: - return t(Root.GenericUnknownRole); - case RESTJSONErrorCodes.MissingAccess: - return t(Root.GenericMissingAccess); - default: - return error.message; - } -} - -function stringifyHTTPError(t: TFunction, error: HTTPError) { - switch (error.status) { - case 500: - return t(Root.GenericDiscordInternalServerError); - case 502: - case 504: - return t(Root.GenericDiscordGateway); - case 503: - return t(Root.GenericDiscordUnavailable); - default: - return error.message; - } -} diff --git a/src/lib/util/common/guild.ts b/src/lib/util/common/guild.ts deleted file mode 100644 index 3ce25777c..000000000 --- a/src/lib/util/common/guild.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { container } from '@sapphire/framework'; -import type { Guild, GuildResolvable } from 'discord.js'; - -export function resolveGuild(resolvable: GuildResolvable): Guild { - const guild = container.client.guilds.resolve(resolvable); - if (guild === null) throw new TypeError(`${resolvable} resolved to null.`); - - return guild; -} diff --git a/src/lib/util/common/index.ts b/src/lib/util/common/index.ts deleted file mode 100644 index a98e2b0f0..000000000 --- a/src/lib/util/common/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -export * from '#utils/common/comparators'; -export * from '#utils/common/error'; -export * from '#utils/common/guards'; -export * from '#utils/common/guild'; -export * from '#utils/common/parse'; -export * from '#utils/common/promises'; -export * from '#utils/common/times'; diff --git a/src/lib/util/common/parse.ts b/src/lib/util/common/parse.ts deleted file mode 100644 index 347c9d34a..000000000 --- a/src/lib/util/common/parse.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { isNullishOrEmpty } from '@sapphire/utilities'; - -export function maybeParseNumber(value: string | bigint | null | undefined): number | null { - if (isNullishOrEmpty(value)) return null; - return Number(value); -} - -export function maybeParseDate(value: string | null | undefined): number | null { - if (isNullishOrEmpty(value)) return null; - return Date.parse(value); -} diff --git a/src/lib/util/constants.ts b/src/lib/util/constants.ts deleted file mode 100644 index 9fa139b95..000000000 --- a/src/lib/util/constants.ts +++ /dev/null @@ -1,151 +0,0 @@ -import { getRootData } from '@sapphire/pieces'; -import { PermissionFlagsBits } from 'discord.js'; -import { join } from 'node:path'; - -export const mainFolder = getRootData().root; -export const rootFolder = join(mainFolder, '..'); - -export const ZeroWidthSpace = '\u200B'; -export const LongWidthSpace = '\u3000'; - -export const EmojiData = { - MessageAttachmentIcon: { id: '1262394450580340786', name: 'MessageAttachmentIcon', animated: false }, - IntegrationIcon: { id: '1251906194759749653', name: 'IntegrationIcon', animated: false }, - MembersIcon: { id: '1262394698287550474', name: 'MembersIcon', animated: false } -} as const; - -export const ModeratorPermissionsList = [ - ['ManageChannels', PermissionFlagsBits.ManageChannels], - ['ManageRoles', PermissionFlagsBits.ManageRoles], - ['CreateGuildExpressions', PermissionFlagsBits.CreateGuildExpressions], - ['ManageGuildExpressions', PermissionFlagsBits.ManageGuildExpressions], - ['ManageWebhooks', PermissionFlagsBits.ManageWebhooks], - ['ManageGuild', PermissionFlagsBits.ManageGuild], - ['KickMembers', PermissionFlagsBits.KickMembers], - ['BanMembers', PermissionFlagsBits.BanMembers], - ['ModerateMembers', PermissionFlagsBits.ModerateMembers], - ['MentionEveryone', PermissionFlagsBits.MentionEveryone], - ['ManageMessages', PermissionFlagsBits.ManageMessages], - ['ManageThreads', PermissionFlagsBits.ManageThreads], - ['CreateEvents', PermissionFlagsBits.CreateEvents], - ['ManageEvents', PermissionFlagsBits.ManageEvents], - ['Administrator', PermissionFlagsBits.Administrator] -] as const; - -export const ModeratorPermissionsBits = ModeratorPermissionsList.reduce((acc, [, bit]) => acc | bit, 0n); - -export const enum Emojis { - // ArrowB = '<:ArrowB:694594285269680179>', - // ArrowBL = '<:ArrowBL:694594285118685259>', - // ArrowBR = '<:ArrowBR:694594285445578792>', - // ArrowL = '<:ArrowL:694594285521207436>', - // ArrowR = '<:ArrowR:694594285466812486>', - // ArrowT = '<:ArrowT:694594285487652954>', - // ArrowTL = '<:ArrowTL:694594285625933854>', - // ArrowTR = '<:ArrowTR:694594285412155393>', - ArrowLeft = '<:ArrowL:973978245580075069>', - ArrowRight = '<:ArrowR:973978026536747008>', - ArrowLeftFast = '<:ArrowFastL:973976973120528484>', - ArrowRightFast = '<:ArrowFastR:973977208978800640>', - Stop = '<:Stop:973961000313303060>', - BoostLevel1 = '<:boostlvl1:935169049523019786>', - BoostLevel2 = '<:boostlvl2:935169110311063612>', - BoostLevel3 = '<:boostlvl3:935169145056686101>', - BoostLevel4 = '<:boostlvl4:935169181362569246>', - BoostLevel5 = '<:boostlvl5:935170651117998080>', - BoostLevel6 = '<:boostlvl6:935170683653193788>', - BoostLevel7 = '<:boostlvl7:935170720365944942>', - BoostLevel8 = '<:boostlvl8:935170763894439996>', - BoostLevel9 = '<:boostlvl9:935170794374447184>', - Bot = '<:bot:1262395021173456916>', - IntegrationIcon = '<:IntegrationIcon:1251906194759749653>', - Frame = '<:frame:1262396085176107040>', - GreenTick = '<:greenTick:1043562833905987685>', - GreenTickSerialized = 's1043562833905987685', - Loading = '', - RedCross = '<:redCross:1043562794336919605>', - Calendar = '<:calendar_icon:1262390721399492650>', - Hourglass = '<:hourglass:1262391693823578245>', - Member = '<:member:1262381522942558208>', - ShieldMember = '<:shield_member:1262389159155335198>', - Moderator = '<:moderator:1262383567388938240>', - AutoModerator = '<:auto_moderator:1226106862147993650>', - SpammerIcon = '<:spammer:1262395235640676353>', - QuarantinedIcon = '<:quarantined:1262395690143973396>', - Reply = '<:reply:1262387069909733406>', - ReplyInactive = '<:reply_inactive:1262386545529196568>', - Flag = '<:flag:1262387528774848522>', - FlagInactive = '<:flag_inactive:1262387790348419129>', - Timer = '<:timer:985524723490381826>', - Bucket = '<:bucket:1262384919783411813>', - Delete = '<:delete:1262382721276186704>', - DeleteInactive = '<:delete_inactive:1262382743115923478>', - Timeout = '<:timeout:1262379856470212659>', - Kick = '<:kick:1262378332633174017>', - Softban = '<:softban:1262384411245150208>', - Ban = '<:ban:1262378308050489468>' -} - -export const enum BrandingColors { - Primary = 0x050505, - Secondary = 0xfd171b -} - -export const enum Urls { - GitHubOrganization = 'https://github.com/wolfstar-project', - GitHubRepository = 'https://github.com/wolfstar-project/wolfstar', - Website = 'https://wolfstar.rocks' -} - -export const enum CdnUrls { - EscapeRopeGif = 'https://cdn.wolfstar.rocks/wolfstar-assets/escape_rope.gif', - RevolvingHeartTwemoji = 'https://cdn.jsdelivr.net/gh/twitter/twemoji@v14.0.2/assets/72x72/1f49e.png' -} - -export const enum Invites { - Skyra = 'https://discord.com/api/oauth2/authorize?client_id=266624760782258186&permissions=292557286486&scope=bot%20applications.commands', - Dragonite = 'https://discord.com/api/oauth2/authorize?client_id=931264626614763530&permissions=81920&scope=bot%20applications.commands', - Iriss = 'https://discord.com/api/oauth2/authorize?client_id=948377113457745990&permissions=326417868864&scope=bot%20applications.commands', - Nekokai = 'https://discord.com/api/oauth2/authorize?client_id=939613684592934992&permissions=16384&scope=bot%20applications.commands', - Teryl = 'https://discord.com/api/oauth2/authorize?client_id=948377583626637343&permissions=1074004032&scope=applications.commands%20bot', - Artiel = 'https://discord.com/api/oauth2/authorize?client_id=948377028028145755&permissions=51200&scope=applications.commands%20bot' -} - -export const enum LanguageFormatters { - Duration = 'duration', - ExplicitContentFilter = 'explicitContentFilter', - MessageNotifications = 'messageNotifications', - Number = 'number', - NumberCompact = 'numberCompact', - HumanLevels = 'humanLevels', - Permissions = 'permissions', - DateTime = 'dateTime', - HumanDateTime = 'humanDateTime' -} - -export const enum Colors { - White = 0xe7e7e8, - Amber = 0xffc107, - Amber300 = 0xffd54f, - Blue = 0x2196f3, - BlueGrey = 0x607d8b, - Brown = 0x795548, - Cyan = 0x00bcd4, - DeepOrange = 0xff5722, - DeepPurple = 0x673ab7, - Green = 0x4caf50, - Grey = 0x9e9e9e, - Indigo = 0x3f51b5, - LightBlue = 0x03a9f4, - LightGreen = 0x8bc34a, - Lime = 0xcddc39, - Lime300 = 0xdce775, - Orange = 0xff9800, - Pink = 0xe91e63, - Purple = 0x9c27b0, - Red = 0xf44336, - Red300 = 0xe57373, - Teal = 0x009688, - Yellow = 0xffeb3b, - Yellow300 = 0xfff176 -} diff --git a/src/lib/util/deprecate.ts b/src/lib/util/deprecate.ts deleted file mode 100644 index a80217799..000000000 --- a/src/lib/util/deprecate.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { Invites } from '#lib/util/constants'; -import { ActionRowBuilder, ButtonBuilder, inlineCode, type MessageActionRowComponentBuilder } from '@discordjs/builders'; -import { isNullishOrEmpty } from '@sapphire/utilities'; -import { ButtonStyle } from 'discord.js'; - -export function createDeprecatedList(options: Options) { - const values = new Map(); - for (const entry of options.entries) { - const keys = typeof entry.in === 'string' ? [entry.in] : entry.in; - const value = typeof entry.out === 'string' ? [entry.out] : entry.out; - for (const key of keys) { - values.set(key, value); - - // Mimic CommandOptions#generateDashLessAliases: - if (key.includes('-')) { - values.set(key.replaceAll('-', ''), value); - } - } - } - - return values; -} - -export function makeRemovedMessage(alias: string, row: ActionRowBuilder) { - const content = `The command ${inlineCode(alias)} has been removed, please read more information about this change with the button below.`; - return { content, components: [row], allowedMentions: { users: [], roles: [] } }; -} - -const listFormatter = new Intl.ListFormat('en-US', { type: 'disjunction' }); -export function makeReplacedMessage(alias: string, row: ActionRowBuilder, list: Map) { - const replacement = list.get(alias); - const content = `The command ${inlineCode(alias)} has been removed${ - isNullishOrEmpty(replacement) ? '' : `, please use ${listFormatter.format(replacement)} instead` - }. You may need to invite the bot with the button below if the command doesn't work.`; - return { content, components: [row], allowedMentions: { users: [], roles: [] } }; -} - -export function makeRow(...buttons: readonly ButtonBuilder[]) { - return new ActionRowBuilder().addComponents(...buttons); -} - -export const ButtonWolfStarV7 = new ButtonBuilder() // - .setLabel('Blog WolfStar Post') - .setStyle(ButtonStyle.Link) - .setURL('https://blog.wolfstar.rocks/wolfstar-v7'); - -export const ButtonSkyraV7 = new ButtonBuilder() // - .setLabel('Blog Skyra Post') - .setStyle(ButtonStyle.Link) - .setURL('https://blog.skyra.pw/skyra-v7'); - -export const ButtonInviteTeryl = new ButtonBuilder() // - .setLabel('Invite Teryl') - .setStyle(ButtonStyle.Link) - .setURL(Invites.Teryl); - -export const ButtonInviteArtiel = new ButtonBuilder() // - .setLabel('Invite Artiel') - .setStyle(ButtonStyle.Link) - .setURL(Invites.Artiel); - -export interface Options { - entries: { out: string | readonly string[]; in: string | readonly string[] }[]; -} diff --git a/src/lib/util/functions/auditLogEmbeds.ts b/src/lib/util/functions/auditLogEmbeds.ts deleted file mode 100644 index aa0a9f468..000000000 --- a/src/lib/util/functions/auditLogEmbeds.ts +++ /dev/null @@ -1,119 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { EmbedBuilder } from '@discordjs/builders'; -import type { TFunction } from '@sapphire/plugin-i18next'; -import { cutText } from '@sapphire/utilities'; -import { Colors, chatInputApplicationCommandMention } from 'discord.js'; -import { auditDiff } from 'evlog'; - -export interface CommandExecutePayload { - actorId: string; - commandName: string; - commandId?: string; - commandType: 'chat-input' | 'context-menu' | 'message'; - channelId: string; - timestamp: Date; -} - -export type AuditLogSettingsAction = 'guild.settings.update' | 'guild.settings.add' | 'guild.settings.remove' | 'guild.settings.access-denied'; - -export interface SettingsChangePayload { - actorId: string; - action: AuditLogSettingsAction; - before: Record; - after: Record; - reason: string | null; - timestamp: Date; -} - -function formatChatInputMention(commandName: string, commandId?: string): string { - const parts = commandName.split(' '); - if (!commandId) return `\`/${commandName}\``; - if (parts.length === 3) return chatInputApplicationCommandMention(parts[0], parts[1], parts[2], commandId); - if (parts.length === 2) return chatInputApplicationCommandMention(parts[0], parts[1], commandId); - return chatInputApplicationCommandMention(parts[0], commandId); -} - -export function buildCommandExecuteEmbed(t: TFunction, payload: CommandExecutePayload): EmbedBuilder { - const { actorId, commandName, commandId, commandType, channelId, timestamp } = payload; - const formattedCommandName = commandType === 'chat-input' ? formatChatInputMention(commandName, commandId) : `\`${commandName}\``; - return new EmbedBuilder() - .setColor(Colors.Blue) - .setTitle(t(LanguageKeys.Events.Guilds.Logs.CommandExecuteTitle)) - .addFields( - { name: t(LanguageKeys.Events.Guilds.Logs.LogFieldUser), value: `<@${actorId}>`, inline: true }, - { name: t(LanguageKeys.Events.Guilds.Logs.LogFieldCommand), value: formattedCommandName, inline: true }, - { - name: t(LanguageKeys.Events.Guilds.Logs.LogFieldType), - value: - commandType === 'chat-input' - ? t(LanguageKeys.Events.Guilds.Logs.CommandTypeChatInput) - : commandType === 'context-menu' - ? t(LanguageKeys.Events.Guilds.Logs.CommandTypeContextMenu) - : t(LanguageKeys.Events.Guilds.Logs.CommandTypeMessage), - inline: true - }, - { name: t(LanguageKeys.Events.Guilds.Logs.LogFieldChannel), value: `<#${channelId}>`, inline: true } - ) - .setTimestamp(timestamp); -} - -export function buildSettingsChangeEmbed(t: TFunction, payload: SettingsChangePayload): EmbedBuilder { - const { actorId, action, before, after, reason, timestamp } = payload; - - const color = action === 'guild.settings.access-denied' ? Colors.Yellow : action === 'guild.settings.remove' ? Colors.Red : Colors.Green; - - const title = - action === 'guild.settings.access-denied' - ? t(LanguageKeys.Events.Guilds.Logs.SettingsAccessDeniedTitle) - : t(LanguageKeys.Events.Guilds.Logs.SettingsUpdateTitle); - - const embed = new EmbedBuilder().setColor(color).setTitle(title).setTimestamp(timestamp); - - if (reason) embed.setDescription(reason); - - const diff = auditDiff(before, after); - const changeFields: { name: string; value: string; inline: boolean }[] = []; - - for (const op of diff.patch.slice(0, 10)) { - const key = op.path.replace(/^\//, '').replaceAll('/', '.'); - let value: string; - if (op.op === 'replace') { - const from = cutText(formatAuditValue(getNestedValue(before, op.path)), 100); - const to = cutText(formatAuditValue(op.value), 100); - if (from === to) continue; - value = `has changed ${from} to ${to}`; - } else if (op.op === 'add') { - value = cutText(formatAuditValue(op.value), 200); - } else if (op.op === 'remove') { - value = cutText(formatAuditValue(getNestedValue(before, op.path)), 200); - } else { - continue; - } - changeFields.push({ name: key, value, inline: false }); - } - - if (changeFields.length > 0) { - embed.addFields({ name: t(LanguageKeys.Events.Guilds.Logs.LogFieldUser), value: `<@${actorId}>`, inline: true }, ...changeFields); - } else { - embed.addFields({ name: t(LanguageKeys.Events.Guilds.Logs.LogFieldUser), value: `<@${actorId}>`, inline: true }); - } - - return embed; -} - -function formatAuditValue(value: unknown): string { - if (value === null || value === undefined) return '`null`'; - if (typeof value === 'string') return value.length === 0 ? '""' : value; - if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint') return String(value); - return '`' + JSON.stringify(value) + '`'; -} - -function getNestedValue(obj: Record, path: string): unknown { - const parts = path.split('/').filter(Boolean); - let current: unknown = obj; - for (const part of parts) { - if (current === null || current === undefined || typeof current !== 'object') return undefined; - current = (current as Record)[part]; - } - return current; -} diff --git a/src/lib/util/functions/channels.ts b/src/lib/util/functions/channels.ts deleted file mode 100644 index 1b79b974c..000000000 --- a/src/lib/util/functions/channels.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import type { GuildTextBasedChannelTypes, TextBasedChannelTypes } from '@sapphire/discord.js-utilities'; -import { UserError } from '@sapphire/framework'; -import type { Message, ThreadChannel } from 'discord.js'; - -/** - * Asserts a text-based channel is not a thread channel. - * @param channel The channel to assert. - * @returns The thread channel. - */ -export function assertNonThread(channel: T): Exclude { - if (channel.isThread()) { - throw new UserError({ identifier: LanguageKeys.Assertions.ExpectedNonThreadChannel, context: { channel: channel.toString() } }); - } - - return channel as Exclude; -} - -export interface SnipedMessage { - message: Message; - timeout: NodeJS.Timeout; -} - -const snipedMessages = new WeakMap(); -export function getSnipedMessage(channel: GuildTextBasedChannelTypes): Message | null { - const current = snipedMessages.get(channel); - return current?.message ?? null; -} - -export function setSnipedMessage(channel: GuildTextBasedChannelTypes, value: Message | null) { - const previous = snipedMessages.get(channel); - if (typeof previous !== 'undefined') clearTimeout(previous.timeout); - - if (value === null) { - snipedMessages.delete(channel); - } else { - const next: SnipedMessage = { - message: value, - timeout: setTimeout(() => snipedMessages.delete(channel), 15000).unref() - }; - snipedMessages.set(channel, next); - } -} diff --git a/src/lib/util/functions/embeds.ts b/src/lib/util/functions/embeds.ts deleted file mode 100644 index 23ae7501c..000000000 --- a/src/lib/util/functions/embeds.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { ZeroWidthSpace } from '#utils/constants'; -import type { EmbedBuilder } from '@discordjs/builders'; -import { isNullishOrEmpty } from '@sapphire/utilities'; - -export function addAutomaticFields(builder: EmbedBuilder, contentOrTitle: string | string[], rawContent?: string | string[]): EmbedBuilder { - if (isNullishOrEmpty(contentOrTitle)) return builder; - - let title: string; - let content: string | string[]; - if (typeof rawContent === 'undefined') { - title = ZeroWidthSpace; - content = contentOrTitle; - } else { - title = contentOrTitle as string; - content = rawContent; - } - - if (Array.isArray(content)) content = content.join('\n'); - if (title === ZeroWidthSpace && !builder.data.description && content.length < 4096) { - builder.data.description = content; - return builder; - } - - let x: number; - let slice: string; - builder.data.fields ??= []; - while (content.length) { - if (content.length < 1024) { - builder.data.fields.push({ name: title, value: content, inline: false }); - return builder; - } - - slice = content.slice(0, 1024); - x = slice.lastIndexOf('\n'); - if (x === -1) x = slice.lastIndexOf(' '); - if (x === -1) x = 1024; - - builder.data.fields.push({ name: title, value: content.trim().slice(0, x), inline: false }); - content = content.slice(x + 1); - title = ZeroWidthSpace; - } - - return builder; -} diff --git a/src/lib/util/functions/index.ts b/src/lib/util/functions/index.ts deleted file mode 100644 index f92b0b7e6..000000000 --- a/src/lib/util/functions/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -export * from '#lib/util/functions/channels'; -export * from '#lib/util/functions/embeds'; -export * from '#lib/util/functions/emojis'; -export * from '#lib/util/functions/guild'; -export * from '#lib/util/functions/messages'; -export * from '#lib/util/functions/permissions'; -export * from '#lib/util/functions/numbers'; -export * from '#lib/util/functions/pieces'; -export * from '#lib/util/functions/users'; -export * from '#lib/util/functions/auditLogEmbeds'; diff --git a/src/lib/util/functions/messages.ts b/src/lib/util/functions/messages.ts deleted file mode 100644 index 64391bbd4..000000000 --- a/src/lib/util/functions/messages.ts +++ /dev/null @@ -1,190 +0,0 @@ -import type { WolfCommand } from '#lib/structures'; -import type { NonGroupMessage, TypedFT, TypedT } from '#lib/types'; -import { floatPromise, minutes, resolveOnErrorCodes } from '#utils/common'; -import { container } from '@sapphire/framework'; -import { send } from '@sapphire/plugin-editable-commands'; -import { resolveKey, type TOptions } from '@sapphire/plugin-i18next'; -import { RESTJSONErrorCodes, type Message, type MessageCreateOptions, type UserResolvable } from 'discord.js'; -import { setTimeout as sleep } from 'node:timers/promises'; -import { ActionRowBuilder, ButtonBuilder, ButtonStyle, ComponentType } from 'discord.js'; - -const messageCommands = new WeakMap(); - -/** - * Sets or resets the tracking status of a message with a command. - * @param message The message to track. - * @param command The command that was run with the given message, if any. - */ -export function setCommand(message: Message, command: WolfCommand | null) { - if (command === null) messageCommands.delete(message); - else messageCommands.set(message, command); -} - -/** - * Gets the tracked command from a message. - * @param message The message to get the command from. - * @returns The command that was run with the given message, if any. - */ -export function getCommand(message: Message): WolfCommand | null { - return messageCommands.get(message) ?? null; -} - -async function deleteMessageImmediately(message: Message): Promise { - return (await resolveOnErrorCodes(message.delete(), RESTJSONErrorCodes.UnknownMessage)) ?? message; -} - -/** - * Deletes a message, skipping if it was already deleted, and aborting if a non-zero timer was set and the message was - * either deleted or edited. - * - * This also ignores the `UnknownMessage` error code. - * @param message The message to delete. - * @param time The amount of time, defaults to 0. - * @returns The deleted message. - */ -export async function deleteMessage(message: Message, time = 0): Promise { - if (time === 0) return deleteMessageImmediately(message); - - const lastEditedTimestamp = message.editedTimestamp; - await sleep(time); - - // If it was deleted or edited, cancel: - if (message.editedTimestamp !== lastEditedTimestamp) { - return message; - } - - return deleteMessageImmediately(message); -} - -/** - * Sends a temporary editable message and then floats a {@link deleteMessage} with the given `timer`. - * @param message The message to reply to. - * @param options The options to be sent to the channel. - * @param timer The timer in which the message should be deleted, using {@link deleteMessage}. - * @returns The response message. - */ -export async function sendTemporaryMessage(message: Message, options: string | MessageCreateOptions, timer = minutes(1)): Promise { - if (typeof options === 'string') options = { content: options }; - - const response = await send(message, options); - floatPromise(deleteMessage(response, timer)); - return response; -} - -/** - * Send an editable localized message using `key`. - * @param message The message to reply to. - * @param key The key to be used when resolving. - * @example - * ```typescript - * await sendLocalizedMessage(message, LanguageKeys.Commands.General.Ping); - * // ➡ "Pinging..." - * ``` - */ -export function sendLocalizedMessage(message: Message, key: LocalizedSimpleKey): Promise; -/** - * Send an editable localized message using an object. - * @param message The message to reply to. - * @param options The options to be sent, requiring at least `key` to be passed. - * @example - * ```typescript - * await sendLocalizedMessage(message, { - * key: LanguageKeys.Commands.General.Ping - * }); - * // ➡ "Pinging..." - * ``` - * @example - * ```typescript - * const latency = 42; - * - * await sendLocalizedMessage(message, { - * key: LanguageKeys.Commands.General.PingPong, - * formatOptions: { latency } - * }); - * // ➡ "Pong! Current latency is 42ms." - * ``` - */ -export function sendLocalizedMessage(message: Message, options: LocalizedMessageOptions): Promise; -export async function sendLocalizedMessage(message: Message, options: LocalizedSimpleKey | LocalizedMessageOptions) { - if (typeof options === 'string') options = { key: options }; - - // @ts-expect-error 2345: Complex overloads - const content = await resolveKey(message, options.key, options.formatOptions); - return send(message, { ...options, content }); -} - -type LocalizedSimpleKey = TypedT; -type LocalizedMessageOptions = Omit & - ( - | { - key: LocalizedSimpleKey; - formatOptions?: TOptions; - } - | { - key: TypedFT; - formatOptions: TOptions; - } - ); - -/** - * The prompt confirmation options. - */ -export interface PromptConfirmationMessageOptions extends MessageCreateOptions { - /** - * The target. - * @default message.author - */ - target?: UserResolvable; - - /** - * The time for the confirmation to run. - * @default minutes(1) - */ - time?: number; -} - -async function promptConfirmationButton(message: NonGroupMessage, response: NonGroupMessage, options: PromptConfirmationMessageOptions) { - const yesButton = new ButtonBuilder().setCustomId('yes').setLabel('Yes').setStyle(ButtonStyle.Success); - const noButton = new ButtonBuilder().setCustomId('no').setLabel('No').setStyle(ButtonStyle.Danger); - - const row = new ActionRowBuilder().addComponents(yesButton, noButton); - - await response.edit({ components: [row] }); - - const target = container.client.users.resolveId(options.target ?? message.author)!; - const interaction = await response.awaitMessageComponent({ - filter: (i) => i.user.id === target, - componentType: ComponentType.Button, - time: options.time ?? minutes(1) - }); - - // Remove all components after interaction - await interaction.update({ components: [] }); - - return interaction.customId === 'yes'; -} - -/** - * Sends a boolean confirmation prompt asking the `target` for either of two choices. - * @param message The message to ask for a confirmation from. - * @param options The options for the message to be sent, alongside the prompt options. - * @returns `null` if no response was given within the requested time, `boolean` otherwise. - */ -export async function promptConfirmation(message: NonGroupMessage, options: string | PromptConfirmationMessageOptions) { - if (typeof options === 'string') options = { content: options }; - - const response = (await send(message, options)) as NonGroupMessage; - return promptConfirmationButton(message, response, options); -} - -export async function promptForMessage( - message: NonGroupMessage, - sendOptions: string | MessageCreateOptions, - time = minutes(1) -): Promise { - const response = await message.channel.send(sendOptions); - const responses = await message.channel.awaitMessages({ filter: (msg) => msg.author === message.author, time, max: 1 }); - floatPromise(deleteMessage(response)); - - return responses.size === 0 ? null : responses.first()!.content; -} diff --git a/src/lib/util/functions/permissions.ts b/src/lib/util/functions/permissions.ts deleted file mode 100644 index 532eb9117..000000000 --- a/src/lib/util/functions/permissions.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { readSettings, type ReadonlyGuildData } from '#lib/database/settings'; -import { OWNERS } from '#root/config'; -import { hasAtLeastOneKeyInMap } from '@sapphire/utilities'; -import { GuildMember, PermissionFlagsBits } from 'discord.js'; - -export async function isModerator(member: GuildMember) { - if (isGuildOwner(member)) return true; - - const settings = await readSettings(member); - return checkModerator(member, settings) || checkAdministrator(member, settings); -} - -export async function isAdmin(member: GuildMember) { - if (isGuildOwner(member)) return true; - - const settings = await readSettings(member); - return checkAdministrator(member, settings); -} - -export function isGuildOwner(member: GuildMember) { - return member.id === member.guild.ownerId; -} - -export function isOwner(member: GuildMember) { - return OWNERS.includes(member.id); -} - -function checkModerator(member: GuildMember, settings: ReadonlyGuildData) { - const roles = settings.rolesModerator; - return roles.length === 0 ? member.permissions.has(PermissionFlagsBits.BanMembers) : hasAtLeastOneKeyInMap(member.roles.cache, roles); -} - -function checkAdministrator(member: GuildMember, settings: ReadonlyGuildData) { - const roles = settings.rolesAdmin; - return roles.length === 0 ? member.permissions.has(PermissionFlagsBits.ManageGuild) : hasAtLeastOneKeyInMap(member.roles.cache, roles); -} diff --git a/src/lib/util/functions/pieces.ts b/src/lib/util/functions/pieces.ts deleted file mode 100644 index c6c164402..000000000 --- a/src/lib/util/functions/pieces.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Piece } from '@sapphire/framework'; -import { bgBlue, bgRed } from 'colorette'; - -export function getLogPrefix(piece: Piece | string) { - return bgBlue(piece instanceof Piece ? `[ ${piece.store.name} => ${piece.name} ]` : `[ ${piece} ]`); -} - -export function getCodeStyle(code: string | number) { - return bgRed(`[ ${code} ]`); -} diff --git a/src/lib/util/functions/users.ts b/src/lib/util/functions/users.ts deleted file mode 100644 index 4ce3a5b1d..000000000 --- a/src/lib/util/functions/users.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { Emojis } from '#utils/constants'; -import { userMention } from '@discordjs/builders'; -import { BitField } from '@sapphire/bitfield'; -import { UserFlags, type Snowflake } from 'discord.js'; - -const ExtendedUserFlagBits = new BitField({ - Quarantined: getExtendedBits(UserFlags.Quarantined), - Collaborator: getExtendedBits(UserFlags.Collaborator), - RestrictedCollaborator: getExtendedBits(UserFlags.RestrictedCollaborator) -}); - -export function getModerationFlags(bitfield: number) { - return { - spammer: (bitfield & UserFlags.Spammer) === UserFlags.Spammer, - quarantined: ExtendedUserFlagBits.has(getExtendedBits(bitfield), ExtendedUserFlagBits.flags.Quarantined) - }; -} - -export function getModerationFlagsString(bitfield: number) { - const { spammer, quarantined } = getModerationFlags(bitfield); - if (spammer && quarantined) return Emojis.SpammerIcon + Emojis.QuarantinedIcon; - if (spammer) return Emojis.SpammerIcon; - if (quarantined) return Emojis.QuarantinedIcon; - return ''; -} - -export function getUserMentionWithFlagsString(bitfield: number, userId: Snowflake) { - const flags = getModerationFlagsString(bitfield); - const mention = userMention(userId); - return flags ? `${mention} ${flags}` : mention; -} - -function getExtendedBits(bitfield: number) { - return (bitfield / (1 << 30)) | 0; -} diff --git a/src/lib/util/moderation-utilities.ts b/src/lib/util/moderation-utilities.ts deleted file mode 100644 index 7ed4c539c..000000000 --- a/src/lib/util/moderation-utilities.ts +++ /dev/null @@ -1,27 +0,0 @@ -import type { WolfArgs } from '#lib/structures'; -import { seconds } from '#utils/common'; - -export const SecondsOptions = ['s', 'sec', 'secs', 'second', 'seconds'] as const; -export const MinutesOptions = ['m', 'min', 'mins', 'minute', 'minutes'] as const; -export const HoursOptions = ['h', 'hr', 'hrs', 'hour', 'hours'] as const; -export const DaysOptions = ['d', 'day', 'days'] as const; -export const TimeOptions = [...SecondsOptions, ...MinutesOptions, ...HoursOptions, ...DaysOptions] as const; - -const maximum = seconds.fromDays(7); - -export function getSeconds(args: WolfArgs) { - const result = - getUnit(args, SecondsOptions) + - getUnit(args, MinutesOptions, seconds.fromMinutes) + - getUnit(args, HoursOptions, seconds.fromHours) + - getUnit(args, DaysOptions, seconds.fromDays); - return Math.min(result, maximum); -} - -function getUnit(args: WolfArgs, flags: readonly string[], cb?: (value: number) => number) { - const value = args.getOption(...flags); - if (value === null) return 0; - - const parsed = Number(value); - return Number.isInteger(parsed) ? (cb ? cb(parsed) : parsed) : 0; -} diff --git a/src/lib/util/moderationConstants.ts b/src/lib/util/moderationConstants.ts deleted file mode 100644 index a7e2ed7e1..000000000 --- a/src/lib/util/moderationConstants.ts +++ /dev/null @@ -1,50 +0,0 @@ -export const enum TypeVariation { - Ban, - Kick, - Mute, - Softban, - VoiceKick, - VoiceMute, - Warning, - RestrictedReaction, - RestrictedEmbed, - RestrictedAttachment, - RestrictedVoice, - SetNickname, - RoleAdd, - RoleRemove, - RestrictedEmoji, - Timeout -} - -export const enum TypeMetadata { - None = 0, - Undo = 1 << 0, - Temporary = 1 << 1, - /** @deprecated Use Temporary instead */ - Fast = 1 << 2, - Archived = 1 << 3, - Completed = 1 << 4 -} - -export const enum SchemaKeys { - Case = 'caseID', - CreatedAt = 'createdAt', - Duration = 'duration', - ExtraData = 'extraData', - Guild = 'guildID', - Moderator = 'moderatorID', - Reason = 'reason', - ImageURL = 'imageURL', - Type = 'type', - User = 'userID' -} - -export interface ModerationTypeAssets { - color: number; - title: string; -} - -export interface Unlock { - unlock(): void; -} diff --git a/src/lib/util/resolvers/Case.ts b/src/lib/util/resolvers/Case.ts deleted file mode 100644 index 554b916d9..000000000 --- a/src/lib/util/resolvers/Case.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { translate } from '#lib/i18n/translate'; -import type { ModerationManager } from '#lib/moderation'; -import { getModeration } from '#utils/functions'; -import { Resolvers, Result, UserError, err, ok } from '@sapphire/framework'; -import type { TFunction } from '@sapphire/plugin-i18next'; -import type { Guild } from 'discord.js'; - -export async function resolveCaseId(parameter: string, t: TFunction, guild: Guild): Promise> { - const maximum = await getModeration(guild).getCurrentId(); - if (maximum === 0) return err(new UserError({ identifier: LanguageKeys.Arguments.CaseNoEntries })); - - if (t(LanguageKeys.Arguments.CaseLatestOptions).includes(parameter)) return ok(maximum); - return Resolvers.resolveInteger(parameter, { minimum: 1, maximum }) // - .mapErr((error) => new UserError({ identifier: translate(error), context: { parameter, minimum: 1, maximum } })); -} - -export async function resolveCase(parameter: string, t: TFunction, guild: Guild): Promise> { - const result = await resolveCaseId(parameter, t, guild); - return result.match({ - ok: async (value) => { - const entry = await getModeration(guild).fetch(value); - return entry ? ok(entry) : err(new UserError({ identifier: LanguageKeys.Arguments.CaseUnknownEntry, context: { parameter } })); - }, - err: (error) => err(error) - }); -} diff --git a/src/lib/util/resolvers/TimeSpan.ts b/src/lib/util/resolvers/TimeSpan.ts deleted file mode 100644 index d4ebfefd1..000000000 --- a/src/lib/util/resolvers/TimeSpan.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import type { Parameter, TypedFT } from '#lib/types'; -import { seconds } from '#utils/common'; -import { Result, err, ok } from '@sapphire/framework'; -import { Duration } from '@sapphire/time-utilities'; - -export function resolveTimeSpan(parameter: string, options?: TimeSpanOptions): Result> { - const duration = parse(parameter); - - if (!Number.isSafeInteger(duration)) { - return err(LanguageKeys.Arguments.TimeSpan); - } - - if (typeof options?.minimum === 'number' && duration < options.minimum) { - return err(LanguageKeys.Arguments.TimeSpanTooSmall); - } - - if (typeof options?.maximum === 'number' && duration > options.maximum) { - return err(LanguageKeys.Arguments.TimeSpanTooBig); - } - - return ok(duration); -} - -function parse(parameter: string) { - const number = Number(parameter); - if (!Number.isNaN(number)) return seconds(number); - - const duration = new Duration(parameter).offset; - if (!Number.isNaN(duration)) return duration; - - const date = Date.parse(parameter); - if (!Number.isNaN(date)) return date - Date.now(); - - return Number.NaN; -} - -export interface TimeSpanOptions { - minimum?: number; - maximum?: number; -} diff --git a/src/lib/util/resolvers/index.ts b/src/lib/util/resolvers/index.ts deleted file mode 100644 index 606873c8e..000000000 --- a/src/lib/util/resolvers/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from '#utils/resolvers/Case'; -export * from '#utils/resolvers/TimeSpan'; diff --git a/src/lib/util/util.ts b/src/lib/util/util.ts deleted file mode 100644 index 48694d11e..000000000 --- a/src/lib/util/util.ts +++ /dev/null @@ -1,363 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import type { GuildMessage } from '#lib/types'; -import { BrandingColors, Urls, ZeroWidthSpace } from '#lib/util/constants'; -import { EmbedBuilder } from '@discordjs/builders'; -import { container } from '@sapphire/framework'; -import { first } from '@sapphire/iterator-utilities/first'; -import { send } from '@sapphire/plugin-editable-commands'; -import type { TFunction } from '@sapphire/plugin-i18next'; -import { isNullishOrEmpty, isNullishOrZero, tryParseURL, type Nullish } from '@sapphire/utilities'; -import { - GuildMember, - PermissionFlagsBits, - StickerFormatType, - type APIUser, - type EmbedAuthorData, - type Guild, - type GuildChannel, - type ImageURLOptions, - type Message, - type MessageMentionTypes, - type Snowflake, - type ThreadChannel, - type User, - type UserResolvable -} from 'discord.js'; - -/** - * Image extensions: - * - bmp - * - jpg - * - jpeg - * - png - * - gif - * - webp - */ -export const IMAGE_EXTENSION = /\.(bmp|jpe?g|png|gif|webp)$/i; - -/** - * Media extensions - * - ...Image extensions - * - ...Audio extensions - * - ...Video extensions - */ -export const MEDIA_EXTENSION = /\.(bmp|jpe?g|png|gifv?|web[pm]|wav|mp[34]|ogg)$/i; - -/** - * Get the content from a message. - * @param message The Message instance to get the content from - */ -export function getContent(message: Message): string | null { - if (message.content) return message.content; - for (const embed of message.embeds) { - if (embed.description) return embed.description; - if (embed.fields.length) return embed.fields[0].value; - } - return null; -} - -export interface ImageAttachment { - url: string; - proxyURL: string; - height: number; - width: number; -} - -export function* getImages(message: Message): IterableIterator { - for (const attachment of message.attachments.values()) { - // Skip if the attachment doesn't have a content type: - if (isNullishOrEmpty(attachment.contentType)) continue; - // Skip if the attachment doesn't have a size: - if (isNullishOrZero(attachment.width) || isNullishOrZero(attachment.height)) continue; - // Skip if the attachment isn't an image: - if (!attachment.contentType.startsWith('image/')) continue; - - yield attachment.proxyURL ?? attachment.url; - } - - for (const embed of message.embeds) { - if (embed.image) { - yield embed.image.proxyURL ?? embed.image.url; - } - - if (embed.thumbnail) { - yield embed.thumbnail.proxyURL ?? embed.thumbnail.url; - } - } - - for (const sticker of message.stickers.values()) { - // Skip if the sticker is a lottie sticker: - if (sticker.format === StickerFormatType.Lottie) continue; - - yield sticker.url; - } -} - -/** - * Get the image url from a message. - * @param message The Message instance to get the image url from - */ -export function getImage(message: Message): string | null { - return first(getImages(message)) ?? null; -} - -export function setMultipleEmbedImages(embed: EmbedBuilder, urls: IterableIterator) { - const embeds = [embed]; - let count = 0; - for (const url of urls) { - if (count === 0) { - embed.setURL(Urls.Website).setImage(url); - } else { - embeds.push(new EmbedBuilder().setURL(Urls.Website).setImage(url)); - - // We only want to send 4 embeds at most - if (count === 3) break; - } - - count++; - } - - return embeds; -} - -/** - * Checks whether or not the user uses the new username change, defined by the - * `discriminator` being `'0'` or in the future, no discriminator at all. - * @see {@link https://dis.gd/usernames} - * @param user The user to check. - */ -export function usesPomelo(user: User | APIUser) { - return isNullishOrEmpty(user.discriminator) || user.discriminator === '0'; -} - -export function getDisplayAvatar(user: User | APIUser, options?: Readonly) { - if (user.avatar === null) { - const id = usesPomelo(user) ? Number(BigInt(user.id) >> 22n) % 6 : Number(user.discriminator) % 5; - return container.client.rest.cdn.defaultAvatar(id); - } - - return container.client.rest.cdn.avatar(user.id, user.avatar, options); -} - -export function getTag(user: User | APIUser) { - return usesPomelo(user) ? `@${user.username}` : `${user.username}#${user.discriminator}`; -} - -export function getEmbedAuthor(user: User | APIUser, url?: string | undefined): EmbedAuthorData { - return { name: getTag(user), iconURL: getDisplayAvatar(user, { size: 128 }), url }; -} - -export function getFullEmbedAuthor(user: User | APIUser, url?: string | undefined): EmbedAuthorData { - return { name: `${getTag(user)} (${user.id})`, iconURL: getDisplayAvatar(user, { size: 128 }), url }; -} - -/** - * Parse a range - * @param input The input to parse - * @example - * parseRange('23..25'); - * // -> [23, 24, 25] - * @example - * parseRange('1..3,23..25'); - * // -> [1, 2, 3, 23, 24, 25] - */ -export function parseRange(input: string): number[] { - const set = new Set(); - for (const subset of input.split(',')) { - const [, stringMin, stringMax] = /(\d+) *\.{2,} *(\d+)/.exec(subset) || [subset, subset, subset]; - let min = Number(stringMin); - let max = Number(stringMax); - if (min > max) [max, min] = [min, max]; - - for (let i = Math.max(1, min); i <= max; ++i) set.add(i); - } - - return [...set]; -} - -/** - * Parses an URL and checks if the extension is valid. - * @param url The url to check - */ -export function getImageUrl(url: string): string | undefined { - const parsed = tryParseURL(url); - return parsed && IMAGE_EXTENSION.test(parsed.pathname) ? parsed.href : undefined; -} - -/** - * Clean all mentions from a body of text - * @param guild The guild for context - * @param input The input to clean - * @returns The input cleaned of mentions - * @license Apache-2.0 - * @copyright 2019 Aura Román - */ -export function cleanMentions(guild: Guild, input: string) { - return input.replace(/@(here|everyone)/g, `@${ZeroWidthSpace}$1`).replace(/<(@[!&]?|#)(\d{17,19})>/g, (match, type, id) => { - switch (type) { - case '@': - case '@!': { - const tag = guild.client.users.cache.get(id); - return tag ? `@${tag.username}` : `<${type}${ZeroWidthSpace}${id}>`; - } - case '@&': { - const role = guild.roles.cache.get(id); - return role ? `@${role.name}` : match; - } - case '#': { - const channel = guild.channels.cache.get(id); - return channel ? `#${channel.name}` : `<${type}${ZeroWidthSpace}${id}>`; - } - default: - return `<${type}${ZeroWidthSpace}${id}>`; - } - }); -} - -export const anyMentionRegExp = /<(@[!&]?|#)(\d{17,19})>/g; -export const hereOrEveryoneMentionRegExp = /@(?:here|everyone)/; - -/** - * Splits a message into multiple messages if it exceeds a certain length, using a specified character as the delimiter. - * @param content The message to split. - * @param options The options for splitting the message. - * @returns An array of messages split from the original message. - * @throws An error if the content cannot be split. - */ -export function splitMessage(content: string, options: SplitMessageOptions) { - if (content.length <= options.maxLength) return [content]; - - let last = 0; - const messages = [] as string[]; - while (last < content.length) { - // If the last chunk can fit the rest of the content, push it and break: - if (content.length - last <= options.maxLength) { - messages.push(content.slice(last)); - break; - } - - // Find the last best index to split the chunk: - const index = content.lastIndexOf(options.char, options.maxLength + last); - if (index === -1) throw new Error('Unable to split content.'); - - messages.push(content.slice(last, index + 1)); - last = index + 1; - } - - return messages; -} - -export interface SplitMessageOptions { - char: string; - maxLength: number; -} - -/** - * Extracts mentions from a body of text. - * @remark Preserves the mentions in the content, if you want to remove them use `cleanMentions`. - * @param input The input to extract mentions from. - */ -export function extractDetailedMentions(input: string | Nullish): DetailedMentionExtractionResult { - const users = new Set(); - const roles = new Set(); - const channels = new Set(); - const parse = [] as MessageMentionTypes[]; - - if (isNullishOrEmpty(input)) { - return { users, roles, channels, parse }; - } - - let result: RegExpExecArray | null; - while ((result = anyMentionRegExp.exec(input)) !== null) { - switch (result[1]) { - case '@': - case '@!': { - users.add(result[2]); - continue; - } - case '@&': { - roles.add(result[2]); - continue; - } - case '#': { - channels.add(result[2]); - continue; - } - } - } - - if (hereOrEveryoneMentionRegExp.test(input)) parse.push('everyone'); - - return { users, roles, channels, parse }; -} - -export interface DetailedMentionExtractionResult { - users: ReadonlySet; - roles: ReadonlySet; - channels: ReadonlySet; - parse: MessageMentionTypes[]; -} - -/** - * Picks a random item from an array - * @param array The array to pick a random item from - * @example - * const randomEntry = pickRandom([1, 2, 3, 4]) // 1 - */ -export function pickRandom(array: readonly T[]): T { - const { length } = array; - return array[Math.floor(Math.random() * length)]; -} - -export function cast(value: unknown): T { - return value as T; -} - -/** - * Validates that a user has VIEW_CHANNEL permissions to a channel - * @param channel The TextChannel to check - * @param user The user for which to check permission - * @returns Whether the user has access to the channel - * @example validateChannelAccess(channel, message.author) - */ -export function validateChannelAccess(channel: GuildChannel | ThreadChannel, user: UserResolvable) { - return (channel.guild !== null && channel.permissionsFor(user)?.has(PermissionFlagsBits.ViewChannel)) || false; -} - -/** - * Shuffles an array, returning it - * @param array The array to shuffle - */ -export const shuffle = (array: T[]): T[] => { - let m = array.length; - while (m) { - const i = Math.floor(Math.random() * m--); - [array[m], array[i]] = [array[i], array[m]]; - } - return array; -}; - -export const random = (num: number) => Math.floor(Math.random() * num); - -export const sendLoadingMessage = (message: T, t: TFunction): Promise => { - const embed = new EmbedBuilder().setDescription(pickRandom(t(LanguageKeys.System.Loading))).setColor(BrandingColors.Secondary); - return send(message, { embeds: [embed] }) as Promise; -}; - -export function getColor(message: { member?: GuildMember | Nullish }) { - return message.member?.displayColor ?? BrandingColors.Primary; -} - -/** - * Checks if the provided user ID is the same as the client's ID. - * - * @param userId - The user ID to check. - */ -export function isUserSelf(userId: Snowflake) { - return userId === process.env.CLIENT_ID; -} - -export interface MuteOptions { - reason?: string; - duration?: number | string | null; -} diff --git a/src/listeners/analytics/analyticsSync.ts b/src/listeners/analytics/analyticsSync.ts deleted file mode 100644 index 368e58163..000000000 --- a/src/listeners/analytics/analyticsSync.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { AnalyticsListener } from '#lib/structures'; -import { Actions, Events, Points, Tags } from '#lib/types'; -import { Point } from '@influxdata/influxdb-client'; -import { ApplyOptions } from '@sapphire/decorators'; - -@ApplyOptions({ event: Events.AnalyticsSync }) -export class UserAnalyticsEvent extends AnalyticsListener { - // eslint-disable-next-line @typescript-eslint/require-await - public async run(guilds: number, users: number) { - this.writePoints([this.syncGuilds(guilds), this.syncUsers(users), this.syncMessageCount()]); - - return this.container.client.analytics!.writeApi.flush(); - } - - private syncGuilds(value: number) { - return ( - new Point(Points.Guilds) - .tag(Tags.Action, Actions.Sync) - // TODO: Adjust for traditional sharding - .intField('value', value) - ); - } - - private syncUsers(value: number) { - return ( - new Point(Points.Users) - .tag(Tags.Action, Actions.Sync) - // TODO: Adjust for traditional sharding - .intField('value', value) - ); - } - - private syncMessageCount() { - const { client } = this.container; - const value = client.analytics!.messageCount; - client.analytics!.messageCount = 0; - - return new Point(Points.MessageCount) // - .tag(Tags.Action, Actions.Sync) - .intField('value', value); - } -} diff --git a/src/listeners/analytics/commandUsageAnalytics.ts b/src/listeners/analytics/commandUsageAnalytics.ts deleted file mode 100644 index 8a9d3b031..000000000 --- a/src/listeners/analytics/commandUsageAnalytics.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { AnalyticsListener } from '#lib/structures'; -import { Actions, CommandCategoryTypes, Events, Points, Tags } from '#lib/types'; -import { Point } from '@influxdata/influxdb-client'; -import { ApplyOptions } from '@sapphire/decorators'; - -@ApplyOptions({ event: Events.CommandUsageAnalytics }) -export class UserAnalyticsEvent extends AnalyticsListener { - public run(commandName: string, category: string) { - const command = new Point(Points.Commands) - .tag(Tags.Action, Actions.Addition) - .tag(CommandCategoryTypes.Category, category) - .intField(commandName.replace(/^time$/, 'case-time'), 1); - - return this.writePoint(command); - } -} diff --git a/src/listeners/analytics/guilds/guildCreateAnalytics.ts b/src/listeners/analytics/guilds/guildCreateAnalytics.ts deleted file mode 100644 index c80bb092e..000000000 --- a/src/listeners/analytics/guilds/guildCreateAnalytics.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { AnalyticsListener } from '#lib/structures'; -import { Actions, Events, Points, Tags } from '#lib/types'; -import { Point } from '@influxdata/influxdb-client'; -import { ApplyOptions } from '@sapphire/decorators'; -import type { Guild } from 'discord.js'; - -@ApplyOptions({ event: Events.GuildCreate }) -export class UserAnalyticsEvent extends AnalyticsListener { - public run(guild: Guild) { - const guilds = new Point(Points.Guilds) - .tag(Tags.Shard, guild.shardId.toString()) - .tag(Tags.Action, Actions.Addition) - // TODO: Adjust for traditional sharding - .intField('value', guild.client.guilds.cache.size); - const users = new Point(Points.Users) - .tag(Tags.Shard, guild.shardId.toString()) - .tag(Tags.Action, Actions.Addition) - // TODO: Adjust for traditional sharding - .intField( - 'value', - guild.client.guilds.cache.reduce((acc, val) => acc + (val.memberCount ?? 0), 0) - ); - - return this.writePoints([guilds, users]); - } -} diff --git a/src/listeners/analytics/guilds/guildDeleteAnalytics.ts b/src/listeners/analytics/guilds/guildDeleteAnalytics.ts deleted file mode 100644 index 13fc0235d..000000000 --- a/src/listeners/analytics/guilds/guildDeleteAnalytics.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { AnalyticsListener } from '#lib/structures'; -import { Actions, Events, Points, Tags } from '#lib/types'; -import { Point } from '@influxdata/influxdb-client'; -import { ApplyOptions } from '@sapphire/decorators'; -import type { Guild } from 'discord.js'; - -@ApplyOptions({ event: Events.GuildDelete }) -export class UserAnalyticsEvent extends AnalyticsListener { - public run(guild: Guild) { - const guilds = new Point(Points.Guilds) - .tag(Tags.Shard, guild.shardId.toString()) - .tag(Tags.Action, Actions.Subtraction) - // TODO: Adjust for traditional sharding - .intField('value', guild.client.guilds.cache.size); - - const users = new Point(Points.Users) - .tag(Tags.Shard, guild.shardId.toString()) - .tag(Tags.Action, Actions.Subtraction) - // TODO: Adjust for traditional sharding - .intField( - 'value', - guild.client.guilds.cache.reduce((acc, val) => acc + (val.memberCount ?? 0), 0) - ); - return this.writePoints([guilds, users]); - } -} diff --git a/src/listeners/analytics/messages/messageAnalytics.ts b/src/listeners/analytics/messages/messageAnalytics.ts deleted file mode 100644 index ddbc841bb..000000000 --- a/src/listeners/analytics/messages/messageAnalytics.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { AnalyticsListener } from '#lib/structures'; -import { Events } from '#lib/types'; -import { ApplyOptions } from '@sapphire/decorators'; - -@ApplyOptions({ event: Events.MessageCreate }) -export class UserAnalyticsEvent extends AnalyticsListener { - public run(): void { - this.container.client.analytics!.messageCount++; - } -} diff --git a/src/listeners/analytics/resourceAnalyticsSync.ts b/src/listeners/analytics/resourceAnalyticsSync.ts deleted file mode 100644 index 89868ea01..000000000 --- a/src/listeners/analytics/resourceAnalyticsSync.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { AnalyticsListener } from '#lib/structures'; -import { Actions, Events, Points, Tags } from '#lib/types'; -import { Point } from '@influxdata/influxdb-client'; -import { ApplyOptions } from '@sapphire/decorators'; -import { cpus } from 'node:os'; - -@ApplyOptions({ event: Events.ResourceAnalyticsSync }) -export class UserAnalyticsEvent extends AnalyticsListener { - public run() { - this.writePoints([this.syncPerCoreLoad(), this.syncMem()]); - - return this.container.client.analytics!.writeApi.flush(); - } - - private syncPerCoreLoad() { - const point = new Point(Points.PerCoreCPULoad).tag(Tags.Action, Actions.Sync); - - let index = 0; - for (const { times } of cpus()) point.floatField(`cpu_${index++}`, (times.user + times.nice + times.sys + times.irq) / times.idle); - - return point; - } - - private syncMem() { - // TODO: Adjust for traditional sharding - const usage = process.memoryUsage(); - return new Point(Points.Memory) // - .tag(Tags.Action, Actions.Sync) - .floatField('total', usage.heapTotal) - .floatField('used', usage.heapUsed); - } -} diff --git a/src/listeners/commands/_chat-input-shared.ts b/src/listeners/commands/_chat-input-shared.ts deleted file mode 100644 index 6aa28b226..000000000 --- a/src/listeners/commands/_chat-input-shared.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { getSupportedUserLanguageT } from '#lib/i18n/translate'; -import { type ChatInputCommandErrorPayload } from '@sapphire/framework'; -import type { ChatInputSubcommandErrorPayload } from '@sapphire/plugin-subcommands'; -import { MessageFlags } from 'discord.js'; -import { flattenError, generateUnexpectedErrorMessage, resolveError } from './_shared.js'; - -export async function handleCommandError(error: unknown, payload: ChatInputCommandErrorPayload | ChatInputSubcommandErrorPayload) { - const { interaction } = payload; - const t = getSupportedUserLanguageT(interaction); - const resolved = flattenError(payload.command, error); - const content = resolved ? resolveError(t, resolved) : generateUnexpectedErrorMessage(interaction.user.id, payload.command, t, error); - - try { - if (interaction.replied) await interaction.followUp({ content, flags: MessageFlags.Ephemeral }); - else if (interaction.deferred) await interaction.editReply({ content }); - else await interaction.reply({ content, flags: MessageFlags.Ephemeral }); - } catch {} -} diff --git a/src/listeners/commands/_command-log-shared.ts b/src/listeners/commands/_command-log-shared.ts deleted file mode 100644 index 79e9c217c..000000000 --- a/src/listeners/commands/_command-log-shared.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { container } from '@sapphire/framework'; - -export interface CommandLogPayload { - guildId: string | null; - userId: string; - commandName: string; - commandType: string; - commandId?: string | null; - subcommand?: string | null; - channelId?: string | null; - success?: boolean; - errorReason?: string | null; - latencyMs?: number | null; -} - -export function normalizeCommandError(err: unknown): string | null { - if (err === null || err === undefined) return null; - if (err instanceof Error) return err.message.slice(0, 2000); - if (typeof err === 'string') return err.slice(0, 2000); - try { - return JSON.stringify(err).slice(0, 2000); - } catch { - return String(err).slice(0, 2000); - } -} - -export function writeCommandLog(payload: CommandLogPayload): void { - if (payload.guildId === null) return; - void container.prisma.commandLog - .create({ - data: { - guildId: payload.guildId, - userId: payload.userId, - commandName: payload.commandName, - commandType: payload.commandType, - commandId: payload.commandId, - subcommand: payload.subcommand, - channelId: payload.channelId, - success: payload.success, - errorReason: payload.errorReason, - executedAt: new Date(), - latencyMs: payload.latencyMs, - metadata: null - } - }) - .catch(() => null); -} diff --git a/src/listeners/commands/_message-shared.ts b/src/listeners/commands/_message-shared.ts deleted file mode 100644 index 1648d0c52..000000000 --- a/src/listeners/commands/_message-shared.ts +++ /dev/null @@ -1,177 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { fetchT, translate } from '#lib/i18n/translate'; -import type { WolfArgs } from '#lib/structures'; -import { Colors, ZeroWidthSpace, rootFolder } from '#utils/constants'; -import { sendTemporaryMessage } from '#utils/functions'; -import { EmbedBuilder } from '@discordjs/builders'; -import { ArgumentError, Command, Events, UserError, container, type MessageCommandErrorPayload } from '@sapphire/framework'; -import type { TFunction } from '@sapphire/plugin-i18next'; -import type { MessageSubcommandErrorPayload } from '@sapphire/plugin-subcommands'; -import { codeBlock, cutText } from '@sapphire/utilities'; -import { DiscordAPIError, HTTPError, RESTJSONErrorCodes, Routes, type Message } from 'discord.js'; -import { generateUnexpectedErrorMessage } from './_shared.js'; - -const ignoredCodes = [RESTJSONErrorCodes.UnknownChannel, RESTJSONErrorCodes.UnknownMessage]; - -export async function handleCommandError(error: unknown, payload: MessageCommandErrorPayload | MessageSubcommandErrorPayload) { - const { message, command } = payload; - let t: TFunction; - let parameters: string; - if ('args' in payload) { - t = (payload.args as WolfArgs).t; - parameters = payload.parameters; - } else { - t = await fetchT({ guild: message.guild, channel: message.channel, user: message.author }); - parameters = message.content.slice(payload.context.commandPrefix.length + payload.context.commandName.length).trim(); - } - - // If the error was a string or an UserError, send it to the user: - if (!(error instanceof Error)) return stringError(message, t, String(error)); - if (error instanceof ArgumentError) return argumentError(message, t, error); - if (error instanceof UserError) return userError(message, t, error); - - const { client, logger } = container; - // If the error was an AbortError or an Internal Server Error, tell the user to re-try: - if (error.name === 'AbortError' || error.message === 'Internal Server Error') { - logger.warn(`${getWarnError(message)} (${message.author.id}) | ${error.constructor.name}`); - return sendTemporaryMessage(message, t(LanguageKeys.System.DiscordAbortError)); - } - - // Extract useful information about the DiscordAPIError - if (error instanceof DiscordAPIError) { - if (isSilencedError(message, error)) return; - client.emit(Events.Error, error); - } else { - logger.warn(`${getWarnError(message)} (${message.author.id}) | ${error.constructor.name}`); - } - - // Send a detailed message: - await sendErrorChannel(message, command, parameters, error); - - // Emit where the error was emitted - logger.fatal(`[COMMAND] ${command.location.full}\n${error.stack || error.message}`); - try { - await sendTemporaryMessage(message, generateUnexpectedErrorMessage(message.author.id, command, t, error)); - } catch (err) { - client.emit(Events.Error, err); - } - - return undefined; -} - -function isSilencedError(message: Message, error: DiscordAPIError) { - return ( - // If it's an unknown channel or an unknown message, ignore: - ignoredCodes.includes(error.code as number) || - // If it's a DM message reply after a block, ignore: - isDirectMessageReplyAfterBlock(message, error) - ); -} - -function isDirectMessageReplyAfterBlock(message: Message, error: DiscordAPIError) { - // When sending a message to a user who has blocked the bot, Discord replies with 50007 "Cannot send messages to this user": - if (error.code !== RESTJSONErrorCodes.CannotSendMessagesToThisUser) return false; - - // If it's not a Direct Message, return false: - if (message.guild !== null) return false; - - // If the query was made to the message's channel, then it was a DM response: - return error.url === Routes.channelMessages(message.channel.id); -} - -function stringError(message: Message, t: TFunction, error: string) { - return alert(message, t(LanguageKeys.Events.Errors.String, { mention: message.author.toString(), message: error })); -} - -function argumentError(message: Message, t: TFunction, error: ArgumentError) { - const argument = error.argument.name; - const identifier = translate(error.identifier); - const parameter = error.parameter.replaceAll('`', '῾'); - return alert(message, t(identifier, { ...error, ...(error.context as object), argument, parameter: cutText(parameter, 50) })); -} - -function userError(message: Message, t: TFunction, error: UserError) { - // `context: { silent: true }` should make UserError silent: - // Use cases for this are for example permissions error when running the `eval` command. - if (Reflect.get(new Object(error.context), 'silent')) return; - - const identifier = translate(error.identifier); - const content = t(identifier, error.context as any) as string; - return alert(message, content); -} - -function alert(message: Message, content: string) { - return sendTemporaryMessage(message, { content, allowedMentions: { users: [message.author.id], roles: [] } }); -} - -async function sendErrorChannel(message: Message, command: Command, parameters: string, error: Error) { - const webhook = container.client.webhookError; - if (webhook === null) return; - - const lines = [getLinkLine(message.url), getCommandLine(command), getArgumentsLine(parameters), getErrorLine(error)]; - - // If it's a DiscordAPIError or a HTTPError, add the HTTP path and code lines after the second one. - if (error instanceof DiscordAPIError || error instanceof HTTPError) { - lines.splice(2, 0, getPathLine(error), getCodeLine(error)); - } - - const embed = new EmbedBuilder().setDescription(lines.join('\n')).setColor(Colors.Red).setTimestamp(); - try { - await webhook.send({ embeds: [embed] }); - } catch (err) { - container.client.emit(Events.Error, err); - } -} - -/** - * Formats a message url line. - * @param url The url to format. - */ -function getLinkLine(url: string): string { - return `[**Jump to Message!**](${url})`; -} - -/** - * Formats a command line. - * @param command The command to format. - */ -function getCommandLine(command: Command): string { - return `**Command**: ${command.location.full.slice(rootFolder.length)}`; -} - -/** - * Formats an error path line. - * @param error The error to format. - */ -function getPathLine(error: DiscordAPIError | HTTPError): string { - return `**Path**: ${error.method.toUpperCase()} ${error.url}`; -} - -/** - * Formats an error code line. - * @param error The error to format. - */ -function getCodeLine(error: DiscordAPIError | HTTPError): string { - return `**Code**: ${'code' in error ? error.code : error.status}`; -} - -/** - * Formats an arguments line. - * @param parameters The arguments the user used when running the command. - */ -function getArgumentsLine(parameters: string): string { - if (parameters.length === 0) return '**Parameters**: Not Supplied'; - return `**Parameters**: [\`${parameters.trim().replaceAll('`', '῾') || ZeroWidthSpace}\`]`; -} - -/** - * Formats an error codeblock. - * @param error The error to format. - */ -function getErrorLine(error: Error): string { - return `**Error**: ${codeBlock('js', error.stack || error.toString())}`; -} - -function getWarnError(message: Message) { - return `ERROR: /${message.guild ? `${message.guild.id}/${message.channel.id}` : `DM/${message.author.id}`}/${message.id}`; -} diff --git a/src/listeners/commands/_shared.ts b/src/listeners/commands/_shared.ts deleted file mode 100644 index 98728bc1f..000000000 --- a/src/listeners/commands/_shared.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { translate } from '#lib/i18n/translate'; -import { OWNERS } from '#root/config'; -import { getCodeStyle, getLogPrefix } from '#utils/functions'; -import { ArgumentError, ResultError, UserError, container, type Command } from '@sapphire/framework'; -import type { TFunction } from '@sapphire/plugin-i18next'; -import { cutText } from '@sapphire/utilities'; -import { captureException } from '@sentry/node'; -import { envIsDefined } from '@skyra/env-utilities'; -import { DiscordAPIError, HTTPError, RESTJSONErrorCodes, codeBlock, type Snowflake } from 'discord.js'; -import { exists } from 'i18next'; - -const Root = LanguageKeys.Errors; - -export function resolveError(t: TFunction, error: UserError | string) { - return typeof error === 'string' ? resolveStringError(t, error) : resolveUserError(t, error); -} - -function resolveStringError(t: TFunction, error: string) { - return exists(error) ? t(error) : error; -} - -function resolveUserError(t: TFunction, error: UserError) { - const identifier = translate(error.identifier); - return t( - identifier, - error instanceof ArgumentError - ? { ...error, ...(error.context as object), argument: error.argument.name, parameter: cutText(error.parameter.replaceAll('`', '῾'), 50) } - : (error.context as any) - ) as string; -} - -export function flattenError(command: Command, error: unknown): UserError | string | null { - if (typeof error === 'string') return error; - - if (!(error instanceof Error)) { - container.logger.fatal(getLogPrefix(command), 'Unknown unhandled error:', error); - return null; - } - - if (error instanceof ResultError) return flattenError(command, error.value); - if (error instanceof UserError) return error; - - if (error instanceof DiscordAPIError) { - container.logger.error(getLogPrefix(command), getCodeStyle(error.code.toString()), 'Unhandled error:', error); - return getDiscordError(error.code as number); - } - - if (error instanceof HTTPError) { - container.logger.error(getLogPrefix(command), getCodeStyle(error.status.toString()), 'Unhandled error:', error); - return getHttpError(error.status); - } - - if (error.name === 'AbortError') { - return LanguageKeys.System.DiscordAbortError; - } - - container.logger.fatal(getLogPrefix(command), error); - return null; -} - -const sentry = envIsDefined('SENTRY_URL'); -export function generateUnexpectedErrorMessage(userId: Snowflake, command: Command, t: TFunction, error: unknown) { - if (OWNERS.includes(userId)) return codeBlock('js', String(error)); - if (!sentry) return t(LanguageKeys.Events.Errors.UnexpectedError); - - try { - const report = captureException(error, { tags: { command: command.name } }); - return t(LanguageKeys.Events.Errors.UnexpectedErrorWithContext, { report }); - } catch (error) { - return t(LanguageKeys.Events.Errors.UnexpectedError); - } -} - -function getDiscordError(code: RESTJSONErrorCodes) { - switch (code) { - case RESTJSONErrorCodes.UnknownChannel: - return Root.GenericUnknownChannel; - case RESTJSONErrorCodes.UnknownGuild: - return Root.GenericUnknownGuild; - case RESTJSONErrorCodes.UnknownMember: - return Root.GenericUnknownMember; - case RESTJSONErrorCodes.UnknownMessage: - return Root.GenericUnknownMessage; - case RESTJSONErrorCodes.UnknownRole: - return Root.GenericUnknownRole; - case RESTJSONErrorCodes.MissingAccess: - return Root.GenericMissingAccess; - default: - return null; - } -} - -function getHttpError(status: number) { - switch (status) { - case 500: - return Root.GenericDiscordInternalServerError; - case 502: - case 504: - return Root.GenericDiscordGateway; - case 503: - return Root.GenericDiscordUnavailable; - default: - return null; - } -} diff --git a/src/listeners/commands/chatInputCommandError.ts b/src/listeners/commands/chatInputCommandError.ts deleted file mode 100644 index 35616b0c7..000000000 --- a/src/listeners/commands/chatInputCommandError.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Events, Listener, type ChatInputCommandErrorPayload } from '@sapphire/framework'; -import { handleCommandError } from './_chat-input-shared.js'; - -export class UserListener extends Listener { - public run(error: unknown, payload: ChatInputCommandErrorPayload) { - return handleCommandError(error, payload); - } -} diff --git a/src/listeners/commands/chatInputCommandErrorCommandLog.ts b/src/listeners/commands/chatInputCommandErrorCommandLog.ts deleted file mode 100644 index 1989c53dc..000000000 --- a/src/listeners/commands/chatInputCommandErrorCommandLog.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Events, Listener, type ChatInputCommandErrorPayload } from '@sapphire/framework'; -import { normalizeCommandError, writeCommandLog } from './_command-log-shared.js'; - -export class UserListener extends Listener { - public run(error: unknown, payload: ChatInputCommandErrorPayload) { - const { interaction, duration } = payload; - writeCommandLog({ - guildId: interaction.guildId, - userId: interaction.user.id, - commandName: interaction.commandName, - commandType: 'CHAT_INPUT', - commandId: interaction.commandId, - subcommand: interaction.options.getSubcommand(false), - channelId: interaction.channelId, - success: false, - errorReason: normalizeCommandError(error), - latencyMs: duration !== undefined ? Math.round(duration) : null - }); - } -} diff --git a/src/listeners/commands/chatInputCommandSuccessAnalytics.ts b/src/listeners/commands/chatInputCommandSuccessAnalytics.ts deleted file mode 100644 index deb6923d6..000000000 --- a/src/listeners/commands/chatInputCommandSuccessAnalytics.ts +++ /dev/null @@ -1,31 +0,0 @@ -import type { WolfCommand } from '#lib/structures'; -import { readSettings, readSettingsAuditLog } from '#lib/database'; -import { Events as WolfEvents } from '#lib/types'; -import { ApplyOptions } from '@sapphire/decorators'; -import { Events, Listener, type ChatInputCommandSuccessPayload } from '@sapphire/framework'; - -@ApplyOptions({ event: Events.ChatInputCommandSuccess }) -export class UserListener extends Listener { - public async run(payload: ChatInputCommandSuccessPayload) { - const command = payload.command as WolfCommand; - const { interaction } = payload; - this.container.client.emit(WolfEvents.CommandUsageAnalytics, command.name, command.category); - - if (!interaction.guildId || command.category === 'System') return; - const settings = await readSettings(interaction.guildId); - - const subcommandGroup = interaction.options.getSubcommandGroup(false); - const subcommand = interaction.options.getSubcommand(false); - const parts = [interaction.commandName, subcommandGroup, subcommand].filter(Boolean) as string[]; - const commandName = parts.join(' '); - - void readSettingsAuditLog(settings) - .command(interaction.user.id, { - commandName, - commandId: interaction.commandId, - commandType: 'chat-input', - channelId: interaction.channelId - }) - .catch(() => null); - } -} diff --git a/src/listeners/commands/chatInputCommandSuccessCommandLog.ts b/src/listeners/commands/chatInputCommandSuccessCommandLog.ts deleted file mode 100644 index bc1e26076..000000000 --- a/src/listeners/commands/chatInputCommandSuccessCommandLog.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { ApplyOptions } from '@sapphire/decorators'; -import { Events, Listener, type ChatInputCommandSuccessPayload } from '@sapphire/framework'; -import { writeCommandLog } from './_command-log-shared.js'; - -@ApplyOptions({ event: Events.ChatInputCommandSuccess }) -export class UserListener extends Listener { - public run(payload: ChatInputCommandSuccessPayload) { - const { interaction, duration } = payload; - writeCommandLog({ - guildId: interaction.guildId, - userId: interaction.user.id, - commandName: interaction.commandName, - commandType: 'CHAT_INPUT', - commandId: interaction.commandId, - subcommand: interaction.options.getSubcommand(false), - channelId: interaction.channelId, - success: true, - errorReason: null, - latencyMs: duration !== undefined ? Math.round(duration) : null - }); - } -} diff --git a/src/listeners/commands/chatInputCommandSuccessLogger.ts b/src/listeners/commands/chatInputCommandSuccessLogger.ts deleted file mode 100644 index 2d7c175f6..000000000 --- a/src/listeners/commands/chatInputCommandSuccessLogger.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { ApplyOptions } from '@sapphire/decorators'; -import { Events, Listener, LogLevel, type ChatInputCommandSuccessPayload } from '@sapphire/framework'; -import { cyan } from 'colorette'; -import type { User } from 'discord.js'; - -@ApplyOptions({ event: Events.ChatInputCommandSuccess }) -export class UserListener extends Listener { - public run({ interaction }: ChatInputCommandSuccessPayload) { - const shard = `[${cyan('0')}]`; - const commandName = cyan(`/${interaction.commandName}`); - const author = this.author(interaction.user); - const sentAt = interaction.guildId ? `${interaction.guild?.name ?? 'Unknown'}[${cyan(interaction.guildId)}]` : cyan('Direct Messages'); - this.container.logger.debug(`${shard} - ${commandName} ${author} ${sentAt}`); - } - - public override onLoad() { - this.enabled = this.container.logger.has(LogLevel.Debug); - return super.onLoad(); - } - - private author(author: User) { - return `${author.username}[${cyan(author.id)}]`; - } -} diff --git a/src/listeners/commands/chatInputSubcommandError.ts b/src/listeners/commands/chatInputSubcommandError.ts deleted file mode 100644 index c0ddbddfd..000000000 --- a/src/listeners/commands/chatInputSubcommandError.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Listener } from '@sapphire/framework'; -import type { ChatInputSubcommandErrorPayload, SubcommandPluginEvents } from '@sapphire/plugin-subcommands'; -import { handleCommandError } from './_chat-input-shared.js'; - -export class UserListener extends Listener { - public run(error: Error, payload: ChatInputSubcommandErrorPayload) { - return handleCommandError(error, payload); - } -} diff --git a/src/listeners/commands/contextMenuCommandError.ts b/src/listeners/commands/contextMenuCommandError.ts deleted file mode 100644 index f08a2a2a7..000000000 --- a/src/listeners/commands/contextMenuCommandError.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Events, Listener, type ContextMenuCommandErrorPayload } from '@sapphire/framework'; - -export class UserListener extends Listener { - public run(error: Error, payload: ContextMenuCommandErrorPayload) { - this.container.logger.fatal(`[COMMAND] ${payload.command.location.full}\n${error.stack || error.message}`); - } -} diff --git a/src/listeners/commands/contextMenuCommandErrorCommandLog.ts b/src/listeners/commands/contextMenuCommandErrorCommandLog.ts deleted file mode 100644 index 685e452f4..000000000 --- a/src/listeners/commands/contextMenuCommandErrorCommandLog.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Events, Listener, type ContextMenuCommandErrorPayload } from '@sapphire/framework'; -import { normalizeCommandError, writeCommandLog } from './_command-log-shared.js'; - -export class UserListener extends Listener { - public run(error: unknown, payload: ContextMenuCommandErrorPayload) { - const { interaction, duration } = payload; - writeCommandLog({ - guildId: interaction.guildId, - userId: interaction.user.id, - commandName: interaction.commandName, - commandType: 'CONTEXT_MENU', - commandId: interaction.commandId, - subcommand: null, - channelId: interaction.channelId, - success: false, - errorReason: normalizeCommandError(error), - latencyMs: duration !== undefined ? Math.round(duration) : null - }); - } -} diff --git a/src/listeners/commands/contextMenuCommandSuccessAnalytics.ts b/src/listeners/commands/contextMenuCommandSuccessAnalytics.ts deleted file mode 100644 index aaa64fab2..000000000 --- a/src/listeners/commands/contextMenuCommandSuccessAnalytics.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { WolfCommand } from '#lib/structures'; -import { Events as WolfEvents } from '#lib/types'; -import { readSettings, readSettingsAuditLog } from '#lib/database'; -import { ApplyOptions } from '@sapphire/decorators'; -import { Events, Listener, type ContextMenuCommandSuccessPayload } from '@sapphire/framework'; - -@ApplyOptions({ event: Events.ContextMenuCommandSuccess }) -export class UserListener extends Listener { - public async run(payload: ContextMenuCommandSuccessPayload) { - const command = payload.command as WolfCommand; - const { interaction } = payload; - this.container.client.emit(WolfEvents.CommandUsageAnalytics, command.name, command.category); - - if (!interaction.guildId || command.category === 'System') return; - const settings = await readSettings(interaction.guildId); - void readSettingsAuditLog(settings) - .command(interaction.user.id, { - commandName: interaction.commandName, - commandType: 'context-menu', - channelId: interaction.channelId - }) - .catch(() => null); - } -} diff --git a/src/listeners/commands/contextMenuCommandSuccessCommandLog.ts b/src/listeners/commands/contextMenuCommandSuccessCommandLog.ts deleted file mode 100644 index 53df68768..000000000 --- a/src/listeners/commands/contextMenuCommandSuccessCommandLog.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { ApplyOptions } from '@sapphire/decorators'; -import { Events, Listener, type ContextMenuCommandSuccessPayload } from '@sapphire/framework'; -import { writeCommandLog } from './_command-log-shared.js'; - -@ApplyOptions({ event: Events.ContextMenuCommandSuccess }) -export class UserListener extends Listener { - public run(payload: ContextMenuCommandSuccessPayload) { - const { interaction, duration } = payload; - writeCommandLog({ - guildId: interaction.guildId, - userId: interaction.user.id, - commandName: interaction.commandName, - commandType: 'CONTEXT_MENU', - commandId: interaction.commandId, - subcommand: null, - channelId: interaction.channelId, - success: true, - errorReason: null, - latencyMs: duration !== undefined ? Math.round(duration) : null - }); - } -} diff --git a/src/listeners/commands/contextMenuCommandSuccessLogger.ts b/src/listeners/commands/contextMenuCommandSuccessLogger.ts deleted file mode 100644 index 1a2625ebd..000000000 --- a/src/listeners/commands/contextMenuCommandSuccessLogger.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { ApplyOptions } from '@sapphire/decorators'; -import { Events, Listener, LogLevel, type ContextMenuCommandSuccessPayload } from '@sapphire/framework'; -import { cyan } from 'colorette'; -import type { User } from 'discord.js'; - -@ApplyOptions({ event: Events.ContextMenuCommandSuccess }) -export class UserListener extends Listener { - public run({ interaction }: ContextMenuCommandSuccessPayload) { - const shard = `[${cyan('0')}]`; - const commandName = cyan(interaction.commandName); - const author = this.author(interaction.user); - const sentAt = interaction.guildId ? `${interaction.guild?.name ?? 'Unknown'}[${cyan(interaction.guildId)}]` : cyan('Direct Messages'); - this.container.logger.debug(`${shard} - ${commandName} ${author} ${sentAt}`); - } - - public override onLoad() { - this.enabled = this.container.logger.has(LogLevel.Debug); - return super.onLoad(); - } - - private author(author: User) { - return `${author.username}[${cyan(author.id)}]`; - } -} diff --git a/src/listeners/commands/messageCommandError.ts b/src/listeners/commands/messageCommandError.ts deleted file mode 100644 index ae80c18ef..000000000 --- a/src/listeners/commands/messageCommandError.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Events, Listener, type MessageCommandErrorPayload } from '@sapphire/framework'; -import { handleCommandError } from './_message-shared.js'; - -export class UserListener extends Listener { - public run(error: Error, payload: MessageCommandErrorPayload) { - return handleCommandError(error, payload); - } -} diff --git a/src/listeners/commands/messageCommandErrorCommandLog.ts b/src/listeners/commands/messageCommandErrorCommandLog.ts deleted file mode 100644 index 0a708944c..000000000 --- a/src/listeners/commands/messageCommandErrorCommandLog.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Command, Events, Listener, type MessageCommandErrorPayload } from '@sapphire/framework'; -import { normalizeCommandError, writeCommandLog } from './_command-log-shared.js'; - -export class UserListener extends Listener { - public run(error: unknown, payload: MessageCommandErrorPayload) { - const command = payload.command as Command; - const { message, duration } = payload; - writeCommandLog({ - guildId: message.guildId, - userId: message.author.id, - commandName: command.name, - commandType: 'MESSAGE', - commandId: null, - subcommand: null, - channelId: message.channelId, - success: false, - errorReason: normalizeCommandError(error), - latencyMs: duration !== undefined ? Math.round(duration) : null - }); - } -} diff --git a/src/listeners/commands/messageCommandSuccessAnalytics.ts b/src/listeners/commands/messageCommandSuccessAnalytics.ts deleted file mode 100644 index 6971aca31..000000000 --- a/src/listeners/commands/messageCommandSuccessAnalytics.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { WolfCommand } from '#lib/structures'; -import { Events as WolfEvents } from '#lib/types'; -import { ApplyOptions } from '@sapphire/decorators'; -import { readSettings, readSettingsAuditLog } from '#lib/database'; -import { Events, Listener, type MessageCommandSuccessPayload } from '@sapphire/framework'; - -@ApplyOptions({ event: Events.MessageCommandSuccess }) -export class UserListener extends Listener { - public async run(payload: MessageCommandSuccessPayload) { - const command = payload.command as WolfCommand; - const { message } = payload; - this.container.client.emit(WolfEvents.CommandUsageAnalytics, command.name, command.category); - - if (!message.guildId || command.category === 'System') return; - const settings = await readSettings(message.guildId); - void readSettingsAuditLog(settings) - .command(message.author.id, { - commandName: command.name, - commandType: 'message', - channelId: message.channelId - }) - .catch(() => null); - } -} diff --git a/src/listeners/commands/messageCommandSuccessAutoDelete.ts b/src/listeners/commands/messageCommandSuccessAutoDelete.ts deleted file mode 100644 index 0e8a751d5..000000000 --- a/src/listeners/commands/messageCommandSuccessAutoDelete.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { readSettings } from '#lib/database'; -import { isGuildMessage } from '#utils/common'; -import { deleteMessage } from '#utils/functions'; -import { ApplyOptions } from '@sapphire/decorators'; -import { Events, Listener, type MessageCommandSuccessPayload } from '@sapphire/framework'; - -@ApplyOptions({ event: Events.MessageCommandSuccess }) -export class UserListener extends Listener { - public async run({ message }: MessageCommandSuccessPayload) { - if (!isGuildMessage(message)) return; - - const settings = await readSettings(message.guild); - const commandAutoDeleteEntry = settings.commandAutoDelete.find(([id]) => id === message.channel.id); - if (commandAutoDeleteEntry && message.deletable) { - await deleteMessage(message, commandAutoDeleteEntry[1]); - } - } -} diff --git a/src/listeners/commands/messageCommandSuccessCommandLog.ts b/src/listeners/commands/messageCommandSuccessCommandLog.ts deleted file mode 100644 index deba97cd5..000000000 --- a/src/listeners/commands/messageCommandSuccessCommandLog.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { ApplyOptions } from '@sapphire/decorators'; -import { Command, Events, Listener, type MessageCommandSuccessPayload } from '@sapphire/framework'; -import { writeCommandLog } from './_command-log-shared.js'; - -@ApplyOptions({ event: Events.MessageCommandSuccess }) -export class UserListener extends Listener { - public run(payload: MessageCommandSuccessPayload) { - const command = payload.command as Command; - const { message, duration } = payload; - writeCommandLog({ - guildId: message.guildId, - userId: message.author.id, - commandName: command.name, - commandType: 'MESSAGE', - commandId: null, - subcommand: null, - channelId: message.channelId, - success: true, - errorReason: null, - latencyMs: duration !== undefined ? Math.round(duration) : null - }); - } -} diff --git a/src/listeners/commands/messageSubcommandError.ts b/src/listeners/commands/messageSubcommandError.ts deleted file mode 100644 index 59d42058a..000000000 --- a/src/listeners/commands/messageSubcommandError.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Listener } from '@sapphire/framework'; -import type { MessageSubcommandErrorPayload, SubcommandPluginEvents } from '@sapphire/plugin-subcommands'; -import { handleCommandError } from './_message-shared.js'; - -export class UserListener extends Listener { - public run(error: unknown, payload: MessageSubcommandErrorPayload) { - return handleCommandError(error, payload); - } -} diff --git a/src/listeners/guildMessageLog.ts b/src/listeners/guildMessageLog.ts deleted file mode 100644 index 74aaff067..000000000 --- a/src/listeners/guildMessageLog.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { writeSettings, type GuildSettingsOfType } from '#lib/database'; -import { EmbedBuilder } from '@discordjs/builders'; -import { canSendEmbeds } from '@sapphire/discord.js-utilities'; -import { Listener } from '@sapphire/framework'; -import { isNullish, type Awaitable, type Nullish } from '@sapphire/utilities'; -import { DiscordAPIError, HTTPError, type Guild, type MessageCreateOptions, type TextChannel } from 'discord.js'; - -export class UserListener extends Listener { - public async run( - guild: Guild, - logChannelId: string | Nullish, - key: GuildSettingsOfType, - makeMessage: () => Awaitable - ) { - if (isNullish(logChannelId)) return; - - const channel = guild.channels.cache.get(logChannelId) as TextChannel; - if (!channel) { - await writeSettings(guild, { [key]: null }, guild.client.user!.id); - return; - } - - // Don't post if it's not possible - if (!canSendEmbeds(channel)) return; - - const options = this.resolveOptions(await makeMessage()); - try { - await channel.send(options); - } catch (error) { - this.container.logger.fatal( - error instanceof DiscordAPIError || error instanceof HTTPError - ? `Failed to send '${key}' log for guild ${guild} in channel ${channel.name}. Error: [${error.status} - ${error.method} | ${error.url}] ${error.message}` - : `Failed to send '${key}' log for guild ${guild} in channel ${channel.name}. Error: ${(error as Error).message}` - ); - } - } - - private resolveOptions(options: MessageCreateOptions | EmbedBuilder | EmbedBuilder[]): MessageCreateOptions { - if (Array.isArray(options)) return { embeds: options }; - if (options instanceof EmbedBuilder) return { embeds: [options] }; - return options; - } -} diff --git a/src/listeners/guilds/bans/guildBanAdd.ts b/src/listeners/guilds/bans/guildBanAdd.ts deleted file mode 100644 index 187e4d8ee..000000000 --- a/src/listeners/guilds/bans/guildBanAdd.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { readSettings } from '#lib/database'; -import { getModeration } from '#utils/functions'; -import { TypeVariation } from '#utils/moderationConstants'; -import { Listener } from '@sapphire/framework'; -import type { GuildBan } from 'discord.js'; - -export class UserListener extends Listener { - public async run({ guild, user }: GuildBan) { - if (!guild.available) return; - - const settings = await readSettings(guild); - if (!guild.available || !settings.eventsBanAdd) return; - - const moderation = getModeration(guild); - await moderation.waitLock(); - - if (moderation.checkSimilarEntryHasBeenCreated(TypeVariation.Ban, user.id)) return; - await moderation.insert(moderation.create({ user: user.id, type: TypeVariation.Ban })); - } -} diff --git a/src/listeners/guilds/bans/guildBanRemove.ts b/src/listeners/guilds/bans/guildBanRemove.ts deleted file mode 100644 index 3ff57e42b..000000000 --- a/src/listeners/guilds/bans/guildBanRemove.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { readSettings } from '#lib/database'; -import { getModeration } from '#utils/functions'; -import { TypeMetadata, TypeVariation } from '#utils/moderationConstants'; -import { Listener } from '@sapphire/framework'; -import type { GuildBan } from 'discord.js'; - -export class UserListener extends Listener { - public async run({ guild, user }: GuildBan) { - if (!guild.available) return; - - const settings = await readSettings(guild); - if (!guild.available || !settings.eventsBanRemove) return; - - const moderation = getModeration(guild); - await moderation.waitLock(); - - if (moderation.checkSimilarEntryHasBeenCreated(TypeVariation.Ban, user.id)) return; - await moderation.insert(moderation.create({ user, type: TypeVariation.Ban, metadata: TypeMetadata.Undo })); - } -} diff --git a/src/listeners/guilds/channels/channelDeleteNotify.ts b/src/listeners/guilds/channels/channelDeleteNotify.ts deleted file mode 100644 index beddca7cf..000000000 --- a/src/listeners/guilds/channels/channelDeleteNotify.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { readSettings } from '#lib/database'; -import { getT } from '#lib/i18n'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { Colors } from '#utils/constants'; -import { getLogger } from '#utils/functions'; -import { EmbedBuilder } from '@discordjs/builders'; -import { ApplyOptions } from '@sapphire/decorators'; -import { Events, Listener } from '@sapphire/framework'; -import type { TFunction } from '@sapphire/plugin-i18next'; -import type { CategoryChannel, NewsChannel, TextChannel, VoiceChannel } from 'discord.js'; - -type GuildBasedChannel = TextChannel | VoiceChannel | CategoryChannel | NewsChannel; - -@ApplyOptions({ event: Events.ChannelDelete }) -export class UserListener extends Listener { - public async run(channel: GuildBasedChannel) { - const settings = await readSettings(channel.guild); - await getLogger(channel.guild).send({ - key: 'channelsLogsChannelDelete', - channelId: settings.channelsLogsChannelDelete, - makeMessage: () => { - const t = getT(settings.language); - const changes = [...this.getChannelInformation(t, channel)]; - return new EmbedBuilder() - .setColor(Colors.Red) - .setAuthor({ - name: `${channel.name} (${channel.id})`, - iconURL: channel.guild.iconURL({ size: 64, extension: 'png' }) ?? undefined - }) - .setDescription(changes.join('\n')) - .setFooter({ text: t(LanguageKeys.Events.Guilds.Logs.ChannelDelete) }) - .setTimestamp(); - } - }); - } - - private *getChannelInformation(t: TFunction, channel: GuildBasedChannel) { - if (channel.parentId) yield t(LanguageKeys.Events.Guilds.Logs.ChannelCreateParent, { value: `<#${channel.parentId}>` }); - } -} diff --git a/src/listeners/guilds/channels/voiceStateUpdateNotify.ts b/src/listeners/guilds/channels/voiceStateUpdateNotify.ts deleted file mode 100644 index f71bd0e87..000000000 --- a/src/listeners/guilds/channels/voiceStateUpdateNotify.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { readSettings, type ReadonlyGuildData } from '#lib/database'; -import { getT } from '#lib/i18n'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { Colors } from '#utils/constants'; -import { getLogger } from '#utils/functions'; -import { getFullEmbedAuthor } from '#utils/util'; -import { EmbedBuilder } from '@discordjs/builders'; -import { ApplyOptions } from '@sapphire/decorators'; -import { Events, Listener } from '@sapphire/framework'; -import type { TFunction } from '@sapphire/plugin-i18next'; -import type { Snowflake, User, VoiceBasedChannel, VoiceState } from 'discord.js'; - -@ApplyOptions({ event: Events.VoiceStateUpdate }) -export class UserListener extends Listener { - public async run(old: VoiceState, next: VoiceState) { - // If the channel is the same, return: - if (old.channelId === next.channelId) return; - - const oldChannel = old.channel; - const nextChannel = next.channel; - const user = await this.container.client.users.fetch(next.id); - - const settings = await readSettings(next.guild); - await getLogger(next.guild).send({ - key: 'channelsLogsVoiceChannel', - channelId: settings.channelsLogsVoiceChannel, - condition: () => this.onCondition(oldChannel, nextChannel, user, settings), - makeMessage: () => { - const t = getT(settings.language); - const { description, color } = this.render(t, oldChannel, nextChannel); - return new EmbedBuilder() // - .setAuthor(getFullEmbedAuthor(user)) - .setColor(color) - .setDescription(description) - .setFooter({ text: t(LanguageKeys.Events.Messages.VoiceActivityFooter) }) - .setTimestamp(); - } - }); - } - - private onCondition(old: VoiceBasedChannel | null, next: VoiceBasedChannel | null, user: User, settings: ReadonlyGuildData) { - // If includeBots is false, and the user is a bot, return false - if (!settings.eventsIncludeBots && user.bot) return false; - - const ignoredChannels = settings.channelsIgnoreVoiceActivity; - const ignoredAll = settings.channelsIgnoreAll; - // Assume in all conditions that old !== next, as checked earlier. - // If the old channel is null, the user joined a channel, check if `next` is ignored: - if (old === null) return this.onConditionSingleChannel(next!, ignoredChannels, ignoredAll); - // If the new channel is null, the user left a channel, check if `old` is ignored: - if (next === null) return this.onConditionSingleChannel(old, ignoredChannels, ignoredAll); - // If the user changed channels, check if any of the two channels are ignored: - return ( - this.onConditionSingleChannel(old, ignoredChannels, ignoredAll) || // - this.onConditionSingleChannel(next, ignoredChannels, ignoredAll) - ); - } - - private onConditionSingleChannel(channel: VoiceBasedChannel, ignoredChannels: readonly Snowflake[], ignoredAll: readonly Snowflake[]) { - // If the channel is in the ignoredChannels array, return false - if (ignoredChannels.includes(channel.id)) return false; - // If the channel or its parent is in the ignoredAll array, return false - if (ignoredAll.some((id) => id === channel.id || channel.parentId === id)) return false; - // All checks passed, return true - return true; - } - - private render(t: TFunction, old: VoiceBasedChannel | null, next: VoiceBasedChannel | null) { - if (old === null) { - return { - color: Colors.Green, - description: t(LanguageKeys.Events.Guilds.Logs.VoiceChannelJoin, { channel: next!.toString() }) - }; - } - - if (next === null) { - return { - color: Colors.Red, - description: t(LanguageKeys.Events.Guilds.Logs.VoiceChannelLeave, { channel: old.toString() }) - }; - } - - return { - color: Colors.Blue, - description: t(LanguageKeys.Events.Guilds.Logs.VoiceChannelMove, { oldChannel: old.toString(), newChannel: next.toString() }) - }; - } -} diff --git a/src/listeners/guilds/emojis/emojiCreateNotify.ts b/src/listeners/guilds/emojis/emojiCreateNotify.ts deleted file mode 100644 index dbc5e5488..000000000 --- a/src/listeners/guilds/emojis/emojiCreateNotify.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { readSettings } from '#lib/database'; -import { getT } from '#lib/i18n'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { Colors } from '#utils/constants'; -import { getLogger } from '#utils/functions'; -import { EmbedBuilder } from '@discordjs/builders'; -import { ApplyOptions } from '@sapphire/decorators'; -import { Events, Listener } from '@sapphire/framework'; -import type { TFunction } from '@sapphire/plugin-i18next'; -import type { GuildEmoji } from 'discord.js'; - -@ApplyOptions({ event: Events.GuildEmojiCreate }) -export class UserListener extends Listener { - public async run(next: GuildEmoji) { - const settings = await readSettings(next.guild); - await getLogger(next.guild).send({ - key: 'channelsLogsEmojiCreate', - channelId: settings.channelsLogsEmojiCreate, - makeMessage: () => { - const t = getT(settings.language); - const changes: string[] = [...this.getEmojiInformation(t, next)]; - return new EmbedBuilder() - .setColor(Colors.Green) - .setThumbnail(next.imageURL({ size: 256 })) - .setAuthor({ name: `${next.name} (${next.id})`, iconURL: next.guild.iconURL({ size: 64, extension: 'png' }) ?? undefined }) - .setDescription(changes.join('\n')) - .setFooter({ text: t(LanguageKeys.Events.Guilds.Logs.EmojiCreate) }) - .setTimestamp(); - } - }); - } - - private *getEmojiInformation(t: TFunction, next: GuildEmoji) { - if (next.animated) yield t(LanguageKeys.Events.Guilds.Logs.EmojiCreateAnimated); - if (!next.available) yield t(LanguageKeys.Events.Guilds.Logs.EmojiCreateUnAvailable); - if (next.managed) yield t(LanguageKeys.Events.Guilds.Logs.EmojiCreateManaged); - if (next.requiresColons) yield t(LanguageKeys.Events.Guilds.Logs.EmojiCreateRequiresColons); - - const roles = next.roles.cache; - if (roles.size !== 0) { - const values = [...next.roles.cache.values()].map((role) => role.toString()); - yield t(LanguageKeys.Events.Guilds.Logs.EmojiCreateRoles, { values, count: values.length }); - } - } -} diff --git a/src/listeners/guilds/emojis/emojiDeleteNotify.ts b/src/listeners/guilds/emojis/emojiDeleteNotify.ts deleted file mode 100644 index affbab4bf..000000000 --- a/src/listeners/guilds/emojis/emojiDeleteNotify.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { readSettings } from '#lib/database'; -import { getT } from '#lib/i18n'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { Colors } from '#utils/constants'; -import { getLogger } from '#utils/functions'; -import { EmbedBuilder } from '@discordjs/builders'; -import { ApplyOptions } from '@sapphire/decorators'; -import { Events, Listener } from '@sapphire/framework'; -import type { GuildEmoji } from 'discord.js'; - -@ApplyOptions({ event: Events.GuildEmojiDelete }) -export class UserListener extends Listener { - public async run(next: GuildEmoji) { - const settings = await readSettings(next.guild); - await getLogger(next.guild).send({ - key: 'channelsLogsEmojiDelete', - channelId: settings.channelsLogsEmojiDelete, - makeMessage: () => { - const t = getT(settings.language); - return new EmbedBuilder() - .setColor(Colors.Red) - .setThumbnail(next.imageURL({ size: 256 })) - .setAuthor({ name: `${next.name} (${next.id})`, iconURL: next.guild.iconURL({ size: 64, extension: 'png' }) ?? undefined }) - .setFooter({ text: t(LanguageKeys.Events.Guilds.Logs.EmojiDelete) }) - .setTimestamp(); - } - }); - } -} diff --git a/src/listeners/guilds/members/guildMemberAdd.ts b/src/listeners/guilds/members/guildMemberAdd.ts deleted file mode 100644 index 1647c68a3..000000000 --- a/src/listeners/guilds/members/guildMemberAdd.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { readSettings, writeSettings } from '#lib/database'; -import { getT } from '#lib/i18n'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { Events } from '#lib/types'; -import { seconds, toErrorCodeResult } from '#utils/common'; -import { Colors } from '#utils/constants'; -import { getLogPrefix, getLogger, getStickyRoles, getUserMentionWithFlagsString } from '#utils/functions'; -import { getFullEmbedAuthor } from '#utils/util'; -import { EmbedBuilder } from '@discordjs/builders'; -import { Listener } from '@sapphire/framework'; -import type { TFunction } from '@sapphire/plugin-i18next'; -import { isNullish, type Nullish } from '@sapphire/utilities'; -import { Guild, PermissionFlagsBits, RESTJSONErrorCodes, TimestampStyles, time, type GuildMember, type Snowflake } from 'discord.js'; - -const Root = LanguageKeys.Events.Guilds.Members; - -export class UserListener extends Listener { - public async run(member: GuildMember) { - if (await this.#handleStickyRoles(member)) return; - this.container.client.emit(Events.NotMutedMemberAdd, member); - } - - async #handleStickyRoles(member: GuildMember) { - if (!member.guild.members.me!.permissions.has(PermissionFlagsBits.ManageRoles)) return false; - - const stickyRoles = await getStickyRoles(member).fetch(member.id); - if (stickyRoles.length === 0) return false; - - // Handle the case the user is muted - const settings = await readSettings(member); - const mutedRoleId = settings.rolesMuted; - const targetChannelId = settings.channelsLogsMemberAdd; - if (mutedRoleId && stickyRoles.includes(mutedRoleId)) { - void this.#handleMutedMemberAddRole(member, mutedRoleId); - void this.#handleMutedMemberNotify(getT(settings.language), member, targetChannelId); - - return true; - } - - void this.#handleStickyRolesAddRoles(member, stickyRoles); - - return false; - } - - async #handleMutedMemberAddRole(member: GuildMember, mutedRoleId: Snowflake) { - const { guild } = member; - const role = guild.roles.cache.get(mutedRoleId); - if (isNullish(role)) { - await writeSettings(member, { rolesMuted: null }, member.client.user!.id); - } else { - const result = await toErrorCodeResult(member.roles.add(role)); - await result.inspectErrAsync((code) => this.#handleMutedMemberAddRoleErr(guild, code)); - } - } - - async #handleMutedMemberAddRoleErr(guild: Guild, code: RESTJSONErrorCodes) { - // The member left the guild before we could add the role, ignore: - if (code === RESTJSONErrorCodes.UnknownMember) return; - - // The role was deleted, remove it from the settings: - if (code === RESTJSONErrorCodes.UnknownRole) { - await writeSettings(guild, { rolesMuted: null }, guild.client.user!.id); - return; - } - - // Otherwise, log the error: - this.container.logger.error(`${getLogPrefix(this)} Failed to add the muted role to a member.`); - } - - async #handleMutedMemberNotify(t: TFunction, member: GuildMember, targetChannelId: Snowflake | Nullish) { - await getLogger(member.guild).send({ - key: 'channelsLogsMemberAdd', - channelId: targetChannelId, - makeMessage: () => { - const { user } = member; - const description = t(Root.GuildMemberAddDescription, { - user: getUserMentionWithFlagsString(user.flags?.bitfield ?? 0, user.id), - relativeTime: time(seconds.fromMilliseconds(user.createdTimestamp), TimestampStyles.RelativeTime) - }); - return new EmbedBuilder() - .setColor(Colors.Amber) - .setAuthor(getFullEmbedAuthor(member.user)) - .setDescription(description) - .setFooter({ text: t(Root.GuildMemberAddMute) }) - .setTimestamp(); - } - }); - } - - async #handleStickyRolesAddRoles(member: GuildMember, stickyRoles: readonly Snowflake[]) { - const guildRoles = member.guild.roles; - const roles = stickyRoles.filter((role) => guildRoles.cache.has(role)); - const result = await toErrorCodeResult(member.roles.add(roles)); - await result.inspectErrAsync((code) => this.#handleStickyRolesAddRolesErr(code)); - } - - #handleStickyRolesAddRolesErr(code: RESTJSONErrorCodes) { - // The member left the guild before we could add the roles, ignore: - if (code === RESTJSONErrorCodes.UnknownMember) return; - - // Otherwise, log the error: - this.container.logger.error(`${getLogPrefix(this)} Failed to add the muted role to a member.`); - } -} diff --git a/src/listeners/guilds/members/guildMemberUpdateTimeoutNotify.ts b/src/listeners/guilds/members/guildMemberUpdateTimeoutNotify.ts deleted file mode 100644 index 514ddede0..000000000 --- a/src/listeners/guilds/members/guildMemberUpdateTimeoutNotify.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { readSettings } from '#lib/database'; -import { ModerationActions } from '#lib/moderation'; -import { Events } from '#lib/types'; -import { getLogger, getModeration } from '#utils/functions'; -import { TypeMetadata, TypeVariation } from '#utils/moderationConstants'; -import { ApplyOptions } from '@sapphire/decorators'; -import { Listener } from '@sapphire/framework'; -import { isNumber } from '@sapphire/utilities'; -import type { GuildMember } from 'discord.js'; - -@ApplyOptions({ event: Events.GuildMemberUpdate }) -export class UserListener extends Listener { - public async run(previous: GuildMember, next: GuildMember) { - const prevTimeout = this.#getTimeout(previous); - const nextTimeout = this.#getTimeout(next); - if (prevTimeout === nextTimeout) return; - - const { user, guild } = next; - const logger = getLogger(guild); - - // If the action was done by Wolf, skip: - const actionByWolf = logger.timeout.isSet(user.id); - if (actionByWolf) return; - - const controller = new AbortController(); - const contextPromise = logger.timeout.wait(user.id, controller.signal); - - // If the guild doesn't have manual logging enabled, skip: - const settings = await readSettings(guild); - const manualLoggingEnabled = settings.eventsTimeout; - if (!manualLoggingEnabled) { - controller.abort(); - return; - } - - const context = await contextPromise; - const moderation = getModeration(guild); - - const duration = this.#getDuration(nextTimeout); - const entry = moderation.create({ - user, - moderator: context?.userId, - type: TypeVariation.Timeout, - metadata: duration ? TypeMetadata.Temporary : TypeMetadata.Undo, - duration, - reason: context?.reason - }); - await moderation.insert(entry); - await ModerationActions.timeout.completeLastModerationEntryFromUser({ guild, userId: user.id }); - } - - #getTimeout(member: GuildMember) { - const timeout = member.communicationDisabledUntilTimestamp; - return isNumber(timeout) && timeout >= Date.now() ? timeout : null; - } - - #getDuration(timeout: number | null) { - if (timeout === null) return null; - - const now = Date.now(); - return timeout > now ? timeout - now : null; - } -} diff --git a/src/listeners/guilds/members/notMutedMemberAddInitialRole.ts b/src/listeners/guilds/members/notMutedMemberAddInitialRole.ts deleted file mode 100644 index 8058278f9..000000000 --- a/src/listeners/guilds/members/notMutedMemberAddInitialRole.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { readSettings, writeSettings, type GuildDataKey } from '#lib/database'; -import { Events } from '#lib/types'; -import { toErrorCodeResult } from '#utils/common'; -import { getCodeStyle, getLogPrefix } from '#utils/functions'; -import { ApplyOptions } from '@sapphire/decorators'; -import { Listener } from '@sapphire/framework'; -import { isNullish } from '@sapphire/utilities'; -import { PermissionFlagsBits, RESTJSONErrorCodes, type GuildMember } from 'discord.js'; - -@ApplyOptions({ event: Events.NotMutedMemberAdd }) -export class UserListener extends Listener { - public async run(member: GuildMember) { - // If the bot cannot manage roles, do not proceed: - if (!this.canGiveRoles(member)) return; - - const settings = await readSettings(member); - const initial = settings.rolesInitial; - const initialHumans = settings.rolesInitialHumans; - const initialBots = settings.rolesInitialBots; - const roleId = initial ?? (member.user.bot ? initialBots : initialHumans); - if (!roleId) return; - - const result = await toErrorCodeResult(member.roles.add(roleId)); - // If the role was not found or the bot can't give the role, remove it from the settings: - if (result.isErrAnd((code) => code === RESTJSONErrorCodes.UnknownRole || code === RESTJSONErrorCodes.MissingPermissions)) { - const key: GuildDataKey = initial // - ? 'rolesInitial' - : member.user.bot - ? 'rolesInitialBots' - : 'rolesInitialHumans'; - await writeSettings(member, { [key]: null }, member.client.user!.id); - return; - } - - // In any other case, log the error as unexpected: - result.inspectErr((code) => this.container.logger.error(`${getLogPrefix(this)} Failed to give role: ${getCodeStyle(code)}`)); - } - - private canGiveRoles(member: GuildMember) { - const permissions = member.guild.members.me?.permissions; - return !isNullish(permissions) && permissions.has(PermissionFlagsBits.ManageRoles); - } -} diff --git a/src/listeners/guilds/members/notMutedMemberAddNotify.ts b/src/listeners/guilds/members/notMutedMemberAddNotify.ts deleted file mode 100644 index 528aa39a8..000000000 --- a/src/listeners/guilds/members/notMutedMemberAddNotify.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { readSettings } from '#lib/database'; -import { getT } from '#lib/i18n'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { Events } from '#lib/types'; -import { seconds } from '#utils/common'; -import { Colors } from '#utils/constants'; -import { getLogger, getUserMentionWithFlagsString } from '#utils/functions'; -import { getFullEmbedAuthor } from '#utils/util'; -import { EmbedBuilder, TimestampStyles, time } from '@discordjs/builders'; -import { ApplyOptions } from '@sapphire/decorators'; -import { Listener } from '@sapphire/framework'; -import type { GuildMember } from 'discord.js'; - -const Root = LanguageKeys.Events.Guilds.Members; - -@ApplyOptions({ event: Events.NotMutedMemberAdd }) -export class UserListener extends Listener { - public async run(member: GuildMember) { - const settings = await readSettings(member); - const logChannelId = settings.channelsLogsMemberAdd; - await getLogger(member.guild).send({ - key: 'channelsLogsMemberAdd', - channelId: logChannelId, - makeMessage: () => { - const t = getT(settings.language); - const { user } = member; - const description = t(Root.GuildMemberAddDescription, { - user: getUserMentionWithFlagsString(user.flags?.bitfield ?? 0, user.id), - relativeTime: time(seconds.fromMilliseconds(user.createdTimestamp), TimestampStyles.RelativeTime) - }); - return new EmbedBuilder() - .setColor(Colors.Green) - .setAuthor(getFullEmbedAuthor(member.user)) - .setDescription(description) - .setFooter({ text: t(Root.GuildMemberAdd) }) - .setTimestamp(); - } - }); - } -} diff --git a/src/listeners/guilds/members/rawMemberRemoveNotify.ts b/src/listeners/guilds/members/rawMemberRemoveNotify.ts deleted file mode 100644 index b1cdc95ac..000000000 --- a/src/listeners/guilds/members/rawMemberRemoveNotify.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { readSettings } from '#lib/database'; -import { getT } from '#lib/i18n'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { Events } from '#lib/types'; -import { seconds } from '#utils/common'; -import { Colors } from '#utils/constants'; -import { getLogger, getModeration, getUserMentionWithFlagsString } from '#utils/functions'; -import { TypeVariation } from '#utils/moderationConstants'; -import { getFullEmbedAuthor } from '#utils/util'; -import { EmbedBuilder, TimestampStyles, time } from '@discordjs/builders'; -import { ApplyOptions } from '@sapphire/decorators'; -import { Listener } from '@sapphire/framework'; -import { isNullish } from '@sapphire/utilities'; -import type { GatewayGuildMemberRemoveDispatchData, Guild, GuildMember } from 'discord.js'; - -const Root = LanguageKeys.Events.Guilds.Members; - -@ApplyOptions({ event: Events.RawMemberRemove }) -export class UserListener extends Listener { - public async run(guild: Guild, member: GuildMember | null, { user }: GatewayGuildMemberRemoveDispatchData) { - const settings = await readSettings(guild); - const targetChannelId = settings.channelsLogsMemberRemove; - if (isNullish(targetChannelId)) return; - - const isModerationAction = await this.isModerationAction(guild, user); - - const t = getT(settings.language); - const footer = isModerationAction.kicked - ? t(Root.GuildMemberKicked) - : isModerationAction.banned - ? t(Root.GuildMemberBanned) - : isModerationAction.softbanned - ? t(Root.GuildMemberSoftBanned) - : t(Root.GuildMemberRemove); - - const joinedTimestamp = this.processJoinedTimestamp(member); - await getLogger(guild).send({ - key: 'channelsLogsMemberRemove', - channelId: targetChannelId, - makeMessage: () => { - const key = joinedTimestamp === -1 ? Root.GuildMemberRemoveDescription : Root.GuildMemberRemoveDescriptionWithJoinedAt; - const description = t(key, { - user: getUserMentionWithFlagsString(user.flags ?? 0, user.id), - relativeTime: time(seconds.fromMilliseconds(joinedTimestamp), TimestampStyles.RelativeTime) - }); - - return new EmbedBuilder() - .setColor(Colors.Red) - .setAuthor(getFullEmbedAuthor(user)) - .setDescription(description) - .setFooter({ text: footer }) - .setTimestamp(); - } - }); - } - - private async isModerationAction(guild: Guild, user: GatewayGuildMemberRemoveDispatchData['user']): Promise { - const moderation = getModeration(guild); - await moderation.waitLock(); - - const latestLogForUser = moderation.getLatestRecentCachedEntryForUser(user.id); - - if (latestLogForUser === null) { - return { - kicked: false, - banned: false, - softbanned: false - }; - } - - return { - kicked: latestLogForUser.type === TypeVariation.Kick, - banned: latestLogForUser.type === TypeVariation.Ban, - softbanned: latestLogForUser.type === TypeVariation.Softban - }; - } - - private processJoinedTimestamp(member: GuildMember | null) { - if (member === null) return -1; - if (member.joinedTimestamp === null) return -1; - return member.joinedTimestamp; - } -} - -interface IsModerationAction { - readonly kicked: boolean; - readonly banned: boolean; - readonly softbanned: boolean; -} diff --git a/src/listeners/guilds/rawGuildAuditLogEntryCreateLoggerTrack.ts b/src/listeners/guilds/rawGuildAuditLogEntryCreateLoggerTrack.ts deleted file mode 100644 index 3211ec8ec..000000000 --- a/src/listeners/guilds/rawGuildAuditLogEntryCreateLoggerTrack.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { getLogger } from '#utils/functions/guild'; -import { ApplyOptions } from '@sapphire/decorators'; -import { Listener } from '@sapphire/framework'; -import { isNullish, isNullishOrEmpty } from '@sapphire/utilities'; -import { AuditLogEvent, GatewayDispatchEvents, Guild, type GatewayGuildAuditLogEntryCreateDispatchData } from 'discord.js'; - -@ApplyOptions({ event: GatewayDispatchEvents.GuildAuditLogEntryCreate, emitter: 'ws' }) -export class UserListener extends Listener { - public override run(data: GatewayGuildAuditLogEntryCreateDispatchData) { - const guild = this.container.client.guilds.cache.get(data.guild_id); - if (!guild) return; - - switch (data.action_type) { - case AuditLogEvent.MemberUpdate: - return this.#handleMemberUpdateTimeout(guild, data); - case AuditLogEvent.MessageBulkDelete: - getLogger(guild).prune.setFromAuditLogs(data.target_id!, { userId: data.user_id! }); - break; - default: - break; - } - } - - #handleMemberUpdateTimeout(guild: Guild, data: GatewayGuildAuditLogEntryCreateDispatchData) { - if (isNullishOrEmpty(data.changes)) return; - - const change = data.changes.find((change) => change.key === 'communication_disabled_until'); - if (isNullish(change)) return; - - getLogger(guild).timeout.setFromAuditLogs(data.target_id!, { - userId: data.user_id!, - reason: data.reason - }); - } -} diff --git a/src/listeners/guilds/rawGuildCreateMemberFetch.ts b/src/listeners/guilds/rawGuildCreateMemberFetch.ts deleted file mode 100644 index 53fcb2bf6..000000000 --- a/src/listeners/guilds/rawGuildCreateMemberFetch.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { ApplyOptions } from '@sapphire/decorators'; -import { Listener } from '@sapphire/framework'; -import { GatewayDispatchEvents, type GatewayGuildCreateDispatchData } from 'discord.js'; - -@ApplyOptions({ event: GatewayDispatchEvents.GuildCreate, emitter: 'ws' }) -export class UserListener extends Listener { - public run(data: GatewayGuildCreateDispatchData, shardId: number) { - this.container.client.guildMemberFetchQueue.add(shardId, data.id); - } -} diff --git a/src/listeners/guilds/rawGuildDelete.ts b/src/listeners/guilds/rawGuildDelete.ts deleted file mode 100644 index 73e014c4c..000000000 --- a/src/listeners/guilds/rawGuildDelete.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { deleteSettingsCached } from '#lib/database'; -import { ApplyOptions } from '@sapphire/decorators'; -import { Listener } from '@sapphire/framework'; -import { GatewayDispatchEvents, type GatewayGuildDeleteDispatchData } from 'discord.js'; - -@ApplyOptions({ event: GatewayDispatchEvents.GuildDelete, emitter: 'ws' }) -export class UserListener extends Listener { - public run(data: GatewayGuildDeleteDispatchData) { - if (data.unavailable) return; - - deleteSettingsCached(data.id); - } -} diff --git a/src/listeners/guilds/rawGuildDeleteMemberFetch.ts b/src/listeners/guilds/rawGuildDeleteMemberFetch.ts deleted file mode 100644 index d6c329513..000000000 --- a/src/listeners/guilds/rawGuildDeleteMemberFetch.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { ApplyOptions } from '@sapphire/decorators'; -import { Listener } from '@sapphire/framework'; -import { GatewayDispatchEvents, type GatewayGuildDeleteDispatchData } from 'discord.js'; - -@ApplyOptions({ event: GatewayDispatchEvents.GuildDelete, emitter: 'ws' }) -export class UserListener extends Listener { - public run(data: GatewayGuildDeleteDispatchData, shardId: number) { - this.container.client.guildMemberFetchQueue.remove(shardId, data.id); - } -} diff --git a/src/listeners/guilds/roles/roleDelete.ts b/src/listeners/guilds/roles/roleDelete.ts deleted file mode 100644 index 3bc82d01c..000000000 --- a/src/listeners/guilds/roles/roleDelete.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { readSettingsPermissionNodes, writeSettingsTransaction, type StickyRole, type UniqueRoleSet } from '#lib/database'; -import { Listener } from '@sapphire/framework'; -import { filter, map, toArray } from '@sapphire/iterator-utilities'; -import type { Role } from 'discord.js'; - -export class UserListener extends Listener { - public async run(role: Role) { - if (!role.guild.available) return; - - using trx = await writeSettingsTransaction(role); - - trx.write({ stickyRoles: this.#filterStickyRoles(trx.settings.stickyRoles, role) }); - trx.write({ rolesUniqueRoleSets: this.#filterUniqueRoleSets(trx.settings.rolesUniqueRoleSets, role) }); - - trx.write({ reactionRoles: trx.settings.reactionRoles.filter((rr) => rr.role !== role.id) }); - trx.write({ rolesModerator: trx.settings.rolesModerator.filter((rm) => rm !== role.id) }); - trx.write({ rolesAdmin: trx.settings.rolesAdmin.filter((rm) => rm !== role.id) }); - trx.write({ rolesPublic: trx.settings.rolesPublic.filter((rm) => rm !== role.id) }); - - trx.write({ selfmodAttachmentsIgnoredRoles: trx.settings.selfmodAttachmentsIgnoredRoles.filter((rm) => rm !== role.id) }); - trx.write({ selfmodCapitalsIgnoredRoles: trx.settings.selfmodCapitalsIgnoredRoles.filter((rm) => rm !== role.id) }); - trx.write({ selfmodLinksIgnoredRoles: trx.settings.selfmodLinksIgnoredRoles.filter((rm) => rm !== role.id) }); - trx.write({ selfmodMessagesIgnoredRoles: trx.settings.selfmodMessagesIgnoredRoles.filter((rm) => rm !== role.id) }); - trx.write({ selfmodNewlinesIgnoredRoles: trx.settings.selfmodNewlinesIgnoredRoles.filter((rm) => rm !== role.id) }); - trx.write({ selfmodInvitesIgnoredRoles: trx.settings.selfmodInvitesIgnoredRoles.filter((rm) => rm !== role.id) }); - trx.write({ selfmodFilterIgnoredRoles: trx.settings.selfmodFilterIgnoredRoles.filter((rm) => rm !== role.id) }); - trx.write({ selfmodReactionsIgnoredRoles: trx.settings.selfmodReactionsIgnoredRoles.filter((rm) => rm !== role.id) }); - - if (trx.settings.rolesInitial === role.id) trx.write({ rolesInitial: null }); - if (trx.settings.rolesInitialHumans === role.id) trx.write({ rolesInitialHumans: null }); - if (trx.settings.rolesInitialBots === role.id) trx.write({ rolesInitialBots: null }); - if (trx.settings.rolesMuted === role.id) trx.write({ rolesMuted: null }); - if (trx.settings.rolesRestrictedReaction === role.id) trx.write({ rolesRestrictedReaction: null }); - if (trx.settings.rolesRestrictedEmbed === role.id) trx.write({ rolesRestrictedEmbed: null }); - if (trx.settings.rolesRestrictedEmoji === role.id) trx.write({ rolesRestrictedEmoji: null }); - if (trx.settings.rolesRestrictedAttachment === role.id) trx.write({ rolesRestrictedAttachment: null }); - if (trx.settings.rolesRestrictedVoice === role.id) trx.write({ rolesRestrictedVoice: null }); - - const permissionNodes = readSettingsPermissionNodes(trx.settings); - if (permissionNodes.has(role.id)) { - trx.write({ permissionsRoles: permissionNodes.refresh(trx.settings) }); - } - - await trx.submitWithAudit(role.client.user!.id); - } - - #filterStickyRoles(roles: readonly StickyRole[], role: Role) { - const mapped = map(roles, (entry): StickyRole => ({ user: entry.user, roles: entry.roles.filter((srr) => srr !== role.id) })); - const filtered = filter(mapped, (entry) => entry.roles.length > 0); - return toArray(filtered); - } - - #filterUniqueRoleSets(roles: readonly UniqueRoleSet[], role: Role) { - const mapped = map(roles, (entry): UniqueRoleSet => ({ name: entry.name, roles: entry.roles.filter((urs) => urs !== role.id) })); - const filtered = filter(mapped, (entry) => entry.roles.length > 0); - return toArray(filtered); - } -} diff --git a/src/listeners/guilds/roles/roleDeleteNotify.ts b/src/listeners/guilds/roles/roleDeleteNotify.ts deleted file mode 100644 index a52756fa2..000000000 --- a/src/listeners/guilds/roles/roleDeleteNotify.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { readSettings } from '#lib/database'; -import { getT } from '#lib/i18n'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { Colors } from '#utils/constants'; -import { getLogger } from '#utils/functions'; -import { EmbedBuilder } from '@discordjs/builders'; -import { ApplyOptions } from '@sapphire/decorators'; -import { Events, Listener } from '@sapphire/framework'; -import type { Role } from 'discord.js'; - -@ApplyOptions({ event: Events.GuildRoleDelete }) -export class UserListener extends Listener { - public async run(role: Role) { - const settings = await readSettings(role); - await getLogger(role.guild).send({ - key: 'channelsLogsRoleDelete', - channelId: settings.channelsLogsRoleDelete, - makeMessage: () => { - const t = getT(settings.language); - return new EmbedBuilder() - .setColor(Colors.Red) - .setAuthor({ name: `${role.name} (${role.id})`, iconURL: role.guild.iconURL({ size: 64, extension: 'png' }) ?? undefined }) - .setFooter({ text: t(LanguageKeys.Events.Guilds.Logs.RoleDelete) }) - .setTimestamp(); - } - }); - } -} diff --git a/src/listeners/guilds/roles/roleUpdate.ts b/src/listeners/guilds/roles/roleUpdate.ts deleted file mode 100644 index 4eb441a46..000000000 --- a/src/listeners/guilds/roles/roleUpdate.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { readSettingsCached, readSettingsPermissionNodes, writeSettings } from '#lib/database'; -import { Listener } from '@sapphire/framework'; -import type { Role } from 'discord.js'; - -export class UserListener extends Listener { - public async run(previous: Role, next: Role) { - if (!next.guild.available) return; - if (previous.position === next.position) return; - - const settings = readSettingsCached(next); - if (!settings) return; - - const nodes = readSettingsPermissionNodes(settings); - if (!nodes.has(next.id)) return; - - await writeSettings(next, { permissionsRoles: nodes.refresh(settings) }, next.client.user!.id); - } -} diff --git a/src/listeners/interactions/interactionCreate.ts b/src/listeners/interactions/interactionCreate.ts deleted file mode 100644 index ff1b3ab38..000000000 --- a/src/listeners/interactions/interactionCreate.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { ApplyOptions } from '@sapphire/decorators'; -import { Listener } from '@sapphire/framework'; -import { Events, type Interaction } from 'discord.js'; - -@ApplyOptions({ event: Events.InteractionCreate }) -export class UserListener extends Listener { - public run(interaction: Interaction) { - if (!interaction.isMessageComponent()) return; - - for (const llic of this.container.client.lliCollectors) { - // Attempt to route interactions only to collectors that are associated with - // the message that triggered the interaction. If the collector exposes a - // `messageId` or `message.id` property, use that as routing metadata. - const anyCollector = llic as any; - const targetMessageId: string | undefined = anyCollector.messageId ?? anyCollector.message?.id; - - if (targetMessageId && interaction.message?.id !== targetMessageId) { - continue; - } - llic.send(interaction); - } - } -} diff --git a/src/listeners/mentionPrefixOnly.ts b/src/listeners/mentionPrefixOnly.ts deleted file mode 100644 index 93d87ed8f..000000000 --- a/src/listeners/mentionPrefixOnly.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { readSettings } from '#lib/database'; -import { getT } from '#lib/i18n'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import type { DMMessage, GuildMessage } from '#lib/types'; -import { isModerator, sendLocalizedMessage } from '#utils/functions'; -import { Events, Listener } from '@sapphire/framework'; -import { send } from '@sapphire/plugin-editable-commands'; -import type { Message } from 'discord.js'; - -export default class extends Listener { - public run(message: Message) { - return message.guild ? this.guild(message as GuildMessage) : this.dm(message as DMMessage); - } - - private async dm(message: DMMessage) { - const prefix = (await this.container.client.fetchPrefix(message)) as string; - return sendLocalizedMessage(message, { key: LanguageKeys.Misc.PrefixReminder, formatOptions: { prefix } }); - } - - private async guild(message: GuildMessage) { - const settings = await readSettings(message.guild); - if (settings.disabledChannels.includes(message.channel.id) && !(await isModerator(message.member))) return; - - const t = getT(settings.language); - return send(message, t(LanguageKeys.Misc.PrefixReminder, { prefix: settings.prefix })); - } -} diff --git a/src/listeners/mentionSpamExceeded.ts b/src/listeners/mentionSpamExceeded.ts deleted file mode 100644 index c3611622f..000000000 --- a/src/listeners/mentionSpamExceeded.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { readSettings, readSettingsNoMentionSpam } from '#lib/database'; -import { getT } from '#lib/i18n'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { Events, type GuildMessage } from '#lib/types'; -import { getModeration } from '#utils/functions'; -import { TypeVariation } from '#utils/moderationConstants'; -import { getTag } from '#utils/util'; -import { Listener } from '@sapphire/framework'; - -export class UserListener extends Listener { - public async run(message: GuildMessage) { - const settings = await readSettings(message.guild); - const moderation = getModeration(message.guild); - const lock = moderation.createLock(); - try { - const t = getT(settings.language); - await message.guild.members - .ban(message.author.id, { deleteMessageSeconds: 0, reason: t(LanguageKeys.Events.NoMentionSpam.Footer) }) - .catch((error) => this.container.client.emit(Events.Error, error)); - await message.channel - .send(t(LanguageKeys.Events.NoMentionSpam.Message, { userId: message.author.id, userTag: getTag(message.author) })) - .catch((error) => this.container.client.emit(Events.Error, error)); - - const ctx = readSettingsNoMentionSpam(settings); - ctx.delete(message.author.id); - - const threshold = settings.noMentionSpamMentionsAllowed; - const reason = t(LanguageKeys.Events.NoMentionSpam.ModerationLog, { threshold }); - await moderation.insert(moderation.create({ user: message.author.id, type: TypeVariation.Ban, reason })); - } finally { - lock(); - } - } -} diff --git a/src/listeners/mentionSpamWarning.ts b/src/listeners/mentionSpamWarning.ts deleted file mode 100644 index 0ea26dec4..000000000 --- a/src/listeners/mentionSpamWarning.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { sendTemporaryMessage } from '#utils/functions'; -import { Listener } from '@sapphire/framework'; -import { resolveKey } from '@sapphire/plugin-i18next'; -import type { Message } from 'discord.js'; - -export class UserListener extends Listener { - public async run(message: Message) { - await sendTemporaryMessage(message, await resolveKey(message, LanguageKeys.Events.NoMentionSpam.Alert)); - } -} diff --git a/src/listeners/messages/rawMessageDeleteBulkNotify.ts b/src/listeners/messages/rawMessageDeleteBulkNotify.ts deleted file mode 100644 index bcee3108d..000000000 --- a/src/listeners/messages/rawMessageDeleteBulkNotify.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { readSettings } from '#lib/database'; -import { getT } from '#lib/i18n'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import type { GuildMessage } from '#lib/types'; -import { Colors } from '#utils/constants'; -import { formatMessage, formatTimestamp } from '#utils/formatters'; -import { getLogger } from '#utils/functions/guild'; -import { EmbedBuilder } from '@discordjs/builders'; -import { ApplyOptions } from '@sapphire/decorators'; -import { Listener } from '@sapphire/framework'; -import type { TFunction } from '@sapphire/plugin-i18next'; -import { - AttachmentBuilder, - GatewayDispatchEvents, - SnowflakeUtil, - channelMention, - messageLink, - userMention, - type GatewayMessageDeleteBulkDispatchData, - type GuildTextBasedChannel, - type Snowflake -} from 'discord.js'; - -@ApplyOptions({ event: GatewayDispatchEvents.MessageDeleteBulk, emitter: 'ws' }) -export class UserListener extends Listener { - public async run(data: GatewayMessageDeleteBulkDispatchData) { - if (!data.guild_id) return; - - const guild = this.container.client.guilds.cache.get(data.guild_id); - if (!guild) return; - - const logger = getLogger(guild); - - const channel = guild.channels.cache.get(data.channel_id) as GuildTextBasedChannel; - if (!channel) return logger.prune.unset(data.channel_id); - - const messages = data.ids.map((id) => ({ id, message: channel.messages.cache.get(id) ?? null }) as BulkMessageEntry); - const contextPromise = logger.prune.wait(data.channel_id); - - const settings = await readSettings(guild); - await logger.send({ - key: 'channelsLogsPrune', - channelId: settings.channelsLogsPrune, - condition: () => - !settings.messagesIgnoreChannels.some((id) => id === channel.id || channel.parentId === id) || - !settings.channelsIgnoreMessageDelete.some((id) => id === channel.id && channel.parentId === id) || - !settings.channelsIgnoreAll.some((id) => id === channel.id || channel.parentId === id), - makeMessage: async () => { - const t = getT(settings.language); - const context = await contextPromise; - const description = context - ? t(LanguageKeys.Events.Messages.MessageDeleteBulk, { - author: userMention(context.userId), - channel: channelMention(channel.id), - count: messages.length - }) - : t(LanguageKeys.Events.Messages.MessageDeleteBulkUnknown, { - channel: channelMention(channel.id), - count: messages.length - }); - - const embed = new EmbedBuilder() - .setFooter({ text: t(LanguageKeys.Events.Messages.MessageDeleteBulkFooter) }) - .setDescription(description) - .setColor(Colors.Brown) - .setTimestamp(); - - return { embeds: [embed], files: [this.generateAttachment(t, channel.id, guild.id, messages)] }; - }, - onAbort: () => logger.prune.unset(data.channel_id) - }); - } - - private generateAttachment(t: TFunction, channelId: Snowflake, guildId: Snowflake, messages: readonly BulkMessageEntry[]) { - const header = t(LanguageKeys.Commands.Moderation.PruneLogHeader); - const processed = messages - .map((entry) => - entry.message - ? formatMessage(t, entry.message) - : `${formatTimestamp(t, SnowflakeUtil.timestampFrom(entry.id))} ${messageLink(channelId, entry.id, guildId)}` - ) - .reverse() - .join('\n\n'); - - const buffer = Buffer.from(`${header}\n\n${processed}`); - return new AttachmentBuilder(buffer, { name: 'prune.txt' }); - } -} - -interface BulkMessageEntry { - id: string; - message: GuildMessage | null; -} diff --git a/src/listeners/messages/rawMessageDeleteNotify.ts b/src/listeners/messages/rawMessageDeleteNotify.ts deleted file mode 100644 index c83d2a090..000000000 --- a/src/listeners/messages/rawMessageDeleteNotify.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { readSettings, type GuildDataKey, type ReadonlyGuildData } from '#lib/database'; -import { getT } from '#lib/i18n'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import type { GuildMessage } from '#lib/types'; -import { Colors } from '#utils/constants'; -import { makeRow } from '#utils/deprecate'; -import { getLogger } from '#utils/functions'; -import { getContent, getFullEmbedAuthor, getImages, setMultipleEmbedImages } from '#utils/util'; -import { ButtonBuilder, EmbedBuilder } from '@discordjs/builders'; -import { ApplyOptions } from '@sapphire/decorators'; -import { isNsfwChannel } from '@sapphire/discord.js-utilities'; -import { Listener } from '@sapphire/framework'; -import type { TFunction } from '@sapphire/plugin-i18next'; -import { cutText, isNullish, isNullishOrEmpty } from '@sapphire/utilities'; -import { ButtonStyle, GatewayDispatchEvents, messageLink, type GatewayMessageDeleteDispatchData, type GuildTextBasedChannel } from 'discord.js'; - -@ApplyOptions({ event: GatewayDispatchEvents.MessageDelete, emitter: 'ws' }) -export class UserListener extends Listener { - public async run(data: GatewayMessageDeleteDispatchData) { - if (!data.guild_id) return; - - const guild = this.container.client.guilds.cache.get(data.guild_id); - if (!guild) return; - - const channel = guild.channels.cache.get(data.channel_id) as GuildTextBasedChannel; - if (!channel) return; - - const message = channel.messages.cache.get(data.id) as GuildMessage | undefined; - - const settings = await readSettings(guild); - const key: GuildDataKey = isNsfwChannel(channel) ? 'channelsLogsMessageDeleteNsfw' : 'channelsLogsMessageDelete'; - await getLogger(guild).send({ - key, - channelId: settings[key], - condition: () => this.onCondition(message, channel, settings), - makeMessage: () => { - const t = getT(settings.language); - const embed = new EmbedBuilder().setColor(Colors.Red).setTimestamp(); - - if (isNullish(message)) { - return { - embeds: [embed.setFooter({ text: t(LanguageKeys.Events.Messages.MessageDeleteUnknown, { channel: `#${channel.name}` }) })], - components: [this.getJumpButton(t, channel.id, data.id)] - }; - } - - embed - .setAuthor(getFullEmbedAuthor(message.author, message.url)) - .setFooter({ text: t(LanguageKeys.Events.Messages.MessageDelete, { channel: `#${channel.name}` }) }); - - const content = getContent(message); - if (!isNullishOrEmpty(content)) embed.setDescription(cutText(content, 1900)); - - return setMultipleEmbedImages(embed, getImages(message)); - } - }); - } - - private onCondition(message: GuildMessage | undefined, channel: GuildTextBasedChannel, settings: ReadonlyGuildData) { - // If includeBots is false, and the message author is a bot, return false - if (!settings.eventsIncludeBots && message?.author.bot) return false; - // If allowUnknownMessages is false, and the message is nullish, return false - if (!settings.eventsUnknownMessages && isNullish(message)) return false; - // If the channel is in the ignoredChannels array, return false - if (settings.messagesIgnoreChannels.includes(channel.id)) return false; - // If the channel or its parent is in the ignoredDeletes array, return false - if (settings.channelsIgnoreMessageDelete.some((id) => id === channel.id || channel.parentId === id)) return false; - // If the channel or its parent is in the ignoredAll array, return false - if (settings.channelsIgnoreAll.some((id) => id === channel.id || channel.parentId === id)) return false; - // All checks passed, return true - return true; - } - - private getJumpButton(t: TFunction, channelId: string, messageId: string) { - return makeRow( - new ButtonBuilder() - .setStyle(ButtonStyle.Link) - .setURL(messageLink(channelId, messageId)) - .setLabel(t(LanguageKeys.Events.Messages.JumpToContext)) - ); - } -} diff --git a/src/listeners/messages/rawMessageUpdateNotify.ts b/src/listeners/messages/rawMessageUpdateNotify.ts deleted file mode 100644 index 1407dcab5..000000000 --- a/src/listeners/messages/rawMessageUpdateNotify.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { readSettings, type GuildDataKey, type ReadonlyGuildData } from '#lib/database'; -import { getT } from '#lib/i18n'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { type GuildMessage } from '#lib/types'; -import { escapeMarkdown } from '#utils/External/escapeMarkdown'; -import { Colors } from '#utils/constants'; -import { addAutomaticFields, getLogger } from '#utils/functions'; -import { getFullEmbedAuthor } from '#utils/util'; -import { EmbedBuilder } from '@discordjs/builders'; -import { ApplyOptions } from '@sapphire/decorators'; -import { isNsfwChannel } from '@sapphire/discord.js-utilities'; -import { Listener } from '@sapphire/framework'; -import { isNullish, isNullishOrEmpty } from '@sapphire/utilities'; -import { diffWordsWithSpace } from 'diff'; -import { - GatewayDispatchEvents, - bold, - messageLink, - strikethrough, - type APIUser, - type GatewayMessageUpdateDispatchData, - type GuildTextBasedChannel -} from 'discord.js'; - -@ApplyOptions({ event: GatewayDispatchEvents.MessageUpdate, emitter: 'ws' }) -export class UserListener extends Listener { - public async run(data: GatewayMessageUpdateDispatchData) { - if (!data.guild_id) return; - - const guild = this.container.client.guilds.cache.get(data.guild_id); - if (!guild) return; - - const channel = guild.channels.cache.get(data.channel_id) as GuildTextBasedChannel; - if (!channel) return; - - const cachedMessage = channel.messages.cache.get(data.id) as GuildMessage | undefined; - const oldContent = cachedMessage?.content; - const currentContent = data.content ?? ''; - if ((cachedMessage && cachedMessage.content === currentContent) || data.webhook_id || !data.author) return; - - const key: GuildDataKey = isNsfwChannel(channel) ? 'channelsLogsMessageUpdateNsfw' : 'channelsLogsMessageUpdate'; - const settings = await readSettings(guild); - await getLogger(guild).send({ - key, - channelId: settings[key], - condition: () => this.onCondition(cachedMessage, channel, data.author!, settings), - makeMessage: () => { - const t = getT(settings.language); - const embed = new EmbedBuilder() - .setColor(Colors.Amber) - .setAuthor(getFullEmbedAuthor(data.author!, messageLink(data.channel_id, data.id))) - .setTimestamp(); - - if (isNullish(cachedMessage)) { - addAutomaticFields(embed, currentContent) // - .setFooter({ text: t(LanguageKeys.Events.Messages.MessageUpdateUnknown, { channel: `#${channel.name}` }) }); - } else { - addAutomaticFields(embed, this.getMessageDifference(oldContent!, currentContent)) // - .setFooter({ text: t(LanguageKeys.Events.Messages.MessageUpdate, { channel: `#${channel.name}` }) }); - } - return embed; - } - }); - } - - private onCondition(cachedMessage: GuildMessage | undefined, channel: GuildTextBasedChannel, author: APIUser, settings: ReadonlyGuildData) { - // If includeBots is false, and the message author is a bot, return false - if (!settings.eventsIncludeBots && author.bot) return false; - // If allowUnknownMessages is false, and the message is nullish, return false - if (!settings.eventsUnknownMessages && isNullish(cachedMessage)) return false; - // If the channel is in the ignoredChannels array, return false - if (settings.messagesIgnoreChannels.includes(channel.id)) return false; - // If the channel or its parent is in the ignoredEdits array, return false - if (settings.channelsIgnoreMessageEdit.some((id) => id === channel.id || channel.parentId === id)) return false; - // If the channel or its parent is in the ignoredAll array, return false - if (settings.channelsIgnoreAll.some((id) => id === channel.id || channel.parentId === id)) return false; - // All checks passed, return true - return true; - } - - private getMessageDifference(old: string, current: string) { - const oldEmpty = isNullishOrEmpty(old); - const currentEmpty = isNullishOrEmpty(current); - - // If both are empty, return an empty string - if (oldEmpty && currentEmpty) return ''; - // If it went from empty to not empty, return the current bolded - if (oldEmpty && !currentEmpty) return bold(current); - // If it went from not empty to empty, return the old strikethrough - if (!oldEmpty && currentEmpty) return strikethrough(old); - // If both are not empty, return the difference - return diffWordsWithSpace(escapeMarkdown(old), escapeMarkdown(current)) - .map((result) => (result.added ? bold(result.value) : result.removed ? strikethrough(result.value) : result.value)) - .join(' '); - } -} diff --git a/src/listeners/moderation/moderationEntryAdd.ts b/src/listeners/moderation/moderationEntryAdd.ts deleted file mode 100644 index eed72fbe7..000000000 --- a/src/listeners/moderation/moderationEntryAdd.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { writeSettings } from '#lib/database'; -import type { ModerationManager } from '#lib/moderation'; -import { getEmbed, getUndoTaskName } from '#lib/moderation/common'; -import { resolveOnErrorCodes } from '#utils/common'; -import { getModeration } from '#utils/functions'; -import { canSendEmbeds } from '@sapphire/discord.js-utilities'; -import { Listener } from '@sapphire/framework'; -import { fetchT } from '@sapphire/plugin-i18next'; -import { isNullishOrZero } from '@sapphire/utilities'; -import { RESTJSONErrorCodes } from 'discord.js'; - -export class UserListener extends Listener { - public run(entry: ModerationManager.Entry) { - return Promise.all([this.sendMessage(entry), this.scheduleDuration(entry)]); - } - - private async sendMessage(entry: ModerationManager.Entry) { - const moderation = getModeration(entry.guild); - const channel = await moderation.fetchChannel(); - if (channel === null || !canSendEmbeds(channel)) return; - - const t = await fetchT(entry.guild); - const options = { embeds: [await getEmbed(t, entry)] }; - try { - await resolveOnErrorCodes(channel.send(options), RESTJSONErrorCodes.MissingAccess, RESTJSONErrorCodes.MissingPermissions); - } catch (error) { - await writeSettings(entry.guild, { channelsLogsModeration: null }, entry.guild.client.user!.id); - } - } - - private async scheduleDuration(entry: ModerationManager.Entry) { - if (isNullishOrZero(entry.duration)) return; - - const taskName = getUndoTaskName(entry.type); - if (taskName === null) return; - - await this.container.schedule - .add(taskName, entry.expiresTimestamp!, { - catchUp: true, - data: { - caseID: entry.id, - userID: entry.userId, - guildID: entry.guild.id, - // @ts-expect-error complex types - type: entry.type, - duration: entry.duration, - extraData: entry.extraData - } - }) - .catch((error) => this.container.logger.fatal(error)); - } -} diff --git a/src/listeners/moderation/moderationEntryEdit.ts b/src/listeners/moderation/moderationEntryEdit.ts deleted file mode 100644 index 2dc408040..000000000 --- a/src/listeners/moderation/moderationEntryEdit.ts +++ /dev/null @@ -1,148 +0,0 @@ -import { writeSettings } from '#lib/database'; -import type { ModerationManager } from '#lib/moderation'; -import { getEmbed, getUndoTaskName } from '#lib/moderation/common'; -import type { ScheduleEntry } from '#lib/schedule'; -import type { GuildMessage } from '#lib/types'; -import { resolveOnErrorCodes } from '#utils/common'; -import { getModeration } from '#utils/functions'; -import { isUserSelf } from '#utils/util'; -import { canSendEmbeds, type GuildTextBasedChannelTypes } from '@sapphire/discord.js-utilities'; -import { Listener } from '@sapphire/framework'; -import { fetchT } from '@sapphire/plugin-i18next'; -import { isNullish } from '@sapphire/utilities'; -import { DiscordAPIError, RESTJSONErrorCodes, type Collection, type Embed, type Message, type Snowflake } from 'discord.js'; - -export class UserListener extends Listener { - public run(old: ModerationManager.Entry, entry: ModerationManager.Entry) { - return Promise.all([this.scheduleDuration(old, entry), this.sendMessage(old, entry)]); - } - - private async scheduleDuration(old: ModerationManager.Entry, entry: ModerationManager.Entry) { - // If the entry has been archived in this update, delete the task: - if (entry.isArchived() || entry.isCompleted()) { - await this.#tryDeleteTask(entry.task); - return; - } - - if (old.duration === entry.duration) return; - - const { task } = entry; - if (isNullish(task)) { - if (entry.duration !== null) await this.#createNewTask(entry); - } else if (entry.duration === null) { - // If the new duration is null, delete the previous task: - await this.#tryDeleteTask(task); - } else { - // If the new duration is not null, reschedule the previous task: - await task.reschedule(entry.expiresTimestamp!); - } - } - - private async sendMessage(old: ModerationManager.Entry, entry: ModerationManager.Entry) { - if (entry.isArchived() || this.#isCompleteUpdate(old, entry)) return; - - const moderation = getModeration(entry.guild); - const channel = await moderation.fetchChannel(); - if (channel === null || !canSendEmbeds(channel)) return; - - const t = await fetchT(entry.guild); - const previous = await this.fetchModerationLogMessage(entry, channel); - const options = { embeds: [await getEmbed(t, entry)] }; - try { - await resolveOnErrorCodes( - previous === null ? channel.send(options) : previous.edit(options), - RESTJSONErrorCodes.MissingAccess, - RESTJSONErrorCodes.MissingPermissions - ); - } catch (error) { - await writeSettings(entry.guild, { channelsLogsModeration: null }, entry.guild.client.user!.id); - } - } - - private async fetchModerationLogMessage(entry: ModerationManager.Entry, channel: GuildTextBasedChannelTypes) { - const messages = await this.fetchChannelMessages(channel); - for (const message of messages.values()) { - if (this.#validateModerationLogMessage(message, entry.id)) return message; - } - - return null; - } - - /** - * Fetch 100 messages from the modlogs channel - */ - private async fetchChannelMessages(channel: GuildTextBasedChannelTypes, remainingRetries = 5): Promise> { - try { - return (await channel.messages.fetch({ limit: 100 })) as Collection; - } catch (error) { - if (error instanceof DiscordAPIError) throw error; - return this.fetchChannelMessages(channel, --remainingRetries); - } - } - - #isCompleteUpdate(old: ModerationManager.Entry, entry: ModerationManager.Entry) { - return !old.isCompleted() && entry.isCompleted(); - } - - async #tryDeleteTask(task: ScheduleEntry | null) { - if (!isNullish(task) && !task.running) await task.delete(); - } - - #validateModerationLogMessage(message: Message, caseId: number) { - return ( - isUserSelf(message.author.id) && - message.attachments.size === 0 && - message.embeds.length === 1 && - this.#validateModerationLogMessageEmbed(message.embeds[0]) && - message.embeds[0].footer!.text.includes(caseId.toString()) - ); - } - - #validateModerationLogMessageEmbed(embed: Embed) { - return ( - this.#validateModerationLogMessageEmbedAuthor(embed.author) && - this.#validateModerationLogMessageEmbedDescription(embed.description) && - this.#validateModerationLogMessageEmbedColor(embed.color) && - this.#validateModerationLogMessageEmbedFooter(embed.footer) && - this.#validateModerationLogMessageEmbedTimestamp(embed.timestamp) - ); - } - - #validateModerationLogMessageEmbedAuthor(author: Embed['author']) { - return author !== null && typeof author.name === 'string' && /\(\d{17,19}\)$/.test(author.name) && typeof author.iconURL === 'string'; - } - - #validateModerationLogMessageEmbedDescription(description: Embed['description']) { - return typeof description === 'string' && description.split('\n').length >= 3; - } - - #validateModerationLogMessageEmbedColor(color: Embed['color']) { - return !isNullish(color); - } - - #validateModerationLogMessageEmbedFooter(footer: Embed['footer']) { - return footer !== null && typeof footer.text === 'string' && typeof footer.iconURL === 'string'; - } - - #validateModerationLogMessageEmbedTimestamp(timestamp: Embed['timestamp']) { - return !isNullish(timestamp); - } - - async #createNewTask(entry: ModerationManager.Entry) { - const taskName = getUndoTaskName(entry.type); - if (isNullish(taskName)) return; - - await this.container.schedule.add(taskName, entry.expiresTimestamp!, { - catchUp: true, - data: { - caseID: entry.id, - userID: entry.userId, - guildID: entry.guild.id, - // @ts-expect-error complex types - type: entry.type, - duration: entry.duration, - extraData: entry.extraData - } - }); - } -} diff --git a/src/listeners/reactions/rawReactionAddBlockList.ts b/src/listeners/reactions/rawReactionAddBlockList.ts deleted file mode 100644 index 71499698a..000000000 --- a/src/listeners/reactions/rawReactionAddBlockList.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { readSettings, readSettingsAdder, type GuildSettingsOfType } from '#lib/database'; -import { api } from '#lib/discord/Api'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { AutoModerationOnInfraction, ModerationListener, type HardPunishment } from '#lib/moderation'; -import { Events } from '#lib/types'; -import type { LLRCData } from '#utils/LongLivingReactionCollector'; -import { floatPromise, seconds } from '#utils/common'; -import { Colors } from '#utils/constants'; -import { - deleteMessage, - getCustomEmojiUrl, - getEmojiReactionFormat, - getEncodedTwemoji, - getTwemojiUrl, - isModerator, - type SerializedEmoji -} from '#utils/functions'; -import { getFullEmbedAuthor } from '#utils/util'; -import { EmbedBuilder } from '@discordjs/builders'; -import { ApplyOptions } from '@sapphire/decorators'; -import { fetchT, resolveKey } from '@sapphire/plugin-i18next'; -import type { Nullish } from '@sapphire/utilities'; - -type ArgumentType = [data: LLRCData, reaction: SerializedEmoji, channelId: string | Nullish, blockedReactions: readonly string[]]; - -@ApplyOptions({ event: Events.RawReactionAdd }) -export class UserModerationEvent extends ModerationListener { - protected keyEnabled: GuildSettingsOfType = 'selfmodReactionsEnabled'; - protected softPunishmentPath: GuildSettingsOfType = 'selfmodReactionsSoftAction'; - protected hardPunishmentPath: HardPunishment = { - action: 'selfmodReactionsHardAction', - actionDuration: 'selfmodReactionsHardActionDuration', - adder: 'reactions' - }; - - public async run(data: LLRCData, emoji: SerializedEmoji) { - const settings = await readSettings(data.guild); - const blockedReactions = settings.selfmodReactionsBlocked; - const logChannelId = settings.channelsLogsModeration; - - if (!settings.selfmodReactionsEnabled || blockedReactions.length === 0 || settings.channelsIgnoreReactionAdd.includes(data.channel.id)) { - return; - } - - const member = await data.guild.members.fetch(data.userId); - if (member.user.bot || (await isModerator(member))) return; - - const args = [data, emoji, logChannelId, blockedReactions] as const; - const preProcessed = this.preProcess(args); - if (preProcessed === null) return; - - const softAction = settings.selfmodReactionsSoftAction; - const hardAction = settings.selfmodReactionsHardAction; - this.processSoftPunishment(args, preProcessed, AutoModerationOnInfraction.resolve(softAction)); - - const adder = readSettingsAdder(settings, this.hardPunishmentPath.adder); - if (!adder) return this.processHardPunishment(data.guild, data.userId, hardAction); - - try { - const points = typeof preProcessed === 'number' ? preProcessed : 1; - adder.add(data.userId, points); - } catch { - await this.processHardPunishment(data.guild, data.userId, hardAction); - } - } - - protected preProcess([, emoji, , blockedReactions]: Readonly) { - return blockedReactions.includes(emoji) ? 1 : null; - } - - protected onDelete([data, emoji]: Readonly) { - floatPromise(api().channels.deleteUserMessageReaction(data.channel.id, data.messageId, getEmojiReactionFormat(emoji), data.userId)); - } - - protected onAlert([data]: Readonly) { - floatPromise( - resolveKey(data.guild, LanguageKeys.Events.Reactions.Filter, { user: `<@${data.userId}>` }) - .then((content) => data.channel.send(content)) - .then((message) => deleteMessage(message, seconds(15))) - ); - } - - protected async onLogMessage([data]: Readonly) { - const user = await this.container.client.users.fetch(data.userId); - const t = await fetchT(data.guild); - return new EmbedBuilder() - .setColor(Colors.Red) - .setAuthor(getFullEmbedAuthor(user)) - .setThumbnail( - data.emoji.id === null // - ? getTwemojiUrl(getEncodedTwemoji(data.emoji.name!)) - : getCustomEmojiUrl(data.emoji.id, data.emoji.animated) - ) - .setDescription(`[${t(LanguageKeys.Misc.JumpTo)}](https://discord.com/channels/${data.guild.id}/${data.channel.id}/${data.messageId})`) - .setFooter({ text: `${data.channel.name} | ${t(LanguageKeys.Events.Reactions.FilterFooter)}` }) - .setTimestamp(); - } - - protected onLog(args: Readonly) { - this.container.client.emit(Events.GuildMessageLog, args[0].guild, args[2], 'channelsLogsModeration', this.onLogMessage.bind(this, args)); - } -} diff --git a/src/listeners/reactions/rawReactionAddNotify.ts b/src/listeners/reactions/rawReactionAddNotify.ts deleted file mode 100644 index fdb18fd7b..000000000 --- a/src/listeners/reactions/rawReactionAddNotify.ts +++ /dev/null @@ -1,175 +0,0 @@ -import { readSettings } from '#lib/database'; -import { api } from '#lib/discord/Api'; -import { getT } from '#lib/i18n'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { Events } from '#lib/types'; -import type { LLRCData, LLRCDataEmoji } from '#utils/LongLivingReactionCollector'; -import { toErrorCodeResult } from '#utils/common'; -import { Colors } from '#utils/constants'; -import { - getCodeStyle, - getCustomEmojiUrl, - getEmojiId, - getEmojiReactionFormat, - getEncodedTwemoji, - getLogPrefix, - getLogger, - getTwemojiUrl, - type SerializedEmoji -} from '#utils/functions'; -import { getFullEmbedAuthor } from '#utils/util'; -import { EmbedBuilder } from '@discordjs/builders'; -import { ApplyOptions } from '@sapphire/decorators'; -import type { GuildTextBasedChannelTypes } from '@sapphire/discord.js-utilities'; -import { Listener } from '@sapphire/framework'; -import type { TFunction } from '@sapphire/plugin-i18next'; -import { isNullish } from '@sapphire/utilities'; -import { - Collection, - PermissionFlagsBits, - RESTJSONErrorCodes, - inlineCode, - messageLink, - type RESTGetAPIChannelMessageReactionUsersResult -} from 'discord.js'; - -@ApplyOptions({ event: Events.RawReactionAdd }) -export class UserListener extends Listener { - private readonly kCountCache = new Collection(); - private readonly kSyncCache = new Collection>(); - private kTimerSweeper: NodeJS.Timeout | null = null; - - public async run(data: LLRCData, emoji: SerializedEmoji) { - // If the bot cannot fetch messages, do not proceed: - if (!this.#canFetchMessages(data.channel)) return; - - const settings = await readSettings(data.guild); - const t = getT(settings.language); - const allowedEmojis = settings.selfmodReactionsAllowed; - - const emojiId = getEmojiId(emoji); - if (allowedEmojis.some((allowedEmoji) => getEmojiId(allowedEmoji as SerializedEmoji) === emojiId)) return; - - const targetChannelId = settings.channelsLogsReaction; - - this.container.client.emit(Events.ReactionBlocked, data, emoji); - if (isNullish(targetChannelId) || (!settings.eventsTwemojiReactions && data.emoji.id === null)) return; - - if (settings.messagesIgnoreChannels.includes(data.channel.id)) return; - if (settings.channelsIgnoreReactionAdd.some((id) => id === data.channel.id || data.channel.parentId === id)) return; - if (settings.channelsIgnoreAll.some((id) => id === data.channel.id || data.channel.parentId === id)) return; - - const count = await this.#retrieveCount(data, emoji); - if (isNullish(count) || count > 1) return; - - const user = await this.container.client.users.fetch(data.userId); - if (user.bot) return; - - await getLogger(data.guild).send({ - key: 'channelsLogsReaction', - channelId: targetChannelId, - makeMessage: () => - new EmbedBuilder() - .setColor(Colors.Green) - .setAuthor(getFullEmbedAuthor(user)) - .setThumbnail(this.#renderThumbnail(data.emoji)) - .setDescription(this.#renderDescription(t, data)) - .setFooter({ text: t(LanguageKeys.Events.Reactions.ReactionFooter) }) - .setTimestamp() - }); - } - - public override onUnload() { - super.onUnload(); - if (this.kTimerSweeper) clearInterval(this.kTimerSweeper); - } - - #renderThumbnail(emoji: LLRCDataEmoji) { - return emoji.id === null // - ? getTwemojiUrl(getEncodedTwemoji(emoji.name!)) - : getCustomEmojiUrl(emoji.id, emoji.animated); - } - - #renderDescription(t: TFunction, data: LLRCData) { - return t(LanguageKeys.Events.Reactions.ReactionDescription, { - emoji: data.emoji.id ? `${data.emoji.name} (${inlineCode(data.emoji.id)})` : data.emoji.name, - message: messageLink(data.channel.id, data.messageId, data.guild.id) - }); - } - - #canFetchMessages(channel: GuildTextBasedChannelTypes) { - const permissions = channel.permissionsFor(this.container.client.id!); - return !isNullish(permissions) && permissions.has(PermissionFlagsBits.ViewChannel | PermissionFlagsBits.ReadMessageHistory); - } - - async #retrieveCount(data: LLRCData, emoji: SerializedEmoji): Promise { - const id = `${data.messageId}.${getEmojiId(emoji)}`; - - // Pull from sync queue, and if it exists, await - const sync = this.kSyncCache.get(id); - if (typeof sync !== 'undefined') await sync; - - // Retrieve the reaction count - const previousCount = this.kCountCache.get(id); - if (typeof previousCount !== 'undefined') { - previousCount.count++; - previousCount.sweepAt = Date.now() + 120000; - return previousCount.count; - } - - // Pull the reactions from the API - const promise = this.#fetchCount(data, emoji, id); - this.kSyncCache.set(id, promise); - - const resolved = await promise; - return isNullish(resolved) ? null : resolved.count; - } - - async #fetchCount(data: LLRCData, emoji: SerializedEmoji, id: string): Promise { - const result = await toErrorCodeResult(api().channels.getMessageReactions(data.channel.id, data.messageId, getEmojiReactionFormat(emoji))); - return result.match({ - ok: (data) => this.#fetchCountOk(data, id), - err: (error) => this.#fetchCountErr(error) - }); - } - - #fetchCountOk(data: RESTGetAPIChannelMessageReactionUsersResult, id: string): InternalCacheEntry { - const count: InternalCacheEntry = { count: data.length, sweepAt: Date.now() + 120000 }; - this.kCountCache.set(id, count); - this.kSyncCache.delete(id); - - if (this.kTimerSweeper === null) { - this.kTimerSweeper = setInterval(() => { - const now = Date.now(); - this.kCountCache.sweep((entry) => entry.sweepAt < now); - if (this.kTimerSweeper !== null && this.kCountCache.size === 0) { - clearInterval(this.kTimerSweeper); - this.kTimerSweeper = null; - } - }, 5000).unref(); - } - - return count; - } - - #fetchCountErr(code: RESTJSONErrorCodes): InternalCacheEntry | null { - if (!UserListener.IgnoreReactionCountFetchErrors.includes(code)) { - this.container.logger.error(`${getLogPrefix(this)} ${getCodeStyle(code)} Failed to fetch message reaction count.`); - } - - return null; - } - - private static readonly IgnoreReactionCountFetchErrors = [ - RESTJSONErrorCodes.UnknownMessage, - RESTJSONErrorCodes.UnknownChannel, - RESTJSONErrorCodes.UnknownGuild, - RESTJSONErrorCodes.UnknownEmoji, - RESTJSONErrorCodes.MissingAccess - ]; -} - -interface InternalCacheEntry { - sweepAt: number; - count: number; -} diff --git a/src/listeners/ready.ts b/src/listeners/ready.ts deleted file mode 100644 index 15c889caf..000000000 --- a/src/listeners/ready.ts +++ /dev/null @@ -1,193 +0,0 @@ -import { Events, Schedules } from '#lib/types'; -import { ApplyOptions } from '@sapphire/decorators'; -import { Listener, Piece, Store } from '@sapphire/framework'; -import type { TFunction } from '@sapphire/plugin-i18next'; -import { isNullish } from '@sapphire/utilities'; -import { envParseBoolean } from '@skyra/env-utilities'; -import { blue, gray, green, red, redBright, white, yellow } from 'colorette'; - -@ApplyOptions({ once: true }) -export class UserListener extends Listener { - private readonly style = this.container.client.dev ? yellow : blue; - - public async run() { - try { - await this.initAnalytics(); - - // Setup the stat updating task - await this.initPostStatsTask().catch((error) => this.container.logger.fatal(error)); - } catch (error) { - this.container.logger.fatal(error); - } - - this.printBanner(); - this.printStoreDebugInformation(); - } - - private async initPostStatsTask() { - const { queue } = this.container.schedule; - if (!queue.some((task) => task.taskId === Schedules.Poststats)) { - await this.container.schedule.add(Schedules.Poststats, '*/10 * * * *', { data: null }); - } - } - - private async initSyncResourceAnalyticsTask() { - const { queue } = this.container.schedule; - if (!queue.some((task) => task.taskId === Schedules.SyncResourceAnalytics)) { - await this.container.schedule.add(Schedules.SyncResourceAnalytics, '*/1 * * * *', { data: null }); - } - } - - private async initAnalytics() { - if (envParseBoolean('INFLUX_ENABLED')) { - const { client } = this.container; - client.emit( - Events.AnalyticsSync, - client.guilds.cache.size, - client.guilds.cache.reduce((acc, val) => acc + (val.memberCount ?? 0), 0) - ); - - await this.initSyncResourceAnalyticsTask().catch((error) => this.container.logger.fatal(error)); - } - } - - private printBanner() { - const { client } = this.container; - const success = green('+'); - const failed = red('-'); - const llc = client.dev ? redBright : white; - const blc = client.dev ? red : gray; - - const line01 = llc(String.raw` . `); - const line02 = llc(String.raw` ${blc('@@@@@@@')} @@@@ @@@@@ `); - const line03 = llc(String.raw` ${blc('@@@@@@@@@@')} @@@@@@@@@@@@ `); - const line04 = llc(String.raw` @@ ${blc('@@@@@@@@')} @@@@ @@@@@@@@@@ `); - const line05 = llc(String.raw` @@ ${blc('@@@@@@@@')} @@@@ @@@@@@@@@@@ `); - const line06 = llc(String.raw` @@@ ${blc('@@@@@')} @@@@ @@@ @@@@ @@@@@ `); - const line07 = llc(String.raw` @@@ ${blc('@@@@@ @@@')} @@@@ . @@@ @@@@ @@@@@ `); - const line08 = llc(String.raw` @@ ${blc('@@@@@ @@@@@@@@@@')} @@ @@@@ @@@@ `); - const line09 = llc(String.raw` @@@@@@@ ${blc('@@@@ @@@ @@@')} @@@ @@@ .@@@ `); - const line10 = llc(String.raw` @@@@ ${blc('@@@@@@@@@@ @@@@@@@@@@@')} @@@@@@@ @@ @@@ `); - const line11 = llc(String.raw` . @@@@@@@ ${blc('@@@@@@@@@@ @@@')} @@@@ @@@ @@ @@@@@ `); - const line12 = llc(String.raw` @@@@@@ ${blc('@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@')} @@@@@@ `); - const line13 = llc(String.raw` @@@@@ ${blc('@@@@ @@@ @@@@@@@@@ @@ @@@@')} `); - const line14 = llc(String.raw` @@@@ . @@ @@@@ @@ @@@@ @@@ @@@@@ `); - const line15 = llc(String.raw` @@@@ @@@@@@@@ @@@@@@@ @@@ @@@@@@. `); - const line16 = llc(String.raw` @@@ @@@@@@@@@@@@@@@ @@@@@ `); - const line17 = llc(String.raw` @@@ @@@ @@@@@@@@@@@@@@@@@ @@@ `); - const line18 = llc(String.raw` @@@ @@@@@@ ${blc('@@@@@@@@@@@@@@@@@@')} @@@@@@@@@@@@@@@@@@ `); - const line19 = llc(String.raw` @@@@ @@@@ ${blc('@@@@@@ @@ @@ @@@@@@')} @@@@@ @@@@@@ @@ `); - const line20 = llc(String.raw` @@@@@@ @@@@@ ${blc('@@@@@@@@@@ @@@@@@@@@@@@@@@@@')} @@@@ @@@@@@@@@@@@ `); - const line21 = llc(String.raw` @@@@@@@@ @@@@@@ ${blc('@@@@@ @@ @@@@@@@@')} @@@@@@@@@@@@@@@@@@ `); - const line22 = llc(String.raw` @@@@@@@@@ @@@@@@ @@ ${blc('@@@@@@@@@@@@')} @@@@@@ @@@@@ @@@@ `); - const line23 = llc(String.raw` @@@@@@@@ @@@@@@ @@@@@@@@ ${blc('@@@@@@@@@@@@@@')} @@@@@@@@@@@@@ @@ `); - const line24 = llc(String.raw` @@@@@@@@ @@@@@@@@@ @@@@@@@@ ${blc('@@@@@@@@@@@@@@')} @@@@@@@@@ @@@@@@ `); - const line25 = llc(String.raw` @@@@@@@@ @@@@@@@ @@@@@@@ @@@ @@ @@@@ ${blc('@@@@@@@@@ @@@@@@@@@')} `); - const line26 = llc(String.raw` @@@@@@@@ @@@ @@@@@@@@@@@@@ @@@ @@ @@@ ${blc('@@@@@@@@ @@@ @@@')} `); - const line27 = llc(String.raw` @@@@@@@@ @@@@@@ @ ${blc('@@@@@@@@@@@@@@@@ @@@ @@ @@@@ @@@ @@@ @')} `); - const line28 = llc(String.raw` @@@ @@@@@@@@@@@@ ${blc('@@@@ @@@@@@@@@@@@@@ @@ @@@@ @@@ @@@ ')}`); - const line29 = llc(String.raw` @@@@@@ @@@@@@@@@@@@@@@@@@@ ${blc('@@@@@@@@@@@@ @@@@@')} @@@ @@ @@ @@@ @@ `); - const line30 = llc(String.raw` @@@@@@@@@@@@@@@ @@@@@@@ @@@@@@@@@ @@@@@@ @@@@@ @@@@ @@@@@ @@@@ @@ `); - const line31 = llc(String.raw` @@@@ @@@@@@ @@@@@@@@@@@@ .@@@@@@ @@@@@ @@@@@@ @@@@ @@ `); - const line32 = llc(String.raw` @@@@ @@@@@@@@@@@@@ ${blc('@@@@@@@@@@@ @@@@@ @@@@@@@ @@@@ @@@ @@@@@@ ')}`); - const line33 = llc(String.raw` @@@@@@@@@@@@@ ${blc('@@@@@@@@@@@@@ @@')} @@@@@ @@@@@@@@@@@@ @@@ @@@@@ `); - const line34 = llc(String.raw` ${blc('@@@ @@@@@@@ @@@@@@ @@@@@@@@@@@@ @@@@@ @@@')} `); - const line35 = llc(String.raw` . . ${blc('@@@ @@@@@@ @@@@@@@@@@@@ @@@ @@@ @@@@@@@@')} `); - const line36 = llc(String.raw` .${blc('@@ @@ @@@ @@@@@@@@@@@@@ @@@@ @@@@@@@@ @@@@')} `); - const line37 = llc(String.raw` @@@@ ${blc('@@@ @@@@@@@ @@@ @@ @@@@@@@@@@@@ @@@@@@')} `); - const line38 = llc(String.raw` @@@ ${blc('@@@ @@@@@@ @@@@@@@@@@@@@@@@@@@ @@@@@@@')} `); - const line39 = llc(String.raw` @@@@@@ ${blc('@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@')} `); - const line40 = llc(String.raw` @@ @@ ${blc('@@@@@@ @@@@@ @@@ @@@@@@ @@@@@@@@@')} `); - const line41 = llc(String.raw` @@@ ${blc('@@@@@ @@@@ @@@ @@@ @@@@@@@@')} `); - const line42 = llc(String.raw` @@ @@@@ @@@@ @@ @@@@@@@@ `); - const line43 = llc(String.raw` @@@@@@ @@@@ @@ @@@@ . . `); - const line44 = llc(String.raw` . @@@@@ @@@ @@ `); - const line45 = llc(String.raw` @@@@ @@ @@@@@ `); - // Offset Pad - const pad = ' '.repeat(7); - - const isAuthEnabled = !isNullish(client.options.api?.auth); - - console.log( - String.raw` -${line01} -${line02} -${line03} -${line04} -${line05} -${line06} -${line07} -${line08} -${line09} -${line10} -${line11} -${line12} -${line13} -${line14} -${line15} -${line16} -${line17} -${line18} -${line19} -${line20} -${line21} -${line22} -${line23} -${line24} -${line25} -${line26} -${line27} -${line28} -${line29} -${line30} -${line31} -${line32} -${line33} -${line34} -${line35} -${line36} -${line37} -${line38} -${line39} -${line40} -${line41} -${line42} -${line43} -${line44} -${line45} - __ __ _ __ _____ _ -${pad} \ \ / / | |/ _/ ____| | -${pad} \ \ /\ / /__ | | || (___ | |_ __ _ _ __ -${pad} \ \/ \/ / _ \| | _\___ \| __/ _\` | '__| -${pad} \ /\ / (_) | | | ____) | || (_| | | -${pad} \/ \/ \___/|_|_||_____/ \__\__,_|_| -${blc(process.env.CLIENT_VERSION.padStart(55, ' '))} -${pad}[${success}] Gateway -${pad}[${client.analytics ? success : failed}] Analytics -${pad}[${success}] API -${pad}[${isAuthEnabled ? success : failed}] OAuth 2.0 Enabled -${pad}[${success}] Moderation -${client.dev ? ` ${pad}${blc('<')}${llc('/')}${blc('>')} ${llc('DEVELOPMENT MODE')}` : ''} - `.trim() - ); - } - - private printStoreDebugInformation() { - const { client, logger, i18n } = this.container; - const stores = [...client.stores.values()]; - - for (const store of stores) { - logger.info(this.styleStore(store)); - } - - logger.info(this.styleLanguages(i18n.languages)); - } - - private styleStore(store: Store) { - return gray(`├─ Loaded ${this.style(store.size.toString().padEnd(2, ' '))} ${store.name}.`); - } - - private styleLanguages(languages: Map) { - return gray(`└─ Loaded ${this.style(languages.size.toString().padEnd(2, ' '))} languages.`); - } -} diff --git a/src/listeners/shard/shardDisconnect.ts b/src/listeners/shard/shardDisconnect.ts deleted file mode 100644 index 802a467e9..000000000 --- a/src/listeners/shard/shardDisconnect.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { ShardListener } from '#lib/structures'; -import { red } from 'colorette'; -import type { CloseEvent } from 'discord.js'; - -export class UserShardListener extends ShardListener { - protected readonly title = red('Disconnected'); - - public run(event: CloseEvent, id: number) { - this.container.logger.error(`${this.header(id)}:\n\tCode: ${event.code}\n\tReason: ${event.reason}`); - } -} diff --git a/src/listeners/shard/shardError.ts b/src/listeners/shard/shardError.ts deleted file mode 100644 index 2e6ad5152..000000000 --- a/src/listeners/shard/shardError.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { ShardListener } from '#lib/structures'; -import { red } from 'colorette'; - -export class UserShardListener extends ShardListener { - protected readonly title = red('Error'); - - public run(error: Error, id: number) { - this.container.logger.error(`${this.header(id)}: ${error.stack ?? error.message}`); - } -} diff --git a/src/listeners/shard/shardReady.ts b/src/listeners/shard/shardReady.ts deleted file mode 100644 index 5f387483e..000000000 --- a/src/listeners/shard/shardReady.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { ShardListener } from '#lib/structures'; -import { green } from 'colorette'; - -export class UserShardListener extends ShardListener { - protected readonly title = green('Ready'); - - public run(id: number, unavailableGuilds: Set | null) { - this.container.logger.info(`${this.header(id)}: ${unavailableGuilds?.size ?? 'Unknown or no unavailable'} guilds`); - } -} diff --git a/src/listeners/shard/shardReconnecting.ts b/src/listeners/shard/shardReconnecting.ts deleted file mode 100644 index ba6c515e1..000000000 --- a/src/listeners/shard/shardReconnecting.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { ShardListener } from '#lib/structures'; -import { yellow } from 'colorette'; - -export class UserShardListener extends ShardListener { - protected readonly title = yellow('Reconnecting'); - - public run(id: number) { - this.container.logger.warn(`${this.header(id)}: ${this.title}`); - } -} diff --git a/src/listeners/shard/shardResume.ts b/src/listeners/shard/shardResume.ts deleted file mode 100644 index ac6cd0d0f..000000000 --- a/src/listeners/shard/shardResume.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { ShardListener } from '#lib/structures'; -import { yellow } from 'colorette'; - -export class UserShardListener extends ShardListener { - protected readonly title = yellow('Resumed'); - - public run(id: number, replayedEvents: number) { - this.container.logger.info(`${this.header(id)}: ${replayedEvents} events replayed.`); - } -} diff --git a/src/preconditions/Administrator.ts b/src/preconditions/Administrator.ts deleted file mode 100644 index 06bf360f7..000000000 --- a/src/preconditions/Administrator.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { PermissionsPrecondition } from '#lib/structures'; -import type { GuildMessage } from '#lib/types'; -import { isAdmin } from '#utils/functions'; - -export class UserPermissionsPrecondition extends PermissionsPrecondition { - public async handle(message: GuildMessage): PermissionsPrecondition.AsyncResult { - return (await isAdmin(message.member)) ? this.ok() : this.error({ identifier: LanguageKeys.Preconditions.Administrator }); - } -} diff --git a/src/preconditions/BotOwner.ts b/src/preconditions/BotOwner.ts deleted file mode 100644 index b9706c163..000000000 --- a/src/preconditions/BotOwner.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { OWNERS } from '#root/config'; -import { Precondition } from '@sapphire/framework'; -import type { Message } from 'discord.js'; - -export class UserPrecondition extends Precondition { - public override messageRun(message: Message): Precondition.Result { - return OWNERS.includes(message.author.id) ? this.ok() : this.error({ context: { silent: true } }); - } -} diff --git a/src/preconditions/Enabled.ts b/src/preconditions/Enabled.ts deleted file mode 100644 index 1aef7de55..000000000 --- a/src/preconditions/Enabled.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { CommandMatcher, readSettings, type ReadonlyGuildData } from '#lib/database'; -import type { WolfCommand } from '#lib/structures'; -import { isModerator } from '#utils/functions'; -import { ApplyOptions } from '@sapphire/decorators'; -import { - AllFlowsPrecondition, - Command, - Identifiers, - Precondition, - type ChatInputCommand, - type ContextMenuCommand, - type PreconditionContext, - type PreconditionResult -} from '@sapphire/framework'; -import type { CacheType, ChatInputCommandInteraction, ContextMenuCommandInteraction, Guild, GuildMember, Message } from 'discord.js'; - -@ApplyOptions({ position: 10 }) -export class UserPrecondition extends AllFlowsPrecondition { - public override messageRun(message: Message, command: Command, context: Precondition.Context): Precondition.Result { - return message.guild ? this.runGuild(message.guild!, message.member!, message.channelId, command, context) : this.runDM(command, context); - } - - public override chatInputRun( - interaction: ChatInputCommandInteraction, - command: ChatInputCommand, - context: PreconditionContext - ): PreconditionResult { - return interaction.guildId - ? this.runGuild(interaction.guild!, interaction.member as GuildMember, interaction.channelId, command, context) - : this.runDM(command, context); - } - - public override contextMenuRun( - interaction: ContextMenuCommandInteraction, - command: ContextMenuCommand, - context: PreconditionContext - ): PreconditionResult { - return interaction.guildId - ? this.runGuild(interaction.guild!, interaction.member as GuildMember, interaction.channelId, command, context) - : this.runDM(command, context); - } - - private runDM(command: Command, context: Precondition.Context): Precondition.Result { - return command.enabled ? this.ok() : this.error({ identifier: Identifiers.CommandDisabled, context }); - } - - private async runGuild( - guild: Guild, - member: GuildMember, - channelId: string, - command: Command, - context: Precondition.Context - ): Precondition.AsyncResult { - const settings = await readSettings(guild); - const disabled = this.checkGuildDisabled(settings, channelId, command as WolfCommand); - if (disabled) { - const canOverride = await isModerator(member); - if (!canOverride) return this.error({ context: { ...context, silent: true } }); - } - - return this.runDM(command, context); - } - - private checkGuildDisabled(settings: ReadonlyGuildData, channelId: string, command: WolfCommand) { - if (settings.disabledChannels.includes(channelId)) return true; - if (CommandMatcher.matchAny(settings.disabledCommands, command)) return true; - - const entry = settings.disabledCommandsChannels.find((d) => d.channel === channelId); - if (entry === undefined) return false; - - return CommandMatcher.matchAny(entry.commands, command); - } -} diff --git a/src/preconditions/Everyone.ts b/src/preconditions/Everyone.ts deleted file mode 100644 index 332eeb341..000000000 --- a/src/preconditions/Everyone.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { PermissionsPrecondition } from '#lib/structures'; -import { ApplyOptions } from '@sapphire/decorators'; - -@ApplyOptions({ guildOnly: false }) -export class UserPermissionsPrecondition extends PermissionsPrecondition { - public handle(): PermissionsPrecondition.Result { - return this.ok(); - } -} diff --git a/src/preconditions/Moderator.ts b/src/preconditions/Moderator.ts deleted file mode 100644 index af2ee76e8..000000000 --- a/src/preconditions/Moderator.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { PermissionsPrecondition } from '#lib/structures'; -import type { GuildMessage } from '#lib/types'; -import { isModerator } from '#utils/functions'; - -export class UserPermissionsPrecondition extends PermissionsPrecondition { - public async handle(message: GuildMessage): PermissionsPrecondition.AsyncResult { - return (await isModerator(message.member)) ? this.ok() : this.error({ identifier: LanguageKeys.Preconditions.Moderator }); - } -} diff --git a/src/preconditions/ServerOwner.ts b/src/preconditions/ServerOwner.ts deleted file mode 100644 index f4e4a806b..000000000 --- a/src/preconditions/ServerOwner.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { PermissionsPrecondition } from '#lib/structures'; -import type { GuildMessage } from '#lib/types'; - -export class UserPermissionsPrecondition extends PermissionsPrecondition { - public handle(message: GuildMessage): PermissionsPrecondition.Result { - return message.author.id === message.guild.ownerId ? this.ok() : this.error({ identifier: LanguageKeys.Preconditions.ServerOwner }); - } -} diff --git a/src/routes/commands.get.ts b/src/routes/commands.get.ts deleted file mode 100644 index 4eea3d167..000000000 --- a/src/routes/commands.get.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { ratelimit } from '#lib/api/utils'; -import { getT } from '#lib/i18n/translate'; -import type { WolfCommand } from '#lib/structures'; -import { PermissionLevels } from '#lib/types'; -import { seconds } from '#utils/common'; -import type { Command } from '@sapphire/framework'; -import { Route } from '@sapphire/plugin-api'; -import type { TFunction } from '@sapphire/plugin-i18next'; -import type { Locale } from 'discord.js'; - -export class UserRoute extends Route { - @ratelimit(seconds(2), 2) - public run(request: Route.Request, response: Route.Response) { - const { lang, category } = request.query; - const commands = this.container.stores.get('commands'); - const language = getT(lang as Locale); - const filtered = (category ? commands.filter((cmd) => cmd.category === category) : commands).filter( - (cmd) => (cmd as WolfCommand).permissionLevel < PermissionLevels.BotOwner - ); - - return response.json(filtered.map(UserRoute.process.bind(null, language))); - } - - private static process(t: TFunction, cmd: Command) { - const command = cmd as WolfCommand; - return { - category: command.category, - subCategory: command.subCategory, - alias: command.aliases, - description: t(command.description), - extendedHelp: t(command.detailedDescription, { prefix: process.env.CLIENT_PREFIX }), - guarded: command.guarded, - name: command.name, - permissionLevel: command.permissionLevel, - preconditions: command.preconditions - }; - } -} diff --git a/src/routes/guilds/[guild]/audit-logs.get.ts b/src/routes/guilds/[guild]/audit-logs.get.ts deleted file mode 100644 index d7ff8203e..000000000 --- a/src/routes/guilds/[guild]/audit-logs.get.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { authenticated, canManage, ratelimit } from '#lib/api/utils'; -import type { AuditEventChanges, AuditOutcome, DashboardAuditAction, DashboardAuditChanges, DashboardAuditEntry } from '#lib/database'; -import { DASHBOARD_AUDIT_ACTIONS } from '#lib/database/settings/auditActions'; -import { seconds } from '#utils/common'; -import { HttpCodes, Route } from '@sapphire/plugin-api'; -import type { APIGuildMember } from 'discord-api-types/v10'; -import type { GuildMember } from 'discord.js'; -import { auditDiff } from 'evlog'; - -function getNestedValue(obj: Record, path: string): unknown { - const parts = path.split('/').filter(Boolean); - let current: unknown = obj; - for (const part of parts) { - if (current === null || current === undefined || typeof current !== 'object') return undefined; - current = (current as Record)[part]; - } - return current; -} - -function patchToChanges(stored: AuditEventChanges | null): DashboardAuditChanges { - const diff = auditDiff(stored?.before ?? {}, stored?.after ?? {}); - const added: Record = {}; - const removed: Record = {}; - const changed: Record = {}; - - for (const op of diff.patch) { - const key = op.path.replace(/^\//, '').replaceAll('/', '.'); - if (op.op === 'add') { - added[key] = op.value; - } else if (op.op === 'remove') { - removed[key] = getNestedValue(stored?.before ?? {}, op.path); - } else { - changed[key] = { from: getNestedValue(stored?.before ?? {}, op.path), to: op.value }; - } - } - - const result: DashboardAuditChanges = {}; - if (Object.keys(added).length) result.added = added; - if (Object.keys(removed).length) result.removed = removed; - if (Object.keys(changed).length) result.changed = changed; - return result; -} - -function serializeMember(member: GuildMember | null, actorId: string): APIGuildMember { - if (!member) return fallbackMember(actorId); - return { - user: { - id: member.user.id, - username: member.user.username, - global_name: member.user.globalName ?? null, - avatar: member.user.avatar, - discriminator: member.user.discriminator - }, - roles: [...member.roles.cache.keys()], - joined_at: member.joinedAt?.toISOString() ?? null, - nick: member.nickname ?? null, - avatar: member.avatar - }; -} - -function fallbackMember(actorId: string): APIGuildMember { - return { - user: { id: actorId, username: 'Unknown', global_name: null, avatar: null, discriminator: '0' }, - roles: [], - joined_at: null, - nick: null, - avatar: null - }; -} - -export class UserRoute extends Route { - @authenticated() - @ratelimit(seconds(10), 5, true) - public async run(request: Route.Request, response: Route.Response) { - const guildId = request.params.guild; - - const guild = this.container.client.guilds.cache.get(guildId); - if (!guild) return response.error(HttpCodes.BadRequest); - - const member = await guild.members.fetch(request.auth!.id).catch(() => null); - if (!member) return response.error(HttpCodes.BadRequest); - - if (!(await canManage(guild, member))) return response.error(HttpCodes.Forbidden); - - const limit = Math.min(Math.max(Number.parseInt(request.query.limit as string, 10) || 10, 1), 100); - const offset = Math.max(Number.parseInt(request.query.offset as string, 10) || 0, 0); - - const where = { tenantId: guildId, action: { in: [...DASHBOARD_AUDIT_ACTIONS] } }; - - const [rows, total] = await Promise.all([ - this.container.prisma.auditEvent.findMany({ - where, - orderBy: { timestamp: 'desc' }, - take: limit, - skip: offset - }), - this.container.prisma.auditEvent.count({ where }) - ]); - - const uniqueActorIds = [...new Set(rows.map((r) => r.actorId))]; - const resolvedMembers = await Promise.all(uniqueActorIds.map((id) => guild.members.fetch(id).catch(() => null))); - const memberMap = new Map(uniqueActorIds.map((id, i) => [id, serializeMember(resolvedMembers[i], id)])); - - return response.status(HttpCodes.OK).json({ - entries: rows.map( - (row) => - ({ - id: row.id, - guildId: guildId, - action: row.action as DashboardAuditAction, - outcome: row.outcome as AuditOutcome, - member: memberMap.get(row.actorId) ?? fallbackMember(row.actorId), - changes: patchToChanges(row.changes as AuditEventChanges | null), - reason: row.reason ?? null, - timestamp: row.timestamp.toISOString() - }) satisfies DashboardAuditEntry - ), - total - }); - } -} diff --git a/src/routes/guilds/[guild]/command-logs.get.ts b/src/routes/guilds/[guild]/command-logs.get.ts deleted file mode 100644 index 555345555..000000000 --- a/src/routes/guilds/[guild]/command-logs.get.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { authenticated, canManage, ratelimit } from '#lib/api/utils'; -import { seconds } from '#utils/common'; -import { HttpCodes, Route } from '@sapphire/plugin-api'; - -export class UserRoute extends Route { - @authenticated() - @ratelimit(seconds(10), 5, true) - public async run(request: Route.Request, response: Route.Response) { - const guildId = request.params.guild; - - const guild = this.container.client.guilds.cache.get(guildId); - if (!guild) return response.error(HttpCodes.BadRequest); - - const member = await guild.members.fetch(request.auth!.id).catch(() => null); - if (!member) return response.error(HttpCodes.BadRequest); - - if (!(await canManage(guild, member))) return response.error(HttpCodes.Forbidden); - - const parsedLimit = Number.parseInt(request.query.limit as string, 10); - const limit = Math.min(Math.max(Number.isNaN(parsedLimit) ? 10 : parsedLimit, 1), 100); - const offset = Math.max(Number.parseInt(request.query.offset as string, 10) || 0, 0); - const userId = typeof request.query.userId === 'string' && request.query.userId ? request.query.userId : undefined; - const commandName = typeof request.query.commandName === 'string' && request.query.commandName ? request.query.commandName : undefined; - const rawSuccess = request.query.success as string | undefined; - const success = rawSuccess === 'true' ? true : rawSuccess === 'false' ? false : undefined; - - const where = { - guildId, - ...(userId !== undefined && { userId }), - ...(commandName !== undefined && { commandName }), - ...(success !== undefined && { success }) - }; - - const [rows, total] = await Promise.all([ - this.container.prisma.commandLog.findMany({ - where, - orderBy: { executedAt: 'desc' }, - take: limit, - skip: offset - }), - this.container.prisma.commandLog.count({ where }) - ]); - - return response.status(HttpCodes.OK).json({ - entries: rows.map((row) => ({ - id: row.id, - guildId: row.guildId, - userId: row.userId, - commandName: row.commandName, - commandType: row.commandType, - commandId: row.commandId, - subcommand: row.subcommand, - channelId: row.channelId, - success: row.success, - errorReason: row.errorReason, - executedAt: row.executedAt.toISOString(), - latencyMs: row.latencyMs, - metadata: row.metadata as Record | null - })), - total - }); - } -} diff --git a/src/routes/guilds/[guild]/settings.get.ts b/src/routes/guilds/[guild]/settings.get.ts deleted file mode 100644 index 3dd4c5c52..000000000 --- a/src/routes/guilds/[guild]/settings.get.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { authenticated, canManage, ratelimit } from '#lib/api/utils'; -import { readSettings, serializeSettings, type ReadonlyGuildData } from '#lib/database'; -import { seconds } from '#utils/common'; -import { HttpCodes, Route, type MimeType } from '@sapphire/plugin-api'; - -export class UserRoute extends Route { - @authenticated() - @ratelimit(seconds(5), 2, true) - public async run(request: Route.Request, response: Route.Response) { - const guildId = request.params.guild; - - const guild = this.container.client.guilds.cache.get(guildId); - if (!guild) return response.error(HttpCodes.BadRequest); - - const member = await guild.members.fetch(request.auth!.id).catch(() => null); - if (!member) return response.error(HttpCodes.BadRequest); - - if (!(await canManage(guild, member))) return response.error(HttpCodes.Forbidden); - - const settings = await readSettings(guild); - return this.sendSettings(response, settings); - } - - private sendSettings(response: Route.Response, settings: ReadonlyGuildData) { - return response - .status(HttpCodes.OK) - .setContentType('application/json' satisfies MimeType) - .end(serializeSettings(settings)); - } -} diff --git a/src/routes/index.get.ts b/src/routes/index.get.ts deleted file mode 100644 index 2bbdbaf28..000000000 --- a/src/routes/index.get.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Route } from '@sapphire/plugin-api'; - -export class UserRoute extends Route { - public run(_request: Route.Request, response: Route.Response) { - response.json({ message: 'Hello World' }); - } -} diff --git a/src/routes/languages.get.ts b/src/routes/languages.get.ts deleted file mode 100644 index da9c02177..000000000 --- a/src/routes/languages.get.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { ratelimit } from '#lib/api/utils'; -import { seconds } from '#utils/common'; -import { Route } from '@sapphire/plugin-api'; - -export class UserRoute extends Route { - @ratelimit(seconds(2), 2) - public run(_request: Route.Request, response: Route.Response) { - return response.json([...this.container.i18n.languages.keys()]); - } -} diff --git a/src/serializers/boolean.ts b/src/serializers/boolean.ts deleted file mode 100644 index 2b85eb40e..000000000 --- a/src/serializers/boolean.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Serializer } from '#lib/database'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import type { Awaitable } from '@sapphire/utilities'; - -export class UserSerializer extends Serializer { - public async parse(args: Serializer.Args) { - return this.result(args, await args.pickResult('boolean')); - } - - public isValid(value: boolean): Awaitable { - return typeof value === 'boolean'; - } - - public override stringify(value: boolean, { t }: Serializer.UpdateContext): string { - return t(value ? LanguageKeys.Arguments.BooleanEnabled : LanguageKeys.Arguments.BooleanDisabled); - } -} diff --git a/src/serializers/categoryortextchannel.ts b/src/serializers/categoryortextchannel.ts deleted file mode 100644 index 452b3fe79..000000000 --- a/src/serializers/categoryortextchannel.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Serializer } from '#lib/database'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { isCategoryChannel, isTextChannel } from '@sapphire/discord.js-utilities'; -import type { Awaitable } from '@sapphire/utilities'; - -export class UserSerializer extends Serializer { - public async parse(args: Serializer.Args, { t, entry }: Serializer.UpdateContext) { - const result = await args.pickResult('guildChannel'); - if (result.isErr()) { - return this.errorFromArgument(args, result.unwrapErr()); - } - - const channel = result.unwrap(); - if (isTextChannel(channel) || isCategoryChannel(channel)) { - return this.ok(channel.id); - } - - return this.error(t(LanguageKeys.Serializers.InvalidChannel, { name: entry.name })); - } - - public isValid(value: string, context: Serializer.UpdateContext): Awaitable { - return context.guild.channels.cache.has(value); - } - - public override stringify(value: string, context: Serializer.UpdateContext): string { - return context.guild.channels.cache.get(value)?.name ?? value; - } -} diff --git a/src/serializers/channel.ts b/src/serializers/channel.ts deleted file mode 100644 index 8073995b7..000000000 --- a/src/serializers/channel.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { Serializer } from '#lib/database'; -import { ApplyOptions } from '@sapphire/decorators'; -import { isCategoryChannel, isGuildBasedChannelByGuildKey, isNewsChannel, isTextChannel, isVoiceChannel } from '@sapphire/discord.js-utilities'; -import { isNullish, type Awaitable } from '@sapphire/utilities'; -import type { Channel } from 'discord.js'; - -@ApplyOptions({ - aliases: ['guildTextChannel', 'guildVoiceChannel', 'guildCategoryChannel'] satisfies SerializerType[] -}) -export class UserSerializer extends Serializer { - public async parse(args: Serializer.Args, { entry }: Serializer.UpdateContext) { - const result = await args.pickResult(entry.type as SerializerType); - return result.match({ - ok: (value) => this.ok(value.id), - err: (error) => this.errorFromArgument(args, error) - }); - } - - public isValid(value: string, context: Serializer.UpdateContext): Awaitable { - const channel = context.guild.channels.cache.get(value); - return !isNullish(channel) && this.isValidChannel(channel, context.entry.type as SerializerType); - } - - /** - * The stringify method to be overwritten in actual Serializers - * @param value The data to stringify - * @param guild The guild given for context in this call - */ - public override stringify(value: string, context: Serializer.UpdateContext): string { - return context.guild.channels.cache.get(value)?.name ?? value; - } - - private isValidChannel(channel: Channel, type: SerializerType): boolean { - if (!isGuildBasedChannelByGuildKey(channel)) return false; - - switch (type) { - case 'guildTextChannel': - return isTextChannel(channel) || isNewsChannel(channel); - case 'guildVoiceChannel': - return isVoiceChannel(channel); - case 'guildCategoryChannel': - return isCategoryChannel(channel); - default: - return false; - } - } -} - -type SerializerType = 'guildTextChannel' | 'guildVoiceChannel' | 'guildCategoryChannel'; diff --git a/src/serializers/command.ts b/src/serializers/command.ts deleted file mode 100644 index 6ff323b5f..000000000 --- a/src/serializers/command.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Serializer } from '#lib/database'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import type { Awaitable } from '@sapphire/utilities'; - -export class UserSerializer extends Serializer { - public async parse(args: Serializer.Args) { - const result = await args.pickResult('commandName'); - return result.match({ - ok: (value) => this.ok(value.name), - err: (error) => this.errorFromArgument(args, error) - }); - } - - public isValid(value: string, { t, entry }: Serializer.UpdateContext): Awaitable { - const command = this.container.stores.get('commands').has(value); - if (!command) throw t(LanguageKeys.Serializers.InvalidCommand, { name: entry.name }); - return true; - } - - public override stringify(value: string) { - return (this.container.stores.get('commands').get(value) || { name: value }).name; - } -} diff --git a/src/serializers/commandautodelete.ts b/src/serializers/commandautodelete.ts deleted file mode 100644 index 3073b8ecb..000000000 --- a/src/serializers/commandautodelete.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { Serializer, type CommandAutoDelete } from '#lib/database'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { seconds } from '#utils/common'; -import type { Awaitable } from '@sapphire/utilities'; - -export class UserSerializer extends Serializer { - public async parse(args: Serializer.Args) { - const command = await args.pickResult('command'); - if (command.isErr()) return this.errorFromArgument(args, command.unwrapErr()); - - const duration = await args.pickResult('timespan', { minimum: seconds(1) }); - if (duration.isErr()) return this.errorFromArgument(args, duration.unwrapErr()); - - return this.ok([command.unwrap().name, duration.unwrap()] as const); - } - - public isValid(value: CommandAutoDelete): Awaitable { - return ( - Array.isArray(value) && - value.length === 2 && - typeof value[0] === 'string' && - typeof value[1] === 'number' && - this.container.stores.get('commands').has(value[0]) - ); - } - - public override stringify(value: CommandAutoDelete, { t }: Serializer.UpdateContext): string { - return `[${value[0]} -> ${t(LanguageKeys.Globals.DurationValue, { value: value[1] })}]`; - } - - public override equals(left: CommandAutoDelete, right: CommandAutoDelete): boolean { - return left[0] === right[0]; - } -} diff --git a/src/serializers/commandmatch.ts b/src/serializers/commandmatch.ts deleted file mode 100644 index a5216881a..000000000 --- a/src/serializers/commandmatch.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { CommandMatcher, Serializer } from '#lib/database'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import type { Awaitable } from '@sapphire/utilities'; - -export class UserSerializer extends Serializer { - public async parse(args: Serializer.Args) { - return this.result(args, await args.pickResult('commandMatch')); - } - - public isValid(value: string, { t, entry }: Serializer.UpdateContext): Awaitable { - const command = CommandMatcher.resolve(value); - if (!command) throw t(LanguageKeys.Serializers.InvalidCommand, { name: entry.name }); - return true; - } - - public override stringify(value: string) { - return (this.container.stores.get('commands').get(value) || { name: value }).name; - } -} diff --git a/src/serializers/disabledcommandchannel.ts b/src/serializers/disabledcommandchannel.ts deleted file mode 100644 index d8800bcc2..000000000 --- a/src/serializers/disabledcommandchannel.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { Serializer, type DisabledCommandChannel } from '#lib/database'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { isTextChannel } from '@sapphire/discord.js-utilities'; -import type { Awaitable } from '@sapphire/utilities'; - -export class UserSerializer extends Serializer { - public async parse(args: Serializer.Args) { - const channel = await args.pickResult('guildTextChannel'); - if (channel.isErr()) return this.errorFromArgument(args, channel.unwrapErr()); - - const commands = await args.repeatResult('command'); - if (commands.isErr()) return this.errorFromArgument(args, commands.unwrapErr()); - - return this.ok({ channel: channel.unwrap().id, commands: commands.unwrap().map((command) => command.name) }); - } - - public isValid(value: DisabledCommandChannel, { t, entry, guild }: Serializer.UpdateContext): Awaitable { - const channel = guild.channels.cache.get(value.channel); - if (!channel) { - throw new Error(t(LanguageKeys.Serializers.DisabledCommandChannels.ChannelDoesNotExist)); - } - - if (!isTextChannel(channel)) { - throw t(LanguageKeys.Serializers.InvalidChannel, { name: entry.name }); - } - - for (const command of value.commands) { - if (!this.container.stores.get('commands').has(command)) { - throw new Error(t(LanguageKeys.Serializers.DisabledCommandChannels.CommandDoesNotExist, { name: command })); - } - } - - return true; - } - - public override stringify(value: DisabledCommandChannel, { t, guild }: Serializer.UpdateContext): string { - const name = guild.channels.cache.get(value.channel)?.name ?? t(LanguageKeys.Serializers.UnknownChannel); - return `[${name} -> ${value.commands.join(' | ')}]`; - } - - public override equals(left: DisabledCommandChannel, right: DisabledCommandChannel): boolean { - return left.channel === right.channel; - } -} diff --git a/src/serializers/emoji.ts b/src/serializers/emoji.ts deleted file mode 100644 index cfcc99b75..000000000 --- a/src/serializers/emoji.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Serializer } from '#lib/database'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { getEmojiString, getEmojiTextFormat, isValidSerializedEmoji, type SerializedEmoji } from '#utils/functions'; -import type { Awaitable } from '@sapphire/utilities'; - -export class UserSerializer extends Serializer { - public async parse(args: Serializer.Args) { - const result = await args.pickResult('emoji'); - return result.match({ - ok: (value) => this.ok(getEmojiString(value)), - err: (error) => this.errorFromArgument(args, error) - }); - } - - public isValid(value: SerializedEmoji, { t, entry }: Serializer.UpdateContext): Awaitable { - if (isValidSerializedEmoji(value)) return true; - throw new Error(t(LanguageKeys.Serializers.InvalidEmoji, { name: entry.name })); - } - - public override stringify(data: SerializedEmoji) { - return getEmojiTextFormat(data); - } -} diff --git a/src/serializers/guild.ts b/src/serializers/guild.ts deleted file mode 100644 index e679547b8..000000000 --- a/src/serializers/guild.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Serializer } from '#lib/database'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import type { Awaitable } from '@sapphire/utilities'; - -export class UserSerializer extends Serializer { - public async parse(args: Serializer.Args) { - return this.result(args, await args.pickResult('snowflake')); - } - - public isValid(value: string, { t, entry }: Serializer.UpdateContext): Awaitable { - const guild = this.container.client.guilds.cache.get(value); - if (!guild) { - throw t(LanguageKeys.Serializers.InvalidGuild, { name: entry.name }); - } - - return true; - } - - public override stringify(value: string) { - return (this.container.client.guilds.cache.get(value) || { name: value }).name; - } -} diff --git a/src/serializers/invite.ts b/src/serializers/invite.ts deleted file mode 100644 index e910d72a9..000000000 --- a/src/serializers/invite.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Serializer } from '#lib/database'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; - -export class UserSerializer extends Serializer { - public async parse(args: Serializer.Args) { - const result = await args.pickResult('invite'); - return result.match({ - ok: (value) => this.ok(value.code), - err: (error) => this.errorFromArgument(args, error) - }); - } - - public async isValid(value: string, { t, entry }: Serializer.UpdateContext): Promise { - const invite = await this.container.client.invites.fetch(value); - if (invite === null || !Reflect.has(invite, 'guildId')) { - throw t(LanguageKeys.Serializers.InvalidInvite, { name: entry.name }); - } - - return true; - } -} diff --git a/src/serializers/language.ts b/src/serializers/language.ts deleted file mode 100644 index 5bd1f1a1e..000000000 --- a/src/serializers/language.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Serializer } from '#lib/database'; -import type { Awaitable } from '@sapphire/utilities'; - -export class UserSerializer extends Serializer { - public async parse(args: Serializer.Args) { - return this.result(args, await args.pickResult('language')); - } - - public isValid(value: string): Awaitable { - return this.container.i18n.languages.has(value); - } -} diff --git a/src/serializers/notAllowed.ts b/src/serializers/notAllowed.ts deleted file mode 100644 index a978fa93a..000000000 --- a/src/serializers/notAllowed.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Serializer } from '#lib/database'; -import type { Awaitable } from '@sapphire/utilities'; - -export class UserSerializer extends Serializer { - public parse() { - return this.error('Not allowed'); - } - - public isValid(): Awaitable { - return false; - } -} diff --git a/src/serializers/number.ts b/src/serializers/number.ts deleted file mode 100644 index 569fd3de4..000000000 --- a/src/serializers/number.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Serializer } from '#lib/database'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { ApplyOptions } from '@sapphire/decorators'; -import type { Awaitable } from '@sapphire/utilities'; - -@ApplyOptions({ - aliases: ['integer', 'float'] -}) -export class UserSerializer extends Serializer { - public async parse(args: Serializer.Args, { entry }: Serializer.UpdateContext) { - return this.result(args, await args.pickResult(entry.type as SerializerType)); - } - - public isValid(value: number, context: Serializer.UpdateContext): Awaitable { - switch (context.entry.type as SerializerType) { - case 'integer': { - if (typeof value === 'number' && Number.isInteger(value) && this.minOrMax(value, value, context)) return true; - throw context.t(LanguageKeys.Serializers.InvalidInt, { name: context.entry.name }); - } - case 'number': - case 'float': { - if (typeof value === 'number' && !Number.isNaN(value) && this.minOrMax(value, value, context)) return true; - throw context.t(LanguageKeys.Serializers.InvalidFloat, { name: context.entry.name }); - } - default: { - throw new Error('Unreachable'); - } - } - } -} - -type SerializerType = 'integer' | 'number' | 'float'; diff --git a/src/serializers/permissionnode.ts b/src/serializers/permissionnode.ts deleted file mode 100644 index a9b055323..000000000 --- a/src/serializers/permissionnode.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { CommandMatcher, Serializer, type PermissionsNode } from '#lib/database'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import type { WolfCommand } from '#lib/structures'; -import { PermissionLevels } from '#lib/types'; -import type { CommandStore } from '@sapphire/framework'; -import { isObject } from '@sapphire/utilities'; -import type { GuildMember, Role } from 'discord.js'; - -export class UserSerializer extends Serializer { - public parse(_: Serializer.Args, { t }: Serializer.UpdateContext) { - return this.error(t(LanguageKeys.Serializers.Unsupported)); - } - - public async isValid(value: PermissionsNode, { t, entry, guild }: Serializer.UpdateContext): Promise { - // Safe-guard checks against arbitrary data - if (!isObject(value)) throw t(LanguageKeys.Serializers.PermissionNodeInvalid); - if (Object.keys(value).length !== 3) throw t(LanguageKeys.Serializers.PermissionNodeInvalid); - if (typeof value.id !== 'string') throw t(LanguageKeys.Serializers.PermissionNodeInvalid); - if (!Array.isArray(value.allow)) throw t(LanguageKeys.Serializers.PermissionNodeInvalid); - if (!Array.isArray(value.deny)) throw t(LanguageKeys.Serializers.PermissionNodeInvalid); - - // Check for target validity - let target: GuildMember | Role; - if (entry.name === 'permissionsRoles') { - const role = guild.roles.cache.get(value.id); - if (!role) throw t(LanguageKeys.Serializers.PermissionNodeInvalidTarget); - target = role; - } else { - target = await guild.members.fetch(value.id).catch(() => { - throw t(LanguageKeys.Serializers.PermissionNodeInvalidTarget); - }); - } - - // The @everyone role should not have allows - if (target.id === guild.id && value.allow.length !== 0) { - throw t(LanguageKeys.Serializers.PermissionNodeSecurityEveryoneAllows); - } - - // The owner cannot have allows nor denies - if (target.id === guild.ownerId) { - throw t(LanguageKeys.Serializers.PermissionNodeSecurityOwner); - } - - // Check all commands - const commands = this.container.stores.get('commands'); - const checked = new Set(); - for (const allowed of value.allow) { - if (checked.has(allowed)) throw t(LanguageKeys.Serializers.PermissionNodeDuplicatedCommand, { command: allowed }); - - const match = CommandMatcher.resolve(allowed); - if (match === null || !this.validCommand(commands, match)) { - throw t(LanguageKeys.Serializers.PermissionNodeInvalidCommand, { command: allowed }); - } - checked.add(match); - } - - for (const denied of value.deny) { - if (checked.has(denied)) throw t(LanguageKeys.Serializers.PermissionNodeDuplicatedCommand, { command: denied }); - - const match = CommandMatcher.resolve(denied); - if (match === null || !this.validCommand(commands, match)) { - throw t(LanguageKeys.Serializers.PermissionNodeInvalidCommand, { command: denied }); - } - checked.add(match); - } - - return true; - } - - public override stringify(value: PermissionsNode) { - return `${value.id}(${value.allow.join(', ')} | ${value.deny.join(', ')})`; - } - - private validCommand(commands: CommandStore, name: string) { - const command = commands.get(name) as WolfCommand | undefined; - - // No command means it matched a group, which is fine: - if (command === undefined) return true; - - // If it matched a command, it must not be a bot-owner one: - return command.permissionLevel < PermissionLevels.BotOwner; - } -} diff --git a/src/serializers/reactionrole.ts b/src/serializers/reactionrole.ts deleted file mode 100644 index 918e112bf..000000000 --- a/src/serializers/reactionrole.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Serializer, type ReactionRole } from '#lib/database'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { getEmojiTextFormat, isValidSerializedEmoji } from '#utils/functions'; -import { isObject, type Awaitable } from '@sapphire/utilities'; - -export class UserSerializer extends Serializer { - public parse(_: Serializer.Args, { t }: Serializer.UpdateContext) { - return this.error(t(LanguageKeys.Serializers.Unsupported)); - } - - public isValid(value: ReactionRole, { t }: Serializer.UpdateContext): Awaitable { - if ( - isObject(value) && - Object.keys(value).length === 4 && - typeof value.emoji === 'string' && - isValidSerializedEmoji(value.emoji) && - (typeof value.message === 'string' || value.message === null) && - typeof value.channel === 'string' && - typeof value.role === 'string' - ) - return true; - - throw t(LanguageKeys.Serializers.ReactionRoleInvalid); - } - - public override stringify(value: ReactionRole, { t, guild }: Serializer.UpdateContext) { - const emoji = getEmojiTextFormat(value.emoji); - const role = guild.roles.cache.get(value.role)?.name ?? t(LanguageKeys.Serializers.UnknownRole); - const url = `https://discord.com/channels/${guild.id}/${value.channel}/${value.message}`; - return `${emoji} | ${url} -> ${role}`; - } -} diff --git a/src/serializers/role.ts b/src/serializers/role.ts deleted file mode 100644 index e8f5ada65..000000000 --- a/src/serializers/role.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Serializer } from '#lib/database'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import type { Awaitable } from '@sapphire/utilities'; - -export class UserSerializer extends Serializer { - public async parse(args: Serializer.Args) { - const result = await args.pickResult('role'); - return result.match({ - ok: (value) => this.ok(value.id), - err: (error) => this.errorFromArgument(args, error) - }); - } - - public isValid(value: string, { t, entry, guild }: Serializer.UpdateContext): Awaitable { - if (guild.roles.cache.has(value)) return true; - throw t(LanguageKeys.Serializers.InvalidRole, { name: entry.name }); - } - - public override stringify(value: string, { guild }: Serializer.UpdateContext) { - return guild.roles.cache.get(value)?.name ?? value; - } -} diff --git a/src/serializers/snowflake.ts b/src/serializers/snowflake.ts deleted file mode 100644 index 1fbf1fb78..000000000 --- a/src/serializers/snowflake.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Serializer } from '#lib/database'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { DiscordSnowflake } from '@sapphire/snowflake'; -import type { Awaitable } from '@sapphire/utilities'; - -export class UserSerializer extends Serializer { - /** - * The validator, requiring all numbers and 17 to 19 digits (future-proof). - */ - private readonly kRegExp = /^\d{17,19}$/; - - /** - * Stanislav's join day, known as the oldest user in Discord, and practically - * the lowest snowflake we can get (as they're bound by the creation date). - */ - private readonly kMinimum = new Date(2015, 1, 28).getTime(); - - public async parse(args: Serializer.Args) { - return this.result(args, await args.pickResult('snowflake')); - } - - public isValid(value: string, { t, entry }: Serializer.UpdateContext): Awaitable { - if (this.kRegExp.test(value)) { - const snowflake = DiscordSnowflake.deconstruct(value); - const timestamp = Number(snowflake.timestamp); - if (timestamp >= this.kMinimum && timestamp < Date.now()) return true; - } - throw t(LanguageKeys.Serializers.InvalidSnowflake, { name: entry.name }); - } -} diff --git a/src/serializers/stickyrole.ts b/src/serializers/stickyrole.ts deleted file mode 100644 index 1f4bdc282..000000000 --- a/src/serializers/stickyrole.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Serializer, type StickyRole } from '#lib/database'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { isObject, type Awaitable } from '@sapphire/utilities'; - -export class UserSerializer extends Serializer { - public parse(_: Serializer.Args, { t }: Serializer.UpdateContext) { - return this.error(t(LanguageKeys.Serializers.Unsupported)); - } - - public isValid(value: StickyRole, { t, guild }: Serializer.UpdateContext): Awaitable { - if ( - isObject(value) && - Object.keys(value).length === 2 && - typeof value.user === 'string' && - Array.isArray(value.roles) && - value.roles.every((role) => typeof role === 'string' && guild.roles.cache.has(role)) - ) - return true; - - throw t(LanguageKeys.Serializers.StickyRoleInvalid); - } - - public override stringify(value: StickyRole, { t, guild }: Serializer.UpdateContext) { - const username = guild.client.users.cache.get(value.user)?.username ?? t(LanguageKeys.Serializers.UnknownUser); - const roles = value.roles.map((role) => guild.roles.cache.get(role)?.name ?? t(LanguageKeys.Serializers.UnknownRole)); - return `[${username} -> ${roles}]`; - } -} diff --git a/src/serializers/string.ts b/src/serializers/string.ts deleted file mode 100644 index 9c6de708b..000000000 --- a/src/serializers/string.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Serializer } from '#lib/database'; -import type { Awaitable } from '@sapphire/utilities'; - -export class UserSerializer extends Serializer { - public async parse(args: Serializer.Args, { entry }: Serializer.UpdateContext) { - return this.result(args, await args.restResult('string', { minimum: entry.minimum, maximum: entry.maximum })); - } - - public isValid(value: string, context: Serializer.UpdateContext): Awaitable { - return this.minOrMax(value, value.length, context).isOk(); - } -} diff --git a/src/serializers/timespan.ts b/src/serializers/timespan.ts deleted file mode 100644 index 4768ef0df..000000000 --- a/src/serializers/timespan.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Serializer } from '#lib/database'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import type { Awaitable } from '@sapphire/utilities'; - -export class UserSerializer extends Serializer { - public async parse(args: Serializer.Args, { entry }: Serializer.UpdateContext) { - return this.result(args, await args.pickResult(entry.type as 'timespan', { minimum: entry.minimum, maximum: entry.maximum })); - } - - public isValid(value: number, context: Serializer.UpdateContext): Awaitable { - if (typeof value === 'number' && Number.isInteger(value) && this.minOrMax(value, value, context)) return true; - throw context.t(LanguageKeys.Serializers.InvalidInt, { name: context.entry.name }); - } - - public override stringify(data: number, { t }: Serializer.UpdateContext): string { - return t(LanguageKeys.Globals.DurationValue, { value: data }); - } -} diff --git a/src/serializers/uniqueroleset.ts b/src/serializers/uniqueroleset.ts deleted file mode 100644 index 58a5f1df2..000000000 --- a/src/serializers/uniqueroleset.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { Serializer, type UniqueRoleSet } from '#lib/database'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { resolveGuild } from '#utils/common'; -import { isObject, type Awaitable } from '@sapphire/utilities'; - -export class UserSerializer extends Serializer { - public async parse(args: Serializer.Args) { - const name = await args.pickResult('string'); - if (name.isErr()) return this.errorFromArgument(args, name.unwrapErr()); - - const roles = await args.repeatResult('role'); - if (roles.isErr()) return this.errorFromArgument(args, roles.unwrapErr()); - - return this.ok({ name: name.unwrap(), roles: roles.unwrap().map((role) => role.id) }); - } - - public isValid(value: UniqueRoleSet, { t, guild }: Serializer.UpdateContext): Awaitable { - if ( - isObject(value) && - Object.keys(value).length === 2 && - typeof value.name === 'string' && - Array.isArray(value.roles) && - value.roles.every((role) => typeof role === 'string' && guild.roles.cache.has(role)) - ) - return true; - - throw t(LanguageKeys.Serializers.UniqueRoleSetInvalid); - } - - public override stringify(value: UniqueRoleSet, { t, entity }: Serializer.UpdateContext) { - const guild = resolveGuild(entity.id); - return `[${value.name} -> \`${value.roles - .map((role) => guild.roles.cache.get(role)?.name ?? t(LanguageKeys.Serializers.UnknownRole)) - .join('` | `')}\`]`; - } -} diff --git a/src/serializers/url.ts b/src/serializers/url.ts deleted file mode 100644 index d87402a12..000000000 --- a/src/serializers/url.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { Serializer } from '#lib/database'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import type { Awaitable } from '@sapphire/utilities'; - -export class UserSerializer extends Serializer { - private readonly kProtocol = /^https?:\/\//; - - public parse(args: Serializer.Args, { t, entry }: Serializer.UpdateContext) { - const value = args.next(); - try { - const { hostname } = new URL(this.kProtocol.test(value) ? value : `https://${value}`); - if (hostname.length <= 128) return this.ok(hostname); - return this.error(t(LanguageKeys.Serializers.MinMaxMaxInclusive, { name: entry.name, max: 128 })); - } catch { - return this.error(t(LanguageKeys.Serializers.MinMaxMaxInclusive, { name: entry.name, max: 128 })); - } - } - - public isValid(value: string, { t, entry }: Serializer.UpdateContext): Awaitable { - try { - const { hostname } = new URL(this.kProtocol.test(value) ? value : `https://${value}`); - return hostname.length <= 128; - } catch { - throw new Error(t(LanguageKeys.Serializers.InvalidUrl, { name: entry.name })); - } - } - - public validate(data: string, { entry, t }: Serializer.UpdateContext) { - try { - const { hostname } = new URL(this.kProtocol.test(data) ? data : `https://${data}`); - if (hostname.length > 128) throw t(LanguageKeys.Serializers.MinMaxMaxInclusive, { name: entry.name, max: 128 }); - return hostname; - } catch { - throw t(LanguageKeys.Serializers.InvalidUrl, { name: entry.name }); - } - } - - public override stringify(data: string) { - return `https://${data}`; - } -} diff --git a/src/serializers/user.ts b/src/serializers/user.ts deleted file mode 100644 index aef1f7298..000000000 --- a/src/serializers/user.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { Serializer } from '#lib/database'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { getTag } from '#utils/util'; -import { SnowflakeRegex } from '@sapphire/discord.js-utilities'; -import { isNullish } from '@sapphire/utilities'; - -export class UserSerializer extends Serializer { - public async parse(args: Serializer.Args) { - const result = await args.pickResult('user'); - return result.match({ - ok: (value) => this.ok(value.id), - err: (error) => this.errorFromArgument(args, error) - }); - } - - public async isValid(value: string, { t, entry }: Serializer.UpdateContext): Promise { - try { - // If it's not a valid snowflake, throw - if (!SnowflakeRegex.test(value)) throw undefined; - - // Fetch the value, if it exists, it'll resolve and return true - await this.container.client.users.fetch(value); - return true; - } catch { - throw t(LanguageKeys.Serializers.InvalidUser, { name: entry.name }); - } - } - - public override stringify(value: string) { - const user = this.container.client.users.cache.get(value); - return isNullish(user) ? value : getTag(user); - } -} diff --git a/src/serializers/word.ts b/src/serializers/word.ts deleted file mode 100644 index b94ed04f0..000000000 --- a/src/serializers/word.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { readSettingsWordFilterRegExp, Serializer, type ReadonlyGuildData } from '#lib/database'; -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { IncomingType, OutgoingType } from '#lib/moderation/workers'; -import type { Awaitable } from '@sapphire/utilities'; -import { remove as removeConfusables } from 'confusables'; - -export class UserSerializer extends Serializer { - public async parse(args: Serializer.Args, { t, entry, entity }: Serializer.UpdateContext) { - const result = await args.restResult('string', { minimum: entry.minimum, maximum: entry.maximum }); - if (result.isErr()) return this.result(args, result); - - const word = removeConfusables(result.unwrap().toLowerCase()); - if (await this.hasWord(entity, word)) return this.error(t(LanguageKeys.Serializers.WordIncluded, { name: entry.name, value: word })); - return this.ok(word); - } - - public isValid(value: string, context: Serializer.UpdateContext): Awaitable { - const word = removeConfusables(value.toLowerCase()); - return value === word && this.minOrMax(value, value.length, context).isOk(); - } - - private async hasWord(settings: ReadonlyGuildData, content: string) { - const words = settings.selfmodFilterRaw; - if (words.includes(content)) return true; - - const regExp = readSettingsWordFilterRegExp(settings); - if (regExp === null) return false; - - try { - const result = await this.container.workers.send({ type: IncomingType.RunRegExp, content, regExp }); - return result.type === OutgoingType.RegExpMatch; - } catch { - return false; - } - } -} diff --git a/src/tasks/moderation/moderationEndAddRole.ts b/src/tasks/moderation/moderationEndAddRole.ts deleted file mode 100644 index 8fbb8c1b8..000000000 --- a/src/tasks/moderation/moderationEndAddRole.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { ModerationActions, ModerationTask, type ModerationData } from '#lib/moderation'; -import { fetchT } from '@sapphire/plugin-i18next'; -import { PermissionFlagsBits, type Guild, type Role } from 'discord.js'; - -export class UserModerationTask extends ModerationTask { - protected async handle(guild: Guild, data: ModerationData<{ role: Role }>) { - const me = guild.members.me ?? (await guild.members.fetch(this.container.client.id!)); - if (!me.permissions.has(PermissionFlagsBits.ManageRoles)) return null; - - const t = await fetchT(guild); - const reason = `[MODERATION] Role removed after ${t(LanguageKeys.Globals.DurationValue, { value: data.duration })}`; - const actionData = await this.getActionData(guild, data.userID, data.extraData.role); - await ModerationActions.roleAdd.undo(guild, { user: data.userID, reason }, actionData); - return null; - } -} diff --git a/src/tasks/moderation/moderationEndBan.ts b/src/tasks/moderation/moderationEndBan.ts deleted file mode 100644 index b0321288c..000000000 --- a/src/tasks/moderation/moderationEndBan.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { ModerationActions, ModerationTask, type ModerationData } from '#lib/moderation'; -import { fetchT } from '@sapphire/plugin-i18next'; -import { PermissionFlagsBits, type Guild } from 'discord.js'; - -export class UserModerationTask extends ModerationTask { - protected async handle(guild: Guild, data: ModerationData) { - const me = guild.members.me ?? (await guild.members.fetch(this.container.client.id!)); - if (!me.permissions.has(PermissionFlagsBits.BanMembers)) return null; - - const t = await fetchT(guild); - const reason = `[MODERATION] Ban released after ${t(LanguageKeys.Globals.DurationValue, { value: data.duration })}`; - const actionData = await this.getActionData(guild, data.userID); - await ModerationActions.ban.undo(guild, { user: data.userID, reason }, actionData); - return null; - } -} diff --git a/src/tasks/moderation/moderationEndMute.ts b/src/tasks/moderation/moderationEndMute.ts deleted file mode 100644 index 379a3bb94..000000000 --- a/src/tasks/moderation/moderationEndMute.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { ModerationActions, ModerationTask, type ModerationData } from '#lib/moderation'; -import { fetchT } from '@sapphire/plugin-i18next'; -import type { Guild } from 'discord.js'; - -export class UserModerationTask extends ModerationTask { - protected async handle(guild: Guild, data: ModerationData) { - const t = await fetchT(guild); - const reason = `[MODERATION] Mute released after ${t(LanguageKeys.Globals.DurationValue, { value: data.duration })}`; - const actionData = await this.getActionData(guild, data.userID); - await ModerationActions.mute.undo(guild, { user: data.userID, reason }, actionData); - return null; - } -} diff --git a/src/tasks/moderation/moderationEndRemoveRole.ts b/src/tasks/moderation/moderationEndRemoveRole.ts deleted file mode 100644 index 457ebf8f5..000000000 --- a/src/tasks/moderation/moderationEndRemoveRole.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { ModerationActions, ModerationTask, type ModerationData } from '#lib/moderation'; -import { fetchT } from '@sapphire/plugin-i18next'; -import { PermissionFlagsBits, type Guild, type Role } from 'discord.js'; - -export class UserModerationTask extends ModerationTask { - protected async handle(guild: Guild, data: ModerationData<{ role: Role }>) { - const me = guild.members.me ?? (await guild.members.fetch(this.container.client.id!)); - if (!me.permissions.has(PermissionFlagsBits.ManageRoles)) return null; - - const t = await fetchT(guild); - const reason = `[MODERATION] Role re-added after ${t(LanguageKeys.Globals.DurationValue, { value: data.duration })}`; - const actionData = await this.getActionData(guild, data.userID, data.extraData.role); - await ModerationActions.roleRemove.undo(guild, { user: data.userID, reason }, actionData); - return null; - } -} diff --git a/src/tasks/moderation/moderationEndRestrictionAttachment.ts b/src/tasks/moderation/moderationEndRestrictionAttachment.ts deleted file mode 100644 index bf57f24d9..000000000 --- a/src/tasks/moderation/moderationEndRestrictionAttachment.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { ModerationActions, ModerationTask, type ModerationData } from '#lib/moderation'; -import { fetchT } from '@sapphire/plugin-i18next'; -import { PermissionFlagsBits, type Guild } from 'discord.js'; - -export class UserModerationTask extends ModerationTask { - protected async handle(guild: Guild, data: ModerationData) { - const me = guild.members.me ?? (await guild.members.fetch(this.container.client.id!)); - if (!me.permissions.has(PermissionFlagsBits.ManageRoles)) return null; - - const t = await fetchT(guild); - const reason = `[MODERATION] Attachment Restricted released after ${t(LanguageKeys.Globals.DurationValue, { value: data.duration })}`; - const actionData = await this.getActionData(guild, data.userID); - await ModerationActions.restrictedAttachment.undo(guild, { user: data.userID, reason }, actionData); - return null; - } -} diff --git a/src/tasks/moderation/moderationEndRestrictionEmbed.ts b/src/tasks/moderation/moderationEndRestrictionEmbed.ts deleted file mode 100644 index 83b89085e..000000000 --- a/src/tasks/moderation/moderationEndRestrictionEmbed.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { ModerationActions, ModerationTask, type ModerationData } from '#lib/moderation'; -import { fetchT } from '@sapphire/plugin-i18next'; -import { PermissionFlagsBits, type Guild } from 'discord.js'; - -export class UserModerationTask extends ModerationTask { - protected async handle(guild: Guild, data: ModerationData) { - const me = guild.members.me ?? (await guild.members.fetch(this.container.client.id!)); - if (!me.permissions.has(PermissionFlagsBits.ManageRoles)) return null; - - const t = await fetchT(guild); - const reason = `[MODERATION] Embed Restricted released after ${t(LanguageKeys.Globals.DurationValue, { value: data.duration })}`; - const actionData = await this.getActionData(guild, data.userID); - await ModerationActions.restrictedEmbed.undo(guild, { user: data.userID, reason }, actionData); - return null; - } -} diff --git a/src/tasks/moderation/moderationEndRestrictionEmoji.ts b/src/tasks/moderation/moderationEndRestrictionEmoji.ts deleted file mode 100644 index b3a1d574a..000000000 --- a/src/tasks/moderation/moderationEndRestrictionEmoji.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { ModerationActions, ModerationTask, type ModerationData } from '#lib/moderation'; -import { fetchT } from '@sapphire/plugin-i18next'; -import { PermissionFlagsBits, type Guild } from 'discord.js'; - -export class UserModerationTask extends ModerationTask { - protected async handle(guild: Guild, data: ModerationData) { - const me = guild.members.me ?? (await guild.members.fetch(this.container.client.id!)); - if (!me.permissions.has(PermissionFlagsBits.ManageRoles)) return null; - - const t = await fetchT(guild); - const reason = `[MODERATION] Emoji Restricted released after ${t(LanguageKeys.Globals.DurationValue, { value: data.duration })}`; - const actionData = await this.getActionData(guild, data.userID); - await ModerationActions.restrictedEmoji.undo(guild, { user: data.userID, reason }, actionData); - return null; - } -} diff --git a/src/tasks/moderation/moderationEndRestrictionReaction.ts b/src/tasks/moderation/moderationEndRestrictionReaction.ts deleted file mode 100644 index 3d30464fc..000000000 --- a/src/tasks/moderation/moderationEndRestrictionReaction.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { ModerationActions, ModerationTask, type ModerationData } from '#lib/moderation'; -import { fetchT } from '@sapphire/plugin-i18next'; -import { PermissionFlagsBits, type Guild } from 'discord.js'; - -export class UserModerationTask extends ModerationTask { - protected async handle(guild: Guild, data: ModerationData) { - const me = guild.members.me ?? (await guild.members.fetch(this.container.client.id!)); - if (!me.permissions.has(PermissionFlagsBits.ManageRoles)) return null; - - const t = await fetchT(guild); - const reason = `[MODERATION] Reaction Restricted released after ${t(LanguageKeys.Globals.DurationValue, { value: data.duration })}`; - const actionData = await this.getActionData(guild, data.userID); - await ModerationActions.restrictedReaction.undo(guild, { user: data.userID, reason }, actionData); - return null; - } -} diff --git a/src/tasks/moderation/moderationEndRestrictionVoice.ts b/src/tasks/moderation/moderationEndRestrictionVoice.ts deleted file mode 100644 index 7637f315c..000000000 --- a/src/tasks/moderation/moderationEndRestrictionVoice.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { ModerationActions, ModerationTask, type ModerationData } from '#lib/moderation'; -import { fetchT } from '@sapphire/plugin-i18next'; -import { PermissionFlagsBits, type Guild } from 'discord.js'; - -export class UserModerationTask extends ModerationTask { - protected async handle(guild: Guild, data: ModerationData) { - const me = guild.members.me ?? (await guild.members.fetch(this.container.client.id!)); - if (!me.permissions.has(PermissionFlagsBits.ManageRoles)) return null; - - const t = await fetchT(guild); - const reason = `[MODERATION] Voice Restricted released after ${t(LanguageKeys.Globals.DurationValue, { value: data.duration })}`; - const actionData = await this.getActionData(guild, data.userID); - await ModerationActions.restrictedVoice.undo(guild, { user: data.userID, reason }, actionData); - return null; - } -} diff --git a/src/tasks/moderation/moderationEndSetNickname.ts b/src/tasks/moderation/moderationEndSetNickname.ts deleted file mode 100644 index 77310674d..000000000 --- a/src/tasks/moderation/moderationEndSetNickname.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { ModerationActions, ModerationTask, type ModerationData } from '#lib/moderation'; -import { fetchT } from '@sapphire/plugin-i18next'; -import { PermissionFlagsBits, type Guild } from 'discord.js'; - -export class UserModerationTask extends ModerationTask { - protected async handle(guild: Guild, data: ModerationData<{ oldName: string }>) { - const me = guild.members.me ?? (await guild.members.fetch(this.container.client.id!)); - if (!me.permissions.has(PermissionFlagsBits.ManageNicknames)) return null; - - const t = await fetchT(guild); - const reason = `[MODERATION] Nickname reverted after ${t(LanguageKeys.Globals.DurationValue, { value: data.duration })}`; - const actionData = await this.getActionData(guild, data.userID, data.extraData.oldName); - await ModerationActions.setNickname.undo(guild, { user: data.userID, reason }, actionData); - return null; - } -} diff --git a/src/tasks/moderation/moderationEndTimeout.ts b/src/tasks/moderation/moderationEndTimeout.ts deleted file mode 100644 index 0ac88d08f..000000000 --- a/src/tasks/moderation/moderationEndTimeout.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { ModerationTask, type ModerationData } from '#lib/moderation'; -import { getModeration } from '#utils/functions'; -import { TypeMetadata, TypeVariation } from '#utils/moderationConstants'; -import { fetchT } from '@sapphire/plugin-i18next'; -import type { Guild } from 'discord.js'; - -export class UserModerationTask extends ModerationTask { - protected async handle(guild: Guild, data: ModerationData) { - const t = await fetchT(guild); - - const moderation = getModeration(guild); - - const reason = `[MODERATION] Timeout released after ${t(LanguageKeys.Globals.DurationValue, { value: data.duration })}`; - const entry = moderation.create({ - user: data.userID, - type: TypeVariation.Timeout, - metadata: TypeMetadata.Undo, - reason - }); - await moderation.insert(entry); - return null; - } -} diff --git a/src/tasks/moderation/moderationEndVoiceMute.ts b/src/tasks/moderation/moderationEndVoiceMute.ts deleted file mode 100644 index 6354d0967..000000000 --- a/src/tasks/moderation/moderationEndVoiceMute.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { ModerationActions, ModerationTask, type ModerationData } from '#lib/moderation'; -import { fetchT } from '@sapphire/plugin-i18next'; -import { PermissionFlagsBits, type Guild } from 'discord.js'; - -export class UserModerationTask extends ModerationTask { - protected async handle(guild: Guild, data: ModerationData) { - const me = guild.members.me ?? (await guild.members.fetch(this.container.client.id!)); - if (!me.permissions.has(PermissionFlagsBits.MuteMembers)) return null; - - const t = await fetchT(guild); - const reason = `[MODERATION] Voice Mute released after ${t(LanguageKeys.Globals.DurationValue, { value: data.duration })}`; - const actionData = await this.getActionData(guild, data.userID); - await ModerationActions.voiceMute.undo(guild, { user: data.userID, reason }, actionData); - return null; - } -} diff --git a/src/tasks/moderation/moderationEndWarning.ts b/src/tasks/moderation/moderationEndWarning.ts deleted file mode 100644 index fcc9668e8..000000000 --- a/src/tasks/moderation/moderationEndWarning.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { LanguageKeys } from '#lib/i18n/languageKeys'; -import { ModerationActions, ModerationTask, type ModerationData } from '#lib/moderation'; -import { fetchT } from '@sapphire/plugin-i18next'; -import { PermissionFlagsBits, type Guild } from 'discord.js'; - -export class UserModerationTask extends ModerationTask { - protected async handle(guild: Guild, data: ModerationData) { - const me = guild.members.me ?? (await guild.members.fetch(this.container.client.id!)); - if (!me.permissions.has(PermissionFlagsBits.BanMembers)) return null; - - const t = await fetchT(guild); - const reason = `[MODERATION] Warning released after ${t(LanguageKeys.Globals.DurationValue, { value: data.duration })}`; - const actionData = await this.getActionData(guild, data.userID, data.caseID); - await ModerationActions.warning.undo(guild, { user: data.userID, reason }, actionData); - return null; - } -} diff --git a/src/tasks/syncResourceAnalytics.ts b/src/tasks/syncResourceAnalytics.ts deleted file mode 100644 index 3244b1f3a..000000000 --- a/src/tasks/syncResourceAnalytics.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Task } from '#lib/schedule'; -import { Events } from '#lib/types'; - -export class UserTask extends Task { - public run() { - this.container.client.emit(Events.ResourceAnalyticsSync); - return null; - } -} diff --git a/src/tsconfig.json b/src/tsconfig.json deleted file mode 100644 index f9b308876..000000000 --- a/src/tsconfig.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "../tsconfig.base.json", - "compilerOptions": { - "module": "ESNext", - "moduleResolution": "bundler", - "rootDir": "..", - "noEmit": true, - "allowJs": true, - "skipLibCheck": true, - "resolvePackageJsonImports": true - }, - "include": [".", "./**/*.json"], - "exclude": ["./tsconfig.json", "../dist"] -} diff --git a/tests/tsconfig.json b/tests/tsconfig.json deleted file mode 100644 index 42502d2b0..000000000 --- a/tests/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "extends": "../tsconfig.base.json", - "compilerOptions": { - "noEmit": true, - "types": ["vitest/globals"], - "verbatimModuleSyntax": false, - "paths": { - "#utils/*": ["../src/lib/util/*"], - "#lib/*": ["../src/lib/*"], - "#languages": ["../src/languages/index"], - "#root/*": ["../src/*"] - } - }, - "include": [".", "../src"] -} diff --git a/tsconfig.base.json b/tsconfig.base.json index 1dd4cba64..ab37235db 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -1,6 +1,9 @@ { - "extends": ["@sapphire/ts-config", "@sapphire/ts-config/extra-strict", "@sapphire/ts-config/decorators", "@sapphire/ts-config/verbatim"], + "extends": "@sapphire/ts-config/extra-strict", "compilerOptions": { - "removeComments": true + "lib": ["ESNext", "DOM"], + "emitDecoratorMetadata": false, + "target": "ESNext", + "module": "ESNext" } } diff --git a/tsdown.config.ts b/tsdown.config.ts deleted file mode 100644 index 6a404fe87..000000000 --- a/tsdown.config.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { defineConfig } from 'tsdown'; -import { resolve, dirname, join } from 'node:path'; -import { fileURLToPath } from 'node:url'; -import { existsSync, copyFileSync, mkdirSync, cpSync } from 'node:fs'; -const __filename = fileURLToPath(import.meta.url); -const __dirname = dirname(__filename); -import type { RolldownPluginOption } from 'rolldown'; -import alias from '@rollup/plugin-alias'; - -// Plugin to copy .mjs files from src to dist -function copyPlugin(): RolldownPluginOption { - return { - name: 'copy-mjs-files', - buildEnd() { - // Copy worker.mjs to dist - const workerFile = resolve(__dirname, 'src/lib/moderation/workers/worker.mjs'); - const destDir = resolve(__dirname, 'dist/lib/moderation/workers'); - const destFile = join(destDir, 'worker.mjs'); - - const srcDir = resolve(__dirname, 'src/languages'); - const destLanguagesDir = resolve(__dirname, 'dist/languages'); - - if (existsSync(workerFile)) { - mkdirSync(destDir, { recursive: true }); - copyFileSync(workerFile, destFile); - console.log('✓ Copied worker.mjs to dist'); - } - - if (existsSync(srcDir)) { - mkdirSync(destLanguagesDir, { recursive: true }); - cpSync(srcDir, destLanguagesDir, { recursive: true }); - console.log('✓ Copied languages to dist'); - } - } - }; -} - -export default defineConfig({ - entry: ['src/**/*.ts', '!src/languages/**/*.ts'], - format: 'esm', - plugins: [ - alias({ - entries: [ - { - find: '#lib', - replacement: '#lib', - customResolver(source) { - if (source === '#lib/database') return resolve('src/lib/database/index.ts'); - if (source === '#lib/database/entities') return resolve('src/lib/database/entities/index.ts'); - if (source === '#lib/database/keys') return resolve('src/lib/database/keys/index.ts'); - if (source === '#lib/database/settings') return resolve('src/lib/database/settings/index.ts'); - if (source === '#lib/discord') return resolve('src/lib/discord/index.ts'); - if (source === '#lib/moderation') return resolve('src/lib/moderation/index.ts'); - if (source === '#lib/moderation/actions') return resolve('src/lib/moderation/actions/index.ts'); - if (source === '#lib/moderation/common') return resolve('src/lib/moderation/common/index.ts'); - if (source === '#lib/moderation/managers/loggers') return resolve('src/lib/moderation/managers/loggers/index.ts'); - if (source === '#lib/moderation/managers') return resolve('src/lib/moderation/managers/index.ts'); - if (source === '#lib/moderation/workers') return resolve('src/lib/moderation/workers/index.ts'); - if (source === '#lib/schedule') return resolve('src/lib/schedule/index.ts'); - if (source === '#lib/structures') return resolve('src/lib/structures/index.ts'); - if (source === '#lib/structures/data') return resolve('src/lib/structures/data/index.ts'); - if (source === '#lib/structures/managers') return resolve('src/lib/structures/managers/index.ts'); - if (source === '#lib/setup') return resolve('src/lib/setup/index.ts'); - if (source === '#lib/types') return resolve('src/lib/types/index.ts'); - if (source === '#lib/i18n/languageKeys') return resolve('src/lib/i18n/languageKeys/index.ts'); - if (source === '#lib/i18n') return resolve('src/lib/i18n/index.ts'); - // Handle other #lib/* imports - const subPath = source.replace('#lib/', ''); - return resolve(__dirname, 'src/lib', `${subPath}.ts`); - } - }, - { find: /^#root\/(.*)/, replacement: resolve('src/$1.ts') }, - { find: '#generated/prisma', replacement: resolve('src/generated/prisma/client.js') }, - { find: '#languages', replacement: resolve('src/languages/index.ts') }, - { - find: '#utils', - replacement: '#utils', - customResolver(source) { - if (source === '#utils/common') return resolve('src/lib/util/common/index.ts'); - if (source === '#utils/functions') return resolve('src/lib/util/functions/index.ts'); - if (source === '#utils/resolvers') return resolve('src/lib/util/resolvers/index.ts'); - // Handle other #utils/* imports - const subPath = source.replace('#utils/', ''); - return resolve(__dirname, 'src/lib/util', `${subPath}.ts`); - } - } - ] - }), - copyPlugin() - ], - dts: true, - unbundle: true, - sourcemap: true, - minify: false, - platform: 'node', - tsconfig: 'src/tsconfig.json', - treeshake: true, - deps: { skipNodeModulesBundle: true } -}); diff --git a/vitest.config.ts b/vitest.config.ts index 5982aff0b..e6ae8430b 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -1,80 +1,49 @@ -import { resolve } from 'node:path'; +import { dirname, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; import { defineConfig } from 'vitest/config'; +const configDir = dirname(fileURLToPath(import.meta.url)); + function toPosix(path: string) { return path.replace(/\\/g, '/'); } function fromRoot(...paths: string[]) { - return toPosix(resolve(...paths)); + return toPosix(resolve(configDir, ...paths)); } -const srcRoot = fromRoot('src'); -const libRoot = fromRoot('src', 'lib'); -const utilRoot = fromRoot('src', 'lib', 'util'); +const srcRoot = fromRoot('projects', 'bot', 'src'); +const libRoot = fromRoot('projects', 'bot', 'src', 'lib'); +const utilRoot = fromRoot('projects', 'bot', 'src', 'lib', 'util'); +const testsRoot = fromRoot('projects', 'bot', 'tests'); export default defineConfig({ resolve: { alias: [ + { find: /^#mocks\/(.*)/, replacement: `${testsRoot}/mocks/$1` }, { find: /^#lib\/(.*)/, replacement: `${libRoot}/$1` }, { find: '#lib', replacement: libRoot }, - { find: /^#root\/(.*)/, replacement: `${srcRoot}/$1.ts` }, - { find: '#generated/prisma', replacement: `${srcRoot}/generated/prisma/client.js` }, - { find: '#languages', replacement: `${srcRoot}/languages/index.ts` }, { find: /^#utils\/(.*)/, replacement: `${utilRoot}/$1` }, - { find: '#utils', replacement: utilRoot } + { find: '#utils', replacement: utilRoot }, + { find: /^#root\/(.*)/, replacement: `${srcRoot}/$1.ts` }, + { find: '#root/config', replacement: `${srcRoot}/config.ts` }, + { find: '#languages', replacement: `${srcRoot}/locales/index.ts` } ] }, test: { - setupFiles: ['./tests/vitest.setup.ts'], + include: [ + fromRoot('projects/bot/tests/**/*.test.ts'), + fromRoot('projects/shared/tests/**/*.test.ts') + ], + setupFiles: [fromRoot('projects/bot/tests/vitest.setup.ts')], globals: true, + passWithNoTests: true, coverage: { provider: 'v8', - reportsDirectory: './coverage', + reportsDirectory: fromRoot('coverage'), reporter: ['text', 'lcov', 'cobertura'], reportOnFailure: true, - include: ['src/lib/**'], - exclude: [ - 'src/lib/api', - 'src/lib/customCommands', - 'src/lib/database/entities', - 'src/lib/database/index.ts', - 'src/lib/database/migrations', - 'src/lib/database/repositories', - 'src/lib/database/settings', - 'src/lib/database/utils', - 'src/lib/discord', - 'src/lib/env', - 'src/lib/extensions', - 'src/lib/games/base', - 'src/lib/games/connect-four', - 'src/lib/games/HungerGamesUsage.ts', - 'src/lib/games/Slotmachine.ts', - 'src/lib/games/tic-tac-toe', - 'src/lib/games/WheelOfFortune.ts', - 'src/lib/i18n/structures/Augments.d.ts', - 'src/lib/moderation', - 'src/lib/setup/PaginatedMessage.ts', - 'src/lib/WolfClient.ts', - 'src/lib/structures', - 'src/lib/types', - 'src/lib/util/APIs', - 'src/lib/util/Color.ts', - 'src/lib/util/decorators.ts', - 'src/lib/util/External', - 'src/lib/util/Leaderboard.ts', - 'src/lib/util/Links', - 'src/lib/util/LongLivingReactionCollector.ts', - 'src/lib/util/Models', - 'src/lib/util/Notifications', - 'src/lib/util/Parsers', - 'src/lib/util/PreciseTimeout.ts', - 'src/lib/util/PromptList.ts', - 'src/lib/util/Security/GuildSecurity.ts', - 'src/lib/util/Security/ModerationActions.ts', - 'src/lib/util/Timers.ts', - 'src/lib/weather' - ] + include: [fromRoot('projects/bot/src/lib/**')] } }, esbuild: { From d3cc9f948c33efa590a2f88977f94931684a4dcc Mon Sep 17 00:00:00 2001 From: RedStar Date: Fri, 12 Jun 2026 14:21:03 +0200 Subject: [PATCH 02/12] chore: update pnpm and dependencies to latest versions --- mise.toml | 2 +- package.json | 30 +- pnpm-lock.yaml | 1852 ++++++++++------- pnpm-workspace.yaml | 27 +- prisma.config.ts | 15 +- projects/bot/package.json | 13 +- projects/gateway/package.json | 10 +- projects/shared/package.json | 4 +- .../20240805115805_init/migration.sql | 0 .../migration.sql | 0 .../migration.sql | 0 .../migration.sql | 0 .../migration.sql | 0 .../migration.sql | 0 .../prisma}/migrations/migration_lock.toml | 0 .../shared/src/lib/prisma}/schema.prisma | 0 taze.config.ts | 7 - 17 files changed, 1156 insertions(+), 804 deletions(-) rename {prisma => projects/shared/src/lib/prisma}/migrations/20240805115805_init/migration.sql (100%) rename {prisma => projects/shared/src/lib/prisma}/migrations/20260416120000_add_dashboard_audit_log/migration.sql (100%) rename {prisma => projects/shared/src/lib/prisma}/migrations/20260416130000_migrate_audit_log_to_audit_event/migration.sql (100%) rename {prisma => projects/shared/src/lib/prisma}/migrations/20260516000000_add_channels_logs_command_settings/migration.sql (100%) rename {prisma => projects/shared/src/lib/prisma}/migrations/20260518000000_add_command_log/migration.sql (100%) rename {prisma => projects/shared/src/lib/prisma}/migrations/20260520000000_update_command_log/migration.sql (100%) rename {prisma => projects/shared/src/lib/prisma}/migrations/migration_lock.toml (100%) rename {prisma => projects/shared/src/lib/prisma}/schema.prisma (100%) diff --git a/mise.toml b/mise.toml index d5eb0d4d5..a6327548d 100644 --- a/mise.toml +++ b/mise.toml @@ -1,3 +1,3 @@ [tools] node = "lts" -pnpm = "10" +pnpm = "11" diff --git a/package.json b/package.json index b91e62b77..a27e712c4 100644 --- a/package.json +++ b/package.json @@ -21,24 +21,22 @@ "prepare": "husky" }, "devDependencies": { - "@commitlint/cli": "^20.5.3", - "@commitlint/config-conventional": "^20.5.3", - "@sapphire/prettier-config": "^2.0.0", + "@commitlint/cli": "^21.0.2", + "@commitlint/config-conventional": "^21.0.2", "@sapphire/ts-config": "^5.0.3", - "@types/node": "^22.8.7", - "@vitest/coverage-v8": "^4.1.7", + "@types/node": "^24.13.2", + "@vitest/coverage-v8": "^4.1.8", "cz-conventional-changelog": "^3.3.0", "husky": "^9.1.7", - "lint-staged": "^16.4.0", - "oxfmt": "^0.51.0", - "oxlint": "^1.66.0", - "prettier": "^3.8.3", - "prisma": "^4.1.1", - "taze": "^19.13.0", - "tsdown": "latest", - "typescript": "^4.7.4", - "vite": "^6.3.5", - "vitest": "^4.1.7" + "nano-staged": "^1.0.2", + "oxfmt": "^0.54.0", + "oxlint": "^1.69.0", + "prisma": "^7.8.0", + "taze": "^19.14.1", + "tsdown": "0.22.0", + "typescript": "^6.0.3", + "vite": "^6.4.3", + "vitest": "^4.1.8" }, "repository": { "type": "git", @@ -63,5 +61,5 @@ } }, "prettier": "@sapphire/prettier-config", - "packageManager": "pnpm@10.33.4" + "packageManager": "pnpm@11.4.0" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0a957cced..a3ac473d3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -16,59 +16,53 @@ importers: .: devDependencies: '@commitlint/cli': - specifier: ^20.5.3 - version: 20.5.3(@types/node@22.19.21)(conventional-commits-parser@6.4.0)(typescript@4.9.5) + specifier: ^21.0.2 + version: 21.0.2(@types/node@24.13.2)(conventional-commits-parser@6.4.0)(typescript@6.0.3) '@commitlint/config-conventional': - specifier: ^20.5.3 - version: 20.5.3 - '@sapphire/prettier-config': - specifier: ^2.0.0 - version: 2.0.0 + specifier: ^21.0.2 + version: 21.0.2 '@sapphire/ts-config': specifier: ^5.0.3 version: 5.0.3 '@types/node': - specifier: ^22.8.7 - version: 22.19.21 + specifier: ^24.13.2 + version: 24.13.2 '@vitest/coverage-v8': - specifier: ^4.1.7 + specifier: ^4.1.8 version: 4.1.8(vitest@4.1.8) cz-conventional-changelog: specifier: ^3.3.0 - version: 3.3.0(@types/node@22.19.21)(typescript@4.9.5) + version: 3.3.0(@types/node@24.13.2)(typescript@6.0.3) husky: specifier: ^9.1.7 version: 9.1.7 - lint-staged: - specifier: ^16.4.0 - version: 16.4.0 + nano-staged: + specifier: ^1.0.2 + version: 1.0.2 oxfmt: - specifier: ^0.51.0 - version: 0.51.0 + specifier: ^0.54.0 + version: 0.54.0 oxlint: - specifier: ^1.66.0 + specifier: ^1.69.0 version: 1.69.0 - prettier: - specifier: ^3.8.3 - version: 3.8.4 prisma: - specifier: ^4.1.1 - version: 4.16.2 + specifier: ^7.8.0 + version: 7.8.0(@types/react@19.2.17)(magicast@0.5.3)(react-dom@19.2.7)(react@19.2.7)(typescript@6.0.3) taze: - specifier: ^19.13.0 + specifier: ^19.14.1 version: 19.14.1 tsdown: - specifier: latest - version: 0.22.2(typescript@4.9.5) + specifier: 0.22.0 + version: 0.22.0(typescript@6.0.3) typescript: - specifier: ^4.7.4 - version: 4.9.5 + specifier: ^6.0.3 + version: 6.0.3 vite: - specifier: ^6.3.5 - version: 6.4.3(@types/node@22.19.21)(jiti@2.6.1)(yaml@2.9.0) + specifier: ^6.4.3 + version: 6.4.3(@types/node@24.13.2)(jiti@2.7.0)(yaml@2.9.0) vitest: - specifier: ^4.1.7 - version: 4.1.8(@opentelemetry/api@1.9.1)(@types/node@22.19.21)(@vitest/coverage-v8@4.1.8)(vite@6.4.3) + specifier: ^4.1.8 + version: 4.1.8(@opentelemetry/api@1.9.1)(@types/node@24.13.2)(@vitest/coverage-v8@4.1.8)(vite@6.4.3) projects/bot: dependencies: @@ -76,11 +70,11 @@ importers: specifier: ^1.1.0 version: 1.14.1 '@discordjs/collection': - specifier: ^1.0.1 - version: 1.5.3 + specifier: 2.1.1 + version: 2.1.1 '@prisma/client': - specifier: ^4.1.1 - version: 4.16.2(prisma@4.16.2) + specifier: ^7.8.0 + version: 7.8.0(prisma@7.8.0)(typescript@6.0.3) '@sapphire/async-queue': specifier: ^1.3.2 version: 1.5.5 @@ -90,12 +84,9 @@ importers: '@sapphire/utilities': specifier: ^3.8.0 version: 3.18.2 - '@sentry/integrations': - specifier: ^7.8.0 - version: 7.114.0 '@sentry/node': - specifier: ^7.8.0 - version: 7.120.4 + specifier: ^10.57.0 + version: 10.57.0 '@skyra/char': specifier: ^1.0.3 version: 1.0.3 @@ -134,7 +125,7 @@ importers: version: link:../shared devDependencies: '@rollup/plugin-alias': - specifier: latest + specifier: 6.0.0 version: 6.0.0(rollup@4.61.1) '@sapphire/framework': specifier: ^4.5.0 @@ -143,8 +134,8 @@ importers: specifier: ^14.14.1 version: 14.26.4 tsdown: - specifier: latest - version: 0.22.2(typescript@6.0.3) + specifier: 0.22.0 + version: 0.22.0(typescript@6.0.3) typescript: specifier: ^6.0.0 version: 6.0.3 @@ -152,13 +143,13 @@ importers: projects/gateway: dependencies: '@discordjs/rest': - specifier: ^1.0.1 - version: 1.7.1 + specifier: ^2.6.1 + version: 2.6.1 '@discordjs/ws': - specifier: ^0.2.0 - version: 0.2.0 + specifier: ^2.0.4 + version: 2.0.4 '@sapphire/utilities': - specifier: ^3.8.0 + specifier: ^3.18.2 version: 3.18.2 '@wolfstar/env-utilities': specifier: ^3.0.1 @@ -177,8 +168,8 @@ importers: version: link:../shared devDependencies: typescript: - specifier: ^4.7.4 - version: 4.9.5 + specifier: ^6.0.0 + version: 6.0.3 projects/shared: dependencies: @@ -208,8 +199,8 @@ importers: version: 5.0.0 devDependencies: typescript: - specifier: ^4.7.4 - version: 4.9.5 + specifier: ^6.0.0 + version: 6.0.3 packages: @@ -268,90 +259,70 @@ packages: resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} engines: {node: '>=18'} - '@commitlint/cli@20.5.3': - resolution: {integrity: sha512-OJdL0EXWD5y9LPa0nr/geOwzaS8BsdaybKkcloB0JgsguGxNv2R+hC2FTPqrAcprg35zF33KOQerY0x8W1aesA==} - engines: {node: '>=v18'} + '@commitlint/cli@21.0.2': + resolution: {integrity: sha512-YMmfLbqBg+ZRvvmPhc+cilSQFrh/AgzVgCT1U/OifmUZEwPbvCtA8rN//YNaF9d5eoZphxVMGYtmwA2QgQORgg==} + engines: {node: '>=22.12.0'} hasBin: true - '@commitlint/config-conventional@20.5.3': - resolution: {integrity: sha512-j34Qqeaa152chJgz2ysyk0BCpHenJn1lV0Rx0VXf8k3ccQcED+48EZrzMvo9jLmJUyBrrBwvu89I+2er4gW7QQ==} - engines: {node: '>=v18'} - - '@commitlint/config-validator@20.5.0': - resolution: {integrity: sha512-T/Uh6iJUzyx7j35GmHWdIiGRQB+ouZDk0pwAaYq4SXgB54KZhFdJ0vYmxiW6AMYICTIWuyMxDBl1jK74oFp/Gw==} - engines: {node: '>=v18'} + '@commitlint/config-conventional@21.0.2': + resolution: {integrity: sha512-P/ZRhryQmkj0Z0dY9FOoRwe3xkwJyyAdtXwt01NT2kuZttcG2CNYp1q5Ci3u+nDT2jcbJRw2kt13Czl1qKNPfg==} + engines: {node: '>=22.12.0'} '@commitlint/config-validator@21.0.1': resolution: {integrity: sha512-Zd2UFdndeMMaW2O96HK0tdfT4gOImUvidMpAd/pws2zZ4m1nrAZ/9b/v2JYuE8fs86GpXv9F7LNaIuCIWhY+pA==} engines: {node: '>=22.12.0'} - '@commitlint/ensure@20.5.3': - resolution: {integrity: sha512-4i4AgNvH62owG9MwSiWKrle7HGNpBHHdLnWFIp5fTsHUYe5kRuh15t08L/0pdbbrRk8JKXQxxN4hZQcn+szkrw==} - engines: {node: '>=v18'} - - '@commitlint/execute-rule@20.0.0': - resolution: {integrity: sha512-xyCoOShoPuPL44gVa+5EdZsBVao/pNzpQhkzq3RdtlFdKZtjWcLlUFQHSWBuhk5utKYykeJPSz2i8ABHQA+ZZw==} - engines: {node: '>=v18'} + '@commitlint/ensure@21.0.1': + resolution: {integrity: sha512-jJ1037967wU7YN/xkv+iRlOBlmaOXPhPO5KQSqya6GyXzBlwuLzELBFao16DVg9dZyqmNrhewzwZ3SAibetHBQ==} + engines: {node: '>=22.12.0'} '@commitlint/execute-rule@21.0.1': resolution: {integrity: sha512-RifH+FmImozKBE6mozhF4K3r2RRKP7SMi/Q/zLCmExtp5e05lhHOUYqGBlFBAGNHaZxU/WYw1XuugYK9jQzqnA==} engines: {node: '>=22.12.0'} - '@commitlint/format@20.5.0': - resolution: {integrity: sha512-TI9EwFU/qZWSK7a5qyXMpKPPv3qta7FO4tKW+Wt2al7sgMbLWTsAcDpX1cU8k16TRdsiiet9aOw0zpvRXNJu7Q==} - engines: {node: '>=v18'} - - '@commitlint/is-ignored@20.5.0': - resolution: {integrity: sha512-JWLarAsurHJhPozbuAH6GbP4p/hdOCoqS9zJMfqwswne+/GPs5V0+rrsfOkP68Y8PSLphwtFXV0EzJ+GTXTTGg==} - engines: {node: '>=v18'} + '@commitlint/format@21.0.1': + resolution: {integrity: sha512-ksmG2+cHGtuDPQQbhBbC4unwm444+6TiPw0d1bKf67hntgZqZ8E0g1MuYKUuyT5IH4IMmXZhKq22/Z3jBvtQIw==} + engines: {node: '>=22.12.0'} - '@commitlint/lint@20.5.3': - resolution: {integrity: sha512-M7JbWBNr2gXKaPc4i/KipsuW1gkDHpj35KPjWtKy3Z+2AQw5wu1gBi1LIO0uoaij67CqY4K8PxPZSGens4evCw==} - engines: {node: '>=v18'} + '@commitlint/is-ignored@21.0.2': + resolution: {integrity: sha512-H5z4t8PC9tUsmZ/o+EptM3Nq8sTFtskAShdcqxCoyzklW5eaVT5xbrDAET2uypzir9Vsj4ZZmBtyKjYe2XqgeQ==} + engines: {node: '>=22.12.0'} - '@commitlint/load@20.5.3': - resolution: {integrity: sha512-1FDZWuKyu98Myb8i7Tp31jPU2rZpOwAdYRyJcy2KoGg7Xk2A+bgHN8smhMaaNSNkmE8fwt53BokywZq8Gv/5XQ==} - engines: {node: '>=v18'} + '@commitlint/lint@21.0.2': + resolution: {integrity: sha512-PnUmLYGeGLfW8oVatR9KpNxSHYAnJOEWlMZzfdeFOUq6WUrFx1fGQaWCWJqMoIll/xPM+GdfJV+tKHZVHhl0Fg==} + engines: {node: '>=22.12.0'} '@commitlint/load@21.0.2': resolution: {integrity: sha512-lwUE70hN0/qE/ZRROhbaX65ly/FF12DrqfReLCESo37M0OQCFAf2jRS+2tSCSORq+bm4Kdju7qNDj46uc1QzTA==} engines: {node: '>=22.12.0'} - '@commitlint/message@20.4.3': - resolution: {integrity: sha512-6akwCYrzcrFcTYz9GyUaWlhisY4lmQ3KvrnabmhoeAV8nRH4dXJAh4+EUQ3uArtxxKQkvxJS78hNX2EU3USgxQ==} - engines: {node: '>=v18'} - - '@commitlint/parse@20.5.0': - resolution: {integrity: sha512-SeKWHBMk7YOTnnEWUhx+d1a9vHsjjuo6Uo1xRfPNfeY4bdYFasCH1dDpAv13Lyn+dDPOels+jP6D2GRZqzc5fA==} - engines: {node: '>=v18'} + '@commitlint/message@21.0.2': + resolution: {integrity: sha512-5n4aqHGD/FNnom/D5L8i7cYtV+xjuXcBL832C3w9VglEsZzIsoHpJsvxzJ7cgiOsOdc/2jU4t5+7qMHh7GBX3g==} + engines: {node: '>=22.12.0'} - '@commitlint/read@20.5.0': - resolution: {integrity: sha512-JDEIJ2+GnWpK8QqwfmW7O42h0aycJEWNqcdkJnyzLD11nf9dW2dWLTVEa8Wtlo4IZFGLPATjR5neA5QlOvIH1w==} - engines: {node: '>=v18'} + '@commitlint/parse@21.0.2': + resolution: {integrity: sha512-QVZJhGHTm+oiuWyEKOCTQ0ZM3mfJ0eGWFeHuj7WzSKEth+UukcCHac9GD8pgdFlg/qGkFWOtyaNd1T8REgagaw==} + engines: {node: '>=22.12.0'} - '@commitlint/resolve-extends@20.5.3': - resolution: {integrity: sha512-+ogW9v/u9JqpvAgTrLra/YTFo0KkjU6iNblF89pPsj4NebNc+DAWctsludwezI8YnsjBmfHpApSwcXprN/f/ew==} - engines: {node: '>=v18'} + '@commitlint/read@21.0.2': + resolution: {integrity: sha512-BtsrnLVycSSKf4Q0gMch4giCj5NNlmcbhc8ra5vONgGtP2IjRDo33bEFtr5Pm+2N+5fXGWb2MksWPrspPfdhdw==} + engines: {node: '>=22.12.0'} '@commitlint/resolve-extends@21.0.1': resolution: {integrity: sha512-0DhjYWL6uYrY16Efa032fYk3woGJDU4AGWiG1XXltT9AMUNYKyb5cIZU2ivbaMZ3+kKFqUjikD2cjh66Sbh/Sg==} engines: {node: '>=22.12.0'} - '@commitlint/rules@20.5.3': - resolution: {integrity: sha512-MPlMnb9D3wbszYMp+1hPtuhtPJndRo6I6yfkZVA4+jR8w7Kqp0u2u/Y+gzbaItx5Lltq5rw7FSZQWJMoXUC4NQ==} - engines: {node: '>=v18'} - - '@commitlint/to-lines@20.0.0': - resolution: {integrity: sha512-2l9gmwiCRqZNWgV+pX1X7z4yP0b3ex/86UmUFgoRt672Ez6cAM2lOQeHFRUTuE6sPpi8XBCGnd8Kh3bMoyHwJw==} - engines: {node: '>=v18'} + '@commitlint/rules@21.0.2': + resolution: {integrity: sha512-k6tQ69Td7t2qUSIbik8D3TL1q3ZJpkEbV+yLogDzCRAdOxJm4ndhtBNREsLA1/puRfWvzS9eioF2w43WT+hHgQ==} + engines: {node: '>=22.12.0'} - '@commitlint/top-level@20.4.3': - resolution: {integrity: sha512-qD9xfP6dFg5jQ3NMrOhG0/w5y3bBUsVGyJvXxdWEwBm8hyx4WOk3kKXw28T5czBYvyeCVJgJJ6aoJZUWDpaacQ==} - engines: {node: '>=v18'} + '@commitlint/to-lines@21.0.1': + resolution: {integrity: sha512-bd1BFII7p1EQZre9Kaj+kKaMFP3cFCdt21K7DItVux9XP5WjLgJ0/Uy1pJJh9aPwVJ6SKg62PxqlZaHI8hQAXw==} + engines: {node: '>=22.12.0'} - '@commitlint/types@20.5.0': - resolution: {integrity: sha512-ZJoS8oSq2CAZEpc/YI9SulLrdiIyXeHb/OGqGrkUP6Q7YV+0ouNAa7GjqRdXeQPncHQIDz/jbCTlHScvYvO/gA==} - engines: {node: '>=v18'} + '@commitlint/top-level@21.0.2': + resolution: {integrity: sha512-s9KKM+e+mXgFeIh4n7KmOGAVT3mkJ3Fp1bBYHIK5pjeUwlEMzp/tZfb5u0Poa680AsQTXMEMRxZi1vQ9m2X5ug==} + engines: {node: '>=22.12.0'} '@commitlint/types@21.0.1': resolution: {integrity: sha512-4u7w8jcoCUFWhjWnASYzZHAP34OqOtuFBN87nQmFvqda03YU0T6z+yB4w0gSAMpekiRqqGk5rt+qSlW+a2vSEg==} @@ -385,30 +356,36 @@ packages: resolution: {integrity: sha512-y4UPwWhH6vChKRkGdMB4odasUbHOUwy7KL+OVwF86PvT6QVOwElx+TiI1/6kcmcEe+g5YRXJFiXSXUdabqZOvQ==} engines: {node: '>=16.11.0'} - '@discordjs/rest@1.7.1': - resolution: {integrity: sha512-Ofa9UqT0U45G/eX86cURQnX7gzOJLG2oC28VhIk/G6IliYgQF7jFByBJEykPSHE4MxPhqCleYvmsrtfKh1nYmQ==} - engines: {node: '>=16.9.0'} - '@discordjs/rest@2.6.1': resolution: {integrity: sha512-wwQdgjeaoYFiaG+atbqx6aJDpqW7JHAo0HrQkBTbYzM3/PJ3GweQIpgElNcGZ26DCUOXMyawYd0YF7vtr+fZXg==} engines: {node: '>=18'} - '@discordjs/util@0.3.1': - resolution: {integrity: sha512-HxXKYKg7vohx2/OupUN/4Sd02Ev3PBJ5q0gtjdcvXb0ErCva8jNHWfe/v5sU3UKjIB/uxOhc+TDOnhqffj9pRA==} - engines: {node: '>=16.9.0'} - '@discordjs/util@1.2.0': resolution: {integrity: sha512-3LKP7F2+atl9vJFhaBjn4nOaSWahZ/yWjOvA4e5pnXkt2qyXRCHLxoBQy81GFtLGCq7K9lPm9R517M1U+/90Qg==} engines: {node: '>=18'} - '@discordjs/ws@0.2.0': - resolution: {integrity: sha512-IYcxeWixOidlVwMIWh3xwac2n2V+8p47N4m6ZCjaHqJYHdVw/feK3zmsVYL7TEqpxrF1GHwoDp7DgI77yeEDFg==} - engines: {node: '>=16.9.0'} - '@discordjs/ws@1.2.3': resolution: {integrity: sha512-wPlQDxEmlDg5IxhJPuxXr3Vy9AjYq5xCvFWGJyD7w7Np8ZGu+Mc+97LCoEc/+AYCo2IDpKioiH0/c/mj5ZR9Uw==} engines: {node: '>=16.11.0'} + '@discordjs/ws@2.0.4': + resolution: {integrity: sha512-ARXnE+qi+D7Y4trd1bKA9uhiUxQvLbOKcdehDa6NLd7FiqmDvvk8N5RGk6Ho9gdT/Wap09dz/IuLv7hNpUzt6g==} + engines: {node: '>=20'} + + '@electric-sql/pglite-socket@0.1.1': + resolution: {integrity: sha512-p2hoXw3Z3LQHwTeikdZNsFBOvXGqKY2hk51BBw+8NKND8eoH+8LFOtW9Z8CQKmTJ2qqGYu82ipqiyFZOTTXNfw==} + hasBin: true + peerDependencies: + '@electric-sql/pglite': 0.4.1 + + '@electric-sql/pglite-tools@0.3.1': + resolution: {integrity: sha512-C+T3oivmy9bpQvSxVqXA1UDY8cB9Eb9vZHL9zxWwEUfDixbXv4G3r2LjoTdR33LD8aomR3O9ZXEO3XEwr/cUCA==} + peerDependencies: + '@electric-sql/pglite': 0.4.1 + + '@electric-sql/pglite@0.4.1': + resolution: {integrity: sha512-mZ9NzzUSYPOCnxHH1oAHPRzoMFJHY472raDKwXl/+6oPbpdJ7g8LsCN4FSaIIfkiCKHhb3iF/Zqo3NYxaIhU7Q==} + '@emnapi/core@1.11.0': resolution: {integrity: sha512-l9Oo58x0HOP5znGzVhYW9U3e5wVuA4LAZU2AGezTmkhO1CgQRFDhDg4nneHsu/t3WniXg9QrG2nIXL/ZS8ln8Q==} @@ -574,13 +551,15 @@ packages: cpu: [x64] os: [win32] - '@fastify/busboy@2.1.1': - resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} - engines: {node: '>=14'} - '@henrygd/queue@1.2.0': resolution: {integrity: sha512-jW/BLSTpcvExDhqJGxtIPgGr2O0IFF8XUNDwEbfCfhrXT8a4xztQ9Lv6U/vbYzYC0xVWn+3zv6YnLUh3bEFUKA==} + '@hono/node-server@1.19.11': + resolution: {integrity: sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g==} + engines: {node: '>=18.14.1'} + peerDependencies: + hono: ^4 + '@ioredis/commands@1.10.0': resolution: {integrity: sha512-UmeW7z4LfctwoQ5wkhVzgq8tXkreED2xZGpX+Bg+zA+WJFZCT6c062AfCK/Dfk81xZnnwdhJCUMkitihRaoC2Q==} @@ -597,12 +576,19 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@kurkle/color@0.3.4': + resolution: {integrity: sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==} + '@napi-rs/wasm-runtime@1.1.5': resolution: {integrity: sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==} peerDependencies: '@emnapi/core': ^1.7.1 '@emnapi/runtime': ^1.7.1 + '@opentelemetry/api-logs@0.214.0': + resolution: {integrity: sha512-40lSJeqYO8Uz2Yj7u94/SJWE/wONa7rmMKjI1ZcIjgf3MHNHv1OZUCrCETGuaRF62d5pQD1wKIW+L4lmSMTzZA==} + engines: {node: '>=8.0.0'} + '@opentelemetry/api-logs@0.53.0': resolution: {integrity: sha512-8HArjKx+RaAI8uEIgcORbZIPklyh1YLjPSBus8hjRmvLi6DeFzgOcdZ7KwPabKj8mXF8dX0hyfAyGfycz0DbFw==} engines: {node: '>=14'} @@ -631,6 +617,12 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' + '@opentelemetry/core@2.8.0': + resolution: {integrity: sha512-hd1Lfh8p545nNz+jq1Ejfz+Mn1hyLuxYn1YzTfFNrxr8urEWMNQLPf1Th8kjOH+HxwawCrtgBp8JpBUR4ZSgww==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + '@opentelemetry/instrumentation-amqplib@0.46.1': resolution: {integrity: sha512-AyXVnlCf/xV3K/rNumzKxZqsULyITJH6OVLiW6730JPRqWA7Zc9bvYoVNpN6iOpTU8CasH34SU/ksVJmObFibQ==} engines: {node: '>=14'} @@ -775,6 +767,12 @@ packages: peerDependencies: '@opentelemetry/api': ^1.7.0 + '@opentelemetry/instrumentation@0.214.0': + resolution: {integrity: sha512-MHqEX5Dk59cqVah5LiARMACku7jXSVk9iVDWOea4x3cr7VfdByeDCURK6o1lntT1JS/Tsovw01UJrBhN3/uC5w==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation@0.53.0': resolution: {integrity: sha512-DMwg0hy4wzf7K73JJtl95m/e0boSoWhH07rfvHvYzQtBD3Bmv0Wc1x733vyZBqmFm8OjJD0/pfiUg1W3JjFX0A==} engines: {node: '>=14'} @@ -803,12 +801,24 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' + '@opentelemetry/resources@2.8.0': + resolution: {integrity: sha512-qmXQ27ilDbUK/vGMqwL8D4/rhn76C+sherM4wTbjlfknR8Nvfc/hCxjRJPhkzZzUsPiNg16SA31NxMabwttRjg==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.3.0 <1.10.0' + '@opentelemetry/sdk-trace-base@1.30.1': resolution: {integrity: sha512-jVPgBbH1gCy2Lb7X0AVQ8XAfgg0pJ4nvl8/IiQA6nxOsPvS+0zMJaFSs2ltXe0J6C8dqjcnpyqINDJmU30+uOg==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' + '@opentelemetry/sdk-trace-base@2.8.0': + resolution: {integrity: sha512-mhU4jp+vW0mGbFRd+GeXHvmfA4aDqWjBjLC3pE5XMpLs0IE2ryYb019Ts2AQrOq67gaTF25D91+fgvEHDZEnuQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.3.0 <1.10.0' + '@opentelemetry/semantic-conventions@1.27.0': resolution: {integrity: sha512-sAay1RrB+ONOem0OZanAR1ZI/k7yDpnOQSQmTMuGImUQb2y8EbSaCJ94FQluM74xoU03vlb2d2U90hZluL6nQg==} engines: {node: '>=14'} @@ -830,124 +840,124 @@ packages: '@oxc-project/types@0.135.0': resolution: {integrity: sha512-wR+xRdFkUBMvcAjBJ2q2kcZM6d+DKu2NgoOyxZgYwZdLhmiv6+rnO8PZ/P68kMiZtIKm+pW7zyEJ4kSOs0vo+Q==} - '@oxfmt/binding-android-arm-eabi@0.51.0': - resolution: {integrity: sha512-Ni0sCqg5CIHaLIYFGj+ncbcumylvNC6FE4rfD0KfdmnWHbPJ+zev0qZCXKxy2hFVa0fYRK0yPzf5nzPbkZou7g==} + '@oxfmt/binding-android-arm-eabi@0.54.0': + resolution: {integrity: sha512-NAtpl/SiaeU103e7/OmZw0MvUnsUUopW7hEm/ecegJg7YM0skQaA0IXEZoyTV6NUdiNPupdIUreRqUZTShbn/g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [android] - '@oxfmt/binding-android-arm64@0.51.0': - resolution: {integrity: sha512-eu5lAZjuo0KAkp+M24EhDqfOwA8owQ8d7wyBlOUUGRbDLHpU3IRlDHp8Dif+YqGlxs6jra7yS6WQu/NkPhAxeg==} + '@oxfmt/binding-android-arm64@0.54.0': + resolution: {integrity: sha512-B4VZfBUlKK1rmMChsssNZbkZjE8+FzG3avMjGgMDwbGxXRoXkoeXiAZ+78Oa+eyDPHvDCiUb4zH/vmCOUSafLQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@oxfmt/binding-darwin-arm64@0.51.0': - resolution: {integrity: sha512-6LsUNIdURhhcIfIn8+xsOb61mSTa9msAHTeSGx9Jf4rsP/gN8PGCF+SKWPAQZbND2w/WBkqQ6303jqEEIXzMdQ==} + '@oxfmt/binding-darwin-arm64@0.54.0': + resolution: {integrity: sha512-i02vF75b+ePsQP3tHqSxVYI5S6b8X/xqdPu7/mDHXtpgXLTYXi3jJmfHU0j+dnZZDKaYTx/ioCK7QYJmtiJR2g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@oxfmt/binding-darwin-x64@0.51.0': - resolution: {integrity: sha512-9aUMGmVxdHjYMsEAW1tNRoieTJXlVNDFkRvIR1J7LttJXWjVYCu2ekclLij2KJtxBxSQOYSHd12ME/adVGVbZg==} + '@oxfmt/binding-darwin-x64@0.54.0': + resolution: {integrity: sha512-8VMFvGvooXj7mswkbrhdVZ2/sgiDaBzWpkkbtO+qGDLV4EfJd67nQadHkQC0ZNbaWA9ajXfqI6i7PZLIeDzxEQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@oxfmt/binding-freebsd-x64@0.51.0': - resolution: {integrity: sha512-mkY1nhZTqYb+NHaAWxOCKISN6FwdrwMNsu17vTUA3wzUV2VJ+Paq15ZokRcsMU/2PUdHO73prxyeJpjXQ3MPpQ==} + '@oxfmt/binding-freebsd-x64@0.54.0': + resolution: {integrity: sha512-0cRHnp43WN1Jrc5s0BdbdKgR1XirdvHy7TAFi3JEsoEVQVJxTXMbpVd76sxXlgRswNMDhVFSJw+y7Eb8mEavFQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@oxfmt/binding-linux-arm-gnueabihf@0.51.0': - resolution: {integrity: sha512-wtFwNwE4+YCNuPaWoGDZeGsKvD6D1YSUNBJNn/rJBh7CrDBThFE+TBI5kY7vRW9rIOQRsbW2IpyyL3Du4Zqwiw==} + '@oxfmt/binding-linux-arm-gnueabihf@0.54.0': + resolution: {integrity: sha512-JyQAk3hK/OEtup7Rw6kZwfdzbKqTVD5jXXb8Xpfay29suwZyfBDMVW/bj4RqEPySYWc6zCp198pOluf8n5uYzg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxfmt/binding-linux-arm-musleabihf@0.51.0': - resolution: {integrity: sha512-rnOaNx86G7iRKM6lsCIQMux0SMGNC/TEbFR+r7lpruJ12bnrIWgxd5w1PLqOvgR9r8ZJbpK/zfRKctJnh8/Jfg==} + '@oxfmt/binding-linux-arm-musleabihf@0.54.0': + resolution: {integrity: sha512-qnvLatTpM8vtvjOfcckBOzJjk+n6ce/wwpP8OFeUrD5aNLYcKyWAitwj+Rk3PK9jGanbZvKsJnv14JGQ6XqFdw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxfmt/binding-linux-arm64-gnu@0.51.0': - resolution: {integrity: sha512-jOgDzSqWcICGRjsp4mc08FxKMN8vzP2Kgs4E0d2HUP99F+nJDQKklRV4Zuj+0gcBgjrzx2CbpqaIdUVPepCojA==} + '@oxfmt/binding-linux-arm64-gnu@0.54.0': + resolution: {integrity: sha512-SMkhnCzIYZYDk9vw3W/80eeYKmrMpGF0Giuxt4HruFlCH7jEtnPeb3SdQKMfgYi/dgtaf+hZAb5XWPYnxqCQ3w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@oxfmt/binding-linux-arm64-musl@0.51.0': - resolution: {integrity: sha512-KBUCdrH5bwVrAvI9gU/1S55oH6fzXjr++J/oVocdu7bYTks1l7DNNT+rLd/1TDdAEjObGwmfWamn7LC1m8A0DQ==} + '@oxfmt/binding-linux-arm64-musl@0.54.0': + resolution: {integrity: sha512-QrwJlBFFKnxOd95TAaszpMbZBLzMoYMpGaQTZF8oibacnF5rv8l12IhILhQRPmksWiBqg0YSe2Mnl7ayeJAHSA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@oxfmt/binding-linux-ppc64-gnu@0.51.0': - resolution: {integrity: sha512-NapfjYsABFqTJ1Dn9Efq6sN5esaHconVKwVLbDGNQLrwpOx/g17mkwErHzU72PutL67nf3wNAkbq122H+zLxag==} + '@oxfmt/binding-linux-ppc64-gnu@0.54.0': + resolution: {integrity: sha512-WILatiol/TUHTlhod7R09+7Az/XlhKwmY1MHfLZNmewltPWNN/EwxP2rQSHahibZ/cB8gmckEBjBOByD+5bYsQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@oxfmt/binding-linux-riscv64-gnu@0.51.0': - resolution: {integrity: sha512-5dlDt1dUZCVi6elIhiK1PWg9wpTzTcIuj0IZnSurvIoMrhOWqqTcc1dSTxcSkNaBZhfsNqRZdINI1zAgbKkJNQ==} + '@oxfmt/binding-linux-riscv64-gnu@0.54.0': + resolution: {integrity: sha512-f05YMG4BH4G8S4ME6UM6fi1MnJ9094mrnvO5Pa4SJlMfWlUM+1/ZWMEF4NnjM7shZAvbHsHRuVYpUo0PHC4P9Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [glibc] - '@oxfmt/binding-linux-riscv64-musl@0.51.0': - resolution: {integrity: sha512-pgdWUJn0S5nulyiVdlFV8DzCUnGXkU99W5PSkkmbaZW+LrZBPxpezun4G0DDHbQaVYuJeCuKsXsGKGo77CkUTQ==} + '@oxfmt/binding-linux-riscv64-musl@0.54.0': + resolution: {integrity: sha512-UfL+2hj1ClNqcCRT9s8vBU4axDpjxgVxX96G+9DYAYjoc5b0u15CJtn2jgsi9iM+EbGNc5CW1HVRgwVu76UsSA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] libc: [musl] - '@oxfmt/binding-linux-s390x-gnu@0.51.0': - resolution: {integrity: sha512-2XTFUe97CbDGAI8vjwDfZ1HdakO0XIADyJ24idEg64SC4/K4in/OisXVnrW4NMK7I6TgC7EqRhC0Ln/nKhAemA==} + '@oxfmt/binding-linux-s390x-gnu@0.54.0': + resolution: {integrity: sha512-3/XZe931Hka+J6NjnaqJzYpsWWxDTuRdUdwSQHnOuJEgbC+SehIMFJS8hsEjV7LBhVSL2OCnRLvbVW8O97XIyw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@oxfmt/binding-linux-x64-gnu@0.51.0': - resolution: {integrity: sha512-kQ1OuCqqt/yyf0ZN9VFxW1/JnlgJgii3Dr7pWf9vNBvrX1hv6g39/+mc5oGRHRGJFZtl3zsGDWR9c5N2B/gwBw==} + '@oxfmt/binding-linux-x64-gnu@0.54.0': + resolution: {integrity: sha512-Ik93RlObtu43GbxApafayFjwYE06L6Xr08cSwpBPYbDrLp2ReZx0Jm1DqwRyYRnukUJy+rK2WaEvUQOxdytU9Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@oxfmt/binding-linux-x64-musl@0.51.0': - resolution: {integrity: sha512-ARTYqxHF475o96Gbn41hvSWSSRygPlRDXZZgZ9I2scU1y0qiWpCQyZCoefaQa0mwv+wwtZ+luS4YOzsRzM/izg==} + '@oxfmt/binding-linux-x64-musl@0.54.0': + resolution: {integrity: sha512-yZcakmPlD86CNymknd7KfW+FH+qfbqJH+i0h69CYfV1+KMoVeM9UED+8+TDVoU4haxI0NxY7RPCvRLy3Sqd2Qg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@oxfmt/binding-openharmony-arm64@0.51.0': - resolution: {integrity: sha512-QiC1XrCl6a6BmqMzduO8hdIRMf1m44hCkt2Q68KWkTvUB/E7fd2iomyNh6KnnRca5w6eBrRAAtLFqTh+xjsjJA==} + '@oxfmt/binding-openharmony-arm64@0.54.0': + resolution: {integrity: sha512-GiVBZNnEZnKu00f1jTg49nomv187d0GQX+O+ocykoLeiaALuEO+swoTehHn9TehTfi7V8H0i0e/yvUjCqnwk1w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@oxfmt/binding-win32-arm64-msvc@0.51.0': - resolution: {integrity: sha512-NC/hJb9dtU23Zf8L7IVK95xnFjiQ7AfcLO2l5pb69TDEr958qxrtnB2CveeeNSCBFNIkgaTCfd/vHNSoG78l9g==} + '@oxfmt/binding-win32-arm64-msvc@0.54.0': + resolution: {integrity: sha512-J0SSB8Z1Fre2sxRolYcW6Rl1RQmKdQ2hnHyq4YJrfBRiXTObLw4DXnIVraM/UyqGqwOi7yTrQA4VT7DPxlHVKA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@oxfmt/binding-win32-ia32-msvc@0.51.0': - resolution: {integrity: sha512-2C45za4Rj36n8YIbhRL1PQbxmXJYf81WEcAgvj5I4ptRROG+A+81hREEN5bmCHADE1UfYaN312U6tkILoZZy6w==} + '@oxfmt/binding-win32-ia32-msvc@0.54.0': + resolution: {integrity: sha512-O61UDVj8zz6yXJjkHPf05VaMLOXmEF8P5kf/N0W7AQMmd6bcQogl+KJc7rMutKTL524oE9iH32JXZClBFmEQIg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ia32] os: [win32] - '@oxfmt/binding-win32-x64-msvc@0.51.0': - resolution: {integrity: sha512-73RqdAuVKQTkjZIDw08JaDHUM4lav5Qu+CaPwg4QbbA7k8o7LEW0p3UsfZ/F8dsO/pwVYh3RzFcanwLRTTahbQ==} + '@oxfmt/binding-win32-x64-msvc@0.54.0': + resolution: {integrity: sha512-1MDpqJPiFqxWtIHas8vkb1VZ7f7eKyTffAwmO8isxQYMaG1OFKsH666BWLeXQLO+IWNfiMssLD55hbR1lIPTqg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] @@ -1074,27 +1084,143 @@ packages: cpu: [x64] os: [win32] - '@prisma/client@4.16.2': - resolution: {integrity: sha512-qCoEyxv1ZrQ4bKy39GnylE8Zq31IRmm8bNhNbZx7bF2cU5aiCCnSa93J2imF88MBjn7J9eUQneNxUQVJdl/rPQ==} - engines: {node: '>=14.17'} + '@prisma/client-runtime-utils@7.8.0': + resolution: {integrity: sha512-5NQZztQ0oY/ADFkmd9gPuweH5A1/CCY8YQPorLLO0Mu6a87mY5gsnDkzmFmIHs9NFaLnZojzgddFVN4RpKYrdw==} + + '@prisma/client@7.8.0': + resolution: {integrity: sha512-HFp3Dawv/3sU3JtlPha90IB+48lS7zHiH4LKZPjmcE8YH5P9DOXGPvo8dqOtO7MqLDd1p2hOWMcFlRT1DMblHw==} + engines: {node: ^20.19 || ^22.12 || >=24.0} peerDependencies: prisma: '*' + typescript: '>=5.4.0' peerDependenciesMeta: prisma: optional: true + typescript: + optional: true + + '@prisma/config@7.8.0': + resolution: {integrity: sha512-HFESzd9rx2ZQxlK+TL7tu1HPvCqrHiL6LCxYykI2c34mvaUuIVVl3lYuicJD/MNnzgPnyeBEMlK4WTomJCV5jw==} + + '@prisma/debug@7.2.0': + resolution: {integrity: sha512-YSGTiSlBAVJPzX4ONZmMotL+ozJwQjRmZweQNIq/ER0tQJKJynNkRB3kyvt37eOfsbMCXk3gnLF6J9OJ4QWftw==} + + '@prisma/debug@7.8.0': + resolution: {integrity: sha512-p+QZReysDUqXC+mk17q9a+Y/qzh4c2KYliDK30buYUyfrGeTGSyfmc0AIrJRhZJrLHhRiJa9Au/J72h3C+szvA==} + + '@prisma/dev@0.24.3': + resolution: {integrity: sha512-ffHlQuKXZiaDt9Go0OnCTdJZrHxK0k7omJKNV86/VjpsXu5EIHZLK0T7JSWgvNlJwh56kW9JFu9v0qJciFzepg==} + + '@prisma/engines-version@7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a': + resolution: {integrity: sha512-fJPQxCkLgA5EayWaW8eArgCvjJ+N+Kz3VyeNKMEeYiQC4alNkxRKFVAGxv/ZUzuJISKqdw+zGeDbS6mn6RCPOA==} + + '@prisma/engines@7.8.0': + resolution: {integrity: sha512-jx3rCnNNrt5uzbkKlegtQ2GZHxSlihMCzutgT/BP6UIDF1r9tDI39hV/0T/cHZgzJ3ELbuQPXlVZy+Y1n0pcgw==} - '@prisma/engines-version@4.16.1-1.4bc8b6e1b66cb932731fb1bdbbc550d1e010de81': - resolution: {integrity: sha512-q617EUWfRIDTriWADZ4YiWRZXCa/WuhNgLTVd+HqWLffjMSPzyM5uOWoauX91wvQClSKZU4pzI4JJLQ9Kl62Qg==} + '@prisma/fetch-engine@7.8.0': + resolution: {integrity: sha512-gwB0Euiz/DDRyxFRpLXYlK3RfaZUj1c5dAYMuhZYfApg7arknJlcb9bIsOHDppJmbqYaVA+yBIiFMDBfprsNPQ==} - '@prisma/engines@4.16.2': - resolution: {integrity: sha512-vx1nxVvN4QeT/cepQce68deh/Turxy5Mr+4L4zClFuK1GlxN3+ivxfuv+ej/gvidWn1cE1uAhW7ALLNlYbRUAw==} + '@prisma/get-platform@7.2.0': + resolution: {integrity: sha512-k1V0l0Td1732EHpAfi2eySTezyllok9dXb6UQanajkJQzPUGi3vO2z7jdkz67SypFTdmbnyGYxvEvYZdZsMAVA==} + + '@prisma/get-platform@7.8.0': + resolution: {integrity: sha512-WlxgRGnolL8VH2EmkH1R/DkKNr/mVdS3G2h42IZFFZ3eUrH9OT6t73kIOSlkkrv50wG123Iq8d96ufv5LlZktw==} '@prisma/instrumentation@5.22.0': resolution: {integrity: sha512-LxccF392NN37ISGxIurUljZSh1YWnphO34V5a0+T7FVQG2u9bhAXRTJpgmQ3483woVhkraQZFF7cbRrpbw/F4Q==} + '@prisma/query-plan-executor@7.2.0': + resolution: {integrity: sha512-EOZmNzcV8uJ0mae3DhTsiHgoNCuu1J9mULQpGCh62zN3PxPTd+qI9tJvk5jOst8WHKQNwJWR3b39t0XvfBB0WQ==} + + '@prisma/streams-local@0.1.2': + resolution: {integrity: sha512-l49yTxKKF2odFxaAXTmwmkBKL3+bVQ1tFOooGifu4xkdb9NMNLxHj27XAhTylWZod8I+ISGM5erU1xcl/oBCtg==} + engines: {bun: '>=1.3.6', node: '>=22.0.0'} + + '@prisma/studio-core@0.27.3': + resolution: {integrity: sha512-AADjNFPdsrglxHQVTmHFqv6DuKQZ5WY4p5/gVFY017twvNrSwpLJ9lqUbYYxEu2W7nbvVxTZA8deJ8LseNALsw==} + engines: {node: ^20.19 || ^22.12 || >=24.0, pnpm: '8'} + peerDependencies: + '@types/react': ^18.0.0 || ^19.0.0 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + '@quansync/fs@1.0.0': resolution: {integrity: sha512-4TJ3DFtlf1L5LDMaM6CanJ/0lckGNtJcMjQ1NAV6zDmA0tEHKZtxNKin8EgPaVX1YzljbxckyT2tJrpQKAtngQ==} + '@radix-ui/primitive@1.1.3': + resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==} + + '@radix-ui/react-compose-refs@1.1.2': + resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-primitive@2.1.3': + resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-slot@1.2.3': + resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-toggle@1.1.10': + resolution: {integrity: sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-use-controllable-state@1.2.2': + resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-effect-event@0.0.2': + resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-layout-effect@1.1.1': + resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@rolldown/binding-android-arm64@1.1.1': resolution: {integrity: sha512-BLf9Wak/gfwVb7NQTQW4wBgL3oAfPy7ArEkhwV543OVw/uY6B47z5xYsqPSZ9PDOorvURPinws6ThaFuNgGLgA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1372,10 +1498,6 @@ packages: resolution: {integrity: sha512-2v49P++RzHGb23bdjSa9u7flkdvhrq94IUO9PneY538TILN5QiMxfaXVK+pDR2YR7jpQYBy9APwtFDes2Svykg==} engines: {node: '>=v14.0.0', npm: '>=7.0.0'} - '@sapphire/prettier-config@2.0.0': - resolution: {integrity: sha512-Vie8KR5zQ6sbEP4+biW/IR7k55saGfZkTSuRlgvxCBKb4SBJdRWcOBI80i+JxMVIDDZKgXlgYnXEST+FgZiWXA==} - engines: {node: '>=v14.0.0', npm: '>=7.0.0'} - '@sapphire/ratelimits@2.4.11': resolution: {integrity: sha512-O6FNA/P0wxU4Ve9gxL948CoZw7+sSpujyUR2CLyLLCNuNvuFGFxPCJVl5crFVLXMIyBIrc2qk+/H9bsqsyQK1Q==} engines: {node: '>=v14.0.0', npm: '>=7.0.0'} @@ -1408,38 +1530,59 @@ packages: resolution: {integrity: sha512-QGLdC9+pT74Zd7aaObqn0EUfq40c4dyTL65pFnkM6WO1QYN7Yg/s4CdH+CXmx0Zcu6wcfCWILSftXPMosJHP5A==} engines: {node: '>=v14.0.0'} - '@sentry-internal/tracing@7.120.4': - resolution: {integrity: sha512-Fz5+4XCg3akeoFK+K7g+d7HqGMjmnLoY2eJlpONJmaeT9pXY7yfUyXKZMmMajdE2LxxKJgQ2YKvSCaGVamTjHw==} - engines: {node: '>=8'} - - '@sentry/core@7.114.0': - resolution: {integrity: sha512-YnanVlmulkjgZiVZ9BfY9k6I082n+C+LbZo52MTvx3FY6RE5iyiPMpaOh67oXEZRWcYQEGm+bKruRxLVP6RlbA==} - engines: {node: '>=8'} + '@sentry-internal/server-utils@10.57.0': + resolution: {integrity: sha512-Qu8ETmX/ITzteG7Im46b9HOxKKzeaIeqNvftaIlFURu1RUQdHbtGerS7QOmXzwnhuqNGNeiCQYkduB798IfRqA==} + engines: {node: '>=18'} - '@sentry/core@7.120.4': - resolution: {integrity: sha512-TXu3Q5kKiq8db9OXGkWyXUbIxMMuttB5vJ031yolOl5T/B69JRyAoKuojLBjRv1XX583gS1rSSoX8YXX7ATFGA==} - engines: {node: '>=8'} + '@sentry/core@10.57.0': + resolution: {integrity: sha512-kntItTA2kiT0YpL7encXaF6mkdZMB+y48lwj8w1wkfBpfJAC7sifdgrzLQZqmsqVNE3crg9VfufaAGA+78uFMg==} + engines: {node: '>=18'} '@sentry/core@8.55.2': resolution: {integrity: sha512-YlEBwybUcOQ/KjMHDmof1vwweVnBtBxYlQp7DE3fOdtW4pqqdHWTnTntQs4VgYfxzjJYgtkd9LHlGtg8qy+JVQ==} engines: {node: '>=14.18'} - '@sentry/integrations@7.114.0': - resolution: {integrity: sha512-BJIBWXGKeIH0ifd7goxOS29fBA8BkEgVVCahs6xIOXBjX1IRS6PmX0zYx/GP23nQTfhJiubv2XPzoYOlZZmDxg==} - engines: {node: '>=8'} - - '@sentry/integrations@7.120.4': - resolution: {integrity: sha512-kkBTLk053XlhDCg7OkBQTIMF4puqFibeRO3E3YiVc4PGLnocXMaVpOSCkMqAc1k1kZ09UgGi8DxfQhnFEjUkpA==} - engines: {node: '>=8'} + '@sentry/node-core@10.57.0': + resolution: {integrity: sha512-2v2IF6MfTiu7pimWEq2rYhZsmlwyNbs3bHUsrYFPeP/Rpa6ObDuUWPdVEzJjfyK+AqqYZYxZdV0l3+B13kTEmQ==} + engines: {node: '>=18'} + peerDependencies: + '@opentelemetry/api': ^1.9.0 + '@opentelemetry/core': ^1.30.1 || ^2.1.0 + '@opentelemetry/exporter-trace-otlp-http': '>=0.57.0 <1' + '@opentelemetry/instrumentation': '>=0.57.1 <1' + '@opentelemetry/sdk-trace-base': ^1.30.1 || ^2.1.0 + '@opentelemetry/semantic-conventions': ^1.39.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + '@opentelemetry/core': + optional: true + '@opentelemetry/exporter-trace-otlp-http': + optional: true + '@opentelemetry/instrumentation': + optional: true + '@opentelemetry/sdk-trace-base': + optional: true + '@opentelemetry/semantic-conventions': + optional: true - '@sentry/node@7.120.4': - resolution: {integrity: sha512-qq3wZAXXj2SRWhqErnGCSJKUhPSlZ+RGnCZjhfjHpP49KNpcd9YdPTIUsFMgeyjdh6Ew6aVCv23g1hTP0CHpYw==} - engines: {node: '>=8'} + '@sentry/node@10.57.0': + resolution: {integrity: sha512-7KEStrJ97wPf1fA5nU5ONeTTcIIlh7oT8OMffEVA1PXmlhFoXhcQZVzr4rM+zj9tfMWT01og5Ng/Grgh3dN+FA==} + engines: {node: '>=18'} '@sentry/node@8.55.2': resolution: {integrity: sha512-x3Whryb4TytiIhH9ABLVuASfBvwA50v6PpJYvq0Y9dUMi9Eb0cfuqvRCB3e+oVntZHQpnXor2U/gRBIdG2jp4w==} engines: {node: '>=14.18'} + '@sentry/opentelemetry@10.57.0': + resolution: {integrity: sha512-iwRz8cEK0GOISG34aJRO8GdYOk3nfpuT6dT2GDQrxw8f7JjkJKx9LPU8MaenOFa4MhY+Z02hI6NNcrbsoI3cXg==} + engines: {node: '>=18'} + peerDependencies: + '@opentelemetry/api': ^1.9.0 + '@opentelemetry/core': ^1.30.1 || ^2.1.0 + '@opentelemetry/sdk-trace-base': ^1.30.1 || ^2.1.0 + '@opentelemetry/semantic-conventions': ^1.39.0 + '@sentry/opentelemetry@8.55.2': resolution: {integrity: sha512-pbhXi4cS1W4l392yEfIx3UD28OYAl9JkYOmh/Cpm6cPTtRMPxi3hWeujGbcXV9T/RkWYjqd+JdUDJjqsWSww9A==} engines: {node: '>=14.18'} @@ -1451,22 +1594,6 @@ packages: '@opentelemetry/sdk-trace-base': ^1.30.1 '@opentelemetry/semantic-conventions': ^1.28.0 - '@sentry/types@7.114.0': - resolution: {integrity: sha512-tsqkkyL3eJtptmPtT0m9W/bPLkU7ILY7nvwpi1hahA5jrM7ppoU0IMaQWAgTD+U3rzFH40IdXNBFb8Gnqcva4w==} - engines: {node: '>=8'} - - '@sentry/types@7.120.4': - resolution: {integrity: sha512-cUq2hSSe6/qrU6oZsEP4InMI5VVdD86aypE+ENrQ6eZEVLTCYm1w6XhW1NvIu3UuWh7gZec4a9J7AFpYxki88Q==} - engines: {node: '>=8'} - - '@sentry/utils@7.114.0': - resolution: {integrity: sha512-319N90McVpupQ6vws4+tfCy/03AdtsU0MurIE4+W5cubHME08HtiEWlfacvAxX+yuKFhvdsO4K4BB/dj54ideg==} - engines: {node: '>=8'} - - '@sentry/utils@7.120.4': - resolution: {integrity: sha512-zCKpyDIWKHwtervNK2ZlaK8mMV7gVUijAgFeJStH+CU/imcdquizV3pFLlSQYRswG+Lbyd6CT/LGRh3IbtkCFw==} - engines: {node: '>=8'} - '@simple-libs/child-process-utils@1.0.2': resolution: {integrity: sha512-/4R8QKnd/8agJynkNdJmNw2MBxuFTRcNFnE5Sg/G+jkSsV8/UBgULMzhizWWW42p8L5H7flImV2ATi79Ove2Tw==} engines: {node: '>=18'} @@ -1486,9 +1613,6 @@ packages: '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} - '@tokenizer/token@0.3.0': - resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} - '@tybys/wasm-util@0.10.2': resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} @@ -1516,12 +1640,18 @@ packages: '@types/node@22.19.21': resolution: {integrity: sha512-VMeFBSCKQKmm2swI2kW51SFusDqekC6q9trBCvJ/JliDchFSuoYYKN7yVNjPthP1HKZcx3U1gI/wTcEBjEFKTA==} + '@types/node@24.13.2': + resolution: {integrity: sha512-fRa09kZTgu8o71KFcDjUFuc7F+dEbZYZmkI0mg5YBTRs0yMKjYHsq/c0urDKeDb+D5qVgXOdFcuu+DZPKOITwA==} + '@types/pg-pool@2.0.6': resolution: {integrity: sha512-TaAUE5rq2VQYxab5Ts7WZhKNmuN78Q6PiFonTDdpbx8a1H0M1vhy3rhiMjl+e2iHmogyMw7jZF4FrE6eJUy5HQ==} '@types/pg@8.6.1': resolution: {integrity: sha512-1Kc4oAGzAl7uqUStZCDvaLFqZrW9qWSjXOmBfdgyBP5La7Us6Mg4GBvRlSoaZMhQF/zSj1C8CtKMBkoiT8eL8w==} + '@types/react@19.2.17': + resolution: {integrity: sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==} + '@types/shimmer@1.2.0': resolution: {integrity: sha512-UE7oxhQLLd9gub6JKIAhDq06T0F6FnztwMNRvYgjeQSBeMc1ZG/tA47EwfduvkuQS8apbkM/lpLpWsaCeYsXVg==} @@ -1600,10 +1730,6 @@ packages: resolution: {integrity: sha512-Q1mRxbRMrHoVn6EOuxT4AzoR9fmknt7XkgqeF7yGVvcBxwaQmm5J6e63f+++JMbjsttfXcrRLqRVWHQ+WhvDLQ==} engines: {node: '>=18'} - abort-controller@3.0.0: - resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} - engines: {node: '>=6.5'} - acorn-import-attributes@1.9.5: resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} peerDependencies: @@ -1621,10 +1747,6 @@ packages: resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} engines: {node: '>=8'} - ansi-escapes@7.3.0: - resolution: {integrity: sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==} - engines: {node: '>=18'} - ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -1666,12 +1788,19 @@ packages: resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} engines: {node: '>= 4.0.0'} + aws-ssl-profiles@1.1.2: + resolution: {integrity: sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==} + engines: {node: '>= 6.0.0'} + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + better-result@2.9.2: + resolution: {integrity: sha512-WIFoBPCdnTOdk9inkE1ZRvCZ4P0CpSkAiLlchC65N7n9DcjZ3NhqkBOlafzpOVnO8ixyi37kicmSJ3ENhPZl7Q==} + birpc@4.0.0: resolution: {integrity: sha512-LShSxJP0KTmd101b6DRyGBj57LZxSDYWKitQNW/mi8GRMvZb078Uf9+pveax1DrVL89vm7mWe+TovdI/UDOuPw==} @@ -1688,8 +1817,13 @@ packages: buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} - buffer@6.0.3: - resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + c12@3.3.4: + resolution: {integrity: sha512-cM0ApFQSBXuourJejzwv/AuPRvAxordTyParRVcHjjtXirtkzM0uK2L9TTn9s0cXZbG7E55jCivRQzoxYmRAlA==} + peerDependencies: + magicast: '*' + peerDependenciesMeta: + magicast: + optional: true cac@7.0.0: resolution: {integrity: sha512-tixWYgm5ZoOD+3g6UTea91eow5z6AAHaho3g0V9CNSNb45gM8SmflpAc+GRd1InC4AqN/07Unrgp56Y94N9hJQ==} @@ -1718,32 +1852,35 @@ packages: chardet@0.7.0: resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} + chart.js@4.5.1: + resolution: {integrity: sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw==} + engines: {pnpm: '>=8'} + + chokidar@5.0.0: + resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} + engines: {node: '>= 20.19.0'} + cjs-module-lexer@1.4.3: resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==} + cjs-module-lexer@2.2.0: + resolution: {integrity: sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==} + cli-cursor@3.1.0: resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} engines: {node: '>=8'} - cli-cursor@5.0.0: - resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} - engines: {node: '>=18'} - cli-spinners@2.9.2: resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} engines: {node: '>=6'} - cli-truncate@5.2.0: - resolution: {integrity: sha512-xRwvIOMGrfOAnM1JYtqQImuaNtDEv9v6oIYAs4LIHwTiKee8uwvIi363igssOC0O5U04i4AlENs79LQLu9tEMw==} - engines: {node: '>=20'} - cli-width@3.0.0: resolution: {integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==} engines: {node: '>= 10'} - cliui@8.0.1: - resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} - engines: {node: '>=12'} + cliui@9.0.1: + resolution: {integrity: sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==} + engines: {node: '>=20'} clone@1.0.4: resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} @@ -1769,10 +1906,6 @@ packages: colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} - commander@14.0.3: - resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==} - engines: {node: '>=20'} - commitizen@4.3.1: resolution: {integrity: sha512-gwAPAVTy/j5YcOOebcCRIijn+mSjWJC+IYKivTu6aG8Ei/scoXgfsMRnuAk6b0GRste2J4NGxVdMN3ZpfNaVaw==} engines: {node: '>= 12'} @@ -1784,6 +1917,9 @@ packages: concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + confbox@0.2.4: + resolution: {integrity: sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==} + conventional-changelog-angular@8.3.1: resolution: {integrity: sha512-6gfI3otXK5Ph5DfCOI1dblr+kN3FAm5a97hYoQkqNZxOaYa5WKfXH+AnpsmS+iUH2mgVC2Cg2Qw9m5OKcmNrIg==} engines: {node: '>=18'} @@ -1820,6 +1956,13 @@ packages: typescript: optional: true + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + cz-conventional-changelog@3.3.0: resolution: {integrity: sha512-U466fIzU5U22eES5lTNiNbZ+d8dfcHcssH4o7QsdWaCcRs/feIPCxKYSWkYBNs5mny7MvEfwpTLWjvbm94hecw==} engines: {node: '>= 10'} @@ -1836,6 +1979,10 @@ packages: dedent@0.7.0: resolution: {integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==} + deepmerge-ts@7.1.5: + resolution: {integrity: sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==} + engines: {node: '>=16.0.0'} + defaults@1.0.4: resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} @@ -1889,12 +2036,19 @@ packages: oxc-resolver: optional: true + effect@3.20.0: + resolution: {integrity: sha512-qMLfDJscrNG8p/aw+IkT9W7fgj50Z4wG5bLBy0Txsxz8iUHjDIkOgO3SV0WZfnQbNG2VJYb0b+rDLMrhM4+Krw==} + emoji-regex@10.6.0: resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + empathic@2.0.0: + resolution: {integrity: sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==} + engines: {node: '>=14'} + empathic@2.0.1: resolution: {integrity: sha512-YGRs8knHhKHVShLkFET/rWAU8kmHbOV5LwN938RHI0pljAJ1Gf6SzXsSmRaEzcXTtOOmVqJ5+WtQPL5uigY50Q==} engines: {node: '>=14'} @@ -1903,9 +2057,9 @@ packages: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} - environment@1.1.0: - resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} - engines: {node: '>=18'} + env-paths@3.0.0: + resolution: {integrity: sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} error-ex@1.3.4: resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} @@ -1917,8 +2071,8 @@ packages: es-module-lexer@2.1.0: resolution: {integrity: sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==} - es-toolkit@1.47.0: - resolution: {integrity: sha512-n1GuoD0WEQZMBk5tttoZSqwgyLx01oqa5XsBmCHwPyNe1S9jPBEmtR2pSgp2kJuWE3ciFZ6yRHmY4pM4C3OOkw==} + es-toolkit@1.47.1: + resolution: {integrity: sha512-5RAqEwf4P4E17p+W75KLOWw/nOvKZzSQpxM32IpI2KZLaVonjTrZ0Ai5ghMaVI9eKC2p8eoQgcBdkEDgzFk6+Q==} esbuild@0.25.12: resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} @@ -1936,17 +2090,6 @@ packages: estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} - event-target-shim@5.0.1: - resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} - engines: {node: '>=6'} - - eventemitter3@5.0.4: - resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} - - events@3.3.0: - resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} - engines: {node: '>=0.8.x'} - expand-tilde@2.0.2: resolution: {integrity: sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==} engines: {node: '>=0.10.0'} @@ -1955,10 +2098,17 @@ packages: resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} + exsolve@1.0.8: + resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} + external-editor@3.1.0: resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} engines: {node: '>=4'} + fast-check@3.23.2: + resolution: {integrity: sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==} + engines: {node: '>=8.0.0'} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -1978,10 +2128,6 @@ packages: resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} engines: {node: '>=8'} - file-type@18.7.0: - resolution: {integrity: sha512-ihHtXRzXEziMrQ56VSgU7wkxh55iNchFkosu7Y9/S+tXHdKyrGjVK0ujbqNnsxzea+78MaLhN6PGmfYSAv1ACw==} - engines: {node: '>=14.16'} - fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} @@ -1996,6 +2142,10 @@ packages: resolution: {integrity: sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==} engines: {node: '>= 8'} + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + forwarded-parse@2.1.2: resolution: {integrity: sha512-alTFZZQDKMporBH77856pXgzhEzaUVmLCDk+egLgIgHst3Tpndzz8MnKe+GzRJRfvVdn69HhpW7cmXzvtLvJAw==} @@ -2017,6 +2167,9 @@ packages: fzf@0.5.2: resolution: {integrity: sha512-Tt4kuxLXFKHy8KT40zwsUPUkg1CrsgY25FxA2U/j/0WgEDCk3ddc/zLTCCcbSHX9FcKtLuVaDGtGE/STWC+j3Q==} + generate-function@2.3.1: + resolution: {integrity: sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==} + get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} @@ -2025,10 +2178,17 @@ packages: resolution: {integrity: sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==} engines: {node: '>=18'} + get-port-please@3.2.0: + resolution: {integrity: sha512-I9QVvBw5U/hw3RmWpYKRumUeaDgxTPd401x364rLmWBJcOQ753eov1eTgzDqRG9bqFIfDc7gfzcQEWrUri3o1A==} + get-tsconfig@5.0.0-beta.5: resolution: {integrity: sha512-/6gFNr0N04nob252sTQxyFLi3eKFRqIg1I87YcqAMT1i6SQrSF6KujUEQrtrjMV0H/eejTCltLdDSTEMzHbnsQ==} engines: {node: '>=20.20.0'} + giget@3.3.0: + resolution: {integrity: sha512-gzi2D96p+AMfDcmJHGDj3KJ9NRiwvlFAU5yfa3ROwWZmFUjX4P43x3BcyRaOMMLto1vUo7C+86+MFhYTl6Ryiw==} + hasBin: true + git-raw-commits@5.0.1: resolution: {integrity: sha512-Y+csSm2GD/PCSh6Isd/WiMjNAydu0VBiG9J7EdQsNA5P9uXvLayqjmTsNlK5Gs9IhblFZqOU0yid5Il5JPoLiQ==} engines: {node: '>=18'} @@ -2057,6 +2217,12 @@ packages: resolution: {integrity: sha512-rEDCuqUQ4tbD78TpzsMtt5OIf0cBCSDWSJtUDaF6JsAh+k0v9r++NzxNEG87oDZx9ZwGhD8DaezR2L/yrw0Jdw==} engines: {node: '>=10'} + grammex@3.1.12: + resolution: {integrity: sha512-6ufJOsSA7LcQehIJNCO7HIBykfM7DXQual0Ny780/DEcJIpBlHRvcqEBWGPYd7hrXL2GJ3oJI1MIhaXjWmLQOQ==} + + graphmatch@1.1.1: + resolution: {integrity: sha512-5ykVn/EXM1hF0XCaWh05VbYvEiOL2lY1kBxZtaYsyvjp7cmWOU1XsAdfQBwClraEofXDT197lFbXOEVMHpvQOg==} + has-flag@3.0.0: resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} engines: {node: '>=4'} @@ -2073,12 +2239,19 @@ packages: resolution: {integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==} engines: {node: '>=0.10.0'} + hono@4.12.25: + resolution: {integrity: sha512-2NFaIyNVgJmBs/ecmtGzlmluTFs5cHEWGTdu0t1HBwYzoGXOL5nUQBRMXsXWla5i4KkG//QMzVP88m1+I3fdAQ==} + engines: {node: '>=16.9.0'} + hookable@6.1.1: resolution: {integrity: sha512-U9LYDy1CwhMCnprUfeAZWZGByVbhd54hwepegYTK7Pi5NvqEj63ifz5z+xukznehT7i6NIZRu89Ay1AZmRsLEQ==} html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + http-status-codes@2.3.0: + resolution: {integrity: sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA==} + husky@9.1.7: resolution: {integrity: sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==} engines: {node: '>=18'} @@ -2091,12 +2264,13 @@ packages: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} + iconv-lite@0.7.2: + resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} + engines: {node: '>=0.10.0'} + ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - immediate@3.0.6: - resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} - import-fresh@3.3.1: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} @@ -2104,8 +2278,9 @@ packages: import-in-the-middle@1.15.0: resolution: {integrity: sha512-bpQy+CrsRmYmoPMAE/0G33iwRqwW4ouqdRg8jgbH3aKuCtOc8lxgmYXg2dMM92CRiGP660EtBcymH/eVUpCSaA==} - import-meta-resolve@4.2.0: - resolution: {integrity: sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==} + import-in-the-middle@3.0.2: + resolution: {integrity: sha512-LGLYRl0A2gtyUJb2WDliBHmk6TtlHwdDjxonacZ8QrEs/ZW+YDgNv2QAfjRQWpS8HqvNcq6GGnN6jrOa5FysDQ==} + engines: {node: '>=18'} import-without-cache@0.4.0: resolution: {integrity: sha512-NkJQA7oZ4YHQhd2+H3BoRFKF3d/XNsiKpHZCQEMH9pDX27hQQLsTyOocyRgaIVtf8gHX3Nt3LPkR4e5EdtPAGQ==} @@ -2148,10 +2323,6 @@ packages: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} - is-fullwidth-code-point@5.1.0: - resolution: {integrity: sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==} - engines: {node: '>=18'} - is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} @@ -2172,6 +2343,9 @@ packages: resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} engines: {node: '>=12'} + is-property@1.0.2: + resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==} + is-unicode-supported@0.1.0: resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} engines: {node: '>=10'} @@ -2205,6 +2379,10 @@ packages: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true + jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} + hasBin: true + js-tokens@10.0.0: resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==} @@ -2229,24 +2407,9 @@ packages: jsonfile@6.2.1: resolution: {integrity: sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==} - lie@3.1.1: - resolution: {integrity: sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==} - lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - lint-staged@16.4.0: - resolution: {integrity: sha512-lBWt8hujh/Cjysw5GYVmZpFHXDCgZzhrOm8vbcUdobADZNOK/bRshr2kM3DfgrrtR1DQhfupW9gnIXOfiFi+bw==} - engines: {node: '>=20.17'} - hasBin: true - - listr2@9.0.5: - resolution: {integrity: sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==} - engines: {node: '>=20.0.0'} - - localforage@1.10.0: - resolution: {integrity: sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==} - lodash.map@4.6.0: resolution: {integrity: sha512-worNHGKLDetmcEYDvh2stPCrrQRkP20E4l0iIS7F8EvzMqBBi7ltvFN5m1HvTf1P7Jk1txKhvFcmYsCr8O2F1Q==} @@ -2263,14 +2426,17 @@ packages: resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} engines: {node: '>=10'} - log-update@6.1.0: - resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} - engines: {node: '>=18'} + long@5.3.2: + resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} longest@2.0.1: resolution: {integrity: sha512-Ajzxb8CM6WAnFjgiloPsI3bF+WCxcvhdIG3KNA2KN962+tdBsHcuQ4k4qX/EcS/2CRkcc0iAkR956Nib6aXU/Q==} engines: {node: '>=0.10.0'} + lru.min@1.1.4: + resolution: {integrity: sha512-DqC6n3QQ77zdFpCMASA1a3Jlb64Hv2N2DciFGkO/4L9+q/IpIAuRlKOvCXabtRW6cQf8usbmM6BE/TOPysCdIA==} + engines: {bun: '>=1.0.0', deno: '>=1.30.0', node: '>=8.0.0'} + magic-bytes.js@1.13.0: resolution: {integrity: sha512-afO2mnxW7GDTXMm5/AoN1WuOcdoKhtgXjIvHmobqTD1grNplhGdv3PFOyjCVmrnOZBIT/gD/koDKpYG+0mvHcg==} @@ -2318,6 +2484,19 @@ packages: mute-stream@0.0.8: resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} + mysql2@3.15.3: + resolution: {integrity: sha512-FBrGau0IXmuqg4haEZRBfHNWB5mUARw6hNwPDXXGg0XzVJ50mr/9hb267lvpVMnhZ1FON3qNd4Xfcez1rbFwSg==} + engines: {node: '>= 8.0'} + + named-placeholders@1.1.6: + resolution: {integrity: sha512-Tz09sEL2EEuv5fFowm419c1+a/jSMiBjI9gHxVLrVdbUkkNUUfjsVYs9pVZu5oCon/kmRh9TfLEObFtkVxmY0w==} + engines: {node: '>=8.0.0'} + + nano-staged@1.0.2: + resolution: {integrity: sha512-Fytar3zHLY99nlMfqPPbraxZodqQAHPpdPRyYaplL+lB9DCR6pUrafxbG+Btz4+7fO5Rm/+DO4ZeDO/nLSUMhw==} + engines: {node: ^22 || >= 24} + hasBin: true + nanoid@3.3.12: resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -2333,6 +2512,9 @@ packages: ofetch@1.5.1: resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==} + ohash@2.0.11: + resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} + once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -2352,15 +2534,18 @@ packages: resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} engines: {node: '>=0.10.0'} - oxfmt@0.51.0: - resolution: {integrity: sha512-l/AoAnaEOV7Q5/Z9kHOMDehVJnCgYN7wRoooWCTUMBMi16BJhLZqd9cmCnwcVFfVlzkt53zK2KLPFNp8vSsoDg==} + oxfmt@0.54.0: + resolution: {integrity: sha512-DjnMwn7smSLF+Mc2+pRItnuPftm/dkUFpY/d4+33y9TfKrsHZo8GLhmUg9BrOIUEy94Rlom1Q11N6vuhE+e0oQ==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: svelte: ^5.0.0 + vite-plus: '*' peerDependenciesMeta: svelte: optional: true + vite-plus: + optional: true oxlint@1.69.0: resolution: {integrity: sha512-ypZkK/aDc5NQV8zIR6s2H2Tl3aNW8FmJ1m9+2qsaYuRenl8vgnHNCGwTHviWJdUQzglOlHFchgopdtGhSy17Rw==} @@ -2394,15 +2579,18 @@ packages: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - peek-readable@5.4.2: - resolution: {integrity: sha512-peBp3qZyuS6cNIJ2akRNG1uo1WJ1d0wTxg/fxMdZ0BqCVhx242bSFHM9eNqflfJVS9SsgkzgT/1UgnsurBOTMg==} - engines: {node: '>=14.16'} + perfect-debounce@2.1.0: + resolution: {integrity: sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==} pg-int8@1.0.1: resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} @@ -2426,6 +2614,9 @@ packages: resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} engines: {node: '>=12'} + pkg-types@2.3.1: + resolution: {integrity: sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==} + pnpm-workspace-yaml@1.6.1: resolution: {integrity: sha512-yTeZntGWi8m9WNuhoVsP0DpFc4sC1U0+rr/qR6Zi9n2g3sxXY+JfccjXjjruNz96tM8I09yaJUA86doRnNLkbg==} @@ -2449,34 +2640,51 @@ packages: resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} engines: {node: '>=0.10.0'} - prettier@3.8.4: - resolution: {integrity: sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q==} - engines: {node: '>=14'} - hasBin: true + postgres@3.4.7: + resolution: {integrity: sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw==} + engines: {node: '>=12'} - prisma@4.16.2: - resolution: {integrity: sha512-SYCsBvDf0/7XSJyf2cHTLjLeTLVXYfqp7pG5eEVafFLeT0u/hLFz/9W196nDRGUOo1JfPatAEb+uEnTQImQC1g==} - engines: {node: '>=14.17'} + prisma@7.8.0: + resolution: {integrity: sha512-yfN4yrw7HV9kEJhoy1+jgah0jafEIQsf7uWouSsM8MvJtlubsk+kM7AIBWZ8+GJl74Yj3c+nbYqBkMOxtsZ3Lw==} + engines: {node: ^20.19 || ^22.12 || >=24.0} hasBin: true + peerDependencies: + better-sqlite3: '>=9.0.0' + typescript: '>=5.4.0' + peerDependenciesMeta: + better-sqlite3: + optional: true + typescript: + optional: true + + proper-lockfile@4.1.2: + resolution: {integrity: sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==} - process@0.11.10: - resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} - engines: {node: '>= 0.6.0'} + pure-rand@6.1.0: + resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} quansync@1.0.0: resolution: {integrity: sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA==} + rc9@3.0.1: + resolution: {integrity: sha512-gMDyleLWVE+i6Sgtc0QbbY6pEKqYs97NGi6isHQPqYlLemPoO8dxQ3uGi0f4NiP98c+jMW6cG1Kx9dDwfvqARQ==} + + react-dom@19.2.7: + resolution: {integrity: sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==} + peerDependencies: + react: ^19.2.7 + + react@19.2.7: + resolution: {integrity: sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==} + engines: {node: '>=0.10.0'} + readable-stream@3.6.2: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} - readable-stream@4.7.0: - resolution: {integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - readable-web-to-node-stream@3.0.4: - resolution: {integrity: sha512-9nX56alTf5bwXQ3ZDipHJhusu9NTQJ/CVPtb/XHAJCXihZeitfJvIRS4GqQ/mfIoOE3IelHMrpayVrosdHBuLw==} - engines: {node: '>=8'} + readdirp@5.0.0: + resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} + engines: {node: '>= 20.19.0'} redis-errors@1.2.0: resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==} @@ -2486,9 +2694,8 @@ packages: resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==} engines: {node: '>=4'} - require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} + remeda@2.33.4: + resolution: {integrity: sha512-ygHswjlc/opg2VrtiYvUOPLjxjtdKvjGz1/plDhkG66hjNjFr1xmfrs2ClNFo/E6TyUFiwYNh53bKV26oBoMGQ==} require-from-string@2.0.2: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} @@ -2498,6 +2705,10 @@ packages: resolution: {integrity: sha512-gAZ+kLqBdHarXB64XpAe2VCjB7rIRv+mU8tfRWziHRJ5umKsIHN2tLLv6EtMw7WCdP19S0ERVMldNvxYCHnhSQ==} engines: {node: '>=8.6.0'} + require-in-the-middle@8.0.1: + resolution: {integrity: sha512-QT7FVMXfWOYFbeRBF6nu+I6tr2Tf3u0q8RIEjNob/heKY/nh7drD/k7eeMFmSQgnTtCzLDcCu/XEnpW2wk4xCQ==} + engines: {node: '>=9.3.0 || >=8.10.0 <9.0.0'} + resolve-dir@1.0.1: resolution: {integrity: sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==} engines: {node: '>=0.10.0'} @@ -2526,8 +2737,9 @@ packages: resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} engines: {node: '>=18'} - rfdc@1.4.1: - resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + retry@0.12.0: + resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} + engines: {node: '>= 4'} rolldown-plugin-dts@0.25.2: resolution: {integrity: sha512-nMhN/R+vmR8GM45ZW1FWMSjRTSDDn/6w4GTf8RNrEFCBdl8B1kySWrU1ixPtbwzXoRlcO+R/S88VgXuJQwfdDg==} @@ -2571,11 +2783,25 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + semver@7.8.4: resolution: {integrity: sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==} engines: {node: '>=10'} hasBin: true + seq-queue@0.0.5: + resolution: {integrity: sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + shimmer@1.2.1: resolution: {integrity: sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==} @@ -2589,31 +2815,26 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} - slice-ansi@7.1.2: - resolution: {integrity: sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==} - engines: {node: '>=18'} - - slice-ansi@8.0.0: - resolution: {integrity: sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg==} - engines: {node: '>=20'} - source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + sqlstring@2.3.3: + resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==} + engines: {node: '>= 0.6'} + stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} standard-as-callback@2.1.0: resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==} + std-env@3.10.0: + resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + std-env@4.1.0: resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==} - string-argv@0.3.2: - resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} - engines: {node: '>=0.6.19'} - string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -2622,10 +2843,6 @@ packages: resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} engines: {node: '>=18'} - string-width@8.2.1: - resolution: {integrity: sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA==} - engines: {node: '>=20'} - string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} @@ -2645,10 +2862,6 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} - strtok3@7.1.1: - resolution: {integrity: sha512-mKX8HA/cdBqMKUr0MMZAFssCkIGoZeSCMXgnt79yKxNFguMLVFgRe6wB+fsL0NmoHDbeyZXczy7vEPSoo3rkzg==} - engines: {node: '>=16'} - supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} @@ -2701,10 +2914,6 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} - token-types@5.0.1: - resolution: {integrity: sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==} - engines: {node: '>=14.16'} - tree-kill@1.2.2: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true @@ -2712,14 +2921,14 @@ packages: ts-mixer@6.0.4: resolution: {integrity: sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA==} - tsdown@0.22.2: - resolution: {integrity: sha512-VX9gsyKXsTnBZjnIM4jsHl9aRv+GfgkE/k1hQslilaBfZMlaw3JuGR+6yhiU0QxWBtOCDnTjwOSoXzgB7Rr50g==} + tsdown@0.22.0: + resolution: {integrity: sha512-FgW0hHb27nGQA/+F3d5+U9wKXkfilk9DVkc5+7x/ZqF03g+Hoz/eeApT32jqxATt9eRoR+1jxk7MUMON+O4CXw==} engines: {node: ^22.18.0 || >=24.0.0} hasBin: true peerDependencies: '@arethetypeswrong/core': ^0.18.1 - '@tsdown/css': 0.22.2 - '@tsdown/exe': 0.22.2 + '@tsdown/css': 0.22.0 + '@tsdown/exe': 0.22.0 '@vitejs/devtools': '*' publint: ^0.3.8 tsx: '*' @@ -2753,11 +2962,6 @@ packages: resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} engines: {node: '>=10'} - typescript@4.9.5: - resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} - engines: {node: '>=4.2.0'} - hasBin: true - typescript@5.4.5: resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} engines: {node: '>=14.17'} @@ -2780,9 +2984,8 @@ packages: undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - undici@5.29.0: - resolution: {integrity: sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==} - engines: {node: '>=14.0'} + undici-types@7.18.2: + resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} undici@6.24.1: resolution: {integrity: sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA==} @@ -2795,6 +2998,14 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + valibot@1.2.0: + resolution: {integrity: sha512-mm1rxUsmOxzrwnX5arGS+U4T25RdvpPjPN4yR0u9pUBov9+zGVtO84tif1eY4r6zWxVxu3KzIyknJy3rxfRZZg==} + peerDependencies: + typescript: '>=5' + peerDependenciesMeta: + typescript: + optional: true + vite@6.4.3: resolution: {integrity: sha512-NTKlcQjlAK7MlQoyb6LgaqHc8sso/pVyUJYWMws3jg21uTJw/LddqIFPcPqP6PzpgbIcZyKI85sFE4HBrQDA8A==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} @@ -2883,6 +3094,11 @@ packages: resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} hasBin: true + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + why-is-node-running@2.3.0: resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} engines: {node: '>=8'} @@ -2928,13 +3144,16 @@ packages: engines: {node: '>= 14.6'} hasBin: true - yargs-parser@21.1.1: - resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} - engines: {node: '>=12'} + yargs-parser@22.0.0: + resolution: {integrity: sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==} + engines: {node: ^20.19.0 || ^22.12.0 || >=23} - yargs@17.7.2: - resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} - engines: {node: '>=12'} + yargs@18.0.0: + resolution: {integrity: sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=23} + + zeptomatch@2.1.0: + resolution: {integrity: sha512-KiGErG2J0G82LSpniV0CtIzjlJ10E04j02VOudJsPyPwNZgGnRKQy7I1R7GMyg/QswnE4l7ohSGrQbQbjXPPDA==} snapshots: @@ -2990,155 +3209,113 @@ snapshots: '@bcoe/v8-coverage@1.0.2': {} - '@commitlint/cli@20.5.3(@types/node@22.19.21)(conventional-commits-parser@6.4.0)(typescript@4.9.5)': + '@commitlint/cli@21.0.2(@types/node@24.13.2)(conventional-commits-parser@6.4.0)(typescript@6.0.3)': dependencies: - '@commitlint/format': 20.5.0 - '@commitlint/lint': 20.5.3 - '@commitlint/load': 20.5.3(@types/node@22.19.21)(typescript@4.9.5) - '@commitlint/read': 20.5.0(conventional-commits-parser@6.4.0) - '@commitlint/types': 20.5.0 + '@commitlint/format': 21.0.1 + '@commitlint/lint': 21.0.2 + '@commitlint/load': 21.0.2(@types/node@24.13.2)(typescript@6.0.3) + '@commitlint/read': 21.0.2(conventional-commits-parser@6.4.0) + '@commitlint/types': 21.0.1 tinyexec: 1.2.4 - yargs: 17.7.2 + yargs: 18.0.0 transitivePeerDependencies: - '@types/node' - conventional-commits-filter - conventional-commits-parser - typescript - '@commitlint/config-conventional@20.5.3': + '@commitlint/config-conventional@21.0.2': dependencies: - '@commitlint/types': 20.5.0 + '@commitlint/types': 21.0.1 conventional-changelog-conventionalcommits: 9.3.1 - '@commitlint/config-validator@20.5.0': - dependencies: - '@commitlint/types': 20.5.0 - ajv: 8.20.0 - '@commitlint/config-validator@21.0.1': dependencies: '@commitlint/types': 21.0.1 ajv: 8.20.0 - optional: true - '@commitlint/ensure@20.5.3': + '@commitlint/ensure@21.0.1': dependencies: - '@commitlint/types': 20.5.0 - es-toolkit: 1.47.0 - - '@commitlint/execute-rule@20.0.0': {} + '@commitlint/types': 21.0.1 + es-toolkit: 1.47.1 - '@commitlint/execute-rule@21.0.1': - optional: true + '@commitlint/execute-rule@21.0.1': {} - '@commitlint/format@20.5.0': + '@commitlint/format@21.0.1': dependencies: - '@commitlint/types': 20.5.0 + '@commitlint/types': 21.0.1 picocolors: 1.1.1 - '@commitlint/is-ignored@20.5.0': + '@commitlint/is-ignored@21.0.2': dependencies: - '@commitlint/types': 20.5.0 + '@commitlint/types': 21.0.1 semver: 7.8.4 - '@commitlint/lint@20.5.3': - dependencies: - '@commitlint/is-ignored': 20.5.0 - '@commitlint/parse': 20.5.0 - '@commitlint/rules': 20.5.3 - '@commitlint/types': 20.5.0 - - '@commitlint/load@20.5.3(@types/node@22.19.21)(typescript@4.9.5)': + '@commitlint/lint@21.0.2': dependencies: - '@commitlint/config-validator': 20.5.0 - '@commitlint/execute-rule': 20.0.0 - '@commitlint/resolve-extends': 20.5.3 - '@commitlint/types': 20.5.0 - cosmiconfig: 9.0.2(typescript@4.9.5) - cosmiconfig-typescript-loader: 6.3.0(@types/node@22.19.21)(cosmiconfig@9.0.2)(typescript@4.9.5) - es-toolkit: 1.47.0 - is-plain-obj: 4.1.0 - picocolors: 1.1.1 - transitivePeerDependencies: - - '@types/node' - - typescript + '@commitlint/is-ignored': 21.0.2 + '@commitlint/parse': 21.0.2 + '@commitlint/rules': 21.0.2 + '@commitlint/types': 21.0.1 - '@commitlint/load@21.0.2(@types/node@22.19.21)(typescript@4.9.5)': + '@commitlint/load@21.0.2(@types/node@24.13.2)(typescript@6.0.3)': dependencies: '@commitlint/config-validator': 21.0.1 '@commitlint/execute-rule': 21.0.1 '@commitlint/resolve-extends': 21.0.1 '@commitlint/types': 21.0.1 - cosmiconfig: 9.0.2(typescript@4.9.5) - cosmiconfig-typescript-loader: 6.3.0(@types/node@22.19.21)(cosmiconfig@9.0.2)(typescript@4.9.5) - es-toolkit: 1.47.0 + cosmiconfig: 9.0.2(typescript@6.0.3) + cosmiconfig-typescript-loader: 6.3.0(@types/node@24.13.2)(cosmiconfig@9.0.2)(typescript@6.0.3) + es-toolkit: 1.47.1 is-plain-obj: 4.1.0 picocolors: 1.1.1 transitivePeerDependencies: - '@types/node' - typescript - optional: true - '@commitlint/message@20.4.3': {} + '@commitlint/message@21.0.2': {} - '@commitlint/parse@20.5.0': + '@commitlint/parse@21.0.2': dependencies: - '@commitlint/types': 20.5.0 + '@commitlint/types': 21.0.1 conventional-changelog-angular: 8.3.1 conventional-commits-parser: 6.4.0 - '@commitlint/read@20.5.0(conventional-commits-parser@6.4.0)': + '@commitlint/read@21.0.2(conventional-commits-parser@6.4.0)': dependencies: - '@commitlint/top-level': 20.4.3 - '@commitlint/types': 20.5.0 + '@commitlint/top-level': 21.0.2 + '@commitlint/types': 21.0.1 git-raw-commits: 5.0.1(conventional-commits-parser@6.4.0) - minimist: 1.2.8 tinyexec: 1.2.4 transitivePeerDependencies: - conventional-commits-filter - conventional-commits-parser - '@commitlint/resolve-extends@20.5.3': - dependencies: - '@commitlint/config-validator': 20.5.0 - '@commitlint/types': 20.5.0 - es-toolkit: 1.47.0 - global-directory: 5.0.0 - import-meta-resolve: 4.2.0 - resolve-from: 5.0.0 - '@commitlint/resolve-extends@21.0.1': dependencies: '@commitlint/config-validator': 21.0.1 '@commitlint/types': 21.0.1 - es-toolkit: 1.47.0 + es-toolkit: 1.47.1 global-directory: 5.0.0 resolve-from: 5.0.0 - optional: true - '@commitlint/rules@20.5.3': + '@commitlint/rules@21.0.2': dependencies: - '@commitlint/ensure': 20.5.3 - '@commitlint/message': 20.4.3 - '@commitlint/to-lines': 20.0.0 - '@commitlint/types': 20.5.0 + '@commitlint/ensure': 21.0.1 + '@commitlint/message': 21.0.2 + '@commitlint/to-lines': 21.0.1 + '@commitlint/types': 21.0.1 - '@commitlint/to-lines@20.0.0': {} + '@commitlint/to-lines@21.0.1': {} - '@commitlint/top-level@20.4.3': + '@commitlint/top-level@21.0.2': dependencies: escalade: 3.2.0 - '@commitlint/types@20.5.0': - dependencies: - conventional-commits-parser: 6.4.0 - picocolors: 1.1.1 - '@commitlint/types@21.0.1': dependencies: conventional-commits-parser: 6.4.0 picocolors: 1.1.1 - optional: true '@conventional-changelog/git-client@2.7.0(conventional-commits-parser@6.4.0)': dependencies: @@ -3166,17 +3343,6 @@ snapshots: dependencies: discord-api-types: 0.38.48 - '@discordjs/rest@1.7.1': - dependencies: - '@discordjs/collection': 1.5.3 - '@discordjs/util': 0.3.1 - '@sapphire/async-queue': 1.5.5 - '@sapphire/snowflake': 3.5.5 - discord-api-types: 0.38.48 - file-type: 18.7.0 - tslib: 2.8.1 - undici: 5.29.0 - '@discordjs/rest@2.6.1': dependencies: '@discordjs/collection': 2.1.1 @@ -3189,16 +3355,15 @@ snapshots: tslib: 2.8.1 undici: 6.24.1 - '@discordjs/util@0.3.1': {} - '@discordjs/util@1.2.0': dependencies: discord-api-types: 0.38.48 - '@discordjs/ws@0.2.0': + '@discordjs/ws@1.2.3': dependencies: - '@discordjs/collection': 1.5.3 - '@discordjs/rest': 1.7.1 + '@discordjs/collection': 2.1.1 + '@discordjs/rest': 2.6.1 + '@discordjs/util': 1.2.0 '@sapphire/async-queue': 1.5.5 '@types/ws': 8.18.1 '@vladfrangu/async_event_emitter': 2.4.7 @@ -3209,7 +3374,7 @@ snapshots: - bufferutil - utf-8-validate - '@discordjs/ws@1.2.3': + '@discordjs/ws@2.0.4': dependencies: '@discordjs/collection': 2.1.1 '@discordjs/rest': 2.6.1 @@ -3224,6 +3389,16 @@ snapshots: - bufferutil - utf-8-validate + '@electric-sql/pglite-socket@0.1.1(@electric-sql/pglite@0.4.1)': + dependencies: + '@electric-sql/pglite': 0.4.1 + + '@electric-sql/pglite-tools@0.3.1(@electric-sql/pglite@0.4.1)': + dependencies: + '@electric-sql/pglite': 0.4.1 + + '@electric-sql/pglite@0.4.1': {} + '@emnapi/core@1.11.0': dependencies: '@emnapi/wasi-threads': 1.2.2 @@ -3318,10 +3493,12 @@ snapshots: '@esbuild/win32-x64@0.25.12': optional: true - '@fastify/busboy@2.1.1': {} - '@henrygd/queue@1.2.0': {} + '@hono/node-server@1.19.11(hono@4.12.25)': + dependencies: + hono: 4.12.25 + '@ioredis/commands@1.10.0': {} '@jridgewell/gen-mapping@0.3.13': @@ -3338,6 +3515,8 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + '@kurkle/color@0.3.4': {} + '@napi-rs/wasm-runtime@1.1.5(@emnapi/core@1.11.0)(@emnapi/runtime@1.11.0)': dependencies: '@emnapi/core': 1.11.0 @@ -3345,6 +3524,10 @@ snapshots: '@tybys/wasm-util': 0.10.2 optional: true + '@opentelemetry/api-logs@0.214.0': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/api-logs@0.53.0': dependencies: '@opentelemetry/api': 1.9.1 @@ -3368,6 +3551,11 @@ snapshots: '@opentelemetry/api': 1.9.1 '@opentelemetry/semantic-conventions': 1.28.0 + '@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/semantic-conventions': 1.41.1 + '@opentelemetry/instrumentation-amqplib@0.46.1(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 @@ -3576,6 +3764,15 @@ snapshots: transitivePeerDependencies: - supports-color + '@opentelemetry/instrumentation@0.214.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/api-logs': 0.214.0 + import-in-the-middle: 3.0.2 + require-in-the-middle: 8.0.1 + transitivePeerDependencies: + - supports-color + '@opentelemetry/instrumentation@0.53.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 @@ -3620,6 +3817,12 @@ snapshots: '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.28.0 + '@opentelemetry/resources@2.8.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.8.0(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + '@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 @@ -3627,6 +3830,13 @@ snapshots: '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.28.0 + '@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.8.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.8.0(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + '@opentelemetry/semantic-conventions@1.27.0': {} '@opentelemetry/semantic-conventions@1.28.0': {} @@ -3640,61 +3850,61 @@ snapshots: '@oxc-project/types@0.135.0': {} - '@oxfmt/binding-android-arm-eabi@0.51.0': + '@oxfmt/binding-android-arm-eabi@0.54.0': optional: true - '@oxfmt/binding-android-arm64@0.51.0': + '@oxfmt/binding-android-arm64@0.54.0': optional: true - '@oxfmt/binding-darwin-arm64@0.51.0': + '@oxfmt/binding-darwin-arm64@0.54.0': optional: true - '@oxfmt/binding-darwin-x64@0.51.0': + '@oxfmt/binding-darwin-x64@0.54.0': optional: true - '@oxfmt/binding-freebsd-x64@0.51.0': + '@oxfmt/binding-freebsd-x64@0.54.0': optional: true - '@oxfmt/binding-linux-arm-gnueabihf@0.51.0': + '@oxfmt/binding-linux-arm-gnueabihf@0.54.0': optional: true - '@oxfmt/binding-linux-arm-musleabihf@0.51.0': + '@oxfmt/binding-linux-arm-musleabihf@0.54.0': optional: true - '@oxfmt/binding-linux-arm64-gnu@0.51.0': + '@oxfmt/binding-linux-arm64-gnu@0.54.0': optional: true - '@oxfmt/binding-linux-arm64-musl@0.51.0': + '@oxfmt/binding-linux-arm64-musl@0.54.0': optional: true - '@oxfmt/binding-linux-ppc64-gnu@0.51.0': + '@oxfmt/binding-linux-ppc64-gnu@0.54.0': optional: true - '@oxfmt/binding-linux-riscv64-gnu@0.51.0': + '@oxfmt/binding-linux-riscv64-gnu@0.54.0': optional: true - '@oxfmt/binding-linux-riscv64-musl@0.51.0': + '@oxfmt/binding-linux-riscv64-musl@0.54.0': optional: true - '@oxfmt/binding-linux-s390x-gnu@0.51.0': + '@oxfmt/binding-linux-s390x-gnu@0.54.0': optional: true - '@oxfmt/binding-linux-x64-gnu@0.51.0': + '@oxfmt/binding-linux-x64-gnu@0.54.0': optional: true - '@oxfmt/binding-linux-x64-musl@0.51.0': + '@oxfmt/binding-linux-x64-musl@0.54.0': optional: true - '@oxfmt/binding-openharmony-arm64@0.51.0': + '@oxfmt/binding-openharmony-arm64@0.54.0': optional: true - '@oxfmt/binding-win32-arm64-msvc@0.51.0': + '@oxfmt/binding-win32-arm64-msvc@0.54.0': optional: true - '@oxfmt/binding-win32-ia32-msvc@0.51.0': + '@oxfmt/binding-win32-ia32-msvc@0.54.0': optional: true - '@oxfmt/binding-win32-x64-msvc@0.51.0': + '@oxfmt/binding-win32-x64-msvc@0.54.0': optional: true '@oxlint/binding-android-arm-eabi@1.69.0': @@ -3754,15 +3964,72 @@ snapshots: '@oxlint/binding-win32-x64-msvc@1.69.0': optional: true - '@prisma/client@4.16.2(prisma@4.16.2)': + '@prisma/client-runtime-utils@7.8.0': {} + + '@prisma/client@7.8.0(prisma@7.8.0)(typescript@6.0.3)': dependencies: - '@prisma/engines-version': 4.16.1-1.4bc8b6e1b66cb932731fb1bdbbc550d1e010de81 + '@prisma/client-runtime-utils': 7.8.0 optionalDependencies: - prisma: 4.16.2 + prisma: 7.8.0(@types/react@19.2.17)(magicast@0.5.3)(react-dom@19.2.7)(react@19.2.7)(typescript@6.0.3) + typescript: 6.0.3 + + '@prisma/config@7.8.0(magicast@0.5.3)': + dependencies: + c12: 3.3.4(magicast@0.5.3) + deepmerge-ts: 7.1.5 + effect: 3.20.0 + empathic: 2.0.0 + transitivePeerDependencies: + - magicast + + '@prisma/debug@7.2.0': {} - '@prisma/engines-version@4.16.1-1.4bc8b6e1b66cb932731fb1bdbbc550d1e010de81': {} + '@prisma/debug@7.8.0': {} - '@prisma/engines@4.16.2': {} + '@prisma/dev@0.24.3(typescript@6.0.3)': + dependencies: + '@electric-sql/pglite': 0.4.1 + '@electric-sql/pglite-socket': 0.1.1(@electric-sql/pglite@0.4.1) + '@electric-sql/pglite-tools': 0.3.1(@electric-sql/pglite@0.4.1) + '@hono/node-server': 1.19.11(hono@4.12.25) + '@prisma/get-platform': 7.2.0 + '@prisma/query-plan-executor': 7.2.0 + '@prisma/streams-local': 0.1.2 + foreground-child: 3.3.1 + get-port-please: 3.2.0 + hono: 4.12.25 + http-status-codes: 2.3.0 + pathe: 2.0.3 + proper-lockfile: 4.1.2 + remeda: 2.33.4 + std-env: 3.10.0 + valibot: 1.2.0(typescript@6.0.3) + zeptomatch: 2.1.0 + transitivePeerDependencies: + - typescript + + '@prisma/engines-version@7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a': {} + + '@prisma/engines@7.8.0': + dependencies: + '@prisma/debug': 7.8.0 + '@prisma/engines-version': 7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a + '@prisma/fetch-engine': 7.8.0 + '@prisma/get-platform': 7.8.0 + + '@prisma/fetch-engine@7.8.0': + dependencies: + '@prisma/debug': 7.8.0 + '@prisma/engines-version': 7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a + '@prisma/get-platform': 7.8.0 + + '@prisma/get-platform@7.2.0': + dependencies: + '@prisma/debug': 7.2.0 + + '@prisma/get-platform@7.8.0': + dependencies: + '@prisma/debug': 7.8.0 '@prisma/instrumentation@5.22.0': dependencies: @@ -3772,10 +4039,83 @@ snapshots: transitivePeerDependencies: - supports-color + '@prisma/query-plan-executor@7.2.0': {} + + '@prisma/streams-local@0.1.2': + dependencies: + ajv: 8.20.0 + better-result: 2.9.2 + env-paths: 3.0.0 + proper-lockfile: 4.1.2 + + '@prisma/studio-core@0.27.3(@types/react@19.2.17)(react-dom@19.2.7)(react@19.2.7)': + dependencies: + '@radix-ui/react-toggle': 1.1.10(@types/react@19.2.17)(react-dom@19.2.7)(react@19.2.7) + '@types/react': 19.2.17 + chart.js: 4.5.1 + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + transitivePeerDependencies: + - '@types/react-dom' + '@quansync/fs@1.0.0': dependencies: quansync: 1.0.0 + '@radix-ui/primitive@1.1.3': {} + + '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.17)(react@19.2.7)': + dependencies: + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-primitive@2.1.3(@types/react@19.2.17)(react-dom@19.2.7)(react@19.2.7)': + dependencies: + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-slot@1.2.3(@types/react@19.2.17)(react@19.2.7)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-toggle@1.1.10(@types/react@19.2.17)(react-dom@19.2.7)(react@19.2.7)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-primitive': 2.1.3(@types/react@19.2.17)(react-dom@19.2.7)(react@19.2.7) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.17)(react@19.2.7)': + dependencies: + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.17)(react@19.2.7)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.17)(react@19.2.7)': + dependencies: + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.17 + '@rolldown/binding-android-arm64@1.1.1': optional: true @@ -3949,10 +4289,6 @@ snapshots: '@sapphire/utilities': 3.18.2 tslib: 2.8.1 - '@sapphire/prettier-config@2.0.0': - dependencies: - prettier: 3.8.4 - '@sapphire/ratelimits@2.4.11': {} '@sapphire/result@2.8.0': {} @@ -3977,45 +4313,41 @@ snapshots: '@sapphire/utilities@3.18.2': {} - '@sentry-internal/tracing@7.120.4': - dependencies: - '@sentry/core': 7.120.4 - '@sentry/types': 7.120.4 - '@sentry/utils': 7.120.4 - - '@sentry/core@7.114.0': + '@sentry-internal/server-utils@10.57.0': dependencies: - '@sentry/types': 7.114.0 - '@sentry/utils': 7.114.0 + '@sentry/core': 10.57.0 - '@sentry/core@7.120.4': - dependencies: - '@sentry/types': 7.120.4 - '@sentry/utils': 7.120.4 + '@sentry/core@10.57.0': {} '@sentry/core@8.55.2': {} - '@sentry/integrations@7.114.0': - dependencies: - '@sentry/core': 7.114.0 - '@sentry/types': 7.114.0 - '@sentry/utils': 7.114.0 - localforage: 1.10.0 - - '@sentry/integrations@7.120.4': + '@sentry/node-core@10.57.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.8.0)(@opentelemetry/instrumentation@0.214.0)(@opentelemetry/sdk-trace-base@2.8.0)(@opentelemetry/semantic-conventions@1.41.1)': dependencies: - '@sentry/core': 7.120.4 - '@sentry/types': 7.120.4 - '@sentry/utils': 7.120.4 - localforage: 1.10.0 + '@sentry/core': 10.57.0 + '@sentry/opentelemetry': 10.57.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.8.0)(@opentelemetry/sdk-trace-base@2.8.0)(@opentelemetry/semantic-conventions@1.41.1) + import-in-the-middle: 3.0.2 + optionalDependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.8.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': 2.8.0(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 - '@sentry/node@7.120.4': + '@sentry/node@10.57.0': dependencies: - '@sentry-internal/tracing': 7.120.4 - '@sentry/core': 7.120.4 - '@sentry/integrations': 7.120.4 - '@sentry/types': 7.120.4 - '@sentry/utils': 7.120.4 + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.8.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': 2.8.0(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + '@sentry-internal/server-utils': 10.57.0 + '@sentry/core': 10.57.0 + '@sentry/node-core': 10.57.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.8.0)(@opentelemetry/instrumentation@0.214.0)(@opentelemetry/sdk-trace-base@2.8.0)(@opentelemetry/semantic-conventions@1.41.1) + '@sentry/opentelemetry': 10.57.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.8.0)(@opentelemetry/sdk-trace-base@2.8.0)(@opentelemetry/semantic-conventions@1.41.1) + import-in-the-middle: 3.0.2 + transitivePeerDependencies: + - '@opentelemetry/exporter-trace-otlp-http' + - supports-color '@sentry/node@8.55.2': dependencies: @@ -4057,6 +4389,14 @@ snapshots: transitivePeerDependencies: - supports-color + '@sentry/opentelemetry@10.57.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.8.0)(@opentelemetry/sdk-trace-base@2.8.0)(@opentelemetry/semantic-conventions@1.41.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.8.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': 2.8.0(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + '@sentry/core': 10.57.0 + '@sentry/opentelemetry@8.55.2(@opentelemetry/api@1.9.1)(@opentelemetry/context-async-hooks@1.30.1)(@opentelemetry/core@1.30.1)(@opentelemetry/instrumentation@0.57.2)(@opentelemetry/sdk-trace-base@1.30.1)(@opentelemetry/semantic-conventions@1.41.1)': dependencies: '@opentelemetry/api': 1.9.1 @@ -4067,18 +4407,6 @@ snapshots: '@opentelemetry/semantic-conventions': 1.41.1 '@sentry/core': 8.55.2 - '@sentry/types@7.114.0': {} - - '@sentry/types@7.120.4': {} - - '@sentry/utils@7.114.0': - dependencies: - '@sentry/types': 7.114.0 - - '@sentry/utils@7.120.4': - dependencies: - '@sentry/types': 7.120.4 - '@simple-libs/child-process-utils@1.0.2': dependencies: '@simple-libs/stream-utils': 1.2.0 @@ -4091,8 +4419,6 @@ snapshots: '@standard-schema/spec@1.1.0': {} - '@tokenizer/token@0.3.0': {} - '@tybys/wasm-util@0.10.2': dependencies: tslib: 2.8.1 @@ -4123,6 +4449,10 @@ snapshots: dependencies: undici-types: 6.21.0 + '@types/node@24.13.2': + dependencies: + undici-types: 7.18.2 + '@types/pg-pool@2.0.6': dependencies: '@types/pg': 8.6.1 @@ -4133,6 +4463,10 @@ snapshots: pg-protocol: 1.14.0 pg-types: 2.2.0 + '@types/react@19.2.17': + dependencies: + csstype: 3.2.3 + '@types/shimmer@1.2.0': {} '@types/tedious@4.0.14': @@ -4157,7 +4491,7 @@ snapshots: obug: 2.1.2 std-env: 4.1.0 tinyrainbow: 3.1.0 - vitest: 4.1.8(@opentelemetry/api@1.9.1)(@types/node@22.19.21)(@vitest/coverage-v8@4.1.8)(vite@6.4.3) + vitest: 4.1.8(@opentelemetry/api@1.9.1)(@types/node@24.13.2)(@vitest/coverage-v8@4.1.8)(vite@6.4.3) '@vitest/expect@4.1.8': dependencies: @@ -4174,7 +4508,7 @@ snapshots: estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 6.4.3(@types/node@22.19.21)(jiti@2.6.1)(yaml@2.9.0) + vite: 6.4.3(@types/node@24.13.2)(jiti@2.7.0)(yaml@2.9.0) '@vitest/pretty-format@4.1.8': dependencies: @@ -4247,10 +4581,6 @@ snapshots: '@wolfstar/start-banner@3.0.1': {} - abort-controller@3.0.0: - dependencies: - event-target-shim: 5.0.1 - acorn-import-attributes@1.9.5(acorn@8.17.0): dependencies: acorn: 8.17.0 @@ -4268,10 +4598,6 @@ snapshots: dependencies: type-fest: 0.21.3 - ansi-escapes@7.3.0: - dependencies: - environment: 1.1.0 - ansi-regex@5.0.1: {} ansi-styles@3.2.1: @@ -4306,10 +4632,14 @@ snapshots: at-least-node@1.0.0: {} + aws-ssl-profiles@1.1.2: {} + balanced-match@1.0.2: {} base64-js@1.5.1: {} + better-result@2.9.2: {} + birpc@4.0.0: {} bl@4.1.0: @@ -4332,10 +4662,22 @@ snapshots: base64-js: 1.5.1 ieee754: 1.2.1 - buffer@6.0.3: + c12@3.3.4(magicast@0.5.3): dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 + chokidar: 5.0.0 + confbox: 0.2.4 + defu: 6.1.7 + dotenv: 17.4.2 + exsolve: 1.0.8 + giget: 3.3.0 + jiti: 2.7.0 + ohash: 2.0.11 + pathe: 2.0.3 + perfect-debounce: 2.1.0 + pkg-types: 2.3.1 + rc9: 3.0.1 + optionalDependencies: + magicast: 0.5.3 cac@7.0.0: {} @@ -4358,30 +4700,31 @@ snapshots: chardet@0.7.0: {} + chart.js@4.5.1: + dependencies: + '@kurkle/color': 0.3.4 + + chokidar@5.0.0: + dependencies: + readdirp: 5.0.0 + cjs-module-lexer@1.4.3: {} + cjs-module-lexer@2.2.0: {} + cli-cursor@3.1.0: dependencies: restore-cursor: 3.1.0 - cli-cursor@5.0.0: - dependencies: - restore-cursor: 5.1.0 - cli-spinners@2.9.2: {} - cli-truncate@5.2.0: - dependencies: - slice-ansi: 8.0.0 - string-width: 8.2.1 - cli-width@3.0.0: {} - cliui@8.0.1: + cliui@9.0.1: dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 + string-width: 7.2.0 + strip-ansi: 7.2.0 + wrap-ansi: 9.0.2 clone@1.0.4: {} @@ -4401,12 +4744,10 @@ snapshots: colorette@2.0.20: {} - commander@14.0.3: {} - - commitizen@4.3.1(@types/node@22.19.21)(typescript@4.9.5): + commitizen@4.3.1(@types/node@24.13.2)(typescript@6.0.3): dependencies: cachedir: 2.3.0 - cz-conventional-changelog: 3.3.0(@types/node@22.19.21)(typescript@4.9.5) + cz-conventional-changelog: 3.3.0(@types/node@24.13.2)(typescript@6.0.3) dedent: 0.7.0 detect-indent: 6.1.0 find-node-modules: 2.1.3 @@ -4430,6 +4771,8 @@ snapshots: concat-map@0.0.1: {} + confbox@0.2.4: {} + conventional-changelog-angular@8.3.1: dependencies: compare-func: 2.0.0 @@ -4447,32 +4790,40 @@ snapshots: convert-source-map@2.0.0: {} - cosmiconfig-typescript-loader@6.3.0(@types/node@22.19.21)(cosmiconfig@9.0.2)(typescript@4.9.5): + cosmiconfig-typescript-loader@6.3.0(@types/node@24.13.2)(cosmiconfig@9.0.2)(typescript@6.0.3): dependencies: - '@types/node': 22.19.21 - cosmiconfig: 9.0.2(typescript@4.9.5) + '@types/node': 24.13.2 + cosmiconfig: 9.0.2(typescript@6.0.3) jiti: 2.6.1 - typescript: 4.9.5 + typescript: 6.0.3 - cosmiconfig@9.0.2(typescript@4.9.5): + cosmiconfig@9.0.2(typescript@6.0.3): dependencies: env-paths: 2.2.1 import-fresh: 3.3.1 js-yaml: 4.2.0 parse-json: 5.2.0 optionalDependencies: - typescript: 4.9.5 + typescript: 6.0.3 + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + csstype@3.2.3: {} - cz-conventional-changelog@3.3.0(@types/node@22.19.21)(typescript@4.9.5): + cz-conventional-changelog@3.3.0(@types/node@24.13.2)(typescript@6.0.3): dependencies: chalk: 2.4.2 - commitizen: 4.3.1(@types/node@22.19.21)(typescript@4.9.5) + commitizen: 4.3.1(@types/node@24.13.2)(typescript@6.0.3) conventional-commit-types: 3.0.0 lodash.map: 4.6.0 longest: 2.0.1 word-wrap: 1.2.5 optionalDependencies: - '@commitlint/load': 21.0.2(@types/node@22.19.21)(typescript@4.9.5) + '@commitlint/load': 21.0.2(@types/node@24.13.2)(typescript@6.0.3) transitivePeerDependencies: - '@types/node' - typescript @@ -4483,6 +4834,8 @@ snapshots: dedent@0.7.0: {} + deepmerge-ts@7.1.5: {} + defaults@1.0.4: dependencies: clone: 1.0.4 @@ -4532,15 +4885,22 @@ snapshots: dts-resolver@3.0.0: {} + effect@3.20.0: + dependencies: + '@standard-schema/spec': 1.1.0 + fast-check: 3.23.2 + emoji-regex@10.6.0: {} emoji-regex@8.0.0: {} + empathic@2.0.0: {} + empathic@2.0.1: {} env-paths@2.2.1: {} - environment@1.1.0: {} + env-paths@3.0.0: {} error-ex@1.3.4: dependencies: @@ -4550,7 +4910,7 @@ snapshots: es-module-lexer@2.1.0: {} - es-toolkit@1.47.0: {} + es-toolkit@1.47.1: {} esbuild@0.25.12: optionalDependencies: @@ -4589,24 +4949,24 @@ snapshots: dependencies: '@types/estree': 1.0.9 - event-target-shim@5.0.1: {} - - eventemitter3@5.0.4: {} - - events@3.3.0: {} - expand-tilde@2.0.2: dependencies: homedir-polyfill: 1.0.3 expect-type@1.3.0: {} + exsolve@1.0.8: {} + external-editor@3.1.0: dependencies: chardet: 0.7.0 iconv-lite: 0.4.24 tmp: 0.0.33 + fast-check@3.23.2: + dependencies: + pure-rand: 6.1.0 + fast-deep-equal@3.1.3: {} fast-uri@3.1.2: {} @@ -4619,12 +4979,6 @@ snapshots: dependencies: escape-string-regexp: 1.0.5 - file-type@18.7.0: - dependencies: - readable-web-to-node-stream: 3.0.4 - strtok3: 7.1.1 - token-types: 5.0.1 - fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 @@ -4643,6 +4997,11 @@ snapshots: micromatch: 4.0.8 resolve-dir: 1.0.1 + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + forwarded-parse@2.1.2: {} fs-extra@9.1.0: @@ -4661,14 +5020,22 @@ snapshots: fzf@0.5.2: {} + generate-function@2.3.1: + dependencies: + is-property: 1.0.2 + get-caller-file@2.0.5: {} get-east-asian-width@1.6.0: {} + get-port-please@3.2.0: {} + get-tsconfig@5.0.0-beta.5: dependencies: resolve-pkg-maps: 1.0.0 + giget@3.3.0: {} + git-raw-commits@5.0.1(conventional-commits-parser@6.4.0): dependencies: '@conventional-changelog/git-client': 2.7.0(conventional-commits-parser@6.4.0) @@ -4711,6 +5078,10 @@ snapshots: chalk: 4.1.2 tinygradient: 1.1.5 + grammex@3.1.12: {} + + graphmatch@1.1.1: {} + has-flag@3.0.0: {} has-flag@4.0.0: {} @@ -4723,10 +5094,14 @@ snapshots: dependencies: parse-passwd: 1.0.0 + hono@4.12.25: {} + hookable@6.1.1: {} html-escaper@2.0.2: {} + http-status-codes@2.3.0: {} + husky@9.1.7: {} i18next@22.5.1: @@ -4737,9 +5112,11 @@ snapshots: dependencies: safer-buffer: 2.1.2 - ieee754@1.2.1: {} + iconv-lite@0.7.2: + dependencies: + safer-buffer: 2.1.2 - immediate@3.0.6: {} + ieee754@1.2.1: {} import-fresh@3.3.1: dependencies: @@ -4753,7 +5130,12 @@ snapshots: cjs-module-lexer: 1.4.3 module-details-from-path: 1.0.4 - import-meta-resolve@4.2.0: {} + import-in-the-middle@3.0.2: + dependencies: + acorn: 8.17.0 + acorn-import-attributes: 1.9.5(acorn@8.17.0) + cjs-module-lexer: 2.2.0 + module-details-from-path: 1.0.4 import-without-cache@0.4.0: {} @@ -4808,10 +5190,6 @@ snapshots: is-fullwidth-code-point@3.0.0: {} - is-fullwidth-code-point@5.1.0: - dependencies: - get-east-asian-width: 1.6.0 - is-glob@4.0.3: dependencies: is-extglob: 2.1.1 @@ -4824,6 +5202,8 @@ snapshots: is-plain-obj@4.1.0: {} + is-property@1.0.2: {} + is-unicode-supported@0.1.0: {} is-utf8@0.2.1: {} @@ -4852,6 +5232,8 @@ snapshots: jiti@2.6.1: {} + jiti@2.7.0: {} + js-tokens@10.0.0: {} js-tokens@4.0.0: {} @@ -4872,34 +5254,8 @@ snapshots: optionalDependencies: graceful-fs: 4.2.11 - lie@3.1.1: - dependencies: - immediate: 3.0.6 - lines-and-columns@1.2.4: {} - lint-staged@16.4.0: - dependencies: - commander: 14.0.3 - listr2: 9.0.5 - picomatch: 4.0.4 - string-argv: 0.3.2 - tinyexec: 1.2.4 - yaml: 2.9.0 - - listr2@9.0.5: - dependencies: - cli-truncate: 5.2.0 - colorette: 2.0.20 - eventemitter3: 5.0.4 - log-update: 6.1.0 - rfdc: 1.4.1 - wrap-ansi: 9.0.2 - - localforage@1.10.0: - dependencies: - lie: 3.1.1 - lodash.map@4.6.0: {} lodash.snakecase@4.1.1: {} @@ -4913,16 +5269,12 @@ snapshots: chalk: 4.1.2 is-unicode-supported: 0.1.0 - log-update@6.1.0: - dependencies: - ansi-escapes: 7.3.0 - cli-cursor: 5.0.0 - slice-ansi: 7.1.2 - strip-ansi: 7.2.0 - wrap-ansi: 9.0.2 + long@5.3.2: {} longest@2.0.1: {} + lru.min@1.1.4: {} + magic-bytes.js@1.13.0: {} magic-string@0.30.21: @@ -4964,6 +5316,24 @@ snapshots: mute-stream@0.0.8: {} + mysql2@3.15.3: + dependencies: + aws-ssl-profiles: 1.1.2 + denque: 2.1.0 + generate-function: 2.3.1 + iconv-lite: 0.7.2 + long: 5.3.2 + lru.min: 1.1.4 + named-placeholders: 1.1.6 + seq-queue: 0.0.5 + sqlstring: 2.3.3 + + named-placeholders@1.1.6: + dependencies: + lru.min: 1.1.4 + + nano-staged@1.0.2: {} + nanoid@3.3.12: {} node-fetch-native@1.6.7: {} @@ -4976,6 +5346,8 @@ snapshots: node-fetch-native: 1.6.7 ufo: 1.6.4 + ohash@2.0.11: {} + once@1.4.0: dependencies: wrappy: 1.0.2 @@ -5002,29 +5374,29 @@ snapshots: os-tmpdir@1.0.2: {} - oxfmt@0.51.0: + oxfmt@0.54.0: dependencies: tinypool: 2.1.0 optionalDependencies: - '@oxfmt/binding-android-arm-eabi': 0.51.0 - '@oxfmt/binding-android-arm64': 0.51.0 - '@oxfmt/binding-darwin-arm64': 0.51.0 - '@oxfmt/binding-darwin-x64': 0.51.0 - '@oxfmt/binding-freebsd-x64': 0.51.0 - '@oxfmt/binding-linux-arm-gnueabihf': 0.51.0 - '@oxfmt/binding-linux-arm-musleabihf': 0.51.0 - '@oxfmt/binding-linux-arm64-gnu': 0.51.0 - '@oxfmt/binding-linux-arm64-musl': 0.51.0 - '@oxfmt/binding-linux-ppc64-gnu': 0.51.0 - '@oxfmt/binding-linux-riscv64-gnu': 0.51.0 - '@oxfmt/binding-linux-riscv64-musl': 0.51.0 - '@oxfmt/binding-linux-s390x-gnu': 0.51.0 - '@oxfmt/binding-linux-x64-gnu': 0.51.0 - '@oxfmt/binding-linux-x64-musl': 0.51.0 - '@oxfmt/binding-openharmony-arm64': 0.51.0 - '@oxfmt/binding-win32-arm64-msvc': 0.51.0 - '@oxfmt/binding-win32-ia32-msvc': 0.51.0 - '@oxfmt/binding-win32-x64-msvc': 0.51.0 + '@oxfmt/binding-android-arm-eabi': 0.54.0 + '@oxfmt/binding-android-arm64': 0.54.0 + '@oxfmt/binding-darwin-arm64': 0.54.0 + '@oxfmt/binding-darwin-x64': 0.54.0 + '@oxfmt/binding-freebsd-x64': 0.54.0 + '@oxfmt/binding-linux-arm-gnueabihf': 0.54.0 + '@oxfmt/binding-linux-arm-musleabihf': 0.54.0 + '@oxfmt/binding-linux-arm64-gnu': 0.54.0 + '@oxfmt/binding-linux-arm64-musl': 0.54.0 + '@oxfmt/binding-linux-ppc64-gnu': 0.54.0 + '@oxfmt/binding-linux-riscv64-gnu': 0.54.0 + '@oxfmt/binding-linux-riscv64-musl': 0.54.0 + '@oxfmt/binding-linux-s390x-gnu': 0.54.0 + '@oxfmt/binding-linux-x64-gnu': 0.54.0 + '@oxfmt/binding-linux-x64-musl': 0.54.0 + '@oxfmt/binding-openharmony-arm64': 0.54.0 + '@oxfmt/binding-win32-arm64-msvc': 0.54.0 + '@oxfmt/binding-win32-ia32-msvc': 0.54.0 + '@oxfmt/binding-win32-x64-msvc': 0.54.0 oxlint@1.69.0: optionalDependencies: @@ -5065,11 +5437,13 @@ snapshots: path-is-absolute@1.0.1: {} + path-key@3.1.1: {} + path-parse@1.0.7: {} pathe@2.0.3: {} - peek-readable@5.4.2: {} + perfect-debounce@2.1.0: {} pg-int8@1.0.1: {} @@ -5089,6 +5463,12 @@ snapshots: picomatch@4.0.4: {} + pkg-types@2.3.1: + dependencies: + confbox: 0.2.4 + exsolve: 1.0.8 + pathe: 2.0.3 + pnpm-workspace-yaml@1.6.1: dependencies: yaml: 2.9.0 @@ -5109,33 +5489,54 @@ snapshots: dependencies: xtend: 4.0.2 - prettier@3.8.4: {} + postgres@3.4.7: {} - prisma@4.16.2: + prisma@7.8.0(@types/react@19.2.17)(magicast@0.5.3)(react-dom@19.2.7)(react@19.2.7)(typescript@6.0.3): dependencies: - '@prisma/engines': 4.16.2 + '@prisma/config': 7.8.0(magicast@0.5.3) + '@prisma/dev': 0.24.3(typescript@6.0.3) + '@prisma/engines': 7.8.0 + '@prisma/studio-core': 0.27.3(@types/react@19.2.17)(react-dom@19.2.7)(react@19.2.7) + mysql2: 3.15.3 + postgres: 3.4.7 + optionalDependencies: + typescript: 6.0.3 + transitivePeerDependencies: + - '@types/react' + - '@types/react-dom' + - magicast + - react + - react-dom - process@0.11.10: {} + proper-lockfile@4.1.2: + dependencies: + graceful-fs: 4.2.11 + retry: 0.12.0 + signal-exit: 3.0.7 + + pure-rand@6.1.0: {} quansync@1.0.0: {} + rc9@3.0.1: + dependencies: + defu: 6.1.7 + destr: 2.0.5 + + react-dom@19.2.7(react@19.2.7): + dependencies: + react: 19.2.7 + scheduler: 0.27.0 + + react@19.2.7: {} + readable-stream@3.6.2: dependencies: inherits: 2.0.4 string_decoder: 1.3.0 util-deprecate: 1.0.2 - readable-stream@4.7.0: - dependencies: - abort-controller: 3.0.0 - buffer: 6.0.3 - events: 3.3.0 - process: 0.11.10 - string_decoder: 1.3.0 - - readable-web-to-node-stream@3.0.4: - dependencies: - readable-stream: 4.7.0 + readdirp@5.0.0: {} redis-errors@1.2.0: {} @@ -5143,7 +5544,7 @@ snapshots: dependencies: redis-errors: 1.2.0 - require-directory@2.1.1: {} + remeda@2.33.4: {} require-from-string@2.0.2: {} @@ -5155,6 +5556,13 @@ snapshots: transitivePeerDependencies: - supports-color + require-in-the-middle@8.0.1: + dependencies: + debug: 4.4.3 + module-details-from-path: 1.0.4 + transitivePeerDependencies: + - supports-color + resolve-dir@1.0.1: dependencies: expand-tilde: 2.0.2 @@ -5183,23 +5591,7 @@ snapshots: onetime: 7.0.0 signal-exit: 4.1.0 - rfdc@1.4.1: {} - - rolldown-plugin-dts@0.25.2(rolldown@1.1.1)(typescript@4.9.5): - dependencies: - '@babel/generator': 8.0.0-rc.6 - '@babel/helper-validator-identifier': 8.0.0-rc.6 - '@babel/parser': 8.0.0-rc.6 - ast-kit: 3.0.0-beta.1 - birpc: 4.0.0 - dts-resolver: 3.0.0 - get-tsconfig: 5.0.0-beta.5 - obug: 2.1.2 - rolldown: 1.1.1 - optionalDependencies: - typescript: 4.9.5 - transitivePeerDependencies: - - oxc-resolver + retry@0.12.0: {} rolldown-plugin-dts@0.25.2(rolldown@1.1.1)(typescript@6.0.3): dependencies: @@ -5279,8 +5671,18 @@ snapshots: safer-buffer@2.1.2: {} + scheduler@0.27.0: {} + semver@7.8.4: {} + seq-queue@0.0.5: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + shimmer@1.2.1: {} siginfo@2.0.0: {} @@ -5289,25 +5691,17 @@ snapshots: signal-exit@4.1.0: {} - slice-ansi@7.1.2: - dependencies: - ansi-styles: 6.2.3 - is-fullwidth-code-point: 5.1.0 - - slice-ansi@8.0.0: - dependencies: - ansi-styles: 6.2.3 - is-fullwidth-code-point: 5.1.0 - source-map-js@1.2.1: {} + sqlstring@2.3.3: {} + stackback@0.0.2: {} standard-as-callback@2.1.0: {} - std-env@4.1.0: {} + std-env@3.10.0: {} - string-argv@0.3.2: {} + std-env@4.1.0: {} string-width@4.2.3: dependencies: @@ -5321,11 +5715,6 @@ snapshots: get-east-asian-width: 1.6.0 strip-ansi: 7.2.0 - string-width@8.2.1: - dependencies: - get-east-asian-width: 1.6.0 - strip-ansi: 7.2.0 - string_decoder@1.3.0: dependencies: safe-buffer: 5.2.1 @@ -5342,11 +5731,6 @@ snapshots: strip-json-comments@3.1.1: {} - strtok3@7.1.1: - dependencies: - '@tokenizer/token': 0.3.0 - peek-readable: 5.4.2 - supports-color@5.5.0: dependencies: has-flag: 3.0.0 @@ -5402,41 +5786,11 @@ snapshots: dependencies: is-number: 7.0.0 - token-types@5.0.1: - dependencies: - '@tokenizer/token': 0.3.0 - ieee754: 1.2.1 - tree-kill@1.2.2: {} ts-mixer@6.0.4: {} - tsdown@0.22.2(typescript@4.9.5): - dependencies: - ansis: 4.3.1 - cac: 7.0.0 - defu: 6.1.7 - empathic: 2.0.1 - hookable: 6.1.1 - import-without-cache: 0.4.0 - obug: 2.1.2 - picomatch: 4.0.4 - rolldown: 1.1.1 - rolldown-plugin-dts: 0.25.2(rolldown@1.1.1)(typescript@4.9.5) - semver: 7.8.4 - tinyexec: 1.2.4 - tinyglobby: 0.2.17 - tree-kill: 1.2.2 - unconfig-core: 7.5.0 - optionalDependencies: - typescript: 4.9.5 - transitivePeerDependencies: - - '@ts-macro/tsc' - - '@typescript/native-preview' - - oxc-resolver - - vue-tsc - - tsdown@0.22.2(typescript@6.0.3): + tsdown@0.22.0(typescript@6.0.3): dependencies: ansis: 4.3.1 cac: 7.0.0 @@ -5465,8 +5819,6 @@ snapshots: type-fest@0.21.3: {} - typescript@4.9.5: {} - typescript@5.4.5: {} typescript@6.0.3: {} @@ -5482,15 +5834,13 @@ snapshots: dependencies: '@quansync/fs': 1.0.0 defu: 6.1.7 - jiti: 2.6.1 + jiti: 2.7.0 quansync: 1.0.0 unconfig-core: 7.5.0 undici-types@6.21.0: {} - undici@5.29.0: - dependencies: - '@fastify/busboy': 2.1.1 + undici-types@7.18.2: {} undici@6.24.1: {} @@ -5498,7 +5848,11 @@ snapshots: util-deprecate@1.0.2: {} - vite@6.4.3(@types/node@22.19.21)(jiti@2.6.1)(yaml@2.9.0): + valibot@1.2.0(typescript@6.0.3): + optionalDependencies: + typescript: 6.0.3 + + vite@6.4.3(@types/node@24.13.2)(jiti@2.7.0)(yaml@2.9.0): dependencies: esbuild: 0.25.12 fdir: 6.5.0(picomatch@4.0.4) @@ -5507,12 +5861,12 @@ snapshots: rollup: 4.61.1 tinyglobby: 0.2.17 optionalDependencies: - '@types/node': 22.19.21 + '@types/node': 24.13.2 fsevents: 2.3.3 - jiti: 2.6.1 + jiti: 2.7.0 yaml: 2.9.0 - vitest@4.1.8(@opentelemetry/api@1.9.1)(@types/node@22.19.21)(@vitest/coverage-v8@4.1.8)(vite@6.4.3): + vitest@4.1.8(@opentelemetry/api@1.9.1)(@types/node@24.13.2)(@vitest/coverage-v8@4.1.8)(vite@6.4.3): dependencies: '@vitest/expect': 4.1.8 '@vitest/mocker': 4.1.8(vite@6.4.3) @@ -5532,11 +5886,11 @@ snapshots: tinyexec: 1.2.4 tinyglobby: 0.2.17 tinyrainbow: 3.1.0 - vite: 6.4.3(@types/node@22.19.21)(jiti@2.6.1)(yaml@2.9.0) + vite: 6.4.3(@types/node@24.13.2)(jiti@2.7.0)(yaml@2.9.0) why-is-node-running: 2.3.0 optionalDependencies: '@opentelemetry/api': 1.9.1 - '@types/node': 22.19.21 + '@types/node': 24.13.2 '@vitest/coverage-v8': 4.1.8(vitest@4.1.8) transitivePeerDependencies: - msw @@ -5549,6 +5903,10 @@ snapshots: dependencies: isexe: 2.0.0 + which@2.0.2: + dependencies: + isexe: 2.0.0 + why-is-node-running@2.3.0: dependencies: siginfo: 2.0.0 @@ -5578,14 +5936,18 @@ snapshots: yaml@2.9.0: {} - yargs-parser@21.1.1: {} + yargs-parser@22.0.0: {} - yargs@17.7.2: + yargs@18.0.0: dependencies: - cliui: 8.0.1 + cliui: 9.0.1 escalade: 3.2.0 get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.3 + string-width: 7.2.0 y18n: 5.0.8 - yargs-parser: 21.1.1 + yargs-parser: 22.0.0 + + zeptomatch@2.1.0: + dependencies: + grammex: 3.1.12 + graphmatch: 1.1.1 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index da4af6852..0b8cecdfe 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,21 +1,22 @@ packages: - - 'projects/*' + - 'projects/*' -ignoredBuiltDependencies: - - bufferutil - - zlib-sync - -onlyBuiltDependencies: - - '@prisma/client' - - '@prisma/engines' - - prisma +allowBuilds: + bufferutil: false + 'zlib-sync': false + '@prisma/client': true + '@prisma/engines': true + prisma: true + esbuild: false overrides: - ansi-regex: ^5.0.1 - discord-api-types: ^0.38.34 - minimist: ^1.2.6 - vite: ^6.3.5 + ansi-regex: ^5.0.1 + discord-api-types: ^0.38.34 + minimist: ^1.2.6 + vite: ^6.3.5 dedupePeers: true shellEmulator: true + +minimumReleaseAge: 0 diff --git a/prisma.config.ts b/prisma.config.ts index 90ae38b5a..4f77819c1 100644 --- a/prisma.config.ts +++ b/prisma.config.ts @@ -1,14 +1,13 @@ -import { config } from 'dotenv'; -import { defineConfig, env } from 'prisma/config'; - -config({ path: 'src/.env' }); +import { defineConfig } from "prisma/config"; +import "dotenv/config"; export default defineConfig({ - schema: 'prisma/schema.prisma', + schema: "projects/shared/src/lib/prisma/schema.prisma", migrations: { - path: 'prisma/migrations' + path: "projects/shared/src/lib/prisma/migrations", }, datasource: { - url: env('DATABASE_URL') - } + // Use process.env so non-Prisma tools (knip) can load this file without DATABASE_URL + url: process.env.DATABASE_URL ?? "", + }, }); diff --git a/projects/bot/package.json b/projects/bot/package.json index d4bf5081d..75a38c53e 100644 --- a/projects/bot/package.json +++ b/projects/bot/package.json @@ -21,13 +21,12 @@ }, "dependencies": { "@discordjs/builders": "^1.1.0", - "@discordjs/collection": "^1.0.1", - "@prisma/client": "^4.1.1", + "@discordjs/collection": "2.1.1", + "@prisma/client": "^7.8.0", "@sapphire/async-queue": "^1.3.2", "@sapphire/result": "^2.1.1", "@sapphire/utilities": "^3.8.0", - "@sentry/integrations": "^7.8.0", - "@sentry/node": "^7.8.0", + "@sentry/node": "^10.57.0", "@wolfstar/env-utilities": "^3.0.1", "@wolfstar/http-framework": "^3.0.1", "@wolfstar/http-framework-i18n": "^3.0.1", @@ -36,16 +35,16 @@ "@skyra/char": "^1.0.3", "@skyra/jaro-winkler": "^1.1.1", "colorette": "^2.0.19", - "discord-api-types": "^0.37.0", + "discord-api-types": "^0.38.48", "gradient-string": "^2.0.1", "wolfstar-shared": "workspace:^", "tslib": "^2.4.0" }, "devDependencies": { - "@rollup/plugin-alias": "latest", + "@rollup/plugin-alias": "6.0.0", "@sapphire/framework": "^4.5.0", "discord.js": "^14.14.1", - "tsdown": "latest", + "tsdown": "0.22.0", "typescript": "^6.0.0" } } diff --git a/projects/gateway/package.json b/projects/gateway/package.json index beb8e6fc9..0f23d3855 100644 --- a/projects/gateway/package.json +++ b/projects/gateway/package.json @@ -18,16 +18,16 @@ "start": "node --enable-source-maps dist/main.js" }, "dependencies": { - "@discordjs/rest": "^1.0.1", - "@discordjs/ws": "^0.2.0", - "@sapphire/utilities": "^3.8.0", + "@discordjs/rest": "^2.6.1", + "@discordjs/ws": "^2.0.4", + "@sapphire/utilities": "^3.18.2", "@wolfstar/env-utilities": "^3.0.1", "@wolfstar/start-banner": "^3.0.1", - "discord-api-types": "^0.37.0", + "discord-api-types": "^0.38.48", "gradient-string": "^2.0.1", "wolfstar-shared": "workspace:^" }, "devDependencies": { - "typescript": "^4.7.4" + "typescript": "^6.0.0" } } diff --git a/projects/shared/package.json b/projects/shared/package.json index ea343af93..584f4b4e9 100644 --- a/projects/shared/package.json +++ b/projects/shared/package.json @@ -29,11 +29,11 @@ "@sapphire/result": "^2.1.1", "@sapphire/utilities": "^3.8.0", "@vladfrangu/async_event_emitter": "^2.0.1", - "discord-api-types": "^0.37.0", + "discord-api-types": "^0.38.48", "ioredis": "^5.2.2", "ix": "^5.0.0" }, "devDependencies": { - "typescript": "^4.7.4" + "typescript": "^6.0.0" } } diff --git a/prisma/migrations/20240805115805_init/migration.sql b/projects/shared/src/lib/prisma/migrations/20240805115805_init/migration.sql similarity index 100% rename from prisma/migrations/20240805115805_init/migration.sql rename to projects/shared/src/lib/prisma/migrations/20240805115805_init/migration.sql diff --git a/prisma/migrations/20260416120000_add_dashboard_audit_log/migration.sql b/projects/shared/src/lib/prisma/migrations/20260416120000_add_dashboard_audit_log/migration.sql similarity index 100% rename from prisma/migrations/20260416120000_add_dashboard_audit_log/migration.sql rename to projects/shared/src/lib/prisma/migrations/20260416120000_add_dashboard_audit_log/migration.sql diff --git a/prisma/migrations/20260416130000_migrate_audit_log_to_audit_event/migration.sql b/projects/shared/src/lib/prisma/migrations/20260416130000_migrate_audit_log_to_audit_event/migration.sql similarity index 100% rename from prisma/migrations/20260416130000_migrate_audit_log_to_audit_event/migration.sql rename to projects/shared/src/lib/prisma/migrations/20260416130000_migrate_audit_log_to_audit_event/migration.sql diff --git a/prisma/migrations/20260516000000_add_channels_logs_command_settings/migration.sql b/projects/shared/src/lib/prisma/migrations/20260516000000_add_channels_logs_command_settings/migration.sql similarity index 100% rename from prisma/migrations/20260516000000_add_channels_logs_command_settings/migration.sql rename to projects/shared/src/lib/prisma/migrations/20260516000000_add_channels_logs_command_settings/migration.sql diff --git a/prisma/migrations/20260518000000_add_command_log/migration.sql b/projects/shared/src/lib/prisma/migrations/20260518000000_add_command_log/migration.sql similarity index 100% rename from prisma/migrations/20260518000000_add_command_log/migration.sql rename to projects/shared/src/lib/prisma/migrations/20260518000000_add_command_log/migration.sql diff --git a/prisma/migrations/20260520000000_update_command_log/migration.sql b/projects/shared/src/lib/prisma/migrations/20260520000000_update_command_log/migration.sql similarity index 100% rename from prisma/migrations/20260520000000_update_command_log/migration.sql rename to projects/shared/src/lib/prisma/migrations/20260520000000_update_command_log/migration.sql diff --git a/prisma/migrations/migration_lock.toml b/projects/shared/src/lib/prisma/migrations/migration_lock.toml similarity index 100% rename from prisma/migrations/migration_lock.toml rename to projects/shared/src/lib/prisma/migrations/migration_lock.toml diff --git a/prisma/schema.prisma b/projects/shared/src/lib/prisma/schema.prisma similarity index 100% rename from prisma/schema.prisma rename to projects/shared/src/lib/prisma/schema.prisma diff --git a/taze.config.ts b/taze.config.ts index 6f6a3c944..78f6550a2 100644 --- a/taze.config.ts +++ b/taze.config.ts @@ -8,13 +8,6 @@ export default defineConfig({ recursive: true, includeLocked: true, interactive: true, - packageMode: { - typescript: 'ignore', - '@prisma/client': 'ignore', - '@prisma/adapter-pg': 'ignore', - 'prisma-json-types-generator': 'ignore', - prisma: 'ignore' - }, depFields: { overrides: false } From 7cec4e728b24546b1d2b5fb7350a05e5dfc8fdbd Mon Sep 17 00:00:00 2001 From: RedStar Date: Fri, 12 Jun 2026 16:49:34 +0200 Subject: [PATCH 03/12] refactor: implement GatewayManagers and scoped managers for better organization - Introduced GatewayManagers to aggregate various entity managers (Guild, Channel, Member, etc.) for improved structure and maintainability. - Created individual managers (ChannelManager, EmojiManager, GuildManager, etc.) to handle specific actions (create, update, delete) for their respective entities. - Updated action handlers to utilize the new managers, streamlining the code and enhancing readability. - Adjusted TypeScript configurations and dependencies for better compatibility and performance. --- pnpm-lock.yaml | 2 +- projects/gateway/src/lib/Client.ts | 3 + .../gateway/src/lib/actions/ChannelCreate.ts | 5 +- .../gateway/src/lib/actions/ChannelDelete.ts | 5 +- .../gateway/src/lib/actions/ChannelUpdate.ts | 6 +- .../gateway/src/lib/actions/GuildCreate.ts | 24 +--- .../gateway/src/lib/actions/GuildDelete.ts | 5 +- .../src/lib/actions/GuildEmojisUpdate.ts | 36 +----- .../gateway/src/lib/actions/GuildMemberAdd.ts | 5 +- .../src/lib/actions/GuildMemberRemove.ts | 11 +- .../src/lib/actions/GuildMemberUpdate.ts | 13 +- .../src/lib/actions/GuildMembersChunk.ts | 7 +- .../src/lib/actions/GuildRoleCreate.ts | 5 +- .../src/lib/actions/GuildRoleDelete.ts | 11 +- .../src/lib/actions/GuildRoleUpdate.ts | 6 +- .../src/lib/actions/GuildStickersUpdate.ts | 36 +----- .../gateway/src/lib/actions/GuildUpdate.ts | 7 +- .../gateway/src/lib/actions/MessageCreate.ts | 5 +- .../gateway/src/lib/actions/MessageDelete.ts | 13 +- .../src/lib/actions/MessageDeleteBulk.ts | 12 +- .../gateway/src/lib/actions/MessageUpdate.ts | 11 +- .../src/lib/managers/BaseScopedManager.ts | 38 ++++++ .../src/lib/managers/ChannelManager.ts | 38 ++++++ .../gateway/src/lib/managers/EmojiManager.ts | 31 +++++ .../src/lib/managers/GatewayManagers.ts | 33 +++++ .../gateway/src/lib/managers/GuildManager.ts | 77 +++++++++++ .../gateway/src/lib/managers/MemberManager.ts | 57 +++++++++ .../src/lib/managers/MessageManager.ts | 47 +++++++ .../gateway/src/lib/managers/RoleManager.ts | 31 +++++ .../src/lib/managers/StickerManager.ts | 31 +++++ .../gateway/src/listeners/ws/dispatch.mts | 3 +- projects/gateway/src/listeners/ws/ready.mts | 4 +- projects/gateway/src/listeners/ws/resumed.mts | 4 +- projects/gateway/src/tsconfig.json | 3 +- projects/shared/src/index.ts | 2 + projects/shared/src/lib/cache/CacheGuilds.ts | 32 +++++ .../src/lib/cache/base/HashScopedCache.ts | 50 +++++++- .../shared/src/lib/cache/interfaces/ICache.ts | 71 ++++++++++ .../shared/src/lib/cache/structures/Guild.ts | 8 +- .../shared/src/lib/cache/structures/Member.ts | 13 +- .../src/lib/cache/structures/Message.ts | 5 + .../shared/src/lib/cache/structures/Role.ts | 2 + .../shared/src/lib/cache/structures/User.ts | 62 +++++++++ .../interfaces/IStructureCreator.ts | 19 +++ .../unions/channel/GuildThreadChannel.ts | 3 +- .../unions/channel/GuildVoiceChannel.ts | 5 +- .../unions/channel/base/GuildBasedChannel.ts | 12 +- .../channel/base/GuildTextBasedChannel.ts | 1 + .../cache/structures/values/GuildFeatures.ts | 2 +- .../shared/src/lib/structures/Listener.ts | 1 + .../src/lib/structures/ListenerStore.ts | 3 +- .../tests/lib/cache/HashScopedCache.test.ts | 121 ++++++++++++++++++ tsconfig.base.json | 4 +- 53 files changed, 824 insertions(+), 217 deletions(-) create mode 100644 projects/gateway/src/lib/managers/BaseScopedManager.ts create mode 100644 projects/gateway/src/lib/managers/ChannelManager.ts create mode 100644 projects/gateway/src/lib/managers/EmojiManager.ts create mode 100644 projects/gateway/src/lib/managers/GatewayManagers.ts create mode 100644 projects/gateway/src/lib/managers/GuildManager.ts create mode 100644 projects/gateway/src/lib/managers/MemberManager.ts create mode 100644 projects/gateway/src/lib/managers/MessageManager.ts create mode 100644 projects/gateway/src/lib/managers/RoleManager.ts create mode 100644 projects/gateway/src/lib/managers/StickerManager.ts create mode 100644 projects/shared/src/lib/cache/interfaces/ICache.ts create mode 100644 projects/shared/src/lib/cache/structures/User.ts create mode 100644 projects/shared/src/lib/cache/structures/interfaces/IStructureCreator.ts create mode 100644 projects/shared/tests/lib/cache/HashScopedCache.test.ts diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a3ac473d3..7ca006790 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -58,7 +58,7 @@ importers: specifier: ^6.0.3 version: 6.0.3 vite: - specifier: ^6.4.3 + specifier: ^6.3.5 version: 6.4.3(@types/node@24.13.2)(jiti@2.7.0)(yaml@2.9.0) vitest: specifier: ^4.1.8 diff --git a/projects/gateway/src/lib/Client.ts b/projects/gateway/src/lib/Client.ts index f04ff41ee..51d99b064 100644 --- a/projects/gateway/src/lib/Client.ts +++ b/projects/gateway/src/lib/Client.ts @@ -1,3 +1,4 @@ +import { GatewayManagers } from '#lib/managers/GatewayManagers'; import { REST, RESTOptions } from '@discordjs/rest'; import { OptionalWebSocketManagerOptions, RequiredWebSocketManagerOptions, WebSocketManager } from '@discordjs/ws'; import { envParseInteger, envParseString } from '@wolfstar/env-utilities'; @@ -30,6 +31,7 @@ export function createClient(options: ClientOptions) { block: envParseInteger('BROKER_BLOCK', 5000), max: envParseInteger('BROKER_MAX', 10) }); + container.managers = new GatewayManagers(container.cache, container.broker, container.rest); container.stores.register(new ListenerStore()); } @@ -50,6 +52,7 @@ declare module '@sapphire/pieces' { interface Container { broker: MessageBroker; cache: Cache; + managers: GatewayManagers; redis: Redis; rest: REST; ws: WebSocketManager; diff --git a/projects/gateway/src/lib/actions/ChannelCreate.ts b/projects/gateway/src/lib/actions/ChannelCreate.ts index 86c8735eb..29ea14283 100644 --- a/projects/gateway/src/lib/actions/ChannelCreate.ts +++ b/projects/gateway/src/lib/actions/ChannelCreate.ts @@ -1,11 +1,10 @@ import { isNullish } from '@sapphire/utilities'; import type { GatewayChannelCreateDispatchData } from 'discord-api-types/v10'; -import { Channel, container, RedisMessageType } from 'wolfstar-shared'; +import { container } from 'wolfstar-shared'; export async function handleChannelCreate(payload: GatewayChannelCreateDispatchData) { if (!('guild_id' in payload)) return; if (isNullish(payload.guild_id)) return; - await container.cache.channels.set(payload.guild_id, Channel.fromAPI(payload)); - await container.broker.send({ type: RedisMessageType.ChannelCreate, data: payload }); + await container.managers.channels.handleCreate(payload.guild_id, payload); } diff --git a/projects/gateway/src/lib/actions/ChannelDelete.ts b/projects/gateway/src/lib/actions/ChannelDelete.ts index 126e81dc4..8c655c1b5 100644 --- a/projects/gateway/src/lib/actions/ChannelDelete.ts +++ b/projects/gateway/src/lib/actions/ChannelDelete.ts @@ -1,11 +1,10 @@ import { isNullish } from '@sapphire/utilities'; import type { GatewayChannelDeleteDispatchData } from 'discord-api-types/v10'; -import { container, RedisMessageType } from 'wolfstar-shared'; +import { container } from 'wolfstar-shared'; export async function handleChannelDelete(payload: GatewayChannelDeleteDispatchData) { if (!('guild_id' in payload)) return; if (isNullish(payload.guild_id)) return; - await container.cache.channels.remove(payload.guild_id, payload.id); - await container.broker.send({ type: RedisMessageType.ChannelDelete, old: payload }); + await container.managers.channels.handleDelete(payload.guild_id, payload); } diff --git a/projects/gateway/src/lib/actions/ChannelUpdate.ts b/projects/gateway/src/lib/actions/ChannelUpdate.ts index 5aac9d742..7bd7f75e1 100644 --- a/projects/gateway/src/lib/actions/ChannelUpdate.ts +++ b/projects/gateway/src/lib/actions/ChannelUpdate.ts @@ -1,12 +1,10 @@ import { isNullish } from '@sapphire/utilities'; import type { GatewayChannelUpdateDispatchData } from 'discord-api-types/v10'; -import { Channel, container, RedisMessageType } from 'wolfstar-shared'; +import { container } from 'wolfstar-shared'; export async function handleChannelUpdate(payload: GatewayChannelUpdateDispatchData) { if (!('guild_id' in payload)) return; if (isNullish(payload.guild_id)) return; - const old = (await container.cache.channels.get(payload.guild_id, payload.id))?.toJSON() ?? null; - await container.cache.channels.set(payload.guild_id, Channel.fromAPI(payload)); - await container.broker.send({ type: RedisMessageType.ChannelUpdate, old, data: payload }); + await container.managers.channels.handleUpdate(payload.guild_id, payload); } diff --git a/projects/gateway/src/lib/actions/GuildCreate.ts b/projects/gateway/src/lib/actions/GuildCreate.ts index ab51179d7..54fd0699b 100644 --- a/projects/gateway/src/lib/actions/GuildCreate.ts +++ b/projects/gateway/src/lib/actions/GuildCreate.ts @@ -1,26 +1,6 @@ import type { GatewayGuildCreateDispatchData } from 'discord-api-types/v10'; -import { Channel, container, Emoji, Guild, Member, Role, Sticker } from 'wolfstar-shared'; +import { container } from 'wolfstar-shared'; export async function handleGuildCreate(payload: GatewayGuildCreateDispatchData) { - await container.cache.guilds.set(Guild.fromAPI(payload)); - await container.cache.emojis.set( - payload.id, - payload.emojis.map((emoji) => Emoji.fromAPI(emoji)) - ); - await container.cache.channels.set( - payload.id, - payload.channels.map((entry) => Channel.fromAPI(entry)) - ); - await container.cache.members.set( - payload.id, - payload.members.map((entry) => Member.fromAPI(entry)) - ); - await container.cache.roles.set( - payload.id, - payload.roles.map((emoji) => Role.fromAPI(emoji)) - ); - await container.cache.stickers.set( - payload.id, - payload.stickers.map((emoji) => Sticker.fromAPI(emoji)) - ); + await container.managers.guilds.handleCreate(payload); } diff --git a/projects/gateway/src/lib/actions/GuildDelete.ts b/projects/gateway/src/lib/actions/GuildDelete.ts index 992f6ce8d..9e6e38c49 100644 --- a/projects/gateway/src/lib/actions/GuildDelete.ts +++ b/projects/gateway/src/lib/actions/GuildDelete.ts @@ -2,8 +2,5 @@ import type { GatewayGuildDeleteDispatchData } from 'discord-api-types/v10'; import { container } from 'wolfstar-shared'; export async function handleGuildDelete(payload: GatewayGuildDeleteDispatchData) { - for (const channelId of await container.cache.channels.keys(payload.id)) { - await container.cache.messages.clear(channelId); - } - await container.cache.guilds.remove(payload.id); + await container.managers.guilds.handleDelete(payload); } diff --git a/projects/gateway/src/lib/actions/GuildEmojisUpdate.ts b/projects/gateway/src/lib/actions/GuildEmojisUpdate.ts index fe1aa629c..818bcbf80 100644 --- a/projects/gateway/src/lib/actions/GuildEmojisUpdate.ts +++ b/projects/gateway/src/lib/actions/GuildEmojisUpdate.ts @@ -1,38 +1,6 @@ -import { isNullish } from '@sapphire/utilities'; import type { GatewayGuildEmojisUpdateDispatchData } from 'discord-api-types/v10'; -import { container, Emoji, RedisMessageType } from 'wolfstar-shared'; +import { container } from 'wolfstar-shared'; export async function handleGuildEmojisUpdate(payload: GatewayGuildEmojisUpdateDispatchData) { - const oldEntries = await container.cache.emojis.entries(payload.guild_id); - - for (const emoji of payload.emojis) { - const updated = Emoji.fromAPI(emoji); - const old = oldEntries.get(updated.id); - - if (isNullish(old)) { - // A new emoji has been created: - await container.cache.emojis.set(payload.guild_id, updated); - await container.broker.send({ type: RedisMessageType.EmojiCreate, data: emoji, guild_id: payload.guild_id }); - } else if (!updated.equals(old)) { - // An emoji has been updated: - await container.cache.emojis.set(payload.guild_id, updated); - await container.broker.send({ type: RedisMessageType.EmojiUpdate, old: old.toJSON(), data: emoji, guild_id: payload.guild_id }); - } - - // Remove the processed entry from the retrieved map, as the current - // entry is a created, updated, or untouched one. - // - // The remaining entries will be deleted ones, so this operation comes - // handy to create a fast emoji deletion dispatch. - // - // On a side note, this does not mutate the actual cache, which is in - // Redis. - oldEntries.delete(updated.id); - } - - // Process deleted entries: - await container.cache.emojis.remove(payload.guild_id, [...oldEntries.keys()]); - for (const emoji of oldEntries.values()) { - await container.broker.send({ type: RedisMessageType.EmojiDelete, old: emoji.toJSON(), guild_id: payload.guild_id }); - } + await container.managers.emojis.handleUpdate(payload); } diff --git a/projects/gateway/src/lib/actions/GuildMemberAdd.ts b/projects/gateway/src/lib/actions/GuildMemberAdd.ts index 1329fa24c..090ce1ed3 100644 --- a/projects/gateway/src/lib/actions/GuildMemberAdd.ts +++ b/projects/gateway/src/lib/actions/GuildMemberAdd.ts @@ -1,7 +1,6 @@ import type { GatewayGuildMemberAddDispatchData } from 'discord-api-types/v10'; -import { container, Member, RedisMessageType } from 'wolfstar-shared'; +import { container } from 'wolfstar-shared'; export async function handleGuildMemberAdd(payload: GatewayGuildMemberAddDispatchData) { - await container.cache.members.set(payload.guild_id, Member.fromAPI(payload)); - await container.broker.send({ type: RedisMessageType.MemberAdd, data: payload }); + await container.managers.members.handleAdd(payload); } diff --git a/projects/gateway/src/lib/actions/GuildMemberRemove.ts b/projects/gateway/src/lib/actions/GuildMemberRemove.ts index 71e0c2ad7..8e5bcc6c7 100644 --- a/projects/gateway/src/lib/actions/GuildMemberRemove.ts +++ b/projects/gateway/src/lib/actions/GuildMemberRemove.ts @@ -1,13 +1,6 @@ -import { isNullish } from '@sapphire/utilities'; import type { GatewayGuildMemberRemoveDispatchData } from 'discord-api-types/v10'; -import { container, RedisMessageType } from 'wolfstar-shared'; +import { container } from 'wolfstar-shared'; export async function handleGuildMemberRemove(payload: GatewayGuildMemberRemoveDispatchData) { - const old = await container.cache.members.get(payload.guild_id, payload.user.id); - if (isNullish(old)) { - await container.broker.send({ type: RedisMessageType.MemberRemove, old: null, user: payload.user, guild_id: payload.guild_id }); - } else { - await container.cache.members.remove(payload.guild_id, old.id); - await container.broker.send({ type: RedisMessageType.MemberRemove, old: old.toJSON(), user: payload.user, guild_id: payload.guild_id }); - } + await container.managers.members.handleRemove(payload); } diff --git a/projects/gateway/src/lib/actions/GuildMemberUpdate.ts b/projects/gateway/src/lib/actions/GuildMemberUpdate.ts index fda424ad3..342b8985e 100644 --- a/projects/gateway/src/lib/actions/GuildMemberUpdate.ts +++ b/projects/gateway/src/lib/actions/GuildMemberUpdate.ts @@ -1,15 +1,6 @@ -import { isNullish } from '@sapphire/utilities'; import type { GatewayGuildMemberUpdateDispatchData } from 'discord-api-types/v10'; -import { container, Member, RedisMessageType } from 'wolfstar-shared'; +import { container } from 'wolfstar-shared'; export async function handleGuildMemberUpdate(payload: GatewayGuildMemberUpdateDispatchData) { - const old = await container.cache.members.get(payload.guild_id, payload.user.id); - if (isNullish(old)) { - await container.cache.members.set(payload.guild_id, Member.fromAPI(payload)); - await container.broker.send({ type: RedisMessageType.MemberUpdate, old: null, data: payload }); - } else { - const data = old.patch(payload); - await container.cache.members.set(payload.guild_id, data); - await container.broker.send({ type: RedisMessageType.MemberUpdate, old: old.toJSON(), data: data.toJSON() }); - } + await container.managers.members.handleUpdate(payload); } diff --git a/projects/gateway/src/lib/actions/GuildMembersChunk.ts b/projects/gateway/src/lib/actions/GuildMembersChunk.ts index 1b919580c..c0d5e5b25 100644 --- a/projects/gateway/src/lib/actions/GuildMembersChunk.ts +++ b/projects/gateway/src/lib/actions/GuildMembersChunk.ts @@ -1,9 +1,6 @@ import type { GatewayGuildMembersChunkDispatchData } from 'discord-api-types/v10'; -import { container, Member } from 'wolfstar-shared'; +import { container } from 'wolfstar-shared'; export async function handleGuildMembersChunk(payload: GatewayGuildMembersChunkDispatchData) { - await container.cache.members.set( - payload.guild_id, - payload.members.map((data) => Member.fromAPI(data)) - ); + await container.managers.members.handleChunk(payload); } diff --git a/projects/gateway/src/lib/actions/GuildRoleCreate.ts b/projects/gateway/src/lib/actions/GuildRoleCreate.ts index ea6274bae..96f869ec4 100644 --- a/projects/gateway/src/lib/actions/GuildRoleCreate.ts +++ b/projects/gateway/src/lib/actions/GuildRoleCreate.ts @@ -1,7 +1,6 @@ import type { GatewayGuildRoleCreateDispatchData } from 'discord-api-types/v10'; -import { container, RedisMessageType, Role } from 'wolfstar-shared'; +import { container } from 'wolfstar-shared'; export async function handleGuildRoleCreate(payload: GatewayGuildRoleCreateDispatchData) { - await container.cache.roles.set(payload.guild_id, Role.fromAPI(payload.role)); - await container.broker.send({ type: RedisMessageType.RoleCreate, data: payload.role, guild_id: payload.guild_id }); + await container.managers.roles.handleCreate(payload); } diff --git a/projects/gateway/src/lib/actions/GuildRoleDelete.ts b/projects/gateway/src/lib/actions/GuildRoleDelete.ts index d589f1d07..0fd09e968 100644 --- a/projects/gateway/src/lib/actions/GuildRoleDelete.ts +++ b/projects/gateway/src/lib/actions/GuildRoleDelete.ts @@ -1,13 +1,6 @@ -import { isNullish } from '@sapphire/utilities'; import type { GatewayGuildRoleDeleteDispatchData } from 'discord-api-types/v10'; -import { container, RedisMessageType } from 'wolfstar-shared'; +import { container } from 'wolfstar-shared'; export async function handleGuildRoleDelete(payload: GatewayGuildRoleDeleteDispatchData) { - const old = await container.cache.roles.get(payload.guild_id, payload.role_id); - if (isNullish(old)) { - await container.broker.send({ type: RedisMessageType.RoleDelete, old: { id: payload.role_id }, guild_id: payload.guild_id }); - } else { - await container.cache.roles.remove(payload.guild_id, old.id); - await container.broker.send({ type: RedisMessageType.RoleDelete, old: old.toJSON(), guild_id: payload.guild_id }); - } + await container.managers.roles.handleDelete(payload); } diff --git a/projects/gateway/src/lib/actions/GuildRoleUpdate.ts b/projects/gateway/src/lib/actions/GuildRoleUpdate.ts index 62b7e44b9..d70204aa0 100644 --- a/projects/gateway/src/lib/actions/GuildRoleUpdate.ts +++ b/projects/gateway/src/lib/actions/GuildRoleUpdate.ts @@ -1,8 +1,6 @@ import type { GatewayGuildRoleUpdateDispatchData } from 'discord-api-types/v10'; -import { container, RedisMessageType, Role } from 'wolfstar-shared'; +import { container } from 'wolfstar-shared'; export async function handleGuildRoleUpdate(payload: GatewayGuildRoleUpdateDispatchData) { - const old = await container.cache.roles.get(payload.guild_id, payload.role.id); - await container.cache.roles.set(payload.guild_id, Role.fromAPI(payload.role)); - await container.broker.send({ type: RedisMessageType.RoleUpdate, old: old?.toJSON() ?? null, data: payload.role, guild_id: payload.guild_id }); + await container.managers.roles.handleUpdate(payload); } diff --git a/projects/gateway/src/lib/actions/GuildStickersUpdate.ts b/projects/gateway/src/lib/actions/GuildStickersUpdate.ts index a4cd26a97..a4f10bb70 100644 --- a/projects/gateway/src/lib/actions/GuildStickersUpdate.ts +++ b/projects/gateway/src/lib/actions/GuildStickersUpdate.ts @@ -1,38 +1,6 @@ -import { isNullish } from '@sapphire/utilities'; import type { GatewayGuildStickersUpdateDispatchData } from 'discord-api-types/v10'; -import { container, RedisMessageType, Sticker } from 'wolfstar-shared'; +import { container } from 'wolfstar-shared'; export async function handleGuildStickersUpdate(payload: GatewayGuildStickersUpdateDispatchData) { - const oldEntries = await container.cache.stickers.entries(payload.guild_id); - - for (const sticker of payload.stickers) { - const updated = Sticker.fromAPI(sticker); - const old = oldEntries.get(updated.id); - - if (isNullish(old)) { - // A new sticker has been created: - await container.cache.stickers.set(payload.guild_id, updated); - await container.broker.send({ type: RedisMessageType.StickerCreate, data: sticker, guild_id: payload.guild_id }); - } else if (!updated.equals(old)) { - // A sticker has been updated: - await container.cache.stickers.set(payload.guild_id, updated); - await container.broker.send({ type: RedisMessageType.StickerUpdate, old: old.toJSON(), data: sticker, guild_id: payload.guild_id }); - } - - // Remove the processed entry from the retrieved map, as the current - // entry is a created, updated, or untouched one. - // - // The remaining entries will be deleted ones, so this operation comes - // handy to create a fast sticker deletion dispatch. - // - // On a side note, this does not mutate the actual cache, which is in - // Redis. - oldEntries.delete(updated.id); - } - - // Process deleted entries: - await container.cache.stickers.remove(payload.guild_id, [...oldEntries.keys()]); - for (const sticker of oldEntries.values()) { - await container.broker.send({ type: RedisMessageType.StickerDelete, old: sticker.toJSON(), guild_id: payload.guild_id }); - } + await container.managers.stickers.handleUpdate(payload); } diff --git a/projects/gateway/src/lib/actions/GuildUpdate.ts b/projects/gateway/src/lib/actions/GuildUpdate.ts index 1349b12da..f5cb73fac 100644 --- a/projects/gateway/src/lib/actions/GuildUpdate.ts +++ b/projects/gateway/src/lib/actions/GuildUpdate.ts @@ -1,9 +1,6 @@ import type { GatewayGuildUpdateDispatchData } from 'discord-api-types/v10'; -import { container, Guild, RedisMessageType } from 'wolfstar-shared'; +import { container } from 'wolfstar-shared'; export async function handleGuildUpdate(payload: GatewayGuildUpdateDispatchData) { - const old = await container.cache.guilds.get(payload.id); - const data = Guild.fromAPI(payload); - await container.cache.guilds.set(data); - await container.broker.send({ type: RedisMessageType.GuildUpdate, old: old?.toJSON() ?? null, data: data.toJSON() }); + await container.managers.guilds.handleUpdate(payload); } diff --git a/projects/gateway/src/lib/actions/MessageCreate.ts b/projects/gateway/src/lib/actions/MessageCreate.ts index 934007283..afec23385 100644 --- a/projects/gateway/src/lib/actions/MessageCreate.ts +++ b/projects/gateway/src/lib/actions/MessageCreate.ts @@ -1,11 +1,10 @@ import { isNullish } from '@sapphire/utilities'; import type { GatewayMessageCreateDispatchData } from 'discord-api-types/v10'; -import { container, Message, RedisMessageType } from 'wolfstar-shared'; +import { container } from 'wolfstar-shared'; export async function handleMessageCreate(payload: GatewayMessageCreateDispatchData) { if (!('guild_id' in payload)) return; if (isNullish(payload.guild_id)) return; - await container.cache.messages.set(payload.channel_id, Message.fromAPI(payload)); - await container.broker.send({ type: RedisMessageType.MessageCreate, data: payload }); + await container.managers.messages.handleCreate(payload); } diff --git a/projects/gateway/src/lib/actions/MessageDelete.ts b/projects/gateway/src/lib/actions/MessageDelete.ts index b1f580683..013a84c41 100644 --- a/projects/gateway/src/lib/actions/MessageDelete.ts +++ b/projects/gateway/src/lib/actions/MessageDelete.ts @@ -1,19 +1,10 @@ import { isNullish } from '@sapphire/utilities'; import type { GatewayMessageDeleteDispatchData } from 'discord-api-types/v10'; -import { container, RedisMessageType } from 'wolfstar-shared'; +import { container } from 'wolfstar-shared'; export async function handleMessageDelete(payload: GatewayMessageDeleteDispatchData) { if (!('guild_id' in payload)) return; if (isNullish(payload.guild_id)) return; - const old = await container.cache.messages.get(payload.channel_id, payload.id); - if (isNullish(old)) { - await container.broker.send({ - type: RedisMessageType.MessageDelete, - old: { id: payload.id, channel_id: payload.channel_id, guild_id: payload.guild_id } - }); - } else { - await container.cache.messages.remove(payload.channel_id, payload.id); - await container.broker.send({ type: RedisMessageType.MessageDelete, old: old.toJSON() }); - } + await container.managers.messages.handleDelete(payload.guild_id, payload); } diff --git a/projects/gateway/src/lib/actions/MessageDeleteBulk.ts b/projects/gateway/src/lib/actions/MessageDeleteBulk.ts index 69576c543..f822d26b0 100644 --- a/projects/gateway/src/lib/actions/MessageDeleteBulk.ts +++ b/projects/gateway/src/lib/actions/MessageDeleteBulk.ts @@ -1,18 +1,10 @@ import { isNullish } from '@sapphire/utilities'; import type { GatewayMessageDeleteBulkDispatchData } from 'discord-api-types/v10'; -import { container, RedisMessageType } from 'wolfstar-shared'; +import { container } from 'wolfstar-shared'; export async function handleMessageDeleteBulk(payload: GatewayMessageDeleteBulkDispatchData) { if (!('guild_id' in payload)) return; if (isNullish(payload.guild_id)) return; - const entries = await container.cache.messages.get(payload.channel_id, payload.ids); - await container.cache.messages.remove(payload.channel_id, payload.ids); - - await container.broker.send({ - type: RedisMessageType.MessageDeleteBulk, - old: payload.ids.map((id) => entries.get(BigInt(id))?.toJSON() ?? { id }), - channel_id: payload.channel_id, - guild_id: payload.guild_id - }); + await container.managers.messages.handleDeleteBulk(payload.guild_id, payload); } diff --git a/projects/gateway/src/lib/actions/MessageUpdate.ts b/projects/gateway/src/lib/actions/MessageUpdate.ts index d3ac1cf4d..071018f5d 100644 --- a/projects/gateway/src/lib/actions/MessageUpdate.ts +++ b/projects/gateway/src/lib/actions/MessageUpdate.ts @@ -1,17 +1,10 @@ import { isNullish } from '@sapphire/utilities'; import type { GatewayMessageUpdateDispatchData } from 'discord-api-types/v10'; -import { container, Message, RedisMessageType } from 'wolfstar-shared'; +import { container } from 'wolfstar-shared'; export async function handleMessageUpdate(payload: GatewayMessageUpdateDispatchData) { if (!('guild_id' in payload)) return; if (isNullish(payload.guild_id)) return; - const old = await container.cache.messages.get(payload.guild_id, payload.id); - if (isNullish(old)) { - await container.cache.messages.set(payload.guild_id, Message.fromAPI(payload as any)); - await container.broker.send({ type: RedisMessageType.MessageUpdate, old: null, data: payload }); - } else { - await container.cache.messages.set(payload.guild_id, old.patch(payload)); - await container.broker.send({ type: RedisMessageType.MessageUpdate, old: old.toJSON(), data: payload }); - } + await container.managers.messages.handleUpdate(payload); } diff --git a/projects/gateway/src/lib/managers/BaseScopedManager.ts b/projects/gateway/src/lib/managers/BaseScopedManager.ts new file mode 100644 index 000000000..12e96a831 --- /dev/null +++ b/projects/gateway/src/lib/managers/BaseScopedManager.ts @@ -0,0 +1,38 @@ +import type { REST } from '@discordjs/rest'; +import type { NonNullObject } from '@sapphire/utilities'; +import type { HashScopedCache, IStructure, MessageBroker, ScopedCache } from 'wolfstar-shared'; + +/** + * Base class for guild-scoped managers, mirroring the discord.js + * `CachedManager` pattern (discordjs/discord.js#11426) on top of wolfstar's + * Redis-backed {@link HashScopedCache}. + * + * A manager owns the cache and message-broker interaction for a single entity + * type, keeping the WebSocket action handlers thin. + */ +export abstract class BaseScopedManager { + public constructor( + public readonly cache: HashScopedCache, + protected readonly broker: MessageBroker, + protected readonly rest?: REST + ) {} + + /** + * Stores `data` in the cache, returning both the previously cached value (if + * any) and the resulting structure. When `overwrite` is `false`, an existing + * entry is patched rather than replaced. + */ + protected async upsert(parentId: ScopedCache.Snowflake, data: NonNullObject, overwrite = false): Promise> { + const id = this.cache.structure.getId?.(data) ?? BigInt((data as { id: ScopedCache.Snowflake }).id); + const old = overwrite ? null : await this.cache.get(parentId, id); + const value = await this.cache.add(parentId, data, overwrite); + return { old, value }; + } +} + +export namespace BaseScopedManager { + export interface AddResult { + old: T | null; + value: T; + } +} diff --git a/projects/gateway/src/lib/managers/ChannelManager.ts b/projects/gateway/src/lib/managers/ChannelManager.ts new file mode 100644 index 000000000..eb487f4af --- /dev/null +++ b/projects/gateway/src/lib/managers/ChannelManager.ts @@ -0,0 +1,38 @@ +import { BaseScopedManager } from './BaseScopedManager'; +import { isNullish } from '@sapphire/utilities'; +import { Routes, type APIChannel, type Snowflake } from 'discord-api-types/v10'; +import { Channel, type FetchOptions, RedisMessageType } from 'wolfstar-shared'; + +export class ChannelManager extends BaseScopedManager { + public async handleCreate(guildId: Snowflake, data: APIChannel) { + await this.cache.set(guildId, Channel.fromAPI(data)); + await this.broker.send({ type: RedisMessageType.ChannelCreate, data }); + } + + public async handleUpdate(guildId: Snowflake, data: APIChannel) { + const old = (await this.cache.get(guildId, data.id))?.toJSON() ?? null; + await this.cache.set(guildId, Channel.fromAPI(data)); + await this.broker.send({ type: RedisMessageType.ChannelUpdate, old, data }); + } + + public async handleDelete(guildId: Snowflake, data: APIChannel) { + await this.cache.remove(guildId, data.id); + await this.broker.send({ type: RedisMessageType.ChannelDelete, old: data }); + } + + /** + * Fetches a channel, hitting the cache first unless `force` is set. + */ + public async fetch(guildId: Snowflake, channelId: Snowflake, options: FetchOptions = {}): Promise { + const { force = false, cache = true } = options; + if (!force) { + const cached = await this.cache.get(guildId, channelId); + if (!isNullish(cached)) return cached; + } + + if (isNullish(this.rest)) throw new Error('The REST client is not available to this manager.'); + const data = (await this.rest.get(Routes.channel(channelId))) as APIChannel; + if (!cache) return Channel.fromAPI(data); + return this.cache.add(guildId, data, true); + } +} diff --git a/projects/gateway/src/lib/managers/EmojiManager.ts b/projects/gateway/src/lib/managers/EmojiManager.ts new file mode 100644 index 000000000..6ee9388ee --- /dev/null +++ b/projects/gateway/src/lib/managers/EmojiManager.ts @@ -0,0 +1,31 @@ +import { BaseScopedManager } from './BaseScopedManager'; +import { isNullish } from '@sapphire/utilities'; +import type { GatewayGuildEmojisUpdateDispatchData } from 'discord-api-types/v10'; +import { Emoji, RedisMessageType } from 'wolfstar-shared'; + +export class EmojiManager extends BaseScopedManager { + public async handleUpdate(payload: GatewayGuildEmojisUpdateDispatchData) { + const oldEntries = await this.cache.entries(payload.guild_id); + + for (const emoji of payload.emojis) { + const updated = Emoji.fromAPI(emoji); + const old = oldEntries.get(updated.id); + + if (isNullish(old)) { + await this.cache.set(payload.guild_id, updated); + await this.broker.send({ type: RedisMessageType.EmojiCreate, data: emoji, guild_id: payload.guild_id }); + } else if (!updated.equals(old)) { + await this.cache.set(payload.guild_id, updated); + await this.broker.send({ type: RedisMessageType.EmojiUpdate, old: old.toJSON(), data: emoji, guild_id: payload.guild_id }); + } + + // Drop processed entries; whatever remains was deleted on Discord's side. + oldEntries.delete(updated.id); + } + + await this.cache.remove(payload.guild_id, [...oldEntries.keys()]); + for (const emoji of oldEntries.values()) { + await this.broker.send({ type: RedisMessageType.EmojiDelete, old: emoji.toJSON(), guild_id: payload.guild_id }); + } + } +} diff --git a/projects/gateway/src/lib/managers/GatewayManagers.ts b/projects/gateway/src/lib/managers/GatewayManagers.ts new file mode 100644 index 000000000..38f287b41 --- /dev/null +++ b/projects/gateway/src/lib/managers/GatewayManagers.ts @@ -0,0 +1,33 @@ +import { ChannelManager } from './ChannelManager'; +import { EmojiManager } from './EmojiManager'; +import { GuildManager } from './GuildManager'; +import { MemberManager } from './MemberManager'; +import { MessageManager } from './MessageManager'; +import { RoleManager } from './RoleManager'; +import { StickerManager } from './StickerManager'; +import type { REST } from '@discordjs/rest'; +import type { Cache, MessageBroker } from 'wolfstar-shared'; + +/** + * Aggregates every gateway manager behind a single facade, wiring each one to + * the shared cache, message broker and REST client. + */ +export class GatewayManagers { + public readonly guilds: GuildManager; + public readonly channels: ChannelManager; + public readonly roles: RoleManager; + public readonly members: MemberManager; + public readonly messages: MessageManager; + public readonly emojis: EmojiManager; + public readonly stickers: StickerManager; + + public constructor(cache: Cache, broker: MessageBroker, rest: REST) { + this.guilds = new GuildManager(cache, broker, rest); + this.channels = new ChannelManager(cache.channels, broker, rest); + this.roles = new RoleManager(cache.roles, broker); + this.members = new MemberManager(cache.members, broker, rest); + this.messages = new MessageManager(cache.messages, broker); + this.emojis = new EmojiManager(cache.emojis, broker); + this.stickers = new StickerManager(cache.stickers, broker); + } +} diff --git a/projects/gateway/src/lib/managers/GuildManager.ts b/projects/gateway/src/lib/managers/GuildManager.ts new file mode 100644 index 000000000..8ed5d4160 --- /dev/null +++ b/projects/gateway/src/lib/managers/GuildManager.ts @@ -0,0 +1,77 @@ +import type { REST } from '@discordjs/rest'; +import { isNullish } from '@sapphire/utilities'; +import { + Routes, + type APIGuild, + type GatewayGuildCreateDispatchData, + type GatewayGuildDeleteDispatchData, + type GatewayGuildUpdateDispatchData, + type Snowflake +} from 'discord-api-types/v10'; +import { type Cache, Channel, Emoji, type FetchOptions, Guild, Member, type MessageBroker, RedisMessageType, Role, Sticker } from 'wolfstar-shared'; + +/** + * Manager for guilds and their initial bulk-cached collections. Unlike the + * scoped managers, it spans several caches because a guild owns channels, + * members, roles, emojis and stickers. + */ +export class GuildManager { + public constructor( + public readonly cache: Cache, + protected readonly broker: MessageBroker, + protected readonly rest?: REST + ) {} + + public async handleCreate(payload: GatewayGuildCreateDispatchData) { + await this.cache.guilds.add(payload, true); + await this.cache.emojis.set( + payload.id, + payload.emojis.map((emoji) => Emoji.fromAPI(emoji)) + ); + await this.cache.channels.set( + payload.id, + payload.channels.map((entry) => Channel.fromAPI(entry)) + ); + await this.cache.members.set( + payload.id, + payload.members.map((entry) => Member.fromAPI(entry)) + ); + await this.cache.roles.set( + payload.id, + payload.roles.map((role) => Role.fromAPI(role)) + ); + await this.cache.stickers.set( + payload.id, + (payload.stickers ?? []).map((sticker) => Sticker.fromAPI(sticker)) + ); + } + + public async handleUpdate(payload: GatewayGuildUpdateDispatchData) { + const old = await this.cache.guilds.get(payload.id); + const data = await this.cache.guilds.add(payload, true); + await this.broker.send({ type: RedisMessageType.GuildUpdate, old: old?.toJSON() ?? null, data: data.toJSON() }); + } + + public async handleDelete(payload: GatewayGuildDeleteDispatchData) { + for (const channelId of await this.cache.channels.keys(payload.id)) { + await this.cache.messages.clear(channelId); + } + await this.cache.guilds.remove(payload.id); + } + + /** + * Fetches a guild, hitting the cache first unless `force` is set. + */ + public async fetch(guildId: Snowflake, options: FetchOptions = {}): Promise { + const { force = false, cache = true } = options; + if (!force) { + const cached = await this.cache.guilds.get(guildId); + if (!isNullish(cached)) return cached; + } + + if (isNullish(this.rest)) throw new Error('The REST client is not available to this manager.'); + const data = (await this.rest.get(Routes.guild(guildId))) as APIGuild; + if (!cache) return Guild.fromAPI(data); + return this.cache.guilds.add(data, true); + } +} diff --git a/projects/gateway/src/lib/managers/MemberManager.ts b/projects/gateway/src/lib/managers/MemberManager.ts new file mode 100644 index 000000000..bc8147180 --- /dev/null +++ b/projects/gateway/src/lib/managers/MemberManager.ts @@ -0,0 +1,57 @@ +import { BaseScopedManager } from './BaseScopedManager'; +import { isNullish } from '@sapphire/utilities'; +import { + Routes, + type APIGuildMember, + type GatewayGuildMemberAddDispatchData, + type GatewayGuildMemberRemoveDispatchData, + type GatewayGuildMembersChunkDispatchData, + type GatewayGuildMemberUpdateDispatchData, + type Snowflake +} from 'discord-api-types/v10'; +import { type FetchOptions, Member, RedisMessageType } from 'wolfstar-shared'; + +export class MemberManager extends BaseScopedManager { + public async handleAdd(payload: GatewayGuildMemberAddDispatchData) { + await this.cache.set(payload.guild_id, Member.fromAPI(payload)); + await this.broker.send({ type: RedisMessageType.MemberAdd, data: payload }); + } + + public async handleUpdate(payload: GatewayGuildMemberUpdateDispatchData) { + const { old, value } = await this.upsert(payload.guild_id, payload); + await this.broker.send({ type: RedisMessageType.MemberUpdate, old: old?.toJSON() ?? null, data: value.toJSON() }); + } + + public async handleRemove(payload: GatewayGuildMemberRemoveDispatchData) { + const old = await this.cache.get(payload.guild_id, payload.user.id); + if (isNullish(old)) { + await this.broker.send({ type: RedisMessageType.MemberRemove, old: null, user: payload.user, guild_id: payload.guild_id }); + } else { + await this.cache.remove(payload.guild_id, old.id); + await this.broker.send({ type: RedisMessageType.MemberRemove, old: old.toJSON(), user: payload.user, guild_id: payload.guild_id }); + } + } + + public async handleChunk(payload: GatewayGuildMembersChunkDispatchData) { + await this.cache.set( + payload.guild_id, + payload.members.map((data) => Member.fromAPI(data)) + ); + } + + /** + * Fetches a member, hitting the cache first unless `force` is set. + */ + public async fetch(guildId: Snowflake, userId: Snowflake, options: FetchOptions = {}): Promise { + const { force = false, cache = true } = options; + if (!force) { + const cached = await this.cache.get(guildId, userId); + if (!isNullish(cached)) return cached; + } + + if (isNullish(this.rest)) throw new Error('The REST client is not available to this manager.'); + const data = (await this.rest.get(Routes.guildMember(guildId, userId))) as APIGuildMember; + if (!cache) return Member.fromAPI(data); + return this.cache.add(guildId, data, true); + } +} diff --git a/projects/gateway/src/lib/managers/MessageManager.ts b/projects/gateway/src/lib/managers/MessageManager.ts new file mode 100644 index 000000000..b01cb680b --- /dev/null +++ b/projects/gateway/src/lib/managers/MessageManager.ts @@ -0,0 +1,47 @@ +import { BaseScopedManager } from './BaseScopedManager'; +import { isNullish } from '@sapphire/utilities'; +import type { + GatewayMessageCreateDispatchData, + GatewayMessageDeleteBulkDispatchData, + GatewayMessageDeleteDispatchData, + GatewayMessageUpdateDispatchData, + Snowflake +} from 'discord-api-types/v10'; +import { Message, RedisMessageType } from 'wolfstar-shared'; + +export class MessageManager extends BaseScopedManager { + public async handleCreate(payload: GatewayMessageCreateDispatchData) { + await this.cache.set(payload.channel_id, Message.fromAPI(payload)); + await this.broker.send({ type: RedisMessageType.MessageCreate, data: payload }); + } + + public async handleUpdate(payload: GatewayMessageUpdateDispatchData) { + const { old } = await this.upsert(payload.channel_id, payload); + await this.broker.send({ type: RedisMessageType.MessageUpdate, old: old?.toJSON() ?? null, data: payload }); + } + + public async handleDelete(guildId: Snowflake, payload: GatewayMessageDeleteDispatchData) { + const old = await this.cache.get(payload.channel_id, payload.id); + if (isNullish(old)) { + await this.broker.send({ + type: RedisMessageType.MessageDelete, + old: { id: payload.id, channel_id: payload.channel_id, guild_id: guildId } + }); + } else { + await this.cache.remove(payload.channel_id, payload.id); + await this.broker.send({ type: RedisMessageType.MessageDelete, old: old.toJSON() }); + } + } + + public async handleDeleteBulk(guildId: Snowflake, payload: GatewayMessageDeleteBulkDispatchData) { + const entries = await this.cache.get(payload.channel_id, payload.ids); + await this.cache.remove(payload.channel_id, payload.ids); + + await this.broker.send({ + type: RedisMessageType.MessageDeleteBulk, + old: payload.ids.map((id) => entries.get(BigInt(id))?.toJSON() ?? { id }), + channel_id: payload.channel_id, + guild_id: guildId + }); + } +} diff --git a/projects/gateway/src/lib/managers/RoleManager.ts b/projects/gateway/src/lib/managers/RoleManager.ts new file mode 100644 index 000000000..afd3e9be4 --- /dev/null +++ b/projects/gateway/src/lib/managers/RoleManager.ts @@ -0,0 +1,31 @@ +import { BaseScopedManager } from './BaseScopedManager'; +import { isNullish } from '@sapphire/utilities'; +import type { + GatewayGuildRoleCreateDispatchData, + GatewayGuildRoleDeleteDispatchData, + GatewayGuildRoleUpdateDispatchData +} from 'discord-api-types/v10'; +import { RedisMessageType, Role } from 'wolfstar-shared'; + +export class RoleManager extends BaseScopedManager { + public async handleCreate(payload: GatewayGuildRoleCreateDispatchData) { + await this.cache.set(payload.guild_id, Role.fromAPI(payload.role)); + await this.broker.send({ type: RedisMessageType.RoleCreate, data: payload.role, guild_id: payload.guild_id }); + } + + public async handleUpdate(payload: GatewayGuildRoleUpdateDispatchData) { + const old = await this.cache.get(payload.guild_id, payload.role.id); + await this.cache.set(payload.guild_id, Role.fromAPI(payload.role)); + await this.broker.send({ type: RedisMessageType.RoleUpdate, old: old?.toJSON() ?? null, data: payload.role, guild_id: payload.guild_id }); + } + + public async handleDelete(payload: GatewayGuildRoleDeleteDispatchData) { + const old = await this.cache.get(payload.guild_id, payload.role_id); + if (isNullish(old)) { + await this.broker.send({ type: RedisMessageType.RoleDelete, old: { id: payload.role_id }, guild_id: payload.guild_id }); + } else { + await this.cache.remove(payload.guild_id, old.id); + await this.broker.send({ type: RedisMessageType.RoleDelete, old: old.toJSON(), guild_id: payload.guild_id }); + } + } +} diff --git a/projects/gateway/src/lib/managers/StickerManager.ts b/projects/gateway/src/lib/managers/StickerManager.ts new file mode 100644 index 000000000..85472d40c --- /dev/null +++ b/projects/gateway/src/lib/managers/StickerManager.ts @@ -0,0 +1,31 @@ +import { BaseScopedManager } from './BaseScopedManager'; +import { isNullish } from '@sapphire/utilities'; +import type { GatewayGuildStickersUpdateDispatchData } from 'discord-api-types/v10'; +import { RedisMessageType, Sticker } from 'wolfstar-shared'; + +export class StickerManager extends BaseScopedManager { + public async handleUpdate(payload: GatewayGuildStickersUpdateDispatchData) { + const oldEntries = await this.cache.entries(payload.guild_id); + + for (const sticker of payload.stickers) { + const updated = Sticker.fromAPI(sticker); + const old = oldEntries.get(updated.id); + + if (isNullish(old)) { + await this.cache.set(payload.guild_id, updated); + await this.broker.send({ type: RedisMessageType.StickerCreate, data: sticker, guild_id: payload.guild_id }); + } else if (!updated.equals(old)) { + await this.cache.set(payload.guild_id, updated); + await this.broker.send({ type: RedisMessageType.StickerUpdate, old: old.toJSON(), data: sticker, guild_id: payload.guild_id }); + } + + // Drop processed entries; whatever remains was deleted on Discord's side. + oldEntries.delete(updated.id); + } + + await this.cache.remove(payload.guild_id, [...oldEntries.keys()]); + for (const sticker of oldEntries.values()) { + await this.broker.send({ type: RedisMessageType.StickerDelete, old: sticker.toJSON(), guild_id: payload.guild_id }); + } + } +} diff --git a/projects/gateway/src/listeners/ws/dispatch.mts b/projects/gateway/src/listeners/ws/dispatch.mts index 2b4166db7..e99f3f05f 100644 --- a/projects/gateway/src/listeners/ws/dispatch.mts +++ b/projects/gateway/src/listeners/ws/dispatch.mts @@ -1,6 +1,7 @@ +import { all } from '#lib/actions/All'; import { makeWebSocketListener } from '#lib/structures/ws-listener'; import { WebSocketShardEvents } from '@discordjs/ws'; export default makeWebSocketListener(WebSocketShardEvents.Dispatch, (payload) => { - console.log(payload.data.t); + return all(payload); }); diff --git a/projects/gateway/src/listeners/ws/ready.mts b/projects/gateway/src/listeners/ws/ready.mts index 5c02e15e2..278b252da 100644 --- a/projects/gateway/src/listeners/ws/ready.mts +++ b/projects/gateway/src/listeners/ws/ready.mts @@ -1,6 +1,6 @@ import { makeWebSocketListener } from '#lib/structures/ws-listener'; import { WebSocketShardEvents } from '@discordjs/ws'; -export default makeWebSocketListener(WebSocketShardEvents.Ready, (payload) => { - console.log(`[WS] ${payload.shardId} is now ready.`); +export default makeWebSocketListener(WebSocketShardEvents.Ready, (_data, shardId) => { + console.log(`[WS] ${shardId} is now ready.`); }); diff --git a/projects/gateway/src/listeners/ws/resumed.mts b/projects/gateway/src/listeners/ws/resumed.mts index fb0f62ba6..34674c60a 100644 --- a/projects/gateway/src/listeners/ws/resumed.mts +++ b/projects/gateway/src/listeners/ws/resumed.mts @@ -1,6 +1,6 @@ import { makeWebSocketListener } from '#lib/structures/ws-listener'; import { WebSocketShardEvents } from '@discordjs/ws'; -export default makeWebSocketListener(WebSocketShardEvents.Resumed, (payload) => { - console.log(`[WS] ${payload.shardId} has resumed previous session.`); +export default makeWebSocketListener(WebSocketShardEvents.Resumed, (shardId) => { + console.log(`[WS] ${shardId} has resumed previous session.`); }); diff --git a/projects/gateway/src/tsconfig.json b/projects/gateway/src/tsconfig.json index c7306c7c8..ce32a410f 100644 --- a/projects/gateway/src/tsconfig.json +++ b/projects/gateway/src/tsconfig.json @@ -3,9 +3,8 @@ "compilerOptions": { "outDir": "../dist", "rootDir": ".", - "baseUrl": ".", "paths": { - "#lib/*": ["lib/*"] + "#lib/*": ["./lib/*"] }, "composite": true }, diff --git a/projects/shared/src/index.ts b/projects/shared/src/index.ts index 84e8a7a41..f4e38837d 100644 --- a/projects/shared/src/index.ts +++ b/projects/shared/src/index.ts @@ -14,6 +14,7 @@ export { default as Redis, type RedisOptions } from 'ioredis'; export type { HashScopedCache } from './lib/cache/base/HashScopedCache.js'; export type { ScopedCache } from './lib/cache/base/ScopedCache.js'; export * from './lib/cache/Cache.js'; +export type { FetchOptions, ICache } from './lib/cache/interfaces/ICache.js'; export type { CacheChannels } from './lib/cache/CacheChannels.js'; export type { CacheEmojis } from './lib/cache/CacheEmojis.js'; export type { CacheGuilds } from './lib/cache/CacheGuilds.js'; @@ -27,6 +28,7 @@ export * from './lib/cache/structures/Guild.js'; export * from './lib/cache/structures/interfaces/BufferEncodable.js'; export * from './lib/cache/structures/interfaces/Identifiable.js'; export * from './lib/cache/structures/interfaces/IStructure.js'; +export type { IStructureCreator } from './lib/cache/structures/interfaces/IStructureCreator.js'; export * from './lib/cache/structures/interfaces/JsonEncodable.js'; export * from './lib/cache/structures/Member.js'; export * from './lib/cache/structures/Message.js'; diff --git a/projects/shared/src/lib/cache/CacheGuilds.ts b/projects/shared/src/lib/cache/CacheGuilds.ts index b4fad7ff9..e0db5ec7c 100644 --- a/projects/shared/src/lib/cache/CacheGuilds.ts +++ b/projects/shared/src/lib/cache/CacheGuilds.ts @@ -10,6 +10,22 @@ export class CacheGuilds extends ScopedCache { await this.client.set(this.makeId(guild.id), guild.toBuffer()); } + /** + * Adds or updates a guild from raw API data, returning the stored structure. + * + * If the guild already exists and `overwrite` is `false`, the existing value is + * merged with `data` before being reconstructed; otherwise a fresh instance is + * built from `data` alone. + * @param data The raw API guild data to store. + * @param overwrite Whether to replace an existing guild instead of patching it. + */ + public async add(data: Guild.Json, overwrite = false): Promise { + const existing = overwrite ? null : await this.get(BigInt(data.id)); + const value = existing === null ? Guild.fromAPI(data) : Guild.fromAPI({ ...existing.toJSON(), ...data }); + await this.set(value); + return value; + } + public async has(guildId: ScopedCache.Snowflake) { const data = await this.client.exists(this.makeId(guildId)); return data === 1; @@ -33,12 +49,28 @@ export class CacheGuilds extends ScopedCache { return count(this.client.scanBufferStream({ match: this.makeId('*'), count: 100 })); } + /** + * Gets the number of cached guilds. + * @remark RFC alias of {@link CacheGuilds.count}. + */ + public getSize() { + return this.count(); + } + public async remove(guildId: ScopedCache.Snowflake) { const key = this.makeId(guildId); const result = await this.client.del(key, `${key}:channels`, `${key}:emojis`, `${key}:members`, `${key}:roles`, `${key}:stickers`); return result > 0; } + /** + * Deletes a guild and all of its scoped sub-caches. + * @remark RFC alias of {@link CacheGuilds.remove}. + */ + public delete(guildId: ScopedCache.Snowflake) { + return this.remove(guildId); + } + public async *keys(): AsyncIterable { // eslint-disable-next-line @typescript-eslint/dot-notation const offset = this.parent['prefix'].length; diff --git a/projects/shared/src/lib/cache/base/HashScopedCache.ts b/projects/shared/src/lib/cache/base/HashScopedCache.ts index 5d3a0c216..1916c1e76 100644 --- a/projects/shared/src/lib/cache/base/HashScopedCache.ts +++ b/projects/shared/src/lib/cache/base/HashScopedCache.ts @@ -1,12 +1,14 @@ import { Collection } from '@discordjs/collection'; -import { isNullish } from '@sapphire/utilities'; +import { isNullish, type NonNullObject } from '@sapphire/utilities'; import { Reader } from '../../data/Reader.js'; -import type { IStructure, IStructureConstructor } from '../structures/interfaces/IStructure.js'; +import type { IStructure } from '../structures/interfaces/IStructure.js'; +import type { IStructureCreator } from '../structures/interfaces/IStructureCreator.js'; +import type { ICache } from '../interfaces/ICache.js'; import { ScopedCache } from './ScopedCache.js'; -export abstract class HashScopedCache extends ScopedCache { +export abstract class HashScopedCache extends ScopedCache implements ICache { public abstract readonly tail: string; - public abstract readonly structure: IStructureConstructor; + public abstract readonly structure: IStructureCreator; /** * Sets an entry to the hashmap. @@ -17,6 +19,30 @@ export abstract class HashScopedCache extends ScopedCache return Array.isArray(entries) ? this.setMany(parentId, entries as readonly T[]) : this.setOne(parentId, entries as T); } + /** + * Adds or updates an entry from raw API data, returning the stored structure. + * + * If the entry already exists and `overwrite` is `false`, it is patched with the + * new data; otherwise a fresh instance is constructed. Patching uses the + * structure's {@link IStructureCreator.patch} when available, falling back to a + * full reconstruction that merges the existing serialized value with `data`. + * @param parentId The parent's ID. + * @param data The raw API data to store. Must carry the entry's identity. + * @param overwrite Whether to replace an existing entry instead of patching it. + */ + public async add(parentId: ScopedCache.Snowflake, data: NonNullObject, overwrite = false): Promise { + const id = this.structure.getId?.(data) ?? BigInt((data as { id: ScopedCache.Snowflake }).id); + const existing = overwrite ? null : await this.getOne(parentId, id); + + const value = + existing === null // + ? this.structure.fromAPI(data) + : (this.structure.patch?.(existing, data) ?? this.structure.fromAPI({ ...existing.toJSON(), ...data })); + + await this.setOne(parentId, value); + return value; + } + /** * Checks whether or not an ID is in the hashmap. * @param parentId The parent's ID. @@ -91,6 +117,14 @@ export abstract class HashScopedCache extends ScopedCache return this.client.hlen(this.makeId(parentId)); } + /** + * Gets the number of entries scoped under `parentId`. + * @remark RFC alias of {@link HashScopedCache.count}. + */ + public getSize(parentId: ScopedCache.Snowflake) { + return this.count(parentId); + } + /** * Removes one or more entries from the hashmap. * @param parentId The parent's ID. @@ -104,6 +138,14 @@ export abstract class HashScopedCache extends ScopedCache return result; } + /** + * Deletes one or more entries from the hashmap. + * @remark RFC alias of {@link HashScopedCache.remove}. + */ + public delete(parentId: ScopedCache.Snowflake, entries: ScopedCache.Snowflake | readonly ScopedCache.Snowflake[]) { + return this.remove(parentId, entries); + } + /** * Removes the hashmap from the cache, effectively clearing all of its entries. * @param parentId The parent's ID. diff --git a/projects/shared/src/lib/cache/interfaces/ICache.ts b/projects/shared/src/lib/cache/interfaces/ICache.ts new file mode 100644 index 000000000..af4184660 --- /dev/null +++ b/projects/shared/src/lib/cache/interfaces/ICache.ts @@ -0,0 +1,71 @@ +import type { Awaitable, NonNullObject } from '@sapphire/utilities'; +import type { ScopedCache } from '../base/ScopedCache.js'; +import type { IStructure } from '../structures/interfaces/IStructure.js'; +import type { IStructureCreator } from '../structures/interfaces/IStructureCreator.js'; + +/** + * The guild-scoped cache contract aligned with the discord.js async caching RFC + * (discordjs/discord.js#11426). + * + * @remark Unlike the upstream proposal, wolfstar caches are scoped under a parent + * (the guild or channel ID), so every operation takes a `parentId` in addition to + * the entry key. The semantics of each method match the RFC otherwise. + */ +export interface ICache { + /** + * The creator used to construct and patch the structures this cache holds. + */ + readonly structure: IStructureCreator; + + /** + * Retrieves an entry from the cache. + */ + get(parentId: ScopedCache.Snowflake, entryId: ScopedCache.Snowflake): Awaitable; + + /** + * Sets one or more entries in the cache. + */ + set(parentId: ScopedCache.Snowflake, entries: T | readonly T[]): Awaitable; + + /** + * Adds or updates data in the cache, returning the instantiated structure. + * If the entry exists it is patched with the new data unless `overwrite` is `true`; + * otherwise a new instance is constructed and stored. + */ + add(parentId: ScopedCache.Snowflake, data: NonNullObject, overwrite?: boolean): Awaitable; + + /** + * Checks whether an entry exists in the cache. + */ + has(parentId: ScopedCache.Snowflake, entryId: ScopedCache.Snowflake): Awaitable; + + /** + * Deletes one or more entries from the cache, returning the amount removed. + */ + delete(parentId: ScopedCache.Snowflake, entries: ScopedCache.Snowflake | readonly ScopedCache.Snowflake[]): Awaitable; + + /** + * Clears all entries scoped under `parentId`. + */ + clear(parentId: ScopedCache.Snowflake): Awaitable; + + /** + * Gets the number of entries scoped under `parentId`. + */ + getSize(parentId: ScopedCache.Snowflake): Awaitable; +} + +/** + * Options shared by every manager `fetch` method, mirroring the RFC's `FetchOptions`. + */ +export interface FetchOptions { + /** + * Whether to skip the cache check and force an API request. + */ + force?: boolean; + + /** + * Whether to cache the fetched result. + */ + cache?: boolean; +} diff --git a/projects/shared/src/lib/cache/structures/Guild.ts b/projects/shared/src/lib/cache/structures/Guild.ts index 1b02d9e6a..8e4148ca4 100644 --- a/projects/shared/src/lib/cache/structures/Guild.ts +++ b/projects/shared/src/lib/cache/structures/Guild.ts @@ -122,7 +122,7 @@ export class Guild implements IStructure { return { id: this.id.toString(), afk_channel_id: this.afkChannelId?.toString() ?? null, - afk_timeout: this.afkTimeout, + afk_timeout: this.afkTimeout as Guild.Json['afk_timeout'], banner: this.banner, default_message_notifications: this.defaultMessageNotifications, description: this.description, @@ -138,7 +138,7 @@ export class Guild implements IStructure { name: this.name, nsfw_level: this.nsfwLevel, owner_id: this.ownerId.toString(), - preferred_locale: this.preferredLocale, + preferred_locale: this.preferredLocale as Guild.Json['preferred_locale'], premium_progress_bar_enabled: this.premiumProgressBarEnabled, premium_subscription_count: this.premiumSubscriptionCount ?? undefined, premium_tier: this.premiumTier, @@ -150,7 +150,9 @@ export class Guild implements IStructure { vanity_url_code: this.vanityUrlCode, verification_level: this.verificationLevel, widget_channel_id: this.widgetChannelId?.toString(), - widget_enabled: this.widgetEnabled ?? undefined + widget_enabled: this.widgetEnabled ?? undefined, + safety_alerts_channel_id: null, + incidents_data: null }; } diff --git a/projects/shared/src/lib/cache/structures/Member.ts b/projects/shared/src/lib/cache/structures/Member.ts index 482fad13c..8a8388819 100644 --- a/projects/shared/src/lib/cache/structures/Member.ts +++ b/projects/shared/src/lib/cache/structures/Member.ts @@ -1,6 +1,7 @@ import { isNullish, type Nullish } from '@sapphire/utilities'; -import type { Nullable } from 'discord-api-types/utils/internals.js'; import type { APIGuildMember, APIUser } from 'discord-api-types/v10'; + +type Nullable = { [P in keyof T]: T[P] | null }; import { defaultOptional, fromTimestamp, toTimestamp } from '../../common/util.js'; import type { Reader } from '../../data/Reader.js'; import { Writer } from '../../data/Writer.js'; @@ -86,10 +87,12 @@ export class Member implements IStructure { id: this.id.toString(), username: this.username, discriminator: this.discriminator.toString().padStart(4, '0'), + global_name: null, bot: this.bot ?? undefined, avatar: this.avatar, public_flags: this.flags ?? undefined }, + flags: 0 as APIGuildMember['flags'], nick: this.nickname, avatar: this.guildAvatar, roles: this.roles.map((role) => role.toString()), @@ -102,6 +105,14 @@ export class Member implements IStructure { }; } + public static getId(data: Member.Json): bigint { + return BigInt(data.user!.id); + } + + public static patch(existing: Member, data: Partial): Member { + return existing.patch(data); + } + public static fromAPI(data: Member.Json, user?: APIUser): Member { user ??= data.user; if (isNullish(user)) throw new TypeError('Expected user to be defined'); diff --git a/projects/shared/src/lib/cache/structures/Message.ts b/projects/shared/src/lib/cache/structures/Message.ts index 52b28dca2..0f620fbb8 100644 --- a/projects/shared/src/lib/cache/structures/Message.ts +++ b/projects/shared/src/lib/cache/structures/Message.ts @@ -62,6 +62,7 @@ export class Message implements IStructure { id: this.author.id.toString(), username: this.author.username, discriminator: this.author.discriminator.toString().padStart(4, '0'), + global_name: null, avatar: this.author.avatar ?? null }, content: this.content, @@ -93,6 +94,10 @@ export class Message implements IStructure { }; } + public static patch(existing: Message, data: Partial): Message { + return existing.patch(data); + } + public static fromAPI(data: Message.Json): Message { return new Message({ id: BigInt(data.id!), diff --git a/projects/shared/src/lib/cache/structures/Role.ts b/projects/shared/src/lib/cache/structures/Role.ts index 65e01428f..1c9cf597d 100644 --- a/projects/shared/src/lib/cache/structures/Role.ts +++ b/projects/shared/src/lib/cache/structures/Role.ts @@ -57,6 +57,8 @@ export class Role implements IStructure { id: this.id.toString(), name: this.name, color: this.color, + colors: { primary_color: this.color, secondary_color: null, tertiary_color: null }, + flags: 0 as APIRole['flags'], hoist: this.hoist, icon: this.icon, managed: this.managed, diff --git a/projects/shared/src/lib/cache/structures/User.ts b/projects/shared/src/lib/cache/structures/User.ts new file mode 100644 index 000000000..372dd5ba2 --- /dev/null +++ b/projects/shared/src/lib/cache/structures/User.ts @@ -0,0 +1,62 @@ +import type { IStructure } from './interfaces/IStructure.js'; +import type { APIUser } from 'discord-api-types/v10'; +import { Writer } from '../../data/Writer.js'; +import type { Nullish } from '@sapphire/utilities'; + +export class User implements IStructure { + public readonly id: bigint; + public readonly username: string; + public readonly globalName: string | null; + public readonly discriminator: number; + public readonly avatar: string | null; + public readonly bot: boolean | null; + public readonly flags: number | null; + + public constructor(data: User.Data) { + this.id = data.id; + this.username = data.username; + this.discriminator = data.discriminator; + this.avatar = data.avatar ?? null; + this.bot = data.bot ?? null; + this.flags = data.flags ?? null; + } + toBuffer(): Buffer { + return new Writer(100) + .u64(this.id) + .string(this.username) + .string(this.globalName) + .u16(this.discriminator) + .string(this.avatar) + .bool(this.bot) + .u32(this.flags).trimmed; + } + toJSON(): User.Json { + return { + ...this.toJSON(), + id: this.id.toString(), + username: this.username, + discriminator: this.discriminator.toString().padStart(4, '0'), + avatar: this.avatar, + bot: this.bot, + flags: this.flags, + }; + } +} + + + + +export namespace User { + export type Json = APIUser; + + export interface Data { + id: bigint; + username: string; + globalName?: string | Nullish; + discriminator: number; + bot?: boolean | Nullish; + avatar?: string | Nullish; + flags?: number | Nullish; + joinedAt?: number | Nullish; + } +} diff --git a/projects/shared/src/lib/cache/structures/interfaces/IStructureCreator.ts b/projects/shared/src/lib/cache/structures/interfaces/IStructureCreator.ts new file mode 100644 index 000000000..7b3769dee --- /dev/null +++ b/projects/shared/src/lib/cache/structures/interfaces/IStructureCreator.ts @@ -0,0 +1,19 @@ +import type { NonNullObject } from '@sapphire/utilities'; +import type { IStructure, IStructureConstructor } from './IStructure.js'; + +export interface IStructureCreator extends IStructureConstructor { + /** + * Resolves the entity's ID from raw API data. + * @remark Defaults to `BigInt(data.id)` when not implemented, which is correct + * for every structure whose identity lives on the top-level `id` field. + */ + getId?(data: NonNullObject): bigint; + + /** + * Patches an existing instance with partial API data, returning the updated instance. + * @remark When not implemented, the caller falls back to a full reconstruction by + * merging the existing serialized value with `data`, which generalises patching to + * every structure without bespoke logic. + */ + patch?(existing: T, data: NonNullObject): T; +} diff --git a/projects/shared/src/lib/cache/structures/unions/channel/GuildThreadChannel.ts b/projects/shared/src/lib/cache/structures/unions/channel/GuildThreadChannel.ts index c5ead1572..749954f44 100644 --- a/projects/shared/src/lib/cache/structures/unions/channel/GuildThreadChannel.ts +++ b/projects/shared/src/lib/cache/structures/unions/channel/GuildThreadChannel.ts @@ -41,13 +41,14 @@ export class GuildThreadChannel extends GuildBasedChannel public override toJSON(): GuildVoiceChannel.Json { return { ...super.toJSON(), + position: this.position ?? 0, bitrate: this.bitrate ?? undefined, user_limit: this.userLimit ?? undefined, rtc_region: this.rtcRegion, @@ -54,7 +55,7 @@ export class GuildVoiceChannel extends GuildBasedChannel export namespace GuildVoiceChannel { export type Type = ChannelType.GuildStageVoice | ChannelType.GuildVoice; - export type Json = Omit; + export type Json = Omit, 'guild_id'>; export interface Data extends GuildBasedChannel.Data { bitrate?: number | Nullish; userLimit?: number | Nullish; diff --git a/projects/shared/src/lib/cache/structures/unions/channel/base/GuildBasedChannel.ts b/projects/shared/src/lib/cache/structures/unions/channel/base/GuildBasedChannel.ts index a2328360b..81ac9bce3 100644 --- a/projects/shared/src/lib/cache/structures/unions/channel/base/GuildBasedChannel.ts +++ b/projects/shared/src/lib/cache/structures/unions/channel/base/GuildBasedChannel.ts @@ -1,11 +1,11 @@ import type { Nullish } from '@sapphire/utilities'; -import type { APIGuildChannel, APIOverwrite, ChannelFlags, ChannelType, OverwriteType } from 'discord-api-types/v10'; +import type { APIGuildChannel, APIOverwrite, ChannelFlags, GuildChannelType, OverwriteType } from 'discord-api-types/v10'; import { normalizeNullable } from '../../../../../common/util.js'; import type { Reader } from '../../../../../data/Reader.js'; import { Writer } from '../../../../../data/Writer.js'; import type { IStructure } from '../../../interfaces/IStructure.js'; -export abstract class GuildBasedChannel implements IStructure { +export abstract class GuildBasedChannel implements IStructure { public readonly id: bigint; public readonly type: T; public readonly name: string; @@ -64,9 +64,9 @@ export abstract class GuildBasedChannel implements IStruc } export namespace GuildBasedChannel { - export type Json = Omit, 'guild_id'>; + export type Json = Omit, 'guild_id'> & { position?: number }; - export interface Data { + export interface Data { id: bigint; name: string; type: T; @@ -85,7 +85,7 @@ export namespace GuildBasedChannel { } } -export function guildBasedFromAPIShared(data: GuildBasedChannel.Json): GuildBasedChannel.Data { +export function guildBasedFromAPIShared(data: GuildBasedChannel.Json): GuildBasedChannel.Data { return { id: BigInt(data.id), type: data.type, @@ -105,7 +105,7 @@ export function guildBasedFromAPIShared(data: GuildBasedC }; } -export function guildBasedFromBinaryShared(reader: Reader): GuildBasedChannel.Data { +export function guildBasedFromBinaryShared(reader: Reader): GuildBasedChannel.Data { return { id: reader.u64()!, type: reader.u8()! as T, diff --git a/projects/shared/src/lib/cache/structures/unions/channel/base/GuildTextBasedChannel.ts b/projects/shared/src/lib/cache/structures/unions/channel/base/GuildTextBasedChannel.ts index a72e4b573..9d48d2604 100644 --- a/projects/shared/src/lib/cache/structures/unions/channel/base/GuildTextBasedChannel.ts +++ b/projects/shared/src/lib/cache/structures/unions/channel/base/GuildTextBasedChannel.ts @@ -17,6 +17,7 @@ export abstract class GuildTextBasedChannel exte public override toJSON(): GuildTextBasedChannel.Json { return { ...super.toJSON(), + position: this.position ?? 0, default_auto_archive_duration: this.defaultAutoArchiveDuration ?? undefined, topic: this.topic }; diff --git a/projects/shared/src/lib/cache/structures/values/GuildFeatures.ts b/projects/shared/src/lib/cache/structures/values/GuildFeatures.ts index 61766d51e..8c41d8fb9 100644 --- a/projects/shared/src/lib/cache/structures/values/GuildFeatures.ts +++ b/projects/shared/src/lib/cache/structures/values/GuildFeatures.ts @@ -32,7 +32,7 @@ export const GuildFeatureBits = { export const GuildFeatureEntries = Object.entries(GuildFeatureBits) as [feature: GuildFeature, bit: number][]; export function toFeatures(features: readonly GuildFeature[]) { - return features.reduce((bits, feature) => bits | (GuildFeatureBits[feature] ?? 0), 0); + return features.reduce((bits, feature) => bits | (GuildFeatureBits[feature as keyof typeof GuildFeatureBits] ?? 0), 0); } export function fromFeatures(value: number): GuildFeature[] { diff --git a/projects/shared/src/lib/structures/Listener.ts b/projects/shared/src/lib/structures/Listener.ts index 9be700076..ecb40298b 100644 --- a/projects/shared/src/lib/structures/Listener.ts +++ b/projects/shared/src/lib/structures/Listener.ts @@ -1,3 +1,4 @@ +// oxlint-disable no-underscore-dangle import { Piece, type Container } from '@sapphire/pieces'; export abstract class Listener extends Piece { diff --git a/projects/shared/src/lib/structures/ListenerStore.ts b/projects/shared/src/lib/structures/ListenerStore.ts index 860dee0b0..fadc5bee3 100644 --- a/projects/shared/src/lib/structures/ListenerStore.ts +++ b/projects/shared/src/lib/structures/ListenerStore.ts @@ -3,7 +3,6 @@ import { Listener } from './Listener.js'; export class ListenerStore extends Store { public constructor() { - // TODO: https://github.com/sapphiredev/pieces/pull/230 - super(Listener as any, { name: 'listeners' }); + super(Listener, { name: 'listeners' }); } } diff --git a/projects/shared/tests/lib/cache/HashScopedCache.test.ts b/projects/shared/tests/lib/cache/HashScopedCache.test.ts new file mode 100644 index 000000000..1c3f76f05 --- /dev/null +++ b/projects/shared/tests/lib/cache/HashScopedCache.test.ts @@ -0,0 +1,121 @@ +import type { APIEmoji, APIGuildMember } from 'discord-api-types/v10'; +import { Cache } from '../../../src/lib/cache/Cache.js'; +import { Emoji } from '../../../src/lib/cache/structures/Emoji.js'; +import { Member } from '../../../src/lib/cache/structures/Member.js'; + +/** + * Minimal in-memory stand-in for the subset of the ioredis hash API used by + * {@link HashScopedCache}. Keeps the tests free of a live Redis instance. + */ +class FakeRedis { + private readonly store = new Map>(); + + public async hgetBuffer(key: string, field: string): Promise { + return this.store.get(key)?.get(field) ?? null; + } + + public async hset(key: string, field: string, value: Buffer): Promise { + const existed = this.store.get(key)?.has(field) ?? false; + this.bucket(key).set(field, value); + return existed ? 0 : 1; + } + + public async hmgetBuffer(key: string, ...fields: string[]): Promise<(Buffer | null)[]> { + const bucket = this.store.get(key); + return fields.map((field) => bucket?.get(field) ?? null); + } + + public async hexists(key: string, field: string): Promise { + return this.store.get(key)?.has(field) ? 1 : 0; + } + + public async hdel(key: string, ...fields: string[]): Promise { + const bucket = this.store.get(key); + if (!bucket) return 0; + let removed = 0; + for (const field of fields) if (bucket.delete(field)) removed++; + return removed; + } + + private bucket(key: string): Map { + let bucket = this.store.get(key); + if (!bucket) { + bucket = new Map(); + this.store.set(key, bucket); + } + + return bucket; + } +} + +function createCache() { + return new Cache({ client: new FakeRedis() as never, prefix: 's7' }); +} + +const guildId = '737141877803057244'; + +const emojiData: APIEmoji = { + id: '298835537815175168', + name: 'wolf', + animated: true, + available: true, + managed: false, + require_colons: true, + roles: [] +}; + +const memberData: APIGuildMember = { + user: { id: '266624760782258186', username: 'Wolf', discriminator: '0001', global_name: null, avatar: null }, + nick: 'Original', + avatar: null, + roles: ['111111111111111111'], + joined_at: '2019-02-03T21:57:10.354Z', + premium_since: null, + deaf: false, + mute: false, + flags: 0 +}; + +describe('HashScopedCache.add', () => { + it('constructs and stores a fresh entry on a cache miss', async () => { + const cache = createCache(); + + const value = await cache.emojis.add(guildId, emojiData); + expect(value).toBeInstanceOf(Emoji); + expect(value.name).toBe('wolf'); + + const stored = await cache.emojis.get(guildId, BigInt(emojiData.id!)); + expect(stored?.name).toBe('wolf'); + }); + + it('patches an existing entry without dropping untouched fields', async () => { + const cache = createCache(); + await cache.emojis.add(guildId, emojiData); + + // Emoji has no bespoke patch, so this exercises the generic merge fallback. + const patched = await cache.emojis.add(guildId, { id: emojiData.id, name: 'renamed' }); + expect(patched.name).toBe('renamed'); + expect(patched.animated).toBe(true); + expect(patched.requireColons).toBe(true); + }); + + it('replaces the entry entirely when overwrite is true', async () => { + const cache = createCache(); + await cache.emojis.add(guildId, emojiData); + + const overwritten = await cache.emojis.add(guildId, { id: emojiData.id, name: 'reset' }, true); + expect(overwritten.name).toBe('reset'); + expect(overwritten.animated).toBeNull(); + }); + + it('uses the structure-specific patch and id resolver for members', async () => { + const cache = createCache(); + await cache.members.add(guildId, memberData); + + const updated = await cache.members.add(guildId, { ...memberData, nick: 'Renamed' }); + expect(updated.id).toBe(BigInt(memberData.user!.id)); + expect(updated.nickname).toBe('Renamed'); + // joined_at is preserved through the patch path. + expect(updated.joinedAt).toBe(Date.parse(memberData.joined_at)); + }); +}); diff --git a/tsconfig.base.json b/tsconfig.base.json index ab37235db..3d2f1c662 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -1,9 +1,7 @@ { - "extends": "@sapphire/ts-config/extra-strict", + "extends": ["@sapphire/ts-config/extra-strict", "@sapphire/ts-config/bundler"], "compilerOptions": { "lib": ["ESNext", "DOM"], "emitDecoratorMetadata": false, - "target": "ESNext", - "module": "ESNext" } } From 354b3bc6af69bcd12fd298be94ebfbe7ee5271ef Mon Sep 17 00:00:00 2001 From: RedStar Date: Fri, 12 Jun 2026 16:56:20 +0200 Subject: [PATCH 04/12] chore: remove deprecated Docker control script and configuration files - Deleted the PowerShell script `control.ps1` used for managing Docker containers. - Removed the `docker-compose.yml` file that defined the Docker services for the project. - Eliminated the associated `README.md` documentation for the Docker setup. --- projects/docker/README.md | 21 ---------- projects/docker/control.ps1 | 55 -------------------------- projects/docker/docker-compose.yml | 63 ------------------------------ 3 files changed, 139 deletions(-) delete mode 100644 projects/docker/README.md delete mode 100644 projects/docker/control.ps1 delete mode 100644 projects/docker/docker-compose.yml diff --git a/projects/docker/README.md b/projects/docker/README.md deleted file mode 100644 index 3161cba73..000000000 --- a/projects/docker/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# Skyra Dockerfiles - -This folder contains all the files required to control Docker development environments for Skyra. Most of the meat of -the content is in the `docker-compose.yml` file which has the info on which images can be build and as which containers -they would be ran. In order to easily control the docker-compose file there is a powershell, `control.ps1`. - -Skyra currently has the following microservices that can be dockerized: - -- PostgreSQL Database - - Service name in docker-compose: `postgres` - - Image used: `skyrabot/postgres:latest` - - For more information see [skyra-project/docker-images] -- Redis - - Service name in docker-compose: `redis` - - Image used: `redis:alpine` - - For more information see [redis] - - - -[redis]: https://hub.docker.com/_/redis -[skyra-project/docker-images]: https://github.com/skyra-project/docker-images diff --git a/projects/docker/control.ps1 b/projects/docker/control.ps1 deleted file mode 100644 index bc12d1976..000000000 --- a/projects/docker/control.ps1 +++ /dev/null @@ -1,55 +0,0 @@ -function Remove-All-Containers { - docker container stop $(docker ps -aq) - docker container rm $(docker ps -aq) -} - -function Show-Help { - Write-Host "" - Write-Host "Skyra Docker Control Script" -ForegroundColor blue - Write-Host "" - Write-Host "Usage" -ForegroundColor yellow - Write-Host " -./.docker/control.ps1 [COMMAND] [ARGS...] -./.docker/control.ps1 -h | --help" - Write-Host "" - Write-Host "Commands" -ForegroundColor yellow - Write-Host " -build Builds a Docker image so it is prepped for running -start Starts a service in detached state -stop Stops a service -remove Removes a single service -removeall Removes all services - For this command no service is required and it can be skipped by just hitting enter when prompted -push Pushes a docker image to Dockerhub -logs Shows the logs of a service -tail Tails the logs of a service -update Updates a running service" -} - -function Step-Run { - Param ( - [String]$Command = $( Read-Host "What command do you want to run? If unsure type help" ), - [String]$Service - ) - - Begin { - if ($Command -Ne "help" -And $Command -Ne "h" -And $Command -Ne "removeall" -And $Service -Eq "") { - $Service = $( Read-Host "What Docker service do you want to control?" ) - } - } - - Process { - switch ($Command) { - build { docker-compose -p skyra -f "$($PSScriptRoot)/docker-compose.yml" -f "$($PSScriptRoot)/docker-build.yml" build $Service } - start { docker-compose -p skyra -f "$($PSScriptRoot)/docker-compose.yml" up -d $Service } - logs { docker-compose -p skyra -f "$($PSScriptRoot)/docker-compose.yml" logs $Service } - tail { docker-compose -p skyra -f "$($PSScriptRoot)/docker-compose.yml" logs -f $Service } - push { docker push $Service } - remove { docker-compose -p skyra -f "$($PSScriptRoot)/docker-compose.yml" rm -fv $Service } - update { docker-compose -p skyra -f "$($PSScriptRoot)/docker-compose.yml" pull $Service; docker-compose -p skyra -f "$($PSScriptRoot)/docker-compose.yml" up -d --force-recreate $Service } - removeall { Remove-All-Containers } - default { Show-Help } - } - } -} - -Step-Run @Args diff --git a/projects/docker/docker-compose.yml b/projects/docker/docker-compose.yml deleted file mode 100644 index 60490511c..000000000 --- a/projects/docker/docker-compose.yml +++ /dev/null @@ -1,63 +0,0 @@ -version: '2.4' -services: - postgres: - container_name: postgres - image: 'skyrabot/postgres:latest' - networks: - - wolfstar - ports: - - '5432:5432' - restart: always - volumes: - - 'postgres-data:/var/lib/postgresql/data' - - redis: - command: 'redis-server --port 8287 --requirepass redis' - container_name: redis - image: 'redis:alpine' - networks: - - wolfstar - ports: - - '8287:8287' - restart: always - - wolfstar-bot: - build: - context: ../../ - dockerfile: ../bot/Dockerfile - container_name: wolfstar-bot - depends_on: - - redis - - postgres - env_file: - - ../bot/src/.env.development - - ../bot/src/.env.development.local - image: 'ghcr.io/wolfstar-project/wolfstar-bot:latest' - networks: - - wolfstar - ports: - - '8282:8282' - - '7282:7282' - restart: always - tty: true - - wolfstar-gateway: - build: - context: ../../ - dockerfile: ../gateway/Dockerfile - container_name: wolfstar-gateway - env_file: - - ../gateway/src/.env.development - - ../gateway/src/.env.development.local - image: 'ghcr.io/wolfstar-project/wolfstar-gateway:latest' - networks: - - wolfstar - restart: always - tty: true - -volumes: - postgres-data: - external: true - -networks: - wolfstar: From fdbe4c49b6d8845606f48665f08a4774c07cdefe Mon Sep 17 00:00:00 2001 From: RedStar Date: Fri, 12 Jun 2026 17:00:04 +0200 Subject: [PATCH 05/12] chore: update TypeScript configuration and dependencies - Removed deprecated TypeScript rule for await in commands. - Added new TypeScript rules for projects configuration. - Updated `pnpm-lock.yaml` to include `@rollup/plugin-alias` and `tsdown` dependencies. - Switched build and watch scripts in `package.json` files to use `tsdown`. - Introduced new `tsdown.config.ts` files for project-specific TypeScript configurations. --- .oxlintrc.json | 14 +++++++------ pnpm-lock.yaml | 12 +++++++++++ projects/gateway/package.json | 6 ++++-- projects/gateway/tsdown.config.ts | 33 ++++++++++++++++++++++++++++++ projects/shared/package.json | 6 ++++-- projects/shared/tsdown.config.ts | 34 +++++++++++++++++++++++++++++++ 6 files changed, 95 insertions(+), 10 deletions(-) create mode 100644 projects/gateway/tsdown.config.ts create mode 100644 projects/shared/tsdown.config.ts diff --git a/.oxlintrc.json b/.oxlintrc.json index 865394a8a..6b22593bd 100644 --- a/.oxlintrc.json +++ b/.oxlintrc.json @@ -194,12 +194,6 @@ "typescript/triple-slash-reference": "off" } }, - { - "files": ["src/commands/**/*.ts"], - "rules": { - "typescript/require-await": "off" - } - }, { "files": ["tests/**/*.?([cm])[jt]s?(x)"], "plugins": ["vitest", "typescript"], @@ -249,6 +243,14 @@ "no-await-in-loop": "off", "no-console": "off" } + }, + { + "files": ["projects/**/tsdown.config.ts"], + "plugins": ["typescript"], + "rules": { + "no-underscore-dangle": "off", + "no-console": "off" + } } ] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7ca006790..976782e24 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -167,6 +167,12 @@ importers: specifier: workspace:^ version: link:../shared devDependencies: + '@rollup/plugin-alias': + specifier: 6.0.0 + version: 6.0.0(rollup@4.61.1) + tsdown: + specifier: 0.22.0 + version: 0.22.0(typescript@6.0.3) typescript: specifier: ^6.0.0 version: 6.0.3 @@ -198,6 +204,12 @@ importers: specifier: ^5.0.0 version: 5.0.0 devDependencies: + '@rollup/plugin-alias': + specifier: 6.0.0 + version: 6.0.0(rollup@4.61.1) + tsdown: + specifier: 0.22.0 + version: 0.22.0(typescript@6.0.3) typescript: specifier: ^6.0.0 version: 6.0.3 diff --git a/projects/gateway/package.json b/projects/gateway/package.json index 0f23d3855..c722e1bf1 100644 --- a/projects/gateway/package.json +++ b/projects/gateway/package.json @@ -11,9 +11,9 @@ "#lib/*": "./dist/lib/*.js" }, "scripts": { - "build": "tsc -b src", + "build": "tsdown", "dev": "pnpm build && pnpm start", - "watch": "tsc -b src -w", + "watch": "tsdown --watch", "clean": "node scripts/clean.mjs", "start": "node --enable-source-maps dist/main.js" }, @@ -28,6 +28,8 @@ "wolfstar-shared": "workspace:^" }, "devDependencies": { + "@rollup/plugin-alias": "6.0.0", + "tsdown": "0.22.0", "typescript": "^6.0.0" } } diff --git a/projects/gateway/tsdown.config.ts b/projects/gateway/tsdown.config.ts new file mode 100644 index 000000000..381bb4478 --- /dev/null +++ b/projects/gateway/tsdown.config.ts @@ -0,0 +1,33 @@ +import { defineConfig } from 'tsdown'; +import { resolve, dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); +import alias from '@rollup/plugin-alias'; + +export default defineConfig({ + entry: ['src/**/*.ts'], + format: 'esm', + plugins: [ + alias({ + entries: [ + { + find: '#lib', + replacement: '#lib', + customResolver(source) { + const subPath = source.replace('#lib/', ''); + return resolve(__dirname, 'src/lib', `${subPath}.ts`); + } + } + ] + }) + ], + dts: true, + unbundle: true, + sourcemap: true, + minify: false, + platform: 'node', + tsconfig: 'src/tsconfig.json', + treeshake: true, + deps: { skipNodeModulesBundle: true } +}); diff --git a/projects/shared/package.json b/projects/shared/package.json index 584f4b4e9..d1423bb68 100644 --- a/projects/shared/package.json +++ b/projects/shared/package.json @@ -16,9 +16,9 @@ "#lib/*": "./dist/lib/*.js" }, "scripts": { - "build": "tsc -b src", + "build": "tsdown", "dev": "pnpm build && pnpm start", - "watch": "tsc -b src -w", + "watch": "tsdown --watch", "prisma:generate": "pnpm prisma generate", "clean": "node scripts/clean.mjs", "start": "node --enable-source-maps dist/main.js" @@ -34,6 +34,8 @@ "ix": "^5.0.0" }, "devDependencies": { + "@rollup/plugin-alias": "6.0.0", + "tsdown": "0.22.0", "typescript": "^6.0.0" } } diff --git a/projects/shared/tsdown.config.ts b/projects/shared/tsdown.config.ts new file mode 100644 index 000000000..0a3b7e2f3 --- /dev/null +++ b/projects/shared/tsdown.config.ts @@ -0,0 +1,34 @@ +import { defineConfig } from 'tsdown'; +import { resolve, dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +import alias from '@rollup/plugin-alias'; + +export default defineConfig({ + entry: ['src/index.ts'], + format: 'esm', + plugins: [ + alias({ + entries: [ + { + find: '#lib', + replacement: '#lib', + customResolver(source) { + const subPath = source.replace('#lib/', ''); + return resolve(__dirname, 'src/lib', `${subPath}.ts`); + } + } + ] + }) + ], + dts: true, + unbundle: true, + sourcemap: true, + minify: false, + platform: 'node', + tsconfig: 'src/tsconfig.json', + treeshake: true, + deps: { skipNodeModulesBundle: true } +}); From ebe145d14bfade1266e466d9e5eb4daf8e1d098e Mon Sep 17 00:00:00 2001 From: RedStar Date: Fri, 12 Jun 2026 17:09:29 +0200 Subject: [PATCH 06/12] refactor: update gateway client intents and application name - Replaced deprecated intents `GuildBans` and `GuildEmojisAndStickers` with `GuildModeration` and `GuildExpressions`. - Updated application name from `Skyra` to `WolfStar` in the logging output for better branding consistency. --- projects/gateway/src/main.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/projects/gateway/src/main.ts b/projects/gateway/src/main.ts index 0c424aa98..e3721bfa5 100644 --- a/projects/gateway/src/main.ts +++ b/projects/gateway/src/main.ts @@ -10,8 +10,8 @@ setup(new URL('../src/.env', import.meta.url)); createClient({ ws: { intents: - GatewayIntentBits.GuildBans | - GatewayIntentBits.GuildEmojisAndStickers | + GatewayIntentBits.GuildModeration | + GatewayIntentBits.GuildExpressions | GatewayIntentBits.GuildInvites | GatewayIntentBits.GuildMembers | GatewayIntentBits.GuildMessageReactions | @@ -45,7 +45,7 @@ console.log( String.raw`╲________╱╲___╱____╱ ╲______╱ ╲________╱╲________╱╲___╱____╱ ╲_____╱ ` ], extra: [ - ` Skyra ${envParseString('CLIENT_VERSION')} Gateway`, + ` WolfStar ${envParseString('CLIENT_VERSION')} Gateway`, ` ├ WebSocket: ${container.ws.options.shardCount} shards`, ` └ Redis : ${container.redis.options.host}:${container.redis.options.port}` ] From 1d19c2e5d878692b9229dcf4e043ba7cd9fe456f Mon Sep 17 00:00:00 2001 From: RedStar Date: Fri, 12 Jun 2026 17:11:47 +0200 Subject: [PATCH 07/12] chore: update Dockerfiles for bot and gateway to use pnpm - Changed base image from `node:16-buster-slim` to `node:24-alpine`. - Replaced `yarn` commands with `pnpm` for package management. - Updated environment variables to support `pnpm`. - Adjusted file copies to use `pnpm-lock.yaml` and `pnpm-workspace.yaml` instead of `yarn.lock` and `.yarnrc.yml`. --- projects/bot/Dockerfile | 27 ++++++++++++--------------- projects/gateway/Dockerfile | 26 ++++++++++++-------------- 2 files changed, 24 insertions(+), 29 deletions(-) diff --git a/projects/bot/Dockerfile b/projects/bot/Dockerfile index 950f7ef78..e3dd6325e 100644 --- a/projects/bot/Dockerfile +++ b/projects/bot/Dockerfile @@ -2,24 +2,22 @@ # Base Stage # # ================ # -FROM node:16-buster-slim as base +FROM node:24-alpine AS base WORKDIR /usr/src/app ENV HUSKY=0 ENV CI=true +ENV PNPM_HOME="/pnpm" +ENV PATH="$PNPM_HOME:$PATH" -RUN apt-get update && \ - apt-get upgrade -y --no-install-recommends && \ - apt-get install -y --no-install-recommends build-essential python3 libfontconfig1 dumb-init && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/* +RUN apk add --no-cache dumb-init g++ make python3 +RUN corepack enable && corepack prepare pnpm@11.4.0 --activate -COPY --chown=node:node yarn.lock . +COPY --chown=node:node pnpm-lock.yaml . +COPY --chown=node:node pnpm-workspace.yaml . COPY --chown=node:node package.json . COPY --chown=node:node projects/bot/package.json projects/bot/package.json -COPY --chown=node:node .yarnrc.yml . -COPY --chown=node:node .yarn/ .yarn/ ENTRYPOINT ["dumb-init", "--"] @@ -27,7 +25,7 @@ ENTRYPOINT ["dumb-init", "--"] # Builder Stage # # ================ # -FROM base as builder +FROM base AS builder ENV NODE_ENV="development" @@ -36,8 +34,8 @@ COPY --chown=node:node scripts/ scripts/ COPY --chown=node:node projects/bot/scripts/ projects/bot/scripts/ COPY --chown=node:node projects/bot/src/ projects/bot/src/ -RUN yarn install --immutable -RUN cd projects/bot/ && yarn run build +RUN pnpm install --frozen-lockfile +RUN cd projects/bot/ && pnpm run build # ================ # # Runner Stage # @@ -48,15 +46,14 @@ FROM base AS runner ENV NODE_ENV="production" ENV NODE_OPTIONS="--enable-source-maps --max_old_space_size=4096" -COPY --chown=node:node projects/bot/scripts/workerTsLoader.js projects/bot/scripts/workerTsLoader.js COPY --chown=node:node projects/bot/src/.env projects/bot/src/.env COPY --chown=node:node --from=builder /usr/src/app/projects/bot/dist projects/bot/dist -RUN yarn workspaces focus --all --production +RUN pnpm install --prod --frozen-lockfile --offline RUN chown node:node /usr/src/app/ USER node WORKDIR /usr/src/app/projects/bot -CMD [ "yarn", "run", "start" ] +CMD [ "pnpm", "run", "start" ] diff --git a/projects/gateway/Dockerfile b/projects/gateway/Dockerfile index 2b166f7da..ea05de9c5 100644 --- a/projects/gateway/Dockerfile +++ b/projects/gateway/Dockerfile @@ -2,24 +2,22 @@ # Base Stage # # ================ # -FROM node:16-buster-slim as base +FROM node:24-alpine AS base WORKDIR /usr/src/app ENV HUSKY=0 ENV CI=true +ENV PNPM_HOME="/pnpm" +ENV PATH="$PNPM_HOME:$PATH" -RUN apt-get update && \ - apt-get upgrade -y --no-install-recommends && \ - apt-get install -y --no-install-recommends build-essential python3 libfontconfig1 dumb-init && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/* +RUN apk add --no-cache dumb-init g++ make python3 +RUN corepack enable && corepack prepare pnpm@11.4.0 --activate -COPY --chown=node:node yarn.lock . +COPY --chown=node:node pnpm-lock.yaml . +COPY --chown=node:node pnpm-workspace.yaml . COPY --chown=node:node package.json . COPY --chown=node:node projects/gateway/package.json projects/gateway/package.json -COPY --chown=node:node .yarnrc.yml . -COPY --chown=node:node .yarn/ .yarn/ ENTRYPOINT ["dumb-init", "--"] @@ -27,7 +25,7 @@ ENTRYPOINT ["dumb-init", "--"] # Builder Stage # # ================ # -FROM base as builder +FROM base AS builder ENV NODE_ENV="development" @@ -36,8 +34,8 @@ COPY --chown=node:node scripts/ scripts/ COPY --chown=node:node projects/gateway/scripts/ projects/gateway/scripts/ COPY --chown=node:node projects/gateway/src/ projects/gateway/src/ -RUN yarn install --immutable -RUN cd projects/gateway/ && yarn run build +RUN pnpm install --frozen-lockfile +RUN cd projects/gateway/ && pnpm run build # ================ # # Runner Stage # @@ -51,11 +49,11 @@ ENV NODE_OPTIONS="--enable-source-maps --max_old_space_size=4096" COPY --chown=node:node projects/gateway/src/.env projects/gateway/src/.env COPY --chown=node:node --from=builder /usr/src/app/projects/gateway/dist projects/gateway/dist -RUN yarn workspaces focus --all --production +RUN pnpm install --prod --frozen-lockfile --offline RUN chown node:node /usr/src/app/ USER node WORKDIR /usr/src/app/projects/gateway -CMD [ "yarn", "run", "start" ] +CMD [ "pnpm", "run", "start" ] From 2a612d8d478e486ff261ed6ef2e1f0bcb9ac75b2 Mon Sep 17 00:00:00 2001 From: RedStar Date: Fri, 12 Jun 2026 17:14:53 +0200 Subject: [PATCH 08/12] chore: remove unused TypeScript ESLint configuration files - Deleted `tsconfig.eslint.json` files from both the bot and gateway projects as they are no longer needed. --- projects/bot/tsconfig.eslint.json | 4 ---- projects/gateway/tsconfig.eslint.json | 4 ---- 2 files changed, 8 deletions(-) delete mode 100644 projects/bot/tsconfig.eslint.json delete mode 100644 projects/gateway/tsconfig.eslint.json diff --git a/projects/bot/tsconfig.eslint.json b/projects/bot/tsconfig.eslint.json deleted file mode 100644 index 388bb593b..000000000 --- a/projects/bot/tsconfig.eslint.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "extends": "../../tsconfig.eslint.json", - "include": ["src", "tests"] -} diff --git a/projects/gateway/tsconfig.eslint.json b/projects/gateway/tsconfig.eslint.json deleted file mode 100644 index 388bb593b..000000000 --- a/projects/gateway/tsconfig.eslint.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "extends": "../../tsconfig.eslint.json", - "include": ["src", "tests"] -} From 189710dda08db48c1f14bcb3542b654fc03f6721 Mon Sep 17 00:00:00 2001 From: RedStar Date: Fri, 12 Jun 2026 17:16:47 +0200 Subject: [PATCH 09/12] chore: fix pre-commit hook and nano-staged configuration Co-Authored-By: Claude Sonnet 4.6 --- .husky/pre-commit | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.husky/pre-commit b/.husky/pre-commit index 46a165512..b56825eae 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,3 +1,3 @@ #!/bin/sh -pnpm lint-staged +pnpm exec nano-staged diff --git a/package.json b/package.json index a27e712c4..9add31692 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "@commitlint/config-conventional" ] }, - "lint-staged": { + "nano-staged": { "*": "oxfmt --no-error-on-unmatched-pattern", "*.{mjs,js,ts}": "oxlint --fix" }, From 8864bfef3f5961bb9b9bb20b46c54255f1d0d3eb Mon Sep 17 00:00:00 2001 From: RedStar Date: Fri, 12 Jun 2026 17:17:17 +0200 Subject: [PATCH 10/12] chore: apply oxfmt hook fixes for husky and commitlint scripts Co-Authored-By: Claude Sonnet 4.6 --- .husky/commit-msg | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.husky/commit-msg b/.husky/commit-msg index 5aabba4da..27d06982c 100644 --- a/.husky/commit-msg +++ b/.husky/commit-msg @@ -1,3 +1,3 @@ #!/bin/sh -pnpm commitlint --edit $1 +pnpm exec commitlint --edit $1 diff --git a/package.json b/package.json index 9add31692..2b6514922 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "format": "prettier --write --log-level=warn \"projects/**/*.{js,mjs,ts,json}\"", "audit:verify": "node scripts/audit-verify.mjs", "scripts:tlds": "node scripts/tlds.mjs", - "prepare": "husky" + "prepare": "node .husky/install.mjs" }, "devDependencies": { "@commitlint/cli": "^21.0.2", From 2a665ff158339d5b5fd45341e73c89ce76d334e7 Mon Sep 17 00:00:00 2001 From: RedStar Date: Fri, 12 Jun 2026 17:17:40 +0200 Subject: [PATCH 11/12] chore: remove prettier format script in favour of oxfmt Co-Authored-By: Claude Sonnet 4.6 --- package.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/package.json b/package.json index 2b6514922..d7fa00eb3 100644 --- a/package.json +++ b/package.json @@ -15,8 +15,6 @@ "test": "vitest run --config vitest.config.ts", "lint:fix": "oxlint --fix && oxfmt", "lint": "oxlint && oxfmt --check", - "format": "prettier --write --log-level=warn \"projects/**/*.{js,mjs,ts,json}\"", - "audit:verify": "node scripts/audit-verify.mjs", "scripts:tlds": "node scripts/tlds.mjs", "prepare": "node .husky/install.mjs" }, From f6bebbe27a83d2aa31ea9f0d58859f923f143ef2 Mon Sep 17 00:00:00 2001 From: RedStar Date: Fri, 12 Jun 2026 17:18:47 +0200 Subject: [PATCH 12/12] chore: remove audit-verify script replaced by V7 architecture Co-Authored-By: Claude Sonnet 4.6 --- scripts/audit-verify.mjs | 166 --------------------------------------- 1 file changed, 166 deletions(-) delete mode 100644 scripts/audit-verify.mjs diff --git a/scripts/audit-verify.mjs b/scripts/audit-verify.mjs deleted file mode 100644 index d9e059520..000000000 --- a/scripts/audit-verify.mjs +++ /dev/null @@ -1,166 +0,0 @@ -/** - * Standalone audit chain integrity verifier. - * - * Reads all audit_event rows from Postgres, re-derives each row's SHA-256 - * envelope hash, validates the prevHash chain, and exits 1 if any violation - * is found. - * - * Usage: node scripts/audit-verify.mjs - * DATABASE_URL=postgres://... node scripts/audit-verify.mjs - */ - -import { readFileSync } from 'node:fs'; -import { resolve, dirname } from 'node:path'; -import { fileURLToPath } from 'node:url'; -import { createHash } from 'node:crypto'; -import pg from 'pg'; - -const { Pool } = pg; - -// --------------------------------------------------------------------------- -// .env loader — mirrors prisma.config.ts (reads src/.env) -// --------------------------------------------------------------------------- - -const __dirname = dirname(fileURLToPath(import.meta.url)); -const envPath = resolve(__dirname, '../src/.env'); - -try { - const raw = readFileSync(envPath, 'utf8'); - for (const line of raw.split('\n')) { - const trimmed = line.trim(); - if (!trimmed || trimmed.startsWith('#')) continue; - const eqIdx = trimmed.indexOf('='); - if (eqIdx === -1) continue; - const key = trimmed.slice(0, eqIdx).trim(); - const val = trimmed - .slice(eqIdx + 1) - .trim() - .replace(/^["']|["']$/g, ''); - if (key && !(key in process.env)) process.env[key] = val; - } -} catch { - // .env not present — rely on environment variables already set -} - -// --------------------------------------------------------------------------- -// Envelope helpers (inlined from AuditLogEnvelope.ts — must stay in sync) -// --------------------------------------------------------------------------- - -function canonicalize(value) { - if (typeof value === 'bigint') return JSON.stringify(value.toString()); - if (value === null || typeof value !== 'object') return JSON.stringify(value); - if (Array.isArray(value)) return `[${value.map(canonicalize).join(',')}]`; - const keys = Object.keys(value).sort(); - return `{${keys.map((k) => `${JSON.stringify(k)}:${canonicalize(value[k])}`).join(',')}}`; -} - -function hashEnvelope(envelope) { - return createHash('sha256').update(canonicalize(envelope)).digest('hex'); -} - -// --------------------------------------------------------------------------- -// Main -// --------------------------------------------------------------------------- - -const DATABASE_URL = process.env.DATABASE_URL; -if (!DATABASE_URL) { - console.error('[ERROR] DATABASE_URL is not set. Set it in src/.env or the environment.'); - process.exit(1); -} - -const pool = new Pool({ connectionString: DATABASE_URL }); - -let client; -try { - client = await pool.connect(); -} catch (err) { - console.error(`[ERROR] Could not connect to database: ${err.message}`); - await pool.end(); - process.exit(1); -} - -let violations = 0; - -try { - const { rows } = await client.query( - `SELECT id, action, actor_type, actor_id, outcome, tenant_id, - timestamp, changes, reason, prev_hash, hash - FROM audit_event` - ); - - console.log(`Verifying ${rows.length} audit event(s)...`); - - if (rows.length > 0) { - // Index rows by prevHash for O(1) chain traversal - const byPrevHash = new Map(); // prevHash -> row - let root = null; - - for (const row of rows) { - if (row.prev_hash === null) { - if (root) { - console.error(`[CHAIN FORK] Multiple root events (prevHash=null): ${root.id} and ${row.id}`); - violations++; - } else { - root = row; - } - } else { - if (byPrevHash.has(row.prev_hash)) { - console.error(`[CHAIN FORK] Multiple events claim prevHash=${row.prev_hash}`); - violations++; - } - byPrevHash.set(row.prev_hash, row); - } - } - - if (!root) { - console.error(`[ERROR] No root event found (prevHash=null) but rows exist`); - console.error(`[ORPHAN] ${rows.length} row(s) unreachable (no chain root)`); - violations += 1 + rows.length; - } else { - let current = root; - const visited = new Set(); - - while (current) { - if (visited.has(current.id)) { - console.error(`[CYCLE] Cycle detected at id=${current.id}`); - violations++; - break; - } - visited.add(current.id); - - const envelope = { - action: current.action, - actor: { type: current.actor_type, id: current.actor_id }, - outcome: current.outcome, - tenantId: current.tenant_id, - timestamp: current.timestamp.toISOString(), - changes: current.changes, - reason: current.reason, - requestId: null, - traceId: null, - prevHash: current.prev_hash - }; - - const computedHash = hashEnvelope(envelope); - if (computedHash !== current.hash) { - console.error(`[HASH MISMATCH] id=${current.id} stored=${current.hash} computed=${computedHash}`); - violations++; - } - - current = byPrevHash.get(current.hash) ?? null; - } - - const orphans = rows.length - visited.size; - if (orphans > 0) { - console.error(`[ORPHAN] ${orphans} row(s) not reachable from the chain root`); - violations += orphans; - } - } - } -} finally { - client.release(); - await pool.end(); -} - -console.log(`\nAudit chain verification: ${violations} integrity violation(s) found`); -if (violations > 0) process.exit(1);