forked from syntaxbullet/aurorabot
Tickets: #2, #3 - Remove duplicate type definitions from shared/lib/config.ts - Import types from schema files (game-settings.ts, guild-settings.ts) - Add GuildConfig interface to guild-settings.ts schema - Rename ModerationConfig to ModerationCaseConfig in moderation.service.ts - Delete shared/config/config.json and shared/scripts/migrate-config-to-db.ts - Update settings API to use gameSettingsService exclusively - Return DB format (strings) from API instead of runtime BigInts - Fix moderation service tests to pass config as parameter Breaking Changes: - Removes legacy file-based configuration system - API now returns database format with string values for BigInt fields
208 lines
6.8 KiB
TypeScript
208 lines
6.8 KiB
TypeScript
import type {
|
|
LevelingConfig,
|
|
EconomyConfig as EconomyConfigDB,
|
|
InventoryConfig as InventoryConfigDB,
|
|
LootdropConfig,
|
|
TriviaConfig as TriviaConfigDB,
|
|
ModerationConfig
|
|
} from "@db/schema/game-settings";
|
|
import type { GuildConfig } from "@db/schema/guild-settings";
|
|
|
|
const guildConfigCache = new Map<string, { config: GuildConfig; timestamp: number }>();
|
|
const CACHE_TTL_MS = 60000;
|
|
|
|
export async function getGuildConfig(guildId: string): Promise<GuildConfig> {
|
|
const cached = guildConfigCache.get(guildId);
|
|
if (cached && Date.now() - cached.timestamp < CACHE_TTL_MS) {
|
|
return cached.config;
|
|
}
|
|
|
|
try {
|
|
const { guildSettingsService } = await import('@shared/modules/guild-settings/guild-settings.service');
|
|
const dbSettings = await guildSettingsService.getSettings(guildId);
|
|
|
|
if (dbSettings) {
|
|
const config: GuildConfig = {
|
|
studentRole: dbSettings.studentRoleId,
|
|
visitorRole: dbSettings.visitorRoleId,
|
|
colorRoles: dbSettings.colorRoleIds ?? [],
|
|
welcomeChannelId: dbSettings.welcomeChannelId,
|
|
welcomeMessage: dbSettings.welcomeMessage,
|
|
feedbackChannelId: dbSettings.feedbackChannelId,
|
|
terminal: dbSettings.terminalChannelId ? {
|
|
channelId: dbSettings.terminalChannelId,
|
|
messageId: dbSettings.terminalMessageId ?? "",
|
|
} : undefined,
|
|
moderation: {
|
|
cases: {
|
|
dmOnWarn: dbSettings.moderationDmOnWarn ?? true,
|
|
logChannelId: dbSettings.moderationLogChannelId,
|
|
autoTimeoutThreshold: dbSettings.moderationAutoTimeoutThreshold,
|
|
},
|
|
},
|
|
};
|
|
|
|
guildConfigCache.set(guildId, { config, timestamp: Date.now() });
|
|
return config;
|
|
}
|
|
} catch (error) {
|
|
console.error("Failed to load guild config from database:", error);
|
|
}
|
|
|
|
return {
|
|
studentRole: undefined,
|
|
visitorRole: undefined,
|
|
colorRoles: [],
|
|
welcomeChannelId: undefined,
|
|
welcomeMessage: undefined,
|
|
feedbackChannelId: undefined,
|
|
terminal: undefined,
|
|
moderation: { cases: { dmOnWarn: true } },
|
|
};
|
|
}
|
|
|
|
export function invalidateGuildConfigCache(guildId: string) {
|
|
guildConfigCache.delete(guildId);
|
|
}
|
|
|
|
// Re-export DB types
|
|
export type { LevelingConfig, LootdropConfig, ModerationConfig };
|
|
|
|
// Runtime config types with BigInt for numeric fields
|
|
export interface EconomyConfig {
|
|
daily: {
|
|
amount: bigint;
|
|
streakBonus: bigint;
|
|
weeklyBonus: bigint;
|
|
cooldownMs: number;
|
|
};
|
|
transfers: {
|
|
allowSelfTransfer: boolean;
|
|
minAmount: bigint;
|
|
};
|
|
exam: {
|
|
multMin: number;
|
|
multMax: number;
|
|
};
|
|
}
|
|
|
|
export interface InventoryConfig {
|
|
maxStackSize: bigint;
|
|
maxSlots: number;
|
|
}
|
|
|
|
export interface TriviaConfig {
|
|
entryFee: bigint;
|
|
rewardMultiplier: number;
|
|
timeoutSeconds: number;
|
|
cooldownMs: number;
|
|
categories: number[];
|
|
difficulty: 'easy' | 'medium' | 'hard' | 'random';
|
|
}
|
|
|
|
export interface GameConfigType {
|
|
leveling: LevelingConfig;
|
|
economy: EconomyConfig;
|
|
inventory: InventoryConfig;
|
|
commands: Record<string, boolean>;
|
|
lootdrop: LootdropConfig;
|
|
trivia: TriviaConfig;
|
|
moderation: ModerationConfig;
|
|
system: Record<string, unknown>;
|
|
}
|
|
|
|
export const config: GameConfigType = {} as GameConfigType;
|
|
|
|
export const GameConfig = config;
|
|
|
|
async function loadFromDatabase(): Promise<boolean> {
|
|
try {
|
|
const { gameSettingsService } = await import('@shared/modules/game-settings/game-settings.service');
|
|
const dbSettings = await gameSettingsService.getSettings();
|
|
|
|
if (dbSettings) {
|
|
Object.assign(config, {
|
|
leveling: {
|
|
...dbSettings.leveling,
|
|
},
|
|
economy: {
|
|
daily: {
|
|
...dbSettings.economy.daily,
|
|
amount: BigInt(dbSettings.economy.daily.amount),
|
|
streakBonus: BigInt(dbSettings.economy.daily.streakBonus),
|
|
weeklyBonus: BigInt(dbSettings.economy.daily.weeklyBonus),
|
|
},
|
|
transfers: {
|
|
...dbSettings.economy.transfers,
|
|
minAmount: BigInt(dbSettings.economy.transfers.minAmount),
|
|
},
|
|
exam: dbSettings.economy.exam,
|
|
},
|
|
inventory: {
|
|
...dbSettings.inventory,
|
|
maxStackSize: BigInt(dbSettings.inventory.maxStackSize),
|
|
},
|
|
commands: dbSettings.commands,
|
|
lootdrop: dbSettings.lootdrop,
|
|
trivia: {
|
|
...dbSettings.trivia,
|
|
entryFee: BigInt(dbSettings.trivia.entryFee),
|
|
},
|
|
moderation: dbSettings.moderation,
|
|
system: dbSettings.system,
|
|
});
|
|
console.log("🎮 Game config loaded from database.");
|
|
return true;
|
|
}
|
|
} catch (error) {
|
|
console.error("Failed to load game config from database:", error);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
async function loadDefaults(): Promise<void> {
|
|
console.warn("⚠️ No game config found in database. Using defaults.");
|
|
const { gameSettingsService } = await import('@shared/modules/game-settings/game-settings.service');
|
|
const defaults = gameSettingsService.getDefaults();
|
|
Object.assign(config, {
|
|
leveling: defaults.leveling,
|
|
economy: {
|
|
...defaults.economy,
|
|
daily: {
|
|
...defaults.economy.daily,
|
|
amount: BigInt(defaults.economy.daily.amount),
|
|
streakBonus: BigInt(defaults.economy.daily.streakBonus),
|
|
weeklyBonus: BigInt(defaults.economy.daily.weeklyBonus),
|
|
},
|
|
transfers: {
|
|
...defaults.economy.transfers,
|
|
minAmount: BigInt(defaults.economy.transfers.minAmount),
|
|
},
|
|
},
|
|
inventory: {
|
|
...defaults.inventory,
|
|
maxStackSize: BigInt(defaults.inventory.maxStackSize),
|
|
},
|
|
commands: defaults.commands,
|
|
lootdrop: defaults.lootdrop,
|
|
trivia: {
|
|
...defaults.trivia,
|
|
entryFee: BigInt(defaults.trivia.entryFee),
|
|
},
|
|
moderation: defaults.moderation,
|
|
system: defaults.system,
|
|
});
|
|
}
|
|
|
|
export async function reloadConfig(): Promise<void> {
|
|
const dbLoaded = await loadFromDatabase();
|
|
|
|
if (!dbLoaded) {
|
|
await loadDefaults();
|
|
}
|
|
}
|
|
|
|
export async function initializeConfig(): Promise<void> {
|
|
await reloadConfig();
|
|
}
|