import 'dotenv/config'; import { z } from 'zod'; /** * The configuration schema for the server. */ const configSchema = z.object({ /** * The database configuration. */ database: z.object({ path: z.string().default('data.db'), }), /** * The server configuration. */ server: z.object({ port: z.coerce.number().int() .positive() .default(3000), host: z.string().default('0.0.0.0'), /** Maximum encoded HTTP body or WebSocket message size in bytes. */ maxRequestBodyBytes: z.coerce .number() .int() .positive() .default(1024 * 1024), cors: z .object({ origin: z.string().default('*'), methods: z.array(z.string()).default([ 'GET', 'POST', 'PUT', 'DELETE', 'OPTIONS' ]), allowedHeaders: z.array(z.string()).default([ 'Content-Type', 'cache-control', 'X-Timestamp', 'X-PublicKey', 'X-Signature' ]), }) .partial() .prefault({}), }), /** * The authentication configuration. */ auth: z .object({ timestampWindowMs: z.coerce .number() .int() .positive() .default(5 * 60 * 1000), }) .prefault({}), }); /** Raw configuration object accepted before Zod parsing. */ type ConfigInput = z.input; /** Fully parsed and defaulted configuration shape. */ type ConfigSchema = z.output; /** * Typed, validated server configuration loaded from environment or objects. */ export class Config { /** * Creates a new Config from the environment variables. * @returns The Config. */ static fromEnv(): Config { return this.from({ database: { path: process.env.DATABASE_PATH, }, server: { port: process.env.SERVER_PORT, maxRequestBodyBytes: process.env.SERVER_MAX_REQUEST_BODY_BYTES, host: process.env.SERVER_HOST, cors: { origin: process.env.CORS_ORIGIN, methods: process.env.CORS_METHODS?.split(','), allowedHeaders: process.env.CORS_ALLOWED_HEADERS?.split(','), }, }, auth: { timestampWindowMs: process.env.AUTH_TIMESTAMP_WINDOW_MS ? Number(process.env.AUTH_TIMESTAMP_WINDOW_MS) : undefined, }, }); } /** * Creates a new Config from a configuration object. * @param config - The configuration object. * @returns The Config. */ static from(config: ConfigInput): Config { return new Config(configSchema.parse(config)); } /** * Gets the database configuration. * @returns The database configuration. */ public get database(): Readonly { return this.config.database; } /** * Gets the server configuration. * @returns The server configuration. */ public get server(): Readonly { return this.config.server; } /** * Gets the authentication configuration. * @returns The authentication configuration. */ public get auth(): Readonly { return this.config.auth; } /** * @param config - Parsed configuration produced by the Zod schema. */ private constructor(private readonly config: ConfigSchema) {} }