feat(core): Enable modules to append to workflow context (#18551)

This commit is contained in:
Iván Ovejero
2025-08-25 11:45:25 +02:00
committed by GitHub
parent fb97ec876c
commit 0488ea3e8d
5 changed files with 105 additions and 3 deletions

View File

@@ -221,6 +221,48 @@ describe('initModules', () => {
expect(moduleRegistry.isActive(moduleName as any)).toBe(true);
expect(moduleRegistry.getActiveModules()).toEqual([moduleName]);
});
it('registers context for module with `context` method', async () => {
// ARRANGE
const moduleName = 'test-module';
const moduleContext = { proxy: 'test-proxy', config: { enabled: true } };
const ModuleClass: ModuleInterface = {
init: jest.fn(),
context: jest.fn().mockReturnValue(moduleContext),
};
const moduleMetadata = mock<ModuleMetadata>({
getEntries: jest.fn().mockReturnValue([[moduleName, { class: ModuleClass }]]),
});
Container.get = jest.fn().mockReturnValue(ModuleClass);
const moduleRegistry = new ModuleRegistry(moduleMetadata, mock(), mock(), mock());
// ACT
await moduleRegistry.initModules();
// ASSERT
expect(ModuleClass.context).toHaveBeenCalled();
expect(moduleRegistry.context.has(moduleName)).toBe(true);
expect(moduleRegistry.context.get(moduleName)).toBe(moduleContext);
});
it('does not register context for module without `context` method', async () => {
// ARRANGE
const moduleName = 'test-module';
const ModuleClass: ModuleInterface = { init: jest.fn() };
const moduleMetadata = mock<ModuleMetadata>({
getEntries: jest.fn().mockReturnValue([[moduleName, { class: ModuleClass }]]),
});
Container.get = jest.fn().mockReturnValue(ModuleClass);
const moduleRegistry = new ModuleRegistry(moduleMetadata, mock(), mock(), mock());
// ACT
await moduleRegistry.initModules();
// ASSERT
expect(moduleRegistry.context.has(moduleName)).toBe(false);
});
});
describe('loadDir', () => {

View File

@@ -1,5 +1,5 @@
import { ModuleMetadata } from '@n8n/decorators';
import type { EntityClass, ModuleSettings } from '@n8n/decorators';
import type { EntityClass, ModuleContext, ModuleSettings } from '@n8n/decorators';
import { Container, Service } from '@n8n/di';
import { existsSync } from 'fs';
import path from 'path';
@@ -19,6 +19,8 @@ export class ModuleRegistry {
readonly settings: Map<string, ModuleSettings> = new Map();
readonly context: Map<string, ModuleContext> = new Map();
constructor(
private readonly moduleMetadata: ModuleMetadata,
private readonly licenseState: LicenseState,
@@ -116,6 +118,10 @@ export class ModuleRegistry {
if (moduleSettings) this.settings.set(moduleName, moduleSettings);
const moduleContext = await Container.get(ModuleClass).context?.();
if (moduleContext) this.context.set(moduleName, moduleContext);
this.logger.debug(`Initialized module "${moduleName}"`);
this.activeModules.push(moduleName);