Parse AppConfig with a zod schema

This commit is contained in:
Alex Gleason 2025-07-03 19:04:40 -05:00
parent fce2a3da23
commit 49952a10bf
No known key found for this signature in database
GPG Key ID: 7211D1F99744FBB7
3 changed files with 23 additions and 6 deletions

8
package-lock.json generated
View File

@ -61,7 +61,7 @@
"tailwind-merge": "^2.5.2", "tailwind-merge": "^2.5.2",
"tailwindcss-animate": "^1.0.7", "tailwindcss-animate": "^1.0.7",
"vaul": "^0.9.3", "vaul": "^0.9.3",
"zod": "^3.23.8" "zod": "^3.25.71"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.9.0", "@eslint/js": "^9.9.0",
@ -8244,9 +8244,9 @@
} }
}, },
"node_modules/zod": { "node_modules/zod": {
"version": "3.24.3", "version": "3.25.71",
"resolved": "https://registry.npmjs.org/zod/-/zod-3.24.3.tgz", "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.71.tgz",
"integrity": "sha512-HhY1oqzWCQWuUqvBFnsyrtZRhyPeR7SUGv+C4+MsisMuVfSPx8HpwWqH8tRahSlt6M3PiFAcoeFhZAqIXTxoSg==", "integrity": "sha512-BsBc/NPk7h8WsUWYWYL+BajcJPY8YhjelaWu2NMLuzgraKAz4Lb4/6K11g9jpuDetjMiqhZ6YaexFLOC0Ogi3Q==",
"license": "MIT", "license": "MIT",
"funding": { "funding": {
"url": "https://github.com/sponsors/colinhacks" "url": "https://github.com/sponsors/colinhacks"

View File

@ -63,7 +63,7 @@
"tailwind-merge": "^2.5.2", "tailwind-merge": "^2.5.2",
"tailwindcss-animate": "^1.0.7", "tailwindcss-animate": "^1.0.7",
"vaul": "^0.9.3", "vaul": "^0.9.3",
"zod": "^3.23.8" "zod": "^3.25.71"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.9.0", "@eslint/js": "^9.9.0",

View File

@ -1,4 +1,5 @@
import { ReactNode, useEffect } from 'react'; import { ReactNode, useEffect } from 'react';
import { z } from 'zod';
import { useLocalStorage } from '@/hooks/useLocalStorage'; import { useLocalStorage } from '@/hooks/useLocalStorage';
import { AppContext, type AppConfig, type AppContextType, type Theme } from '@/contexts/AppContext'; import { AppContext, type AppConfig, type AppContextType, type Theme } from '@/contexts/AppContext';
@ -12,6 +13,12 @@ interface AppProviderProps {
presetRelays?: { name: string; url: string }[]; presetRelays?: { name: string; url: string }[];
} }
// Zod schema for AppConfig validation
const AppConfigSchema: z.ZodType<AppConfig> = z.object({
theme: z.enum(['dark', 'light', 'system']),
relayUrl: z.string().url(),
});
export function AppProvider(props: AppProviderProps) { export function AppProvider(props: AppProviderProps) {
const { const {
children, children,
@ -21,7 +28,17 @@ export function AppProvider(props: AppProviderProps) {
} = props; } = props;
// App configuration state with localStorage persistence // App configuration state with localStorage persistence
const [config, setConfig] = useLocalStorage<AppConfig>(storageKey, defaultConfig); const [config, setConfig] = useLocalStorage<AppConfig>(
storageKey,
defaultConfig,
{
serialize: JSON.stringify,
deserialize: (value: string) => {
const parsed = JSON.parse(value);
return AppConfigSchema.parse(parsed);
}
}
);
// Generic config updater with callback pattern // Generic config updater with callback pattern
const updateConfig = (updater: (currentConfig: AppConfig) => AppConfig) => { const updateConfig = (updater: (currentConfig: AppConfig) => AppConfig) => {