type ConfigScope = "global" | "user" | "both"; type ConfigValueType = "string" | "number" | "boolean" | "json"; export type SupportedValue = string | number | boolean | Record | unknown[]; export type ConfigDefinition = { key: string; scope: ConfigScope; valueType: ConfigValueType; defaultValue: T; userOverridable: boolean; validate?: (value: T) => boolean; }; function defineConfig(config: ConfigDefinition): ConfigDefinition { return config; } const CONFIG_REGISTRY = { siteName: defineConfig({ key: "siteName", scope: "global", valueType: "string", defaultValue: "Person Panel", userOverridable: false, validate: (value: string) => value.trim().length > 0 && value.length <= 64, }), allowRegister: defineConfig({ key: "allowRegister", scope: "global", valueType: "boolean", defaultValue: true, userOverridable: false, }), theme: defineConfig({ key: "theme", scope: "both", valueType: "string", defaultValue: "light", userOverridable: true, validate: (value: string) => ["light", "dark", "system"].includes(value), }), dashboardLayout: defineConfig({ key: "dashboardLayout", scope: "user", valueType: "json", defaultValue: [], userOverridable: true, }), } as const; export type KnownConfigKey = keyof typeof CONFIG_REGISTRY; type KnownConfigDefinition = (typeof CONFIG_REGISTRY)[K]; export type KnownConfigValue = KnownConfigDefinition["defaultValue"]; export type KnownConfigItem = (typeof CONFIG_REGISTRY)[KnownConfigKey]; export const KNOWN_CONFIG_KEYS = Object.keys(CONFIG_REGISTRY) as KnownConfigKey[]; export function isKnownConfigKey(key: string): key is KnownConfigKey { return key in CONFIG_REGISTRY; } export function getConfigDefinition(key: K): KnownConfigDefinition { return CONFIG_REGISTRY[key]; } export function getConfigDefaultValue(key: K): KnownConfigValue { return CONFIG_REGISTRY[key].defaultValue; } export function getConfigScope(key: K) { return CONFIG_REGISTRY[key].scope; } export function canUserOverride(key: K) { return CONFIG_REGISTRY[key].userOverridable; } export function getConfigValueType(key: K) { return CONFIG_REGISTRY[key].valueType; } function isSupportedValueType(valueType: ConfigValueType, value: unknown) { if (valueType === "string") return typeof value === "string"; if (valueType === "number") return typeof value === "number" && Number.isFinite(value); if (valueType === "boolean") return typeof value === "boolean"; if (valueType === "json") return value !== undefined; return false; } export function validateConfigValue(key: K, value: unknown): value is KnownConfigValue { const definition = getConfigDefinition(key); if (!isSupportedValueType(definition.valueType, value)) { return false; } const validator = (definition as ConfigDefinition>).validate; if (!validator) { return true; } return validator(value as KnownConfigValue); } export function serializeConfigValue(key: K, value: KnownConfigValue): string { const valueType = getConfigValueType(key); if (valueType === "json") { return JSON.stringify(value); } return String(value); } export function deserializeConfigValue(key: K, rawValue: string): KnownConfigValue { const valueType = getConfigValueType(key); switch (valueType) { case "string": return rawValue as KnownConfigValue; case "number": return Number(rawValue) as unknown as KnownConfigValue; case "boolean": return (rawValue === "true") as unknown as KnownConfigValue; case "json": default: return JSON.parse(rawValue) as KnownConfigValue; } }