feat: implement reporting system
This commit is contained in:
@@ -17,7 +17,7 @@
|
||||
"dependencies": {
|
||||
"@lbf-bot/database": "workspace:*",
|
||||
"@lbf-bot/utils": "workspace:*",
|
||||
"discord.js": "^14.21.0",
|
||||
"discord.js": "^14.26.4",
|
||||
"sharp": "^0.34.5",
|
||||
"zod": "4.1.11"
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ import { gemmesCommand } from "./gemmes";
|
||||
import { resultCommand } from "./result";
|
||||
import { queteCommand } from "./quete";
|
||||
import { tgCommand } from "./tg";
|
||||
import { reportmsgCommand } from "./reportmsg";
|
||||
import { reportsCommand } from "./reports";
|
||||
|
||||
export type CommandHandler = (
|
||||
message: OmitPartialGroupDMChannel<Message<boolean>>,
|
||||
@@ -26,5 +28,7 @@ export const commands: Record<string, Command> = {
|
||||
gemmes: gemmesCommand,
|
||||
quete: queteCommand,
|
||||
result: resultCommand,
|
||||
tg: tgCommand,
|
||||
tg: tgCommand,
|
||||
reportmsg: reportmsgCommand,
|
||||
reports: reportsCommand,
|
||||
};
|
||||
|
||||
23
apps/discord-bot/src/commands/reportmsg.ts
Normal file
23
apps/discord-bot/src/commands/reportmsg.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { ChannelType } from "discord.js";
|
||||
import { sendReportEmbed } from "~/reporting";
|
||||
import { replyError } from "~/discord";
|
||||
import type { Command } from "./index";
|
||||
import { env } from "~/env";
|
||||
|
||||
export const reportmsgCommand: Command = {
|
||||
help: "Envoie le message de signalement dans ce salon",
|
||||
handler: async (message) => {
|
||||
if (!message.member?.roles.cache.has(env.DISCORD_STAFF_ROLE_ID)) {
|
||||
await replyError(message, "Tu t'es cru chez mémé ou quoi faut être staff");
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.channel.type !== ChannelType.GuildText) {
|
||||
await replyError(message, "Cette commande doit être utilisée dans un salon texte.");
|
||||
return;
|
||||
}
|
||||
|
||||
await message.delete();
|
||||
await sendReportEmbed(message.channel);
|
||||
},
|
||||
};
|
||||
50
apps/discord-bot/src/commands/reports.ts
Normal file
50
apps/discord-bot/src/commands/reports.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { EmbedBuilder } from "discord.js";
|
||||
import { db, tables, eq } from "@lbf-bot/database";
|
||||
import { noMention, replyError } from "~/discord";
|
||||
import { searchPlayer } from "~/wov";
|
||||
import type { Command } from "./index";
|
||||
|
||||
export const reportsCommand: Command = {
|
||||
help: "Liste tous les signalements d'un joueur",
|
||||
handler: async (message, args) => {
|
||||
const username = args.join(" ");
|
||||
if (!username) {
|
||||
await replyError(message, "Usage: `lbf reports <pseudo>`");
|
||||
return;
|
||||
}
|
||||
|
||||
const player = await searchPlayer(username);
|
||||
if (!player) {
|
||||
await replyError(message, `Aucun joueur avec le pseudo **${username}** n'a été trouvé.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const reports = await db
|
||||
.select()
|
||||
.from(tables.reports)
|
||||
.where(eq(tables.reports.playerId, player.id))
|
||||
.orderBy(tables.reports.createdAt);
|
||||
|
||||
if (reports.length === 0) {
|
||||
await message.reply({ ...noMention, content: `Aucun signalement trouvé pour **${username}**.` });
|
||||
return;
|
||||
}
|
||||
|
||||
const lines = reports.map((r, i) => {
|
||||
const date = r.createdAt.toLocaleDateString("fr-FR");
|
||||
const reason = r.reason.length > 100 ? `${r.reason.slice(0, 100)}…` : r.reason;
|
||||
const link = r.messageLink ? ` - [voir](${r.messageLink})` : "";
|
||||
return `**${i + 1}.** ${date} - \`${reason}\`${link}`;
|
||||
});
|
||||
|
||||
await message.reply({
|
||||
...noMention,
|
||||
embeds: [
|
||||
new EmbedBuilder()
|
||||
.setTitle(`Signalements de ${username}`)
|
||||
.setDescription(lines.join("\n"))
|
||||
.setFooter({ text: `${reports.length} signalement${reports.length > 1 ? "s" : ""}` }),
|
||||
],
|
||||
});
|
||||
},
|
||||
};
|
||||
@@ -13,6 +13,7 @@ export const env = parseEnv({
|
||||
// TODO: rename to reward ask channel or smth
|
||||
DISCORD_ADMIN_CHANNEL: z.string(),
|
||||
DISCORD_TRACKING_CHANNEL: z.string(),
|
||||
DISCORD_REPORT_CHANNEL: z.string(),
|
||||
DISCORD_STAFF_ROLE_ID: z.string(),
|
||||
COMMIT_SHA: z.string().default("dev"),
|
||||
WOV_API_KEY: z.string(),
|
||||
|
||||
@@ -4,6 +4,11 @@ import { env } from "~/env";
|
||||
import { questCheckCron } from "~/quests";
|
||||
import { trackingCron } from "~/tracking";
|
||||
import { commands } from "~/commands";
|
||||
import {
|
||||
handleReportButton, handleReportModal, handleEditButton, handleDeleteButton, handleEditModal,
|
||||
REPORT_BUTTON_ID, REPORT_MODAL_ID,
|
||||
REPORT_EDIT_BUTTON_PREFIX, REPORT_DELETE_BUTTON_PREFIX, REPORT_EDIT_MODAL_PREFIX,
|
||||
} from "~/reporting";
|
||||
|
||||
const onReady = async (client: Client<true>) => {
|
||||
logger.info(`Client ready`);
|
||||
@@ -37,7 +42,30 @@ const onMessage = async (message: OmitPartialGroupDMChannel<Message>) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const setupBotMode = (client: Client) => {
|
||||
client.on("clientReady", (client) => { void onReady(client); });
|
||||
client.on("messageCreate", (message) => { void onMessage(message); });
|
||||
const onInteraction = async (interaction: Parameters<Parameters<Client["on"]>[1]>[0], client: Client) => {
|
||||
if (interaction.isButton()) {
|
||||
if (interaction.customId === REPORT_BUTTON_ID) {
|
||||
await handleReportButton(interaction);
|
||||
} else if (interaction.customId.startsWith(`${REPORT_EDIT_BUTTON_PREFIX}:`)) {
|
||||
const reportId = interaction.customId.slice(REPORT_EDIT_BUTTON_PREFIX.length + 1);
|
||||
await handleEditButton(interaction, reportId);
|
||||
} else if (interaction.customId.startsWith(`${REPORT_DELETE_BUTTON_PREFIX}:`)) {
|
||||
const reportId = interaction.customId.slice(REPORT_DELETE_BUTTON_PREFIX.length + 1);
|
||||
await handleDeleteButton(interaction, reportId);
|
||||
}
|
||||
} else if (interaction.isModalSubmit()) {
|
||||
if (interaction.customId === REPORT_MODAL_ID) {
|
||||
await handleReportModal(interaction, client);
|
||||
} else if (interaction.customId.startsWith(`${REPORT_EDIT_MODAL_PREFIX}:`)) {
|
||||
const rest = interaction.customId.slice(REPORT_EDIT_MODAL_PREFIX.length + 1);
|
||||
const [reportId, channelId, messageId] = rest.split(":");
|
||||
await handleEditModal(interaction, client, reportId, channelId, messageId);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const setupBotMode = (client: Client) => {
|
||||
client.on("clientReady", (client) => { void onReady(client); });
|
||||
client.on("messageCreate", (message) => { void onMessage(message); });
|
||||
client.on("interactionCreate", (interaction) => { void onInteraction(interaction, client); });
|
||||
};
|
||||
|
||||
270
apps/discord-bot/src/reporting.ts
Normal file
270
apps/discord-bot/src/reporting.ts
Normal file
@@ -0,0 +1,270 @@
|
||||
import {
|
||||
ActionRowBuilder, ButtonBuilder, ButtonStyle, ChannelType, ComponentType,
|
||||
EmbedBuilder, FileUploadBuilder, LabelBuilder, MessageFlags, ModalBuilder, TextInputBuilder, TextInputStyle,
|
||||
type ButtonInteraction, type Client, type FileUploadModalData, type ModalSubmitInteraction, type TextChannel,
|
||||
} from "discord.js";
|
||||
import { createLogger } from "@lbf-bot/utils";
|
||||
import { db, tables, eq } from "@lbf-bot/database";
|
||||
import { env } from "~/env";
|
||||
import { searchPlayer } from "~/wov";
|
||||
|
||||
const logger = createLogger({ prefix: "reporting" });
|
||||
|
||||
export const REPORT_BUTTON_ID = "report:open";
|
||||
export const REPORT_MODAL_ID = "report:modal";
|
||||
export const REPORT_EDIT_BUTTON_PREFIX = "report:edit";
|
||||
export const REPORT_DELETE_BUTTON_PREFIX = "report:delete";
|
||||
export const REPORT_EDIT_MODAL_PREFIX = "report:edit:modal";
|
||||
|
||||
const buildReportEmbed = (report: { playerName: string; playerId: string; reason: string; reporterId: string }) =>
|
||||
new EmbedBuilder()
|
||||
.setDescription([
|
||||
`**Pseudo**: \`${report.playerName}\``,
|
||||
`**ID**: \`${report.playerId}\``,
|
||||
`**Raison**: \`\`\`${report.reason}\`\`\``,
|
||||
`-# Signalé par <@${report.reporterId}>`
|
||||
].join("\n"));
|
||||
|
||||
const reportActionRow = (reportId: string) =>
|
||||
new ActionRowBuilder<ButtonBuilder>().addComponents(
|
||||
new ButtonBuilder()
|
||||
.setCustomId(`${REPORT_EDIT_BUTTON_PREFIX}:${reportId}`)
|
||||
.setLabel("Modifier")
|
||||
.setStyle(ButtonStyle.Secondary),
|
||||
new ButtonBuilder()
|
||||
.setCustomId(`${REPORT_DELETE_BUTTON_PREFIX}:${reportId}`)
|
||||
.setLabel("Supprimer")
|
||||
.setStyle(ButtonStyle.Danger),
|
||||
);
|
||||
|
||||
const isAuthorized = (interaction: ButtonInteraction | ModalSubmitInteraction, reporterId: string) => {
|
||||
if (interaction.user.id === reporterId) return true;
|
||||
const { member } = interaction;
|
||||
if (!member) return false;
|
||||
const roles = member.roles;
|
||||
if (Array.isArray(roles)) return roles.includes(env.DISCORD_STAFF_ROLE_ID);
|
||||
return "cache" in roles && roles.cache.has(env.DISCORD_STAFF_ROLE_ID);
|
||||
};
|
||||
|
||||
const extractScreenshots = (fields: ModalSubmitInteraction["fields"]) => {
|
||||
const fileField = fields.fields.get("screenshots") as FileUploadModalData | undefined;
|
||||
const attachments = fileField?.type === ComponentType.FileUpload && fileField.attachments?.size > 0
|
||||
? [...fileField.attachments.values()]
|
||||
: null;
|
||||
const screenshotUrls = attachments ? attachments.map(a => a.url).join("\n") : null;
|
||||
return { attachments, screenshotUrls };
|
||||
};
|
||||
|
||||
const buildModal = () =>
|
||||
new ModalBuilder()
|
||||
.setCustomId(REPORT_MODAL_ID)
|
||||
.setTitle("Signaler un joueur")
|
||||
.addLabelComponents(
|
||||
new LabelBuilder()
|
||||
.setLabel("Pseudo du joueur (les majuscules comptent !)")
|
||||
.setTextInputComponent(
|
||||
new TextInputBuilder()
|
||||
.setCustomId("player_name")
|
||||
.setStyle(TextInputStyle.Short)
|
||||
.setRequired(true),
|
||||
),
|
||||
new LabelBuilder()
|
||||
.setLabel("Raison du signalement")
|
||||
.setTextInputComponent(
|
||||
new TextInputBuilder()
|
||||
.setCustomId("reason")
|
||||
.setStyle(TextInputStyle.Paragraph)
|
||||
.setRequired(true),
|
||||
),
|
||||
new LabelBuilder()
|
||||
.setLabel("Screenshots (optionnel)")
|
||||
.setFileUploadComponent(
|
||||
new FileUploadBuilder()
|
||||
.setCustomId("screenshots")
|
||||
.setMaxValues(10)
|
||||
.setRequired(false),
|
||||
),
|
||||
);
|
||||
|
||||
const buildEditModal = (reportId: string, channelId: string, messageId: string, currentReason: string) =>
|
||||
new ModalBuilder()
|
||||
.setCustomId(`${REPORT_EDIT_MODAL_PREFIX}:${reportId}:${channelId}:${messageId}`)
|
||||
.setTitle("Modifier le signalement")
|
||||
.addLabelComponents(
|
||||
new LabelBuilder()
|
||||
.setLabel("Raison du signalement")
|
||||
.setTextInputComponent(
|
||||
new TextInputBuilder()
|
||||
.setCustomId("reason")
|
||||
.setStyle(TextInputStyle.Paragraph)
|
||||
.setValue(currentReason)
|
||||
.setRequired(true),
|
||||
),
|
||||
new LabelBuilder()
|
||||
.setLabel("Screenshots (optionnel)")
|
||||
.setFileUploadComponent(
|
||||
new FileUploadBuilder()
|
||||
.setCustomId("screenshots")
|
||||
.setMaxValues(10)
|
||||
.setRequired(false),
|
||||
),
|
||||
);
|
||||
|
||||
const retryRow = () =>
|
||||
new ActionRowBuilder<ButtonBuilder>().addComponents(
|
||||
new ButtonBuilder()
|
||||
.setCustomId(REPORT_BUTTON_ID)
|
||||
.setLabel("Réessayer")
|
||||
.setStyle(ButtonStyle.Danger),
|
||||
);
|
||||
|
||||
export const sendReportEmbed = async (channel: TextChannel) => {
|
||||
await channel.send({
|
||||
embeds: [
|
||||
new EmbedBuilder()
|
||||
.setTitle("🚨 Signaler un joueur")
|
||||
.setDescription([
|
||||
"Tu as observé un comportement toxique ou de l'anti jeu ?",
|
||||
"",
|
||||
"Clique sur le bouton ci-dessous pour signaler un joueur.",
|
||||
"Pense à fournir le plus de détails dans 'raison', tu peux aussi ajouter des screenshots.",
|
||||
"",
|
||||
`-# Les signalements sont envoyés dans <#${env.DISCORD_REPORT_CHANNEL}>.`,
|
||||
].join("\n"))
|
||||
.setColor(0xe74c3c),
|
||||
],
|
||||
components: [
|
||||
new ActionRowBuilder<ButtonBuilder>().addComponents(
|
||||
new ButtonBuilder()
|
||||
.setCustomId(REPORT_BUTTON_ID)
|
||||
.setLabel("Signaler un joueur")
|
||||
.setStyle(ButtonStyle.Danger),
|
||||
),
|
||||
],
|
||||
});
|
||||
};
|
||||
|
||||
export const handleReportButton = async (interaction: ButtonInteraction) => {
|
||||
await interaction.showModal(buildModal());
|
||||
};
|
||||
|
||||
export const handleReportModal = async (interaction: ModalSubmitInteraction, client: Client) => {
|
||||
const playerName = interaction.fields.getTextInputValue("player_name");
|
||||
const reason = interaction.fields.getTextInputValue("reason");
|
||||
const { attachments, screenshotUrls } = extractScreenshots(interaction.fields);
|
||||
|
||||
await interaction.deferReply({ flags: MessageFlags.Ephemeral });
|
||||
|
||||
const player = await searchPlayer(playerName);
|
||||
if (!player) {
|
||||
await interaction.editReply({
|
||||
content: `Aucun joueur avec le pseudo **${playerName}** n'a été trouvé. Vérifie les majuscules et réessaie.`,
|
||||
components: [retryRow()],
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const [inserted] = await db
|
||||
.insert(tables.reports)
|
||||
.values({
|
||||
reporterId: interaction.user.id,
|
||||
reporterUsername: interaction.user.username,
|
||||
playerName,
|
||||
playerId: player.id,
|
||||
reason,
|
||||
screenshots: screenshotUrls,
|
||||
})
|
||||
.returning({ id: tables.reports.id });
|
||||
|
||||
let messageLink = "";
|
||||
const reportChannel = await client.channels.fetch(env.DISCORD_REPORT_CHANNEL);
|
||||
if (reportChannel?.type === ChannelType.GuildText) {
|
||||
const reportMessage = await reportChannel.send({
|
||||
embeds: [buildReportEmbed({ playerName, playerId: player.id, reason, reporterId: interaction.user.id })],
|
||||
components: [reportActionRow(inserted.id)],
|
||||
});
|
||||
messageLink = `https://discord.com/channels/${reportChannel.guild.id}/${reportChannel.id}/${reportMessage.id}`;
|
||||
await db.update(tables.reports).set({ messageLink }).where(eq(tables.reports.id, inserted.id));
|
||||
if (attachments) {
|
||||
await reportChannel.send({ files: attachments.map(a => a.url) });
|
||||
}
|
||||
} else {
|
||||
logger.error("Invalid 'DISCORD_REPORT_CHANNEL'");
|
||||
}
|
||||
|
||||
await interaction.editReply({
|
||||
content: `Le joueur **${playerName}** a bien été signalé. Merci !${messageLink ? ` ${messageLink}` : ""}`,
|
||||
});
|
||||
};
|
||||
|
||||
export const handleEditButton = async (interaction: ButtonInteraction, reportId: string) => {
|
||||
const [report] = await db.select().from(tables.reports).where(eq(tables.reports.id, reportId));
|
||||
if (!report) {
|
||||
await interaction.reply({ content: "Signalement introuvable.", flags: MessageFlags.Ephemeral });
|
||||
return;
|
||||
}
|
||||
if (!isAuthorized(interaction, report.reporterId)) {
|
||||
await interaction.reply({ content: "Tu n'as pas la permission de modifier ce signalement.", flags: MessageFlags.Ephemeral });
|
||||
return;
|
||||
}
|
||||
|
||||
await interaction.showModal(buildEditModal(reportId, interaction.channelId, interaction.message.id, report.reason));
|
||||
};
|
||||
|
||||
export const handleDeleteButton = async (interaction: ButtonInteraction, reportId: string) => {
|
||||
await interaction.deferReply({ flags: MessageFlags.Ephemeral });
|
||||
|
||||
const [report] = await db.select().from(tables.reports).where(eq(tables.reports.id, reportId));
|
||||
if (!report) {
|
||||
await interaction.editReply({ content: "Signalement introuvable." });
|
||||
return;
|
||||
}
|
||||
if (!isAuthorized(interaction, report.reporterId)) {
|
||||
await interaction.editReply({ content: "Tu n'as pas la permission de supprimer ce signalement." });
|
||||
return;
|
||||
}
|
||||
|
||||
await db.delete(tables.reports).where(eq(tables.reports.id, reportId));
|
||||
await interaction.message.delete();
|
||||
await interaction.editReply({ content: "Signalement supprimé." });
|
||||
};
|
||||
|
||||
export const handleEditModal = async (interaction: ModalSubmitInteraction, client: Client, reportId: string, channelId: string, messageId: string) => {
|
||||
const reason = interaction.fields.getTextInputValue("reason");
|
||||
const { attachments, screenshotUrls } = extractScreenshots(interaction.fields);
|
||||
|
||||
await interaction.deferReply({ flags: MessageFlags.Ephemeral });
|
||||
|
||||
const [report] = await db.select().from(tables.reports).where(eq(tables.reports.id, reportId));
|
||||
if (!report) {
|
||||
await interaction.editReply({ content: "Signalement introuvable." });
|
||||
return;
|
||||
}
|
||||
if (!isAuthorized(interaction, report.reporterId)) {
|
||||
await interaction.editReply({ content: "Tu n'as pas la permission de modifier ce signalement." });
|
||||
return;
|
||||
}
|
||||
|
||||
const updateData: { reason: string; screenshots?: string | null } = { reason };
|
||||
if (screenshotUrls !== null) updateData.screenshots = screenshotUrls;
|
||||
|
||||
await db.update(tables.reports).set(updateData).where(eq(tables.reports.id, reportId));
|
||||
|
||||
const channel = await client.channels.fetch(channelId);
|
||||
if (channel?.type === ChannelType.GuildText) {
|
||||
try {
|
||||
const message = await channel.messages.fetch(messageId);
|
||||
await message.edit({
|
||||
embeds: [buildReportEmbed({ ...report, reason })],
|
||||
components: [reportActionRow(reportId)],
|
||||
});
|
||||
} catch {
|
||||
logger.error("Failed to fetch/edit report message");
|
||||
}
|
||||
if (attachments) {
|
||||
await channel.send({ files: attachments.map(a => a.url) });
|
||||
}
|
||||
}
|
||||
|
||||
await interaction.editReply({ content: "Signalement modifié." });
|
||||
};
|
||||
10
packages/database/drizzle/0001_broken_dorian_gray.sql
Normal file
10
packages/database/drizzle/0001_broken_dorian_gray.sql
Normal file
@@ -0,0 +1,10 @@
|
||||
CREATE TABLE "reports" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"reporter_id" text NOT NULL,
|
||||
"reporter_username" text NOT NULL,
|
||||
"player_name" text NOT NULL,
|
||||
"player_id" text NOT NULL,
|
||||
"reason" text NOT NULL,
|
||||
"screenshots" text,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL
|
||||
);
|
||||
1
packages/database/drizzle/0002_lucky_praxagora.sql
Normal file
1
packages/database/drizzle/0002_lucky_praxagora.sql
Normal file
@@ -0,0 +1 @@
|
||||
ALTER TABLE "reports" ADD COLUMN "message_link" text;
|
||||
208
packages/database/drizzle/meta/0001_snapshot.json
Normal file
208
packages/database/drizzle/meta/0001_snapshot.json
Normal file
@@ -0,0 +1,208 @@
|
||||
{
|
||||
"id": "4e4b7960-a3a0-4ee7-8bec-4f9379eae836",
|
||||
"prevId": "80475ee2-c581-462e-8075-13b1ae696df5",
|
||||
"version": "7",
|
||||
"dialect": "postgresql",
|
||||
"tables": {
|
||||
"public.accounts": {
|
||||
"name": "accounts",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"player_id": {
|
||||
"name": "player_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"balance": {
|
||||
"name": "balance",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": 0
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.reports": {
|
||||
"name": "reports",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"reporter_id": {
|
||||
"name": "reporter_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"reporter_username": {
|
||||
"name": "reporter_username",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"player_name": {
|
||||
"name": "player_name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"player_id": {
|
||||
"name": "player_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"reason": {
|
||||
"name": "reason",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"screenshots": {
|
||||
"name": "screenshots",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.tracked_players": {
|
||||
"name": "tracked_players",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"player_id": {
|
||||
"name": "player_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.username_history": {
|
||||
"name": "username_history",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"player_id": {
|
||||
"name": "player_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"username": {
|
||||
"name": "username",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"first_seen_at": {
|
||||
"name": "first_seen_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"username_history_player_id_tracked_players_player_id_fk": {
|
||||
"name": "username_history_player_id_tracked_players_player_id_fk",
|
||||
"tableFrom": "username_history",
|
||||
"tableTo": "tracked_players",
|
||||
"columnsFrom": [
|
||||
"player_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"player_id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
}
|
||||
},
|
||||
"enums": {},
|
||||
"schemas": {},
|
||||
"sequences": {},
|
||||
"roles": {},
|
||||
"policies": {},
|
||||
"views": {},
|
||||
"_meta": {
|
||||
"columns": {},
|
||||
"schemas": {},
|
||||
"tables": {}
|
||||
}
|
||||
}
|
||||
214
packages/database/drizzle/meta/0002_snapshot.json
Normal file
214
packages/database/drizzle/meta/0002_snapshot.json
Normal file
@@ -0,0 +1,214 @@
|
||||
{
|
||||
"id": "4643e6bd-db18-44c9-893d-8f57a94e8c0a",
|
||||
"prevId": "4e4b7960-a3a0-4ee7-8bec-4f9379eae836",
|
||||
"version": "7",
|
||||
"dialect": "postgresql",
|
||||
"tables": {
|
||||
"public.accounts": {
|
||||
"name": "accounts",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"player_id": {
|
||||
"name": "player_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"balance": {
|
||||
"name": "balance",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": 0
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.reports": {
|
||||
"name": "reports",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"reporter_id": {
|
||||
"name": "reporter_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"reporter_username": {
|
||||
"name": "reporter_username",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"player_name": {
|
||||
"name": "player_name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"player_id": {
|
||||
"name": "player_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"reason": {
|
||||
"name": "reason",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"screenshots": {
|
||||
"name": "screenshots",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"message_link": {
|
||||
"name": "message_link",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.tracked_players": {
|
||||
"name": "tracked_players",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"player_id": {
|
||||
"name": "player_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.username_history": {
|
||||
"name": "username_history",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"player_id": {
|
||||
"name": "player_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"username": {
|
||||
"name": "username",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"first_seen_at": {
|
||||
"name": "first_seen_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"username_history_player_id_tracked_players_player_id_fk": {
|
||||
"name": "username_history_player_id_tracked_players_player_id_fk",
|
||||
"tableFrom": "username_history",
|
||||
"tableTo": "tracked_players",
|
||||
"columnsFrom": [
|
||||
"player_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"player_id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
}
|
||||
},
|
||||
"enums": {},
|
||||
"schemas": {},
|
||||
"sequences": {},
|
||||
"roles": {},
|
||||
"policies": {},
|
||||
"views": {},
|
||||
"_meta": {
|
||||
"columns": {},
|
||||
"schemas": {},
|
||||
"tables": {}
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,20 @@
|
||||
"when": 1764882945878,
|
||||
"tag": "0000_tan_justin_hammer",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 1,
|
||||
"version": "7",
|
||||
"when": 1778601650406,
|
||||
"tag": "0001_broken_dorian_gray",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 2,
|
||||
"version": "7",
|
||||
"when": 1778605638295,
|
||||
"tag": "0002_lucky_praxagora",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,5 +1,20 @@
|
||||
import { integer, pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core";
|
||||
|
||||
/**
|
||||
* REPORTING SYSTEM
|
||||
*/
|
||||
export const reports = pgTable("reports", {
|
||||
id: uuid("id").primaryKey().defaultRandom(),
|
||||
reporterId: text("reporter_id").notNull(),
|
||||
reporterUsername: text("reporter_username").notNull(),
|
||||
playerName: text("player_name").notNull(),
|
||||
playerId: text("player_id").notNull(),
|
||||
reason: text("reason").notNull(),
|
||||
screenshots: text("screenshots"),
|
||||
messageLink: text("message_link"),
|
||||
createdAt: timestamp("created_at").notNull().defaultNow(),
|
||||
});
|
||||
|
||||
/**
|
||||
* ECONOMY SYSTEM
|
||||
*/
|
||||
|
||||
82
pnpm-lock.yaml
generated
82
pnpm-lock.yaml
generated
@@ -24,8 +24,8 @@ importers:
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/utils
|
||||
discord.js:
|
||||
specifier: ^14.21.0
|
||||
version: 14.25.1
|
||||
specifier: ^14.26.4
|
||||
version: 14.26.4
|
||||
sharp:
|
||||
specifier: ^0.34.5
|
||||
version: 0.34.5
|
||||
@@ -95,8 +95,8 @@ importers:
|
||||
|
||||
packages:
|
||||
|
||||
'@discordjs/builders@1.13.1':
|
||||
resolution: {integrity: sha512-cOU0UDHc3lp/5nKByDxkmRiNZBpdp0kx55aarbiAfakfKJHlxv/yFW1zmIqCAmwH5CRlrH9iMFKJMpvW4DPB+w==}
|
||||
'@discordjs/builders@1.14.1':
|
||||
resolution: {integrity: sha512-gSKkhXLqs96TCzk66VZuHHl8z2bQMJFGwrXC0f33ngK+FLNau4hU1PYny3DNJfNdSH+gVMzE85/d5FQ2BpcNwQ==}
|
||||
engines: {node: '>=16.11.0'}
|
||||
|
||||
'@discordjs/collection@1.5.3':
|
||||
@@ -111,8 +111,8 @@ packages:
|
||||
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==}
|
||||
'@discordjs/rest@2.6.1':
|
||||
resolution: {integrity: sha512-wwQdgjeaoYFiaG+atbqx6aJDpqW7JHAo0HrQkBTbYzM3/PJ3GweQIpgElNcGZ26DCUOXMyawYd0YF7vtr+fZXg==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@discordjs/util@1.2.0':
|
||||
@@ -795,6 +795,10 @@ packages:
|
||||
resolution: {integrity: sha512-jjmJywLAFoWeBi1W7994zZyiNWPIiqRRNAmSERxyg93xRGzNYvGjlZ0gR6x0F4gPRi2+0O6S71kOZYyr3cxaIQ==}
|
||||
engines: {node: '>=v14.0.0', npm: '>=7.0.0'}
|
||||
|
||||
'@sapphire/snowflake@3.5.5':
|
||||
resolution: {integrity: sha512-xzvBr1Q1c4lCe7i6sRnrofxeO1QTP/LKQ6A6qy0iB4x5yfiSfARMEQEghojzTNALDTcv8En04qYNIco9/K9eZQ==}
|
||||
engines: {node: '>=v14.0.0', npm: '>=7.0.0'}
|
||||
|
||||
'@types/esrecurse@4.3.1':
|
||||
resolution: {integrity: sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==}
|
||||
|
||||
@@ -953,11 +957,11 @@ packages:
|
||||
resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
discord-api-types@0.38.36:
|
||||
resolution: {integrity: sha512-qrbUbjjwtyeBg5HsAlm1C859epfOyiLjPqAOzkdWlCNsZCWJrertnETF/NwM8H+waMFU58xGSc5eXUfXah+WTQ==}
|
||||
discord-api-types@0.38.47:
|
||||
resolution: {integrity: sha512-XgXQodHQBAE6kfD7kMvVo30863iHX1LHSqNq6MGUTDwIFCCvHva13+rwxyxVXDqudyApMNAd32PGjgVETi5rjA==}
|
||||
|
||||
discord.js@14.25.1:
|
||||
resolution: {integrity: sha512-2l0gsPOLPs5t6GFZfQZKnL1OJNYFcuC/ETWsW4VtKVD/tg4ICa9x+jb9bkPffkMdRpRpuUaO/fKkHCBeiCKh8g==}
|
||||
discord.js@14.26.4:
|
||||
resolution: {integrity: sha512-4oBp8tc6Kf8IDBwAHhbsMaAqx1b5fob9SNasZT7V6yyyUydoO5i5fGuX7TmvRtR+q/WgKRnRViRoAWnG7fNyvA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
dotenv@17.2.3:
|
||||
@@ -1254,11 +1258,11 @@ packages:
|
||||
lodash.snakecase@4.1.1:
|
||||
resolution: {integrity: sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==}
|
||||
|
||||
lodash@4.17.21:
|
||||
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
|
||||
lodash@4.18.1:
|
||||
resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==}
|
||||
|
||||
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==}
|
||||
|
||||
merge2@1.4.1:
|
||||
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
|
||||
@@ -1497,8 +1501,8 @@ packages:
|
||||
undici-types@6.21.0:
|
||||
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
|
||||
|
||||
undici@6.21.3:
|
||||
resolution: {integrity: sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw==}
|
||||
undici@6.24.1:
|
||||
resolution: {integrity: sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA==}
|
||||
engines: {node: '>=18.17'}
|
||||
|
||||
uri-js@4.4.1:
|
||||
@@ -1538,12 +1542,12 @@ packages:
|
||||
|
||||
snapshots:
|
||||
|
||||
'@discordjs/builders@1.13.1':
|
||||
'@discordjs/builders@1.14.1':
|
||||
dependencies:
|
||||
'@discordjs/formatters': 0.6.2
|
||||
'@discordjs/util': 1.2.0
|
||||
'@sapphire/shapeshift': 4.0.0
|
||||
discord-api-types: 0.38.36
|
||||
discord-api-types: 0.38.47
|
||||
fast-deep-equal: 3.1.3
|
||||
ts-mixer: 6.0.4
|
||||
tslib: 2.8.1
|
||||
@@ -1554,33 +1558,33 @@ snapshots:
|
||||
|
||||
'@discordjs/formatters@0.6.2':
|
||||
dependencies:
|
||||
discord-api-types: 0.38.36
|
||||
discord-api-types: 0.38.47
|
||||
|
||||
'@discordjs/rest@2.6.0':
|
||||
'@discordjs/rest@2.6.1':
|
||||
dependencies:
|
||||
'@discordjs/collection': 2.1.1
|
||||
'@discordjs/util': 1.2.0
|
||||
'@sapphire/async-queue': 1.5.5
|
||||
'@sapphire/snowflake': 3.5.3
|
||||
'@sapphire/snowflake': 3.5.5
|
||||
'@vladfrangu/async_event_emitter': 2.4.7
|
||||
discord-api-types: 0.38.36
|
||||
magic-bytes.js: 1.12.1
|
||||
discord-api-types: 0.38.47
|
||||
magic-bytes.js: 1.13.0
|
||||
tslib: 2.8.1
|
||||
undici: 6.21.3
|
||||
undici: 6.24.1
|
||||
|
||||
'@discordjs/util@1.2.0':
|
||||
dependencies:
|
||||
discord-api-types: 0.38.36
|
||||
discord-api-types: 0.38.47
|
||||
|
||||
'@discordjs/ws@1.2.3':
|
||||
dependencies:
|
||||
'@discordjs/collection': 2.1.1
|
||||
'@discordjs/rest': 2.6.0
|
||||
'@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
|
||||
discord-api-types: 0.38.36
|
||||
discord-api-types: 0.38.47
|
||||
tslib: 2.8.1
|
||||
ws: 8.18.3
|
||||
transitivePeerDependencies:
|
||||
@@ -1987,10 +1991,12 @@ 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': {}
|
||||
|
||||
'@sapphire/snowflake@3.5.5': {}
|
||||
|
||||
'@types/esrecurse@4.3.1': {}
|
||||
|
||||
'@types/estree@1.0.9': {}
|
||||
@@ -2168,23 +2174,23 @@ snapshots:
|
||||
dependencies:
|
||||
path-type: 4.0.0
|
||||
|
||||
discord-api-types@0.38.36: {}
|
||||
discord-api-types@0.38.47: {}
|
||||
|
||||
discord.js@14.25.1:
|
||||
discord.js@14.26.4:
|
||||
dependencies:
|
||||
'@discordjs/builders': 1.13.1
|
||||
'@discordjs/builders': 1.14.1
|
||||
'@discordjs/collection': 1.5.3
|
||||
'@discordjs/formatters': 0.6.2
|
||||
'@discordjs/rest': 2.6.0
|
||||
'@discordjs/rest': 2.6.1
|
||||
'@discordjs/util': 1.2.0
|
||||
'@discordjs/ws': 1.2.3
|
||||
'@sapphire/snowflake': 3.5.3
|
||||
discord-api-types: 0.38.36
|
||||
discord-api-types: 0.38.47
|
||||
fast-deep-equal: 3.1.3
|
||||
lodash.snakecase: 4.1.1
|
||||
magic-bytes.js: 1.12.1
|
||||
magic-bytes.js: 1.13.0
|
||||
tslib: 2.8.1
|
||||
undici: 6.21.3
|
||||
undici: 6.24.1
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- utf-8-validate
|
||||
@@ -2486,9 +2492,9 @@ snapshots:
|
||||
|
||||
lodash.snakecase@4.1.1: {}
|
||||
|
||||
lodash@4.17.21: {}
|
||||
lodash@4.18.1: {}
|
||||
|
||||
magic-bytes.js@1.12.1: {}
|
||||
magic-bytes.js@1.13.0: {}
|
||||
|
||||
merge2@1.4.1: {}
|
||||
|
||||
@@ -2719,7 +2725,7 @@ snapshots:
|
||||
|
||||
undici-types@6.21.0: {}
|
||||
|
||||
undici@6.21.3: {}
|
||||
undici@6.24.1: {}
|
||||
|
||||
uri-js@4.4.1:
|
||||
dependencies:
|
||||
|
||||
Reference in New Issue
Block a user