all repos — stealth-developers @ 83548d80877e385f55e8ca8b5a21daf8388a96cb

chore: format everything
vi did:web:vt3e.cat
Sat, 09 May 2026 01:19:22 +0100
commit

83548d80877e385f55e8ca8b5a21daf8388a96cb

parent

8bee8ce3815083afdc6fb78059396adc11ac73a8

54 files changed, 444 insertions(+), 1062 deletions(-)

jump to
M .config.example.json.config.example.json

@@ -1,18 +1,18 @@

{ - "discord": { - "token": "", - "app_id": "" - }, - "mongodb": { - "uri": "", - "database": "" - }, - "projects": { - "short": { - "name": "name", - "displayName": "Formatted Name", - "iconURL": "URL of icon - optional" - } - }, - "trelloBoardId": "optional -- used in bug reports" + "discord": { + "token": "", + "app_id": "" + }, + "mongodb": { + "uri": "", + "database": "" + }, + "projects": { + "short": { + "name": "name", + "displayName": "Formatted Name", + "iconURL": "URL of icon - optional" + } + }, + "trelloBoardId": "optional -- used in bug reports" }
M .zed/settings.json.zed/settings.json

@@ -3,7 +3,7 @@ //

// For a full list of overridable settings, and general information on folder-specific settings, // see the documentation: https://zed.dev/docs/configuring-zed#settings-files { - "wrap_guides": [80, 100], + "wrap_guides": [80, 100], "format_on_save": "on", "languages": { "Vue.js": {
M README.mdREADME.md

@@ -23,6 +23,7 @@

### setup clone the repo and install any deps: + ```sh git clone https://github.com/willow-contrib/stealth-developers.git cd stealth-developers

@@ -34,11 +35,11 @@ to `.config.json` and fill in the values.

`ENVIRONMENT` is defined by the `NODE_ENV` environment variable; if not set, it will default to `DEV`. - ### running run the bot with: + ```sh bun run start ```

@@ -46,6 +47,7 @@

### development if you want to run the bot in development mode, you can use: + ```sh bun run dev ```
M biome.jsonbiome.json

@@ -1,32 +1,32 @@

{ - "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", - "vcs": { - "enabled": false, - "clientKind": "git", - "useIgnoreFile": false - }, - "files": { - "ignoreUnknown": false, - "ignore": [] - }, - "formatter": { - "enabled": true, - "indentStyle": "tab", - "indentWidth": 2, - "lineWidth": 80 - }, - "organizeImports": { - "enabled": true - }, - "linter": { - "enabled": true, - "rules": { - "recommended": true - } - }, - "javascript": { - "formatter": { - "quoteStyle": "double" - } - } + "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", + "vcs": { + "enabled": false, + "clientKind": "git", + "useIgnoreFile": false + }, + "files": { + "ignoreUnknown": false, + "ignore": [] + }, + "formatter": { + "enabled": true, + "indentStyle": "tab", + "indentWidth": 2, + "lineWidth": 80 + }, + "organizeImports": { + "enabled": true + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true + } + }, + "javascript": { + "formatter": { + "quoteStyle": "double" + } + } }
M package.jsonpackage.json

@@ -1,39 +1,39 @@

{ - "name": "template", - "module": "src/index.ts", - "type": "module", - "license": "AGPL-3.0-only", - "author": { - "name": "willow", - "email": "hai@wlo.moe", - "url": "https://wlo.moe." - }, - "scripts": { - "start": "bun run src/index.ts", - "dev": "bun run src/index.ts --watch", - "fmt": "bunx biome format --write src/", - "lint": "bunx biome lint src/", - "check": "bunx biome check src/" - }, - "devDependencies": { - "@biomejs/biome": "^1.9.4", - "@types/bun": "^1.3.12", - "drizzle-kit": "^1.0.0-beta.9-e89174b" - }, - "peerDependencies": { - "typescript": "^5.9.3" - }, - "dependencies": { - "@libsql/client": "^0.17.2", - "discord-api-types": "^0.38.47", - "discord.js": "^14.26.2", - "drizzle-orm": "^1.0.0-beta.9-e89174b", - "fastest-levenshtein": "^1.0.16", - "nanoid": "^5.1.7", - "pino": "^10.3.1", - "pino-pretty": "^13.1.3", - "tesseract.js": "^7.0.0", - "uwuifier": "^4.2.2", - "zod": "^4.3.6" - } + "name": "template", + "license": "AGPL-3.0-only", + "author": { + "name": "willow", + "email": "hai@wlo.moe", + "url": "https://wlo.moe." + }, + "type": "module", + "module": "src/index.ts", + "scripts": { + "start": "bun run src/index.ts", + "dev": "bun run src/index.ts --watch", + "fmt": "bunx biome format --write src/", + "lint": "bunx biome lint src/", + "check": "bunx biome check src/" + }, + "dependencies": { + "@libsql/client": "^0.17.2", + "discord-api-types": "^0.38.47", + "discord.js": "^14.26.2", + "drizzle-orm": "^1.0.0-beta.9-e89174b", + "fastest-levenshtein": "^1.0.16", + "nanoid": "^5.1.7", + "pino": "^10.3.1", + "pino-pretty": "^13.1.3", + "tesseract.js": "^7.0.0", + "uwuifier": "^4.2.2", + "zod": "^4.3.6" + }, + "devDependencies": { + "@biomejs/biome": "^1.9.4", + "@types/bun": "^1.3.12", + "drizzle-kit": "^1.0.0-beta.9-e89174b" + }, + "peerDependencies": { + "typescript": "^5.9.3" + } }
M scripts/anonymise-database.tsscripts/anonymise-database.ts

@@ -40,6 +40,4 @@ }

} } -console.log( - `done! processed ${processedMessages} messages, updated ${updatedMessages}`, -); +console.log(`done! processed ${processedMessages} messages, updated ${updatedMessages}`);
D scripts/list.ts

@@ -1,31 +0,0 @@

