refactor: rename bot client, environment variables, and project name from Kyoko to Aurora.
This commit is contained in:
@@ -1,12 +1,12 @@
|
|||||||
DB_USER=kyoko
|
DB_USER=aurora
|
||||||
DB_PASSWORD=kyoko
|
DB_PASSWORD=aurora
|
||||||
DB_NAME=kyoko
|
DB_NAME=aurora
|
||||||
DB_PORT=5432
|
DB_PORT=5432
|
||||||
DB_HOST=db
|
DB_HOST=db
|
||||||
DISCORD_BOT_TOKEN=your-discord-bot-token
|
DISCORD_BOT_TOKEN=your-discord-bot-token
|
||||||
DISCORD_CLIENT_ID=your-discord-client-id
|
DISCORD_CLIENT_ID=your-discord-client-id
|
||||||
DISCORD_GUILD_ID=your-discord-guild-id
|
DISCORD_GUILD_ID=your-discord-guild-id
|
||||||
DATABASE_URL=postgres://kyoko:kyoko@db:5432/kyoko
|
DATABASE_URL=postgres://aurora:aurora@db:5432/aurora
|
||||||
|
|
||||||
VPS_USER=your-vps-user
|
VPS_USER=your-vps-user
|
||||||
VPS_HOST=your-vps-ip
|
VPS_HOST=your-vps-ip
|
||||||
|
|||||||
43
README.md
43
README.md
@@ -1,42 +1 @@
|
|||||||
# Kyoko - Discord Rpg
|
# Aurora
|
||||||
|
|
||||||
A Discord bot built with [Bun](https://bun.sh), [Discord.js](https://discord.js.org/), and [Drizzle ORM](https://orm.drizzle.team/).
|
|
||||||
|
|
||||||
## Architecture
|
|
||||||
|
|
||||||
This project uses a modular architecture:
|
|
||||||
|
|
||||||
- **`src/index.ts`**: Entry point. initializes the client.
|
|
||||||
- **`src/lib/KyokoClient.ts`**: Custom Discord Client wrapper handling command loading and events.
|
|
||||||
- **`src/lib/env.ts`**: **Centralized Environment Configuration**. Validates environment variables using `zod` at startup.
|
|
||||||
- **`src/lib/DrizzleClient.ts`**: Database client instance.
|
|
||||||
- **`src/commands/`**: Command files.
|
|
||||||
- **`src/db/`**: Database schema and migrations.
|
|
||||||
|
|
||||||
## Setup
|
|
||||||
|
|
||||||
1. **Install Dependencies**:
|
|
||||||
```bash
|
|
||||||
bun install
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Environment Variables**:
|
|
||||||
Copy `.env.example` to `.env` (create one if it doesn't exist) and fill in the required values:
|
|
||||||
```env
|
|
||||||
DISCORD_BOT_TOKEN=your_token_here
|
|
||||||
DISCORD_CLIENT_ID=your_client_id
|
|
||||||
DISCORD_GUILD_ID=your_guild_id_optional
|
|
||||||
DATABASE_URL=postgres://user:pass@localhost:5432/db_name
|
|
||||||
```
|
|
||||||
*Note: The app will fail to start if `DISCORD_BOT_TOKEN` or `DATABASE_URL` are missing or invalid.*
|
|
||||||
|
|
||||||
3. **Run Development**:
|
|
||||||
```bash
|
|
||||||
bun run dev
|
|
||||||
```
|
|
||||||
|
|
||||||
4. **Database Migrations**:
|
|
||||||
```bash
|
|
||||||
bun run db:push # Apply schema changes
|
|
||||||
bun run generate # Generate migrations
|
|
||||||
```
|
|
||||||
@@ -13,7 +13,7 @@ services:
|
|||||||
- ./src/db/log:/var/log/postgresql
|
- ./src/db/log:/var/log/postgresql
|
||||||
app:
|
app:
|
||||||
container_name: aurora_app
|
container_name: aurora_app
|
||||||
image: kyoko-app
|
image: aurora-app
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
@@ -39,7 +39,7 @@ services:
|
|||||||
|
|
||||||
studio:
|
studio:
|
||||||
container_name: aurora_studio
|
container_name: aurora_studio
|
||||||
image: kyoko-app
|
image: aurora-app
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { createCommand } from "@/lib/utils";
|
|||||||
import { SlashCommandBuilder, PermissionFlagsBits, EmbedBuilder, MessageFlags } from "discord.js";
|
import { SlashCommandBuilder, PermissionFlagsBits, EmbedBuilder, MessageFlags } from "discord.js";
|
||||||
import { configManager } from "@/lib/configManager";
|
import { configManager } from "@/lib/configManager";
|
||||||
import { config, reloadConfig } from "@/lib/config";
|
import { config, reloadConfig } from "@/lib/config";
|
||||||
import { KyokoClient } from "@/lib/BotClient"; // Import directly from lib, avoiding circular dep with index
|
import { AuroraClient } from "@/lib/BotClient";
|
||||||
|
|
||||||
export const features = createCommand({
|
export const features = createCommand({
|
||||||
data: new SlashCommandBuilder()
|
data: new SlashCommandBuilder()
|
||||||
@@ -31,7 +31,7 @@ export const features = createCommand({
|
|||||||
const subcommand = interaction.options.getSubcommand();
|
const subcommand = interaction.options.getSubcommand();
|
||||||
|
|
||||||
if (subcommand === "list") {
|
if (subcommand === "list") {
|
||||||
const activeCommands = KyokoClient.commands;
|
const activeCommands = AuroraClient.commands;
|
||||||
const categories = new Map<string, string[]>();
|
const categories = new Map<string, string[]>();
|
||||||
|
|
||||||
// Group active commands
|
// Group active commands
|
||||||
@@ -87,8 +87,8 @@ export const features = createCommand({
|
|||||||
// Reload config from disk (which was updated by configManager)
|
// Reload config from disk (which was updated by configManager)
|
||||||
reloadConfig();
|
reloadConfig();
|
||||||
|
|
||||||
await KyokoClient.loadCommands(true);
|
await AuroraClient.loadCommands(true);
|
||||||
await KyokoClient.deployCommands();
|
await AuroraClient.deployCommands();
|
||||||
|
|
||||||
await interaction.editReply({ content: `✅ Command **${commandName}** has been ${enabled ? "enabled" : "disabled"}. Commands reloaded!` });
|
await interaction.editReply({ content: `✅ Command **${commandName}** has been ${enabled ? "enabled" : "disabled"}. Commands reloaded!` });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { createCommand } from "@lib/utils";
|
import { createCommand } from "@lib/utils";
|
||||||
import { KyokoClient } from "@/lib/BotClient";
|
import { AuroraClient } from "@/lib/BotClient";
|
||||||
import { SlashCommandBuilder, EmbedBuilder, PermissionFlagsBits, MessageFlags } from "discord.js";
|
import { SlashCommandBuilder, EmbedBuilder, PermissionFlagsBits, MessageFlags } from "discord.js";
|
||||||
import { createErrorEmbed, createSuccessEmbed, createWarningEmbed } from "@lib/embeds";
|
import { createErrorEmbed, createSuccessEmbed, createWarningEmbed } from "@lib/embeds";
|
||||||
|
|
||||||
@@ -13,14 +13,14 @@ export const refresh = createCommand({
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const start = Date.now();
|
const start = Date.now();
|
||||||
await KyokoClient.loadCommands(true);
|
await AuroraClient.loadCommands(true);
|
||||||
const duration = Date.now() - start;
|
const duration = Date.now() - start;
|
||||||
|
|
||||||
// Deploy commands
|
// Deploy commands
|
||||||
await KyokoClient.deployCommands();
|
await AuroraClient.deployCommands();
|
||||||
|
|
||||||
const embed = createSuccessEmbed(
|
const embed = createSuccessEmbed(
|
||||||
`Successfully reloaded ${KyokoClient.commands.size} commands in ${duration}ms.`,
|
`Successfully reloaded ${AuroraClient.commands.size} commands in ${duration}ms.`,
|
||||||
"System Refreshed"
|
"System Refreshed"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Events, MessageFlags } from "discord.js";
|
import { Events, MessageFlags } from "discord.js";
|
||||||
import { KyokoClient } from "@/lib/BotClient";
|
import { AuroraClient } from "@/lib/BotClient";
|
||||||
import { userService } from "@/modules/user/user.service";
|
import { userService } from "@/modules/user/user.service";
|
||||||
import { createErrorEmbed } from "@lib/embeds";
|
import { createErrorEmbed } from "@lib/embeds";
|
||||||
import type { Event } from "@lib/types";
|
import type { Event } from "@lib/types";
|
||||||
@@ -32,7 +32,7 @@ const event: Event<Events.InteractionCreate> = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (interaction.isAutocomplete()) {
|
if (interaction.isAutocomplete()) {
|
||||||
const command = KyokoClient.commands.get(interaction.commandName);
|
const command = AuroraClient.commands.get(interaction.commandName);
|
||||||
if (!command || !command.autocomplete) return;
|
if (!command || !command.autocomplete) return;
|
||||||
try {
|
try {
|
||||||
await command.autocomplete(interaction);
|
await command.autocomplete(interaction);
|
||||||
@@ -44,7 +44,7 @@ const event: Event<Events.InteractionCreate> = {
|
|||||||
|
|
||||||
if (!interaction.isChatInputCommand()) return;
|
if (!interaction.isChatInputCommand()) return;
|
||||||
|
|
||||||
const command = KyokoClient.commands.get(interaction.commandName);
|
const command = AuroraClient.commands.get(interaction.commandName);
|
||||||
|
|
||||||
if (!command) {
|
if (!command) {
|
||||||
console.error(`No command matching ${interaction.commandName} was found.`);
|
console.error(`No command matching ${interaction.commandName} was found.`);
|
||||||
|
|||||||
10
src/index.ts
10
src/index.ts
@@ -1,14 +1,14 @@
|
|||||||
import { KyokoClient } from "@/lib/BotClient";
|
import { AuroraClient } from "@/lib/BotClient";
|
||||||
import { env } from "@lib/env";
|
import { env } from "@lib/env";
|
||||||
|
|
||||||
// Load commands & events
|
// Load commands & events
|
||||||
await KyokoClient.loadCommands();
|
await AuroraClient.loadCommands();
|
||||||
await KyokoClient.loadEvents();
|
await AuroraClient.loadEvents();
|
||||||
await KyokoClient.deployCommands();
|
await AuroraClient.deployCommands();
|
||||||
|
|
||||||
|
|
||||||
// login with the token from .env
|
// login with the token from .env
|
||||||
if (!env.DISCORD_BOT_TOKEN) {
|
if (!env.DISCORD_BOT_TOKEN) {
|
||||||
throw new Error("❌ DISCORD_BOT_TOKEN is not set in environment variables.");
|
throw new Error("❌ DISCORD_BOT_TOKEN is not set in environment variables.");
|
||||||
}
|
}
|
||||||
KyokoClient.login(env.DISCORD_BOT_TOKEN);
|
AuroraClient.login(env.DISCORD_BOT_TOKEN);
|
||||||
@@ -185,4 +185,4 @@ class Client extends DiscordClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const KyokoClient = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.MessageContent, GatewayIntentBits.GuildMessages, GatewayIntentBits.GuildMembers] });
|
export const AuroraClient = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.MessageContent, GatewayIntentBits.GuildMessages, GatewayIntentBits.GuildMembers] });
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { readFileSync, writeFileSync } from 'fs';
|
import { readFileSync, writeFileSync } from 'fs';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import { KyokoClient } from '@/lib/BotClient';
|
import { AuroraClient } from '@/lib/BotClient';
|
||||||
|
|
||||||
const configPath = join(process.cwd(), 'src', 'config', 'config.json');
|
const configPath = join(process.cwd(), 'src', 'config', 'config.json');
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { userTimers } from "@/db/schema";
|
import { userTimers } from "@/db/schema";
|
||||||
import { eq, and, lt } from "drizzle-orm";
|
import { eq, and, lt } from "drizzle-orm";
|
||||||
import { DrizzleClient } from "@/lib/DrizzleClient";
|
import { DrizzleClient } from "@/lib/DrizzleClient";
|
||||||
import { KyokoClient } from "@/lib/BotClient";
|
import { AuroraClient } from "@/lib/BotClient";
|
||||||
import { env } from "@/lib/env";
|
import { env } from "@/lib/env";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -51,7 +51,7 @@ export const schedulerService = {
|
|||||||
|
|
||||||
if (guildId) {
|
if (guildId) {
|
||||||
// We try to fetch, if bot is not in guild or lacks perms, it will catch
|
// We try to fetch, if bot is not in guild or lacks perms, it will catch
|
||||||
const guild = await KyokoClient.guilds.fetch(guildId);
|
const guild = await AuroraClient.guilds.fetch(guildId);
|
||||||
const member = await guild.members.fetch(userIdStr);
|
const member = await guild.members.fetch(userIdStr);
|
||||||
await member.roles.remove(roleId);
|
await member.roles.remove(roleId);
|
||||||
console.log(`👋 Removed temporary role ${roleId} from ${member.user.tag}`);
|
console.log(`👋 Removed temporary role ${roleId} from ${member.user.tag}`);
|
||||||
|
|||||||
Reference in New Issue
Block a user