diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index d192c1b..5c9bd59 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -16,8 +16,6 @@ jobs: - uses: actions/checkout@v6 - name: Install pnpm uses: pnpm/action-setup@v6 - with: - version: 10 - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v6 with: @@ -26,12 +24,12 @@ jobs: - name: Install dependencies run: pnpm install --frozen-lockfile - name: Build - run: pnpm build + run: pnpm turbo build - name: Build production image run: docker build -t quest-bot:test . - name: Test production image run: > docker run --rm --entrypoint sh quest-bot:test -c "set -e; - test -f /app/dist/index.js; - node --check /app/dist/index.js" + test -f /app/apps/bot/dist/index.js; + node --check /app/apps/bot/dist/index.js" diff --git a/.gitignore b/.gitignore index 9c2d0a9..e93d74e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ node_modules generated dist .vscode +.turbo diff --git a/Dockerfile b/Dockerfile index a443ee0..6bb318a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,11 +5,12 @@ RUN corepack enable COPY package.json pnpm-lock.yaml ./ COPY pnpm-workspace.yaml ./ -COPY prisma ./prisma/ +COPY apps/bot/package.json ./apps/bot/package.json +COPY apps/bot/prisma ./apps/bot/prisma/ RUN pnpm install --frozen-lockfile COPY . . -RUN pnpm run build +RUN pnpm --filter @quest/bot build FROM node:24-alpine WORKDIR /app @@ -18,10 +19,11 @@ RUN corepack enable COPY package.json pnpm-lock.yaml ./ COPY pnpm-workspace.yaml ./ -COPY prisma.config.ts ./ -COPY prisma ./prisma/ -RUN pnpm install --prod --frozen-lockfile +COPY apps/bot/package.json ./apps/bot/package.json +COPY apps/bot/prisma.config.ts ./apps/bot/prisma.config.ts +COPY apps/bot/prisma ./apps/bot/prisma/ +RUN pnpm install --prod --frozen-lockfile --filter @quest/bot -COPY --from=builder /app/dist ./dist +COPY --from=builder /app/apps/bot/dist ./apps/bot/dist -CMD ["sh", "-c", "pnpm prisma db push && pnpm start"] +CMD ["sh", "-c", "pnpm --filter @quest/bot db:push && pnpm --filter @quest/bot start"] diff --git a/apps/bot/.gitignore b/apps/bot/.gitignore new file mode 100644 index 0000000..5c4983a --- /dev/null +++ b/apps/bot/.gitignore @@ -0,0 +1 @@ +.turbo \ No newline at end of file diff --git a/apps/bot/package.json b/apps/bot/package.json new file mode 100644 index 0000000..b8c7ef9 --- /dev/null +++ b/apps/bot/package.json @@ -0,0 +1,49 @@ +{ + "$schema": "https://json.schemastore.org/package.json", + "name": "@quest/bot", + "version": "0.1.0", + "private": true, + "type": "module", + "scripts": { + "build": "rimraf dist && prisma generate && tsc", + "lint": "prettier --check . && eslint --ext .ts --format=pretty src", + "format": "prettier --write . && eslint --ext .ts --fix --format=pretty src", + "predev": "pnpm build", + "start": "node --env-file-if-exists=../../.env dist/sharder.js", + "dev": "concurrently \"tsc --watch\" \"node --watch --env-file-if-exists=../../.env dist/index.js\"", + "db:push": "prisma db push", + "db:generate": "prisma generate" + }, + "dependencies": { + "@discordjs/core": "^2.3.0", + "@prisma/adapter-pg": "^7.7.0", + "@prisma/client": "^7.7.0", + "@sapphire/framework": "^5.5.0", + "@types/ms": "^2.1.0", + "discord.js": "^14.24.0", + "dotenv": "^17.4.2", + "ms": "^2.1.3", + "prisma": "^7.7.0", + "zod": "^4.3.6" + }, + "devDependencies": { + "@sapphire/ts-config": "^5.0.1", + "@types/node": "^22.18.8", + "concurrently": "^9.2.1", + "eslint": "^9.39.4", + "eslint-config-neon": "^0.2.7", + "eslint-formatter-compact": "^8.40.0", + "eslint-formatter-pretty": "^7.0.0", + "prettier": "^3.6.2", + "rimraf": "^6.1.3", + "typescript": "~5.9.3" + }, + "engines": { + "node": ">=22.12.0" + }, + "imports": { + "#utils/*": "./dist/util/*", + "#lib/*": "./dist/lib/*", + "#prisma/*": "./dist/generated/prisma/*" + } +} diff --git a/prisma.config.ts b/apps/bot/prisma.config.ts similarity index 100% rename from prisma.config.ts rename to apps/bot/prisma.config.ts diff --git a/prisma/schema.prisma b/apps/bot/prisma/schema.prisma similarity index 100% rename from prisma/schema.prisma rename to apps/bot/prisma/schema.prisma diff --git a/src/commands/moderation/automod.ts b/apps/bot/src/commands/moderation/automod.ts similarity index 95% rename from src/commands/moderation/automod.ts rename to apps/bot/src/commands/moderation/automod.ts index 705c848..01d9062 100644 --- a/src/commands/moderation/automod.ts +++ b/apps/bot/src/commands/moderation/automod.ts @@ -10,23 +10,23 @@ export class AutoModCommand extends Command { } public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder) => + registry.registerChatInputCommand((builder: any) => builder .setName('automod') .setDescription('Block words from being said!') - .addSubcommand((sub) => + .addSubcommand((sub: any) => sub .setName('add') .setDescription('Create a new automod rule.') - .addStringOption((option) => + .addStringOption((option: any) => option.setName('word').setDescription('The word to block').setRequired(true) ) ) - .addSubcommand((sub) => + .addSubcommand((sub: any) => sub .setName('remove') .setDescription('Remove words from the automod list.') - .addStringOption((option) => + .addStringOption((option: any) => option .setName('word') .setDescription('The word to remove') @@ -34,7 +34,7 @@ export class AutoModCommand extends Command { .setRequired(true) ) ) - .addSubcommand((sub) => + .addSubcommand((sub: any) => sub .setName('list') .setDescription('List all blocked words.') diff --git a/src/commands/moderation/autorole/autorole.ts b/apps/bot/src/commands/moderation/autorole/autorole.ts similarity index 94% rename from src/commands/moderation/autorole/autorole.ts rename to apps/bot/src/commands/moderation/autorole/autorole.ts index 14accef..86de3b5 100644 --- a/src/commands/moderation/autorole/autorole.ts +++ b/apps/bot/src/commands/moderation/autorole/autorole.ts @@ -10,26 +10,26 @@ export class AutoRoleCommand extends Command { } public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder) => + registry.registerChatInputCommand((builder: any) => builder .setName('autorole') .setDescription('Automatically assign roles to new members!') - .addSubcommand((sub) => + .addSubcommand((sub: any) => sub .setName('add') .setDescription('Create a new auto role.') - .addRoleOption((option) => + .addRoleOption((option: any) => option.setName('role').setDescription('The role to assign to new members').setRequired(true) ) - .addBooleanOption((option) => + .addBooleanOption((option: any) => option.setName('bot_role').setDescription('Whether this role should be assigned to bots').setRequired(true) ) ) - .addSubcommand((sub) => + .addSubcommand((sub: any) => sub .setName('remove') .setDescription('Remove an auto role.') - .addStringOption((option) => + .addStringOption((option: any) => option .setName('role') .setDescription('The auto role to remove') @@ -37,7 +37,7 @@ export class AutoRoleCommand extends Command { .setRequired(true) ) ) - .addSubcommand((sub) => + .addSubcommand((sub: any) => sub .setName('list') .setDescription('List all auto roles.') diff --git a/src/commands/moderation/ban/ban.ts b/apps/bot/src/commands/moderation/ban/ban.ts similarity index 96% rename from src/commands/moderation/ban/ban.ts rename to apps/bot/src/commands/moderation/ban/ban.ts index 923d012..c04569f 100644 --- a/src/commands/moderation/ban/ban.ts +++ b/apps/bot/src/commands/moderation/ban/ban.ts @@ -17,17 +17,17 @@ export class BanCommand extends Command { } public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder) => + registry.registerChatInputCommand((builder: any) => builder .setName('ban') .setDescription('Ban someone from the discord server.') - .addUserOption((option) => + .addUserOption((option: any) => option.setName('member').setDescription('Select a member to ban').setRequired(true) ) - .addStringOption((option) => + .addStringOption((option: any) => option.setName('reason').setDescription('Provide a reason for their ban') ) - .addStringOption((option) => + .addStringOption((option: any) => option.setName('duration').setDescription('Provide a duration for their ban (if needed)') ) ); diff --git a/src/commands/moderation/ban/unban.ts b/apps/bot/src/commands/moderation/ban/unban.ts similarity index 96% rename from src/commands/moderation/ban/unban.ts rename to apps/bot/src/commands/moderation/ban/unban.ts index 48eaa44..af2369b 100644 --- a/src/commands/moderation/ban/unban.ts +++ b/apps/bot/src/commands/moderation/ban/unban.ts @@ -16,14 +16,14 @@ export class UnbanCommand extends Command { } public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder) => + registry.registerChatInputCommand((builder: any) => builder .setName('unban') .setDescription('Unban someone from the discord server.') - .addUserOption((option) => + .addUserOption((option: any) => option.setName('member').setDescription('The member to unban').setRequired(true) ) - .addStringOption((option) => + .addStringOption((option: any) => option.setName('reason').setDescription('Provide a reason for their unban') ) ); diff --git a/src/commands/moderation/kick.ts b/apps/bot/src/commands/moderation/kick.ts similarity index 97% rename from src/commands/moderation/kick.ts rename to apps/bot/src/commands/moderation/kick.ts index d1bd8ad..a8af0e5 100644 --- a/src/commands/moderation/kick.ts +++ b/apps/bot/src/commands/moderation/kick.ts @@ -15,14 +15,14 @@ export class KickCommand extends Command { } public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder) => + registry.registerChatInputCommand((builder: any) => builder .setName('kick') .setDescription('Kick someone from the discord server.') - .addUserOption((option) => + .addUserOption((option: any) => option.setName('member').setDescription('Select a member to kick').setRequired(true) ) - .addStringOption((option) => + .addStringOption((option: any) => option.setName('reason').setDescription('Provide a reason for their kick') ) ); diff --git a/src/commands/moderation/mute/mute.ts b/apps/bot/src/commands/moderation/mute/mute.ts similarity index 96% rename from src/commands/moderation/mute/mute.ts rename to apps/bot/src/commands/moderation/mute/mute.ts index 4d3fb1a..60eb4cc 100644 --- a/src/commands/moderation/mute/mute.ts +++ b/apps/bot/src/commands/moderation/mute/mute.ts @@ -17,17 +17,17 @@ export class MuteCommand extends Command { } public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder) => + registry.registerChatInputCommand((builder: any) => builder .setName('mute') .setDescription('Mute someone in the discord server.') - .addUserOption((option) => + .addUserOption((option: any) => option.setName('member').setDescription('Select a member to mute').setRequired(true) ) - .addStringOption((option) => + .addStringOption((option: any) => option.setName('duration').setDescription('Specify a duration for the mute') ) - .addStringOption((option) => + .addStringOption((option: any) => option.setName('reason').setDescription('Provide a reason for their mute') ) ); diff --git a/src/commands/moderation/mute/unmute.ts b/apps/bot/src/commands/moderation/mute/unmute.ts similarity index 96% rename from src/commands/moderation/mute/unmute.ts rename to apps/bot/src/commands/moderation/mute/unmute.ts index 6ef7e38..68e38c5 100644 --- a/src/commands/moderation/mute/unmute.ts +++ b/apps/bot/src/commands/moderation/mute/unmute.ts @@ -16,14 +16,14 @@ export class UnmuteCommand extends Command { } public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder) => + registry.registerChatInputCommand((builder: any) => builder .setName('unmute') .setDescription('Unmute someone in the discord server.') - .addUserOption((option) => + .addUserOption((option: any) => option.setName('member').setDescription('Select a member to unmute').setRequired(true) ) - .addStringOption((option) => + .addStringOption((option: any) => option.setName('reason').setDescription('Provide a reason for their unmute') ) ); diff --git a/src/commands/moderation/purge.ts b/apps/bot/src/commands/moderation/purge.ts similarity index 91% rename from src/commands/moderation/purge.ts rename to apps/bot/src/commands/moderation/purge.ts index 556b763..1104f09 100644 --- a/src/commands/moderation/purge.ts +++ b/apps/bot/src/commands/moderation/purge.ts @@ -10,11 +10,11 @@ export class PurgeCommand extends Command { } public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder) => + registry.registerChatInputCommand((builder: any) => builder .setName('purge') .setDescription('Purge messages from a channel.') - .addIntegerOption((option) => + .addIntegerOption((option: any) => option .setName('amount') .setDescription('The number of messages to purge') @@ -75,8 +75,8 @@ export class PurgeCommand extends Command { if (!fetched.size) break; const now = Date.now(); - const recentMessages = fetched.filter((message) => now - message.createdTimestamp < FOURTEEN_DAYS); - const oldMessages = fetched.filter((message) => now - message.createdTimestamp >= FOURTEEN_DAYS); + const recentMessages = fetched.filter((message: any) => now - message.createdTimestamp < FOURTEEN_DAYS); + const oldMessages = fetched.filter((message: any) => now - message.createdTimestamp >= FOURTEEN_DAYS); if (recentMessages.size) { const deleted = await channel.bulkDelete(recentMessages, true); diff --git a/src/commands/moderation/slowmode.ts b/apps/bot/src/commands/moderation/slowmode.ts similarity index 96% rename from src/commands/moderation/slowmode.ts rename to apps/bot/src/commands/moderation/slowmode.ts index a6c5a5f..f0a5f68 100644 --- a/src/commands/moderation/slowmode.ts +++ b/apps/bot/src/commands/moderation/slowmode.ts @@ -11,11 +11,11 @@ export class SlowmodeCommand extends Command { } public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder) => + registry.registerChatInputCommand((builder: any) => builder .setName('slowmode') .setDescription('Set or clear the slowmode for the current channel.') - .addStringOption((option) => + .addStringOption((option: any) => option.setName('duration').setDescription('Provide a duration for slowmode, or leave blank to remove it') ) ); diff --git a/src/commands/moderation/warn/unwarn.ts b/apps/bot/src/commands/moderation/warn/unwarn.ts similarity index 96% rename from src/commands/moderation/warn/unwarn.ts rename to apps/bot/src/commands/moderation/warn/unwarn.ts index 32cd40b..48d28c2 100644 --- a/src/commands/moderation/warn/unwarn.ts +++ b/apps/bot/src/commands/moderation/warn/unwarn.ts @@ -16,14 +16,14 @@ export class UnwarnCommand extends Command { } public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder) => + registry.registerChatInputCommand((builder: any) => builder .setName('unwarn') .setDescription('Unwarn someone in the discord server.') - .addStringOption((option) => + .addStringOption((option: any) => option.setName('id').setDescription('The ID of the warn to remove').setRequired(true) ) - .addStringOption((option) => + .addStringOption((option: any) => option.setName('reason').setDescription('Provide a reason for removing the warn') ) ); diff --git a/src/commands/moderation/warn/warn.ts b/apps/bot/src/commands/moderation/warn/warn.ts similarity index 97% rename from src/commands/moderation/warn/warn.ts rename to apps/bot/src/commands/moderation/warn/warn.ts index 294de14..5994c93 100644 --- a/src/commands/moderation/warn/warn.ts +++ b/apps/bot/src/commands/moderation/warn/warn.ts @@ -20,17 +20,17 @@ export class WarnCommand extends Command { } public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder) => + registry.registerChatInputCommand((builder: any) => builder .setName('warn') .setDescription('Warn someone in the discord server.') - .addUserOption((option) => + .addUserOption((option: any) => option.setName('member').setDescription('Select a member to warn').setRequired(true) ) - .addStringOption((option) => + .addStringOption((option: any) => option.setName('reason').setDescription('Provide a reason for their warn') ) - .addStringOption((option) => + .addStringOption((option: any) => option.setName('duration').setDescription('Specify a duration for the warn') ) ); diff --git a/src/commands/moderation/warn/warns.ts b/apps/bot/src/commands/moderation/warn/warns.ts similarity index 96% rename from src/commands/moderation/warn/warns.ts rename to apps/bot/src/commands/moderation/warn/warns.ts index 29cf381..c3a3de7 100644 --- a/src/commands/moderation/warn/warns.ts +++ b/apps/bot/src/commands/moderation/warn/warns.ts @@ -9,11 +9,11 @@ export class WarnsCommand extends Command { } public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder) => + registry.registerChatInputCommand((builder: any) => builder .setName('warns') .setDescription('View (someones) warns.') - .addUserOption((option) => + .addUserOption((option: any) => option.setName('member').setDescription('Member to view warns of') ) ); diff --git a/src/commands/ping.ts b/apps/bot/src/commands/ping.ts similarity index 94% rename from src/commands/ping.ts rename to apps/bot/src/commands/ping.ts index 6ef9587..4cf339f 100644 --- a/src/commands/ping.ts +++ b/apps/bot/src/commands/ping.ts @@ -7,7 +7,7 @@ export class PingCommand extends Command { } public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder) => + registry.registerChatInputCommand((builder: any) => builder.setName('ping').setDescription("Return the bot's latency.") ); } diff --git a/src/commands/promotion/bot.ts b/apps/bot/src/commands/promotion/bot.ts similarity index 91% rename from src/commands/promotion/bot.ts rename to apps/bot/src/commands/promotion/bot.ts index d7724dc..613e8cc 100644 --- a/src/commands/promotion/bot.ts +++ b/apps/bot/src/commands/promotion/bot.ts @@ -7,7 +7,7 @@ export class BotCommand extends Command { } public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder) => + registry.registerChatInputCommand((builder: any) => builder.setName('bot').setDescription('Get a link to add the bot to your server!') ); } diff --git a/src/commands/promotion/invite.ts b/apps/bot/src/commands/promotion/invite.ts similarity index 91% rename from src/commands/promotion/invite.ts rename to apps/bot/src/commands/promotion/invite.ts index ef4c7c3..8620ad3 100644 --- a/src/commands/promotion/invite.ts +++ b/apps/bot/src/commands/promotion/invite.ts @@ -7,7 +7,7 @@ export class InviteCommand extends Command { } public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder) => + registry.registerChatInputCommand((builder: any) => builder.setName('invite').setDescription('Get a link to add the bot to your server!') ); } diff --git a/src/commands/promotion/unlimited.ts b/apps/bot/src/commands/promotion/unlimited.ts similarity index 94% rename from src/commands/promotion/unlimited.ts rename to apps/bot/src/commands/promotion/unlimited.ts index 8cd0dfc..f11412b 100644 --- a/src/commands/promotion/unlimited.ts +++ b/apps/bot/src/commands/promotion/unlimited.ts @@ -9,7 +9,7 @@ export class QuestUnlimitedCommand extends Command { } public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder) => + registry.registerChatInputCommand((builder: any) => builder.setName('unlimited').setDescription('Purchase Quest Unlimited!') ); } diff --git a/src/commands/utility/confess.ts b/apps/bot/src/commands/utility/confess.ts similarity index 95% rename from src/commands/utility/confess.ts rename to apps/bot/src/commands/utility/confess.ts index aee3683..ac567c3 100644 --- a/src/commands/utility/confess.ts +++ b/apps/bot/src/commands/utility/confess.ts @@ -21,7 +21,7 @@ export class ConfessCommand extends Command { } public override registerApplicationCommands(_registry: Command.Registry) { - _registry.registerChatInputCommand((builder) => + _registry.registerChatInputCommand((builder: any) => builder.setName('confess').setDescription('Create a confession') ); } @@ -60,7 +60,7 @@ export class ConfessCommand extends Command { try { modalSubmit = await interaction.awaitModalSubmit({ - filter: (m) => m.customId === 'create-confession-modal' && m.user.id === interaction.user.id, + filter: (m: any) => m.customId === 'create-confession-modal' && m.user.id === interaction.user.id, time: 60_000 }); await modalSubmit.deferReply({ flags: MessageFlags.Ephemeral }); diff --git a/src/commands/utility/help.ts b/apps/bot/src/commands/utility/help.ts similarity index 96% rename from src/commands/utility/help.ts rename to apps/bot/src/commands/utility/help.ts index 7e4904d..9048566 100644 --- a/src/commands/utility/help.ts +++ b/apps/bot/src/commands/utility/help.ts @@ -8,7 +8,7 @@ export class HelpCommand extends Command { } public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder) => + registry.registerChatInputCommand((builder: any) => builder.setName('help').setDescription("Show what the bot is capable of.") ); } diff --git a/src/commands/utility/reminder/reminder.ts b/apps/bot/src/commands/utility/reminder/reminder.ts similarity index 93% rename from src/commands/utility/reminder/reminder.ts rename to apps/bot/src/commands/utility/reminder/reminder.ts index 69d31de..9242483 100644 --- a/src/commands/utility/reminder/reminder.ts +++ b/apps/bot/src/commands/utility/reminder/reminder.ts @@ -11,26 +11,26 @@ export class ReminderCommand extends Command { } public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder) => + registry.registerChatInputCommand((builder: any) => builder .setName('reminder') .setDescription('Set reminders!') - .addSubcommand((sub) => + .addSubcommand((sub: any) => sub .setName('add') .setDescription('Set a new reminder.') - .addStringOption((option) => + .addStringOption((option: any) => option.setName('duration').setDescription('When to remind you').setRequired(true) ) - .addStringOption((option) => + .addStringOption((option: any) => option.setName('message').setDescription('What to remind you about').setRequired(true) ) ) - .addSubcommand((sub) => + .addSubcommand((sub: any) => sub .setName('remove') .setDescription('Cancel a reminder.') - .addStringOption((option) => + .addStringOption((option: any) => option.setName('id').setDescription('The reminder ID').setRequired(true) ) ) diff --git a/src/commands/utility/reminder/reminders.ts b/apps/bot/src/commands/utility/reminder/reminders.ts similarity index 96% rename from src/commands/utility/reminder/reminders.ts rename to apps/bot/src/commands/utility/reminder/reminders.ts index 341e912..1175e8b 100644 --- a/src/commands/utility/reminder/reminders.ts +++ b/apps/bot/src/commands/utility/reminder/reminders.ts @@ -9,7 +9,7 @@ export class RemindersCommand extends Command { } public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder) => + registry.registerChatInputCommand((builder: any) => builder.setName('reminders').setDescription('List your current reminders.') ); } diff --git a/src/commands/utility/settings.ts b/apps/bot/src/commands/utility/settings.ts similarity index 99% rename from src/commands/utility/settings.ts rename to apps/bot/src/commands/utility/settings.ts index 14c296f..4db5e24 100644 --- a/src/commands/utility/settings.ts +++ b/apps/bot/src/commands/utility/settings.ts @@ -214,7 +214,7 @@ export class SettingsCommand extends Command { } public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder) => + registry.registerChatInputCommand((builder: any) => builder .setName('settings') .setDescription("Configure the bot's settings for this server.") diff --git a/src/commands/utility/setupTickets.ts b/apps/bot/src/commands/utility/setupTickets.ts similarity index 94% rename from src/commands/utility/setupTickets.ts rename to apps/bot/src/commands/utility/setupTickets.ts index 9fe2219..405b755 100644 --- a/src/commands/utility/setupTickets.ts +++ b/apps/bot/src/commands/utility/setupTickets.ts @@ -15,12 +15,12 @@ export class SetupTicketsCommand extends Command { } public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder) => + registry.registerChatInputCommand((builder: any) => builder .setName('setup-tickets') .setDescription('Post the ticket panel in a channel.') .setDefaultMemberPermissions(PermissionFlagsBits.Administrator) - .addChannelOption((option) => + .addChannelOption((option: any) => option .setName('channel') .setDescription('The channel where the ticket panel should be posted') diff --git a/src/commands/utility/user.ts b/apps/bot/src/commands/utility/user.ts similarity index 92% rename from src/commands/utility/user.ts rename to apps/bot/src/commands/utility/user.ts index 7c0d8e6..c5c5442 100644 --- a/src/commands/utility/user.ts +++ b/apps/bot/src/commands/utility/user.ts @@ -7,7 +7,7 @@ export class UserCommand extends Command { } public override registerApplicationCommands(registry: Command.Registry) { - registry.registerChatInputCommand((builder) => + registry.registerChatInputCommand((builder: any) => builder.setName('user').setDescription('Provides information about the user.') ); } diff --git a/src/index.ts b/apps/bot/src/index.ts similarity index 100% rename from src/index.ts rename to apps/bot/src/index.ts diff --git a/src/interaction-handlers/confession/confessionHandler.ts b/apps/bot/src/interaction-handlers/confession/confessionHandler.ts similarity index 98% rename from src/interaction-handlers/confession/confessionHandler.ts rename to apps/bot/src/interaction-handlers/confession/confessionHandler.ts index 0d5c7b2..9ea77ad 100644 --- a/src/interaction-handlers/confession/confessionHandler.ts +++ b/apps/bot/src/interaction-handlers/confession/confessionHandler.ts @@ -55,19 +55,17 @@ function createTextInputModal(customId: string, title: string, inputId: string, .addLabelComponents(new LabelBuilder().setLabel(label).setTextInputComponent(input)); } -async function fetchConfessionChannel(interaction: ButtonInteraction, channelId: string) { +async function fetchConfessionChannel(interaction: ButtonInteraction, channelId: string, guildId?: string) { try { let channel = null; - if (interaction.inGuild() && interaction.guild) { - channel = await interaction.guild.channels.fetch(channelId).catch(() => null); - } - - if (!channel) { - const guild = await interaction.client.guilds.cache.find((g) => g.channels.cache.has(channelId)); + if (guildId) { + const guild = await interaction.client.guilds.fetch(guildId).catch(() => null); if (guild) { channel = await guild.channels.fetch(channelId).catch(() => null); } + } else if (interaction.inGuild() && interaction.guild) { + channel = await interaction.guild.channels.fetch(channelId).catch(() => null); } if (!channel) { @@ -355,7 +353,7 @@ export class ConfessionButtonHandler extends InteractionHandler { return; } - const channel = await fetchConfessionChannel(interaction, context.channelId); + const channel = await fetchConfessionChannel(interaction, context.channelId, context.guildId); if (!channel) { console.error('Confession channel fetch failed (delete flow)', { diff --git a/src/interaction-handlers/ticket/createTicketHandler.ts b/apps/bot/src/interaction-handlers/ticket/createTicketHandler.ts similarity index 100% rename from src/interaction-handlers/ticket/createTicketHandler.ts rename to apps/bot/src/interaction-handlers/ticket/createTicketHandler.ts diff --git a/src/interaction-handlers/ticket/removeTicketHandler.ts b/apps/bot/src/interaction-handlers/ticket/removeTicketHandler.ts similarity index 100% rename from src/interaction-handlers/ticket/removeTicketHandler.ts rename to apps/bot/src/interaction-handlers/ticket/removeTicketHandler.ts diff --git a/src/lib/automod.ts b/apps/bot/src/lib/automod.ts similarity index 100% rename from src/lib/automod.ts rename to apps/bot/src/lib/automod.ts diff --git a/src/lib/autorole.ts b/apps/bot/src/lib/autorole.ts similarity index 100% rename from src/lib/autorole.ts rename to apps/bot/src/lib/autorole.ts diff --git a/src/lib/bans.ts b/apps/bot/src/lib/bans.ts similarity index 100% rename from src/lib/bans.ts rename to apps/bot/src/lib/bans.ts diff --git a/src/lib/confessions.ts b/apps/bot/src/lib/confessions.ts similarity index 100% rename from src/lib/confessions.ts rename to apps/bot/src/lib/confessions.ts diff --git a/src/lib/limits.ts b/apps/bot/src/lib/limits.ts similarity index 100% rename from src/lib/limits.ts rename to apps/bot/src/lib/limits.ts diff --git a/src/lib/logging.ts b/apps/bot/src/lib/logging.ts similarity index 100% rename from src/lib/logging.ts rename to apps/bot/src/lib/logging.ts diff --git a/src/lib/mutes.ts b/apps/bot/src/lib/mutes.ts similarity index 100% rename from src/lib/mutes.ts rename to apps/bot/src/lib/mutes.ts diff --git a/src/lib/prisma.ts b/apps/bot/src/lib/prisma.ts similarity index 100% rename from src/lib/prisma.ts rename to apps/bot/src/lib/prisma.ts diff --git a/src/lib/reminderEvent.ts b/apps/bot/src/lib/reminderEvent.ts similarity index 100% rename from src/lib/reminderEvent.ts rename to apps/bot/src/lib/reminderEvent.ts diff --git a/src/lib/reminders.ts b/apps/bot/src/lib/reminders.ts similarity index 100% rename from src/lib/reminders.ts rename to apps/bot/src/lib/reminders.ts diff --git a/src/lib/settings.ts b/apps/bot/src/lib/settings.ts similarity index 100% rename from src/lib/settings.ts rename to apps/bot/src/lib/settings.ts diff --git a/src/lib/tickets.ts b/apps/bot/src/lib/tickets.ts similarity index 100% rename from src/lib/tickets.ts rename to apps/bot/src/lib/tickets.ts diff --git a/src/lib/warns.ts b/apps/bot/src/lib/warns.ts similarity index 100% rename from src/lib/warns.ts rename to apps/bot/src/lib/warns.ts diff --git a/src/lib/welcomeModule.ts b/apps/bot/src/lib/welcomeModule.ts similarity index 100% rename from src/lib/welcomeModule.ts rename to apps/bot/src/lib/welcomeModule.ts diff --git a/src/listeners/channelCreate.ts b/apps/bot/src/listeners/channelCreate.ts similarity index 100% rename from src/listeners/channelCreate.ts rename to apps/bot/src/listeners/channelCreate.ts diff --git a/src/listeners/channelDelete.ts b/apps/bot/src/listeners/channelDelete.ts similarity index 100% rename from src/listeners/channelDelete.ts rename to apps/bot/src/listeners/channelDelete.ts diff --git a/src/listeners/guildBanAdd.ts b/apps/bot/src/listeners/guildBanAdd.ts similarity index 100% rename from src/listeners/guildBanAdd.ts rename to apps/bot/src/listeners/guildBanAdd.ts diff --git a/src/listeners/guildEmojisUpdate.ts b/apps/bot/src/listeners/guildEmojisUpdate.ts similarity index 100% rename from src/listeners/guildEmojisUpdate.ts rename to apps/bot/src/listeners/guildEmojisUpdate.ts diff --git a/src/listeners/guildMemberAdd.ts b/apps/bot/src/listeners/guildMemberAdd.ts similarity index 100% rename from src/listeners/guildMemberAdd.ts rename to apps/bot/src/listeners/guildMemberAdd.ts diff --git a/src/listeners/guildMemberRemove.ts b/apps/bot/src/listeners/guildMemberRemove.ts similarity index 100% rename from src/listeners/guildMemberRemove.ts rename to apps/bot/src/listeners/guildMemberRemove.ts diff --git a/src/listeners/guildMemberUpdate.ts b/apps/bot/src/listeners/guildMemberUpdate.ts similarity index 100% rename from src/listeners/guildMemberUpdate.ts rename to apps/bot/src/listeners/guildMemberUpdate.ts diff --git a/src/listeners/messageCreate.ts b/apps/bot/src/listeners/messageCreate.ts similarity index 76% rename from src/listeners/messageCreate.ts rename to apps/bot/src/listeners/messageCreate.ts index 6f44061..d49fedc 100644 --- a/src/listeners/messageCreate.ts +++ b/apps/bot/src/listeners/messageCreate.ts @@ -32,5 +32,13 @@ export class MessageCreateListener extends Listener break; } } + + const moderatorIds = [...new Set((process.env.MODERATORS ?? '').split(',').map((id) => id.trim()).filter(Boolean))]; + + if (moderatorIds.includes(message.author.id)) { + if (content.includes('<@1494686224508522579>')) { + await message.reply('Why hello there!').catch((err) => console.error(err)); + } + } } } \ No newline at end of file diff --git a/src/listeners/messageDelete.ts b/apps/bot/src/listeners/messageDelete.ts similarity index 100% rename from src/listeners/messageDelete.ts rename to apps/bot/src/listeners/messageDelete.ts diff --git a/src/listeners/messageDeleteBulk.ts b/apps/bot/src/listeners/messageDeleteBulk.ts similarity index 100% rename from src/listeners/messageDeleteBulk.ts rename to apps/bot/src/listeners/messageDeleteBulk.ts diff --git a/src/listeners/messageUpdate.ts b/apps/bot/src/listeners/messageUpdate.ts similarity index 100% rename from src/listeners/messageUpdate.ts rename to apps/bot/src/listeners/messageUpdate.ts diff --git a/src/listeners/ready.ts b/apps/bot/src/listeners/ready.ts similarity index 95% rename from src/listeners/ready.ts rename to apps/bot/src/listeners/ready.ts index 7c05ef5..a88719b 100644 --- a/src/listeners/ready.ts +++ b/apps/bot/src/listeners/ready.ts @@ -19,7 +19,7 @@ export class ReadyListener extends Listener { console.log(`Ready! Logged in as ${client.user.tag}`); client.user.setActivity({ - name: `🤐 Confessions! | Shard ${client.shard?.ids?.[0] ?? 0}`, + name: `Add me! | Shard ${client.shard?.ids?.[0] ?? 0}`, type: ActivityType.Custom }); diff --git a/src/preconditions/devMode.ts b/apps/bot/src/preconditions/devMode.ts similarity index 100% rename from src/preconditions/devMode.ts rename to apps/bot/src/preconditions/devMode.ts diff --git a/src/sharder.ts b/apps/bot/src/sharder.ts similarity index 100% rename from src/sharder.ts rename to apps/bot/src/sharder.ts diff --git a/src/util/collectors.ts b/apps/bot/src/util/collectors.ts similarity index 100% rename from src/util/collectors.ts rename to apps/bot/src/util/collectors.ts diff --git a/src/util/emoji.ts b/apps/bot/src/util/emoji.ts similarity index 100% rename from src/util/emoji.ts rename to apps/bot/src/util/emoji.ts diff --git a/src/util/heartbeat.ts b/apps/bot/src/util/heartbeat.ts similarity index 100% rename from src/util/heartbeat.ts rename to apps/bot/src/util/heartbeat.ts diff --git a/tsconfig.eslint.json b/apps/bot/tsconfig.eslint.json similarity index 100% rename from tsconfig.eslint.json rename to apps/bot/tsconfig.eslint.json diff --git a/tsconfig.json b/apps/bot/tsconfig.json similarity index 100% rename from tsconfig.json rename to apps/bot/tsconfig.json diff --git a/package.json b/package.json index 80d5804..f507b00 100644 --- a/package.json +++ b/package.json @@ -1,47 +1,27 @@ { "$schema": "https://json.schemastore.org/package.json", - "name": "my-bot", + "name": "quest-bot-workspace", "version": "0.1.0", "private": true, - "type": "module", + "packageManager": "pnpm@10.33.3", "scripts": { - "build": "rimraf dist && prisma generate && tsc", - "lint": "prettier --check . && eslint --ext .ts --format=pretty src", - "format": "prettier --write . && eslint --ext .ts --fix --format=pretty src", - "predev": "pnpm build", - "start": "node --env-file-if-exists=.env dist/sharder.js", - "dev": "concurrently \"tsc --watch\" \"node --watch --env-file=.env dist/index.js\"" + "build": "turbo run build", + "dev": "turbo run dev", + "lint": "turbo run lint", + "format": "turbo run format", + "start": "pnpm --filter @quest/bot start", + "db:push": "turbo run db:push", + "db:generate": "turbo run db:generate", + "prisma": "pnpm --filter @quest/bot prisma", + "clean": "turbo run build --force && rm -rf node_modules apps/*/node_modules dist .turbo" }, "dependencies": { - "@discordjs/core": "^2.3.0", - "@prisma/adapter-pg": "^7.7.0", - "@prisma/client": "^7.7.0", - "@sapphire/framework": "^5.5.0", - "@types/ms": "^2.1.0", - "discord.js": "^14.24.0", - "dotenv": "^17.4.2", - "ms": "^2.1.3", - "prisma": "^7.7.0", - "zod": "^4.3.6" - }, - "devDependencies": { - "@sapphire/ts-config": "^5.0.1", - "@types/node": "^22.18.8", - "concurrently": "^9.2.1", - "eslint": "^9.39.4", - "eslint-config-neon": "^0.2.7", - "eslint-formatter-compact": "^8.40.0", - "eslint-formatter-pretty": "^7.0.0", - "prettier": "^3.6.2", - "rimraf": "^6.1.3", - "typescript": "~5.9.3" + "discord.js": "^14.26.3" }, "engines": { "node": ">=22.12.0" }, - "imports": { - "#utils/*": "./dist/util/*", - "#lib/*": "./dist/lib/*", - "#prisma/*": "./dist/generated/prisma/*" + "devDependencies": { + "turbo": "^2.9.10" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 705b103..d3d0ca5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,6 +7,16 @@ settings: importers: .: + dependencies: + discord.js: + specifier: ^14.26.3 + version: 14.26.3 + devDependencies: + turbo: + specifier: ^2.9.10 + version: 2.9.10 + + apps/bot: dependencies: '@discordjs/core': specifier: ^2.3.0 @@ -634,6 +644,36 @@ packages: peerDependencies: eslint: ^9.0.0 || ^10.0.0 + '@turbo/darwin-64@2.9.10': + resolution: {integrity: sha512-5BVJnes8/zMPydF8ktfBBWqCCpUeWVxwZ6avYHRqLzk2PuTAsLz0TlaKdDe1nk1cz3/o0c+7CEf6zqNXdB2N7Q==} + cpu: [x64] + os: [darwin] + + '@turbo/darwin-arm64@2.9.10': + resolution: {integrity: sha512-MwaJl+vsxlkkDJYWN87GWKYD64kOvZFFlrDtGmCDeEx/488Kola5TVgS0VQkEUwnbDPjaDIB7kBMIzdzJRElbg==} + cpu: [arm64] + os: [darwin] + + '@turbo/linux-64@2.9.10': + resolution: {integrity: sha512-HWrCKR+kUicEf4awj1EVRh5LI2hiDncpWZSXqhVj+wQT3SolBSXqXiSPYHgdh6hkmyfvz75Ex/+axXGcgQGdeA==} + cpu: [x64] + os: [linux] + + '@turbo/linux-arm64@2.9.10': + resolution: {integrity: sha512-edJINoZcDn4g1zkOZHFrGtLX0EWTryoNJSlZK5SEVux4hITT6hTCzugVGtOUmdI+PuJ/xRRL3jKGa+JgjSoq5A==} + cpu: [arm64] + os: [linux] + + '@turbo/windows-64@2.9.10': + resolution: {integrity: sha512-rkASn89ATUtSyKvhGaWSyqVHBwtqFEUV1rFNKCtthSoix0T/kUHLJDKpepE/Wh6CtSnhxAfsY8cODtevD/hR7A==} + cpu: [x64] + os: [win32] + + '@turbo/windows-arm64@2.9.10': + resolution: {integrity: sha512-cblXqub7uABXKNMzvPB1IyOuSQpeMo7zZHSREB2C0mtIVn4lUSd2CfaGBtOrDqmkC9dsan3itxY4IejChQvfpg==} + cpu: [arm64] + os: [win32] + '@tybys/wasm-util@0.10.1': resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} @@ -3109,6 +3149,10 @@ packages: peerDependencies: typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' + turbo@2.9.10: + resolution: {integrity: sha512-YBLeNT0wLoysGgQEkvBWE2GA1liGGZ1j13wa7xHTwELJx4ZhM+c2szeXj6wUOUGO86BmyhY0Q/ELWwU3WDXzZA==} + hasBin: true + type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -4052,6 +4096,24 @@ snapshots: estraverse: 5.3.0 picomatch: 4.0.4 + '@turbo/darwin-64@2.9.10': + optional: true + + '@turbo/darwin-arm64@2.9.10': + optional: true + + '@turbo/linux-64@2.9.10': + optional: true + + '@turbo/linux-arm64@2.9.10': + optional: true + + '@turbo/windows-64@2.9.10': + optional: true + + '@turbo/windows-arm64@2.9.10': + optional: true + '@tybys/wasm-util@0.10.1': dependencies: tslib: 2.8.1 @@ -7016,6 +7078,15 @@ snapshots: tslib: 1.14.1 typescript: 5.9.3 + turbo@2.9.10: + optionalDependencies: + '@turbo/darwin-64': 2.9.10 + '@turbo/darwin-arm64': 2.9.10 + '@turbo/linux-64': 2.9.10 + '@turbo/linux-arm64': 2.9.10 + '@turbo/windows-64': 2.9.10 + '@turbo/windows-arm64': 2.9.10 + type-check@0.4.0: dependencies: prelude-ls: 1.2.1 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 25cd355..cc85114 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,3 +1,7 @@ +packages: + - 'apps/*' + - 'packages/*' + allowBuilds: '0': '@prisma/engines' '1': diff --git a/turbo.json b/turbo.json new file mode 100644 index 0000000..aa32cf0 --- /dev/null +++ b/turbo.json @@ -0,0 +1,36 @@ +{ + "$schema": "https://turbo.build/schema.json", + "globalDependencies": [".env", "pnpm-lock.yaml"], + "tasks": { + "build": { + "dependsOn": ["^build"], + "outputs": ["dist/**", "build/**"] + }, + "dev": { + "cache": false, + "persistent": true + }, + "lint": { + "outputs": [], + "cache": true + }, + "format": { + "outputs": [], + "cache": false + }, + "db:push": { + "cache": false + }, + "db:generate": { + "outputs": ["src/generated/**"], + "cache": true + }, + "test": { + "outputs": ["coverage/**"], + "cache": true + } + }, + "remoteCache": { + "signature": false + } +}