mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 18:12:04 +00:00
refactor(core): Move module logic to @n8n/backend-common (#16528)
Co-authored-by: Danny Martini <danny@n8n.io>
This commit is contained in:
@@ -23,6 +23,7 @@
|
||||
"dependencies": {
|
||||
"@n8n/config": "workspace:^",
|
||||
"@n8n/constants": "workspace:^",
|
||||
"@n8n/decorators": "workspace:^",
|
||||
"@n8n/di": "workspace:^",
|
||||
"callsites": "catalog:",
|
||||
"n8n-workflow": "workspace:^",
|
||||
|
||||
@@ -4,3 +4,5 @@ export * from './types';
|
||||
export { inDevelopment, inProduction, inTest } from './environment';
|
||||
export { isObjectLiteral } from './utils/is-object-literal';
|
||||
export { Logger } from './logging/logger';
|
||||
export { ModuleRegistry } from './modules/module-registry';
|
||||
export { ModulesConfig, ModuleName } from './modules/modules.config';
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import type { LicenseState } from '@n8n/backend-common';
|
||||
import type { ModuleInterface, ModuleMetadata } from '@n8n/decorators';
|
||||
import { Container } from '@n8n/di';
|
||||
import { mock } from 'jest-mock-extended';
|
||||
|
||||
import type { LicenseState } from '../../license-state';
|
||||
import { ModuleConfusionError } from '../errors/module-confusion.error';
|
||||
import { ModuleRegistry } from '../module-registry';
|
||||
import { MODULE_NAMES } from '../modules.config';
|
||||
@@ -43,7 +43,7 @@ describe('loadModules', () => {
|
||||
});
|
||||
|
||||
Container.get = jest.fn().mockReturnValue(ModuleClass);
|
||||
const moduleRegistry = new ModuleRegistry(moduleMetadata, mock(), mock(), mock(), mock());
|
||||
const moduleRegistry = new ModuleRegistry(moduleMetadata, mock(), mock(), mock());
|
||||
|
||||
await moduleRegistry.loadModules([]);
|
||||
|
||||
@@ -57,7 +57,7 @@ describe('loadModules', () => {
|
||||
});
|
||||
|
||||
Container.get = jest.fn().mockReturnValue(ModuleClass);
|
||||
const moduleRegistry = new ModuleRegistry(moduleMetadata, mock(), mock(), mock(), mock());
|
||||
const moduleRegistry = new ModuleRegistry(moduleMetadata, mock(), mock(), mock());
|
||||
|
||||
await moduleRegistry.loadModules([]);
|
||||
|
||||
@@ -75,7 +75,7 @@ describe('initModules', () => {
|
||||
});
|
||||
Container.get = jest.fn().mockReturnValue(ModuleClass);
|
||||
|
||||
const moduleRegistry = new ModuleRegistry(moduleMetadata, mock(), mock(), mock(), mock());
|
||||
const moduleRegistry = new ModuleRegistry(moduleMetadata, mock(), mock(), mock());
|
||||
|
||||
await moduleRegistry.initModules();
|
||||
|
||||
@@ -94,7 +94,7 @@ describe('initModules', () => {
|
||||
const licenseState = mock<LicenseState>({ isLicensed: jest.fn().mockReturnValue(true) });
|
||||
Container.get = jest.fn().mockReturnValue(ModuleClass);
|
||||
|
||||
const moduleRegistry = new ModuleRegistry(moduleMetadata, mock(), licenseState, mock(), mock());
|
||||
const moduleRegistry = new ModuleRegistry(moduleMetadata, licenseState, mock(), mock());
|
||||
|
||||
await moduleRegistry.initModules();
|
||||
|
||||
@@ -113,7 +113,7 @@ describe('initModules', () => {
|
||||
const licenseState = mock<LicenseState>({ isLicensed: jest.fn().mockReturnValue(false) });
|
||||
Container.get = jest.fn().mockReturnValue(ModuleClass);
|
||||
|
||||
const moduleRegistry = new ModuleRegistry(moduleMetadata, mock(), licenseState, mock(), mock());
|
||||
const moduleRegistry = new ModuleRegistry(moduleMetadata, licenseState, mock(), mock());
|
||||
|
||||
await moduleRegistry.initModules();
|
||||
|
||||
@@ -130,7 +130,7 @@ describe('initModules', () => {
|
||||
|
||||
Container.get = jest.fn().mockReturnValue(ModuleClass);
|
||||
|
||||
const moduleRegistry = new ModuleRegistry(moduleMetadata, mock(), mock(), mock(), mock());
|
||||
const moduleRegistry = new ModuleRegistry(moduleMetadata, mock(), mock(), mock());
|
||||
|
||||
await moduleRegistry.initModules();
|
||||
|
||||
@@ -150,7 +150,7 @@ describe('initModules', () => {
|
||||
});
|
||||
Container.get = jest.fn().mockReturnValue(ModuleClass);
|
||||
|
||||
const moduleRegistry = new ModuleRegistry(moduleMetadata, mock(), mock(), mock(), mock());
|
||||
const moduleRegistry = new ModuleRegistry(moduleMetadata, mock(), mock(), mock());
|
||||
|
||||
// ACT
|
||||
await moduleRegistry.initModules();
|
||||
@@ -174,12 +174,13 @@ describe('initModules', () => {
|
||||
});
|
||||
Container.get = jest.fn().mockReturnValue(ModuleClass);
|
||||
|
||||
const moduleRegistry = new ModuleRegistry(moduleMetadata, mock(), mock(), mock(), mock());
|
||||
const moduleRegistry = new ModuleRegistry(moduleMetadata, mock(), mock(), mock());
|
||||
|
||||
// ACT
|
||||
await moduleRegistry.initModules();
|
||||
|
||||
// ASSERT
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
expect(moduleRegistry.isActive(moduleName as any)).toBe(true);
|
||||
expect(moduleRegistry.getActiveModules()).toEqual([moduleName]);
|
||||
});
|
||||
113
packages/@n8n/backend-common/src/modules/module-registry.ts
Normal file
113
packages/@n8n/backend-common/src/modules/module-registry.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
import { ModuleMetadata } from '@n8n/decorators';
|
||||
import type { EntityClass, ModuleSettings } from '@n8n/decorators';
|
||||
import { Container, Service } from '@n8n/di';
|
||||
import path from 'path';
|
||||
|
||||
import { MissingModuleError } from './errors/missing-module.error';
|
||||
import { ModuleConfusionError } from './errors/module-confusion.error';
|
||||
import { ModulesConfig } from './modules.config';
|
||||
import type { ModuleName } from './modules.config';
|
||||
import { LicenseState } from '../license-state';
|
||||
import { Logger } from '../logging/logger';
|
||||
|
||||
@Service()
|
||||
export class ModuleRegistry {
|
||||
readonly entities: EntityClass[] = [];
|
||||
|
||||
readonly settings: Map<string, ModuleSettings> = new Map();
|
||||
|
||||
constructor(
|
||||
private readonly moduleMetadata: ModuleMetadata,
|
||||
private readonly licenseState: LicenseState,
|
||||
private readonly logger: Logger,
|
||||
private readonly modulesConfig: ModulesConfig,
|
||||
) {}
|
||||
|
||||
private readonly defaultModules: ModuleName[] = ['insights', 'external-secrets'];
|
||||
|
||||
private readonly activeModules: string[] = [];
|
||||
|
||||
get eligibleModules(): ModuleName[] {
|
||||
const { enabledModules, disabledModules } = this.modulesConfig;
|
||||
|
||||
const doubleListed = enabledModules.filter((m) => disabledModules.includes(m));
|
||||
|
||||
if (doubleListed.length > 0) throw new ModuleConfusionError(doubleListed);
|
||||
|
||||
const defaultPlusEnabled = [...new Set([...this.defaultModules, ...enabledModules])];
|
||||
|
||||
return defaultPlusEnabled.filter((m) => !disabledModules.includes(m));
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads [module name].module.ts for each eligible module.
|
||||
* This only registers the database entities for module and should be done
|
||||
* before instantiating the datasource.
|
||||
*
|
||||
* This will not register routes or do any other kind of module related
|
||||
* setup.
|
||||
*/
|
||||
async loadModules(modules?: ModuleName[]) {
|
||||
const moduleDir = process.env.NODE_ENV === 'test' ? 'src' : 'dist';
|
||||
const modulesDir = path.resolve(__dirname, `../../../../cli/${moduleDir}/modules`);
|
||||
|
||||
for (const moduleName of modules ?? this.eligibleModules) {
|
||||
try {
|
||||
await import(`${modulesDir}/${moduleName}/${moduleName}.module`);
|
||||
} catch {
|
||||
try {
|
||||
await import(`${modulesDir}/${moduleName}.ee/${moduleName}.module`);
|
||||
} catch (error) {
|
||||
throw new MissingModuleError(moduleName, error instanceof Error ? error.message : '');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const ModuleClass of this.moduleMetadata.getClasses()) {
|
||||
const entities = Container.get(ModuleClass).entities?.();
|
||||
|
||||
if (!entities || entities.length === 0) continue;
|
||||
|
||||
this.entities.push(...entities);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls `init` on each eligible module.
|
||||
*
|
||||
* This will do things like registering routes, setup timers or other module
|
||||
* specific setup.
|
||||
*
|
||||
* `ModuleRegistry.loadModules` must have been called before.
|
||||
*/
|
||||
async initModules() {
|
||||
for (const [moduleName, moduleEntry] of this.moduleMetadata.getEntries()) {
|
||||
const { licenseFlag, class: ModuleClass } = moduleEntry;
|
||||
|
||||
if (licenseFlag && !this.licenseState.isLicensed(licenseFlag)) {
|
||||
this.logger.debug(`Skipped init for unlicensed module "${moduleName}"`);
|
||||
continue;
|
||||
}
|
||||
|
||||
await Container.get(ModuleClass).init?.();
|
||||
|
||||
const moduleSettings = await Container.get(ModuleClass).settings?.();
|
||||
|
||||
if (!moduleSettings) continue;
|
||||
|
||||
this.settings.set(moduleName, moduleSettings);
|
||||
|
||||
this.logger.debug(`Initialized module "${moduleName}"`);
|
||||
|
||||
this.activeModules.push(moduleName);
|
||||
}
|
||||
}
|
||||
|
||||
isActive(moduleName: ModuleName) {
|
||||
return this.activeModules.includes(moduleName);
|
||||
}
|
||||
|
||||
getActiveModules() {
|
||||
return this.activeModules;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,12 @@
|
||||
import 'reflect-metadata';
|
||||
import { inDevelopment, inTest, LicenseState, Logger } from '@n8n/backend-common';
|
||||
import {
|
||||
inDevelopment,
|
||||
inTest,
|
||||
LicenseState,
|
||||
Logger,
|
||||
ModuleRegistry,
|
||||
ModulesConfig,
|
||||
} from '@n8n/backend-common';
|
||||
import { GlobalConfig } from '@n8n/config';
|
||||
import { LICENSE_FEATURES } from '@n8n/constants';
|
||||
import { Container } from '@n8n/di';
|
||||
@@ -27,8 +34,6 @@ import { TelemetryEventRelay } from '@/events/relays/telemetry.event-relay';
|
||||
import { ExternalHooks } from '@/external-hooks';
|
||||
import { License } from '@/license';
|
||||
import { LoadNodesAndCredentials } from '@/load-nodes-and-credentials';
|
||||
import { ModuleRegistry } from '@/modules/module-registry';
|
||||
import { ModulesConfig } from '@/modules/modules.config';
|
||||
import { NodeTypes } from '@/node-types';
|
||||
import { PostHogClient } from '@/posthog';
|
||||
import { ShutdownService } from '@/shutdown/shutdown.service';
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { ModuleRegistry } from '@n8n/backend-common';
|
||||
import type { GlobalConfig, InstanceSettingsConfig } from '@n8n/config';
|
||||
import { mysqlMigrations } from '@n8n/db';
|
||||
import { postgresMigrations } from '@n8n/db';
|
||||
@@ -5,8 +6,6 @@ import { sqliteMigrations } from '@n8n/db';
|
||||
import { mock } from 'jest-mock-extended';
|
||||
import path from 'path';
|
||||
|
||||
import type { ModuleRegistry } from '@/modules/module-registry';
|
||||
|
||||
import { DbConnectionOptions } from '../db-connection-options';
|
||||
|
||||
describe('DbConnectionOptions', () => {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { ModuleRegistry } from '@n8n/backend-common';
|
||||
import { DatabaseConfig, InstanceSettingsConfig } from '@n8n/config';
|
||||
import {
|
||||
entities,
|
||||
@@ -16,8 +17,6 @@ import { UserError } from 'n8n-workflow';
|
||||
import path from 'path';
|
||||
import type { TlsOptions } from 'tls';
|
||||
|
||||
import { ModuleRegistry } from '@/modules/module-registry';
|
||||
|
||||
@Service()
|
||||
export class DbConnectionOptions {
|
||||
constructor(
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Logger } from '@n8n/backend-common';
|
||||
import { ExecutionRepository } from '@n8n/db';
|
||||
import { Container } from '@n8n/di';
|
||||
import { LifecycleMetadata } from '@n8n/decorators';
|
||||
import { Container, Service } from '@n8n/di';
|
||||
import { stringify } from 'flatted';
|
||||
import { ErrorReporter, InstanceSettings, ExecutionLifecycleHooks } from 'n8n-core';
|
||||
import type {
|
||||
@@ -11,7 +12,6 @@ import type {
|
||||
|
||||
import { EventService } from '@/events/event.service';
|
||||
import { ExternalHooks } from '@/external-hooks';
|
||||
import { ModuleRegistry } from '@/modules/module-registry';
|
||||
import { Push } from '@/push';
|
||||
import { WorkflowStatisticsService } from '@/services/workflow-statistics.service';
|
||||
import { isWorkflowIdValid } from '@/utils';
|
||||
@@ -28,6 +28,72 @@ import {
|
||||
} from './shared/shared-hook-functions';
|
||||
import { type ExecutionSaveSettings, toSaveSettings } from './to-save-settings';
|
||||
|
||||
@Service()
|
||||
class ModulesHooksRegistry {
|
||||
addHooks(hooks: ExecutionLifecycleHooks) {
|
||||
const handlers = Container.get(LifecycleMetadata).getHandlers();
|
||||
|
||||
for (const { handlerClass, methodName, eventName } of handlers) {
|
||||
const instance = Container.get(handlerClass);
|
||||
|
||||
switch (eventName) {
|
||||
case 'workflowExecuteAfter':
|
||||
hooks.addHandler(eventName, async function (runData, newStaticData) {
|
||||
const context = {
|
||||
type: 'workflowExecuteAfter',
|
||||
workflow: this.workflowData,
|
||||
runData,
|
||||
newStaticData,
|
||||
};
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/return-await
|
||||
return await instance[methodName].call(instance, context);
|
||||
});
|
||||
break;
|
||||
|
||||
case 'nodeExecuteBefore':
|
||||
hooks.addHandler(eventName, async function (nodeName, taskData) {
|
||||
const context = {
|
||||
type: 'nodeExecuteBefore',
|
||||
workflow: this.workflowData,
|
||||
nodeName,
|
||||
taskData,
|
||||
};
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/return-await
|
||||
return await instance[methodName].call(instance, context);
|
||||
});
|
||||
break;
|
||||
|
||||
case 'nodeExecuteAfter':
|
||||
hooks.addHandler(eventName, async function (nodeName, taskData, executionData) {
|
||||
const context = {
|
||||
type: 'nodeExecuteAfter',
|
||||
workflow: this.workflowData,
|
||||
nodeName,
|
||||
taskData,
|
||||
executionData,
|
||||
};
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/return-await
|
||||
return await instance[methodName].call(instance, context);
|
||||
});
|
||||
break;
|
||||
|
||||
case 'workflowExecuteBefore':
|
||||
hooks.addHandler(eventName, async function (workflowInstance, executionData) {
|
||||
const context = {
|
||||
type: 'workflowExecuteBefore',
|
||||
workflow: this.workflowData,
|
||||
workflowInstance,
|
||||
executionData,
|
||||
};
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/return-await
|
||||
return await instance[methodName].call(instance, context);
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type HooksSetupParameters = {
|
||||
saveSettings: ExecutionSaveSettings;
|
||||
pushRef?: string;
|
||||
@@ -425,7 +491,7 @@ export function getLifecycleHooksForScalingWorker(
|
||||
hookFunctionsPush(hooks, optionalParameters);
|
||||
}
|
||||
|
||||
Container.get(ModuleRegistry).registerLifecycleHooks(hooks);
|
||||
Container.get(ModulesHooksRegistry).addHooks(hooks);
|
||||
|
||||
return hooks;
|
||||
}
|
||||
@@ -487,7 +553,7 @@ export function getLifecycleHooksForScalingMain(
|
||||
hooks.handlers.nodeExecuteBefore = [];
|
||||
hooks.handlers.nodeExecuteAfter = [];
|
||||
|
||||
Container.get(ModuleRegistry).registerLifecycleHooks(hooks);
|
||||
Container.get(ModulesHooksRegistry).addHooks(hooks);
|
||||
|
||||
return hooks;
|
||||
}
|
||||
@@ -511,6 +577,6 @@ export function getLifecycleHooksForRegularMain(
|
||||
hookFunctionsSaveProgress(hooks, optionalParameters);
|
||||
hookFunctionsStatistics(hooks);
|
||||
hookFunctionsExternalHooks(hooks);
|
||||
Container.get(ModuleRegistry).registerLifecycleHooks(hooks);
|
||||
Container.get(ModulesHooksRegistry).addHooks(hooks);
|
||||
return hooks;
|
||||
}
|
||||
|
||||
@@ -1,214 +0,0 @@
|
||||
import { LicenseState, Logger } from '@n8n/backend-common';
|
||||
import { LifecycleMetadata, ModuleMetadata } from '@n8n/decorators';
|
||||
import type { LifecycleContext, EntityClass, ModuleSettings } from '@n8n/decorators';
|
||||
import { Container, Service } from '@n8n/di';
|
||||
import type { ExecutionLifecycleHooks } from 'n8n-core';
|
||||
import type {
|
||||
IDataObject,
|
||||
IRun,
|
||||
IRunExecutionData,
|
||||
ITaskData,
|
||||
ITaskStartedData,
|
||||
IWorkflowBase,
|
||||
Workflow,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import { MissingModuleError } from './errors/missing-module.error';
|
||||
import { ModuleConfusionError } from './errors/module-confusion.error';
|
||||
import { ModulesConfig } from './modules.config';
|
||||
import type { ModuleName } from './modules.config';
|
||||
|
||||
@Service()
|
||||
export class ModuleRegistry {
|
||||
readonly entities: EntityClass[] = [];
|
||||
|
||||
readonly settings: Map<string, ModuleSettings> = new Map();
|
||||
|
||||
constructor(
|
||||
private readonly moduleMetadata: ModuleMetadata,
|
||||
private readonly lifecycleMetadata: LifecycleMetadata,
|
||||
private readonly licenseState: LicenseState,
|
||||
private readonly logger: Logger,
|
||||
private readonly modulesConfig: ModulesConfig,
|
||||
) {}
|
||||
|
||||
private readonly defaultModules: ModuleName[] = ['insights', 'external-secrets'];
|
||||
|
||||
private readonly activeModules: string[] = [];
|
||||
|
||||
get eligibleModules(): ModuleName[] {
|
||||
const { enabledModules, disabledModules } = this.modulesConfig;
|
||||
|
||||
const doubleListed = enabledModules.filter((m) => disabledModules.includes(m));
|
||||
|
||||
if (doubleListed.length > 0) throw new ModuleConfusionError(doubleListed);
|
||||
|
||||
const defaultPlusEnabled = [...new Set([...this.defaultModules, ...enabledModules])];
|
||||
|
||||
return defaultPlusEnabled.filter((m) => !disabledModules.includes(m));
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads [module name].module.ts for each eligible module.
|
||||
* This only registers the database entities for module and should be done
|
||||
* before instantiating the datasource.
|
||||
*
|
||||
* This will not register routes or do any other kind of module related
|
||||
* setup.
|
||||
*/
|
||||
async loadModules(modules?: ModuleName[]) {
|
||||
for (const moduleName of modules ?? this.eligibleModules) {
|
||||
try {
|
||||
await import(`../modules/${moduleName}/${moduleName}.module`);
|
||||
} catch {
|
||||
try {
|
||||
await import(`../modules/${moduleName}.ee/${moduleName}.module`);
|
||||
} catch (error) {
|
||||
throw new MissingModuleError(moduleName, error instanceof Error ? error.message : '');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const ModuleClass of this.moduleMetadata.getClasses()) {
|
||||
const entities = Container.get(ModuleClass).entities?.();
|
||||
|
||||
if (!entities || entities.length === 0) continue;
|
||||
|
||||
this.entities.push(...entities);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls `init` on each eligible module.
|
||||
*
|
||||
* This will do things like registering routes, setup timers or other module
|
||||
* specific setup.
|
||||
*
|
||||
* `ModuleRegistry.loadModules` must have been called before.
|
||||
*/
|
||||
async initModules() {
|
||||
for (const [moduleName, moduleEntry] of this.moduleMetadata.getEntries()) {
|
||||
const { licenseFlag, class: ModuleClass } = moduleEntry;
|
||||
|
||||
if (licenseFlag && !this.licenseState.isLicensed(licenseFlag)) {
|
||||
this.logger.debug(`Skipped init for unlicensed module "${moduleName}"`);
|
||||
continue;
|
||||
}
|
||||
|
||||
await Container.get(ModuleClass).init?.();
|
||||
|
||||
const moduleSettings = await Container.get(ModuleClass).settings?.();
|
||||
|
||||
if (!moduleSettings) continue;
|
||||
|
||||
this.settings.set(moduleName, moduleSettings);
|
||||
|
||||
this.logger.debug(`Initialized module "${moduleName}"`);
|
||||
|
||||
this.activeModules.push(moduleName);
|
||||
}
|
||||
}
|
||||
|
||||
isActive(moduleName: ModuleName) {
|
||||
return this.activeModules.includes(moduleName);
|
||||
}
|
||||
|
||||
getActiveModules() {
|
||||
return this.activeModules;
|
||||
}
|
||||
|
||||
registerLifecycleHooks(hooks: ExecutionLifecycleHooks) {
|
||||
const handlers = this.lifecycleMetadata.getHandlers();
|
||||
|
||||
for (const { handlerClass, methodName, eventName } of handlers) {
|
||||
const instance = Container.get(handlerClass);
|
||||
|
||||
switch (eventName) {
|
||||
case 'workflowExecuteAfter':
|
||||
hooks.addHandler(
|
||||
eventName,
|
||||
async function (
|
||||
this: { workflowData: IWorkflowBase },
|
||||
runData: IRun,
|
||||
newStaticData: IDataObject,
|
||||
) {
|
||||
const context: LifecycleContext = {
|
||||
type: 'workflowExecuteAfter',
|
||||
workflow: this.workflowData,
|
||||
runData,
|
||||
newStaticData,
|
||||
};
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/return-await
|
||||
return await instance[methodName].call(instance, context);
|
||||
},
|
||||
);
|
||||
break;
|
||||
|
||||
case 'nodeExecuteBefore':
|
||||
hooks.addHandler(
|
||||
eventName,
|
||||
async function (
|
||||
this: { workflowData: IWorkflowBase },
|
||||
nodeName: string,
|
||||
taskData: ITaskStartedData,
|
||||
) {
|
||||
const context: LifecycleContext = {
|
||||
type: 'nodeExecuteBefore',
|
||||
workflow: this.workflowData,
|
||||
nodeName,
|
||||
taskData,
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/return-await
|
||||
return await instance[methodName].call(instance, context);
|
||||
},
|
||||
);
|
||||
break;
|
||||
|
||||
case 'nodeExecuteAfter':
|
||||
hooks.addHandler(
|
||||
eventName,
|
||||
async function (
|
||||
this: { workflowData: IWorkflowBase },
|
||||
nodeName: string,
|
||||
taskData: ITaskData,
|
||||
executionData: IRunExecutionData,
|
||||
) {
|
||||
const context: LifecycleContext = {
|
||||
type: 'nodeExecuteAfter',
|
||||
workflow: this.workflowData,
|
||||
nodeName,
|
||||
taskData,
|
||||
executionData,
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/return-await
|
||||
return await instance[methodName].call(instance, context);
|
||||
},
|
||||
);
|
||||
break;
|
||||
|
||||
case 'workflowExecuteBefore':
|
||||
hooks.addHandler(
|
||||
eventName,
|
||||
async function (
|
||||
this: { workflowData: IWorkflowBase },
|
||||
workflowInstance: Workflow,
|
||||
executionData?: IRunExecutionData,
|
||||
) {
|
||||
const context: LifecycleContext = {
|
||||
type: 'workflowExecuteBefore',
|
||||
workflow: this.workflowData,
|
||||
workflowInstance,
|
||||
executionData,
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/return-await
|
||||
return await instance[methodName].call(instance, context);
|
||||
},
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { FrontendSettings, ITelemetrySettings } from '@n8n/api-types';
|
||||
import { LicenseState, Logger } from '@n8n/backend-common';
|
||||
import { LicenseState, Logger, ModuleRegistry } from '@n8n/backend-common';
|
||||
import { GlobalConfig, SecurityConfig } from '@n8n/config';
|
||||
import { LICENSE_FEATURES } from '@n8n/constants';
|
||||
import { Container, Service } from '@n8n/di';
|
||||
@@ -17,7 +17,6 @@ import { CredentialsOverwrites } from '@/credentials-overwrites';
|
||||
import { getLdapLoginLabel } from '@/ldap.ee/helpers.ee';
|
||||
import { License } from '@/license';
|
||||
import { LoadNodesAndCredentials } from '@/load-nodes-and-credentials';
|
||||
import { ModuleRegistry } from '@/modules/module-registry';
|
||||
import { isApiEnabled } from '@/public-api';
|
||||
import { PushConfig } from '@/push/push.config';
|
||||
import type { CommunityPackagesService } from '@/services/community-packages.service';
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { ModuleRegistry } from '@n8n/backend-common';
|
||||
import type { ModuleName } from '@n8n/backend-common';
|
||||
import { Container } from '@n8n/di';
|
||||
|
||||
import { ModuleRegistry } from '@/modules/module-registry';
|
||||
import type { ModuleName } from '@/modules/modules.config';
|
||||
|
||||
export async function loadModules(moduleNames: ModuleName[]) {
|
||||
await Container.get(ModuleRegistry).loadModules(moduleNames);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { LicenseState } from '@n8n/backend-common';
|
||||
import { ModuleRegistry } from '@n8n/backend-common';
|
||||
import { mockLogger } from '@n8n/backend-test-utils';
|
||||
import type { User } from '@n8n/db';
|
||||
import { Container } from '@n8n/di';
|
||||
@@ -14,7 +15,6 @@ import { AUTH_COOKIE_NAME } from '@/constants';
|
||||
import { ControllerRegistry } from '@/controller.registry';
|
||||
import { License } from '@/license';
|
||||
import { rawBodyReader, bodyParser } from '@/middlewares';
|
||||
import { ModuleRegistry } from '@/modules/module-registry';
|
||||
import { PostHogClient } from '@/posthog';
|
||||
import { Push } from '@/push';
|
||||
import type { APIRequest } from '@/requests';
|
||||
|
||||
3
pnpm-lock.yaml
generated
3
pnpm-lock.yaml
generated
@@ -419,6 +419,9 @@ importers:
|
||||
'@n8n/constants':
|
||||
specifier: workspace:^
|
||||
version: link:../constants
|
||||
'@n8n/decorators':
|
||||
specifier: workspace:^
|
||||
version: link:../decorators
|
||||
'@n8n/di':
|
||||
specifier: workspace:^
|
||||
version: link:../di
|
||||
|
||||
Reference in New Issue
Block a user