mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-19 11:01:15 +00:00
refactor(core): Validate all string union config fields (#14527)
This commit is contained in:
@@ -1,5 +1,11 @@
|
|||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
import { Config, Env, Nested } from '../decorators';
|
import { Config, Env, Nested } from '../decorators';
|
||||||
|
|
||||||
|
const samesiteSchema = z.enum(['strict', 'lax', 'none']);
|
||||||
|
|
||||||
|
type Samesite = z.infer<typeof samesiteSchema>;
|
||||||
|
|
||||||
@Config
|
@Config
|
||||||
class CookieConfig {
|
class CookieConfig {
|
||||||
/** This sets the `Secure` flag on n8n auth cookie */
|
/** This sets the `Secure` flag on n8n auth cookie */
|
||||||
@@ -7,8 +13,8 @@ class CookieConfig {
|
|||||||
secure: boolean = true;
|
secure: boolean = true;
|
||||||
|
|
||||||
/** This sets the `Samesite` flag on n8n auth cookie */
|
/** This sets the `Samesite` flag on n8n auth cookie */
|
||||||
@Env('N8N_SAMESITE_COOKIE')
|
@Env('N8N_SAMESITE_COOKIE', samesiteSchema)
|
||||||
samesite: 'strict' | 'lax' | 'none' = 'lax';
|
samesite: Samesite = 'lax';
|
||||||
}
|
}
|
||||||
|
|
||||||
@Config
|
@Config
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
import { Config, Env, Nested } from '../decorators';
|
import { Config, Env, Nested } from '../decorators';
|
||||||
|
|
||||||
|
const cacheBackendSchema = z.enum(['memory', 'redis', 'auto']);
|
||||||
|
type CacheBackend = z.infer<typeof cacheBackendSchema>;
|
||||||
|
|
||||||
@Config
|
@Config
|
||||||
class MemoryConfig {
|
class MemoryConfig {
|
||||||
/** Max size of memory cache in bytes */
|
/** Max size of memory cache in bytes */
|
||||||
@@ -25,8 +30,8 @@ class RedisConfig {
|
|||||||
@Config
|
@Config
|
||||||
export class CacheConfig {
|
export class CacheConfig {
|
||||||
/** Backend to use for caching. */
|
/** Backend to use for caching. */
|
||||||
@Env('N8N_CACHE_BACKEND')
|
@Env('N8N_CACHE_BACKEND', cacheBackendSchema)
|
||||||
backend: 'memory' | 'redis' | 'auto' = 'auto';
|
backend: CacheBackend = 'auto';
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
memory: MemoryConfig;
|
memory: MemoryConfig;
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
import { Config, Env, Nested } from '../decorators';
|
import { Config, Env, Nested } from '../decorators';
|
||||||
|
|
||||||
|
const dbLoggingOptionsSchema = z.enum(['query', 'error', 'schema', 'warn', 'info', 'log', 'all']);
|
||||||
|
type DbLoggingOptions = z.infer<typeof dbLoggingOptionsSchema>;
|
||||||
|
|
||||||
@Config
|
@Config
|
||||||
class LoggingConfig {
|
class LoggingConfig {
|
||||||
/** Whether database logging is enabled. */
|
/** Whether database logging is enabled. */
|
||||||
@@ -9,8 +14,8 @@ class LoggingConfig {
|
|||||||
/**
|
/**
|
||||||
* 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`.
|
||||||
*/
|
*/
|
||||||
@Env('DB_LOGGING_OPTIONS')
|
@Env('DB_LOGGING_OPTIONS', dbLoggingOptionsSchema)
|
||||||
options: 'query' | 'error' | 'schema' | 'warn' | 'info' | 'log' | 'all' = 'error';
|
options: DbLoggingOptions = 'error';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
@@ -131,11 +136,14 @@ export class SqliteConfig {
|
|||||||
executeVacuumOnStartup: boolean = false;
|
executeVacuumOnStartup: boolean = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const dbTypeSchema = z.enum(['sqlite', 'mariadb', 'mysqldb', 'postgresdb']);
|
||||||
|
type DbType = z.infer<typeof dbTypeSchema>;
|
||||||
|
|
||||||
@Config
|
@Config
|
||||||
export class DatabaseConfig {
|
export class DatabaseConfig {
|
||||||
/** Type of database to use */
|
/** Type of database to use */
|
||||||
@Env('DB_TYPE')
|
@Env('DB_TYPE', dbTypeSchema)
|
||||||
type: 'sqlite' | 'mariadb' | 'mysqldb' | 'postgresdb' = 'sqlite';
|
type: DbType = 'sqlite';
|
||||||
|
|
||||||
/** Prefix for table names */
|
/** Prefix for table names */
|
||||||
@Env('DB_TABLE_PREFIX')
|
@Env('DB_TABLE_PREFIX')
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
import { Config, Env, Nested } from '../decorators';
|
import { Config, Env, Nested } from '../decorators';
|
||||||
|
|
||||||
@Config
|
@Config
|
||||||
@@ -15,6 +17,9 @@ class LogWriterConfig {
|
|||||||
logBaseName: string = 'n8nEventLog';
|
logBaseName: string = 'n8nEventLog';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const recoveryModeSchema = z.enum(['simple', 'extensive']);
|
||||||
|
type RecoveryMode = z.infer<typeof recoveryModeSchema>;
|
||||||
|
|
||||||
@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 */
|
||||||
@@ -26,6 +31,6 @@ export class EventBusConfig {
|
|||||||
logWriter: LogWriterConfig;
|
logWriter: LogWriterConfig;
|
||||||
|
|
||||||
/** Whether to recover execution details after a crash or only mark status executions as crashed. */
|
/** Whether to recover execution details after a crash or only mark status executions as crashed. */
|
||||||
@Env('N8N_EVENTBUS_RECOVERY_MODE')
|
@Env('N8N_EVENTBUS_RECOVERY_MODE', recoveryModeSchema)
|
||||||
crashRecoveryMode: 'simple' | 'extensive' = 'extensive';
|
crashRecoveryMode: RecoveryMode = 'extensive';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
import { Config, Env, Nested } from '../decorators';
|
import { Config, Env, Nested } from '../decorators';
|
||||||
|
|
||||||
|
const protocolSchema = z.enum(['http', 'https']);
|
||||||
|
|
||||||
|
export type Protocol = z.infer<typeof protocolSchema>;
|
||||||
|
|
||||||
@Config
|
@Config
|
||||||
class S3BucketConfig {
|
class S3BucketConfig {
|
||||||
/** Name of the n8n bucket in S3-compatible external storage */
|
/** Name of the n8n bucket in S3-compatible external storage */
|
||||||
@@ -28,8 +34,8 @@ export class S3Config {
|
|||||||
@Env('N8N_EXTERNAL_STORAGE_S3_HOST')
|
@Env('N8N_EXTERNAL_STORAGE_S3_HOST')
|
||||||
host: string = '';
|
host: string = '';
|
||||||
|
|
||||||
@Env('N8N_EXTERNAL_STORAGE_S3_PROTOCOL')
|
@Env('N8N_EXTERNAL_STORAGE_S3_PROTOCOL', protocolSchema)
|
||||||
protocol: 'http' | 'https' = 'https';
|
protocol: Protocol = 'https';
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
bucket: S3BucketConfig;
|
bucket: S3BucketConfig;
|
||||||
|
|||||||
@@ -1,13 +1,18 @@
|
|||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
import { Config, Env } from '../decorators';
|
import { Config, Env } from '../decorators';
|
||||||
|
|
||||||
|
const releaseChannelSchema = z.enum(['stable', 'beta', 'nightly', 'dev']);
|
||||||
|
type ReleaseChannel = z.infer<typeof releaseChannelSchema>;
|
||||||
|
|
||||||
@Config
|
@Config
|
||||||
export class GenericConfig {
|
export class GenericConfig {
|
||||||
/** Default timezone for the n8n instance. Can be overridden on a per-workflow basis. */
|
/** Default timezone for the n8n instance. Can be overridden on a per-workflow basis. */
|
||||||
@Env('GENERIC_TIMEZONE')
|
@Env('GENERIC_TIMEZONE')
|
||||||
timezone: string = 'America/New_York';
|
timezone: string = 'America/New_York';
|
||||||
|
|
||||||
@Env('N8N_RELEASE_TYPE')
|
@Env('N8N_RELEASE_TYPE', releaseChannelSchema)
|
||||||
releaseChannel: 'stable' | 'beta' | 'nightly' | 'dev' = 'dev';
|
releaseChannel: ReleaseChannel = 'dev';
|
||||||
|
|
||||||
/** Grace period (in seconds) to wait for components to shut down before process exit. */
|
/** Grace period (in seconds) to wait for components to shut down before process exit. */
|
||||||
@Env('N8N_GRACEFUL_SHUTDOWN_TIMEOUT')
|
@Env('N8N_GRACEFUL_SHUTDOWN_TIMEOUT')
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import { CommaSeperatedStringArray } from '../custom-types';
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
import { CommaSeparatedStringArray } from '../custom-types';
|
||||||
import { Config, Env, Nested } from '../decorators';
|
import { Config, Env, Nested } from '../decorators';
|
||||||
|
|
||||||
/** Scopes (areas of functionality) to filter logs by. */
|
/** Scopes (areas of functionality) to filter logs by. */
|
||||||
@@ -41,6 +43,9 @@ class FileLoggingConfig {
|
|||||||
location: string = 'logs/n8n.log';
|
location: string = 'logs/n8n.log';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const logLevelSchema = z.enum(['error', 'warn', 'info', 'debug', 'silent']);
|
||||||
|
type LogLevel = z.infer<typeof logLevelSchema>;
|
||||||
|
|
||||||
@Config
|
@Config
|
||||||
export class LoggingConfig {
|
export class LoggingConfig {
|
||||||
/**
|
/**
|
||||||
@@ -49,8 +54,8 @@ export class LoggingConfig {
|
|||||||
*
|
*
|
||||||
* @example `N8N_LOG_LEVEL=info` will output `error`, `warn` and `info` logs, but not `debug`.
|
* @example `N8N_LOG_LEVEL=info` will output `error`, `warn` and `info` logs, but not `debug`.
|
||||||
*/
|
*/
|
||||||
@Env('N8N_LOG_LEVEL')
|
@Env('N8N_LOG_LEVEL', logLevelSchema)
|
||||||
level: 'error' | 'warn' | 'info' | 'debug' | 'silent' = 'info';
|
level: LogLevel = 'info';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Where to output logs to. Options are: `console` or `file` or both in a comma separated list.
|
* Where to output logs to. Options are: `console` or `file` or both in a comma separated list.
|
||||||
@@ -58,7 +63,7 @@ export class LoggingConfig {
|
|||||||
* @example `N8N_LOG_OUTPUT=console,file` will output to both console and file.
|
* @example `N8N_LOG_OUTPUT=console,file` will output to both console and file.
|
||||||
*/
|
*/
|
||||||
@Env('N8N_LOG_OUTPUT')
|
@Env('N8N_LOG_OUTPUT')
|
||||||
outputs: CommaSeperatedStringArray<'console' | 'file'> = ['console'];
|
outputs: CommaSeparatedStringArray<'console' | 'file'> = ['console'];
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
file: FileLoggingConfig;
|
file: FileLoggingConfig;
|
||||||
@@ -85,5 +90,5 @@ export class LoggingConfig {
|
|||||||
* `N8N_LOG_SCOPES=license,waiting-executions`
|
* `N8N_LOG_SCOPES=license,waiting-executions`
|
||||||
*/
|
*/
|
||||||
@Env('N8N_LOG_SCOPES')
|
@Env('N8N_LOG_SCOPES')
|
||||||
scopes: CommaSeperatedStringArray<LogScope> = [];
|
scopes: CommaSeparatedStringArray<LogScope> = [];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
import { Config, Env, Nested } from '../decorators';
|
import { Config, Env, Nested } from '../decorators';
|
||||||
|
|
||||||
@Config
|
@Config
|
||||||
@@ -64,11 +66,14 @@ export class TemplateConfig {
|
|||||||
'credentials-shared': string = '';
|
'credentials-shared': string = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const emailModeSchema = z.enum(['', 'smtp']);
|
||||||
|
type EmailMode = z.infer<typeof emailModeSchema>;
|
||||||
|
|
||||||
@Config
|
@Config
|
||||||
class EmailConfig {
|
class EmailConfig {
|
||||||
/** How to send emails */
|
/** How to send emails */
|
||||||
@Env('N8N_EMAIL_MODE')
|
@Env('N8N_EMAIL_MODE', emailModeSchema)
|
||||||
mode: '' | 'smtp' = 'smtp';
|
mode: EmailMode = 'smtp';
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
smtp: SmtpConfig;
|
smtp: SmtpConfig;
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
import { Config, Env } from '../decorators';
|
import { Config, Env } from '../decorators';
|
||||||
|
|
||||||
|
const callerPolicySchema = z.enum(['any', 'none', 'workflowsFromAList', 'workflowsFromSameOwner']);
|
||||||
|
type CallerPolicy = z.infer<typeof callerPolicySchema>;
|
||||||
|
|
||||||
@Config
|
@Config
|
||||||
export class WorkflowsConfig {
|
export class WorkflowsConfig {
|
||||||
/** Default name for workflow */
|
/** Default name for workflow */
|
||||||
@@ -7,9 +12,8 @@ export class WorkflowsConfig {
|
|||||||
defaultName: string = 'My workflow';
|
defaultName: string = 'My workflow';
|
||||||
|
|
||||||
/** 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', callerPolicySchema)
|
||||||
callerPolicyDefaultOption: 'any' | 'none' | 'workflowsFromAList' | 'workflowsFromSameOwner' =
|
callerPolicyDefaultOption: CallerPolicy = 'workflowsFromSameOwner';
|
||||||
'workflowsFromSameOwner';
|
|
||||||
|
|
||||||
/** How many workflows to activate simultaneously during startup. */
|
/** How many workflows to activate simultaneously during startup. */
|
||||||
@Env('N8N_WORKFLOW_ACTIVATION_BATCH_SIZE')
|
@Env('N8N_WORKFLOW_ACTIVATION_BATCH_SIZE')
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ abstract class StringArray<T extends string> extends Array<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CommaSeperatedStringArray<T extends string> extends StringArray<T> {
|
export class CommaSeparatedStringArray<T extends string> extends StringArray<T> {
|
||||||
constructor(str: string) {
|
constructor(str: string) {
|
||||||
super(str, ',');
|
super(str, ',');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
import { AiAssistantConfig } from './configs/aiAssistant.config';
|
import { AiAssistantConfig } from './configs/aiAssistant.config';
|
||||||
import { AuthConfig } from './configs/auth.config';
|
import { AuthConfig } from './configs/auth.config';
|
||||||
import { CacheConfig } from './configs/cache.config';
|
import { CacheConfig } from './configs/cache.config';
|
||||||
@@ -38,6 +40,10 @@ export type { LogScope } from './configs/logging.config';
|
|||||||
export { WorkflowsConfig } from './configs/workflows.config';
|
export { WorkflowsConfig } from './configs/workflows.config';
|
||||||
export * from './custom-types';
|
export * from './custom-types';
|
||||||
|
|
||||||
|
const protocolSchema = z.enum(['http', 'https']);
|
||||||
|
|
||||||
|
export type Protocol = z.infer<typeof protocolSchema>;
|
||||||
|
|
||||||
@Config
|
@Config
|
||||||
export class GlobalConfig {
|
export class GlobalConfig {
|
||||||
@Nested
|
@Nested
|
||||||
@@ -99,8 +105,8 @@ export class GlobalConfig {
|
|||||||
listen_address: string = '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', protocolSchema)
|
||||||
protocol: 'http' | 'https' = 'http';
|
protocol: Protocol = 'http';
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
endpoints: EndpointsConfig;
|
endpoints: EndpointsConfig;
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import { CommaSeperatedStringArray, ColonSeparatedStringArray } from '../src/custom-types';
|
import { CommaSeparatedStringArray, ColonSeparatedStringArray } from '../src/custom-types';
|
||||||
|
|
||||||
describe('CommaSeperatedStringArray', () => {
|
describe('CommaSeparatedStringArray', () => {
|
||||||
it('should parse comma-separated string into array', () => {
|
it('should parse comma-separated string into array', () => {
|
||||||
const result = new CommaSeperatedStringArray('a,b,c');
|
const result = new CommaSeparatedStringArray('a,b,c');
|
||||||
expect(result).toEqual(['a', 'b', 'c']);
|
expect(result).toEqual(['a', 'b', 'c']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle empty strings', () => {
|
it('should handle empty strings', () => {
|
||||||
const result = new CommaSeperatedStringArray('a,b,,,');
|
const result = new CommaSeparatedStringArray('a,b,,,');
|
||||||
expect(result).toEqual(['a', 'b']);
|
expect(result).toEqual(['a', 'b']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { CommaSeperatedStringArray, Config, Env } from '@n8n/config';
|
import { CommaSeparatedStringArray, Config, Env } from '@n8n/config';
|
||||||
import { UnexpectedError } from 'n8n-workflow';
|
import { UnexpectedError } from 'n8n-workflow';
|
||||||
|
|
||||||
const moduleNames = ['insights'] as const;
|
const moduleNames = ['insights'] as const;
|
||||||
type ModuleName = (typeof moduleNames)[number];
|
type ModuleName = (typeof moduleNames)[number];
|
||||||
|
|
||||||
class Modules extends CommaSeperatedStringArray<ModuleName> {
|
class Modules extends CommaSeparatedStringArray<ModuleName> {
|
||||||
constructor(str: string) {
|
constructor(str: string) {
|
||||||
super(str);
|
super(str);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user