n8n
Version:
n8n Workflow Automation Tool
167 lines • 8.53 kB
JavaScript
;
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.VariableExporter = void 0;
const db_1 = require("@n8n/db");
const di_1 = require("@n8n/di");
const n8n_workflow_1 = require("n8n-workflow");
const variables_service_ee_1 = require("../../../../environments.ee/variables/variables.service.ee");
const variable_serializer_1 = require("./variable.serializer");
const unique_filename_allocator_1 = require("../../io/unique-filename-allocator");
const package_export_errors_1 = require("../package-export.errors");
function isBundleableVariable(variable) {
return variable !== undefined;
}
let VariableExporter = class VariableExporter {
constructor(variablesService, sharedWorkflowRepository, variableSerializer) {
this.variablesService = variablesService;
this.sharedWorkflowRepository = sharedWorkflowRepository;
this.variableSerializer = variableSerializer;
}
async export(request) {
if (request.requirements.length === 0) {
return { entries: [], requirements: [] };
}
const workflowIds = [...new Set(request.requirements.map((r) => r.workflowId))];
const [allVariables, accessibleVariables, projectIdByWorkflowId] = await Promise.all([
this.variablesService.getAllCached(),
this.variablesService.getAllForUser(request.user),
this.resolveWorkflowProjects(workflowIds),
]);
const accessibleIds = new Set(accessibleVariables.map((variable) => variable.id));
const resolvedNames = this.resolveRequirements(request.requirements, projectIdByWorkflowId, allVariables, accessibleIds);
this.assertNoBundledVariableCollision(resolvedNames, request.projectTargetsById);
const allocators = new Map();
const allocatorFor = (baseDir) => {
const existing = allocators.get(baseDir);
if (existing)
return existing;
const created = new unique_filename_allocator_1.UniqueFilenameAllocator(baseDir, 'variable');
allocators.set(baseDir, created);
return created;
};
const entries = [];
const bundledVariableIds = new Set();
const requirements = [];
for (const { name, usedByWorkflows, variables } of resolvedNames) {
let aggregateValue;
let everyWorkflowResolvedToSameValue = true;
for (const variable of variables) {
if (!isBundleableVariable(variable)) {
everyWorkflowResolvedToSameValue = false;
continue;
}
if (aggregateValue === undefined) {
aggregateValue = variable.value;
}
else if (aggregateValue !== variable.value) {
everyWorkflowResolvedToSameValue = false;
}
if (bundledVariableIds.has(variable.id))
continue;
bundledVariableIds.add(variable.id);
const baseDir = this.resolveBaseDir(variable, request.projectTargetsById);
const target = allocatorFor(baseDir).allocate(variable.key);
request.writer.writeDirectory(target);
request.writer.writeFile(`${target}/variable.json`, JSON.stringify(this.variableSerializer.serialize(variable, {
includeValue: request.includeVariableValues,
}), null, '\t'));
entries.push({ id: variable.id, name: variable.key, target });
}
requirements.push({
name,
...(request.includeVariableValues &&
everyWorkflowResolvedToSameValue &&
aggregateValue !== undefined
? { value: aggregateValue }
: {}),
usedByWorkflows,
});
}
return { entries, requirements };
}
resolveRequirements(requirements, projectIdByWorkflowId, allVariables, accessibleIds) {
const variablesByKey = new Map();
for (const variable of allVariables) {
const bucket = variablesByKey.get(variable.key);
if (bucket)
bucket.push(variable);
else
variablesByKey.set(variable.key, [variable]);
}
const resolveForWorkflow = (name, workflowId) => {
const workflowProjectId = projectIdByWorkflowId.get(workflowId);
const picked = (0, n8n_workflow_1.pickVariableForProject)(variablesByKey.get(name) ?? [], name, workflowProjectId);
return picked && accessibleIds.has(picked.id) ? picked : undefined;
};
return [...this.groupByName(requirements)].map(([name, usedByWorkflows]) => ({
name,
usedByWorkflows,
variables: usedByWorkflows.map((workflowId) => resolveForWorkflow(name, workflowId)),
}));
}
resolveBaseDir(variable, projectTargetsById) {
if (!projectTargetsById || projectTargetsById.size === 0)
return 'variables';
const prefix = variable.project ? projectTargetsById.get(variable.project.id) : undefined;
return prefix ? `${prefix}/variables` : 'variables';
}
async resolveWorkflowProjects(workflowIds) {
const owners = await this.sharedWorkflowRepository.findByWorkflowIds(workflowIds);
return new Map(owners.map((owner) => [owner.workflowId, owner.project.id]));
}
assertNoBundledVariableCollision(resolvedNames, projectTargetsById) {
const conflictingNames = resolvedNames
.filter(({ variables }) => this.hasDirectoryCollision(variables, projectTargetsById))
.map(({ name }) => name);
if (conflictingNames.length === 0)
return;
const displayedNames = conflictingNames.slice(0, 20);
const omittedCount = conflictingNames.length - displayedNames.length;
throw new package_export_errors_1.PackageExportBlockedError(`${conflictingNames.length} variable name(s) resolve to different variables that would collide in the package. Export aborted.`, {
description: `Conflicting variable name(s): ${displayedNames.join(', ')}${omittedCount > 0 ? `, and ${omittedCount} more` : ''}. Export the projects as a project package instead.`,
});
}
hasDirectoryCollision(variables, projectTargetsById) {
const idByDir = new Map();
for (const variable of variables) {
if (!isBundleableVariable(variable))
continue;
const dir = this.resolveBaseDir(variable, projectTargetsById);
const previousId = idByDir.get(dir);
if (previousId !== undefined && previousId !== variable.id)
return true;
idByDir.set(dir, variable.id);
}
return false;
}
groupByName(requirements) {
const grouped = new Map();
for (const requirement of requirements) {
const workflowIds = grouped.get(requirement.variableName);
if (workflowIds) {
if (!workflowIds.includes(requirement.workflowId)) {
workflowIds.push(requirement.workflowId);
}
}
else {
grouped.set(requirement.variableName, [requirement.workflowId]);
}
}
return grouped;
}
};
exports.VariableExporter = VariableExporter;
exports.VariableExporter = VariableExporter = __decorate([
(0, di_1.Service)(),
__metadata("design:paramtypes", [variables_service_ee_1.VariablesService, db_1.SharedWorkflowRepository, variable_serializer_1.VariableSerializer])
], VariableExporter);
//# sourceMappingURL=variable.exporter.js.map