/** * Environment variable validation */ import { z } from 'zod'; /** * Environment variable schema */ const envSchema = z.object({ // Node environment NODE_ENV: z.enum(['development', 'staging', 'production']).default('development'), // Server configuration PORT: z.string().transform(Number).pipe(z.number().int().positive()).default('3000'), // Database DATABASE_URL: z.string().url(), // Storage (S3/GCS) STORAGE_TYPE: z.enum(['s3', 'gcs']).default('s3'), STORAGE_BUCKET: z.string(), STORAGE_REGION: z.string().default('us-east-1'), AWS_ACCESS_KEY_ID: z.string().optional(), AWS_SECRET_ACCESS_KEY: z.string().optional(), GCP_PROJECT_ID: z.string().optional(), GCP_KEY_FILE: z.string().optional(), // KMS KMS_TYPE: z.enum(['aws', 'gcp']).default('aws'), KMS_KEY_ID: z.string(), KMS_REGION: z.string().default('us-east-1'), // Authentication JWT_SECRET: z.string().min(32), OIDC_ISSUER: z.string().url().optional(), OIDC_CLIENT_ID: z.string().optional(), OIDC_CLIENT_SECRET: z.string().optional(), VC_ISSUER_DID: z.string().optional(), VC_ISSUER_DOMAIN: z.string().optional(), SWAGGER_SERVER_URL: z.string().url().optional(), // eIDAS EIDAS_PROVIDER_URL: z.string().url().optional(), EIDAS_API_KEY: z.string().optional(), // Credential Rate Limiting CREDENTIAL_RATE_LIMIT_PER_USER: z.string().optional(), CREDENTIAL_RATE_LIMIT_PER_IP: z.string().optional(), // CORS CORS_ORIGIN: z.string().optional(), // Logging LOG_LEVEL: z.enum(['fatal', 'error', 'warn', 'info', 'debug', 'trace']).default('info'), // Monitoring OTEL_EXPORTER_OTLP_ENDPOINT: z.string().url().optional(), OTEL_SERVICE_NAME: z.string().optional(), // Payment Gateway PAYMENT_GATEWAY_API_KEY: z.string().optional(), PAYMENT_GATEWAY_WEBHOOK_SECRET: z.string().optional(), // OCR Service OCR_SERVICE_URL: z.string().url().optional(), OCR_SERVICE_API_KEY: z.string().optional(), // ML Classification ML_CLASSIFICATION_SERVICE_URL: z.string().url().optional(), ML_CLASSIFICATION_API_KEY: z.string().optional(), // Redis/Cache REDIS_URL: z.string().url().optional(), // Message Queue MESSAGE_QUEUE_URL: z.string().url().optional(), // Notifications EMAIL_PROVIDER: z.enum(['smtp', 'sendgrid', 'ses', 'sendinblue']).optional(), EMAIL_API_KEY: z.string().optional(), EMAIL_FROM: z.string().email().optional(), EMAIL_FROM_NAME: z.string().optional(), SMS_PROVIDER: z.enum(['twilio', 'aws-sns', 'nexmo']).optional(), SMS_API_KEY: z.string().optional(), SMS_FROM_NUMBER: z.string().optional(), PUSH_PROVIDER: z.enum(['fcm', 'apns', 'web-push']).optional(), PUSH_API_KEY: z.string().optional(), // Credential URLs CREDENTIALS_URL: z.string().url().optional(), RENEWAL_URL: z.string().url().optional(), // Compliance providers KYC_PROVIDER_URL: z.string().url().optional(), AML_PROVIDER_URL: z.string().url().optional(), SANCTIONS_PROVIDER_URL: z.string().url().optional(), // KYC Provider (Veriff) VERIFF_API_KEY: z.string().optional(), VERIFF_API_URL: z.string().url().optional(), VERIFF_WEBHOOK_SECRET: z.string().optional(), // Sanctions Provider (ComplyAdvantage) SANCTIONS_API_KEY: z.string().optional(), SANCTIONS_API_URL: z.string().url().optional(), // eResidency Service ERESIDENCY_SERVICE_URL: z.string().url().optional(), // DSB Configuration DSB_ISSUER_DID: z.string().optional(), DSB_ISSUER_DOMAIN: z.string().optional(), DSB_SCHEMA_REGISTRY_URL: z.string().url().optional(), // Secrets Management SECRETS_PROVIDER: z.enum(['aws', 'gcp', 'env']).optional(), SECRETS_CACHE_TTL: z.string().transform(Number).pipe(z.number().int().positive()).optional(), }); /** * Validated environment variables */ export type Env = z.infer; let env: Env | null = null; /** * Get validated environment variables */ export function getEnv(): Env { if (env) { return env; } try { env = envSchema.parse(process.env); return env; } catch (error) { if (error instanceof z.ZodError) { const missing = error.errors.map((e) => `${e.path.join('.')}: ${e.message}`).join(', '); throw new Error(`Invalid environment variables: ${missing}`); } throw error; } } /** * Validate environment variables on module load */ getEnv();