fix(core): Fix issues with community node installation (no-changelog) (#5481)
This fixes the following issues: * After a community node is installed, we were not calling `postProcessLoaders`, which was causing a bunch of unexpected behaviors, and sometimes even crashes. This was only happening in the session where the package was installed. After a crash, the restarted service was working without these issues. * After a community node is installed, the icon for the nodes and credentials were missing in the UI, as we were creating one icons route per installed package at startup, and this did not handle newly installed packages. restarting the service fixes this issue as well. Fixes https://community.n8n.io/t/showing-weird-count-on-community-nodes/23035
This commit is contained in:
committed by
GitHub
parent
6265f3a27a
commit
a9f08fc5ba
@@ -22,7 +22,6 @@ import { access as fsAccess, mkdir, readdir as fsReaddir, stat as fsStat } from
|
||||
import path from 'path';
|
||||
import config from '@/config';
|
||||
import type { InstalledPackages } from '@db/entities/InstalledPackages';
|
||||
import type { InstalledNodes } from '@db/entities/InstalledNodes';
|
||||
import { executeCommand } from '@/CommunityNodes/helpers';
|
||||
import {
|
||||
CLI_DIR,
|
||||
@@ -198,23 +197,13 @@ export class LoadNodesAndCredentialsClass implements INodesAndCredentials {
|
||||
|
||||
const finalNodeUnpackedPath = path.join(downloadFolder, 'node_modules', packageName);
|
||||
|
||||
const { loadedNodes, packageJson } = await this.runDirectoryLoader(
|
||||
PackageDirectoryLoader,
|
||||
finalNodeUnpackedPath,
|
||||
);
|
||||
const loader = await this.runDirectoryLoader(PackageDirectoryLoader, finalNodeUnpackedPath);
|
||||
|
||||
if (loadedNodes.length > 0) {
|
||||
if (loader.loadedNodes.length > 0) {
|
||||
// Save info to DB
|
||||
try {
|
||||
const installedPackage = await persistInstalledPackageData(
|
||||
packageJson.name,
|
||||
packageJson.version,
|
||||
loadedNodes,
|
||||
this.loaded.nodes,
|
||||
packageJson.author?.name,
|
||||
packageJson.author?.email,
|
||||
);
|
||||
this.attachNodesToNodeTypes(installedPackage.installedNodes);
|
||||
const installedPackage = await persistInstalledPackageData(loader);
|
||||
await this.postProcessLoaders();
|
||||
await this.generateTypesForFrontend();
|
||||
return installedPackage;
|
||||
} catch (error) {
|
||||
@@ -242,9 +231,13 @@ export class LoadNodesAndCredentialsClass implements INodesAndCredentials {
|
||||
|
||||
await removePackageFromDatabase(installedPackage);
|
||||
|
||||
await this.generateTypesForFrontend();
|
||||
if (packageName in this.loaders) {
|
||||
this.loaders[packageName].reset();
|
||||
delete this.loaders[packageName];
|
||||
}
|
||||
|
||||
this.unloadNodes(installedPackage.installedNodes);
|
||||
await this.postProcessLoaders();
|
||||
await this.generateTypesForFrontend();
|
||||
}
|
||||
|
||||
async updateNpmModule(
|
||||
@@ -264,33 +257,17 @@ export class LoadNodesAndCredentialsClass implements INodesAndCredentials {
|
||||
throw error;
|
||||
}
|
||||
|
||||
this.unloadNodes(installedPackage.installedNodes);
|
||||
|
||||
const finalNodeUnpackedPath = path.join(downloadFolder, 'node_modules', packageName);
|
||||
|
||||
const { loadedNodes, packageJson } = await this.runDirectoryLoader(
|
||||
PackageDirectoryLoader,
|
||||
finalNodeUnpackedPath,
|
||||
);
|
||||
const loader = await this.runDirectoryLoader(PackageDirectoryLoader, finalNodeUnpackedPath);
|
||||
|
||||
if (loadedNodes.length > 0) {
|
||||
if (loader.loadedNodes.length > 0) {
|
||||
// Save info to DB
|
||||
try {
|
||||
await removePackageFromDatabase(installedPackage);
|
||||
|
||||
const newlyInstalledPackage = await persistInstalledPackageData(
|
||||
packageJson.name,
|
||||
packageJson.version,
|
||||
loadedNodes,
|
||||
this.loaded.nodes,
|
||||
packageJson.author?.name,
|
||||
packageJson.author?.email,
|
||||
);
|
||||
|
||||
this.attachNodesToNodeTypes(newlyInstalledPackage.installedNodes);
|
||||
|
||||
const newlyInstalledPackage = await persistInstalledPackageData(loader);
|
||||
await this.postProcessLoaders();
|
||||
await this.generateTypesForFrontend();
|
||||
|
||||
return newlyInstalledPackage;
|
||||
} catch (error) {
|
||||
LoggerProxy.error('Failed to save installed packages and nodes', {
|
||||
@@ -363,20 +340,6 @@ export class LoadNodesAndCredentialsClass implements INodesAndCredentials {
|
||||
});
|
||||
}
|
||||
|
||||
private unloadNodes(installedNodes: InstalledNodes[]): void {
|
||||
installedNodes.forEach((installedNode) => {
|
||||
delete this.loaded.nodes[installedNode.type];
|
||||
});
|
||||
}
|
||||
|
||||
private attachNodesToNodeTypes(installedNodes: InstalledNodes[]): void {
|
||||
const loadedNodes = this.loaded.nodes;
|
||||
installedNodes.forEach((installedNode) => {
|
||||
const { type, sourcePath } = loadedNodes[installedNode.type];
|
||||
loadedNodes[installedNode.type] = { type, sourcePath };
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a loader of source files of nodes and credentials in a directory.
|
||||
*/
|
||||
@@ -386,16 +349,18 @@ export class LoadNodesAndCredentialsClass implements INodesAndCredentials {
|
||||
) {
|
||||
const loader = new constructor(dir, this.excludeNodes, this.includeNodes);
|
||||
await loader.loadAll();
|
||||
this.loaders[dir] = loader;
|
||||
this.loaders[loader.packageName] = loader;
|
||||
return loader;
|
||||
}
|
||||
|
||||
async postProcessLoaders() {
|
||||
this.types.nodes = [];
|
||||
this.types.credentials = [];
|
||||
for (const [dir, loader] of Object.entries(this.loaders)) {
|
||||
this.known = { nodes: {}, credentials: {} };
|
||||
this.loaded = { nodes: {}, credentials: {} };
|
||||
this.types = { nodes: [], credentials: [] };
|
||||
|
||||
for (const loader of Object.values(this.loaders)) {
|
||||
// list of node & credential types that will be sent to the frontend
|
||||
const { types } = loader;
|
||||
const { types, directory } = loader;
|
||||
this.types.nodes = this.types.nodes.concat(types.nodes);
|
||||
this.types.credentials = this.types.credentials.concat(types.credentials);
|
||||
|
||||
@@ -416,7 +381,7 @@ export class LoadNodesAndCredentialsClass implements INodesAndCredentials {
|
||||
const { className, sourcePath } = known.nodes[type];
|
||||
this.known.nodes[type] = {
|
||||
className,
|
||||
sourcePath: path.join(dir, sourcePath),
|
||||
sourcePath: path.join(directory, sourcePath),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -424,7 +389,7 @@ export class LoadNodesAndCredentialsClass implements INodesAndCredentials {
|
||||
const { className, sourcePath, nodesToTestWith } = known.credentials[type];
|
||||
this.known.credentials[type] = {
|
||||
className,
|
||||
sourcePath: path.join(dir, sourcePath),
|
||||
sourcePath: path.join(directory, sourcePath),
|
||||
nodesToTestWith: nodesToTestWith?.map((nodeName) => `${packageName}.${nodeName}`),
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user