You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
122 lines
4.0 KiB
122 lines
4.0 KiB
type ConfigScope = "global" | "user" | "both";
|
|
type ConfigValueType = "string" | "number" | "boolean" | "json";
|
|
export type SupportedValue = string | number | boolean | Record<string, unknown> | unknown[];
|
|
|
|
export type ConfigDefinition<T extends SupportedValue = SupportedValue> = {
|
|
key: string;
|
|
scope: ConfigScope;
|
|
valueType: ConfigValueType;
|
|
defaultValue: T;
|
|
userOverridable: boolean;
|
|
validate?: (value: T) => boolean;
|
|
};
|
|
|
|
function defineConfig<T extends SupportedValue>(config: ConfigDefinition<T>): ConfigDefinition<T> {
|
|
return config;
|
|
}
|
|
|
|
const CONFIG_REGISTRY = {
|
|
siteName: defineConfig<string>({
|
|
key: "siteName",
|
|
scope: "global",
|
|
valueType: "string",
|
|
defaultValue: "Person Panel",
|
|
userOverridable: false,
|
|
validate: (value: string) => value.trim().length > 0 && value.length <= 64,
|
|
}),
|
|
allowRegister: defineConfig<boolean>({
|
|
key: "allowRegister",
|
|
scope: "global",
|
|
valueType: "boolean",
|
|
defaultValue: true,
|
|
userOverridable: false,
|
|
}),
|
|
theme: defineConfig<string>({
|
|
key: "theme",
|
|
scope: "both",
|
|
valueType: "string",
|
|
defaultValue: "light",
|
|
userOverridable: true,
|
|
validate: (value: string) => ["light", "dark", "system"].includes(value),
|
|
}),
|
|
dashboardLayout: defineConfig<unknown[]>({
|
|
key: "dashboardLayout",
|
|
scope: "user",
|
|
valueType: "json",
|
|
defaultValue: [],
|
|
userOverridable: true,
|
|
}),
|
|
} as const;
|
|
|
|
export type KnownConfigKey = keyof typeof CONFIG_REGISTRY;
|
|
type KnownConfigDefinition<K extends KnownConfigKey> = (typeof CONFIG_REGISTRY)[K];
|
|
export type KnownConfigValue<K extends KnownConfigKey> = KnownConfigDefinition<K>["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<K extends KnownConfigKey>(key: K): KnownConfigDefinition<K> {
|
|
return CONFIG_REGISTRY[key];
|
|
}
|
|
|
|
export function getConfigDefaultValue<K extends KnownConfigKey>(key: K): KnownConfigValue<K> {
|
|
return CONFIG_REGISTRY[key].defaultValue;
|
|
}
|
|
|
|
export function getConfigScope<K extends KnownConfigKey>(key: K) {
|
|
return CONFIG_REGISTRY[key].scope;
|
|
}
|
|
|
|
export function canUserOverride<K extends KnownConfigKey>(key: K) {
|
|
return CONFIG_REGISTRY[key].userOverridable;
|
|
}
|
|
|
|
export function getConfigValueType<K extends KnownConfigKey>(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<K extends KnownConfigKey>(key: K, value: unknown): value is KnownConfigValue<K> {
|
|
const definition = getConfigDefinition(key);
|
|
if (!isSupportedValueType(definition.valueType, value)) {
|
|
return false;
|
|
}
|
|
const validator = (definition as ConfigDefinition<KnownConfigValue<K>>).validate;
|
|
if (!validator) {
|
|
return true;
|
|
}
|
|
return validator(value as KnownConfigValue<K>);
|
|
}
|
|
|
|
export function serializeConfigValue<K extends KnownConfigKey>(key: K, value: KnownConfigValue<K>): string {
|
|
const valueType = getConfigValueType(key);
|
|
if (valueType === "json") {
|
|
return JSON.stringify(value);
|
|
}
|
|
return String(value);
|
|
}
|
|
|
|
export function deserializeConfigValue<K extends KnownConfigKey>(key: K, rawValue: string): KnownConfigValue<K> {
|
|
const valueType = getConfigValueType(key);
|
|
switch (valueType) {
|
|
case "string":
|
|
return rawValue as KnownConfigValue<K>;
|
|
case "number":
|
|
return Number(rawValue) as unknown as KnownConfigValue<K>;
|
|
case "boolean":
|
|
return (rawValue === "true") as unknown as KnownConfigValue<K>;
|
|
case "json":
|
|
default:
|
|
return JSON.parse(rawValue) as KnownConfigValue<K>;
|
|
}
|
|
}
|
|
|