import { config } from 'dotenv'; import { z } from 'zod'; config(); const emptyToUndefined = (value: unknown) => value === '' || value === undefined || value === null ? undefined : value; const EnvSchema = z.object({ NODE_ENV: z.enum(['development', 'test', 'production']).default('development'), BOT_TOKEN: z.string().min(1), BOT_CLIENT_ID: z.string().min(1), BOT_GUILD_ID: z.preprocess(emptyToUndefined, z.string().min(1).optional()), DATABASE_URL: z.string().url(), REDIS_URL: z.string().url(), LOG_LEVEL: z.string().default('info'), DEFAULT_LOCALE: z.enum(['de', 'en']).default('de'), BACKUP_RETENTION_DAYS: z.coerce.number().int().positive().default(14), BACKUP_CRON: z.string().default('0 3 * * *'), BACKUP_DIR: z.string().default('/backups'), METRICS_TOKEN: z.preprocess(emptyToUndefined, z.string().min(1).optional()), SENTRY_DSN: z.preprocess(emptyToUndefined, z.string().url().optional()), HEALTH_PORT: z.coerce.number().int().positive().default(8080), PUBLIC_BASE_URL: z.string().url().default('http://localhost:8080'), TWITCH_CLIENT_ID: z.preprocess(emptyToUndefined, z.string().min(1).optional()), TWITCH_CLIENT_SECRET: z.preprocess(emptyToUndefined, z.string().min(1).optional()), OWNER_USER_IDS: z.preprocess( emptyToUndefined, z .string() .optional() .transform((value) => value ? value .split(',') .map((id) => id.trim()) .filter((id) => id.length > 0) : [] ) ), WEBUI_URL: z.preprocess(emptyToUndefined, z.string().url().optional()), SUPPORT_SERVER_URL: z.preprocess(emptyToUndefined, z.string().url().optional()), /// Salt for hashing client IPs in verification alt-detection (shared with WebUI). CAPTCHA_IP_HASH_SALT: z.preprocess(emptyToUndefined, z.string().min(16).optional()) }); export const env = EnvSchema.parse(process.env); export function buildBotInviteUrl(clientId = env.BOT_CLIENT_ID): string { const url = new URL('https://discord.com/api/oauth2/authorize'); url.searchParams.set('client_id', clientId); url.searchParams.set('permissions', '4786708802825463'); url.searchParams.set('scope', 'bot applications.commands'); return url.toString(); }