diff --git a/src/lib/config.ts b/src/lib/config.ts index 32478c3..ad31ccd 100644 --- a/src/lib/config.ts +++ b/src/lib/config.ts @@ -1,5 +1,6 @@ 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'); @@ -45,6 +46,56 @@ export interface GameConfigType { // 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, + cooldownMs: z.number(), + }), + transfers: z.object({ + allowSelfTransfer: z.boolean(), + minAmount: bigIntSchema, + }) + }), + 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(), + }) + }) +}); + export function reloadConfig() { if (!existsSync(configPath)) { throw new Error(`Config file not found at ${configPath}`); @@ -82,7 +133,10 @@ reloadConfig(); // Backwards compatibility alias export const GameConfig = config; -export function saveConfig(newConfig: GameConfigType) { +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(); @@ -90,7 +144,7 @@ export function saveConfig(newConfig: GameConfigType) { return value; }; - const jsonString = JSON.stringify(newConfig, replacer, 4); + const jsonString = JSON.stringify(validatedConfig, replacer, 4); writeFileSync(configPath, jsonString, 'utf-8'); reloadConfig(); }