From c8ccdb35b9a40e72e290eb5f7ad43fa9aecf5e33 Mon Sep 17 00:00:00 2001 From: Kalle <38327916+Sendouc@users.noreply.github.com> Date: Sat, 9 Sep 2023 14:02:38 +0300 Subject: [PATCH] Move bot to https://github.com/Sendouc/lohi --- .eslintrc.js | 1 - README.md | 1 - discord-bot/.env.example | 5 - discord-bot/commands/access.ts | 88 --- discord-bot/commands/color.ts | 79 --- discord-bot/commands/index.ts | 51 -- discord-bot/commands/lfg.ts | 49 -- discord-bot/commands/login.ts | 96 ---- discord-bot/commands/pings.ts | 69 --- discord-bot/commands/plus.ts | 85 --- discord-bot/commands/q-data.json | 81 --- discord-bot/commands/q.ts | 106 ---- discord-bot/commands/updateall.ts | 68 --- discord-bot/deploy-commands.ts | 46 -- discord-bot/handleMemberJoin.ts | 9 - discord-bot/ids.ts | 36 -- discord-bot/index.ts | 39 -- discord-bot/package-lock.json | 873 ------------------------------ discord-bot/package.json | 19 - discord-bot/tsconfig.bot.json | 6 - discord-bot/types.ts | 13 - discord-bot/utils.ts | 57 -- tsconfig.json | 1 - 23 files changed, 1878 deletions(-) delete mode 100644 discord-bot/.env.example delete mode 100644 discord-bot/commands/access.ts delete mode 100644 discord-bot/commands/color.ts delete mode 100644 discord-bot/commands/index.ts delete mode 100644 discord-bot/commands/lfg.ts delete mode 100644 discord-bot/commands/login.ts delete mode 100644 discord-bot/commands/pings.ts delete mode 100644 discord-bot/commands/plus.ts delete mode 100644 discord-bot/commands/q-data.json delete mode 100644 discord-bot/commands/q.ts delete mode 100644 discord-bot/commands/updateall.ts delete mode 100644 discord-bot/deploy-commands.ts delete mode 100644 discord-bot/handleMemberJoin.ts delete mode 100644 discord-bot/ids.ts delete mode 100644 discord-bot/index.ts delete mode 100644 discord-bot/package-lock.json delete mode 100644 discord-bot/package.json delete mode 100644 discord-bot/tsconfig.bot.json delete mode 100644 discord-bot/types.ts delete mode 100644 discord-bot/utils.ts diff --git a/.eslintrc.js b/.eslintrc.js index 13c4dac3b..0646ccf0d 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -5,7 +5,6 @@ module.exports = { tsconfigRootDir: __dirname, project: ["./tsconfig.json"], }, - ignorePatterns: ["discord-bot/**/*"], plugins: ["@typescript-eslint"], extends: [ "eslint:recommended", diff --git a/README.md b/README.md index 6d365b32b..43a14c614 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,6 @@ sendou.ink/ │ ├── styles/ -- All .css files of the project for styling │ ├── utils/ -- Random helper functions used in many places │ └── permissions.ts / -- What actions are allowed. Separated by frontend and backend as frontend has constraints based on what user sees. -├── discord-bot/ -- Lohi Discord bot that works together with sendou.ink ├── migrations/ -- Database migrations ├── public/ -- Images, built assets etc. static files to be served as is └── scripts/ -- Stand-alone scripts to be run outside of the app diff --git a/discord-bot/.env.example b/discord-bot/.env.example deleted file mode 100644 index 15db3efa9..000000000 --- a/discord-bot/.env.example +++ /dev/null @@ -1,5 +0,0 @@ -BOT_TOKEN= -TEST_GUILD_ID= -BOT_ID= -SENDOU_INK_URL=http://localhost:5800 -LOHI_TOKEN=salmon \ No newline at end of file diff --git a/discord-bot/commands/access.ts b/discord-bot/commands/access.ts deleted file mode 100644 index 1c8f682b3..000000000 --- a/discord-bot/commands/access.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { SlashCommandBuilder } from "@discordjs/builders"; -import { CacheType, CommandInteraction, GuildMember } from "discord.js"; -import ids from "../ids"; -import type { BotCommand } from "../types"; -import { isPlusTierRoleId, plusTierToRoleId, usersWithAccess } from "../utils"; - -const COMMAND_NAME = "access"; - -export const accessCommand: BotCommand = { - guilds: [ids.guilds.plusServer], - name: COMMAND_NAME, - builder: new SlashCommandBuilder() - .setName(COMMAND_NAME) - .setDescription( - "Get the corresponding Plus Server membership role if you have access", - ), - execute: async ({ interaction }) => { - await givePlusRoleToMember({ - interaction, - member: interaction.member as GuildMember, - }); - }, -}; - -export async function givePlusRoleToMember({ - interaction, - member, -}: { - interaction?: CommandInteraction; - member: GuildMember; -}) { - const { users } = await usersWithAccessCached(); - const usersPlusTier = users[member.id]; - - if (!usersPlusTier) { - return interaction?.reply({ - content: "You currently don't have access", - ephemeral: true, - }); - } - - const targetRoleId = plusTierToRoleId(usersPlusTier); - if (!targetRoleId) { - throw new Error(`No role for plus tier ${usersPlusTier}`); - } - - const roleManager = member.roles; - const usersRoleIds = roleManager.cache.map((r) => r.id); - const alreadyHasRole = usersRoleIds.some((id) => id === targetRoleId); - - if (alreadyHasRole) { - return interaction?.reply({ - content: `You have access to +${usersPlusTier} and already have the role for it`, - ephemeral: true, - }); - } - - const roleIdsToDelete = usersRoleIds.filter(isPlusTierRoleId); - - for (const roleIdToDelete of roleIdsToDelete) { - await roleManager.remove(roleIdToDelete); - } - - await roleManager.add(targetRoleId); - - if (interaction) { - return interaction.reply({ - content: `Gave the role giving access to +${usersPlusTier}`, - ephemeral: true, - }); - } -} - -let cachedAt: Date | null = null; -let usersWithAccessCache: ReturnType | null = null; -async function usersWithAccessCached() { - // fetch fresh data every hour because votings end at the hour - if ( - !cachedAt || - !usersWithAccessCache || - cachedAt.getHours() !== new Date().getHours() - ) { - cachedAt = new Date(); - usersWithAccessCache = usersWithAccess(); - } - - return usersWithAccessCache; -} diff --git a/discord-bot/commands/color.ts b/discord-bot/commands/color.ts deleted file mode 100644 index cbb0606c7..000000000 --- a/discord-bot/commands/color.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { SlashCommandBuilder } from "@discordjs/builders"; -import type { GuildMemberRoleManager } from "discord.js"; -import ids from "../ids"; -import type { BotCommand } from "../types"; -import { patronsFiveDollarsAndOver } from "../utils"; - -const COMMAND_NAME = "color"; -const ACTION_ARG = "hex"; -const ADMIN_DISCORD_ID = "79237403620945920"; - -export const colorCommand: BotCommand = { - guilds: [ids.guilds.plusServer, ids.guilds.sendou], - name: COMMAND_NAME, - builder: new SlashCommandBuilder() - .setName(COMMAND_NAME) - .setDescription( - "Get/update color role (Supporter tier on Patreon or higher needed)", - ) - .addStringOption((option) => - option - .setName(ACTION_ARG) - .setDescription("Hex code of the color role") - .setRequired(true), - ), - execute: async ({ interaction, client }) => { - let hexCode = interaction.options.getString(ACTION_ARG); - if (!hexCode.startsWith("#")) { - hexCode = `#${hexCode}`; - } - - if (!validateHexCode(hexCode)) { - return interaction.reply({ - content: - "Hex code is invalid. Google color picker to find a valid one or DM Sendou for help.", - ephemeral: true, - }); - } - - const patrons = await patronsFiveDollarsAndOver(); - - if ( - !patrons.some((p) => p.discordId === interaction.user.id) && - interaction.user.id !== ADMIN_DISCORD_ID - ) { - return interaction.reply({ - content: - "This command is only available to patrons of 'Supporter' tier or higher https://www.patreon.com/sendou", - ephemeral: true, - }); - } - - const memberRoles = interaction.member?.roles as GuildMemberRoleManager; - - const roleToUpdate = memberRoles.cache.find((role) => - role.name.includes("!"), - ); - - if (roleToUpdate) { - await roleToUpdate.edit({ color: hexCode }); - } else { - const role = await interaction.guild!.roles.create({ - color: hexCode, - name: `${interaction.user.username}!`, - position: 10, - }); - - await memberRoles.add(role); - } - - return interaction.reply({ - content: roleToUpdate ? "Role updated" : "Role created", - ephemeral: true, - }); - }, -}; - -function validateHexCode(hexCode: string) { - return /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(hexCode); -} diff --git a/discord-bot/commands/index.ts b/discord-bot/commands/index.ts deleted file mode 100644 index e85a97797..000000000 --- a/discord-bot/commands/index.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { questionCommand } from "./q"; -import { lfgRoleCommand } from "./lfg"; -import { accessCommand } from "./access"; -import { plusCommand } from "./plus"; -import { updateAllCommand } from "./updateall"; -import { pingRolesCommand } from "./pings"; -import { colorCommand } from "./color"; -import { loginCommand, updateProfileCommand } from "./login"; -import type { BotCommand } from "../types"; - -export const commands = [ - questionCommand, - lfgRoleCommand, - accessCommand, - plusCommand, - updateAllCommand, - pingRolesCommand, - colorCommand, - loginCommand, - updateProfileCommand, -]; - -export const commandsMap = Object.fromEntries(commands.map((c) => [c.name, c])); - -interface CommandsPerGuilds { - guildId: string; - commands: BotCommand[]; -} -export function commandsPerGuild() { - const result: CommandsPerGuilds[] = []; - - for (const command of commands) { - for (const guildId of command.guilds) { - const guildsCommands = result.find((c) => c.guildId === guildId); - - if (!guildsCommands) { - const guildsCommands: CommandsPerGuilds = { - guildId, - commands: [], - }; - guildsCommands.commands.push(command); - result.push(guildsCommands); - continue; - } - - guildsCommands.commands.push(command); - } - } - - return result; -} diff --git a/discord-bot/commands/lfg.ts b/discord-bot/commands/lfg.ts deleted file mode 100644 index db1b14607..000000000 --- a/discord-bot/commands/lfg.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { SlashCommandBuilder } from "@discordjs/builders"; -import type { GuildMemberRoleManager } from "discord.js"; -import ids from "../ids"; -import type { BotCommand } from "../types"; - -const COMMAND_NAME = "lfg"; -const ACTION_ARG = "action"; - -export const lfgRoleCommand: BotCommand = { - guilds: [ids.guilds.sro], - name: COMMAND_NAME, - builder: new SlashCommandBuilder() - .setName(COMMAND_NAME) - .setDescription( - "Turn on/off pings when people are looking for someone to play with", - ) - .addStringOption((option) => - option - .setName(ACTION_ARG) - .setDescription("Add or remove the role?") - .setRequired(true) - .addChoices( - { - name: "add", - value: "add", - }, - { - name: "remove", - value: "remove", - }, - ), - ), - execute: async ({ interaction }) => { - const roleBeingAdded = interaction.options.getString(ACTION_ARG) === "add"; - const commandUserRoles = interaction.member - ?.roles as GuildMemberRoleManager; - - if (roleBeingAdded) { - await commandUserRoles.add(ids.roles.sroLfg); - } else { - await commandUserRoles.remove(ids.roles.sroLfg); - } - - return interaction.reply({ - content: roleBeingAdded ? "Role added" : "Role removed", - ephemeral: true, - }); - }, -}; diff --git a/discord-bot/commands/login.ts b/discord-bot/commands/login.ts deleted file mode 100644 index 1c3804a0a..000000000 --- a/discord-bot/commands/login.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { SlashCommandBuilder } from "@discordjs/builders"; -import type { CommandInteraction, User } from "discord.js"; -import ids from "../ids"; -import type { BotCommand } from "../types"; -import { sendouInkFetch } from "../utils"; - -const LOGIN_COMMAND_NAME = "login"; -const UPDATE_PROFILE_COMMAND_NAME = "update-profile"; - -export const loginCommand: BotCommand = { - guilds: [ids.guilds.plusServer, ids.guilds.sendou], - name: LOGIN_COMMAND_NAME, - builder: new SlashCommandBuilder() - .setName(LOGIN_COMMAND_NAME) - .setDescription("Get log in link for sendou.ink"), - execute: async ({ interaction }) => { - await execute(interaction, false); - }, -}; - -export const updateProfileCommand: BotCommand = { - guilds: [ids.guilds.plusServer, ids.guilds.sendou], - name: UPDATE_PROFILE_COMMAND_NAME, - builder: new SlashCommandBuilder() - .setName(UPDATE_PROFILE_COMMAND_NAME) - .setDescription("Update your username and profile picture on sendou.ink"), - execute: async ({ interaction }) => { - await execute(interaction, true); - }, -}; - -async function execute( - interaction: CommandInteraction, - updateOnly: boolean, -) { - const user = interaction.member?.user as User; - if (!user) { - return interaction.reply({ - content: "Something went wrong", - }); - } - - const hasUniqueUsername = user.discriminator === "0"; - - const discordName = hasUniqueUsername ? user.globalName : user.username; - const discordUniqueName = hasUniqueUsername ? user.username : null; - if (!discordName || !discordUniqueName) { - return interaction.reply({ - content: - "Can't do this with an account that is missing the new kind of Discord username", - }); - } - - const searchParams = new URLSearchParams( - user.avatar - ? { - discordAvatar: user.avatar, - discordId: user.id, - discordName, - discordUniqueName, - updateOnly: String(updateOnly), - } - : { - discordId: user.id, - discordName, - discordUniqueName, - updateOnly: String(updateOnly), - }, - ); - - const response = await sendouInkFetch(`/auth/create-link?${searchParams}`, { - method: "post", - }); - - if (updateOnly) { - if (!response.ok) { - return interaction.reply({ - content: "Something went wrong when updating", - ephemeral: true, - }); - } - - return interaction.reply({ - content: "Updated your profile on sendou.ink", - ephemeral: true, - }); - } - - const { code } = await response.json(); - - return interaction.reply({ - content: - "Use the link below to log in to sendou.ink. It's active for 10 minutes. ⚠️ Don't share this link with others as it will allow them to log in to your account.\n\n[log in link](https://sendou.ink/auth/login?code=${code})", - ephemeral: true, - }); -} diff --git a/discord-bot/commands/pings.ts b/discord-bot/commands/pings.ts deleted file mode 100644 index 78b9e8c09..000000000 --- a/discord-bot/commands/pings.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { SlashCommandBuilder } from "@discordjs/builders"; -import type { GuildMemberRoleManager } from "discord.js"; -import ids from "../ids"; -import type { BotCommand } from "../types"; - -const COMMAND_NAME = "pings"; -const TIER_ARG = "tier"; -const ACTION_ARG = "action"; - -export const pingRolesCommand: BotCommand = { - guilds: [ids.guilds.plusServer], - name: COMMAND_NAME, - builder: new SlashCommandBuilder() - .setName(COMMAND_NAME) - .setDescription( - "Turn on/off pings when people are looking for someone to play with", - ) - .addStringOption((option) => - option - .setName(TIER_ARG) - .setDescription("+2 or +3?") - .setRequired(true) - .addChoices( - { - name: "+2", - value: "+2", - }, - { - name: "+3", - value: "+3", - }, - ), - ) - .addStringOption((option) => - option - .setName(ACTION_ARG) - .setDescription("Add or remove the role?") - .setRequired(true) - .addChoices( - { - name: "add", - value: "add", - }, - { - name: "remove", - value: "remove", - }, - ), - ), - execute: async ({ interaction }) => { - const roleBeingAdded = interaction.options.getString(ACTION_ARG) === "add"; - const tier = interaction.options.getString(TIER_ARG); - const role = - tier === "+2" ? ids.roles.plusTwoPings : ids.roles.plusThreePings; - const commandUserRoles = interaction.member - ?.roles as GuildMemberRoleManager; - - if (roleBeingAdded) { - await commandUserRoles.add(role); - } else { - await commandUserRoles.remove(role); - } - - return interaction.reply({ - content: `${tier} pings role ${roleBeingAdded ? "added" : "removed"}`, - ephemeral: true, - }); - }, -}; diff --git a/discord-bot/commands/plus.ts b/discord-bot/commands/plus.ts deleted file mode 100644 index 55cdf5602..000000000 --- a/discord-bot/commands/plus.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { SlashCommandBuilder } from "@discordjs/builders"; -import { Client, GuildMember, Role } from "discord.js"; -import invariant from "tiny-invariant"; -import ids from "../ids"; -import type { BotCommand } from "../types"; -import { plusTierToRoleId, usersWithAccess } from "../utils"; - -const COMMAND_NAME = "plus"; -const ACTION_ARG = "dry"; - -export const plusCommand: BotCommand = { - guilds: [ids.guilds.adminServer], - name: COMMAND_NAME, - builder: new SlashCommandBuilder() - .setName(COMMAND_NAME) - .setDescription("Remove roles from Plus Server from people who lost access") - .addBooleanOption((option) => - option - .setName(ACTION_ARG) - .setDescription("If true doesn't remove or give roles") - .setRequired(true), - ), - // @ts-expect-error TODO: fix. Library doesn't seem to extract API Message type so I could fix this error? - execute: async ({ interaction, client }) => { - const isDryRun = interaction.options.getBoolean(ACTION_ARG); - - await interaction.deferReply({ ephemeral: true }); - - const { users } = await usersWithAccess(); - - let removed = 0; - let added = 0; - - for (const { member, roleIds } of await membersWithPlusRoles(client)) { - const userMemberStatus = users[member.id]; - const roleIdToGive = plusTierToRoleId(userMemberStatus); - - const roleIdsToRemove = roleIds.filter((id) => id !== roleIdToGive); - - for (const idToRemove of roleIdsToRemove) { - if (!isDryRun) await member.roles.remove(idToRemove); - removed++; - } - - if (roleIdToGive && !roleIds.includes(roleIdToGive)) { - if (!isDryRun) await member.roles.add(roleIdToGive); - added++; - } - } - - return interaction.editReply(`Removed ${removed} roles, gave ${added}.`); - }, -}; - -async function membersWithPlusRoles(client: Client) { - const plusServer = client.guilds.cache.find( - (g) => g.id === ids.guilds.plusServer, - ); - invariant(plusServer); - - const plusOne = await plusServer.roles.fetch(ids.roles.plusOne); - const plusTwo = await plusServer.roles.fetch(ids.roles.plusTwo); - const plusThree = await plusServer.roles.fetch(ids.roles.plusThree); - - const memberIdToRoles = new Map< - string, - { member: GuildMember; roleIds: string[] } - >(); - - for (const role of [plusOne, plusTwo, plusThree]) { - invariant(role); - - for (const [, member] of role.members) { - const value = memberIdToRoles.get(member.id) ?? { member, roleIds: [] }; - - value.roleIds.push(role.id); - memberIdToRoles.set(member.id, value); - } - } - - return Array.from(memberIdToRoles.values()).map(({ roleIds, member }) => ({ - roleIds, - member, - })); -} diff --git a/discord-bot/commands/q-data.json b/discord-bot/commands/q-data.json deleted file mode 100644 index c62a4dc3d..000000000 --- a/discord-bot/commands/q-data.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "sg": { - "seeking": [ - "https://cdn.discordapp.com/attachments/865925063731445760/865925984065552404/SG_NT_Seeking.png", - "https://cdn.discordapp.com/attachments/865925063731445760/865926005776056360/SG_HT_Seeking.png" - ], - "grillers": [ - "https://cdn.discordapp.com/attachments/951441475034558484/951441708745388062/SG_NT_Grillers.png", - "https://cdn.discordapp.com/attachments/951441475034558484/951441742283018291/SG_HT_Grillers.png" - ], - "rush": [ - "https://cdn.discordapp.com/attachments/951442362775765022/951442493927485450/SG_NT_Rush.png", - "https://cdn.discordapp.com/attachments/951442362775765022/951442573971578880/SG_HT_Rush.png" - ] - }, - "mb": { - "seeking": [ - "https://cdn.discordapp.com/attachments/865925063731445760/865926250963140628/MB_NT_Seeking.png", - "https://cdn.discordapp.com/attachments/865925063731445760/865926264409030696/MB_HT_Seeking.png" - ], - "grillers": [ - "https://cdn.discordapp.com/attachments/951441475034558484/951441787573141534/MB_NT_Grillers.png", - "https://cdn.discordapp.com/attachments/951441475034558484/951441828299817020/MB_HT_Grillers.png" - ], - "rush": [ - "https://cdn.discordapp.com/attachments/951442362775765022/951442753563291688/MB_NT_Rush.png", - "https://cdn.discordapp.com/attachments/951442362775765022/951442772345356288/MB_HT_Rush.png" - ] - }, - "lo": { - "seeking": [ - "https://cdn.discordapp.com/attachments/865925063731445760/865926336199655424/LO_NT_Seeking.png", - "https://cdn.discordapp.com/attachments/865925063731445760/865926346545954836/LO_HT_Seeking.png" - ], - "grillers": [ - "https://cdn.discordapp.com/attachments/951441475034558484/951441880841854986/LO_NT_Grillers.png", - "https://cdn.discordapp.com/attachments/951441475034558484/951441897052864532/LO_HT_Grillers.png" - ], - "rush": [ - "https://cdn.discordapp.com/attachments/951442362775765022/951442800166174782/LO_NT_Rush.png", - "https://cdn.discordapp.com/attachments/951442362775765022/951442813596360714/LO_HT_Rush.png" - ] - }, - "ss": { - "seeking": [ - "https://cdn.discordapp.com/attachments/865925063731445760/865926389223784468/SS_NT_Seeking.png", - "https://cdn.discordapp.com/attachments/865925063731445760/865926397561798656/SS_HT_Seeking.png" - ], - "grillers": [ - "https://cdn.discordapp.com/attachments/951441475034558484/951441959510233118/SS_NT_Grillers.png", - "https://cdn.discordapp.com/attachments/951441475034558484/951441974198698005/SS_HT_Grillers.png" - ], - "rush": [ - "https://cdn.discordapp.com/attachments/951442362775765022/951442852485935164/SS_NT_Rush.png", - "https://cdn.discordapp.com/attachments/951442362775765022/951442864305479710/SS_HT_Rush.png" - ] - }, - "ap": { - "seeking": [ - "https://cdn.discordapp.com/attachments/865925063731445760/865926537629663242/AP_NT_Seeking.png", - "https://cdn.discordapp.com/attachments/865925063731445760/865926546635620382/AP_HT_Seeking.png" - ], - "grillers": [ - "https://cdn.discordapp.com/attachments/951441475034558484/951442012626878514/AP_NT_Grillers.png", - "https://cdn.discordapp.com/attachments/951441475034558484/951442021246201906/AP_HT_Grillers.png" - ], - "rush": [ - "https://cdn.discordapp.com/attachments/951442362775765022/951442890721206312/AP_NT_Rush.png", - "https://cdn.discordapp.com/attachments/951442362775765022/951442901219561472/AP_HT_Rush.png" - ] - }, - "fundamentals": "https://docs.google.com/document/d/1WTDiKSzV3SaD8Sn7wWlGreE2Y4Y7UrOv3SSv7qtzvcg/edit?usp=sharing", - "fundamentals2": "https://youtu.be/BvGbmLO94Po", - "advanced": "https://docs.google.com/document/d/16wcdlxqwqBvOnXIviB_ig0FS5_a96DKwYUIiGh6YHa8/edit?usp=sharing", - "spawns": "https://cdn.discordapp.com/attachments/836884751922757652/836886520250105886/SR_Time_Interval.png", - "ballpoint": "https://youtu.be/oSf39Yn0wOU", - "explo": "https://youtu.be/1qSW0_fA_L4", - "dynamo": "https://youtu.be/GrCCAI8giKc", - "bamboo": "https://youtu.be/yptwgqIoYiI", - "hydra": "https://youtu.be/_YduyOTVoLk" -} diff --git a/discord-bot/commands/q.ts b/discord-bot/commands/q.ts deleted file mode 100644 index bb3ff754a..000000000 --- a/discord-bot/commands/q.ts +++ /dev/null @@ -1,106 +0,0 @@ -import type { BotCommand } from "../types"; -import ids from "../ids"; -import { SlashCommandBuilder } from "@discordjs/builders"; -import groupedLinks from "./q-data.json"; - -const COMMAND_NAME = "q"; -const WAVE_ARG = "wave"; - -type Wave = "seeking" | "grillers" | "rush"; - -export const questionCommand: BotCommand = { - name: COMMAND_NAME, - guilds: [ids.guilds.sro], - builder: addSubcommands( - new SlashCommandBuilder() - .setName(COMMAND_NAME) - .setDescription("Find a link"), - ), - execute: async ({ interaction }) => { - let value: string | string[] | Record = - groupedLinks[ - interaction.options.getSubcommand() as keyof typeof groupedLinks - ]; - if (typeof value === "string") { - return interaction.reply({ content: toContent(value), ephemeral: true }); - } - - value = value[interaction.options.getString(WAVE_ARG) as Wave]; - if (!value) { - throw new Error( - `Unknown combination: ${interaction.options.getSubcommand()} + ${value}`, - ); - } - - return interaction.reply({ - content: toContent(value as any), - ephemeral: true, - }); - }, -}; - -function addSubcommands(builder: SlashCommandBuilder) { - for (const [key, value] of Object.entries(groupedLinks)) { - builder.addSubcommand((subcommand) => { - const result = subcommand - .setName(key) - .setDescription(keyToDescription(key)); - - if (typeof value !== "string") { - result.addStringOption((option) => - option - .setName(WAVE_ARG) - .setDescription("Type of map") - .setRequired(true) - .addChoices( - ...Object.keys(value).map((key) => ({ - name: key, - value: key, - })), - ), - ); - } - - return result; - }); - } - - return builder; -} - -function toContent(value: string | string[]) { - if (typeof value === "string") return value; - - return value.join("\n"); -} - -function keyToDescription(key: string) { - const descriptions = new Map([ - ["sg", "Spawning Grounds maps"], - ["mb", "Marooner's Bay maps"], - ["lo", "Lost Outpost maps"], - ["ss", "Salmonid Smokeyard maps"], - ["ap", "Ruins of Ark Polaris maps"], - [ - "fundamentals", - "Written guide going over all the Overfishing fundamentals", - ], - [ - "fundamentals2", - "Live video that goes into some Overfishing fundamentals", - ], - ["advanced", "Written guide going over advanced Overfishing strategies"], - ["spawns", "Table showing spawn timers"], - - ["ballpoint", "Video guide explaining the basics of Ballpoint in SR"], - ["explo", "Video guide explaining the basics of Explosher in SR"], - ["dynamo", "Video guide explaining the basics of Dynamo in SR"], - ["bamboo", "Video guide explaining the basics of Bamboo in SR"], - ["hydra", "Video guide explaining the basics of Hydra in SR"], - ]); - - const result = descriptions.get(key); - if (!result) throw new Error(`Unknown subcommand: ${key}`); - - return result; -} diff --git a/discord-bot/commands/updateall.ts b/discord-bot/commands/updateall.ts deleted file mode 100644 index dcca1973f..000000000 --- a/discord-bot/commands/updateall.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { SlashCommandBuilder } from "@discordjs/builders"; -import { Client } from "discord.js"; -import invariant from "tiny-invariant"; -import type { User } from "../../app/db/types"; -import ids from "../ids"; -import type { BotCommand } from "../types"; -import { sendouInkFetch } from "../utils"; - -const COMMAND_NAME = "updateall"; - -const guildsToCrawlForUpdates = [ids.guilds.plusServer, ids.guilds.sendou]; - -export const updateAllCommand: BotCommand = { - guilds: [ids.guilds.adminServer], - name: COMMAND_NAME, - builder: new SlashCommandBuilder() - .setName(COMMAND_NAME) - .setDescription("Update sendou.ink usernames and avatars"), - // @ts-expect-error TODO: fix. Library doesn't seem to extract API Message type so I could fix this error? - execute: async ({ interaction, client }) => { - await interaction.deferReply({ ephemeral: true }); - - const userUpdates = await getUsersToUpdate(client); - const response = await sendouInkFetch("/users", { - method: "post", - body: JSON.stringify(userUpdates), - }); - - if (!response.ok) { - return interaction.editReply( - `Update failed with status code ${response.status}`, - ); - } - - return interaction.editReply(`Sent ${userUpdates.length} users`); - }, -}; - -async function getUsersToUpdate(client: Client) { - const usersSeen = new Set(); - const userUpdates: Array<{ - discordId: string; - discordAvatar: string | null; - discordName: string | null; - discordUniqueName: string | null; - }> = []; - for (const guildId of guildsToCrawlForUpdates) { - const guild = client.guilds.cache.find((g) => g.id === guildId); - invariant(guild); - - for (const [, { user }] of await guild.members.fetch()) { - if (usersSeen.has(user.id)) continue; - - const hasUniqueUsername = user.discriminator === "0"; - - userUpdates.push({ - discordId: user.id, - discordAvatar: user.avatar, - discordName: hasUniqueUsername ? user.globalName : user.username, - discordUniqueName: hasUniqueUsername ? user.username : null, - }); - - usersSeen.add(user.id); - } - } - - return userUpdates; -} diff --git a/discord-bot/deploy-commands.ts b/discord-bot/deploy-commands.ts deleted file mode 100644 index b3358b964..000000000 --- a/discord-bot/deploy-commands.ts +++ /dev/null @@ -1,46 +0,0 @@ -import "dotenv/config"; - -import { REST } from "@discordjs/rest"; -import { Routes } from "discord-api-types/v9"; -import invariant from "tiny-invariant"; -import { commands, commandsPerGuild } from "./commands"; - -invariant(process.env["BOT_TOKEN"], "DISCORD_TOKEN must be set"); -invariant(process.env["BOT_ID"], "BOT_ID must be set"); - -const rest = new REST({ version: "9" }).setToken(process.env["BOT_TOKEN"]); - -if (process.env.NODE_ENV !== "production") { - invariant(process.env["TEST_GUILD_ID"], "TEST_GUILD_ID must be set"); - const serializedCommands = commands.map((cmd) => cmd.builder.toJSON()); - rest - .put( - Routes.applicationGuildCommands( - process.env["BOT_ID"], - process.env["TEST_GUILD_ID"], - ), - { body: serializedCommands }, // TODO: divide by guild - ) - // eslint-disable-next-line no-console - .then(() => console.log("Successfully registered application commands.")) - .catch(console.error); -} else { - for (const guildsCommands of commandsPerGuild()) { - const serializedCommands = guildsCommands.commands.map((cmd) => - cmd.builder.toJSON(), - ); - - rest - .put( - Routes.applicationGuildCommands( - process.env["BOT_ID"], - guildsCommands.guildId, - ), - { body: serializedCommands }, - ) - .catch(console.error); - } - - // eslint-disable-next-line no-console - console.log("All commands deployed"); -} diff --git a/discord-bot/handleMemberJoin.ts b/discord-bot/handleMemberJoin.ts deleted file mode 100644 index 322e54fe3..000000000 --- a/discord-bot/handleMemberJoin.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { GuildMember } from "discord.js"; -import { givePlusRoleToMember } from "./commands/access"; -import ids from "./ids"; - -export async function handleMemberJoin(member: GuildMember) { - if (member.guild.id !== ids.guilds.plusServer) return; - - await givePlusRoleToMember({ member }); -} diff --git a/discord-bot/ids.ts b/discord-bot/ids.ts deleted file mode 100644 index 6c39df8ea..000000000 --- a/discord-bot/ids.ts +++ /dev/null @@ -1,36 +0,0 @@ -const ids = { - users: { - admin: "79237403620945920", - }, - roles: { - sroLfg: "749589703371653158", - sroCoach: "807258345223356486", - plusTwoPings: "678602424314888224", - plusThreePings: "818060819811663872", - plusOne: "657613334249734165", - plusTwo: "678169134416265260", - plusThree: "815267885601521696", - // TESTING VALUES - // plusTwoPings: "1017077667276783657", - // plusThreePings: "1017077722813575290", - // plusOne: "992852036334911638", - // plusTwo: "992852055251234936", - // plusThree: "992852066403893258", - patreonSupporter: "787281384909045760", - patreonSupporterPlus: "787281624152801350", - patreonSupporterPlusPlus: "787281663138725928", - }, - channels: { - // Salmon Run // Plus Server - bot: ["746130457455886337", "808995745768013854"], - sroLfg: "745036737943699546", - }, - guilds: { - sro: "737359708276654121", - plusServer: "351828612208525333", - sendou: "299182152161951744", - adminServer: "986325847323582474", - }, -} as const; - -export default ids; diff --git a/discord-bot/index.ts b/discord-bot/index.ts deleted file mode 100644 index d1e420cc0..000000000 --- a/discord-bot/index.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { Client, GatewayIntentBits } from "discord.js"; -import "dotenv/config"; -import invariant from "tiny-invariant"; -import { commandsMap } from "./commands"; -import { handleMemberJoin } from "./handleMemberJoin"; - -invariant(process.env["BOT_TOKEN"], "DISCORD_TOKEN must be set"); - -const client = new Client({ - intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMembers], -}); - -client.once("ready", () => { - // eslint-disable-next-line no-console - console.log("Ready!"); -}); - -client.on("guildMemberAdd", handleMemberJoin); - -client.on("interactionCreate", async (interaction) => { - if (!interaction.isCommand()) return; - - const { commandName } = interaction; - const command = commandsMap[commandName]; - - if (!command) { - throw new Error( - `I don't know how to handle the command called "${commandName}"`, - ); - } - - try { - await command.execute({ interaction, client }); - } catch (e) { - console.error(e); - } -}); - -client.login(process.env["BOT_TOKEN"]).catch((err) => console.error(err)); diff --git a/discord-bot/package-lock.json b/discord-bot/package-lock.json deleted file mode 100644 index 10508f019..000000000 --- a/discord-bot/package-lock.json +++ /dev/null @@ -1,873 +0,0 @@ -{ - "name": "lohi", - "version": "1.0.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "lohi", - "dependencies": { - "@discordjs/rest": "^2.0.1", - "discord-api-types": "^0.37.56", - "discord.js": "^14.13.0", - "dotenv": "^16.3.1", - "tiny-invariant": "^1.3.1", - "ts-node": "^10.9.1", - "tsconfig-paths": "^4.2.0", - "typescript": "^5.2.2" - } - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@discordjs/builders": { - "version": "1.6.5", - "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.6.5.tgz", - "integrity": "sha512-SdweyCs/+mHj+PNhGLLle7RrRFX9ZAhzynHahMCLqp5Zeq7np7XC6/mgzHc79QoVlQ1zZtOkTTiJpOZu5V8Ufg==", - "dependencies": { - "@discordjs/formatters": "^0.3.2", - "@discordjs/util": "^1.0.1", - "@sapphire/shapeshift": "^3.9.2", - "discord-api-types": "0.37.50", - "fast-deep-equal": "^3.1.3", - "ts-mixer": "^6.0.3", - "tslib": "^2.6.1" - }, - "engines": { - "node": ">=16.11.0" - } - }, - "node_modules/@discordjs/builders/node_modules/discord-api-types": { - "version": "0.37.50", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.50.tgz", - "integrity": "sha512-X4CDiMnDbA3s3RaUXWXmgAIbY1uxab3fqe3qwzg5XutR3wjqi7M3IkgQbsIBzpqBN2YWr/Qdv7JrFRqSgb4TFg==" - }, - "node_modules/@discordjs/collection": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.5.3.tgz", - "integrity": "sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ==", - "engines": { - "node": ">=16.11.0" - } - }, - "node_modules/@discordjs/formatters": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.3.2.tgz", - "integrity": "sha512-lE++JZK8LSSDRM5nLjhuvWhGuKiXqu+JZ/DsOR89DVVia3z9fdCJVcHF2W/1Zxgq0re7kCzmAJlCMMX3tetKpA==", - "dependencies": { - "discord-api-types": "0.37.50" - }, - "engines": { - "node": ">=16.11.0" - } - }, - "node_modules/@discordjs/formatters/node_modules/discord-api-types": { - "version": "0.37.50", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.50.tgz", - "integrity": "sha512-X4CDiMnDbA3s3RaUXWXmgAIbY1uxab3fqe3qwzg5XutR3wjqi7M3IkgQbsIBzpqBN2YWr/Qdv7JrFRqSgb4TFg==" - }, - "node_modules/@discordjs/rest": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.0.1.tgz", - "integrity": "sha512-/eWAdDRvwX/rIE2tuQUmKaxmWeHmGealttIzGzlYfI4+a7y9b6ZoMp8BG/jaohs8D8iEnCNYaZiOFLVFLQb8Zg==", - "dependencies": { - "@discordjs/collection": "^1.5.3", - "@discordjs/util": "^1.0.1", - "@sapphire/async-queue": "^1.5.0", - "@sapphire/snowflake": "^3.5.1", - "@vladfrangu/async_event_emitter": "^2.2.2", - "discord-api-types": "0.37.50", - "magic-bytes.js": "^1.0.15", - "tslib": "^2.6.1", - "undici": "5.22.1" - }, - "engines": { - "node": ">=16.11.0" - } - }, - "node_modules/@discordjs/rest/node_modules/discord-api-types": { - "version": "0.37.50", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.50.tgz", - "integrity": "sha512-X4CDiMnDbA3s3RaUXWXmgAIbY1uxab3fqe3qwzg5XutR3wjqi7M3IkgQbsIBzpqBN2YWr/Qdv7JrFRqSgb4TFg==" - }, - "node_modules/@discordjs/util": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-1.0.1.tgz", - "integrity": "sha512-d0N2yCxB8r4bn00/hvFZwM7goDcUhtViC5un4hPj73Ba4yrChLSJD8fy7Ps5jpTLg1fE9n4K0xBLc1y9WGwSsA==", - "engines": { - "node": ">=16.11.0" - } - }, - "node_modules/@discordjs/ws": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-1.0.1.tgz", - "integrity": "sha512-avvAolBqN3yrSvdBPcJ/0j2g42ABzrv3PEL76e3YTp2WYMGH7cuspkjfSyNWaqYl1J+669dlLp+YFMxSVQyS5g==", - "dependencies": { - "@discordjs/collection": "^1.5.3", - "@discordjs/rest": "^2.0.1", - "@discordjs/util": "^1.0.1", - "@sapphire/async-queue": "^1.5.0", - "@types/ws": "^8.5.5", - "@vladfrangu/async_event_emitter": "^2.2.2", - "discord-api-types": "0.37.50", - "tslib": "^2.6.1", - "ws": "^8.13.0" - }, - "engines": { - "node": ">=16.11.0" - } - }, - "node_modules/@discordjs/ws/node_modules/discord-api-types": { - "version": "0.37.50", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.50.tgz", - "integrity": "sha512-X4CDiMnDbA3s3RaUXWXmgAIbY1uxab3fqe3qwzg5XutR3wjqi7M3IkgQbsIBzpqBN2YWr/Qdv7JrFRqSgb4TFg==" - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz", - "integrity": "sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.13", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz", - "integrity": "sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@sapphire/async-queue": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.0.tgz", - "integrity": "sha512-JkLdIsP8fPAdh9ZZjrbHWR/+mZj0wvKS5ICibcLrRI1j84UmLMshx5n9QmL8b95d4onJ2xxiyugTgSAX7AalmA==", - "engines": { - "node": ">=v14.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/@sapphire/shapeshift": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.9.2.tgz", - "integrity": "sha512-YRbCXWy969oGIdqR/wha62eX8GNHsvyYi0Rfd4rNW6tSVVa8p0ELiMEuOH/k8rgtvRoM+EMV7Csqz77YdwiDpA==", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "lodash": "^4.17.21" - }, - "engines": { - "node": ">=v14.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/@sapphire/snowflake": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.5.1.tgz", - "integrity": "sha512-BxcYGzgEsdlG0dKAyOm0ehLGm2CafIrfQTZGWgkfKYbj+pNNsorZ7EotuZukc2MT70E0UbppVbtpBrqpzVzjNA==", - "engines": { - "node": ">=v14.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==" - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.10.tgz", - "integrity": "sha512-N+srakvPaYMGkwjNDx3ASx65Zl3QG8dJgVtIB+YMOkucU+zctlv/hdP5250VKdDHSDoW9PFZoCqbqNcAPjCjXA==" - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.2.tgz", - "integrity": "sha512-YwrUA5ysDXHFYfL0Xed9x3sNS4P+aKlCOnnbqUa2E5HdQshHFleCJVrj1PlGTb4GgFUCDyte1v3JWLy2sz8Oqg==" - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", - "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==" - }, - "node_modules/@types/node": { - "version": "17.0.42", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.42.tgz", - "integrity": "sha512-Q5BPGyGKcvQgAMbsr7qEGN/kIPN6zZecYYABeTDBizOsau+2NMdSVTar9UQw21A2+JyA2KRNDYaYrPB0Rpk2oQ==" - }, - "node_modules/@types/ws": { - "version": "8.5.5", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.5.tgz", - "integrity": "sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@vladfrangu/async_event_emitter": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.2.2.tgz", - "integrity": "sha512-HIzRG7sy88UZjBJamssEczH5q7t5+axva19UbZLO6u0ySbYPrwzWiXBcC0WuHyhKKoeCyneH+FvYzKQq/zTtkQ==", - "engines": { - "node": ">=v14.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/acorn": { - "version": "8.7.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", - "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" - }, - "node_modules/busboy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", - "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", - "dependencies": { - "streamsearch": "^1.1.0" - }, - "engines": { - "node": ">=10.16.0" - } - }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/discord-api-types": { - "version": "0.37.56", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.56.tgz", - "integrity": "sha512-Ih3wj0ZTaQxaJRqUEXHMIXfXB86bwMGC0wc2nNsyCJqeo3lC4qnxXtFIsC+IGI46+dSIinuayCAZ6sLEEM02Bw==" - }, - "node_modules/discord.js": { - "version": "14.13.0", - "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.13.0.tgz", - "integrity": "sha512-Kufdvg7fpyTEwANGy9x7i4od4yu5c6gVddGi5CKm4Y5a6sF0VBODObI3o0Bh7TGCj0LfNT8Qp8z04wnLFzgnbA==", - "dependencies": { - "@discordjs/builders": "^1.6.5", - "@discordjs/collection": "^1.5.3", - "@discordjs/formatters": "^0.3.2", - "@discordjs/rest": "^2.0.1", - "@discordjs/util": "^1.0.1", - "@discordjs/ws": "^1.0.1", - "@sapphire/snowflake": "^3.5.1", - "@types/ws": "^8.5.5", - "discord-api-types": "0.37.50", - "fast-deep-equal": "^3.1.3", - "lodash.snakecase": "^4.1.1", - "tslib": "^2.6.1", - "undici": "5.22.1", - "ws": "^8.13.0" - }, - "engines": { - "node": ">=16.11.0" - } - }, - "node_modules/discord.js/node_modules/discord-api-types": { - "version": "0.37.50", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.50.tgz", - "integrity": "sha512-X4CDiMnDbA3s3RaUXWXmgAIbY1uxab3fqe3qwzg5XutR3wjqi7M3IkgQbsIBzpqBN2YWr/Qdv7JrFRqSgb4TFg==" - }, - "node_modules/dotenv": { - "version": "16.3.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", - "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/motdotla/dotenv?sponsor=1" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "node_modules/lodash.snakecase": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", - "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==" - }, - "node_modules/magic-bytes.js": { - "version": "1.0.15", - "resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.0.15.tgz", - "integrity": "sha512-bpRmwbRHqongRhA+mXzbLWjVy7ylqmfMBYaQkSs6pac0z6hBTvsgrH0r4FBYd/UYVJBmS6Rp/O+oCCQVLzKV1g==" - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" - }, - "node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" - }, - "node_modules/streamsearch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", - "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "engines": { - "node": ">=4" - } - }, - "node_modules/tiny-invariant": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.1.tgz", - "integrity": "sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==" - }, - "node_modules/ts-mixer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.3.tgz", - "integrity": "sha512-k43M7uCG1AkTyxgnmI5MPwKoUvS/bRvLvUb7+Pgpdlmok8AoqmUaZxUUw8zKM5B1lqZrt41GjYgnvAi0fppqgQ==" - }, - "node_modules/ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/tsconfig-paths": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", - "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", - "dependencies": { - "json5": "^2.2.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" - }, - "node_modules/typescript": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", - "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undici": { - "version": "5.22.1", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.22.1.tgz", - "integrity": "sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==", - "dependencies": { - "busboy": "^1.6.0" - }, - "engines": { - "node": ">=14.0" - } - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==" - }, - "node_modules/ws": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.0.tgz", - "integrity": "sha512-WR0RJE9Ehsio6U4TuM+LmunEsjQ5ncHlw4sn9ihD6RoJKZrVyH9FWV3dmnwu8B2aNib1OvG2X6adUCyFpQyWcg==", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "engines": { - "node": ">=6" - } - } - }, - "dependencies": { - "@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "requires": { - "@jridgewell/trace-mapping": "0.3.9" - } - }, - "@discordjs/builders": { - "version": "1.6.5", - "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.6.5.tgz", - "integrity": "sha512-SdweyCs/+mHj+PNhGLLle7RrRFX9ZAhzynHahMCLqp5Zeq7np7XC6/mgzHc79QoVlQ1zZtOkTTiJpOZu5V8Ufg==", - "requires": { - "@discordjs/formatters": "^0.3.2", - "@discordjs/util": "^1.0.1", - "@sapphire/shapeshift": "^3.9.2", - "discord-api-types": "0.37.50", - "fast-deep-equal": "^3.1.3", - "ts-mixer": "^6.0.3", - "tslib": "^2.6.1" - }, - "dependencies": { - "discord-api-types": { - "version": "0.37.50", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.50.tgz", - "integrity": "sha512-X4CDiMnDbA3s3RaUXWXmgAIbY1uxab3fqe3qwzg5XutR3wjqi7M3IkgQbsIBzpqBN2YWr/Qdv7JrFRqSgb4TFg==" - } - } - }, - "@discordjs/collection": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.5.3.tgz", - "integrity": "sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ==" - }, - "@discordjs/formatters": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.3.2.tgz", - "integrity": "sha512-lE++JZK8LSSDRM5nLjhuvWhGuKiXqu+JZ/DsOR89DVVia3z9fdCJVcHF2W/1Zxgq0re7kCzmAJlCMMX3tetKpA==", - "requires": { - "discord-api-types": "0.37.50" - }, - "dependencies": { - "discord-api-types": { - "version": "0.37.50", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.50.tgz", - "integrity": "sha512-X4CDiMnDbA3s3RaUXWXmgAIbY1uxab3fqe3qwzg5XutR3wjqi7M3IkgQbsIBzpqBN2YWr/Qdv7JrFRqSgb4TFg==" - } - } - }, - "@discordjs/rest": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.0.1.tgz", - "integrity": "sha512-/eWAdDRvwX/rIE2tuQUmKaxmWeHmGealttIzGzlYfI4+a7y9b6ZoMp8BG/jaohs8D8iEnCNYaZiOFLVFLQb8Zg==", - "requires": { - "@discordjs/collection": "^1.5.3", - "@discordjs/util": "^1.0.1", - "@sapphire/async-queue": "^1.5.0", - "@sapphire/snowflake": "^3.5.1", - "@vladfrangu/async_event_emitter": "^2.2.2", - "discord-api-types": "0.37.50", - "magic-bytes.js": "^1.0.15", - "tslib": "^2.6.1", - "undici": "5.22.1" - }, - "dependencies": { - "discord-api-types": { - "version": "0.37.50", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.50.tgz", - "integrity": "sha512-X4CDiMnDbA3s3RaUXWXmgAIbY1uxab3fqe3qwzg5XutR3wjqi7M3IkgQbsIBzpqBN2YWr/Qdv7JrFRqSgb4TFg==" - } - } - }, - "@discordjs/util": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-1.0.1.tgz", - "integrity": "sha512-d0N2yCxB8r4bn00/hvFZwM7goDcUhtViC5un4hPj73Ba4yrChLSJD8fy7Ps5jpTLg1fE9n4K0xBLc1y9WGwSsA==" - }, - "@discordjs/ws": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-1.0.1.tgz", - "integrity": "sha512-avvAolBqN3yrSvdBPcJ/0j2g42ABzrv3PEL76e3YTp2WYMGH7cuspkjfSyNWaqYl1J+669dlLp+YFMxSVQyS5g==", - "requires": { - "@discordjs/collection": "^1.5.3", - "@discordjs/rest": "^2.0.1", - "@discordjs/util": "^1.0.1", - "@sapphire/async-queue": "^1.5.0", - "@types/ws": "^8.5.5", - "@vladfrangu/async_event_emitter": "^2.2.2", - "discord-api-types": "0.37.50", - "tslib": "^2.6.1", - "ws": "^8.13.0" - }, - "dependencies": { - "discord-api-types": { - "version": "0.37.50", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.50.tgz", - "integrity": "sha512-X4CDiMnDbA3s3RaUXWXmgAIbY1uxab3fqe3qwzg5XutR3wjqi7M3IkgQbsIBzpqBN2YWr/Qdv7JrFRqSgb4TFg==" - } - } - }, - "@jridgewell/resolve-uri": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz", - "integrity": "sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==" - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.13", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz", - "integrity": "sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==" - }, - "@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "@sapphire/async-queue": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.0.tgz", - "integrity": "sha512-JkLdIsP8fPAdh9ZZjrbHWR/+mZj0wvKS5ICibcLrRI1j84UmLMshx5n9QmL8b95d4onJ2xxiyugTgSAX7AalmA==" - }, - "@sapphire/shapeshift": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.9.2.tgz", - "integrity": "sha512-YRbCXWy969oGIdqR/wha62eX8GNHsvyYi0Rfd4rNW6tSVVa8p0ELiMEuOH/k8rgtvRoM+EMV7Csqz77YdwiDpA==", - "requires": { - "fast-deep-equal": "^3.1.3", - "lodash": "^4.17.21" - } - }, - "@sapphire/snowflake": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.5.1.tgz", - "integrity": "sha512-BxcYGzgEsdlG0dKAyOm0ehLGm2CafIrfQTZGWgkfKYbj+pNNsorZ7EotuZukc2MT70E0UbppVbtpBrqpzVzjNA==" - }, - "@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==" - }, - "@tsconfig/node12": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.10.tgz", - "integrity": "sha512-N+srakvPaYMGkwjNDx3ASx65Zl3QG8dJgVtIB+YMOkucU+zctlv/hdP5250VKdDHSDoW9PFZoCqbqNcAPjCjXA==" - }, - "@tsconfig/node14": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.2.tgz", - "integrity": "sha512-YwrUA5ysDXHFYfL0Xed9x3sNS4P+aKlCOnnbqUa2E5HdQshHFleCJVrj1PlGTb4GgFUCDyte1v3JWLy2sz8Oqg==" - }, - "@tsconfig/node16": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", - "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==" - }, - "@types/node": { - "version": "17.0.42", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.42.tgz", - "integrity": "sha512-Q5BPGyGKcvQgAMbsr7qEGN/kIPN6zZecYYABeTDBizOsau+2NMdSVTar9UQw21A2+JyA2KRNDYaYrPB0Rpk2oQ==" - }, - "@types/ws": { - "version": "8.5.5", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.5.tgz", - "integrity": "sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==", - "requires": { - "@types/node": "*" - } - }, - "@vladfrangu/async_event_emitter": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.2.2.tgz", - "integrity": "sha512-HIzRG7sy88UZjBJamssEczH5q7t5+axva19UbZLO6u0ySbYPrwzWiXBcC0WuHyhKKoeCyneH+FvYzKQq/zTtkQ==" - }, - "acorn": { - "version": "8.7.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", - "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==" - }, - "acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==" - }, - "arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" - }, - "busboy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", - "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", - "requires": { - "streamsearch": "^1.1.0" - } - }, - "create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" - }, - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" - }, - "discord-api-types": { - "version": "0.37.56", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.56.tgz", - "integrity": "sha512-Ih3wj0ZTaQxaJRqUEXHMIXfXB86bwMGC0wc2nNsyCJqeo3lC4qnxXtFIsC+IGI46+dSIinuayCAZ6sLEEM02Bw==" - }, - "discord.js": { - "version": "14.13.0", - "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.13.0.tgz", - "integrity": "sha512-Kufdvg7fpyTEwANGy9x7i4od4yu5c6gVddGi5CKm4Y5a6sF0VBODObI3o0Bh7TGCj0LfNT8Qp8z04wnLFzgnbA==", - "requires": { - "@discordjs/builders": "^1.6.5", - "@discordjs/collection": "^1.5.3", - "@discordjs/formatters": "^0.3.2", - "@discordjs/rest": "^2.0.1", - "@discordjs/util": "^1.0.1", - "@discordjs/ws": "^1.0.1", - "@sapphire/snowflake": "^3.5.1", - "@types/ws": "^8.5.5", - "discord-api-types": "0.37.50", - "fast-deep-equal": "^3.1.3", - "lodash.snakecase": "^4.1.1", - "tslib": "^2.6.1", - "undici": "5.22.1", - "ws": "^8.13.0" - }, - "dependencies": { - "discord-api-types": { - "version": "0.37.50", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.50.tgz", - "integrity": "sha512-X4CDiMnDbA3s3RaUXWXmgAIbY1uxab3fqe3qwzg5XutR3wjqi7M3IkgQbsIBzpqBN2YWr/Qdv7JrFRqSgb4TFg==" - } - } - }, - "dotenv": { - "version": "16.3.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", - "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==" - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==" - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "lodash.snakecase": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", - "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==" - }, - "magic-bytes.js": { - "version": "1.0.15", - "resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.0.15.tgz", - "integrity": "sha512-bpRmwbRHqongRhA+mXzbLWjVy7ylqmfMBYaQkSs6pac0z6hBTvsgrH0r4FBYd/UYVJBmS6Rp/O+oCCQVLzKV1g==" - }, - "make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" - }, - "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" - }, - "streamsearch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", - "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==" - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==" - }, - "tiny-invariant": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.1.tgz", - "integrity": "sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==" - }, - "ts-mixer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.3.tgz", - "integrity": "sha512-k43M7uCG1AkTyxgnmI5MPwKoUvS/bRvLvUb7+Pgpdlmok8AoqmUaZxUUw8zKM5B1lqZrt41GjYgnvAi0fppqgQ==" - }, - "ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", - "requires": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - } - }, - "tsconfig-paths": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", - "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", - "requires": { - "json5": "^2.2.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - } - }, - "tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" - }, - "typescript": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", - "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==" - }, - "undici": { - "version": "5.22.1", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.22.1.tgz", - "integrity": "sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==", - "requires": { - "busboy": "^1.6.0" - } - }, - "v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==" - }, - "ws": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.0.tgz", - "integrity": "sha512-WR0RJE9Ehsio6U4TuM+LmunEsjQ5ncHlw4sn9ihD6RoJKZrVyH9FWV3dmnwu8B2aNib1OvG2X6adUCyFpQyWcg==", - "requires": {} - }, - "yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==" - } - } -} diff --git a/discord-bot/package.json b/discord-bot/package.json deleted file mode 100644 index c6e2e3bb4..000000000 --- a/discord-bot/package.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "lohi", - "scripts": { - "dev": "node --experimental-fetch --require ts-node/register --require tsconfig-paths/register index.ts", - "commands": "node --experimental-fetch --require ts-node/register --require tsconfig-paths/register deploy-commands.ts", - "test": "echo \"Error: no test specified\" && exit 1", - "typecheck": "tsc --noEmit" - }, - "dependencies": { - "@discordjs/rest": "^2.0.1", - "discord-api-types": "^0.37.56", - "discord.js": "^14.13.0", - "dotenv": "^16.3.1", - "tiny-invariant": "^1.3.1", - "ts-node": "^10.9.1", - "tsconfig-paths": "^4.2.0", - "typescript": "^5.2.2" - } -} diff --git a/discord-bot/tsconfig.bot.json b/discord-bot/tsconfig.bot.json deleted file mode 100644 index 3b3f8ceda..000000000 --- a/discord-bot/tsconfig.bot.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "extends": "../tsconfig.json", - "compilerOptions": { - "isolatedModules": false - } -} diff --git a/discord-bot/types.ts b/discord-bot/types.ts deleted file mode 100644 index 2b0a46159..000000000 --- a/discord-bot/types.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { SlashCommandBuilder } from "@discordjs/builders"; -import type { Client, CommandInteraction } from "discord.js"; - -export interface BotCommand { - name: string; - /** ID's of guilds where this command will be set */ - guilds: string[]; - builder: Omit; // TODO: figure out correct type here - execute: (commandParameters: { - interaction: CommandInteraction; - client: Client; - }) => Promise; -} diff --git a/discord-bot/utils.ts b/discord-bot/utils.ts deleted file mode 100644 index 121da70c3..000000000 --- a/discord-bot/utils.ts +++ /dev/null @@ -1,57 +0,0 @@ -import invariant from "tiny-invariant"; -import { LOHI_TOKEN_HEADER_NAME } from "~/constants"; -import type { PlusListLoaderData } from "~/routes/plus/list"; -import ids from "./ids"; - -export function sendouInkFetch(path: string, init?: RequestInit) { - invariant(process.env["SENDOU_INK_URL"], "SENDOU_INK_URL is not set"); - invariant(process.env["LOHI_TOKEN"], "LOHI_TOKEN is not set"); - - return fetch(`${process.env["SENDOU_INK_URL"]}${path}`, { - headers: [[LOHI_TOKEN_HEADER_NAME, process.env["LOHI_TOKEN"]]], - ...init, - }); -} - -export async function usersWithAccess(): Promise { - const response = await sendouInkFetch("/plus/list"); - - if (!response.ok) { - throw new Error( - `Failed to fetch users. Response status was ${response.status}`, - ); - } - - return response.json(); -} - -export async function patronsFiveDollarsAndOver(): Promise { - const response = await sendouInkFetch("/patrons"); - - if (!response.ok) { - throw new Error( - `Failed to fetch users. Response status was ${response.status}`, - ); - } - - return (await response.json()).filter((user) => user.patronTier >= 2); -} - -const memberRoles = [ - "", - ids.roles.plusOne, - ids.roles.plusTwo, - ids.roles.plusThree, -] as const; -export function plusTierToRoleId(tier?: number) { - if (!tier) return; - - const result = memberRoles[tier ?? 0]; - if (!result) return; - - return result; -} - -export function isPlusTierRoleId(id: string) { - return memberRoles.slice(1).includes(id as any); -} diff --git a/tsconfig.json b/tsconfig.json index 35ca3926c..95d166d1b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,5 @@ { "include": ["./types/remix.env.d.ts", "**/*.ts", "**/*.tsx"], - "exclude": ["discord-bot/*"], "compilerOptions": { "lib": ["DOM", "DOM.Iterable", "ES2019"], "module": "commonjs",