import { z } from 'zod'; const f = { boolean: (defaultValue?: boolean) => z.boolean().nullish().default(!!defaultValue), number: (defaultValue?: number, val?: (v: z.ZodNumber) => z.ZodNumber) => z.preprocess( v => v === '' || v === undefined ? defaultValue ?? null : typeof v === 'string' ? Number(v) : v, (val?.(z.number()) ?? z.number()).nullish() ) }; export const ConfigWtfSchema = z.object({ vanillaFixes: f.boolean(), largeAddress: f.boolean(true), nameplateRange: f.number(41), alwaysAutoLoot: f.boolean(), fieldOfView: f.number(110), farClip: f.number(777), frillDistance: f.number(70), cameraDistance: f.number(50), soundInBackground: f.boolean(true) }); export type ConfigWtfSchema = z.infer; export const ModStateSchema = z.object({ enabled: z.boolean().default(false), installedVersion: z.string().optional(), installedFiles: z.array(z.string()).default([]), ignoreUpdates: z.boolean().default(false) }); export type ModState = z.infer; export const HardwareInfoSchema = z.object({ totalRamMb: z.number(), cpuCores: z.number(), cpuModel: z.string(), gpuModel: z.string(), vramMb: z.number().nullable(), vramSource: z.enum(['registry', 'wmi', 'none']), detectedAt: z.string(), schemaVersion: z.number() }); export type HardwareInfo = z.infer; export const PreferencesSchema = z.object({ isPortable: z.boolean().optional(), server: z.enum(['live', 'ptr']).default('live'), clientDir: z.string().optional(), version: z.string().optional(), lastPatchedLauncherVersion: z.string().optional(), expectedPatchedWowHash: z.string().optional(), minimizeToTrayOnPlay: f.boolean(true), cleanWdb: f.boolean(true), locale: z .enum(['enUS', 'deDE', 'zhCN', 'esES', 'ptBR', 'ruRU']) .default('enUS'), localePatchLetter: z.string().optional(), localePatchLocale: z.string().optional(), rememberPosition: f.boolean(), windowPosition: z .object({ x: z.number(), y: z.number(), width: z.number(), height: z.number() }) .nullish(), config: ConfigWtfSchema.default({}), mods: z.record(ModStateSchema).default({}), hardware: HardwareInfoSchema.optional(), farClipUserSet: z.boolean().optional() }); export type PreferencesSchema = z.infer; export const TocDataSchema = z.object({ Interface: z.string(), Title: z.string(), Author: z.string(), Notes: z.string(), Version: z.string(), Dependencies: z.string().optional(), OptionalDeps: z.string().optional() }); export type TocData = z.infer; export const AddonDataSchema = z.object({ status: z.enum([ 'available', 'fetching', 'unknown', 'upToDate', 'outOfDate', 'downloading', 'invalid' ]), git: z.string().optional(), toc: TocDataSchema.optional(), description: z.string().optional(), error: z.string().optional(), branch: z.string().optional(), ref: z.string().optional(), folder: z.string(), progress: z.string().optional(), preview: z.string().optional() }); export type AddonData = z.infer; export const NewsItemSchema = z.object({ id: z.string(), title: z.string(), date: z.string(), body: z.string(), url: z.string().url().optional(), author: z.string().nullish() }); export type NewsItem = z.infer; export const NewsFeedSchema = z.object({ items: z.array(NewsItemSchema) }); export type NewsFeed = z.infer; export const ForumAnnouncementSchema = z.object({ id: z.string(), title: z.string(), author: z.string().nullish(), date: z.string(), url: z.string().url(), html: z.string() }); export type ForumAnnouncement = z.infer;