import { z } from 'zod'; /** * Environment contract, validated once at import. * * A missing DATABASE_URL should fail at boot with a readable message, not * surface later as an opaque driver error in the middle of a payroll export. */ const schema = z.object({ NODE_ENV: z.enum(['development', 'test', 'production']).default('development'), DATABASE_URL: z.url({ protocol: /^postgres(ql)?$/ }), /** * Application-level encryption key for the columns PLAN.md §3.6 requires at * rest (NIR, IBAN, BIC). 32 bytes, base64. Kept out of the database so a dump * alone does not disclose them. */ ENCRYPTION_KEY: z .string() .refine( (value) => Buffer.from(value, 'base64').length === 32, 'ENCRYPTION_KEY doit être 32 octets encodés en base64', ), /** Public origin, used for links in invitation and notification e-mails. */ APP_URL: z.url().default('http://localhost:3000'), }); export type Env = z.infer; function load(): Env { const parsed = schema.safeParse(process.env); if (!parsed.success) { const details = parsed.error.issues .map((issue) => ` - ${issue.path.join('.')}: ${issue.message}`) .join('\n'); throw new Error(`Configuration d'environnement invalide :\n${details}`); } return parsed.data; } export const env = load();