deadhead-space-freight-tycoon/apps/server/src/config.ts

46 lines
1.6 KiB
TypeScript

import { z } from "zod";
/** Server settings from environment variables (see `.env.example`). */
const envSchema = z.object({
NODE_ENV: z.enum(["development", "test", "production"]).default("development"),
PORT: z.coerce.number().int().min(0).max(65535).default(3000),
LOG_LEVEL: z.enum(["fatal", "error", "warn", "info", "debug", "trace", "silent"]).default("info"),
DATABASE_URL: z.url(),
TEST_DATABASE_URL: z.url().optional(),
BETTER_AUTH_SECRET: z.string().min(32),
BETTER_AUTH_URL: z.url(),
/** Run background job workers in this process (Step 7.1). */
WORKERS_ENABLED: z.enum(["true", "false"]).default("true"),
});
export interface ServerConfig {
env: "development" | "test" | "production";
port: number;
logLevel: z.infer<typeof envSchema>["LOG_LEVEL"];
databaseUrl: string;
testDatabaseUrl: string | undefined;
authSecret: string;
authUrl: string;
workersEnabled: boolean;
}
/** Validates the environment, throwing one error that lists every problem. */
export function loadConfig(env: Record<string, string | undefined>): ServerConfig {
const result = envSchema.safeParse(env);
if (!result.success) {
const problems = result.error.issues.map((i) => ` ${i.path.join(".")}: ${i.message}`);
throw new Error(`Invalid server environment:\n${problems.join("\n")}`);
}
const e = result.data;
return {
env: e.NODE_ENV,
port: e.PORT,
logLevel: e.LOG_LEVEL,
databaseUrl: e.DATABASE_URL,
testDatabaseUrl: e.TEST_DATABASE_URL,
authSecret: e.BETTER_AUTH_SECRET,
authUrl: e.BETTER_AUTH_URL,
workersEnabled: e.WORKERS_ENABLED === "true",
};
}