/** * Flashcore CRUD operations for XP data persistence * * Uses Flashcore key-value store with array namespaces for hierarchical organization: * - Flashcore.get(userId, { namespace: ['xp', storeId, guildId, 'users'] }) -> UserXP data * - Flashcore.get('members', { namespace: ['xp', storeId, guildId] }) -> string[] of tracked user IDs * - Flashcore.get('config', { namespace: ['xp', storeId, guildId] }) -> GuildConfig * - Flashcore.get('config', { namespace: ['xp', 'global'] }) -> GlobalConfig * - Flashcore.get('schema', { namespace: ['xp', storeId, guildId] }) -> number (schema version) * * Multi-store namespace structure: * - Default store: ['xp', 'default', guildId, 'users'] * - Custom store: ['xp', 'reputation', guildId, 'users'] * - Each store has independent user data, config, members, and schema * * Internal Flashcore keys (colon-separated): * - 'xp:default:guild123:users:user456' (user data - default store) * - 'xp:reputation:guild123:users:user456' (user data - custom store) * - 'xp:default:guild123:members' (members list - default store) * - 'xp:default:guild123:config' (guild config - default store) * - 'xp:global:config' (global defaults - shared across all stores) * - 'xp:default:guild123:schema' (schema version - default store) * * Schema migrations run automatically when data is accessed via getUser() or getConfig(). * Migrations are per-guild, per-store, and execute sequentially (e.g., v1→v2→v3). * See src/store/migrations.ts for migration implementation details. * * Implements caching for guild configs to reduce Flashcore reads. * Cache structure: Map keyed by composite 'guildId:storeId' */ import type { UserXP, GuildConfig, GlobalConfig, FlashcoreOptions } from '../types.js'; export declare const SCHEMA_VERSION = 1; /** * Invalidates cached config for a specific guild and store * Forces next getConfig to read from Flashcore * * @param guildId - Guild ID to invalidate * @param options - Store options (defaults to 'default' store) or { all: true } to clear all stores * * @example * // Invalidate default store * invalidateConfigCache('123...') * * @example * // Invalidate specific store * invalidateConfigCache('123...', { storeId: 'reputation' }) * * @example * // Invalidate all stores for guild * invalidateConfigCache('123...', { all: true }) */ export declare function invalidateConfigCache(guildId: string, options?: FlashcoreOptions | { all: true; }): void; /** * Clears entire config cache * Used when global config changes to force re-merge for all guilds */ export declare function clearConfigCache(): void; /** * Retrieves user XP record for a guild member * * @param guildId - Guild ID * @param userId - User ID * @param options - Store options (defaults to 'default' store) * @returns UserXP data or null if user not tracked * * @example * // Default store * const user = await getUser('123...', '456...') * if (user) { * console.log(`Level ${user.level} with ${user.xp} XP`) * } * * @example * // Custom store * const reputation = await getUser('123...', '456...', { storeId: 'reputation' }) */ export declare function getUser(guildId: string, userId: string, options?: FlashcoreOptions): Promise; /** * Persists user XP record and adds user to members set * * @param guildId - Guild ID * @param userId - User ID * @param data - UserXP data to persist * @param options - Store options (defaults to 'default' store) * * @example * // Default store * await putUser('123...', '456...', { * xp: 1500, * level: 5, * lastAwardedAt: Date.now(), * messages: 423, * xpMessages: 156 * }) * * @example * // Custom store * await putUser('123...', '456...', userData, { storeId: 'reputation' }) */ export declare function putUser(guildId: string, userId: string, data: UserXP, options?: FlashcoreOptions): Promise; /** * Deletes user XP record and removes from members set * * @param guildId - Guild ID * @param userId - User ID * @param options - Store options (defaults to 'default' store) * * @example * // Default store * await deleteUser('123...', '456...') // Resets user's XP progress * * @example * // Custom store * await deleteUser('123...', '456...', { storeId: 'reputation' }) */ export declare function deleteUser(guildId: string, userId: string, options?: FlashcoreOptions): Promise; /** * Loads all user records for a guild * Fetches in parallel for better performance with large member sets * Used for leaderboard generation and bulk operations * * @param guildId - Guild ID * @param options - Store options (defaults to 'default' store) * @returns Map of userId -> UserXP for all tracked members * * @example * // Default store * const allUsers = await getAllUsers('123...') * const sorted = [...allUsers.entries()] * .sort((a, b) => b[1].xp - a[1].xp) * * @example * // Custom store * const reputation = await getAllUsers('123...', { storeId: 'reputation' }) */ export declare function getAllUsers(guildId: string, options?: FlashcoreOptions): Promise>; /** * Adds user ID to tracked members set * Idempotent - safe to call multiple times * * @param guildId - Guild ID * @param userId - User ID to add * @param options - Store options (defaults to 'default' store) */ export declare function addMember(guildId: string, userId: string, options?: FlashcoreOptions): Promise; /** * Removes user ID from tracked members set * Idempotent - safe to call even if user not in set * * @param guildId - Guild ID * @param userId - User ID to remove * @param options - Store options (defaults to 'default' store) */ export declare function removeMember(guildId: string, userId: string, options?: FlashcoreOptions): Promise; /** * Retrieves all tracked member IDs for a guild * * @param guildId - Guild ID * @param options - Store options (defaults to 'default' store) * @returns Set of user IDs (empty if no members tracked) */ export declare function getMembers(guildId: string, options?: FlashcoreOptions): Promise>; /** * Retrieves guild config with caching * Merges stored config with global config and defaults * * @param guildId - Guild ID * @param options - Store options (defaults to 'default' store) * @returns Complete GuildConfig (never null, uses defaults if needed) * * @example * // Default store * const config = await getConfig('123...') * if (config.cooldownSeconds > 0) { ... } * * @example * // Custom store * const repConfig = await getConfig('123...', { storeId: 'reputation' }) */ export declare function getConfig(guildId: string, options?: FlashcoreOptions): Promise; /** * Persists guild config and updates cache * * @param guildId - Guild ID * @param config - Complete GuildConfig to persist * @param options - Store options (defaults to 'default' store) * * @example * // Default store * await putConfig('123...', { * cooldownSeconds: 120, * xpRate: 1.5, * // ... other fields * }) * * @example * // Custom store * await putConfig('123...', config, { storeId: 'reputation' }) */ export declare function putConfig(guildId: string, config: GuildConfig, options?: FlashcoreOptions): Promise; /** * Updates guild config with partial values * Merges with existing config, validates, and persists * * @param guildId - Guild ID * @param partial - Partial config to merge * @param options - Store options (defaults to 'default' store) * @returns Complete merged GuildConfig * * @example * // Default store * const updated = await updateConfig('123...', { * cooldownSeconds: 90 * }) * * @example * // Custom store * const updated = await updateConfig('123...', { xpRate: 2.0 }, { storeId: 'reputation' }) */ export declare function updateConfig(guildId: string, partial: Partial, options?: FlashcoreOptions): Promise; /** * Returns existing config or creates default config for new guild * Merges with global config and persists if created * * @param guildId - Guild ID * @param options - Store options (defaults to 'default' store) * @returns Complete GuildConfig * * @example * // Default store * const config = await getOrInitConfig('123...') // Creates if needed * * @example * // Custom store * const config = await getOrInitConfig('123...', { storeId: 'reputation' }) */ export declare function getOrInitConfig(guildId: string, options?: FlashcoreOptions): Promise; /** * Returns default guild configuration * * @returns GuildConfig with all default values */ export declare function getDefaultConfig(): GuildConfig; /** * Returns default user XP data * * @returns UserXP with all fields initialized to 0 */ export declare function getDefaultUser(): UserXP; /** * Retrieves global configuration defaults * * @returns GlobalConfig (empty object if not set) * * @example * const global = await getGlobalConfig() * if (global.cooldownSeconds) { * console.log('Global cooldown:', global.cooldownSeconds) * } */ export declare function getGlobalConfig(): Promise; /** * Persists global configuration defaults * Clears all guild config caches to force re-merge * * @param config - Partial config to use as global defaults * * @example * await setGlobalConfig({ * cooldownSeconds: 90, * xpRate: 1.2 * }) */ export declare function setGlobalConfig(config: GlobalConfig): Promise; /** * Retrieves schema version for a guild * * @param guildId - Guild ID * @param options - Store options (defaults to 'default' store) * @returns Schema version number (defaults to 1) */ export declare function getSchemaVersion(guildId: string, options?: FlashcoreOptions): Promise; /** * Persists schema version for a guild * Used for future data migrations * * @param guildId - Guild ID * @param version - Schema version number * @param options - Store options (defaults to 'default' store) */ export declare function setSchemaVersion(guildId: string, version: number, options?: FlashcoreOptions): Promise; /** * Validates and normalizes config object from Flashcore * Fills missing fields with defaults * * @param raw - Raw config from Flashcore (may be incomplete) * @param defaults - Default config to fill missing fields * @returns Complete normalized GuildConfig */ export declare function normalizeConfig(raw: unknown, defaults: GuildConfig): GuildConfig; /** * Deep merges two config objects * Override values take precedence over base values * Handles nested multipliers object carefully * * @param base - Base config (lower precedence) * @param override - Override config (higher precedence) * @returns Merged GuildConfig * * @example * const merged = mergeConfigs( * { cooldownSeconds: 60, xpRate: 1.0, multipliers: { server: 1.5 } }, * { cooldownSeconds: 90, multipliers: { role: { '123': 2.0 } } } * ) * // Result: { cooldownSeconds: 90, xpRate: 1.0, multipliers: { server: 1.5, role: { '123': 2.0 } } } */ export declare function mergeConfigs(base: GuildConfig, override: Partial): GuildConfig;