diff --git a/packages/cli/src/config/schema.ts b/packages/cli/src/config/schema.ts index ab3d1edac..e419845d4 100644 --- a/packages/cli/src/config/schema.ts +++ b/packages/cli/src/config/schema.ts @@ -1,8 +1,32 @@ /* eslint-disable no-restricted-syntax */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ - import path from 'path'; -import * as core from 'n8n-core'; +import convict from 'convict'; +import { UserSettings } from 'n8n-core'; +import { jsonParse } from 'n8n-workflow'; + +convict.addFormat({ + name: 'nodes-list', + // @ts-ignore + validate(values: string[], { env }: { env: string }): void { + try { + if (!Array.isArray(values)) { + throw new Error(); + } + + for (const value of values) { + if (typeof value !== 'string') { + throw new Error(); + } + } + } catch (error) { + throw new TypeError(`${env} is not a valid Array of strings.`); + } + }, + coerce(rawValue: string): string[] { + return jsonParse(rawValue, { errorMessage: 'nodes-list needs to be valid JSON' }); + }, +}); export const schema = { database: { @@ -716,47 +740,14 @@ export const schema = { nodes: { include: { doc: 'Nodes to load', - format: function check(rawValue: string): void { - if (rawValue === '') { - return; - } - try { - const values = JSON.parse(rawValue); - if (!Array.isArray(values)) { - throw new Error(); - } - - for (const value of values) { - if (typeof value !== 'string') { - throw new Error(); - } - } - } catch (error) { - throw new TypeError(`The Nodes to include is not a valid Array of strings.`); - } - }, + format: 'nodes-list', default: undefined, env: 'NODES_INCLUDE', }, exclude: { doc: 'Nodes not to load', - format: function check(rawValue: string): void { - try { - const values = JSON.parse(rawValue); - if (!Array.isArray(values)) { - throw new Error(); - } - - for (const value of values) { - if (typeof value !== 'string') { - throw new Error(); - } - } - } catch (error) { - throw new TypeError(`The Nodes to exclude is not a valid Array of strings.`); - } - }, - default: '[]', + format: 'nodes-list', + default: undefined, env: 'NODES_EXCLUDE', }, errorTriggerType: { @@ -804,7 +795,7 @@ export const schema = { location: { doc: 'Log file location; only used if log output is set to file.', format: String, - default: path.join(core.UserSettings.getUserN8nFolderPath(), 'logs/n8n.log'), + default: path.join(UserSettings.getUserN8nFolderPath(), 'logs/n8n.log'), env: 'N8N_LOG_FILE_LOCATION', }, }, @@ -861,7 +852,7 @@ export const schema = { }, localStoragePath: { format: String, - default: path.join(core.UserSettings.getUserN8nFolderPath(), 'binaryData'), + default: path.join(UserSettings.getUserN8nFolderPath(), 'binaryData'), env: 'N8N_BINARY_DATA_STORAGE_PATH', doc: 'Path for binary data storage in "filesystem" mode', }, diff --git a/packages/cli/src/config/types.d.ts b/packages/cli/src/config/types.d.ts index 4c889e934..04e2a75aa 100644 --- a/packages/cli/src/config/types.d.ts +++ b/packages/cli/src/config/types.d.ts @@ -77,7 +77,8 @@ type ToReturnType = T extends NumericPath type ExceptionPaths = { 'queue.bull.redis': object; binaryDataManager: IBinaryDataConfig; - 'nodes.include': undefined; + 'nodes.exclude': string[] | undefined; + 'nodes.include': string[] | undefined; 'userManagement.isInstanceOwnerSetUp': boolean; 'userManagement.skipInstanceOwnerSetup': boolean; }; diff --git a/packages/core/src/DirectoryLoader.ts b/packages/core/src/DirectoryLoader.ts index 6966a791c..58c7826f3 100644 --- a/packages/core/src/DirectoryLoader.ts +++ b/packages/core/src/DirectoryLoader.ts @@ -43,8 +43,8 @@ export abstract class DirectoryLoader { constructor( protected readonly directory: string, - private readonly excludeNodes?: string, - private readonly includeNodes?: string, + protected readonly excludeNodes: string[] = [], + protected readonly includeNodes: string[] = [], ) {} abstract loadAll(): Promise; @@ -69,11 +69,11 @@ export abstract class DirectoryLoader { const fullNodeName = `${packageName}.${tempNode.description.name}`; - if (this.includeNodes !== undefined && !this.includeNodes.includes(fullNodeName)) { + if (this.includeNodes.length && !this.includeNodes.includes(fullNodeName)) { return; } - if (this.excludeNodes?.includes(fullNodeName)) { + if (this.excludeNodes.includes(fullNodeName)) { return; } @@ -338,6 +338,28 @@ export class LazyPackageDirectoryLoader extends PackageDirectoryLoader { this.types.nodes = await this.readJSON('dist/types/nodes.json'); this.types.credentials = await this.readJSON('dist/types/credentials.json'); + if (this.includeNodes.length) { + const allowedNodes: typeof this.known.nodes = {}; + for (const nodeName of this.includeNodes) { + allowedNodes[nodeName] = this.known.nodes[nodeName]; + } + this.known.nodes = allowedNodes; + + this.types.nodes = this.types.nodes.filter((nodeType) => + this.includeNodes.includes(nodeType.name), + ); + } + + if (this.excludeNodes.length) { + for (const nodeName of this.excludeNodes) { + delete this.known.nodes[nodeName]; + } + + this.types.nodes = this.types.nodes.filter( + (nodeType) => !this.excludeNodes.includes(nodeType.name), + ); + } + Logger.debug(`Lazy Loading credentials and nodes from ${this.packageJson.name}`, { credentials: this.types.credentials?.length ?? 0, nodes: this.types.nodes?.length ?? 0,