diff --git a/packages/cli/src/Server.ts b/packages/cli/src/Server.ts index 19960fea37..1ac17c4b30 100644 --- a/packages/cli/src/Server.ts +++ b/packages/cli/src/Server.ts @@ -40,7 +40,6 @@ import type { INodeParameters, INodePropertyOptions, INodeTypeNameVersion, - ITelemetrySettings, WorkflowExecuteMode, ICredentialTypes, ExecutionStatus, @@ -64,7 +63,6 @@ import { GENERATED_STATIC_DIR, inDevelopment, inE2ETests, - LICENSE_FEATURES, N8N_VERSION, RESPONSE_ERROR_MESSAGES, TEMPLATES_DIR, @@ -99,12 +97,7 @@ import { BinaryDataController } from './controllers/binaryData.controller'; import { ExternalSecretsController } from '@/ExternalSecrets/ExternalSecrets.controller.ee'; import { executionsController } from '@/executions/executions.controller'; import { isApiEnabled, loadPublicApiVersions } from '@/PublicApi'; -import { - getInstanceBaseUrl, - isEmailSetUp, - isSharingEnabled, - whereClause, -} from '@/UserManagement/UserManagementHelper'; +import { whereClause } from '@/UserManagement/UserManagementHelper'; import { UserManagementMailer } from '@/UserManagement/email'; import * as Db from '@/Db'; import type { @@ -130,40 +123,25 @@ import * as WorkflowExecuteAdditionalData from '@/WorkflowExecuteAdditionalData' import { toHttpNodeParameters } from '@/CurlConverterHelper'; import { EventBusController } from '@/eventbus/eventBus.controller'; import { EventBusControllerEE } from '@/eventbus/eventBus.controller.ee'; -import { isLogStreamingEnabled } from '@/eventbus/MessageEventBus/MessageEventBusHelper'; import { licenseController } from './license/license.controller'; import { Push, setupPushServer, setupPushHandler } from '@/push'; import { setupAuthMiddlewares } from './middlewares'; -import { - getLdapLoginLabel, - handleLdapInit, - isLdapEnabled, - isLdapLoginEnabled, -} from './Ldap/helpers'; +import { handleLdapInit, isLdapEnabled } from './Ldap/helpers'; import { AbstractServer } from './AbstractServer'; import { PostHogClient } from './posthog'; import { eventBus } from './eventbus'; import { Container } from 'typedi'; import { InternalHooks } from './InternalHooks'; import { License } from './License'; -import { - getStatusUsingPreviousExecutionStatusMethod, - isAdvancedExecutionFiltersEnabled, - isDebugInEditorLicensed, -} from './executions/executionHelpers'; -import { getSamlLoginLabel, isSamlLoginEnabled, isSamlLicensed } from './sso/saml/samlHelpers'; +import { getStatusUsingPreviousExecutionStatusMethod } from './executions/executionHelpers'; import { SamlController } from './sso/saml/routes/saml.controller.ee'; import { SamlService } from './sso/saml/saml.service.ee'; import { variablesController } from './environments/variables/variables.controller'; import { LdapManager } from './Ldap/LdapManager.ee'; -import { getVariablesLimit, isVariablesEnabled } from '@/environments/variables/enviromentHelpers'; import { - getCurrentAuthenticationMethod, isLdapCurrentAuthenticationMethod, isSamlCurrentAuthenticationMethod, } from './sso/ssoHelpers'; -import { isExternalSecretsEnabled } from './ExternalSecrets/externalSecretsHelper.ee'; -import { isSourceControlLicensed } from '@/environments/sourceControl/sourceControlHelper.ee'; import { SourceControlService } from '@/environments/sourceControl/sourceControl.service.ee'; import { SourceControlController } from '@/environments/sourceControl/sourceControl.controller.ee'; import { ExecutionRepository, SettingsRepository } from '@db/repositories'; @@ -176,11 +154,6 @@ import { JwtService } from './services/jwt.service'; import { RoleService } from './services/role.service'; import { UserService } from './services/user.service'; import { OrchestrationController } from './controllers/orchestration.controller'; -import { - getWorkflowHistoryLicensePruneTime, - getWorkflowHistoryPruneTime, - isWorkflowHistoryEnabled, -} from './workflows/workflowHistory/workflowHistoryHelper.ee'; import { WorkflowHistoryController } from './workflows/workflowHistory/workflowHistory.controller.ee'; const exec = promisify(callbackExec); @@ -192,8 +165,6 @@ export class Server extends AbstractServer { activeExecutionsInstance: ActiveExecutions; - frontendSettings: IN8nUISettings; - presetCredentialsLoaded: boolean; loadNodesAndCredentials: LoadNodesAndCredentials; @@ -217,146 +188,6 @@ export class Server extends AbstractServer { this.testWebhooksEnabled = true; this.webhooksEnabled = !config.getEnv('endpoints.disableProductionWebhooksOnMainProcess'); - - const urlBaseWebhook = WebhookHelpers.getWebhookBaseUrl(); - const telemetrySettings: ITelemetrySettings = { - enabled: config.getEnv('diagnostics.enabled'), - }; - - if (telemetrySettings.enabled) { - const conf = config.getEnv('diagnostics.config.frontend'); - const [key, url] = conf.split(';'); - - if (!key || !url) { - LoggerProxy.warn('Diagnostics frontend config is invalid'); - telemetrySettings.enabled = false; - } - - telemetrySettings.config = { key, url }; - } - - // Define it here to avoid calling the function multiple times - const instanceBaseUrl = getInstanceBaseUrl(); - - this.frontendSettings = { - endpointWebhook: this.endpointWebhook, - endpointWebhookTest: this.endpointWebhookTest, - saveDataErrorExecution: config.getEnv('executions.saveDataOnError'), - saveDataSuccessExecution: config.getEnv('executions.saveDataOnSuccess'), - saveManualExecutions: config.getEnv('executions.saveDataManualExecutions'), - executionTimeout: config.getEnv('executions.timeout'), - maxExecutionTimeout: config.getEnv('executions.maxTimeout'), - workflowCallerPolicyDefaultOption: config.getEnv('workflows.callerPolicyDefaultOption'), - timezone: this.timezone, - urlBaseWebhook, - urlBaseEditor: instanceBaseUrl, - versionCli: '', - releaseChannel: config.getEnv('generic.releaseChannel'), - oauthCallbackUrls: { - oauth1: `${instanceBaseUrl}/${this.restEndpoint}/oauth1-credential/callback`, - oauth2: `${instanceBaseUrl}/${this.restEndpoint}/oauth2-credential/callback`, - }, - versionNotifications: { - enabled: config.getEnv('versionNotifications.enabled'), - endpoint: config.getEnv('versionNotifications.endpoint'), - infoUrl: config.getEnv('versionNotifications.infoUrl'), - }, - instanceId: '', - telemetry: telemetrySettings, - posthog: { - enabled: config.getEnv('diagnostics.enabled'), - apiHost: config.getEnv('diagnostics.config.posthog.apiHost'), - apiKey: config.getEnv('diagnostics.config.posthog.apiKey'), - autocapture: false, - disableSessionRecording: config.getEnv( - 'diagnostics.config.posthog.disableSessionRecording', - ), - debug: config.getEnv('logs.level') === 'debug', - }, - personalizationSurveyEnabled: - config.getEnv('personalization.enabled') && config.getEnv('diagnostics.enabled'), - defaultLocale: config.getEnv('defaultLocale'), - userManagement: { - quota: Container.get(License).getUsersLimit(), - showSetupOnFirstLoad: config.getEnv('userManagement.isInstanceOwnerSetUp') === false, - smtpSetup: isEmailSetUp(), - authenticationMethod: getCurrentAuthenticationMethod(), - }, - sso: { - saml: { - loginEnabled: false, - loginLabel: '', - }, - ldap: { - loginEnabled: false, - loginLabel: '', - }, - }, - publicApi: { - enabled: isApiEnabled(), - latestVersion: 1, - path: config.getEnv('publicApi.path'), - swaggerUi: { - enabled: !config.getEnv('publicApi.swaggerUi.disabled'), - }, - }, - workflowTagsDisabled: config.getEnv('workflowTagsDisabled'), - logLevel: config.getEnv('logs.level'), - hiringBannerEnabled: config.getEnv('hiringBanner.enabled'), - templates: { - enabled: config.getEnv('templates.enabled'), - host: config.getEnv('templates.host'), - }, - onboardingCallPromptEnabled: config.getEnv('onboardingCallPrompt.enabled'), - executionMode: config.getEnv('executions.mode'), - pushBackend: config.getEnv('push.backend'), - communityNodesEnabled: config.getEnv('nodes.communityPackages.enabled'), - deployment: { - type: config.getEnv('deployment.type'), - }, - isNpmAvailable: false, - allowedModules: { - builtIn: process.env.NODE_FUNCTION_ALLOW_BUILTIN?.split(',') ?? undefined, - external: process.env.NODE_FUNCTION_ALLOW_EXTERNAL?.split(',') ?? undefined, - }, - enterprise: { - sharing: false, - ldap: false, - saml: false, - logStreaming: false, - advancedExecutionFilters: false, - variables: false, - sourceControl: false, - auditLogs: false, - externalSecrets: false, - showNonProdBanner: false, - debugInEditor: false, - workflowHistory: false, - }, - mfa: { - enabled: false, - }, - hideUsagePage: config.getEnv('hideUsagePage'), - license: { - environment: config.getEnv('license.tenantId') === 1 ? 'production' : 'staging', - }, - variables: { - limit: 0, - }, - expressions: { - evaluator: config.getEnv('expression.evaluator'), - }, - banners: { - dismissed: [], - }, - ai: { - enabled: config.getEnv('ai.enabled'), - }, - workflowHistory: { - pruneTime: -1, - licensePruneTime: -1, - }, - }; } async start() { @@ -443,92 +274,6 @@ export class Server extends AbstractServer { ); } - /** - * Returns the current settings for the frontend - */ - private async getSettingsForFrontend(): Promise { - // Update all urls, in case `WEBHOOK_URL` was updated by `--tunnel` - const instanceBaseUrl = getInstanceBaseUrl(); - this.frontendSettings.urlBaseWebhook = WebhookHelpers.getWebhookBaseUrl(); - this.frontendSettings.urlBaseEditor = instanceBaseUrl; - this.frontendSettings.oauthCallbackUrls = { - oauth1: `${instanceBaseUrl}/${this.restEndpoint}/oauth1-credential/callback`, - oauth2: `${instanceBaseUrl}/${this.restEndpoint}/oauth2-credential/callback`, - }; - - // refresh user management status - Object.assign(this.frontendSettings.userManagement, { - quota: Container.get(License).getUsersLimit(), - authenticationMethod: getCurrentAuthenticationMethod(), - showSetupOnFirstLoad: - config.getEnv('userManagement.isInstanceOwnerSetUp') === false && - config.getEnv('deployment.type').startsWith('desktop_') === false, - }); - - let dismissedBanners: string[] = []; - - try { - dismissedBanners = config.getEnv('ui.banners.dismissed') ?? []; - } catch { - // not yet in DB - } - - this.frontendSettings.banners.dismissed = dismissedBanners; - - // refresh enterprise status - Object.assign(this.frontendSettings.enterprise, { - sharing: isSharingEnabled(), - logStreaming: isLogStreamingEnabled(), - ldap: isLdapEnabled(), - saml: isSamlLicensed(), - advancedExecutionFilters: isAdvancedExecutionFiltersEnabled(), - variables: isVariablesEnabled(), - sourceControl: isSourceControlLicensed(), - externalSecrets: isExternalSecretsEnabled(), - showNonProdBanner: Container.get(License).isFeatureEnabled( - LICENSE_FEATURES.SHOW_NON_PROD_BANNER, - ), - debugInEditor: isDebugInEditorLicensed(), - workflowHistory: isWorkflowHistoryEnabled(), - }); - - if (isLdapEnabled()) { - Object.assign(this.frontendSettings.sso.ldap, { - loginLabel: getLdapLoginLabel(), - loginEnabled: isLdapLoginEnabled(), - }); - } - - if (isSamlLicensed()) { - Object.assign(this.frontendSettings.sso.saml, { - loginLabel: getSamlLoginLabel(), - loginEnabled: isSamlLoginEnabled(), - }); - } - - if (isVariablesEnabled()) { - this.frontendSettings.variables.limit = getVariablesLimit(); - } - - if (isWorkflowHistoryEnabled()) { - Object.assign(this.frontendSettings.workflowHistory, { - pruneTime: getWorkflowHistoryPruneTime(), - licensePruneTime: getWorkflowHistoryLicensePruneTime(), - }); - } - - if (config.getEnv('nodes.communityPackages.enabled')) { - // eslint-disable-next-line @typescript-eslint/naming-convention - const { CommunityPackagesService } = await import('@/services/communityPackages.service'); - this.frontendSettings.missingPackages = - Container.get(CommunityPackagesService).hasMissingPackages; - } - - this.frontendSettings.mfa.enabled = isMfaFeatureEnabled(); - - return this.frontendSettings; - } - private async registerControllers(ignoredEndpoints: Readonly) { const { app, externalHooks, activeWorkflowRunner, nodeTypes } = this; const repositories = Db.collections; @@ -628,17 +373,17 @@ export class Server extends AbstractServer { this.instanceId = await UserSettings.getInstanceId(); - this.frontendSettings.isNpmAvailable = await exec('npm --version') - .then(() => true) - .catch(() => false); + this.frontendService.addToSettings({ + isNpmAvailable: await exec('npm --version') + .then(() => true) + .catch(() => false), + versionCli: N8N_VERSION, + instanceId: this.instanceId, + }); - this.frontendSettings.versionCli = N8N_VERSION; + await this.externalHooks.run('frontend.settings', [this.frontendService.getSettings()]); - this.frontendSettings.instanceId = this.instanceId; - - await this.externalHooks.run('frontend.settings', [this.frontendSettings]); - - await this.postHog.init(this.frontendSettings.instanceId); + await this.postHog.init(this.instanceId); const publicApiEndpoint = config.getEnv('publicApi.path'); const excludeEndpoints = config.getEnv('security.excludeEndpoints'); @@ -665,7 +410,7 @@ export class Server extends AbstractServer { if (isApiEnabled()) { const { apiRouters, apiLatestVersion } = await loadPublicApiVersions(publicApiEndpoint); this.app.use(...apiRouters); - this.frontendSettings.publicApi.latestVersion = apiLatestVersion; + this.frontendService.settings.publicApi.latestVersion = apiLatestVersion; } // Parse cookies for easier access this.app.use(cookieParser()); @@ -1465,7 +1210,7 @@ export class Server extends AbstractServer { async (req: express.Request, res: express.Response): Promise => { void Container.get(InternalHooks).onFrontendSettingsAPI(req.headers.sessionid as string); - return this.getSettingsForFrontend(); + return this.frontendService.getSettings(); }, ), ); diff --git a/packages/cli/src/services/frontend.service.ts b/packages/cli/src/services/frontend.service.ts index 613b716e90..3fdc5eef61 100644 --- a/packages/cli/src/services/frontend.service.ts +++ b/packages/cli/src/services/frontend.service.ts @@ -1,23 +1,187 @@ -import { Service } from 'typedi'; +import { Container, Service } from 'typedi'; import uniq from 'lodash/uniq'; import { createWriteStream } from 'fs'; import { mkdir } from 'fs/promises'; import path from 'path'; -import type { ICredentialType, INodeTypeBaseDescription } from 'n8n-workflow'; +import type { + ICredentialType, + IN8nUISettings, + INodeTypeBaseDescription, + ITelemetrySettings, +} from 'n8n-workflow'; -import { GENERATED_STATIC_DIR } from '@/constants'; +import { GENERATED_STATIC_DIR, LICENSE_FEATURES } from '@/constants'; import { CredentialsOverwrites } from '@/CredentialsOverwrites'; import { CredentialTypes } from '@/CredentialTypes'; import { LoadNodesAndCredentials } from '@/LoadNodesAndCredentials'; +import { License } from '@/License'; +import { getInstanceBaseUrl, isEmailSetUp } from '@/UserManagement/UserManagementHelper'; +import * as WebhookHelpers from '@/WebhookHelpers'; +import { LoggerProxy } from 'n8n-workflow'; +import config from '@/config'; +import { getCurrentAuthenticationMethod } from '@/sso/ssoHelpers'; +import { getLdapLoginLabel } from '@/Ldap/helpers'; +import { getSamlLoginLabel } from '@/sso/saml/samlHelpers'; +import { getVariablesLimit } from '@/environments/variables/enviromentHelpers'; +import { + getWorkflowHistoryLicensePruneTime, + getWorkflowHistoryPruneTime, +} from '@/workflows/workflowHistory/workflowHistoryHelper.ee'; @Service() export class FrontendService { + settings: IN8nUISettings; + constructor( private readonly loadNodesAndCredentials: LoadNodesAndCredentials, private readonly credentialTypes: CredentialTypes, private readonly credentialsOverwrites: CredentialsOverwrites, - ) {} + private readonly license: License, + ) { + this.initSettings(); + } + + private initSettings() { + const instanceBaseUrl = getInstanceBaseUrl(); + const restEndpoint = config.getEnv('endpoints.rest'); + + const telemetrySettings: ITelemetrySettings = { + enabled: config.getEnv('diagnostics.enabled'), + }; + + if (telemetrySettings.enabled) { + const conf = config.getEnv('diagnostics.config.frontend'); + const [key, url] = conf.split(';'); + + if (!key || !url) { + LoggerProxy.warn('Diagnostics frontend config is invalid'); + telemetrySettings.enabled = false; + } + + telemetrySettings.config = { key, url }; + } + + this.settings = { + endpointWebhook: config.getEnv('endpoints.webhook'), + endpointWebhookTest: config.getEnv('endpoints.webhookTest'), + saveDataErrorExecution: config.getEnv('executions.saveDataOnError'), + saveDataSuccessExecution: config.getEnv('executions.saveDataOnSuccess'), + saveManualExecutions: config.getEnv('executions.saveDataManualExecutions'), + executionTimeout: config.getEnv('executions.timeout'), + maxExecutionTimeout: config.getEnv('executions.maxTimeout'), + workflowCallerPolicyDefaultOption: config.getEnv('workflows.callerPolicyDefaultOption'), + timezone: config.getEnv('generic.timezone'), + urlBaseWebhook: WebhookHelpers.getWebhookBaseUrl(), + urlBaseEditor: instanceBaseUrl, + versionCli: '', + releaseChannel: config.getEnv('generic.releaseChannel'), + oauthCallbackUrls: { + oauth1: `${instanceBaseUrl}/${restEndpoint}/oauth1-credential/callback`, + oauth2: `${instanceBaseUrl}/${restEndpoint}/oauth2-credential/callback`, + }, + versionNotifications: { + enabled: config.getEnv('versionNotifications.enabled'), + endpoint: config.getEnv('versionNotifications.endpoint'), + infoUrl: config.getEnv('versionNotifications.infoUrl'), + }, + instanceId: '', + telemetry: telemetrySettings, + posthog: { + enabled: config.getEnv('diagnostics.enabled'), + apiHost: config.getEnv('diagnostics.config.posthog.apiHost'), + apiKey: config.getEnv('diagnostics.config.posthog.apiKey'), + autocapture: false, + disableSessionRecording: config.getEnv( + 'diagnostics.config.posthog.disableSessionRecording', + ), + debug: config.getEnv('logs.level') === 'debug', + }, + personalizationSurveyEnabled: + config.getEnv('personalization.enabled') && config.getEnv('diagnostics.enabled'), + defaultLocale: config.getEnv('defaultLocale'), + userManagement: { + quota: this.license.getUsersLimit(), + showSetupOnFirstLoad: !config.getEnv('userManagement.isInstanceOwnerSetUp'), + smtpSetup: isEmailSetUp(), + authenticationMethod: getCurrentAuthenticationMethod(), + }, + sso: { + saml: { + loginEnabled: false, + loginLabel: '', + }, + ldap: { + loginEnabled: false, + loginLabel: '', + }, + }, + publicApi: { + enabled: !config.get('publicApi.disabled') && !this.license.isAPIDisabled(), + latestVersion: 1, + path: config.getEnv('publicApi.path'), + swaggerUi: { + enabled: !config.getEnv('publicApi.swaggerUi.disabled'), + }, + }, + workflowTagsDisabled: config.getEnv('workflowTagsDisabled'), + logLevel: config.getEnv('logs.level'), + hiringBannerEnabled: config.getEnv('hiringBanner.enabled'), + templates: { + enabled: config.getEnv('templates.enabled'), + host: config.getEnv('templates.host'), + }, + onboardingCallPromptEnabled: config.getEnv('onboardingCallPrompt.enabled'), + executionMode: config.getEnv('executions.mode'), + pushBackend: config.getEnv('push.backend'), + communityNodesEnabled: config.getEnv('nodes.communityPackages.enabled'), + deployment: { + type: config.getEnv('deployment.type'), + }, + isNpmAvailable: false, + allowedModules: { + builtIn: process.env.NODE_FUNCTION_ALLOW_BUILTIN?.split(',') ?? undefined, + external: process.env.NODE_FUNCTION_ALLOW_EXTERNAL?.split(',') ?? undefined, + }, + enterprise: { + sharing: false, + ldap: false, + saml: false, + logStreaming: false, + advancedExecutionFilters: false, + variables: false, + sourceControl: false, + auditLogs: false, + externalSecrets: false, + showNonProdBanner: false, + debugInEditor: false, + workflowHistory: false, + }, + mfa: { + enabled: false, + }, + hideUsagePage: config.getEnv('hideUsagePage'), + license: { + environment: config.getEnv('license.tenantId') === 1 ? 'production' : 'staging', + }, + variables: { + limit: 0, + }, + expressions: { + evaluator: config.getEnv('expression.evaluator'), + }, + banners: { + dismissed: [], + }, + ai: { + enabled: config.getEnv('ai.enabled'), + }, + workflowHistory: { + pruneTime: -1, + licensePruneTime: -1, + }, + }; + } async generateTypes() { this.overwriteCredentialsProperties(); @@ -29,6 +193,93 @@ export class FrontendService { this.writeStaticJSON('credentials', credentials); } + async getSettings(): Promise { + const restEndpoint = config.getEnv('endpoints.rest'); + + // Update all urls, in case `WEBHOOK_URL` was updated by `--tunnel` + const instanceBaseUrl = getInstanceBaseUrl(); + this.settings.urlBaseWebhook = WebhookHelpers.getWebhookBaseUrl(); + this.settings.urlBaseEditor = instanceBaseUrl; + this.settings.oauthCallbackUrls = { + oauth1: `${instanceBaseUrl}/${restEndpoint}/oauth1-credential/callback`, + oauth2: `${instanceBaseUrl}/${restEndpoint}/oauth2-credential/callback`, + }; + + // refresh user management status + Object.assign(this.settings.userManagement, { + quota: this.license.getUsersLimit(), + authenticationMethod: getCurrentAuthenticationMethod(), + showSetupOnFirstLoad: + !config.getEnv('userManagement.isInstanceOwnerSetUp') && + !config.getEnv('deployment.type').startsWith('desktop_'), + }); + + let dismissedBanners: string[] = []; + + try { + dismissedBanners = config.getEnv('ui.banners.dismissed') ?? []; + } catch { + // not yet in DB + } + + this.settings.banners.dismissed = dismissedBanners; + + // refresh enterprise status + Object.assign(this.settings.enterprise, { + sharing: this.license.isSharingEnabled(), + logStreaming: this.license.isLogStreamingEnabled(), + ldap: this.license.isLdapEnabled(), + saml: this.license.isSamlEnabled(), + advancedExecutionFilters: this.license.isAdvancedExecutionFiltersEnabled(), + variables: this.license.isVariablesEnabled(), + sourceControl: this.license.isSourceControlLicensed(), + externalSecrets: this.license.isExternalSecretsEnabled(), + showNonProdBanner: this.license.isFeatureEnabled(LICENSE_FEATURES.SHOW_NON_PROD_BANNER), + debugInEditor: this.license.isDebugInEditorLicensed(), + workflowHistory: + this.license.isWorkflowHistoryLicensed() && config.getEnv('workflowHistory.enabled'), + }); + + if (this.license.isLdapEnabled()) { + Object.assign(this.settings.sso.ldap, { + loginLabel: getLdapLoginLabel(), + loginEnabled: config.getEnv('sso.ldap.loginEnabled'), + }); + } + + if (this.license.isSamlEnabled()) { + Object.assign(this.settings.sso.saml, { + loginLabel: getSamlLoginLabel(), + loginEnabled: config.getEnv('sso.saml.loginEnabled'), + }); + } + + if (this.license.isVariablesEnabled()) { + this.settings.variables.limit = getVariablesLimit(); + } + + if (this.license.isWorkflowHistoryLicensed() && config.getEnv('workflowHistory.enabled')) { + Object.assign(this.settings.workflowHistory, { + pruneTime: getWorkflowHistoryPruneTime(), + licensePruneTime: getWorkflowHistoryLicensePruneTime(), + }); + } + + if (config.getEnv('nodes.communityPackages.enabled')) { + // eslint-disable-next-line @typescript-eslint/naming-convention + const { CommunityPackagesService } = await import('@/services/communityPackages.service'); + this.settings.missingPackages = Container.get(CommunityPackagesService).hasMissingPackages; + } + + this.settings.mfa.enabled = config.get('mfa.enabled'); + + return this.settings; + } + + addToSettings(newSettings: Record) { + this.settings = { ...this.settings, ...newSettings }; + } + private writeStaticJSON(name: string, data: INodeTypeBaseDescription[] | ICredentialType[]) { const filePath = path.join(GENERATED_STATIC_DIR, `types/${name}.json`); const stream = createWriteStream(filePath, 'utf-8');