/
githubmirror
/
novu
Обзор
Документация
Войти
/
githubmirror
/
novu
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
next
apps/api/src/config/env.validators.ts
187 строк
8 KB
Himanshu Garg
refactor(api, worker): remove Cloudflare Scheduler integration and related configurations fixes NV-8518 (#12216)
04 авг 2026, 15:17
Не верифицирован
04 авг 2026, 15:17
7d0c0bd
Код
Авторство
О чём код?
import { DEFAULT_NOTIFICATION_RETENTION_DAYS, FeatureFlagsKeysEnum, StringifyEnv } from '@novu/shared'; import { bool, CleanedEnv, cleanEnv, json, num, port, str, url, ValidatorSpec } from 'envalid'; export function validateEnv() { return cleanEnv(process.env, envValidators); } export type ValidatedEnv = StringifyEnv<CleanedEnv<typeof envValidators>>; const processEnv = process.env as Record<string, string>; // Hold the initial process.env to avoid circular reference function getFeatureFlagValidator(key: FeatureFlagsKeysEnum): ValidatorSpec<string | number | boolean | undefined> { if (key.endsWith('_NUMBER') || key === FeatureFlagsKeysEnum.MAX_ENVIRONMENT_COUNT) { return num({ default: undefined }); } if (key.startsWith('IS_')) { return bool({ default: false }); } return str({ default: undefined }); } // Managed-agent (Thalamus) config is a Novu Cloud concern. On self-hosted (or whenever the URL is // blank) we must not run envalid's `url()` validator, which rejects an empty string even with a // default — a blank `THALAMUS_CF_URL=` is common in self-hosted .env files and would block boot. function getThalamusValidators(): { THALAMUS_CF_URL: ValidatorSpec<string>; THALAMUS_WEBHOOK_SECRET: ValidatorSpec<string>; } { if (processEnv.IS_SELF_HOSTED === 'true' || !processEnv.THALAMUS_CF_URL) { return { THALAMUS_CF_URL: str({ default: undefined }), THALAMUS_WEBHOOK_SECRET: str({ default: undefined }), }; } return { THALAMUS_CF_URL: url(), THALAMUS_WEBHOOK_SECRET: str(), }; } export const envValidators = { TZ: str({ default: 'UTC' }), NODE_ENV: str({ choices: ['dev', 'test', 'production', 'ci', 'local'], default: 'local' }), LOG_LEVEL: str({ choices: ['trace', 'debug', 'info', 'warn', 'error', 'fatal', 'none'] }), PORT: port(), FRONT_BASE_URL: str(), DASHBOARD_URL: str({ default: '' }), DISABLE_USER_REGISTRATION: bool({ default: false }), REDIS_HOST: str(), REDIS_PORT: port(), REDIS_TLS: json({ default: undefined }), REDIS_MASTER_HOST: str({ default: '' }), REDIS_MASTER_PORT: str({ default: '' }), REDIS_SLAVE_HOST: str({ default: '' }), REDIS_SLAVE_PORT: str({ default: '' }), JWT_SECRET: str(), SENDGRID_API_KEY: str({ default: '' }), MONGO_AUTO_CREATE_INDEXES: bool({ default: false }), MONGO_MAX_IDLE_TIME_IN_MS: num({ default: 1000 * 30 }), MONGO_MAX_POOL_SIZE: num({ default: 50 }), MONGO_MIN_POOL_SIZE: num({ default: 10 }), MONGO_URL: str(), NOVU_API_KEY: str({ default: '' }), STORE_ENCRYPTION_KEY: str(), REDIS_CACHE_SERVICE_HOST: str({ default: '' }), REDIS_CACHE_SERVICE_PORT: str({ default: '' }), REDIS_CACHE_SERVICE_TLS: json({ default: undefined }), REDIS_CLUSTER_SERVICE_HOST: str({ default: '' }), REDIS_CLUSTER_SERVICE_PORTS: str({ default: '' }), STORE_NOTIFICATION_CONTENT: bool({ default: false }), WORKER_DEFAULT_CONCURRENCY: num({ default: undefined }), WORKER_DEFAULT_LOCK_DURATION: num({ default: undefined }), ENABLE_OTEL: bool({ default: false }), ENABLE_OTEL_LOGS: bool({ default: false }), OTEL_PROMETHEUS_PORT: num({ default: 9464 }), NOTIFICATION_RETENTION_DAYS: num({ default: DEFAULT_NOTIFICATION_RETENTION_DAYS }), API_ROOT_URL: url(), NOVU_INVITE_TEAM_MEMBER_NUDGE_TRIGGER_IDENTIFIER: str({ default: undefined }), SUBSCRIBER_WIDGET_JWT_EXPIRATION_TIME: str({ default: '15 days' }), NOVU_REGION: str({ default: 'local' }), NOVU_SECRET_KEY: str({ default: '' }), INTERNAL_SERVICES_API_KEY: str({ default: undefined }), STEP_RESOLVER_CF_ACCOUNT_ID: str({ default: undefined }), STEP_RESOLVER_CF_API_TOKEN: str({ default: undefined }), STEP_RESOLVER_CF_DISPATCH_NAMESPACE: str({ default: undefined }), STEP_RESOLVER_CF_PLACEMENT_REGION: str({ default: undefined }), STEP_RESOLVER_DISPATCH_URL: str({ default: undefined }), STEP_RESOLVER_HMAC_SECRET: str({ default: '' }), THALAMUS_CF_API_KEY: str({ default: undefined }), ...getThalamusValidators(), /** * Shared inbound domain for the agent default inbox feature, e.g. `agentconnect.sh`. * When unset the feature is disabled and the worker falls through to the existing * per-tenant Domain/DomainRoute lookup. */ NOVU_AGENT_SHARED_INBOUND_DOMAIN: str({ default: undefined }), NOVU_WHATSAPP_APP_ID: str({ default: undefined }), NOVU_WHATSAPP_APP_SECRET: str({ default: undefined }), NOVU_WHATSAPP_CONFIG_ID: str({ default: undefined }), NOVU_MANAGED_CLAUDE_API_KEY: str({ default: undefined }), MAX_NOVU_MANAGED_CLAUDE_CONVERSATIONS: num({ default: 10 }), MAX_NOVU_MANAGED_CLAUDE_TOKENS_PER_CONVERSATION: num({ default: 100_000 }), // Novu Cloud third party services ...(processEnv.IS_SELF_HOSTED !== 'true' && processEnv.NOVU_ENTERPRISE === 'true' && { HUBSPOT_INVITE_NUDGE_EMAIL_USER_LIST_ID: str({ default: undefined }), HUBSPOT_PRIVATE_APP_ACCESS_TOKEN: str({ default: undefined }), LAUNCH_DARKLY_SDK_KEY: str({ default: '' }), NEW_RELIC_APP_NAME: str({ default: '' }), NEW_RELIC_LICENSE_KEY: str({ default: '' }), PLAIN_SUPPORT_KEY: str({ default: undefined }), PLAIN_IDENTITY_VERIFICATION_SECRET_KEY: str({ default: undefined }), PLAIN_CARDS_HMAC_SECRET_KEY: str({ default: undefined }), STRIPE_API_KEY: str({ default: undefined }), STRIPE_CONNECT_SECRET: str({ default: undefined }), NOVU_INTERNAL_SECRET_KEY: str({ default: '' }), KEYLESS_ORGANIZATION_ID: str({ desc: 'Required organizationId for Keyless authentication', default: undefined }), KEYLESS_USER_EMAIL: str({ desc: 'Required email for Keyless authentication', default: undefined }), KEYLESS_ENV_CREATE_CAP_PER_IP_PER_DAY: num({ default: 15 }), KEYLESS_GENERATE_CAP_PER_IP_PER_DAY: num({ default: 5 }), KEYLESS_MAX_AGENTS_PER_ENV: num({ default: 2 }), // ClickHouse CLICK_HOUSE_URL: str({ default: '' }), CLICK_HOUSE_DATABASE: str({ default: '' }), CLICK_HOUSE_USER: str({ default: '' }), CLICK_HOUSE_PASSWORD: str({ default: '' }), // AI/LLM Configuration AI_LLM_PROVIDER: str({ choices: ['openai', 'anthropic'], default: 'openai' }), AI_LLM_API_KEY: str({ default: '' }), AI_LLM_MODEL: str({ default: '' }), AI_LLM_MAX_OUTPUT_TOKENS: num({ default: 8192 }), AI_LLM_TEMPERATURE: num({ default: 0.7 }), AI_LLM_MAX_RETRIES: num({ default: 3 }), AI_LLM_SERVICE_TIER: str({ choices: ['auto', 'default', 'flex', 'priority'], default: 'priority' }), AI_LLM_PROMPT_CACHE_RETENTION: str({ choices: ['in-memory', '24h'], default: '24h' }), // Brand enrichment CONTEXT_DEV_API_KEY: str({ default: '' }), ...(['production', 'dev'].includes(processEnv.NODE_ENV) ? { THALAMUS_CF_API_KEY: str(), THALAMUS_CF_URL: url(), THALAMUS_WEBHOOK_SECRET: str(), } : { THALAMUS_CF_API_KEY: str({ default: undefined }), THALAMUS_CF_URL: url({ default: undefined }), THALAMUS_WEBHOOK_SECRET: str({ default: undefined }), }), }), // Feature Flags ...(Object.fromEntries( Object.values(FeatureFlagsKeysEnum).map((key) => [key, getFeatureFlagValidator(key)]) ) as Record<FeatureFlagsKeysEnum, ValidatorSpec<string | number | boolean | undefined>>), // Azure validators ...(processEnv.STORAGE_SERVICE === 'AZURE' && { AZURE_ACCOUNT_NAME: str(), AZURE_ACCOUNT_KEY: str(), AZURE_HOST_NAME: str({ default: `https://${processEnv.AZURE_ACCOUNT_NAME}.blob.core.windows.net` }), AZURE_CONTAINER_NAME: str({ default: 'novu' }), }), // GCS validators ...(processEnv.STORAGE_SERVICE === 'GCS' && { GCS_BUCKET_NAME: str(), GCS_DOMAIN: str(), }), // AWS validators ...(processEnv.STORAGE_SERVICE === 'AWS' && { S3_LOCAL_STACK: str({ default: '' }), S3_BUCKET_NAME: str(), S3_REGION: str(), }), // Production validators ...(['local', 'test'].includes(processEnv.NODE_ENV) && { SENTRY_DSN: str({ default: '' }), VERCEL_CLIENT_ID: str({ default: '' }), VERCEL_CLIENT_SECRET: str({ default: '' }), VERCEL_REDIRECT_URI: url({ default: 'https://dashboard.novu.co/auth/login' }), VERCEL_BASE_URL: url({ default: 'https://api.vercel.com' }), }), } satisfies Record<string, ValidatorSpec<unknown>>;