moved to zod, packages messed up still

This commit is contained in:
Bojan Kucera 2025-06-07 14:24:28 -04:00
parent 15dd03c0ec
commit a8ee4022bf
35 changed files with 3245 additions and 691 deletions

View file

@ -0,0 +1,91 @@
/**
* Environment validation utilities using Zod
*/
import { z } from 'zod';
import { config } from 'dotenv';
// Load environment variables
config();
/**
* Creates a Zod schema for environment variable validation
*/
export function createEnvSchema<T extends z.ZodRawShape>(shape: T) {
return z.object(shape);
}
/**
* Validates environment variables against a Zod schema
*/
export function validateEnv<T extends z.ZodRawShape>(
schema: z.ZodObject<T>,
env = process.env
): z.infer<z.ZodObject<T>> {
const result = schema.safeParse(env);
if (!result.success) {
console.error('❌ Invalid environment variables:');
result.error.issues.forEach((issue: any) => {
console.error(` ${issue.path.join('.')}: ${issue.message}`);
});
throw new Error('Environment validation failed');
}
return result.data;
}
/**
* Helper functions for common validation patterns
*/
export const envValidators = { // String with default
str: (defaultValue?: string, description?: string) =>
z.string().default(defaultValue || '').describe(description || ''),
// String with choices (enum)
strWithChoices: (choices: string[], defaultValue?: string, description?: string) =>
z.enum(choices as [string, ...string[]])
.default((defaultValue || choices[0]) as any)
.describe(description || ''),
// Required string
requiredStr: (description?: string) =>
z.string().min(1, 'Required').describe(description || ''),
// Port number
port: (defaultValue?: number, description?: string) =>
z.string().transform((val: string) => parseInt(val, 10))
.pipe(z.number().int().min(1).max(65535))
.default(defaultValue?.toString() || '3000')
.describe(description || ''),
// Number with default
num: (defaultValue?: number, description?: string) =>
z.string().transform((val: string) => parseInt(val, 10))
.pipe(z.number())
.default(defaultValue?.toString() || '0')
.describe(description || ''),
// Boolean with default
bool: (defaultValue?: boolean, description?: string) =>
z.string().transform((val: string) => val === 'true' || val === '1')
.default(defaultValue?.toString() || 'false')
.describe(description || ''),
// URL validation
url: (defaultValue?: string, description?: string) =>
z.string().url().default(defaultValue || 'http://localhost')
.describe(description || ''),
// Email validation
email: (description?: string) =>
z.string().email().describe(description || ''),
};
/**
* Legacy compatibility - creates a cleanEnv-like function
*/
export function cleanEnv<T extends z.ZodRawShape>(
env: Record<string, string | undefined>,
validators: T
): z.infer<z.ZodObject<T>> {
const schema = createEnvSchema(validators);
return validateEnv(schema, env);
}