/** * @fileoverview Centralized Zod validation schemas for all Aurora API endpoints. * Provides type-safe request/response validation for every entity in the system. */ import { z } from "zod"; // ============================================================================ // Common Schemas // ============================================================================ /** * Standard pagination query parameters. */ export const PaginationSchema = z.object({ limit: z.coerce.number().min(1).max(100).optional().default(50), offset: z.coerce.number().min(0).optional().default(0), }); /** * Numeric ID parameter validation. */ export const NumericIdSchema = z.coerce.number().int().positive(); /** * Discord snowflake ID validation (string of digits). */ export const SnowflakeIdSchema = z.string().regex(/^\d{17,20}$/, "Invalid Discord ID format"); // ============================================================================ // Items Schemas // ============================================================================ /** * Valid item types in the system. */ export const ItemTypeEnum = z.enum([ "CONSUMABLE", "EQUIPMENT", "MATERIAL", "LOOTBOX", "COLLECTIBLE", "KEY", "TOOL" ]); /** * Valid item rarities. */ export const ItemRarityEnum = z.enum(["C", "R", "SR", "SSR"]); /** * Query parameters for listing items. */ export const ItemQuerySchema = PaginationSchema.extend({ search: z.string().optional(), type: z.string().optional(), rarity: z.string().optional(), }); /** * Schema for creating a new item. */ export const CreateItemSchema = z.object({ name: z.string().min(1, "Name is required").max(100), description: z.string().max(500).nullable().optional(), rarity: ItemRarityEnum.optional().default("C"), type: ItemTypeEnum, price: z.union([z.string(), z.number()]).nullable().optional(), iconUrl: z.string().optional(), imageUrl: z.string().optional(), usageData: z.any().nullable().optional(), }); /** * Schema for updating an existing item. */ export const UpdateItemSchema = z.object({ name: z.string().min(1).max(100).optional(), description: z.string().max(500).nullable().optional(), rarity: ItemRarityEnum.optional(), type: ItemTypeEnum.optional(), price: z.union([z.string(), z.number()]).nullable().optional(), iconUrl: z.string().optional(), imageUrl: z.string().optional(), usageData: z.any().nullable().optional(), }); // ============================================================================ // Users Schemas // ============================================================================ /** * Query parameters for listing users. */ export const UserQuerySchema = PaginationSchema.extend({ search: z.string().optional(), sortBy: z.enum(["balance", "level", "xp", "username"]).optional().default("balance"), sortOrder: z.enum(["asc", "desc"]).optional().default("desc"), }); /** * Schema for updating a user. */ export const UpdateUserSchema = z.object({ username: z.string().min(1).max(32).optional(), balance: z.union([z.string(), z.number()]).optional(), xp: z.union([z.string(), z.number()]).optional(), level: z.coerce.number().int().min(0).optional(), dailyStreak: z.coerce.number().int().min(0).optional(), isActive: z.boolean().optional(), settings: z.record(z.string(), z.any()).optional(), classId: z.union([z.string(), z.number()]).optional(), }); /** * Schema for adding an item to user inventory. */ export const InventoryAddSchema = z.object({ itemId: z.coerce.number().int().positive("Item ID is required"), quantity: z.union([z.string(), z.number()]).refine( (val) => BigInt(val) > 0n, "Quantity must be positive" ), }); /** * Query params for removing inventory items. */ export const InventoryRemoveQuerySchema = z.object({ amount: z.coerce.number().int().min(1).optional().default(1), }); // ============================================================================ // Classes Schemas // ============================================================================ /** * Schema for creating a new class. */ export const CreateClassSchema = z.object({ id: z.union([z.string(), z.number()]), name: z.string().min(1, "Name is required").max(50), balance: z.union([z.string(), z.number()]).optional().default("0"), roleId: z.string().nullable().optional(), }); /** * Schema for updating a class. */ export const UpdateClassSchema = z.object({ name: z.string().min(1).max(50).optional(), balance: z.union([z.string(), z.number()]).optional(), roleId: z.string().nullable().optional(), }); // ============================================================================ // Moderation Schemas // ============================================================================ /** * Valid moderation case types. */ export const ModerationTypeEnum = z.enum([ "warn", "timeout", "kick", "ban", "note", "prune" ]); /** * Query parameters for searching moderation cases. */ export const CaseQuerySchema = PaginationSchema.extend({ userId: z.string().optional(), moderatorId: z.string().optional(), type: ModerationTypeEnum.optional(), active: z.preprocess( (val) => val === "true" ? true : val === "false" ? false : undefined, z.boolean().optional() ), }); /** * Schema for creating a moderation case. */ export const CreateCaseSchema = z.object({ type: ModerationTypeEnum, userId: z.string().min(1, "User ID is required"), username: z.string().min(1, "Username is required"), moderatorId: z.string().min(1, "Moderator ID is required"), moderatorName: z.string().min(1, "Moderator name is required"), reason: z.string().min(1, "Reason is required").max(1000), metadata: z.record(z.string(), z.any()).optional().default({}), }); /** * Schema for clearing/resolving a moderation case. */ export const ClearCaseSchema = z.object({ clearedBy: z.string().min(1, "Cleared by ID is required"), clearedByName: z.string().min(1, "Cleared by name is required"), reason: z.string().max(500).optional().default("Cleared via API"), }); /** * Case ID pattern validation (CASE-XXXX format). */ export const CaseIdPattern = /^CASE-\d+$/i; // ============================================================================ // Transactions Schemas // ============================================================================ /** * Query parameters for listing transactions. */ export const TransactionQuerySchema = PaginationSchema.extend({ userId: z.string().optional(), type: z.string().optional(), }); // ============================================================================ // Lootdrops Schemas // ============================================================================ /** * Query parameters for listing lootdrops. */ export const LootdropQuerySchema = z.object({ limit: z.coerce.number().min(1).max(100).optional().default(50), }); /** * Schema for spawning a lootdrop. */ export const CreateLootdropSchema = z.object({ channelId: z.string().min(1, "Channel ID is required"), amount: z.coerce.number().int().positive().optional(), currency: z.string().optional(), }); // ============================================================================ // Admin Actions Schemas // ============================================================================ /** * Schema for toggling maintenance mode. */ export const MaintenanceModeSchema = z.object({ enabled: z.boolean(), reason: z.string().max(200).optional(), }); // ============================================================================ // Type Exports // ============================================================================ export type ItemQuery = z.infer; export type CreateItem = z.infer; export type UpdateItem = z.infer; export type UserQuery = z.infer; export type UpdateUser = z.infer; export type InventoryAdd = z.infer; export type CreateClass = z.infer; export type UpdateClass = z.infer; export type CaseQuery = z.infer; export type CreateCase = z.infer; export type ClearCase = z.infer; export type TransactionQuery = z.infer; export type CreateLootdrop = z.infer; export type MaintenanceMode = z.infer;