mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 01:56:46 +00:00
refactor(core): Modularize community packages (#18641)
This commit is contained in:
@@ -22,7 +22,10 @@ describe('eligibleModules', () => {
|
||||
|
||||
it('should consider a module ineligible if it was disabled via env var', () => {
|
||||
process.env.N8N_DISABLED_MODULES = 'insights';
|
||||
expect(Container.get(ModuleRegistry).eligibleModules).toEqual(['external-secrets']);
|
||||
expect(Container.get(ModuleRegistry).eligibleModules).toEqual([
|
||||
'external-secrets',
|
||||
'community-packages',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should consider a module eligible if it was enabled via env var', () => {
|
||||
@@ -30,6 +33,7 @@ describe('eligibleModules', () => {
|
||||
expect(Container.get(ModuleRegistry).eligibleModules).toEqual([
|
||||
'insights',
|
||||
'external-secrets',
|
||||
'community-packages',
|
||||
'data-store',
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -26,7 +26,11 @@ export class ModuleRegistry {
|
||||
private readonly modulesConfig: ModulesConfig,
|
||||
) {}
|
||||
|
||||
private readonly defaultModules: ModuleName[] = ['insights', 'external-secrets'];
|
||||
private readonly defaultModules: ModuleName[] = [
|
||||
'insights',
|
||||
'external-secrets',
|
||||
'community-packages',
|
||||
];
|
||||
|
||||
private readonly activeModules: string[] = [];
|
||||
|
||||
@@ -83,7 +87,7 @@ export class ModuleRegistry {
|
||||
|
||||
if (entities?.length) this.entities.push(...entities);
|
||||
|
||||
const loadDir = Container.get(ModuleClass).loadDir?.();
|
||||
const loadDir = await Container.get(ModuleClass).loadDir?.();
|
||||
|
||||
if (loadDir) this.loadDirs.push(loadDir);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,12 @@ import { CommaSeparatedStringArray, Config, Env } from '@n8n/config';
|
||||
|
||||
import { UnknownModuleError } from './errors/unknown-module.error';
|
||||
|
||||
export const MODULE_NAMES = ['insights', 'external-secrets', 'data-store'] as const;
|
||||
export const MODULE_NAMES = [
|
||||
'insights',
|
||||
'external-secrets',
|
||||
'community-packages',
|
||||
'data-store',
|
||||
] as const;
|
||||
|
||||
export type ModuleName = (typeof MODULE_NAMES)[number];
|
||||
|
||||
|
||||
@@ -11,8 +11,6 @@ import { ExecutionEntity } from './execution-entity';
|
||||
import { ExecutionMetadata } from './execution-metadata';
|
||||
import { Folder } from './folder';
|
||||
import { FolderTagMapping } from './folder-tag-mapping';
|
||||
import { InstalledNodes } from './installed-nodes';
|
||||
import { InstalledPackages } from './installed-packages';
|
||||
import { InvalidAuthToken } from './invalid-auth-token';
|
||||
import { ProcessedData } from './processed-data';
|
||||
import { Project } from './project';
|
||||
@@ -35,8 +33,6 @@ import { WorkflowTagMapping } from './workflow-tag-mapping';
|
||||
|
||||
export {
|
||||
EventDestinations,
|
||||
InstalledNodes,
|
||||
InstalledPackages,
|
||||
InvalidAuthToken,
|
||||
ProcessedData,
|
||||
Settings,
|
||||
@@ -72,8 +68,6 @@ export {
|
||||
|
||||
export const entities = {
|
||||
EventDestinations,
|
||||
InstalledNodes,
|
||||
InstalledPackages,
|
||||
InvalidAuthToken,
|
||||
ProcessedData,
|
||||
Settings,
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
import { Column, Entity, JoinColumn, ManyToOne, PrimaryColumn } from '@n8n/typeorm';
|
||||
|
||||
import { InstalledPackages } from './installed-packages';
|
||||
|
||||
@Entity()
|
||||
export class InstalledNodes {
|
||||
@Column()
|
||||
name: string;
|
||||
|
||||
@PrimaryColumn()
|
||||
type: string;
|
||||
|
||||
@Column()
|
||||
latestVersion: number;
|
||||
|
||||
@ManyToOne('InstalledPackages', 'installedNodes')
|
||||
@JoinColumn({ name: 'package', referencedColumnName: 'packageName' })
|
||||
package: InstalledPackages;
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
import { Column, Entity, JoinColumn, OneToMany, PrimaryColumn } from '@n8n/typeorm';
|
||||
|
||||
import { WithTimestamps } from './abstract-entity';
|
||||
import type { InstalledNodes } from './installed-nodes';
|
||||
|
||||
@Entity()
|
||||
export class InstalledPackages extends WithTimestamps {
|
||||
@PrimaryColumn()
|
||||
packageName: string;
|
||||
|
||||
@Column()
|
||||
installedVersion: string;
|
||||
|
||||
@Column()
|
||||
authorName?: string;
|
||||
|
||||
@Column()
|
||||
authorEmail?: string;
|
||||
|
||||
@OneToMany('InstalledNodes', 'package')
|
||||
@JoinColumn({ referencedColumnName: 'package' })
|
||||
installedNodes: InstalledNodes[];
|
||||
}
|
||||
@@ -12,8 +12,6 @@ export { EventDestinationsRepository } from './event-destinations.repository';
|
||||
export { FolderRepository } from './folder.repository';
|
||||
export { FolderTagMappingRepository } from './folder-tag-mapping.repository';
|
||||
export { ScopeRepository } from './scope.repository';
|
||||
export { InstalledNodesRepository } from './installed-nodes.repository';
|
||||
export { InstalledPackagesRepository } from './installed-packages.repository';
|
||||
export { InvalidAuthTokenRepository } from './invalid-auth-token.repository';
|
||||
export { LicenseMetricsRepository } from './license-metrics.repository';
|
||||
export { ProjectRelationRepository } from './project-relation.repository';
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
import { Service } from '@n8n/di';
|
||||
import { DataSource, Repository } from '@n8n/typeorm';
|
||||
|
||||
import { InstalledNodes } from '../entities';
|
||||
|
||||
@Service()
|
||||
export class InstalledNodesRepository extends Repository<InstalledNodes> {
|
||||
constructor(dataSource: DataSource) {
|
||||
super(InstalledNodes, dataSource.manager);
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
import { Service } from '@n8n/di';
|
||||
import { DataSource, Repository } from '@n8n/typeorm';
|
||||
import type { PackageDirectoryLoader } from 'n8n-core';
|
||||
|
||||
import { InstalledNodesRepository } from './installed-nodes.repository';
|
||||
import { InstalledPackages } from '../entities';
|
||||
|
||||
@Service()
|
||||
export class InstalledPackagesRepository extends Repository<InstalledPackages> {
|
||||
constructor(
|
||||
dataSource: DataSource,
|
||||
private installedNodesRepository: InstalledNodesRepository,
|
||||
) {
|
||||
super(InstalledPackages, dataSource.manager);
|
||||
}
|
||||
|
||||
async saveInstalledPackageWithNodes(packageLoader: PackageDirectoryLoader) {
|
||||
const { packageJson, nodeTypes, loadedNodes } = packageLoader;
|
||||
const { name: packageName, version: installedVersion, author } = packageJson;
|
||||
|
||||
let installedPackage: InstalledPackages;
|
||||
|
||||
await this.manager.transaction(async (manager) => {
|
||||
installedPackage = await manager.save(
|
||||
this.create({
|
||||
packageName,
|
||||
installedVersion,
|
||||
authorName: author?.name,
|
||||
authorEmail: author?.email,
|
||||
}),
|
||||
);
|
||||
|
||||
installedPackage.installedNodes = [];
|
||||
|
||||
for (const loadedNode of loadedNodes) {
|
||||
const installedNode = this.installedNodesRepository.create({
|
||||
name: nodeTypes[loadedNode.name].type.description.displayName,
|
||||
type: `${packageName}.${loadedNode.name}`,
|
||||
latestVersion: loadedNode.version,
|
||||
package: { packageName },
|
||||
});
|
||||
|
||||
installedPackage.installedNodes.push(installedNode);
|
||||
|
||||
await manager.save(installedNode);
|
||||
}
|
||||
});
|
||||
|
||||
return installedPackage!;
|
||||
}
|
||||
}
|
||||
@@ -33,10 +33,10 @@ export interface ModuleInterface {
|
||||
settings?(): Promise<ModuleSettings>;
|
||||
|
||||
/**
|
||||
* @returns Path to a dir to load nodes and credentials from.
|
||||
* @returns Path to a dir to load nodes and credentials from. `null` to skip.
|
||||
* @example '/Users/nathan/.n8n/nodes/node_modules'
|
||||
*/
|
||||
loadDir?(): string;
|
||||
loadDir?(): Promise<string | null>;
|
||||
}
|
||||
|
||||
export type ModuleClass = Constructable<ModuleInterface>;
|
||||
|
||||
Reference in New Issue
Block a user