Source

config/env.js

import { config as dotenvConfig } from "dotenv";
import { z } from "zod";
// Load environment variables from .env file, if available
dotenvConfig({ quiet: true });
/**
 * Environment variables schema and validation for K12 Auth Service.
 * Defines the expected shape of environment variables.
 * Uses `zod` for schema definition and runtime validation.
 * All variables are required unless a default value is provided.
 * Use {@link env} instead of accessing `process.env` directly.
 * @see https://github.com/colinhacks/zod
 */
const envSchema = z.object({
    /** HTTP server port */
    PORT: z.coerce.number().default(3001),
    /** gRPC server port */
    GRPC_PORT: z.coerce.number().default(50051),
    /** Node.js environment (development, production, test) */
    NODE_ENV: z.enum(["development", "local", "production", "test"]).default("local"),
    /** Environment prefix for GCS paths (qa, dev, etc.) */
    ENV_PREFIX: z.string().optional().default(""),
    /** MongoDB connection URI - must be provided */
    MONGODB_URI: z.string().url().default("mongodb://localhost:27017/k12_auth"),
    /** Redis connection URI - must be provided */
    REDIS_URI: z.string().url().default("redis://localhost:6379"),
    /** Redis database index */
    REDIS_DB_INDEX: z.coerce.number().int().min(0).default(0),
    /** JWT Configuration */
    JWT_EXPIRES_IN: z
        .string()
        .default("1h")
        .transform((val) => val),
    JWT_REFRESH_EXPIRES_IN: z
        .string()
        .default("7d")
        .transform((val) => val),
    JWT_SECRET: z.string().default("secret"),
    JWT_REFRESH_SECRET: z.string().default("refresh-secret"),
    /** HashiCorp Vault Configuration */
    /** HashiCorp Vault server URL */
    VAULT_URL: z.string().url().default("http://localhost:8200"),
    /** HashiCorp Vault authentication token */
    VAULT_TOKEN: z.string().optional(),
    /** HashiCorp Vault role ID for AppRole auth */
    VAULT_ROLE_ID: z.string().optional(),
    /** HashiCorp Vault secret ID for AppRole auth */
    VAULT_SECRET_ID: z.string().optional(),
    /** HashiCorp Vault secrets engine mount path */
    VAULT_MOUNT_PATH: z.string().default("secret"),
    /** HashiCorp Vault API version */
    VAULT_API_VERSION: z.enum(["v1", "v2"]).default("v1"),
    /** Google Cloud Storage Configuration */
    GCS_BUCKET_NAME: z.string().default("k12-auth-avatars"),
    GCS_PROJECT_ID: z.string().optional(),
    /** Avatar Image Processing Configuration */
    AVATAR_SIZE: z.coerce.number().int().min(128).max(2048).default(512),
    AVATAR_QUALITY: z.coerce.number().int().min(1).max(100).default(80),
    AVATAR_MAX_SIZE_MB: z.coerce.number().int().min(1).max(50).default(10),
    AVATAR_FORMAT: z.enum(["webp", "jpeg", "png"]).default("webp"),
    AVATAR_COMPRESSION_EFFORT: z.coerce.number().int().min(0).max(6).default(6),
    /** Rate Limiting Configuration */
    RATE_LIMIT_WINDOW_MS: z
        .string()
        .transform((val) => parseInt(val, 10))
        .pipe(z.number().min(1000))
        .default("900000"), // 15 minutes
    RATE_LIMIT_MAX_REQUESTS: z
        .string()
        .transform((val) => parseInt(val, 10))
        .pipe(z.number().min(1))
        .default("100"),
    /** CORS Configuration */
    ALLOWED_ORIGINS: z
        .string()
        .default("http://localhost:3000,https://admin-panel.dev.k12.aaic.dev,https://admin-panel.qa.k12.aaic.dev"),
    /** Logging Configuration */
    LOG_LEVEL: z.enum(["error", "warn", "info", "debug"]).default("info"),
    /** SMTP Configuration (optional) */
    SMTP_HOST: z.string().optional(),
    SMTP_PORT: z.coerce.number().optional(),
    SMTP_USER: z.string().optional(),
    SMTP_PASSWORD: z.string().optional(),
    SMTP_FROM: z.string().optional(),
    /** Admin User Configuration */
    ADMIN_EMAIL: z.string().email().default("root-admin@gmail.com"),
    ADMIN_PASSWORD: z.string().min(8).default("admin123456"),
    /** Password Hashing Configuration */
    BCRYPT_SALT_ROUNDS: z
        .string()
        .transform((val) => parseInt(val, 10))
        .pipe(z.number().min(10).max(15))
        .default("12"),
});
/** Parsed and validated environment variables. */
export const env = envSchema.parse(process.env);