n8n
Version:
n8n Workflow Automation Tool
180 lines • 8.48 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.WorkflowImporter = void 0;
const db_1 = require("@n8n/db");
const di_1 = require("@n8n/di");
const workflow_creation_service_1 = require("../../../../workflows/workflow-creation.service");
const workflow_service_1 = require("../../../../workflows/workflow.service");
const workflow_conflict_policy_1 = require("./workflow-conflict-policy");
const workflow_id_policy_1 = require("./workflow-id-policy");
const workflow_import_match_service_1 = require("./workflow-import-match.service");
const workflow_publisher_1 = require("./workflow-publisher");
let WorkflowImporter = class WorkflowImporter {
constructor(workflowImportMatchService, workflowCreationService, workflowService, workflowPublisher) {
this.workflowImportMatchService = workflowImportMatchService;
this.workflowCreationService = workflowCreationService;
this.workflowService = workflowService;
this.workflowPublisher = workflowPublisher;
}
async plan(context, prepared, options) {
const existingBySourceWorkflowId = await this.workflowImportMatchService.findBySourceWorkflowIds(context.projectId, prepared.map(({ sourceWorkflowId }) => sourceWorkflowId));
const items = [];
const conflicts = [];
const folderConflicts = [];
const sourceCreateIds = [];
for (const workflow of prepared) {
const existing = existingBySourceWorkflowId.get(workflow.sourceWorkflowId) ?? null;
const { action, blocked } = (0, workflow_conflict_policy_1.decideWorkflowConflictAction)(options.workflowConflictPolicy, existing);
const item = toPlanItem(workflow, existing, action, options.workflowIdPolicy);
items.push(item);
if (item.action === 'create' && options.workflowIdPolicy === 'source' && !blocked) {
sourceCreateIds.push(item.decidedId);
}
if (blocked && existing) {
conflicts.push({
sourceWorkflowId: workflow.sourceWorkflowId,
existingWorkflowId: existing.id,
name: existing.name,
});
}
const targetFolderId = workflow.parentFolderId ?? context.folderId;
if (targetFolderId && existing) {
const existingParentFolderId = existing.parentFolder?.id ?? null;
if (existingParentFolderId !== targetFolderId) {
folderConflicts.push({
sourceWorkflowId: workflow.sourceWorkflowId,
existingWorkflowId: existing.id,
existingParentFolderId,
targetFolderId,
name: existing.name,
});
}
}
}
const idConflicts = await this.collectIdConflicts(sourceCreateIds);
return { items, conflicts, idConflicts, folderConflicts };
}
async collectIdConflicts(candidateIds) {
const existing = await this.workflowImportMatchService.findOwningProjectsByWorkflowId(candidateIds);
return candidateIds.flatMap((id) => {
const location = existing.get(id);
if (!location)
return [];
return [
{
sourceWorkflowId: id,
existingWorkflowId: id,
existingProjectId: location.projectId,
isArchived: location.isArchived,
name: location.name,
},
];
});
}
async apply(context, plan, bindings) {
const workflowBindings = new Map(bindings.workflows);
const outcomes = [];
for (const item of plan.items) {
const outcome = await this.applyItem(context, item, bindings);
outcomes.push(outcome);
workflowBindings.set(outcome.sourceWorkflowId, outcome.workflow.id);
}
return { outcomes, bindings: { ...bindings, workflows: workflowBindings } };
}
async applyItem(context, item, bindings) {
if (item.action === 'skip') {
return {
status: 'skipped',
workflow: item.existing,
sourceWorkflowId: item.sourceWorkflowId,
publishing: { state: 'unchanged' },
};
}
const savedWorkflow = await this.persistWorkflow(context, item, bindings);
const { workflow, publishing } = await this.workflowPublisher.apply(context.user, item, savedWorkflow, context.publishingPolicy, context.publishBlocked);
workflow.parentFolder =
workflow.parentFolder ??
savedWorkflow.parentFolder ??
(item.action === 'update' ? item.existing.parentFolder : null) ??
null;
return {
status: item.action === 'create' ? 'created' : 'updated',
workflow,
sourceWorkflowId: item.sourceWorkflowId,
publishing,
};
}
async persistWorkflow(context, item, bindings) {
if (item.action === 'create') {
const entity = prepareEntityForPersist(item.entity, bindings, item.decidedId);
return await this.workflowCreationService.createWorkflow(context.user, entity, {
projectId: context.projectId,
parentFolderId: item.parentFolderId ?? context.folderId ?? undefined,
publicApi: true,
source: 'import',
sourceWorkflowId: item.sourceWorkflowId,
});
}
const entity = prepareEntityForPersist(item.entity, bindings);
return await this.workflowService.update(context.user, entity, item.existing.id, {
publicApi: true,
source: 'import',
});
}
};
exports.WorkflowImporter = WorkflowImporter;
exports.WorkflowImporter = WorkflowImporter = __decorate([
(0, di_1.Service)(),
__metadata("design:paramtypes", [workflow_import_match_service_1.WorkflowImportMatchService, workflow_creation_service_1.WorkflowCreationService, workflow_service_1.WorkflowService, workflow_publisher_1.WorkflowPublisher])
], WorkflowImporter);
function prepareEntityForPersist(source, bindings, decidedId) {
const entity = Object.assign(new db_1.WorkflowEntity(), source, {
nodes: structuredClone(source.nodes),
...(decidedId !== undefined ? { id: decidedId } : {}),
});
applyCredentialBindingsInPlace(entity, bindings.credentials);
return entity;
}
function applyCredentialBindingsInPlace(entity, credentialBindings) {
for (const node of entity.nodes) {
for (const details of Object.values(node.credentials ?? {})) {
if (!details.id)
continue;
const targetId = credentialBindings.get(details.id);
if (targetId) {
details.id = targetId;
}
}
}
}
function toPlanItem(prepared, existing, action, idPolicy) {
if (existing === null) {
return {
action: 'create',
decidedId: (0, workflow_id_policy_1.decideWorkflowId)(idPolicy, prepared.sourceWorkflowId),
...prepared,
};
}
switch (action) {
case 'update':
return { action, ...prepared, existing };
case 'skip':
return { action, ...prepared, existing };
case 'create':
return {
action,
decidedId: (0, workflow_id_policy_1.decideWorkflowId)(idPolicy, prepared.sourceWorkflowId),
...prepared,
};
}
}
//# sourceMappingURL=workflow-importer.js.map