-import client, { rest } from "@/discord"; -import config from "../src/config.ts"; -import { codeBlock, Events, Routes } from "discord.js"; - -await client.login(config.discord.token) - -client.on(Events.ClientReady, async (client) => { - const servers = await client.guilds.fetch() - console.log(`You are in ${servers.size} servers!`) - for (const [id, server] of servers) { - console.log(id, server.name) - - const channels = await client.guilds.cache.get(id)?.channels.fetch() - if (!channels) continue - for (const [id, channel] of channels) { - // console.log(`\t${id}, ${channel?.name}`) - - if (id === "1478940790112915486") { - if (!channel?.isSendable()) continue - - // await channel.send("??? that returned an error but the message did go through good job discord") - - const messages = await channel.messages.fetch({ limit: 100 }) - for (const [id, message] of messages) { - console.log(`${message.author.tag} ${message.content}`) - } - } - } - - } -})
M src/database/queries.tssrc/database/queries.ts

@@ -1,35 +1,16 @@

-import { - type Guild, - type Ticket, - db, - guild, - manager, - tickets, -} from "@/database"; +import { type Guild, type Ticket, db, guild, manager, tickets } from "@/database"; import type { Snowflake } from "discord.js"; import { and, eq, sql } from "drizzle-orm"; type QueryResult<T, WillCreate extends boolean = false> = | { exists: true; data: T } - | (WillCreate extends true - ? { exists: false; data: T } - : { exists: false; data: T | null }); + | (WillCreate extends true ? { exists: false; data: T } : { exists: false; data: T | null }); -export async function getGuild( - guildId: Snowflake, -): Promise<QueryResult<Guild, true>> { - const result = await db - .select() - .from(guild) - .where(eq(guild.guildId, guildId)) - .execute(); +export async function getGuild(guildId: Snowflake): Promise<QueryResult<Guild, true>> { + const result = await db.select().from(guild).where(eq(guild.guildId, guildId)).execute(); if (!result || result.length === 0) { - const newGuild = await db - .insert(guild) - .values({ guildId }) - .returning() - .execute(); + const newGuild = await db.insert(guild).values({ guildId }).returning().execute(); return { exists: false, data: newGuild[0],

@@ -42,9 +23,7 @@ data: result[0],

}; } -export async function getTicketMessage( - guildId: Snowflake, -): Promise<QueryResult<string, false>> { +export async function getTicketMessage(guildId: Snowflake): Promise<QueryResult<string, false>> { const guild = await getGuild(guildId); if (!guild || !guild.data.ticket_message) { return {

@@ -137,9 +116,7 @@

const ticket = await db .select() .from(tickets) - .where( - and(eq(tickets.guildId, guildId), eq(tickets.ticketNumber, numericId)), - ) + .where(and(eq(tickets.guildId, guildId), eq(tickets.ticketNumber, numericId))) .execute(); if (!ticket || ticket.length === 0) {

@@ -155,9 +132,7 @@ data: ticket[0],

}; } -export async function getManagerRoleIds( - guildId: Snowflake, -): Promise<Snowflake[]> { +export async function getManagerRoleIds(guildId: Snowflake): Promise<Snowflake[]> { const rows = await db .select({ roleId: manager.roleId }) .from(manager)
M src/database/schema/bugs.tssrc/database/schema/bugs.ts

@@ -16,10 +16,7 @@

title: text("title").notNull(), description: text("description").notNull(), - projects: text("projects", { mode: "json" }) - .$type<string[]>() - .default([]) - .notNull(), + projects: text("projects", { mode: "json" }).$type<string[]>().default([]).notNull(), sent: integer("sent", { mode: "boolean" }).default(false).notNull(), messageId: text("message_id"),
M src/database/schema/moderators.tssrc/database/schema/moderators.ts

@@ -1,10 +1,10 @@

import { sqliteTable, text } from "drizzle-orm/sqlite-core"; export const moderators = sqliteTable("moderators", { - user_id: text("user_id").primaryKey(), - subjective: text("subjective").notNull(), - objective: text("objective").notNull(), - possessiveDeterminer: text("possessive_determiner").notNull(), - possessive: text("possessive").notNull(), - reflexive: text("reflexive").notNull(), -}) + user_id: text("user_id").primaryKey(), + subjective: text("subjective").notNull(), + objective: text("objective").notNull(), + possessiveDeterminer: text("possessive_determiner").notNull(), + possessive: text("possessive").notNull(), + reflexive: text("reflexive").notNull(), +});
M src/database/schema/sessions.tssrc/database/schema/sessions.ts

@@ -2,10 +2,10 @@ import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";

import { sql } from "drizzle-orm"; export const sessions = sqliteTable("sessions", { - id: text("id").primaryKey(), - userId: text("user_id").notNull(), - username: text("username").notNull(), - createdAt: integer("created_at", { mode: "timestamp" }) - .default(sql`(unixepoch())`) - .notNull(), + id: text("id").primaryKey(), + userId: text("user_id").notNull(), + username: text("username").notNull(), + createdAt: integer("created_at", { mode: "timestamp" }) + .default(sql`(unixepoch())`) + .notNull(), });
M src/database/schema/tickets.tssrc/database/schema/tickets.ts

@@ -15,10 +15,7 @@ anonymousId: text("anonymous_id").notNull(),

claimedBy: text("claimed_by"), claimedAt: integer("claimed_at", { mode: "timestamp" }), - addedUsers: text("added_users", { mode: "json" }) - .$type<string[]>() - .default([]) - .notNull(), + addedUsers: text("added_users", { mode: "json" }).$type<string[]>().default([]).notNull(), type: text("type").notNull(), status: text("status", { enum: ["open", "closed", "archived"] })
M src/events/interactionCreate.tssrc/events/interactionCreate.ts

@@ -15,10 +15,7 @@ if (!command || !command.execute) return;

try { await command.execute(client, interaction); } catch (error) { - logger.error( - error, - `there was an error while executing ${interaction.commandName}`, - ); + logger.error(error, `there was an error while executing ${interaction.commandName}`); if (interaction.deferred || interaction.replied) { await interaction.followUp({
M src/events/messageCreate.tssrc/events/messageCreate.ts

@@ -1,22 +1,9 @@

-import { - AttachmentBuilder, - type Client, - Events, - type GuildMember, - type Message, -} from "discord.js"; +import { AttachmentBuilder, type Client, Events, type GuildMember, type Message } from "discord.js"; import { and, eq } from "drizzle-orm"; import { nanoid } from "nanoid"; -import { - attachments, - db, - ticketMessages, - tickets, - userPreferences, -} from "@/database"; +import { attachments, db, ticketMessages, tickets, userPreferences } from "@/database"; import { getPublicUrl, s3 } from "@/utils/s3"; - import { handleMessage } from "@/automod"; import config from "@/config";

@@ -44,9 +31,7 @@ // const allowed = await checkUwuifyRateLimit(message.author.id);

const allowed = true; if (!allowed) { const info = await getRateLimitInfo(message.author.id); - const resetTime = info?.resetAt - ? Math.floor(info.resetAt.getTime() / 1000) - : Date.now(); + const resetTime = info?.resetAt ? Math.floor(info.resetAt.getTime() / 1000) : Date.now(); try { await message.reply({

@@ -67,14 +52,9 @@ try {

let replyReference = null; if (message.reference?.messageId) { try { - replyReference = await message.channel.messages.fetch( - message.reference.messageId, - ); + replyReference = await message.channel.messages.fetch(message.reference.messageId); } catch (error) { - logger.warn( - error, - "Failed to fetch referenced message for uwuified reply", - ); + logger.warn(error, "Failed to fetch referenced message for uwuified reply"); } }

@@ -83,9 +63,7 @@ for (const attachment of message.attachments.values()) {

try { const resp = await fetch(attachment.url); if (!resp.ok) { - logger.warn( - `Failed to fetch attachment ${attachment.name}, status ${resp.status}`, - ); + logger.warn(`Failed to fetch attachment ${attachment.name}, status ${resp.status}`); continue; }

@@ -101,9 +79,7 @@ }

message.delete(); - const contentParts = [ - `**<@${message.author.id}>**: ${uwuify(message.content)}`, - ]; + const contentParts = [`**<@${message.author.id}>**: ${uwuify(message.content)}`]; if (message.channel.isSendable()) { const sendOptions: {

@@ -148,9 +124,7 @@

const triggers = ["grok is this true", "grok is this false "]; if ( message.channel.isSendable() && - triggers.some((trigger) => - message.content.toLowerCase().includes(trigger), - ) + triggers.some((trigger) => message.content.toLowerCase().includes(trigger)) ) { const chance = Math.random() * 100; if (chance < 25 || message.author.id === "470956810866655242") {

@@ -161,10 +135,7 @@ message.channel.send("yeh");

} } - if ( - message.channel.isSendable() && - message.content.includes("gorque is this true") - ) { + if (message.channel.isSendable() && message.content.includes("gorque is this true")) { message.channel.send("oui 🇫🇷🥖"); }

@@ -174,10 +145,7 @@ const ticket = db

.select() .from(tickets) .where( - and( - eq(tickets.channelId, message.channelId), - eq(tickets.guildId, message.guildId ?? ""), - ), + and(eq(tickets.channelId, message.channelId), eq(tickets.guildId, message.guildId ?? "")), ) .get();

@@ -185,15 +153,10 @@ if (!ticket) return;

try { const isSystem = message.author.id === client.user.id; - const isModerator = await hasManagerPermissions( - message?.member as GuildMember, - ); + const isModerator = await hasManagerPermissions(message?.member as GuildMember); const authorType = isSystem ? "system" : isModerator ? "staff" : "user"; - let anonymisedContent = message.content.replace( - new RegExp(ticket.authorId, "g"), - "Reporter", - ); + let anonymisedContent = message.content.replace(new RegExp(ticket.authorId, "g"), "Reporter"); for (const [index, userId] of (ticket.addedUsers || []).entries()) { anonymisedContent = anonymisedContent.replace(

@@ -230,8 +193,7 @@

const formatSize = (size: number) => { if (size < 1024) return `${size} B`; if (size < 1024 * 1024) return `${(size / 1024).toFixed(2)} KB`; - if (size < 1024 * 1024 * 1024) - return `${(size / (1024 * 1024)).toFixed(2)} MB`; + if (size < 1024 * 1024 * 1024) return `${(size / (1024 * 1024)).toFixed(2)} MB`; return `${(size / (1024 * 1024 * 1024)).toFixed(2)} GB`; };

@@ -274,13 +236,9 @@ if (!statusMessage) continue;

try { statusList[i].status = "uploading"; - await statusMessage.edit( - `**Attachment upload status**\n${renderBoard()}`, - ); + await statusMessage.edit(`**Attachment upload status**\n${renderBoard()}`); - const key = `${ticket.anonymousId}/${savedMessage.id}/${nanoid( - 8, - )}_${attachment.name}`; + const key = `${ticket.anonymousId}/${savedMessage.id}/${nanoid(8)}_${attachment.name}`; const file = s3.file(key); const resp = await fetch(attachment.url);

@@ -303,18 +261,11 @@ });

statusList[i].status = "done"; statusList[i].url = publicUrl; - await statusMessage.edit( - `**Attachment upload status**\n${renderBoard()}`, - ); + await statusMessage.edit(`**Attachment upload status**\n${renderBoard()}`); } catch (error) { - logger.error( - error, - `Failed to upload attachment ${attachment.name}`, - ); + logger.error(error, `Failed to upload attachment ${attachment.name}`); statusList[i].status = "failed"; - await statusMessage.edit( - `**Attachment upload status**\n${renderBoard()}`, - ); + await statusMessage.edit(`**Attachment upload status**\n${renderBoard()}`); } } }
M src/events/messageDelete.tssrc/events/messageDelete.ts

@@ -14,10 +14,7 @@ const ticket = db

.select() .from(tickets) .where( - and( - eq(tickets.channelId, message.channelId), - eq(tickets.guildId, message.guildId ?? ""), - ), + and(eq(tickets.channelId, message.channelId), eq(tickets.guildId, message.guildId ?? "")), ) .get();
M src/handlers/events.tssrc/handlers/events.ts

@@ -25,10 +25,7 @@ logger.info(`found ${events.size} events.`);

for (const event of events.values()) { logger.info(`registering event: ${event.event}`); - client[event.once ? "once" : "on"]( - event.event, - event.execute.bind(null, client), - ); + client[event.once ? "once" : "on"](event.event, event.execute.bind(null, client)); } logger.info(`registered ${events.size} events`);
M src/handlers/interactions.tssrc/handlers/interactions.ts

@@ -14,11 +14,7 @@ const processFile = async (fileUrl: string) => {

const { default: interaction } = await import(fileUrl); if (!interaction) return; - if ( - !interaction.data && - !interaction.buttonExecute && - !interaction.modalExecute - ) { + if (!interaction.data && !interaction.buttonExecute && !interaction.modalExecute) { logger.info(`${fileUrl} does not have a data property, skipping`); return; }

@@ -41,19 +37,12 @@ commands.set(commandName, interaction);

return interaction; }; - return await crawlDirectory<ICommand>( - getHandlerPath("interactions"), - processFile, - ); + return await crawlDirectory<ICommand>(getHandlerPath("interactions"), processFile); } -async function registerInteractions( - client: Client, - interactions: ApplicationCommandData[], -) { +async function registerInteractions(client: Client, interactions: ApplicationCommandData[]) { if (!client.user) return logger.error("client user is not available"); - if (!client.application) - return logger.error("client application is not available"); + if (!client.application) return logger.error("client application is not available"); if (interactions.length === 0) return; logger.info("registering interactions...");
M src/index.tssrc/index.ts

@@ -7,16 +7,22 @@ import "./server";

async function main() { await migrateDb(); - await client.login(config.discord.token); + try { + await client.login(config.discord.token); + } catch (error) { + logger.error(error, "failed to login:"); + process.exit(1); + } } main(); process.on("unhandledRejection", (error) => { logger.error(error, "unhandled promise rejection:"); + console.error(error); }); process.on("uncaughtException", (error) => { - logger.error(error, "uncaught exception"); + logger.error(error, "uncaught exception"); console.error(error); });
M src/interactions/buttons/transcript-btn.tssrc/interactions/buttons/transcript-btn.ts

@@ -19,10 +19,7 @@ });

return; } - if ( - interaction.member && - (await hasManagerPermissions(interaction.member as GuildMember)) - ) { + if (interaction.member && (await hasManagerPermissions(interaction.member as GuildMember))) { await db.insert(ticketAccessLogs).values({ ticketId: ticket.id, userId: interaction.user.id,
M src/interactions/commands/bug/_shared.tssrc/interactions/commands/bug/_shared.ts

@@ -101,8 +101,7 @@ }

export function buildReportModal(bugId?: string, bug?: Bug) { const terminology = config.terminology; - const capitalizedTerminology = - terminology.charAt(0).toUpperCase() + terminology.slice(1); + const capitalizedTerminology = terminology.charAt(0).toUpperCase() + terminology.slice(1); const projectOptions = bug ? getProjectChoices("label", bug.projects[0])

@@ -140,9 +139,7 @@ );

const descriptionLabel = new LabelBuilder() .setLabel("Bug Description") - .setDescription( - bug ? "Update the bug description" : "Describe the bug in detail", - ) + .setDescription(bug ? "Update the bug description" : "Describe the bug in detail") .setTextInputComponent( (() => { const input = new TextInputBuilder()

@@ -164,18 +161,11 @@ modal.setLabelComponents(gameLabel, titleLabel, descriptionLabel);

} else { const mediaLabel = new LabelBuilder() .setLabel("Media") - .setDescription( - "Provide any screenshots or videos that demonstrate the bug", - ) + .setDescription("Provide any screenshots or videos that demonstrate the bug") .setFileUploadComponent( new FileUploadBuilder().setCustomId(INPUT_IDS.MEDIA).setRequired(false), ); - modal.setLabelComponents( - gameLabel, - titleLabel, - descriptionLabel, - mediaLabel, - ); + modal.setLabelComponents(gameLabel, titleLabel, descriptionLabel, mediaLabel); } return modal;
M src/interactions/commands/bug/buttons.tssrc/interactions/commands/bug/buttons.ts

@@ -14,10 +14,7 @@ const results = await db.select().from(bugs).where(eq(bugs.id, parsedId));

return results[0] ?? null; } -export async function handleCloseButton( - client: Client, - interaction: ButtonInteraction, -) { +export async function handleCloseButton(client: Client, interaction: ButtonInteraction) { const guildId = interaction.guildId; if (!guildId) return;

@@ -56,12 +53,7 @@ return;

} if (bug.messageId) { - await updateBugEmbed( - client, - { ...bug, status: "closed" }, - bug.messageId, - channelId, - ); + await updateBugEmbed(client, { ...bug, status: "closed" }, bug.messageId, channelId); } await interaction.reply({

@@ -70,10 +62,7 @@ flags: ["Ephemeral"],

}); } -export async function handleOpenButton( - client: Client, - interaction: ButtonInteraction, -) { +export async function handleOpenButton(client: Client, interaction: ButtonInteraction) { const guildId = interaction.guildId; if (!guildId) return;

@@ -113,12 +102,7 @@ return;

} if (bug.messageId) { - await updateBugEmbed( - client, - { ...bug, status: "open" }, - bug.messageId, - channelId, - ); + await updateBugEmbed(client, { ...bug, status: "open" }, bug.messageId, channelId); } await interaction.reply({

@@ -127,10 +111,7 @@ flags: ["Ephemeral"],

}); } -export async function handleEditButton( - _client: Client, - interaction: ButtonInteraction, -) { +export async function handleEditButton(_client: Client, interaction: ButtonInteraction) { const { parts } = parseComponentId(interaction.customId); const id = parts[1]; const bug = await fetchBugById(id);

@@ -147,10 +128,7 @@ const modal = buildReportModal(String(bug.id), bug);

await interaction.showModal(modal); } -export async function handleDeleteButton( - _client: Client, - interaction: ButtonInteraction, -) { +export async function handleDeleteButton(_client: Client, interaction: ButtonInteraction) { const guildId = interaction.guildId; if (!guildId) return;

@@ -165,9 +143,7 @@ });

return; } - const isManager = await hasManagerPermissions( - interaction.member as GuildMember, - ); + const isManager = await hasManagerPermissions(interaction.member as GuildMember); const isBugReporter = bug.authorId === interaction.user.id; if (!isManager && !isBugReporter) {

@@ -190,8 +166,7 @@ }

const channelId = data.bug_channel_id; if (!channelId) { await interaction.reply({ - content: - "✅ Bug removed from database. (No bug channel configured to remove message/thread)", + content: "✅ Bug removed from database. (No bug channel configured to remove message/thread)", flags: ["Ephemeral"], }); return;

@@ -220,10 +195,7 @@ flags: ["Ephemeral"],

}); } -export async function handleTrelloButton( - _client: Client, - interaction: ButtonInteraction, -) { +export async function handleTrelloButton(_client: Client, interaction: ButtonInteraction) { const { parts } = parseComponentId(interaction.customId); const id = parts[1]; const bug = await fetchBugById(id);
M src/interactions/commands/bug/index.tssrc/interactions/commands/bug/index.ts

@@ -21,25 +21,17 @@

const commandData = new SlashCommandBuilder() .setName("bug") .setDescription("Make a bug report") - .addSubcommand((subcommand) => - subcommand.setName("report").setDescription("Report a new bug"), - ) + .addSubcommand((subcommand) => subcommand.setName("report").setDescription("Report a new bug")) .addSubcommand((subcommand) => subcommand .setName("help") .setDescription("Help a user report a bug") .addUserOption((option) => - option - .setName("user") - .setDescription("The user to send the button to") - .setRequired(false), + option.setName("user").setDescription("The user to send the button to").setRequired(false), ), ); -async function execute( - _client: Client, - interaction: ChatInputCommandInteraction, -) { +async function execute(_client: Client, interaction: ChatInputCommandInteraction) { if (!interaction.isChatInputCommand()) return; const subcommand = interaction.options.getSubcommand();

@@ -112,10 +104,7 @@ });

} } -async function modalExecute( - client: Client, - interaction: ModalSubmitInteraction, -) { +async function modalExecute(client: Client, interaction: ModalSubmitInteraction) { const [, action] = interaction.customId.split(":"); switch (action) { case "edit":
M src/interactions/commands/bug/modals.tssrc/interactions/commands/bug/modals.ts

@@ -4,24 +4,14 @@ import { parseComponentId } from "@/utils/discord/components";

import { AttachmentBuilder } from "discord.js"; import type { Client, ModalSubmitInteraction } from "discord.js"; import { eq, sql } from "drizzle-orm"; -import { - INPUT_IDS, - VALIDATION, - constructContainer, - updateBugEmbed, -} from "./_shared"; +import { INPUT_IDS, VALIDATION, constructContainer, updateBugEmbed } from "./_shared"; -export async function handleNewBugModal( - _client: Client, - interaction: ModalSubmitInteraction, -) { +export async function handleNewBugModal(_client: Client, interaction: ModalSubmitInteraction) { const guildId = interaction.guildId; if (!guildId) return; const title = interaction.fields.getTextInputValue(INPUT_IDS.TITLE); - const description = interaction.fields.getTextInputValue( - INPUT_IDS.DESCRIPTION, - ); + const description = interaction.fields.getTextInputValue(INPUT_IDS.DESCRIPTION); const affected = interaction.fields.getStringSelectValues(INPUT_IDS.AFFECTED); const media = interaction.fields.getUploadedFiles(INPUT_IDS.MEDIA); await interaction.deferReply({ flags: ["Ephemeral"] });

@@ -78,11 +68,7 @@ console.error("error processing uploaded file:", err);

} } - const container = await constructContainer( - bug[0], - interaction.user.id, - attachment, - ); + const container = await constructContainer(bug[0], interaction.user.id, attachment); if (!container) return; const { data, exists } = await getGuild(guildId);

@@ -102,9 +88,7 @@ });

// thread function truncateTitle(title: string, maxLength: number): string { - return title.length > maxLength - ? `${title.substring(0, maxLength)}...` - : title; + return title.length > maxLength ? `${title.substring(0, maxLength)}...` : title; } const paddedNumber = bug[0].bugNumber.toString().padStart(4, "0"); const threadName = `#${paddedNumber} ${truncateTitle(title, VALIDATION.THREAD_NAME_MAX_LENGTH)}`;

@@ -119,18 +103,11 @@ .update(bugs)

.set({ messageId: message.id, threadId: thread.id, sent: true }) .where(eq(bugs.id, bug[0].id)); - thread.send( - "Use this space to discuss the bug, provide additional details, or ask questions.", - ); - interaction.editReply( - `Bug #${paddedNumber} created successfully! Find it here: ${message.url}`, - ); + thread.send("Use this space to discuss the bug, provide additional details, or ask questions."); + interaction.editReply(`Bug #${paddedNumber} created successfully! Find it here: ${message.url}`); } -export async function handleEditModal( - client: Client, - interaction: ModalSubmitInteraction, -) { +export async function handleEditModal(client: Client, interaction: ModalSubmitInteraction) { const guildId = interaction.guildId; if (!guildId) return;

@@ -145,9 +122,7 @@ return;

} const title = interaction.fields.getTextInputValue(INPUT_IDS.TITLE); - const description = interaction.fields.getTextInputValue( - INPUT_IDS.DESCRIPTION, - ); + const description = interaction.fields.getTextInputValue(INPUT_IDS.DESCRIPTION); const affected = interaction.fields.getStringSelectValues(INPUT_IDS.AFFECTED); if (

@@ -192,8 +167,7 @@

const { data, exists } = await getGuild(guildId); if (!exists) { await interaction.reply({ - content: - "✅ Bug updated, but guild configuration missing for updating the public message.", + content: "✅ Bug updated, but guild configuration missing for updating the public message.", flags: ["Ephemeral"], }); return;

@@ -201,8 +175,7 @@ }

const channelId = data.bug_channel_id; if (!channelId) { await interaction.reply({ - content: - "✅ Bug updated, but no bug channel configured to update message.", + content: "✅ Bug updated, but no bug channel configured to update message.", flags: ["Ephemeral"], }); return;
M src/interactions/commands/codes.tssrc/interactions/commands/codes.ts

@@ -12,16 +12,10 @@ const commandData = new SlashCommandBuilder()

.setName("codes") .setDescription(`Get the codes for all ${config.terminology}s`) .addUserOption((option) => - option - .setName("user") - .setDescription("Optional user to mention") - .setRequired(false), + option.setName("user").setDescription("Optional user to mention").setRequired(false), ); -async function execute( - _client: Client, - interaction: ChatInputCommandInteraction, -) { +async function execute(_client: Client, interaction: ChatInputCommandInteraction) { const user = interaction.options.getUser("user"); const container = new ContainerBuilder();

@@ -35,13 +29,10 @@ continue;

} for (const code of project.codes) { const codeText = code.expired ? `~~${code.code}~~` : `**${code.code}**`; - const addedString = code.addedAt - ? `added ${tsRelative(code.addedAt)}` - : undefined; - const lineParts = [ - `- ${codeText}`, - addedString ? `(${addedString})` : undefined, - ].filter(Boolean); + const addedString = code.addedAt ? `added ${tsRelative(code.addedAt)}` : undefined; + const lineParts = [`- ${codeText}`, addedString ? `(${addedString})` : undefined].filter( + Boolean, + ); containerTextArr.push(lineParts.join(" ")); }

@@ -61,9 +52,7 @@ container.addTextDisplayComponents(containerText, footerText);

await interaction.reply({ components: [container], flags: ["IsComponentsV2"], - ...(user - ? { allowedMentions: { users: [user?.id] } } - : { allowedMentions: { users: [] } }), + ...(user ? { allowedMentions: { users: [user?.id] } } : { allowedMentions: { users: [] } }), }); }
M src/interactions/commands/config.tssrc/interactions/commands/config.ts

@@ -48,9 +48,7 @@ { name: "remove", value: "remove" },

{ name: "list", value: "list" }, ), ) - .addRoleOption((opt) => - opt.setName("role").setDescription("role to add/remove"), - ), + .addRoleOption((opt) => opt.setName("role").setDescription("role to add/remove")), ) .addSubcommand((sub) => sub

@@ -76,26 +74,19 @@ .setDescription("value to set (for non-channel keys)")

.setRequired(false), ), ) - .addSubcommand((sub) => - sub.setName("view").setDescription("view current server configuration"), - ); + .addSubcommand((sub) => sub.setName("view").setDescription("view current server configuration")); async function autocomplete(interaction: AutocompleteInteraction) { const focused = interaction.options.getFocused(true); if (focused.name === "key") { const input = String(focused.value).toLowerCase(); - const suggestions = CONFIG_KEYS.filter((k) => - k.toLowerCase().includes(input), - ).slice(0, 25); + const suggestions = CONFIG_KEYS.filter((k) => k.toLowerCase().includes(input)).slice(0, 25); await interaction.respond(suggestions.map((s) => ({ name: s, value: s }))); } } -async function execute( - _client: Client, - interaction: ChatInputCommandInteraction, -) { +async function execute(_client: Client, interaction: ChatInputCommandInteraction) { if (!interaction.guild || !interaction.member) { await interaction.reply({ content: "❌ this command can only be used in a server.",

@@ -153,9 +144,7 @@ const role = interaction.options.getRole("role") as Role | null;

const guildId = interaction.guild.id; const isDeveloper = interaction.user.id === cfg.developerId; - const hasPerms = await hasManagerPermissions( - interaction.member as GuildMember, - ); + const hasPerms = await hasManagerPermissions(interaction.member as GuildMember); if (!isDeveloper && !hasPerms) { await interaction.reply({

@@ -227,10 +216,7 @@ return;

} if (action === "remove") { - await db - .delete(managerTable) - .where(eq(managerTable.roleId, role.id)) - .execute(); + await db.delete(managerTable).where(eq(managerTable.roleId, role.id)).execute(); await interaction.reply({ content: `✅ Removed ${role} from manager roles.`,

@@ -270,10 +256,7 @@

await getGuild(guildId); if (isChannelKey(key)) { - const channel = interaction.options.getChannel( - "channel", - false, - ) as GuildChannel | null; + const channel = interaction.options.getChannel("channel", false) as GuildChannel | null; if (!channel) { await interaction.reply({
M src/interactions/commands/meow.tssrc/interactions/commands/meow.ts

@@ -1,14 +1,8 @@

import { text } from "@/utils/discord/components"; -import { - type ChatInputCommandInteraction, - type Client, - SlashCommandBuilder, -} from "discord.js"; +import { type ChatInputCommandInteraction, type Client, SlashCommandBuilder } from "discord.js"; import Uwuifier from "uwuifier"; -const commandData = new SlashCommandBuilder() - .setName("meow") - .setDescription("mrrp~"); +const commandData = new SlashCommandBuilder().setName("meow").setDescription("mrrp~"); const meowVariants = [ "meow",

@@ -93,9 +87,7 @@

// sometimes extend the meow with repeated letters const extendedMeow = Math.random() > 0.5 - ? meow.replace(/[aeiourw]/g, (m) => - m.repeat(Math.floor(Math.random() * 4) + 1), - ) + ? meow.replace(/[aeiourw]/g, (m) => m.repeat(Math.floor(Math.random() * 4) + 1)) : meow; words.push(`${prefix}${extendedMeow}${suffix}`);

@@ -103,27 +95,17 @@ }

return ( words.join(" ") + - (Math.random() > 0.4 - ? ` ${emoticons[Math.floor(Math.random() * emoticons.length)]}` - : "") + (Math.random() > 0.4 ? ` ${emoticons[Math.floor(Math.random() * emoticons.length)]}` : "") ); } -async function execute( - _client: Client, - interaction: ChatInputCommandInteraction, -) { +async function execute(_client: Client, interaction: ChatInputCommandInteraction) { const uwuifier = new Uwuifier(); const meowText = generateMeow(); const uwuifiedMeowText = uwuifier.uwuifySentence(meowText); - const blacklistedWords = [ - "twerks", - "sees bulge", - "notices buldge", - "starts twerking", - ]; + const blacklistedWords = ["twerks", "sees bulge", "notices buldge", "starts twerking"]; const finalText = blacklistedWords.reduce((acc, word) => { return acc.replace(new RegExp(word, "gi"), "----");
M src/interactions/commands/pronouns.tssrc/interactions/commands/pronouns.ts

@@ -3,62 +3,55 @@ import { db, moderators } from "@/database";

import config from "@/config"; const pronounTypes = { - subjective: "Subject (e.g., **They** are a moderator)", - objective: "Object (e.g., Send **them** a message)", - "possessive-determiner": "Possessive Determiner (e.g., This is **their** post)", - "possessive-pronoun": "Possessive Pronoun (e.g., The post is **theirs**)", - reflexive: "Reflexive (e.g., They assigned it to **themself**)" -} + subjective: "Subject (e.g., **They** are a moderator)", + objective: "Object (e.g., Send **them** a message)", + "possessive-determiner": "Possessive Determiner (e.g., This is **their** post)", + "possessive-pronoun": "Possessive Pronoun (e.g., The post is **theirs**)", + reflexive: "Reflexive (e.g., They assigned it to **themself**)", +}; -const command = new SlashCommandBuilder() - .setName("woke") - .setDescription("Set your pronouns."); +const command = new SlashCommandBuilder().setName("woke").setDescription("Set your pronouns."); Object.entries(pronounTypes).forEach(([key, description]) => { - command.addStringOption((option) => - option - .setName(key) - .setDescription(description) - .setRequired(true) - ); + command.addStringOption((option) => + option.setName(key).setDescription(description).setRequired(true), + ); }); -command.addUserOption((option) => option.setName("user").setRequired(false).setDescription("The user to set pronouns for.")) +command.addUserOption((option) => + option.setName("user").setRequired(false).setDescription("The user to set pronouns for."), +); +async function execute(_client: Client, interaction: ChatInputCommandInteraction) { + const id = interaction.options.getUser("user")?.id || interaction.user.id; + if (interaction.options.getUser("user") && interaction.user.id !== config.developerId) { + await interaction.reply({ content: "You cannot use this command.", ephemeral: true }); + return; + } -async function execute( - _client: Client, - interaction: ChatInputCommandInteraction -) { - const id = interaction.options.getUser("user")?.id || interaction.user.id; - if (interaction.options.getUser("user") && interaction.user.id !== config.developerId) { - await interaction.reply({ content: "You cannot use this command.", ephemeral: true }); - return; - } + const pronounData = { + subjective: interaction.options.getString("subjective", true), + objective: interaction.options.getString("objective", true), + possessiveDeterminer: interaction.options.getString("possessive-determiner", true), + possessive: interaction.options.getString("possessive-pronoun", true), + reflexive: interaction.options.getString("reflexive", true), + }; - const pronounData = { - subjective: interaction.options.getString("subjective", true), - objective: interaction.options.getString("objective", true), - possessiveDeterminer: interaction.options.getString("possessive-determiner", true), - possessive: interaction.options.getString("possessive-pronoun", true), - reflexive: interaction.options.getString("reflexive", true), - }; - - await db.insert(moderators) - .values({ - user_id: id, - ...pronounData, - }) - .onConflictDoUpdate({ - target: moderators.user_id, - set: pronounData, - }); + await db + .insert(moderators) + .values({ + user_id: id, + ...pronounData, + }) + .onConflictDoUpdate({ + target: moderators.user_id, + set: pronounData, + }); - await interaction.reply({ content: "Pronouns updated.", flags: ["Ephemeral"] }); + await interaction.reply({ content: "Pronouns updated.", flags: ["Ephemeral"] }); } - export default { - data: command, - execute, + data: command, + execute, };
M src/interactions/commands/roblox/banHistory.tssrc/interactions/commands/roblox/banHistory.ts

@@ -18,9 +18,7 @@ import { hasManagerPermissions } from "@/utils/discord/permissions";

const commandData = new SlashCommandBuilder() .setName("ban-history") - .setDescription( - `Get a user's ban history in the selected ${config.terminology}`, - ) + .setDescription(`Get a user's ban history in the selected ${config.terminology}`) // .addSubcommand((subcommand) => // subcommand // .setName("discord")

@@ -52,9 +50,7 @@ .setDescription("Get Roblox info from a user ID or username")

.addStringOption((option) => option .setName("input") - .setDescription( - "The Roblox username to lookup - prefix with id: for IDs", - ) + .setDescription("The Roblox username to lookup - prefix with id: for IDs") .setRequired(true), ) .addStringOption((option) =>

@@ -71,10 +67,7 @@ .setRequired(true),

), ); -async function execute( - _client: Client, - interaction: ChatInputCommandInteraction, -) { +async function execute(_client: Client, interaction: ChatInputCommandInteraction) { const subcommand = interaction.options.getSubcommand(); const projectKey = interaction.options.getString( config.terminology,

@@ -84,9 +77,7 @@

const project = config.projects[projectKey]; const universeId = project.universe; - const isModerator = await hasManagerPermissions( - interaction.member as GuildMember, - ); + const isModerator = await hasManagerPermissions(interaction.member as GuildMember); await interaction.deferReply(); try {

@@ -98,9 +89,7 @@ const [linkedRes, linkedErr] = await roblox.getLinkedAccount(target.id);

if (linkedErr) { const message = linkedErr.error; if (message === "User not found") { - await interaction.editReply( - "No linked Roblox account found for that user.", - ); + await interaction.editReply("No linked Roblox account found for that user."); return; } await interaction.editReply(

@@ -133,18 +122,14 @@ await interaction.editReply(`Fetching user with ID ${id}...`);

const [user, userErr] = await roblox.getUser(id); if (userErr) { if (isApiErrorV2(userErr)) { - await interaction.editReply( - `There was an error fetching the user: ${userErr.message}`, - ); + await interaction.editReply(`There was an error fetching the user: ${userErr.message}`); } else { await interaction.editReply("There was an error fetching the user."); } return; } - await interaction.editReply( - `Found user with username ${user.name}, fetching thumbnail...`, - ); + await interaction.editReply(`Found user with username ${user.name}, fetching thumbnail...`); const [thumbnailRes] = await roblox.getThumbnail(id, { shape: "SQUARE" }); const thumbnailUri = thumbnailRes ? thumbnailRes.response?.imageUri : null;

@@ -156,8 +141,7 @@ "<:wawa:1158423817698430977>",

"<:max:1476776753845370991>", "<:snickerdoodle:1477173429575749716>", ]; - const message = - randomMessages[Math.floor(Math.random() * randomMessages.length)]; + const message = randomMessages[Math.floor(Math.random() * randomMessages.length)]; await interaction.editReply(message); const { mainContainer } = await constructUserContainer(user, {

@@ -178,18 +162,14 @@ components: [mainContainer, bansContainer],

}); } catch (err) { console.error(err); - await interaction.editReply( - "An unexpected error occurred while fetching the user.", - ); + await interaction.editReply("An unexpected error occurred while fetching the user."); } } async function buttonExecute(_client: Client, interaction: ButtonInteraction) { const [, action, userId] = interaction.customId.split(":"); - const isModerator = await hasManagerPermissions( - interaction.member as GuildMember, - ); + const isModerator = await hasManagerPermissions(interaction.member as GuildMember); const { container } = await constructBansSummaryContainer(userId, { showPrivate: isModerator, });
M src/interactions/commands/roblox/getUser.tssrc/interactions/commands/roblox/getUser.ts

@@ -31,21 +31,14 @@ .setDescription("Get Roblox info from a user ID or username")

.addStringOption((option) => option .setName("input") - .setDescription( - "The Roblox username to lookup - prefix with id: for IDs", - ) + .setDescription("The Roblox username to lookup - prefix with id: for IDs") .setRequired(true), ), ); -async function execute( - _client: Client, - interaction: ChatInputCommandInteraction, -) { +async function execute(_client: Client, interaction: ChatInputCommandInteraction) { const subcommand = interaction.options.getSubcommand(); - const isModerator = await hasManagerPermissions( - interaction.member as GuildMember, - ); + const isModerator = await hasManagerPermissions(interaction.member as GuildMember); await interaction.deferReply(); try {

@@ -57,9 +50,7 @@ const [linkedRes, linkedErr] = await roblox.getLinkedAccount(target.id);

if (linkedErr) { const message = linkedErr.error; if (message === "User not found") { - await interaction.editReply( - "No linked Roblox account found for that user.", - ); + await interaction.editReply("No linked Roblox account found for that user."); return; } await interaction.editReply(

@@ -91,9 +82,7 @@

await processRobloxUserInteraction(interaction, id, isModerator); } catch (err) { console.error(err); - await interaction.editReply( - "An unexpected error occurred while fetching the user.", - ); + await interaction.editReply("An unexpected error occurred while fetching the user."); } }
M src/interactions/commands/roblox/searchUsers.tssrc/interactions/commands/roblox/searchUsers.ts

@@ -11,16 +11,10 @@ const commandData = new SlashCommandBuilder()

.setName("search") .setDescription("Search for Roblox users") .addStringOption((option) => - option - .setName("query") - .setDescription("The query to search for") - .setRequired(true), + option.setName("query").setDescription("The query to search for").setRequired(true), ); -async function execute( - _client: Client, - interaction: ChatInputCommandInteraction, -) { +async function execute(_client: Client, interaction: ChatInputCommandInteraction) { await interaction.deferReply(); const query = interaction.options.getString("query", true);

@@ -45,9 +39,7 @@ "*",

user.displayName, `[@${user.name}](https://www.roblox.com/users/${user.id}/profile)`, `(${user.id})`, - user.previousUsernames.length - ? `(${user.previousUsernames.join(", ")})` - : "", + user.previousUsernames.length ? `(${user.previousUsernames.join(", ")})` : "", ].join(" "), ) .join("\n");
M src/interactions/commands/stats.tssrc/interactions/commands/stats.ts

@@ -1,9 +1,5 @@

import { db, tickets } from "@/database"; -import { - type ChatInputCommandInteraction, - type Client, - SlashCommandBuilder, -} from "discord.js"; +import { type ChatInputCommandInteraction, type Client, SlashCommandBuilder } from "discord.js"; import { and, eq, gte, isNotNull, ne } from "drizzle-orm"; const commandData = new SlashCommandBuilder()

@@ -63,22 +59,16 @@ const mean = sum / durations.length;

const sorted = [...durations].sort((a, b) => a - b); const mid = Math.floor(sorted.length / 2); - const median = - sorted.length % 2 !== 0 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2; + const median = sorted.length % 2 !== 0 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2; return { mean, median, count: durations.length }; } -async function execute( - client: Client, - interaction: ChatInputCommandInteraction, -) { +async function execute(client: Client, interaction: ChatInputCommandInteraction) { await interaction.deferReply({}); const days = interaction.options.getInteger("days"); - const cutoffDate = days - ? new Date(Date.now() - days * 24 * 60 * 60 * 1000) - : null; + const cutoffDate = days ? new Date(Date.now() - days * 24 * 60 * 60 * 1000) : null; const closedTickets = await db .select()

@@ -89,9 +79,7 @@ isNotNull(tickets.closedAt),

isNotNull(tickets.closedBy), ne(tickets.closedBy, "reporter"), ne(tickets.closedBy, "system"), - interaction.guildId - ? eq(tickets.guildId, interaction.guildId) - : undefined, + interaction.guildId ? eq(tickets.guildId, interaction.guildId) : undefined, cutoffDate ? gte(tickets.closedAt, cutoffDate) : undefined, ), );

@@ -99,9 +87,7 @@

const timeFrameStr = days ? `(Last ${days} Days)` : "(All Time)"; if (closedTickets.length === 0) { - return interaction.editReply( - `No closed tickets found for statistics ${timeFrameStr}.`, - ); + return interaction.editReply(`No closed tickets found for statistics ${timeFrameStr}.`); } const sub = interaction.options.getSubcommand();

@@ -196,12 +182,10 @@ // biome-ignore lint/style/noNonNullAssertion: .

?.push(t.closedAt!.getTime() - t.createdAt.getTime()); } - const modStats = Array.from(modDurations.entries()).map( - ([modId, durations]) => { - const stats = getStats(durations); - return { modId, ...stats }; - }, - ); + const modStats = Array.from(modDurations.entries()).map(([modId, durations]) => { + const stats = getStats(durations); + return { modId, ...stats }; + }); const orderBy = interaction.options.getString("order_by") || "median";

@@ -230,15 +214,9 @@

const widths = { rank: Math.max(4, ...rowsData.map((r) => r.rank.length)), user: Math.max(8, ...rowsData.map((r) => r.username.length)), - count: Math.max( - countTitle.length, - ...rowsData.map((r) => r.count.length), - ), + count: Math.max(countTitle.length, ...rowsData.map((r) => r.count.length)), mean: Math.max(meanTitle.length, ...rowsData.map((r) => r.mean.length)), - median: Math.max( - medianTitle.length, - ...rowsData.map((r) => r.median.length), - ), + median: Math.max(medianTitle.length, ...rowsData.map((r) => r.median.length)), }; const header = [
M src/interactions/commands/ticket-manage.tssrc/interactions/commands/ticket-manage.ts

@@ -36,27 +36,19 @@ subcommand

.setName("prompt") .setDescription("Send the prompt to the designated channel") .addChannelOption((c) => - c - .setName("channel") - .setDescription("The channel to send the prompt in") - .setRequired(true), + c.setName("channel").setDescription("The channel to send the prompt in").setRequired(true), ), ) .addSubcommand((subcommand) => subcommand .setName("message") - .setDescription( - "Edit the saved ticket message (shown when a ticket is created)", - ), + .setDescription("Edit the saved ticket message (shown when a ticket is created)"), ); const MODAL_ID = makeComponentId(commandData, "message"); const INPUT_ID = "message_content"; -async function execute( - _client: Client, - interaction: ChatInputCommandInteraction, -) { +async function execute(_client: Client, interaction: ChatInputCommandInteraction) { if (!interaction.guild || !interaction.member) { await interaction.reply({ content: "❌ This command can only be used in a server.",

@@ -65,9 +57,7 @@ });

return; } - const hasPerms = await hasManagerPermissions( - interaction.member as GuildMember, - ); + const hasPerms = await hasManagerPermissions(interaction.member as GuildMember); if (!hasPerms) { await interaction.reply({ content: "❌ You don't have permission to use this command.",

@@ -83,9 +73,7 @@ const targetChannel = interaction.options.getChannel("channel", true);

const textInput = new LabelBuilder() .setLabel("Message Content") - .setDescription( - "This message will be followed by a button to create a new ticket.", - ) + .setDescription("This message will be followed by a button to create a new ticket.") .setTextInputComponent( new TextInputBuilder() .setCustomId(INPUT_ID)

@@ -103,15 +91,11 @@ return;

} if (sub === "message") { - const { data: currentMessage } = await getTicketMessage( - interaction.guild.id, - ); + const { data: currentMessage } = await getTicketMessage(interaction.guild.id); const textInput = new LabelBuilder() .setLabel("Message Content") - .setDescription( - "This message will be shown to users when they create a ticket.", - ) + .setDescription("This message will be shown to users when they create a ticket.") .setTextInputComponent( new TextInputBuilder() .setCustomId(INPUT_ID)

@@ -130,10 +114,7 @@ return;

} } -async function modalExecute( - _client: Client, - interaction: ModalSubmitInteraction, -) { +async function modalExecute(_client: Client, interaction: ModalSubmitInteraction) { await interaction.deferReply({ flags: ["Ephemeral"] }); if (!interaction.channelId || !interaction.guild || !interaction.guildId) { await interaction.editReply({
M src/interactions/commands/tickets/_shared.tssrc/interactions/commands/tickets/_shared.ts

@@ -32,9 +32,7 @@ } as const;

// -- modals --------------------------------------------------------------------------------------- export function getTicketReasonModal(staff = false) { - const modal = new ModalBuilder() - .setCustomId(MODAL_IDS.reason) - .setTitle("Close Ticket"); + const modal = new ModalBuilder().setCustomId(MODAL_IDS.reason).setTitle("Close Ticket"); const pubReason = new LabelBuilder() .setLabel("Public Reason")

@@ -54,9 +52,7 @@ );

const privateReason = new LabelBuilder() .setLabel("Private Reason") - .setDescription( - "Provide a reason for closing the ticket - this will only be visible to staff", - ) + .setDescription("Provide a reason for closing the ticket - this will only be visible to staff") .setTextInputComponent( new TextInputBuilder() .setCustomId(INPUT_IDS.PRIVATE_REASON)

@@ -69,9 +65,7 @@

const deleteGroup = new LabelBuilder() .setLabel("Immediately delete channel") .setCheckboxComponent( - new CheckboxBuilder() - .setCustomId("ticket:delete_checkbox") - .setDefault(false), + new CheckboxBuilder().setCustomId("ticket:delete_checkbox").setDefault(false), ); modal.addLabelComponents(pubReason);

@@ -122,12 +116,8 @@ );

} const wasBehalfTicket = ticket.openedBy !== ticket.authorId; - const reasonText = ticket.topic - ? `for reason: ${ticket.topic}` - : "without a provided reason"; - const behalfText = wasBehalfTicket - ? `**Opened By**: <@${ticket.openedBy}> ${reasonText}` - : null; + const reasonText = ticket.topic ? `for reason: ${ticket.topic}` : "without a provided reason"; + const behalfText = wasBehalfTicket ? `**Opened By**: <@${ticket.openedBy}> ${reasonText}` : null; const container = new ContainerBuilder() .addTextDisplayComponents(

@@ -150,9 +140,7 @@ .filter(Boolean)

.join("\n"), ), ) - .addSeparatorComponents( - new SeparatorBuilder().setDivider(false).setSpacing(2), - ) + .addSeparatorComponents(new SeparatorBuilder().setDivider(false).setSpacing(2)) .addTextDisplayComponents( text( [

@@ -187,12 +175,7 @@ )

.join(", "); return { - container: constructTicketContainer( - ticket, - attachmentsString, - context, - isPublic, - ), + container: constructTicketContainer(ticket, attachmentsString, context, isPublic), transcriptText, attachments, files: [file],
M src/interactions/commands/tickets/gdpr.tssrc/interactions/commands/tickets/gdpr.ts

@@ -24,17 +24,13 @@ async function buildListContainerForUser(userId: string, page = 1) {

const ticketsRes = await db .select() .from(tickets) - .where( - or(eq(tickets.authorId, userId), like(tickets.addedUsers, `%${userId}%`)), - ); + .where(or(eq(tickets.authorId, userId), like(tickets.addedUsers, `%${userId}%`))); if (!ticketsRes || ticketsRes.length === 0) { const empty = new ContainerBuilder() .setAccentColor(0xff5a00) .addTextDisplayComponents( - new TextDisplayBuilder().setContent( - "## Your Tickets\n\nYou have no tickets.", - ), + new TextDisplayBuilder().setContent("## Your Tickets\n\nYou have no tickets."), ); return { container: empty, totalPages: 0, page: 1, total: 0 }; }

@@ -81,9 +77,7 @@ .setAccentColor(0xff5a00)

.addTextDisplayComponents( new TextDisplayBuilder().setContent(`${header}${ticketLines.join("\n")}`), ) - .addSeparatorComponents( - new SeparatorBuilder().setDivider(false).setSpacing(1), - ); + .addSeparatorComponents(new SeparatorBuilder().setDivider(false).setSpacing(1)); const controls = new ActionRowBuilder<ButtonBuilder>().addComponents( new ButtonBuilder()

@@ -110,10 +104,7 @@

return { container, totalPages, page: currentPage, total }; } -export async function handleListPagination( - _client: Client, - interaction: ButtonInteraction, -) { +export async function handleListPagination(_client: Client, interaction: ButtonInteraction) { const parts = interaction.customId.split(":"); const pagePart = parts[3]; const page = pagePart ? Number.parseInt(pagePart, 10) : 1;

@@ -128,10 +119,7 @@ } catch {}

return; } - const { container } = await buildListContainerForUser( - interaction.user.id, - page, - ); + const { container } = await buildListContainerForUser(interaction.user.id, page); try { await interaction.update({ components: [container] });

@@ -146,10 +134,7 @@ logger.error(err, "failed to update ticket list pagination");

} } -export async function handleList( - _client: Client, - interaction: ChatInputCommandInteraction, -) { +export async function handleList(_client: Client, interaction: ChatInputCommandInteraction) { if (!interaction.guild) { await interaction.reply({ content: "❌ This command can only be used in a server.",

@@ -166,10 +151,7 @@ flags: ["IsComponentsV2", "Ephemeral"],

}); } -export async function handleViewTicket( - _client: Client, - interaction: ChatInputCommandInteraction, -) { +export async function handleViewTicket(_client: Client, interaction: ChatInputCommandInteraction) { await interaction.deferReply(); if (!interaction.guild) { await interaction.editReply({

@@ -180,10 +162,7 @@ }

const ticketId = interaction.options.getInteger("ticket_id", true); - const { data: ticket, exists } = await getTicketByNumericId( - interaction.guild.id, - ticketId, - ); + const { data: ticket, exists } = await getTicketByNumericId(interaction.guild.id, ticketId); if (!exists || !ticket) { await interaction.editReply({ content: `❌ Ticket with ID ${ticketId} not found.`,

@@ -191,12 +170,9 @@ });

return; } - const isStaff = await hasManagerPermissions( - interaction.member as GuildMember, - ); + const isStaff = await hasManagerPermissions(interaction.member as GuildMember); const isAuthor = - ticket.authorId === interaction.user.id || - ticket.addedUsers?.includes(interaction.user.id); + ticket.authorId === interaction.user.id || ticket.addedUsers?.includes(interaction.user.id); if (!isStaff && !isAuthor) { await interaction.editReply({

@@ -205,11 +181,7 @@ });

return; } - const { container, files } = await getTicketContainer( - ticket, - "view", - !isStaff, - ); + const { container, files } = await getTicketContainer(ticket, "view", !isStaff); await interaction.editReply({ components: [container],

@@ -218,10 +190,7 @@ flags: ["IsComponentsV2"],

}); } -export async function handleExport( - _client: Client, - interaction: ChatInputCommandInteraction, -) { +export async function handleExport(_client: Client, interaction: ChatInputCommandInteraction) { const _tickets = await db .select() .from(tickets)
M src/interactions/commands/tickets/index.tssrc/interactions/commands/tickets/index.ts

@@ -24,12 +24,7 @@ handleThank,

handleTranscript, handleUnclaim, } from "./actions"; -import { - handleExport, - handleList, - handleListPagination, - handleViewTicket, -} from "./gdpr"; +import { handleExport, handleList, handleListPagination, handleViewTicket } from "./gdpr"; import { handleReasonModal } from "./modals"; import { hasManagerPermissions } from "@/utils/discord/permissions";

@@ -38,9 +33,7 @@ .setName("ticket")

.setDescription("Manage and create new tickets") // create .addSubcommand( - new SlashCommandSubcommandBuilder() - .setName("create") - .setDescription("Create a new ticket"), + new SlashCommandSubcommandBuilder().setName("create").setDescription("Create a new ticket"), ) // create-for .addSubcommand(

@@ -66,10 +59,7 @@ new SlashCommandSubcommandBuilder()

.setName("add") .setDescription("Add another user to the ticket") .addUserOption((option) => - option - .setName("user") - .setDescription("The user to add") - .setRequired(true), + option.setName("user").setDescription("The user to add").setRequired(true), ), ) // claim

@@ -98,9 +88,7 @@ )

.addStringOption((option) => option .setName("private_reason") - .setDescription( - "Private reason for closing the ticket, shown only to staff", - ) + .setDescription("Private reason for closing the ticket, shown only to staff") .setRequired(false), ), )

@@ -120,9 +108,7 @@ // transcript

.addSubcommand( new SlashCommandSubcommandBuilder() .setName("transcript") - .setDescription( - "Get the transcript of the ticket in the current channel", - ), + .setDescription("Get the transcript of the ticket in the current channel"), ) // list .addSubcommand(

@@ -146,15 +132,10 @@ // export

.addSubcommand( new SlashCommandSubcommandBuilder() .setName("export") - .setDescription( - "Export all of your ticket data in a machine readable format", - ), + .setDescription("Export all of your ticket data in a machine readable format"), ); -async function execute( - client: Client, - interaction: ChatInputCommandInteraction, -) { +async function execute(client: Client, interaction: ChatInputCommandInteraction) { const action = interaction.options.getSubcommand(); const actions = {

@@ -178,10 +159,7 @@ return;

} const { data: guild } = await getGuild(interaction.guildId); - const { data: ticket } = await getTicket( - interaction.guildId, - interaction.channelId, - ); + const { data: ticket } = await getTicket(interaction.guildId, interaction.channelId); if (!ticket) { await interaction.reply({

@@ -205,8 +183,7 @@ }

} const publicReason = interaction.options.getString("reason") ?? undefined; - const privateReason = - interaction.options.getString("private_reason") ?? undefined; + const privateReason = interaction.options.getString("private_reason") ?? undefined; closeLock.set(ticket.id, { expiresAt: Date.now() + thirtySeconds,

@@ -233,23 +210,19 @@ publicReason,

privateReason, }); return; - } + } - const isStaff = await hasManagerPermissions(interaction.member as GuildMember) - return await interaction.showModal( - getTicketReasonModal(isStaff), - ); + const isStaff = await hasManagerPermissions(interaction.member as GuildMember); + return await interaction.showModal(getTicketReasonModal(isStaff)); } await interaction.deferReply({ flags: ["Ephemeral"] }); if (action === "reopen") await handleReopen(client, interaction, ticket); else if (action === "delete") await handleDelete(client, interaction, ticket); - else if (action === "transcript") - await handleTranscript(client, interaction, ticket); + else if (action === "transcript") await handleTranscript(client, interaction, ticket); else if (action === "add") await handleAddUser(client, interaction, ticket); else if (action === "claim") await handleClaim(client, interaction, ticket); - else if (action === "unclaim") - await handleUnclaim(client, interaction, ticket); + else if (action === "unclaim") await handleUnclaim(client, interaction, ticket); else await interaction.editReply("❌ Invalid or unhandled action."); }

@@ -277,10 +250,7 @@ await handleCreate(client, interaction);

return; } - const { data: ticket } = await getTicket( - interaction.guildId, - interaction.channelId, - ); + const { data: ticket } = await getTicket(interaction.guildId, interaction.channelId); if (!ticket) { await interaction.reply({

@@ -290,27 +260,20 @@ return;

} if (action === "close") { - const isStaff = await hasManagerPermissions(interaction.member as GuildMember) - return await interaction.showModal( - getTicketReasonModal(isStaff), - ); - } + const isStaff = await hasManagerPermissions(interaction.member as GuildMember); + return await interaction.showModal(getTicketReasonModal(isStaff)); + } await interaction.deferReply({ flags: ["Ephemeral"] }); if (action === "reopen") await handleReopen(client, interaction, ticket); else if (action === "delete") await handleDelete(client, interaction, ticket); - else if (action === "transcript") - await handleTranscript(client, interaction, ticket); + else if (action === "transcript") await handleTranscript(client, interaction, ticket); else if (action === "claim") await handleClaim(client, interaction, ticket); - else if (action === "unclaim") - await handleUnclaim(client, interaction, ticket); + else if (action === "unclaim") await handleUnclaim(client, interaction, ticket); else await interaction.editReply("❌ Invalid or unhandled action."); } -async function modalExecute( - client: Client, - interaction: ModalSubmitInteraction, -) { +async function modalExecute(client: Client, interaction: ModalSubmitInteraction) { const components = parseComponentId(interaction.customId); const action = components.parts[0];
M src/interactions/commands/tickets/modals.tssrc/interactions/commands/tickets/modals.ts

@@ -6,10 +6,7 @@ import { handleClose } from "./actions";

const logger = loggers.interactions.child({ name: "ticket/modals" }); -export async function handleReasonModal( - _client: Client, - interaction: ModalSubmitInteraction, -) { +export async function handleReasonModal(_client: Client, interaction: ModalSubmitInteraction) { await interaction.deferReply({ flags: ["Ephemeral"] }); if (!interaction.channelId || !interaction.guildId) {

@@ -22,19 +19,12 @@

const publicReason = interaction.fields.getTextInputValue(INPUT_IDS.REASON); let privateReason = ""; try { - privateReason = interaction.fields.getTextInputValue( - INPUT_IDS.PRIVATE_REASON, - ); + privateReason = interaction.fields.getTextInputValue(INPUT_IDS.PRIVATE_REASON); } catch {} - const deleteChannel = interaction.fields.getCheckbox( - "ticket:delete_checkbox", - ); + const deleteChannel = interaction.fields.getCheckbox("ticket:delete_checkbox"); - const { data: ticket, exists } = await getTicket( - interaction.guildId, - interaction.channelId, - ); + const { data: ticket, exists } = await getTicket(interaction.guildId, interaction.channelId); if (!exists || !ticket) { await interaction.editReply({ content: "❌ This channel is not a valid ticket.",
M src/interactions/commands/uwuify.tssrc/interactions/commands/uwuify.ts

@@ -1,35 +1,20 @@

-import { - type ChatInputCommandInteraction, - type Client, - SlashCommandBuilder, -} from "discord.js"; +import { type ChatInputCommandInteraction, type Client, SlashCommandBuilder } from "discord.js"; import Uwuifier from "uwuifier"; const commandData = new SlashCommandBuilder() .setName("uwuify") .setDescription("ok") .addStringOption((option) => - option - .setName("text") - .setDescription("The text to uwuify") - .setRequired(true), + option.setName("text").setDescription("The text to uwuify").setRequired(true), ); -async function execute( - _client: Client, - interaction: ChatInputCommandInteraction, -) { +async function execute(_client: Client, interaction: ChatInputCommandInteraction) { const uwuifier = new Uwuifier(); const text = interaction.options.getString("text", true); const uwuifiedText = uwuifier.uwuifySentence(text); - const blacklistedWords = [ - "twerks", - "sees bulge", - "notices buldge", - "starts twerking", - ]; + const blacklistedWords = ["twerks", "sees bulge", "notices buldge", "starts twerking"]; const finalText = blacklistedWords.reduce((acc, word) => { return acc.replace(new RegExp(word, "gi"), "----");
M src/interactions/commands/uwuifyProxy.tssrc/interactions/commands/uwuifyProxy.ts

@@ -1,19 +1,12 @@

import { db, userPreferences } from "@/database"; -import { - type ChatInputCommandInteraction, - type Client, - SlashCommandBuilder, -} from "discord.js"; +import { type ChatInputCommandInteraction, type Client, SlashCommandBuilder } from "discord.js"; import { eq } from "drizzle-orm"; const commandData = new SlashCommandBuilder() .setName("uwuify-toggle") .setDescription("toggle automatic uwuification of your messages"); -async function execute( - _client: Client, - interaction: ChatInputCommandInteraction, -) { +async function execute(_client: Client, interaction: ChatInputCommandInteraction) { const userId = interaction.user.id; const existing = db
M src/interactions/menus/getUser.tssrc/interactions/menus/getUser.ts

@@ -14,13 +14,8 @@ const commandData = new ContextMenuCommandBuilder()

.setName("Get Roblox Account") .setType(ApplicationCommandType.User); -async function execute( - _client: Client, - interaction: MessageContextMenuCommandInteraction, -) { - const isModerator = await hasManagerPermissions( - interaction.member as GuildMember, - ); +async function execute(_client: Client, interaction: MessageContextMenuCommandInteraction) { + const isModerator = await hasManagerPermissions(interaction.member as GuildMember); await interaction.deferReply(); const target = interaction.targetId;

@@ -29,9 +24,7 @@

if (linkedErr) { const message = linkedErr.error; if (message === "User not found") { - await interaction.editReply( - "No linked Roblox account found for that user.", - ); + await interaction.editReply("No linked Roblox account found for that user."); return; } await interaction.editReply(
M src/interactions/menus/highlight.tssrc/interactions/menus/highlight.ts

@@ -42,8 +42,7 @@ }

try { const url = new URL(t); - if (!domains.some((d) => url.hostname.toLowerCase().includes(d))) - continue; + if (!domains.some((d) => url.hostname.toLowerCase().includes(d))) continue; const normalized = url.href.replace(/\/$/, ""); found.add(normalized);

@@ -54,16 +53,10 @@ return Array.from(found);

} function isVideoAttachment(attachment: Attachment): boolean { - return ( - typeof attachment.contentType === "string" && - attachment.contentType.startsWith("video/") - ); + return typeof attachment.contentType === "string" && attachment.contentType.startsWith("video/"); } -async function execute( - client: Client, - interaction: MessageContextMenuCommandInteraction, -) { +async function execute(client: Client, interaction: MessageContextMenuCommandInteraction) { if (!interaction.guild) { await interaction.reply({ content: "❌ This command can only be used in a server.",

@@ -83,8 +76,7 @@ }

if (!guildConfig.highlights_channel_id) { await interaction.editReply({ - content: - "❌ No highlights channel configured. Use `/config highlight-channel`.", + content: "❌ No highlights channel configured. Use `/config highlight-channel`.", }); return; }

@@ -102,8 +94,7 @@ const videoLinks = extractVideoLinks(targetMessage);

if (videoAttachments.size === 0 && videoLinks.length === 0) { await interaction.editReply({ - content: - "❌ No video attachments or supported links found in this message.", + content: "❌ No video attachments or supported links found in this message.", }); return; }

@@ -133,9 +124,7 @@ const jumpUrl = targetMessage.url;

if (videoLinks.length === 0) videoLinks.push(...files); - const videoLinksText = videoLinks - .map((link) => `• [Video Link](${link})`) - .join(" "); + const videoLinksText = videoLinks.map((link) => `• [Video Link](${link})`).join(" "); const description = `:star: New highlight from ${author}!\n-# [Jump to message](${jumpUrl}) ${videoLinksText}`; try {
M src/roblox/client.tssrc/roblox/client.ts

@@ -109,9 +109,7 @@

const body = await res.json(); if (!res.ok || isApiError(body)) { - const err: ApiError = isApiError(body) - ? body - : errorFromStatus(res.status, res.statusText); + const err: ApiError = isApiError(body) ? body : errorFromStatus(res.status, res.statusText); return [null, err]; }

@@ -132,9 +130,7 @@ let pages = 0;

const MAX_PAGES = 50; while (pages < MAX_PAGES) { - const filter = encodeURIComponent( - `place == '' && user == 'users/${userId}'`, - ); + const filter = encodeURIComponent(`place == '' && user == 'users/${userId}'`); const path = `/user/cloud/v2/universes/${universeId}/user-restrictions:listLogs?filter=${filter}&pageToken=${pageToken}`; const [data, err] = await this.request<UserRestrictionLogsResponse>(path);

@@ -159,9 +155,7 @@

return [data, null]; } - async getUsersByUsernames( - usernames: string[], - ): Promise<Result<GetUsersByUsernamesResponse>> { + async getUsersByUsernames(usernames: string[]): Promise<Result<GetUsersByUsernamesResponse>> { const payload: GetUsersByUsernamesPayload = { usernames, excludeBannedUsers: false,

@@ -212,14 +206,11 @@ return [data, null];

} async getLinkedAccount(discordId: string): Promise<BloxlinkResult> { - const response = await fetch( - `https://api.blox.link/v4/public/discord-to-roblox/${discordId}`, - { - headers: { - Authorization: config.roblox.bloxlinkToken, - }, + const response = await fetch(`https://api.blox.link/v4/public/discord-to-roblox/${discordId}`, { + headers: { + Authorization: config.roblox.bloxlinkToken, }, - ); + }); const data = await response.json();

@@ -229,7 +220,4 @@ return [data, null];

} } -export const roblox = new RobloxClient( - config.roblox.cookie, - config.roblox.apiKey, -); +export const roblox = new RobloxClient(config.roblox.cookie, config.roblox.apiKey);
M src/roblox/profile.tssrc/roblox/profile.ts

@@ -1,10 +1,6 @@

import config, { type Project } from "@/config"; import { roblox } from "@/roblox/client"; -import type { - GetUserResponse, - RobloxUserId, - UserRestrictionLog, -} from "@/roblox/types"; +import type { GetUserResponse, RobloxUserId, UserRestrictionLog } from "@/roblox/types"; import { ActionRowBuilder, ButtonBuilder,

@@ -101,9 +97,7 @@ // ---- moderators -------------------------------------------------------------

const ModeratorCache = new Map<RobloxUserId, string>(); export async function moderatorMention( - moderator: - | { robloxUser: `users/${RobloxUserId}` } - | { gameServerScript: unknown }, + moderator: { robloxUser: `users/${RobloxUserId}` } | { gameServerScript: unknown }, ) { if ("gameServerScript" in moderator) { return "Banned in-game";

@@ -146,8 +140,7 @@ const now = Date.now();

return logs.map((log) => { const startMs = new Date(log.startTime).getTime(); const durationMs = durationToMs(log.duration ?? undefined); - const endMs = - durationMs == null ? Number.POSITIVE_INFINITY : startMs + durationMs; + const endMs = durationMs == null ? Number.POSITIVE_INFINITY : startMs + durationMs; const nowActive = now < endMs; return { ...(log as UserRestrictionLog),

@@ -155,9 +148,7 @@ startMs,

endMs, nowActive, ...(log.universeId ? { universeId: log.universeId } : {}), - project: Object.values(config.projects).find( - (p) => p.universe === log.universeId, - ), + project: Object.values(config.projects).find((p) => p.universe === log.universeId), }; }); }

@@ -187,37 +178,26 @@ startDate: new Date(log.createTime),

}); const endString = - endAbsolute === "permanent" - ? undefined - : `> **Ends:** ${endAbsolute} (${endRelative})`; + endAbsolute === "permanent" ? undefined : `> **Ends:** ${endAbsolute} (${endRelative})`; const lines = [ includeProjectLabel ? `**${includeProjectLabel}**` : undefined, `> Banned **${bannedFor}**, ${startRel}, by **${moderator}**`, `> **Reason:** ${reason}`, - showPrivate - ? `> **Private Reason:** ${log.privateReason || "no private reason"}` - : undefined, + showPrivate ? `> **Private Reason:** ${log.privateReason || "no private reason"}` : undefined, endString, ].filter(Boolean); return lines.join("\n"); } -function buildLogsContainer( - headerTitle: string, - lines: string[], - shown: number, - total: number, -) { +function buildLogsContainer(headerTitle: string, lines: string[], shown: number, total: number) { const header = `### ${headerTitle} - showing ${shown} of ${total}`; const container = new ContainerBuilder() .addTextDisplayComponents( new TextDisplayBuilder().setContent(`${header}\n\n${lines.join("\n\n")}`), ) - .addSeparatorComponents( - new SeparatorBuilder().setDivider(false).setSpacing(1), - ); + .addSeparatorComponents(new SeparatorBuilder().setDivider(false).setSpacing(1)); return container; }

@@ -230,9 +210,7 @@ const showPrivate = Boolean(opts.showPrivate);

if (!bans || bans.length === 0) { const c = new ContainerBuilder().addTextDisplayComponents( - new TextDisplayBuilder().setContent( - "### Bans\n-# No restriction logs found", - ), + new TextDisplayBuilder().setContent("### Bans\n-# No restriction logs found"), ); return { container: c, total: 0 }; }

@@ -241,16 +219,9 @@ const enriched = enrichLogs(bans);

const sorted = enriched.sort((a, b) => b.startMs - a.startMs); const shown = sorted.slice(0, limit); - const lines = await Promise.all( - shown.map((l) => formatRestrictionLog(l, { showPrivate })), - ); + const lines = await Promise.all(shown.map((l) => formatRestrictionLog(l, { showPrivate }))); - const container = buildLogsContainer( - "Bans", - lines, - shown.length, - bans.length, - ); + const container = buildLogsContainer("Bans", lines, shown.length, bans.length); return { container, total: bans.length }; }

@@ -268,9 +239,7 @@ (log) =>

({ ...log, universeId, - project: Object.values(config.projects).find( - (p) => p.universe === universeId, - ), + project: Object.values(config.projects).find((p) => p.universe === universeId), }) as EnrichedLog, ); }),

@@ -305,10 +274,7 @@ return { container: c, total: 0 };

} const lastBans = allLogs - .sort( - (a, b) => - new Date(b.createTime).getTime() - new Date(a.createTime).getTime(), - ) + .sort((a, b) => new Date(b.createTime).getTime() - new Date(a.createTime).getTime()) .slice(0, 3); const projectForUniverse = (universeId: string) =>

@@ -320,19 +286,13 @@ const lines = await Promise.all(

enriched.map((log) => formatRestrictionLog(log, { showPrivate: opts.showPrivate, - includeProjectLabel: - projectForUniverse(log.universeId || "")?.displayName || null, + includeProjectLabel: projectForUniverse(log.universeId || "")?.displayName || null, includeStatus: true, }), ), ); - const container = buildLogsContainer( - "Recent Bans", - lines, - lines.length, - allLogs.length, - ); + const container = buildLogsContainer("Recent Bans", lines, lines.length, allLogs.length); return { container, total: allLogs.length }; }

@@ -347,10 +307,7 @@ originCommand?: string;

}, ) { const lastBans = extras?.bans - ?.sort( - (a, b) => - new Date(b.createTime).getTime() - new Date(a.createTime).getTime(), - ) + ?.sort((a, b) => new Date(b.createTime).getTime() - new Date(a.createTime).getTime()) .slice(0, 3); const banSummary =

@@ -371,9 +328,7 @@ `@${profile.name} - ${profile.id} - created ${createdAtString}`,

].join("\n"), ); const aboutText = text( - ["### About", profile.about ? profile.about : "-# No bio provided"].join( - "\n", - ), + ["### About", profile.about ? profile.about : "-# No bio provided"].join("\n"), ); const banText = text([`-# ${banSummary}`].join("\n"));

@@ -397,10 +352,7 @@ .setStyle(ButtonStyle.Primary)

.setCustomId(`ban-history:summary:${profile.id}`); mainContainer.addActionRowComponents( - new ActionRowBuilder<ButtonBuilder>().addComponents( - profileButton, - bansButton, - ), + new ActionRowBuilder<ButtonBuilder>().addComponents(profileButton, bansButton), ); return { mainContainer, buttons: [profileButton] };
M src/roblox/robloxUser.tssrc/roblox/robloxUser.ts

@@ -1,19 +1,10 @@

import { isApiErrorV2, roblox } from "@/roblox/client"; -import { - constructBansSummaryContainer, - constructUserContainer, - getBans, -} from "@/roblox/profile"; +import { constructUserContainer, getBans } from "@/roblox/profile"; import type { RobloxUserId } from "@/roblox/types"; -import type { - ChatInputCommandInteraction, - MessageContextMenuCommandInteraction, -} from "discord.js"; +import type { ChatInputCommandInteraction, MessageContextMenuCommandInteraction } from "discord.js"; export async function processRobloxUserInteraction( - interaction: - | ChatInputCommandInteraction - | MessageContextMenuCommandInteraction, + interaction: ChatInputCommandInteraction | MessageContextMenuCommandInteraction, id: RobloxUserId, isModerator: boolean, ) {

@@ -22,9 +13,7 @@ await interaction.editReply(`Fetching user with ID ${id}...`);

const [userRes, userErr] = await roblox.getUser(id); if (userErr) { if (isApiErrorV2(userErr)) { - await interaction.editReply( - `There was an error fetching the user: ${userErr.message}`, - ); + await interaction.editReply(`There was an error fetching the user: ${userErr.message}`); } else { await interaction.editReply("There was an error fetching the user."); }

@@ -32,9 +21,7 @@ return;

} const user = userRes; - await interaction.editReply( - `Found user with username ${user.name}, fetching thumbnail...`, - ); + await interaction.editReply(`Found user with username ${user.name}, fetching thumbnail...`); const [thumbnailRes] = await roblox.getThumbnail(id, { shape: "SQUARE" }); const thumbnailUri = thumbnailRes ? thumbnailRes.response?.imageUri : null;

@@ -46,8 +33,7 @@ "<:wawa:1158423817698430977>",

"<:max:1476776753845370991>", "<:snickerdoodle:1477173429575749716>", ]; - const message = - randomMessages[Math.floor(Math.random() * randomMessages.length)]; + const message = randomMessages[Math.floor(Math.random() * randomMessages.length)]; await interaction.editReply(message); const bans = await getBans(id);

@@ -66,8 +52,6 @@ components: [mainContainer],

}); } catch (err) { console.error(err); - await interaction.editReply( - "An unexpected error occurred while fetching the user.", - ); + await interaction.editReply("An unexpected error occurred while fetching the user."); } }
M src/roblox/types/index.tssrc/roblox/types/index.ts

@@ -88,12 +88,7 @@ traceId?: string;

}; } -export type ApiError = - | ApiErrorV2 - | ApiErrorV1 - | ApiErrorV1Alt - | GatewayError - | ApiValidationError; +export type ApiError = ApiErrorV2 | ApiErrorV1 | ApiErrorV1Alt | GatewayError | ApiValidationError; export type Result<T> = [T, null] | [null, ApiError];
M src/tasks/ticketWatcher.tssrc/tasks/ticketWatcher.ts

@@ -20,12 +20,10 @@ let running = false;

const run = async () => { if (running) { - logger.warn( - "previous ticket watcher run still in progress, skipping this tick", - ); + logger.warn("previous ticket watcher run still in progress, skipping this tick"); return; } - running = true; + running = true; try { const openTickets = await db

@@ -34,11 +32,11 @@ .from(tickets)

.where(eq(tickets.status, "open")) .execute(); - for (const ticket of openTickets) { + for (const ticket of openTickets) { try { if (ticket.claimedBy && ticket.claimedAt) { - const claimedAt = new Date(ticket.claimedAt).getTime(); - if (Date.now() - claimedAt > UNCLAIM_MS) { + const claimedAt = new Date(ticket.claimedAt).getTime(); + if (Date.now() - claimedAt > UNCLAIM_MS) { const [lastModMsg] = await db .select() .from(ticketMessages)

@@ -57,7 +55,7 @@ const lastModActivity = lastModMsg

? new Date(lastModMsg.createdAt).getTime() : claimedAt; - if (Date.now() - lastModActivity > UNCLAIM_MS) { + if (Date.now() - lastModActivity > UNCLAIM_MS) { const [lastUserMsg] = await db .select() .from(ticketMessages)

@@ -71,10 +69,7 @@ .orderBy(desc(ticketMessages.createdAt))

.limit(1) .execute(); - if ( - lastUserMsg && - new Date(lastUserMsg.createdAt).getTime() > lastModActivity - ) { + if (lastUserMsg && new Date(lastUserMsg.createdAt).getTime() > lastModActivity) { await db .update(tickets) .set({

@@ -86,13 +81,11 @@ .execute();

continue; } - } + } } } - const createdAt = ticket.createdAt - ? new Date(ticket.createdAt).getTime() - : null; + const createdAt = ticket.createdAt ? new Date(ticket.createdAt).getTime() : null; if (!createdAt) continue; const age = Date.now() - createdAt;

@@ -101,10 +94,7 @@ const userMsgs = await db

.select() .from(ticketMessages) .where( - and( - eq(ticketMessages.ticketId, ticket.id), - eq(ticketMessages.authorType, "user"), - ), + and(eq(ticketMessages.ticketId, ticket.id), eq(ticketMessages.authorType, "user")), ) .execute();

@@ -114,9 +104,7 @@

if (!ticket.warnedAt && age >= WARN_MS && age < CLOSE_MS) { if (ticket.channelId && ticket.guildId) { try { - const channel = await client.channels - .fetch(ticket.channelId) - .catch(() => null); + const channel = await client.channels.fetch(ticket.channelId).catch(() => null); if (channel?.isSendable()) { await channel.send( `<@${ticket.authorId}>, this ticket will be automatically archived in 15 minutes due to inactivity. Please send a message in this channel to keep it open.`,

@@ -151,21 +139,15 @@ .execute();

if (ticket.channelId && ticket.guildId) { try { - const channel = await client.channels - .fetch(ticket.channelId) - .catch(() => null); + const channel = await client.channels.fetch(ticket.channelId).catch(() => null); if (!channel) continue; - await channel.delete( - `Auto-archived due to inactivity for ticket ${ticket.id}`, - ); + await channel.delete(`Auto-archived due to inactivity for ticket ${ticket.id}`); const authorId = ticket.authorId; if (authorId) { - const user = await client.users - .fetch(authorId) - .catch(() => null); + const user = await client.users.fetch(authorId).catch(() => null); if (user) { await user .send(

@@ -175,9 +157,7 @@ .catch(() => null);

} } - const { data: guildData, exists: guildExists } = await getGuild( - ticket.guildId, - ); + const { data: guildData, exists: guildExists } = await getGuild(ticket.guildId); if (!guildExists) continue; const transcriptChannelId = guildData?.ticket_channel_id;

@@ -193,16 +173,11 @@ await transcriptChannel.send({

content: `Ticket #${ticket.id} has been archived due to inactivity.`, }); } catch (err) { - logger.error( - err, - `failed to delete channel for ticket ${ticket.id}`, - ); + logger.error(err, `failed to delete channel for ticket ${ticket.id}`); } } - logger.info( - `archived and deleted ticket ${ticket.id} due to inactivity`, - ); + logger.info(`archived and deleted ticket ${ticket.id} due to inactivity`); } } catch (errTicket) { logger.error(errTicket, `error processing ticket ${ticket.id}`);
M src/types.tssrc/types.ts

@@ -20,16 +20,7 @@ execute?: (client: Client, interaction: BaseInteraction) => Promise<void>;

enabled?: boolean; autocomplete?: (interaction: AutocompleteInteraction) => Promise<void>; - buttonExecute?: ( - client: Client, - interaction: ButtonInteraction, - ) => Promise<void>; - modalExecute?: ( - client: Client, - interaction: ModalSubmitInteraction, - ) => Promise<void>; - selectMenuExecute?: ( - client: Client, - interaction: StringSelectMenuInteraction, - ) => Promise<void>; + buttonExecute?: (client: Client, interaction: ButtonInteraction) => Promise<void>; + modalExecute?: (client: Client, interaction: ModalSubmitInteraction) => Promise<void>; + selectMenuExecute?: (client: Client, interaction: StringSelectMenuInteraction) => Promise<void>; }
M src/utils/discord/components.tssrc/utils/discord/components.ts

@@ -1,9 +1,6 @@

import { TextDisplayBuilder, ThumbnailBuilder } from "discord.js"; -export function makeComponentId( - cmd: unknown, - ...parts: Array<string | number> -): string { +export function makeComponentId(cmd: unknown, ...parts: Array<string | number>): string { const name = typeof cmd === "string" ? cmd
M src/utils/discord/permissions.tssrc/utils/discord/permissions.ts

@@ -1,14 +1,8 @@

import type { GuildMember } from "discord.js"; import { getGuild, getManagerRoleIds } from "../../database/queries"; -export async function hasManagerPermissions( - member: GuildMember, -): Promise<boolean> { - if ( - member.permissions.has("ManageGuild") || - member.guild.ownerId === member.id - ) - return true; +export async function hasManagerPermissions(member: GuildMember): Promise<boolean> { + if (member.permissions.has("ManageGuild") || member.guild.ownerId === member.id) return true; const guild = await getGuild(member.guild.id); const managers = await getManagerRoleIds(guild.data.guildId);
M src/utils/logging.tssrc/utils/logging.ts

@@ -21,7 +21,7 @@ export const loggers = {

events: logger.child({ name: "events" }), interactions: logger.child({ name: "interactions" }), config: logger.child({ name: "config" }), - automod: logger.child({ name: "automod" }) + automod: logger.child({ name: "automod" }), }; export default logger;
M src/utils/tickets/formatting.tssrc/utils/tickets/formatting.ts

@@ -5,8 +5,5 @@ const templates: Record<string, string> = {

"{user}": `<@${user}>`, }; - return Object.entries(templates).reduce( - (msg, [key, val]) => msg.split(key).join(val), - message, - ); + return Object.entries(templates).reduce((msg, [key, val]) => msg.split(key).join(val), message); }
M src/utils/tickets/transcripts.tssrc/utils/tickets/transcripts.ts

@@ -1,16 +1,8 @@

-import { - type Attachment, - type Ticket, - attachments, - db, - ticketMessages, -} from "@/database"; +import { type Attachment, type Ticket, attachments, db, ticketMessages } from "@/database"; import { getPublicUrl } from "@/utils/s3"; import { and, asc, eq } from "drizzle-orm"; -export async function generateTranscript( - ticket: Ticket, -): Promise<[string, Attachment[]]> { +export async function generateTranscript(ticket: Ticket): Promise<[string, Attachment[]]> { const messages = await db .select() .from(ticketMessages)

@@ -24,9 +16,7 @@ .select()

.from(attachments) .where(and(eq(attachments.ownerType, "ticket_message"))); - const relevantAttachments = ticketAttachments.filter((att) => - messageIds.includes(att.ownerId), - ); + const relevantAttachments = ticketAttachments.filter((att) => messageIds.includes(att.ownerId)); const attachmentMap = new Map<number, Attachment[]>(); for (const att of relevantAttachments) {
M src/utils/uwuify.tssrc/utils/uwuify.ts

@@ -1,20 +1,12 @@

import Uwuifier from "uwuifier"; export function uwuify(input: string) { - const uwuifier = new Uwuifier(); - const uwuifiedContent = input - ? uwuifier.uwuifySentence(input) - : ""; + const uwuifier = new Uwuifier(); + const uwuifiedContent = input ? uwuifier.uwuifySentence(input) : ""; - const blacklistedWords = [ - "twerks", - "sees bulge", - "notices buldge", - "starts twerking", - "wank", - ]; + const blacklistedWords = ["twerks", "sees bulge", "notices buldge", "starts twerking", "wank"]; return blacklistedWords.reduce((acc, word) => { return acc.replace(new RegExp(word, "gi"), "----"); - }, uwuifiedContent); + }, uwuifiedContent); }
M src/utils/woke.tssrc/utils/woke.ts

@@ -2,34 +2,33 @@ import { eq } from "drizzle-orm";

import { db, moderators } from "@/database"; type Moderator = { - id: string; - /** they */ - subjective: string; - /** them */ - objective: string; - /** their */ - possessiveDeterminer: string; - /** theirs */ - possessive: string; - /** themself */ - reflexive: string; -} + id: string; + /** they */ + subjective: string; + /** them */ + objective: string; + /** their */ + possessiveDeterminer: string; + /** theirs */ + possessive: string; + /** themself */ + reflexive: string; +}; - -const defaultModerator: Omit<Moderator, 'id'> = { - subjective: 'they', - objective: 'them', - possessiveDeterminer: 'their', - possessive: 'theirs', - reflexive: 'themself' -} +const defaultModerator: Omit<Moderator, "id"> = { + subjective: "they", + objective: "them", + possessiveDeterminer: "their", + possessive: "theirs", + reflexive: "themself", +}; export function getModerator(id: string): Moderator { - const moderator = db.select().from(moderators).where(eq(moderators.user_id, id)).get(); - if (!moderator) return { id, ...defaultModerator} - return { id: id, ...moderator }; + const moderator = db.select().from(moderators).where(eq(moderators.user_id, id)).get(); + if (!moderator) return { id, ...defaultModerator }; + return { id: id, ...moderator }; } export function capitalise(str: string): string { - return str.charAt(0).toUpperCase() + str.slice(1); + return str.charAt(0).toUpperCase() + str.slice(1); }
M tsconfig.jsontsconfig.json

@@ -1,32 +1,32 @@

{ - "compilerOptions": { - "baseUrl": ".", - "paths": { - "@/*": ["./src/*"] - }, + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + }, - // Enable latest features - "lib": ["ESNext", "DOM"], - "target": "ESNext", - "module": "ESNext", - "moduleDetection": "force", - "jsx": "react-jsx", - "allowJs": true, + // Enable latest features + "lib": ["ESNext", "DOM"], + "target": "ESNext", + "module": "ESNext", + "moduleDetection": "force", + "jsx": "react-jsx", + "allowJs": true, - // Bundler mode - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "noEmit": true, + // Bundler mode + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "noEmit": true, - // Best practices - "strict": true, - "skipLibCheck": true, - "noFallthroughCasesInSwitch": true, + // Best practices + "strict": true, + "skipLibCheck": true, + "noFallthroughCasesInSwitch": true, - // Some stricter flags (disabled by default) - "noUnusedLocals": false, - "noUnusedParameters": false, - "noPropertyAccessFromIndexSignature": false - } + // Some stricter flags (disabled by default) + "noUnusedLocals": false, + "noUnusedParameters": false, + "noPropertyAccessFromIndexSignature": false + } }