fix(core): Use explicit types in configs to ensure valid decorator metadata (#10433)
Some checks are pending
Test Master / install-and-build (push) Waiting to run
Test Master / Unit tests (18.x) (push) Blocked by required conditions
Test Master / Unit tests (20.x) (push) Blocked by required conditions
Test Master / Unit tests (22.4) (push) Blocked by required conditions
Test Master / Lint (push) Blocked by required conditions
Test Master / Notify Slack on failure (push) Blocked by required conditions

This commit is contained in:
कारतोफ्फेलस्क्रिप्ट™ 2024-08-15 13:58:20 +02:00 committed by GitHub
parent 0dc3e99b26
commit 2043daa257
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 109 additions and 103 deletions

View file

@ -4,22 +4,22 @@ import { Config, Env, Nested } from '../decorators';
class MemoryConfig { class MemoryConfig {
/** Max size of memory cache in bytes */ /** Max size of memory cache in bytes */
@Env('N8N_CACHE_MEMORY_MAX_SIZE') @Env('N8N_CACHE_MEMORY_MAX_SIZE')
maxSize = 3 * 1024 * 1024; // 3 MiB maxSize: number = 3 * 1024 * 1024; // 3 MiB
/** Time to live (in milliseconds) for data cached in memory. */ /** Time to live (in milliseconds) for data cached in memory. */
@Env('N8N_CACHE_MEMORY_TTL') @Env('N8N_CACHE_MEMORY_TTL')
ttl = 3600 * 1000; // 1 hour ttl: number = 3600 * 1000; // 1 hour
} }
@Config @Config
class RedisConfig { class RedisConfig {
/** Prefix for cache keys in Redis. */ /** Prefix for cache keys in Redis. */
@Env('N8N_CACHE_REDIS_KEY_PREFIX') @Env('N8N_CACHE_REDIS_KEY_PREFIX')
prefix = 'redis'; prefix: string = 'redis';
/** Time to live (in milliseconds) for data cached in Redis. 0 for no TTL. */ /** Time to live (in milliseconds) for data cached in Redis. 0 for no TTL. */
@Env('N8N_CACHE_REDIS_TTL') @Env('N8N_CACHE_REDIS_TTL')
ttl = 3600 * 1000; // 1 hour ttl: number = 3600 * 1000; // 1 hour
} }
@Config @Config

View file

@ -7,18 +7,18 @@ class CredentialsOverwrite {
* Format: { CREDENTIAL_NAME: { PARAMETER: VALUE }} * Format: { CREDENTIAL_NAME: { PARAMETER: VALUE }}
*/ */
@Env('CREDENTIALS_OVERWRITE_DATA') @Env('CREDENTIALS_OVERWRITE_DATA')
data = '{}'; data: string = '{}';
/** Internal API endpoint to fetch overwritten credential types from. */ /** Internal API endpoint to fetch overwritten credential types from. */
@Env('CREDENTIALS_OVERWRITE_ENDPOINT') @Env('CREDENTIALS_OVERWRITE_ENDPOINT')
endpoint = ''; endpoint: string = '';
} }
@Config @Config
export class CredentialsConfig { export class CredentialsConfig {
/** Default name for credentials */ /** Default name for credentials */
@Env('CREDENTIALS_DEFAULT_NAME') @Env('CREDENTIALS_DEFAULT_NAME')
defaultName = 'My credentials'; defaultName: string = 'My credentials';
@Nested @Nested
overwrite: CredentialsOverwrite; overwrite: CredentialsOverwrite;

View file

@ -4,7 +4,7 @@ import { Config, Env, Nested } from '../decorators';
class LoggingConfig { class LoggingConfig {
/** Whether database logging is enabled. */ /** Whether database logging is enabled. */
@Env('DB_LOGGING_ENABLED') @Env('DB_LOGGING_ENABLED')
enabled = false; enabled: boolean = false;
/** /**
* Database logging level. Requires `DB_LOGGING_MAX_EXECUTION_TIME` to be higher than `0`. * Database logging level. Requires `DB_LOGGING_MAX_EXECUTION_TIME` to be higher than `0`.
@ -16,7 +16,7 @@ class LoggingConfig {
* Only queries that exceed this time (ms) will be logged. Set `0` to disable. * Only queries that exceed this time (ms) will be logged. Set `0` to disable.
*/ */
@Env('DB_LOGGING_MAX_EXECUTION_TIME') @Env('DB_LOGGING_MAX_EXECUTION_TIME')
maxQueryExecutionTime = 0; maxQueryExecutionTime: number = 0;
} }
@Config @Config
@ -26,38 +26,38 @@ class PostgresSSLConfig {
* If `DB_POSTGRESDB_SSL_CA`, `DB_POSTGRESDB_SSL_CERT`, or `DB_POSTGRESDB_SSL_KEY` are defined, `DB_POSTGRESDB_SSL_ENABLED` defaults to `true`. * If `DB_POSTGRESDB_SSL_CA`, `DB_POSTGRESDB_SSL_CERT`, or `DB_POSTGRESDB_SSL_KEY` are defined, `DB_POSTGRESDB_SSL_ENABLED` defaults to `true`.
*/ */
@Env('DB_POSTGRESDB_SSL_ENABLED') @Env('DB_POSTGRESDB_SSL_ENABLED')
enabled = false; enabled: boolean = false;
/** SSL certificate authority */ /** SSL certificate authority */
@Env('DB_POSTGRESDB_SSL_CA') @Env('DB_POSTGRESDB_SSL_CA')
ca = ''; ca: string = '';
/** SSL certificate */ /** SSL certificate */
@Env('DB_POSTGRESDB_SSL_CERT') @Env('DB_POSTGRESDB_SSL_CERT')
cert = ''; cert: string = '';
/** SSL key */ /** SSL key */
@Env('DB_POSTGRESDB_SSL_KEY') @Env('DB_POSTGRESDB_SSL_KEY')
key = ''; key: string = '';
/** If unauthorized SSL connections should be rejected */ /** If unauthorized SSL connections should be rejected */
@Env('DB_POSTGRESDB_SSL_REJECT_UNAUTHORIZED') @Env('DB_POSTGRESDB_SSL_REJECT_UNAUTHORIZED')
rejectUnauthorized = true; rejectUnauthorized: boolean = true;
} }
@Config @Config
class PostgresConfig { class PostgresConfig {
/** Postgres database name */ /** Postgres database name */
@Env('DB_POSTGRESDB_DATABASE') @Env('DB_POSTGRESDB_DATABASE')
database = 'n8n'; database: string = 'n8n';
/** Postgres database host */ /** Postgres database host */
@Env('DB_POSTGRESDB_HOST') @Env('DB_POSTGRESDB_HOST')
host = 'localhost'; host: string = 'localhost';
/** Postgres database password */ /** Postgres database password */
@Env('DB_POSTGRESDB_PASSWORD') @Env('DB_POSTGRESDB_PASSWORD')
password = ''; password: string = '';
/** Postgres database port */ /** Postgres database port */
@Env('DB_POSTGRESDB_PORT') @Env('DB_POSTGRESDB_PORT')
@ -65,15 +65,15 @@ class PostgresConfig {
/** Postgres database user */ /** Postgres database user */
@Env('DB_POSTGRESDB_USER') @Env('DB_POSTGRESDB_USER')
user = 'postgres'; user: string = 'postgres';
/** Postgres database schema */ /** Postgres database schema */
@Env('DB_POSTGRESDB_SCHEMA') @Env('DB_POSTGRESDB_SCHEMA')
schema = 'public'; schema: string = 'public';
/** Postgres database pool size */ /** Postgres database pool size */
@Env('DB_POSTGRESDB_POOL_SIZE') @Env('DB_POSTGRESDB_POOL_SIZE')
poolSize = 2; poolSize: number = 2;
@Nested @Nested
ssl: PostgresSSLConfig; ssl: PostgresSSLConfig;
@ -83,15 +83,15 @@ class PostgresConfig {
class MysqlConfig { class MysqlConfig {
/** @deprecated MySQL database name */ /** @deprecated MySQL database name */
@Env('DB_MYSQLDB_DATABASE') @Env('DB_MYSQLDB_DATABASE')
database = 'n8n'; database: string = 'n8n';
/** MySQL database host */ /** MySQL database host */
@Env('DB_MYSQLDB_HOST') @Env('DB_MYSQLDB_HOST')
host = 'localhost'; host: string = 'localhost';
/** MySQL database password */ /** MySQL database password */
@Env('DB_MYSQLDB_PASSWORD') @Env('DB_MYSQLDB_PASSWORD')
password = ''; password: string = '';
/** MySQL database port */ /** MySQL database port */
@Env('DB_MYSQLDB_PORT') @Env('DB_MYSQLDB_PORT')
@ -99,14 +99,14 @@ class MysqlConfig {
/** MySQL database user */ /** MySQL database user */
@Env('DB_MYSQLDB_USER') @Env('DB_MYSQLDB_USER')
user = 'root'; user: string = 'root';
} }
@Config @Config
class SqliteConfig { class SqliteConfig {
/** SQLite database file name */ /** SQLite database file name */
@Env('DB_SQLITE_DATABASE') @Env('DB_SQLITE_DATABASE')
database = 'database.sqlite'; database: string = 'database.sqlite';
/** SQLite database pool size. Set to `0` to disable pooling. */ /** SQLite database pool size. Set to `0` to disable pooling. */
@Env('DB_SQLITE_POOL_SIZE') @Env('DB_SQLITE_POOL_SIZE')
@ -116,7 +116,7 @@ class SqliteConfig {
* Enable SQLite WAL mode. * Enable SQLite WAL mode.
*/ */
@Env('DB_SQLITE_ENABLE_WAL') @Env('DB_SQLITE_ENABLE_WAL')
enableWAL = this.poolSize > 1; enableWAL: boolean = this.poolSize > 1;
/** /**
* Run `VACUUM` on startup to rebuild the database, reducing file size and optimizing indexes. * Run `VACUUM` on startup to rebuild the database, reducing file size and optimizing indexes.
@ -124,7 +124,7 @@ class SqliteConfig {
* @warning Long-running blocking operation that will increase startup time. * @warning Long-running blocking operation that will increase startup time.
*/ */
@Env('DB_SQLITE_VACUUM_ON_STARTUP') @Env('DB_SQLITE_VACUUM_ON_STARTUP')
executeVacuumOnStartup = false; executeVacuumOnStartup: boolean = false;
} }
@Config @Config
@ -135,7 +135,7 @@ export class DatabaseConfig {
/** Prefix for table names */ /** Prefix for table names */
@Env('DB_TABLE_PREFIX') @Env('DB_TABLE_PREFIX')
tablePrefix = ''; tablePrefix: string = '';
@Nested @Nested
logging: LoggingConfig; logging: LoggingConfig;

View file

@ -4,51 +4,51 @@ import { Config, Env, Nested } from '../decorators';
class PrometheusMetricsConfig { class PrometheusMetricsConfig {
/** Whether to enable the `/metrics` endpoint to expose Prometheus metrics. */ /** Whether to enable the `/metrics` endpoint to expose Prometheus metrics. */
@Env('N8N_METRICS') @Env('N8N_METRICS')
enable = false; enable: boolean = false;
/** Prefix for Prometheus metric names. */ /** Prefix for Prometheus metric names. */
@Env('N8N_METRICS_PREFIX') @Env('N8N_METRICS_PREFIX')
prefix = 'n8n_'; prefix: string = 'n8n_';
/** Whether to expose system and Node.js metrics. See: https://www.npmjs.com/package/prom-client */ /** Whether to expose system and Node.js metrics. See: https://www.npmjs.com/package/prom-client */
@Env('N8N_METRICS_INCLUDE_DEFAULT_METRICS') @Env('N8N_METRICS_INCLUDE_DEFAULT_METRICS')
includeDefaultMetrics = true; includeDefaultMetrics: boolean = true;
/** Whether to include a label for workflow ID on workflow metrics. */ /** Whether to include a label for workflow ID on workflow metrics. */
@Env('N8N_METRICS_INCLUDE_WORKFLOW_ID_LABEL') @Env('N8N_METRICS_INCLUDE_WORKFLOW_ID_LABEL')
includeWorkflowIdLabel = false; includeWorkflowIdLabel: boolean = false;
/** Whether to include a label for node type on node metrics. */ /** Whether to include a label for node type on node metrics. */
@Env('N8N_METRICS_INCLUDE_NODE_TYPE_LABEL') @Env('N8N_METRICS_INCLUDE_NODE_TYPE_LABEL')
includeNodeTypeLabel = false; includeNodeTypeLabel: boolean = false;
/** Whether to include a label for credential type on credential metrics. */ /** Whether to include a label for credential type on credential metrics. */
@Env('N8N_METRICS_INCLUDE_CREDENTIAL_TYPE_LABEL') @Env('N8N_METRICS_INCLUDE_CREDENTIAL_TYPE_LABEL')
includeCredentialTypeLabel = false; includeCredentialTypeLabel: boolean = false;
/** Whether to expose metrics for API endpoints. See: https://www.npmjs.com/package/express-prom-bundle */ /** Whether to expose metrics for API endpoints. See: https://www.npmjs.com/package/express-prom-bundle */
@Env('N8N_METRICS_INCLUDE_API_ENDPOINTS') @Env('N8N_METRICS_INCLUDE_API_ENDPOINTS')
includeApiEndpoints = false; includeApiEndpoints: boolean = false;
/** Whether to include a label for the path of API endpoint calls. */ /** Whether to include a label for the path of API endpoint calls. */
@Env('N8N_METRICS_INCLUDE_API_PATH_LABEL') @Env('N8N_METRICS_INCLUDE_API_PATH_LABEL')
includeApiPathLabel = false; includeApiPathLabel: boolean = false;
/** Whether to include a label for the HTTP method of API endpoint calls. */ /** Whether to include a label for the HTTP method of API endpoint calls. */
@Env('N8N_METRICS_INCLUDE_API_METHOD_LABEL') @Env('N8N_METRICS_INCLUDE_API_METHOD_LABEL')
includeApiMethodLabel = false; includeApiMethodLabel: boolean = false;
/** Whether to include a label for the status code of API endpoint calls. */ /** Whether to include a label for the status code of API endpoint calls. */
@Env('N8N_METRICS_INCLUDE_API_STATUS_CODE_LABEL') @Env('N8N_METRICS_INCLUDE_API_STATUS_CODE_LABEL')
includeApiStatusCodeLabel = false; includeApiStatusCodeLabel: boolean = false;
/** Whether to include metrics for cache hits and misses. */ /** Whether to include metrics for cache hits and misses. */
@Env('N8N_METRICS_INCLUDE_CACHE_METRICS') @Env('N8N_METRICS_INCLUDE_CACHE_METRICS')
includeCacheMetrics = false; includeCacheMetrics: boolean = false;
/** Whether to include metrics derived from n8n's internal events */ /** Whether to include metrics derived from n8n's internal events */
@Env('N8N_METRICS_INCLUDE_MESSAGE_EVENT_BUS_METRICS') @Env('N8N_METRICS_INCLUDE_MESSAGE_EVENT_BUS_METRICS')
includeMessageEventBusMetrics = false; includeMessageEventBusMetrics: boolean = false;
} }
@Config @Config
@ -62,41 +62,41 @@ export class EndpointsConfig {
/** Path segment for REST API endpoints. */ /** Path segment for REST API endpoints. */
@Env('N8N_ENDPOINT_REST') @Env('N8N_ENDPOINT_REST')
rest = 'rest'; rest: string = 'rest';
/** Path segment for form endpoints. */ /** Path segment for form endpoints. */
@Env('N8N_ENDPOINT_FORM') @Env('N8N_ENDPOINT_FORM')
form = 'form'; form: string = 'form';
/** Path segment for test form endpoints. */ /** Path segment for test form endpoints. */
@Env('N8N_ENDPOINT_FORM_TEST') @Env('N8N_ENDPOINT_FORM_TEST')
formTest = 'form-test'; formTest: string = 'form-test';
/** Path segment for waiting form endpoints. */ /** Path segment for waiting form endpoints. */
@Env('N8N_ENDPOINT_FORM_WAIT') @Env('N8N_ENDPOINT_FORM_WAIT')
formWaiting = 'form-waiting'; formWaiting: string = 'form-waiting';
/** Path segment for webhook endpoints. */ /** Path segment for webhook endpoints. */
@Env('N8N_ENDPOINT_WEBHOOK') @Env('N8N_ENDPOINT_WEBHOOK')
webhook = 'webhook'; webhook: string = 'webhook';
/** Path segment for test webhook endpoints. */ /** Path segment for test webhook endpoints. */
@Env('N8N_ENDPOINT_WEBHOOK_TEST') @Env('N8N_ENDPOINT_WEBHOOK_TEST')
webhookTest = 'webhook-test'; webhookTest: string = 'webhook-test';
/** Path segment for waiting webhook endpoints. */ /** Path segment for waiting webhook endpoints. */
@Env('N8N_ENDPOINT_WEBHOOK_WAIT') @Env('N8N_ENDPOINT_WEBHOOK_WAIT')
webhookWaiting = 'webhook-waiting'; webhookWaiting: string = 'webhook-waiting';
/** Whether to disable n8n's UI (frontend). */ /** Whether to disable n8n's UI (frontend). */
@Env('N8N_DISABLE_UI') @Env('N8N_DISABLE_UI')
disableUi = false; disableUi: boolean = false;
/** Whether to disable production webhooks on the main process, when using webhook-specific processes. */ /** Whether to disable production webhooks on the main process, when using webhook-specific processes. */
@Env('N8N_DISABLE_PRODUCTION_MAIN_PROCESS') @Env('N8N_DISABLE_PRODUCTION_MAIN_PROCESS')
disableProductionWebhooksOnMainProcess = false; disableProductionWebhooksOnMainProcess: boolean = false;
/** Colon-delimited list of additional endpoints to not open the UI on. */ /** Colon-delimited list of additional endpoints to not open the UI on. */
@Env('N8N_ADDITIONAL_NON_UI_ROUTES') @Env('N8N_ADDITIONAL_NON_UI_ROUTES')
additionalNonUIRoutes = ''; additionalNonUIRoutes: string = '';
} }

View file

@ -4,22 +4,22 @@ import { Config, Env, Nested } from '../decorators';
class LogWriterConfig { class LogWriterConfig {
/* of event log files to keep */ /* of event log files to keep */
@Env('N8N_EVENTBUS_LOGWRITER_KEEPLOGCOUNT') @Env('N8N_EVENTBUS_LOGWRITER_KEEPLOGCOUNT')
keepLogCount = 3; keepLogCount: number = 3;
/** Max size (in KB) of an event log file before a new one is started */ /** Max size (in KB) of an event log file before a new one is started */
@Env('N8N_EVENTBUS_LOGWRITER_MAXFILESIZEINKB') @Env('N8N_EVENTBUS_LOGWRITER_MAXFILESIZEINKB')
maxFileSizeInKB = 10240; // 10 MB maxFileSizeInKB: number = 10240; // 10 MB
/** Basename of event log file */ /** Basename of event log file */
@Env('N8N_EVENTBUS_LOGWRITER_LOGBASENAME') @Env('N8N_EVENTBUS_LOGWRITER_LOGBASENAME')
logBaseName = 'n8nEventLog'; logBaseName: string = 'n8nEventLog';
} }
@Config @Config
export class EventBusConfig { export class EventBusConfig {
/** How often (in ms) to check for unsent event messages. Can in rare cases cause a message to be sent twice. `0` to disable */ /** How often (in ms) to check for unsent event messages. Can in rare cases cause a message to be sent twice. `0` to disable */
@Env('N8N_EVENTBUS_CHECKUNSENTINTERVAL') @Env('N8N_EVENTBUS_CHECKUNSENTINTERVAL')
checkUnsentInterval = 0; checkUnsentInterval: number = 0;
/** Endpoint to retrieve n8n version information from */ /** Endpoint to retrieve n8n version information from */
@Nested @Nested

View file

@ -4,9 +4,9 @@ import { Config, Env } from '../decorators';
export class ExternalSecretsConfig { export class ExternalSecretsConfig {
/** How often (in seconds) to check for secret updates */ /** How often (in seconds) to check for secret updates */
@Env('N8N_EXTERNAL_SECRETS_UPDATE_INTERVAL') @Env('N8N_EXTERNAL_SECRETS_UPDATE_INTERVAL')
updateInterval = 300; updateInterval: number = 300;
/** Whether to prefer GET over LIST when fetching secrets from Hashicorp Vault */ /** Whether to prefer GET over LIST when fetching secrets from Hashicorp Vault */
@Env('N8N_EXTERNAL_SECRETS_PREFER_GET') @Env('N8N_EXTERNAL_SECRETS_PREFER_GET')
preferGet = false; preferGet: boolean = false;
} }

View file

@ -4,29 +4,29 @@ import { Config, Env, Nested } from '../decorators';
class S3BucketConfig { class S3BucketConfig {
/** Name of the n8n bucket in S3-compatible external storage */ /** Name of the n8n bucket in S3-compatible external storage */
@Env('N8N_EXTERNAL_STORAGE_S3_BUCKET_NAME') @Env('N8N_EXTERNAL_STORAGE_S3_BUCKET_NAME')
name = ''; name: string = '';
/** Region of the n8n bucket in S3-compatible external storage @example "us-east-1" */ /** Region of the n8n bucket in S3-compatible external storage @example "us-east-1" */
@Env('N8N_EXTERNAL_STORAGE_S3_BUCKET_REGION') @Env('N8N_EXTERNAL_STORAGE_S3_BUCKET_REGION')
region = ''; region: string = '';
} }
@Config @Config
class S3CredentialsConfig { class S3CredentialsConfig {
/** Access key in S3-compatible external storage */ /** Access key in S3-compatible external storage */
@Env('N8N_EXTERNAL_STORAGE_S3_ACCESS_KEY') @Env('N8N_EXTERNAL_STORAGE_S3_ACCESS_KEY')
accessKey = ''; accessKey: string = '';
/** Access secret in S3-compatible external storage */ /** Access secret in S3-compatible external storage */
@Env('N8N_EXTERNAL_STORAGE_S3_ACCESS_SECRET') @Env('N8N_EXTERNAL_STORAGE_S3_ACCESS_SECRET')
accessSecret = ''; accessSecret: string = '';
} }
@Config @Config
class S3Config { class S3Config {
/** Host of the n8n bucket in S3-compatible external storage @example "s3.us-east-1.amazonaws.com" */ /** Host of the n8n bucket in S3-compatible external storage @example "s3.us-east-1.amazonaws.com" */
@Env('N8N_EXTERNAL_STORAGE_S3_HOST') @Env('N8N_EXTERNAL_STORAGE_S3_HOST')
host = ''; host: string = '';
@Nested @Nested
bucket: S3BucketConfig; bucket: S3BucketConfig;

View file

@ -47,7 +47,7 @@ export class NodesConfig {
/** Node type to use as error trigger */ /** Node type to use as error trigger */
@Env('NODES_ERROR_TRIGGER_TYPE') @Env('NODES_ERROR_TRIGGER_TYPE')
errorTriggerType = 'n8n-nodes-base.errorTrigger'; errorTriggerType: string = 'n8n-nodes-base.errorTrigger';
@Nested @Nested
communityPackages: CommunityPackagesConfig; communityPackages: CommunityPackagesConfig;

View file

@ -4,13 +4,13 @@ import { Config, Env } from '../decorators';
export class PublicApiConfig { export class PublicApiConfig {
/** Whether to disable the Public API */ /** Whether to disable the Public API */
@Env('N8N_PUBLIC_API_DISABLED') @Env('N8N_PUBLIC_API_DISABLED')
disabled = false; disabled: boolean = false;
/** Path segment for the Public API */ /** Path segment for the Public API */
@Env('N8N_PUBLIC_API_ENDPOINT') @Env('N8N_PUBLIC_API_ENDPOINT')
path = 'api'; path: string = 'api';
/** Whether to disable the Swagger UI for the Public API */ /** Whether to disable the Swagger UI for the Public API */
@Env('N8N_PUBLIC_API_SWAGGERUI_DISABLED') @Env('N8N_PUBLIC_API_SWAGGERUI_DISABLED')
swaggerUiDisabled = false; swaggerUiDisabled: boolean = false;
} }

View file

@ -4,83 +4,83 @@ import { Config, Env, Nested } from '../decorators';
class HealthConfig { class HealthConfig {
/** Whether to enable the worker health check endpoint `/healthz`. */ /** Whether to enable the worker health check endpoint `/healthz`. */
@Env('QUEUE_HEALTH_CHECK_ACTIVE') @Env('QUEUE_HEALTH_CHECK_ACTIVE')
active = false; active: boolean = false;
/** Port for worker to respond to health checks requests on, if enabled. */ /** Port for worker to respond to health checks requests on, if enabled. */
@Env('QUEUE_HEALTH_CHECK_PORT') @Env('QUEUE_HEALTH_CHECK_PORT')
port = 5678; port: number = 5678;
} }
@Config @Config
class RedisConfig { class RedisConfig {
/** Redis database for Bull queue. */ /** Redis database for Bull queue. */
@Env('QUEUE_BULL_REDIS_DB') @Env('QUEUE_BULL_REDIS_DB')
db = 0; db: number = 0;
/** Redis host for Bull queue. */ /** Redis host for Bull queue. */
@Env('QUEUE_BULL_REDIS_HOST') @Env('QUEUE_BULL_REDIS_HOST')
host = 'localhost'; host: string = 'localhost';
/** Password to authenticate with Redis. */ /** Password to authenticate with Redis. */
@Env('QUEUE_BULL_REDIS_PASSWORD') @Env('QUEUE_BULL_REDIS_PASSWORD')
password = ''; password: string = '';
/** Port for Redis to listen on. */ /** Port for Redis to listen on. */
@Env('QUEUE_BULL_REDIS_PORT') @Env('QUEUE_BULL_REDIS_PORT')
port = 6379; port: number = 6379;
/** Max cumulative timeout (in milliseconds) of connection retries before process exit. */ /** Max cumulative timeout (in milliseconds) of connection retries before process exit. */
@Env('QUEUE_BULL_REDIS_TIMEOUT_THRESHOLD') @Env('QUEUE_BULL_REDIS_TIMEOUT_THRESHOLD')
timeoutThreshold = 10_000; timeoutThreshold: number = 10_000;
/** Redis username. Redis 6.0 or higher required. */ /** Redis username. Redis 6.0 or higher required. */
@Env('QUEUE_BULL_REDIS_USERNAME') @Env('QUEUE_BULL_REDIS_USERNAME')
username = ''; username: string = '';
/** Redis cluster startup nodes, as comma-separated list of `{host}:{port}` pairs. @example 'redis-1:6379,redis-2:6379' */ /** Redis cluster startup nodes, as comma-separated list of `{host}:{port}` pairs. @example 'redis-1:6379,redis-2:6379' */
@Env('QUEUE_BULL_REDIS_CLUSTER_NODES') @Env('QUEUE_BULL_REDIS_CLUSTER_NODES')
clusterNodes = ''; clusterNodes: string = '';
/** Whether to enable TLS on Redis connections. */ /** Whether to enable TLS on Redis connections. */
@Env('QUEUE_BULL_REDIS_TLS') @Env('QUEUE_BULL_REDIS_TLS')
tls = false; tls: boolean = false;
} }
@Config @Config
class SettingsConfig { class SettingsConfig {
/** How long (in milliseconds) is the lease period for a worker processing a job. */ /** How long (in milliseconds) is the lease period for a worker processing a job. */
@Env('QUEUE_WORKER_LOCK_DURATION') @Env('QUEUE_WORKER_LOCK_DURATION')
lockDuration = 30_000; lockDuration: number = 30_000;
/** How often (in milliseconds) a worker must renew the lease. */ /** How often (in milliseconds) a worker must renew the lease. */
@Env('QUEUE_WORKER_LOCK_RENEW_TIME') @Env('QUEUE_WORKER_LOCK_RENEW_TIME')
lockRenewTime = 15_000; lockRenewTime: number = 15_000;
/** How often (in milliseconds) Bull must check for stalled jobs. `0` to disable. */ /** How often (in milliseconds) Bull must check for stalled jobs. `0` to disable. */
@Env('QUEUE_WORKER_STALLED_INTERVAL') @Env('QUEUE_WORKER_STALLED_INTERVAL')
stalledInterval = 30_000; stalledInterval: number = 30_000;
/** Max number of times a stalled job will be re-processed. See Bull's [documentation](https://docs.bullmq.io/guide/workers/stalled-jobs). */ /** Max number of times a stalled job will be re-processed. See Bull's [documentation](https://docs.bullmq.io/guide/workers/stalled-jobs). */
@Env('QUEUE_WORKER_MAX_STALLED_COUNT') @Env('QUEUE_WORKER_MAX_STALLED_COUNT')
maxStalledCount = 1; maxStalledCount: number = 1;
} }
@Config @Config
class BullConfig { class BullConfig {
/** Prefix for Bull keys on Redis. @example 'bull:jobs:23' */ /** Prefix for Bull keys on Redis. @example 'bull:jobs:23' */
@Env('QUEUE_BULL_PREFIX') @Env('QUEUE_BULL_PREFIX')
prefix = 'bull'; prefix: string = 'bull';
@Nested @Nested
redis: RedisConfig; redis: RedisConfig;
/** How often (in seconds) to poll the Bull queue to identify executions finished during a Redis crash. `0` to disable. May increase Redis traffic significantly. */ /** How often (in seconds) to poll the Bull queue to identify executions finished during a Redis crash. `0` to disable. May increase Redis traffic significantly. */
@Env('QUEUE_RECOVERY_INTERVAL') @Env('QUEUE_RECOVERY_INTERVAL')
queueRecoveryInterval = 60; // watchdog interval queueRecoveryInterval: number = 60; // watchdog interval
/** @deprecated How long (in seconds) a worker must wait for active executions to finish before exiting. Use `N8N_GRACEFUL_SHUTDOWN_TIMEOUT` instead */ /** @deprecated How long (in seconds) a worker must wait for active executions to finish before exiting. Use `N8N_GRACEFUL_SHUTDOWN_TIMEOUT` instead */
@Env('QUEUE_WORKER_TIMEOUT') @Env('QUEUE_WORKER_TIMEOUT')
gracefulShutdownTimeout = 30; gracefulShutdownTimeout: number = 30;
@Nested @Nested
settings: SettingsConfig; settings: SettingsConfig;

View file

@ -4,9 +4,9 @@ import { Config, Env } from '../decorators';
export class TemplatesConfig { export class TemplatesConfig {
/** Whether to load workflow templates. */ /** Whether to load workflow templates. */
@Env('N8N_TEMPLATES_ENABLED') @Env('N8N_TEMPLATES_ENABLED')
enabled = true; enabled: boolean = true;
/** Host to retrieve workflow templates from endpoints. */ /** Host to retrieve workflow templates from endpoints. */
@Env('N8N_TEMPLATES_HOST') @Env('N8N_TEMPLATES_HOST')
host = 'https://api.n8n.io/api/'; host: string = 'https://api.n8n.io/api/';
} }

View file

@ -4,26 +4,26 @@ import { Config, Env, Nested } from '../decorators';
class SmtpAuth { class SmtpAuth {
/** SMTP login username */ /** SMTP login username */
@Env('N8N_SMTP_USER') @Env('N8N_SMTP_USER')
user = ''; user: string = '';
/** SMTP login password */ /** SMTP login password */
@Env('N8N_SMTP_PASS') @Env('N8N_SMTP_PASS')
pass = ''; pass: string = '';
/** SMTP OAuth Service Client */ /** SMTP OAuth Service Client */
@Env('N8N_SMTP_OAUTH_SERVICE_CLIENT') @Env('N8N_SMTP_OAUTH_SERVICE_CLIENT')
serviceClient = ''; serviceClient: string = '';
/** SMTP OAuth Private Key */ /** SMTP OAuth Private Key */
@Env('N8N_SMTP_OAUTH_PRIVATE_KEY') @Env('N8N_SMTP_OAUTH_PRIVATE_KEY')
privateKey = ''; privateKey: string = '';
} }
@Config @Config
class SmtpConfig { class SmtpConfig {
/** SMTP server host */ /** SMTP server host */
@Env('N8N_SMTP_HOST') @Env('N8N_SMTP_HOST')
host = ''; host: string = '';
/** SMTP server port */ /** SMTP server port */
@Env('N8N_SMTP_PORT') @Env('N8N_SMTP_PORT')
@ -39,7 +39,7 @@ class SmtpConfig {
/** How to display sender name */ /** How to display sender name */
@Env('N8N_SMTP_SENDER') @Env('N8N_SMTP_SENDER')
sender = ''; sender: string = '';
@Nested @Nested
auth: SmtpAuth; auth: SmtpAuth;
@ -49,19 +49,19 @@ class SmtpConfig {
export class TemplateConfig { export class TemplateConfig {
/** Overrides default HTML template for inviting new people (use full path) */ /** Overrides default HTML template for inviting new people (use full path) */
@Env('N8N_UM_EMAIL_TEMPLATES_INVITE') @Env('N8N_UM_EMAIL_TEMPLATES_INVITE')
invite = ''; invite: string = '';
/** Overrides default HTML template for resetting password (use full path) */ /** Overrides default HTML template for resetting password (use full path) */
@Env('N8N_UM_EMAIL_TEMPLATES_PWRESET') @Env('N8N_UM_EMAIL_TEMPLATES_PWRESET')
passwordReset = ''; passwordReset: string = '';
/** Overrides default HTML template for notifying that a workflow was shared (use full path) */ /** Overrides default HTML template for notifying that a workflow was shared (use full path) */
@Env('N8N_UM_EMAIL_TEMPLATES_WORKFLOW_SHARED') @Env('N8N_UM_EMAIL_TEMPLATES_WORKFLOW_SHARED')
workflowShared = ''; workflowShared: string = '';
/** Overrides default HTML template for notifying that credentials were shared (use full path) */ /** Overrides default HTML template for notifying that credentials were shared (use full path) */
@Env('N8N_UM_EMAIL_TEMPLATES_CREDENTIALS_SHARED') @Env('N8N_UM_EMAIL_TEMPLATES_CREDENTIALS_SHARED')
credentialsShared = ''; credentialsShared: string = '';
} }
@Config @Config

View file

@ -4,13 +4,13 @@ import { Config, Env } from '../decorators';
export class VersionNotificationsConfig { export class VersionNotificationsConfig {
/** Whether to request notifications about new n8n versions */ /** Whether to request notifications about new n8n versions */
@Env('N8N_VERSION_NOTIFICATIONS_ENABLED') @Env('N8N_VERSION_NOTIFICATIONS_ENABLED')
enabled = true; enabled: boolean = true;
/** Endpoint to retrieve n8n version information from */ /** Endpoint to retrieve n8n version information from */
@Env('N8N_VERSION_NOTIFICATIONS_ENDPOINT') @Env('N8N_VERSION_NOTIFICATIONS_ENDPOINT')
endpoint = 'https://api.n8n.io/api/versions/'; endpoint: string = 'https://api.n8n.io/api/versions/';
/** URL for versions panel to page instructing user on how to update n8n instance */ /** URL for versions panel to page instructing user on how to update n8n instance */
@Env('N8N_VERSION_NOTIFICATIONS_INFO_URL') @Env('N8N_VERSION_NOTIFICATIONS_INFO_URL')
infoUrl = 'https://docs.n8n.io/hosting/installation/updating/'; infoUrl: string = 'https://docs.n8n.io/hosting/installation/updating/';
} }

View file

@ -4,11 +4,11 @@ import { Config, Env } from '../decorators';
export class WorkflowsConfig { export class WorkflowsConfig {
/** Default name for workflow */ /** Default name for workflow */
@Env('WORKFLOWS_DEFAULT_NAME') @Env('WORKFLOWS_DEFAULT_NAME')
defaultName = 'My workflow'; defaultName: string = 'My workflow';
/** Show onboarding flow in new workflow */ /** Show onboarding flow in new workflow */
@Env('N8N_ONBOARDING_FLOW_DISABLED') @Env('N8N_ONBOARDING_FLOW_DISABLED')
onboardingFlowDisabled = false; onboardingFlowDisabled: boolean = false;
/** Default option for which workflows may call the current workflow */ /** Default option for which workflows may call the current workflow */
@Env('N8N_WORKFLOW_CALLER_POLICY_DEFAULT_OPTION') @Env('N8N_WORKFLOW_CALLER_POLICY_DEFAULT_OPTION')

View file

@ -47,6 +47,11 @@ export const Config: ClassDecorator = (ConfigClass: Class) => {
} else { } else {
value = value === 'true'; value = value === 'true';
} }
} else if (type === Object) {
// eslint-disable-next-line n8n-local-rules/no-plain-errors
throw new Error(
`Invalid decorator metadata on key "${key as string}" on ${ConfigClass.name}\n Please use explicit typing on all config fields`,
);
} else if (type !== String && type !== Object) { } else if (type !== String && type !== Object) {
value = new (type as Constructable)(value as string); value = new (type as Constructable)(value as string);
} }

View file

@ -51,19 +51,19 @@ export class GlobalConfig {
/** Path n8n is deployed to */ /** Path n8n is deployed to */
@Env('N8N_PATH') @Env('N8N_PATH')
path = '/'; path: string = '/';
/** Host name n8n can be reached */ /** Host name n8n can be reached */
@Env('N8N_HOST') @Env('N8N_HOST')
host = 'localhost'; host: string = 'localhost';
/** HTTP port n8n can be reached */ /** HTTP port n8n can be reached */
@Env('N8N_PORT') @Env('N8N_PORT')
port = 5678; port: number = 5678;
/** IP address n8n should listen on */ /** IP address n8n should listen on */
@Env('N8N_LISTEN_ADDRESS') @Env('N8N_LISTEN_ADDRESS')
listen_address = '0.0.0.0'; listen_address: string = '0.0.0.0';
/** HTTP Protocol via which n8n can be reached */ /** HTTP Protocol via which n8n can be reached */
@Env('N8N_PROTOCOL') @Env('N8N_PROTOCOL')

View file

@ -232,6 +232,7 @@ describe('GlobalConfig', () => {
DB_POSTGRESDB_USER: 'n8n', DB_POSTGRESDB_USER: 'n8n',
DB_TABLE_PREFIX: 'test_', DB_TABLE_PREFIX: 'test_',
NODES_INCLUDE: '["n8n-nodes-base.hackerNews"]', NODES_INCLUDE: '["n8n-nodes-base.hackerNews"]',
DB_LOGGING_MAX_EXECUTION_TIME: '0',
}; };
const config = Container.get(GlobalConfig); const config = Container.get(GlobalConfig);
expect(config).toEqual({ expect(config).toEqual({