diff --git a/bot/commands/admin/config.ts b/bot/commands/admin/config.ts index 376e5b8..901684a 100644 --- a/bot/commands/admin/config.ts +++ b/bot/commands/admin/config.ts @@ -1,7 +1,7 @@ import { createCommand } from "@shared/lib/utils"; import { SlashCommandBuilder, PermissionFlagsBits, ModalBuilder, TextInputBuilder, TextInputStyle, ActionRowBuilder, ModalSubmitInteraction } from "discord.js"; -import { config, saveConfig } from "@lib/config"; -import type { GameConfigType } from "@lib/config"; +import { config, saveConfig } from "@shared/lib/config"; +import type { GameConfigType } from "@shared/lib/config"; import { createSuccessEmbed, createErrorEmbed } from "@lib/embeds"; export const configCommand = createCommand({ diff --git a/bot/commands/admin/create_color.ts b/bot/commands/admin/create_color.ts index ec8581a..7ab6a6d 100644 --- a/bot/commands/admin/create_color.ts +++ b/bot/commands/admin/create_color.ts @@ -1,6 +1,6 @@ import { createCommand } from "@shared/lib/utils"; import { SlashCommandBuilder, PermissionFlagsBits, AttachmentBuilder } from "discord.js"; -import { config, saveConfig } from "@/lib/config"; +import { config, saveConfig } from "@shared/lib/config"; import { DrizzleClient } from "@shared/db/DrizzleClient"; import { items } from "@db/schema"; import { createSuccessEmbed, createErrorEmbed } from "@lib/embeds"; diff --git a/bot/commands/admin/features.ts b/bot/commands/admin/features.ts index d56c3a0..48f9bea 100644 --- a/bot/commands/admin/features.ts +++ b/bot/commands/admin/features.ts @@ -1,8 +1,8 @@ import { createCommand } from "@shared/lib/utils"; import { SlashCommandBuilder, PermissionFlagsBits, MessageFlags } from "discord.js"; import { createBaseEmbed } from "@lib/embeds"; -import { configManager } from "@/lib/configManager"; -import { config, reloadConfig } from "@/lib/config"; +import { configManager } from "@shared/lib/configManager"; +import { config, reloadConfig } from "@shared/lib/config"; import { AuroraClient } from "@/lib/BotClient"; export const features = createCommand({ diff --git a/bot/commands/admin/prune.ts b/bot/commands/admin/prune.ts index b33fef8..091bb0e 100644 --- a/bot/commands/admin/prune.ts +++ b/bot/commands/admin/prune.ts @@ -1,6 +1,6 @@ import { createCommand } from "@shared/lib/utils"; import { SlashCommandBuilder, PermissionFlagsBits, MessageFlags, ComponentType } from "discord.js"; -import { config } from "@/lib/config"; +import { config } from "@shared/lib/config"; import { PruneService } from "@shared/modules/moderation/prune.service"; import { getConfirmationMessage, diff --git a/bot/commands/admin/warn.ts b/bot/commands/admin/warn.ts index 73b44d0..b6e72c8 100644 --- a/bot/commands/admin/warn.ts +++ b/bot/commands/admin/warn.ts @@ -6,7 +6,7 @@ import { getModerationErrorEmbed, getUserWarningEmbed } from "@/modules/moderation/moderation.view"; -import { config } from "@/lib/config"; +import { config } from "@shared/lib/config"; export const warn = createCommand({ data: new SlashCommandBuilder() diff --git a/bot/commands/economy/exam.ts b/bot/commands/economy/exam.ts index 0533ead..890d184 100644 --- a/bot/commands/economy/exam.ts +++ b/bot/commands/economy/exam.ts @@ -6,7 +6,7 @@ import { UserError } from "@/lib/errors"; import { userTimers, users } from "@db/schema"; import { eq, and, sql } from "drizzle-orm"; import { DrizzleClient } from "@shared/db/DrizzleClient"; -import { config } from "@lib/config"; +import { config } from "@shared/lib/config"; import { TimerType } from "@shared/lib/constants"; const EXAM_TIMER_TYPE = TimerType.EXAM_SYSTEM; diff --git a/bot/commands/economy/pay.ts b/bot/commands/economy/pay.ts index 3698184..2d87899 100644 --- a/bot/commands/economy/pay.ts +++ b/bot/commands/economy/pay.ts @@ -3,7 +3,7 @@ import { createCommand } from "@shared/lib/utils"; import { SlashCommandBuilder, MessageFlags } from "discord.js"; import { economyService } from "@shared/modules/economy/economy.service"; import { userService } from "@shared/modules/user/user.service"; -import { config } from "@/lib/config"; +import { config } from "@shared/lib/config"; import { createErrorEmbed, createSuccessEmbed } from "@lib/embeds"; import { UserError } from "@/lib/errors"; diff --git a/bot/commands/feedback/feedback.ts b/bot/commands/feedback/feedback.ts index 8a2f4b9..7e775e5 100644 --- a/bot/commands/feedback/feedback.ts +++ b/bot/commands/feedback/feedback.ts @@ -1,6 +1,6 @@ import { createCommand } from "@shared/lib/utils"; import { SlashCommandBuilder } from "discord.js"; -import { config } from "@/lib/config"; +import { config } from "@shared/lib/config"; import { createErrorEmbed } from "@/lib/embeds"; import { getFeedbackTypeMenu } from "@/modules/feedback/feedback.view"; diff --git a/bot/commands/inventory/use.ts b/bot/commands/inventory/use.ts index 1d88df8..448a346 100644 --- a/bot/commands/inventory/use.ts +++ b/bot/commands/inventory/use.ts @@ -6,7 +6,7 @@ import { createErrorEmbed } from "@lib/embeds"; import { getItemUseResultEmbed } from "@/modules/inventory/inventory.view"; import type { ItemUsageData } from "@shared/lib/types"; import { UserError } from "@/lib/errors"; -import { config } from "@/lib/config"; +import { config } from "@shared/lib/config"; export const use = createCommand({ data: new SlashCommandBuilder() diff --git a/bot/events/guildMemberAdd.ts b/bot/events/guildMemberAdd.ts index 18187d7..c94537a 100644 --- a/bot/events/guildMemberAdd.ts +++ b/bot/events/guildMemberAdd.ts @@ -1,6 +1,6 @@ import { Events } from "discord.js"; import type { Event } from "@shared/lib/types"; -import { config } from "@lib/config"; +import { config } from "@shared/lib/config"; import { userService } from "@shared/modules/user/user.service"; // Visitor role diff --git a/bot/lib/config.ts b/bot/lib/config.ts deleted file mode 100644 index f5e678d..0000000 --- a/bot/lib/config.ts +++ /dev/null @@ -1,204 +0,0 @@ -import { readFileSync, existsSync, writeFileSync } from 'node:fs'; -import { join } from 'node:path'; -import { z } from 'zod'; - -const configPath = join(import.meta.dir, '..', '..', 'config', 'config.json'); - -export interface GameConfigType { - leveling: { - base: number; - exponent: number; - chat: { - cooldownMs: number; - minXp: number; - maxXp: number; - } - }, - economy: { - daily: { - amount: bigint; - streakBonus: bigint; - weeklyBonus: bigint; - cooldownMs: number; - }, - transfers: { - allowSelfTransfer: boolean; - minAmount: bigint; - }, - exam: { - multMin: number; - multMax: number; - } - }, - inventory: { - maxStackSize: bigint; - maxSlots: number; - }, - commands: Record; - lootdrop: { - activityWindowMs: number; - minMessages: number; - spawnChance: number; - cooldownMs: number; - reward: { - min: number; - max: number; - currency: string; - } - }; - studentRole: string; - visitorRole: string; - colorRoles: string[]; - welcomeChannelId?: string; - welcomeMessage?: string; - feedbackChannelId?: string; - terminal?: { - channelId: string; - messageId: string; - }; - moderation: { - prune: { - maxAmount: number; - confirmThreshold: number; - batchSize: number; - batchDelayMs: number; - }; - cases: { - dmOnWarn: boolean; - logChannelId?: string; - autoTimeoutThreshold?: number; - }; - }; - system: Record; -} - -// Initial default config state -export const config: GameConfigType = {} as GameConfigType; - -const bigIntSchema = z.union([z.string(), z.number(), z.bigint()]) - .refine((val) => { - try { - BigInt(val); - return true; - } catch { - return false; - } - }, { message: "Must be a valid integer" }) - .transform((val) => BigInt(val)); - -const configSchema = z.object({ - leveling: z.object({ - base: z.number(), - exponent: z.number(), - chat: z.object({ - cooldownMs: z.number(), - minXp: z.number(), - maxXp: z.number(), - }) - }), - economy: z.object({ - daily: z.object({ - amount: bigIntSchema, - streakBonus: bigIntSchema, - weeklyBonus: bigIntSchema.default(50n), - cooldownMs: z.number(), - }), - transfers: z.object({ - allowSelfTransfer: z.boolean(), - minAmount: bigIntSchema, - }), - exam: z.object({ - multMin: z.number(), - multMax: z.number(), - }) - }), - inventory: z.object({ - maxStackSize: bigIntSchema, - maxSlots: z.number(), - }), - commands: z.record(z.string(), z.boolean()), - lootdrop: z.object({ - activityWindowMs: z.number(), - minMessages: z.number(), - spawnChance: z.number(), - cooldownMs: z.number(), - reward: z.object({ - min: z.number(), - max: z.number(), - currency: z.string(), - }) - - }), - studentRole: z.string(), - visitorRole: z.string(), - colorRoles: z.array(z.string()).default([]), - welcomeChannelId: z.string().optional(), - welcomeMessage: z.string().optional(), - feedbackChannelId: z.string().optional(), - terminal: z.object({ - channelId: z.string(), - messageId: z.string() - }).optional(), - moderation: z.object({ - prune: z.object({ - maxAmount: z.number().default(100), - confirmThreshold: z.number().default(50), - batchSize: z.number().default(100), - batchDelayMs: z.number().default(1000) - }), - cases: z.object({ - dmOnWarn: z.boolean().default(true), - logChannelId: z.string().optional(), - autoTimeoutThreshold: z.number().optional() - }) - }).default({ - prune: { - maxAmount: 100, - confirmThreshold: 50, - batchSize: 100, - batchDelayMs: 1000 - }, - cases: { - dmOnWarn: true - } - }), - system: z.record(z.string(), z.any()).default({}), -}); - -export function reloadConfig() { - if (!existsSync(configPath)) { - throw new Error(`Config file not found at ${configPath}`); - } - - const raw = readFileSync(configPath, 'utf-8'); - const rawConfig = JSON.parse(raw); - - // Update config object in place - // We use Object.assign to keep the reference to the exported 'config' object same - const validatedConfig = configSchema.parse(rawConfig); - Object.assign(config, validatedConfig); - - console.log("🔄 Config reloaded from disk."); -} - -// Initial load -reloadConfig(); - -// Backwards compatibility alias -export const GameConfig = config; - -export function saveConfig(newConfig: unknown) { - // Validate and transform input - const validatedConfig = configSchema.parse(newConfig); - - const replacer = (key: string, value: any) => { - if (typeof value === 'bigint') { - return value.toString(); - } - return value; - }; - - const jsonString = JSON.stringify(validatedConfig, replacer, 4); - writeFileSync(configPath, jsonString, 'utf-8'); - reloadConfig(); -} diff --git a/bot/lib/loaders/CommandLoader.ts b/bot/lib/loaders/CommandLoader.ts index 63d054d..9397641 100644 --- a/bot/lib/loaders/CommandLoader.ts +++ b/bot/lib/loaders/CommandLoader.ts @@ -1,7 +1,7 @@ import { readdir } from "node:fs/promises"; import { join } from "node:path"; import type { Command } from "@shared/lib/types"; -import { config } from "@lib/config"; +import { config } from "@shared/lib/config"; import type { LoadResult, LoadError } from "./types"; import type { Client } from "../BotClient"; diff --git a/bot/modules/feedback/feedback.interaction.ts b/bot/modules/feedback/feedback.interaction.ts index ec31436..4ccfc7e 100644 --- a/bot/modules/feedback/feedback.interaction.ts +++ b/bot/modules/feedback/feedback.interaction.ts @@ -1,6 +1,6 @@ import type { Interaction } from "discord.js"; import { TextChannel, MessageFlags } from "discord.js"; -import { config } from "@/lib/config"; +import { config } from "@shared/lib/config"; import { AuroraClient } from "@/lib/BotClient"; import { buildFeedbackMessage, getFeedbackModal } from "./feedback.view"; import { FEEDBACK_CUSTOM_IDS, type FeedbackType, type FeedbackData } from "./feedback.types"; diff --git a/bot/modules/user/enrollment.interaction.ts b/bot/modules/user/enrollment.interaction.ts index 2b88fd5..b15b0aa 100644 --- a/bot/modules/user/enrollment.interaction.ts +++ b/bot/modules/user/enrollment.interaction.ts @@ -1,5 +1,5 @@ import { ButtonInteraction, MessageFlags } from "discord.js"; -import { config } from "@/lib/config"; +import { config } from "@shared/lib/config"; import { getEnrollmentSuccessMessage } from "./enrollment.view"; import { classService } from "@shared/modules/class/class.service"; import { userService } from "@shared/modules/user/user.service"; diff --git a/docs/COMMANDS.md b/shared/docs/COMMANDS.md similarity index 100% rename from docs/COMMANDS.md rename to shared/docs/COMMANDS.md diff --git a/docs/CONFIGURATION.md b/shared/docs/CONFIGURATION.md similarity index 100% rename from docs/CONFIGURATION.md rename to shared/docs/CONFIGURATION.md diff --git a/docs/DATABASE.md b/shared/docs/DATABASE.md similarity index 100% rename from docs/DATABASE.md rename to shared/docs/DATABASE.md diff --git a/docs/LOOTBOX_GUIDE.md b/shared/docs/LOOTBOX_GUIDE.md similarity index 100% rename from docs/LOOTBOX_GUIDE.md rename to shared/docs/LOOTBOX_GUIDE.md diff --git a/docs/MODULE_STRUCTURE.md b/shared/docs/MODULE_STRUCTURE.md similarity index 100% rename from docs/MODULE_STRUCTURE.md rename to shared/docs/MODULE_STRUCTURE.md diff --git a/bot/lib/configManager.ts b/shared/lib/configManager.ts similarity index 100% rename from bot/lib/configManager.ts rename to shared/lib/configManager.ts diff --git a/scripts/remote-dashboard.sh b/shared/scripts/remote-dashboard.sh similarity index 100% rename from scripts/remote-dashboard.sh rename to shared/scripts/remote-dashboard.sh diff --git a/scripts/remote-studio.sh b/shared/scripts/remote-studio.sh similarity index 100% rename from scripts/remote-studio.sh rename to shared/scripts/remote-studio.sh diff --git a/scripts/remote.sh b/shared/scripts/remote.sh similarity index 100% rename from scripts/remote.sh rename to shared/scripts/remote.sh