UNPKG

n8n

Version:

n8n Workflow Automation Tool

163 lines • 8.61 kB
"use strict"; const api_types_1 = require("@n8n/api-types"); const di_1 = require("@n8n/di"); const n8n_workflow_1 = require("n8n-workflow"); const bad_request_error_1 = require("../../../../errors/response-errors/bad-request.error"); const forbidden_error_1 = require("../../../../errors/response-errors/forbidden.error"); const event_service_1 = require("../../../../events/event.service"); const package_export_errors_1 = require("../../../../modules/n8n-packages/entities/package-export.errors"); const n8n_packages_service_1 = require("../../../../modules/n8n-packages/n8n-packages.service"); const package_failure_classifier_1 = require("../../../../modules/n8n-packages/package-failure-classifier"); const import_package_upload_1 = require("../../../../modules/n8n-packages/utils/import-package-upload"); const global_middleware_1 = require("../../shared/middlewares/global.middleware"); const PACKAGE_EXPORT_SCOPES = 'project:export,workflow:export'; const EXPORT_COUNTS_HEADER = 'X-N8n-Export-Counts'; function assertPackageExportApiKeyScopes(req, workflowIds, folderIds, projectIds) { const apiKeyScopes = req.tokenGrant?.apiKeyScopes; if (!apiKeyScopes) { throw new forbidden_error_1.ForbiddenError('Forbidden'); } const requiredScopes = []; if (workflowIds.length > 0 || folderIds.length > 0) { requiredScopes.push('workflow:export'); } if (projectIds.length > 0) { requiredScopes.push('project:export'); } for (const scope of requiredScopes) { if (!apiKeyScopes.includes(scope)) { throw new forbidden_error_1.ForbiddenError('Forbidden'); } } return apiKeyScopes; } function assertPackageImportApiKeyScopes(req) { const apiKeyScopes = req.tokenGrant?.apiKeyScopes; if (!apiKeyScopes?.includes('workflow:import')) { throw new forbidden_error_1.ForbiddenError('Forbidden'); } } async function streamPackageExport(res, { stream, counts }) { res.setHeader('Content-Type', 'application/gzip'); res.setHeader('Content-Disposition', 'attachment; filename="export.n8np"'); res.setHeader(EXPORT_COUNTS_HEADER, JSON.stringify(counts)); res.setHeader('Access-Control-Expose-Headers', EXPORT_COUNTS_HEADER); return await new Promise((resolve, reject) => { stream.on('error', reject); res.on('finish', () => resolve(res)); res.on('close', () => { if (!res.writableFinished) stream.destroy(); resolve(res); }); stream.pipe(res); }); } const n8nPackagesHandlers = { exportPackage: [ (0, global_middleware_1.publicApiCompositeScope)(PACKAGE_EXPORT_SCOPES), async (req, res) => { let workflowIds = []; let folderIds = []; let projectIds = []; let includeVariableValues = true; try { const payload = api_types_1.ExportPackageRequestDto.safeParse(req.body); if (!payload.success) { throw new bad_request_error_1.BadRequestError(payload.error.errors.map(({ message }) => message).join('; ')); } workflowIds = payload.data.workflowIds ?? []; folderIds = payload.data.folderIds ?? []; projectIds = payload.data.projectIds ?? []; includeVariableValues = payload.data.includeVariableValues; if (projectIds.length > 0 && (workflowIds.length > 0 || folderIds.length > 0)) { throw new bad_request_error_1.BadRequestError('Provide either workflowIds/folderIds or projectIds, not both'); } if (workflowIds.length === 0 && folderIds.length === 0 && projectIds.length === 0) { throw new bad_request_error_1.BadRequestError('At least one workflowId, folderId, or projectId is required'); } const apiKeyScopes = assertPackageExportApiKeyScopes(req, workflowIds, folderIds, projectIds); const exportResult = await di_1.Container.get(n8n_packages_service_1.N8nPackagesService).exportPackage({ user: req.user, workflowIds, folderIds, projectIds, includeVariableValues, canExportVariableValues: apiKeyScopes.includes('variable:list'), includeTags: payload.data.includeTags, missingWorkflowDependencyPolicy: payload.data.missingWorkflowDependencyPolicy, }); return await streamPackageExport(res, exportResult); } catch (error) { di_1.Container.get(event_service_1.EventService).emit('n8n-package-export-failed', { user: req.user, reason: (0, package_failure_classifier_1.classifyPackageFailure)(error), ...(workflowIds.length ? { workflowIds } : {}), ...(folderIds.length ? { folderIds } : {}), ...(projectIds.length ? { projectIds } : {}), }); if (error instanceof package_export_errors_1.PackageEntityAccessDeniedError || error instanceof package_export_errors_1.PackageEntityNotFoundError) { throw new n8n_workflow_1.UserError(error.message, { description: error.description }); } throw error; } }, ], importPackage: [ (0, global_middleware_1.publicApiCompositeScope)('workflow:import'), async (req, res) => { let projectId; let folderId; try { const payload = api_types_1.ImportPackageRequestDto.safeParse(req.body ?? {}); if (!payload.success) { throw new bad_request_error_1.BadRequestError(payload.error.errors.map(({ message }) => message).join('; ')); } projectId = payload.data.projectId; folderId = payload.data.folderId; assertPackageImportApiKeyScopes(req); const packageFile = (0, import_package_upload_1.resolveImportPackageUpload)(req); const result = await di_1.Container.get(n8n_packages_service_1.N8nPackagesService).importPackage({ user: req.user, apiKeyScopes: req.tokenGrant?.apiKeyScopes, projectId, folderId, credentialMatchingMode: payload.data.credentialMatchingMode, credentialMissingMode: payload.data.credentialMissingMode, bindings: { credentials: new Map(Object.entries(payload.data.bindings.credentials ?? {})), }, workflowConflictPolicy: payload.data.workflowConflictPolicy, workflowPublishingPolicy: payload.data.workflowPublishingPolicy, workflowIdPolicy: payload.data.workflowIdPolicy, missingNodeTypeMode: payload.data.missingNodeTypeMode, projectConflictPolicy: payload.data.projectConflictPolicy, folderConflictPolicy: payload.data.folderConflictPolicy, dataTableMatchingMode: payload.data.dataTableMatchingMode, dataTableMissingMode: payload.data.dataTableMissingMode, dataTableSchemaConflictPolicy: payload.data.dataTableSchemaConflictPolicy, variableMissingMode: payload.data.variableMissingMode, variableConflictPolicy: payload.data.variableConflictPolicy, variableParentPolicy: payload.data.variableParentPolicy, tagMissingMode: payload.data.tagMissingMode, tagConflictPolicy: payload.data.tagConflictPolicy, packageBuffer: packageFile.buffer, }); return res.status(200).json(result); } catch (error) { di_1.Container.get(event_service_1.EventService).emit('n8n-package-import-failed', { user: req.user, reason: (0, package_failure_classifier_1.classifyPackageFailure)(error), ...(projectId ? { projectId } : {}), ...(folderId ? { folderId } : {}), }); throw error; } }, ], }; module.exports = n8nPackagesHandlers; //# sourceMappingURL=n8n-packages.handler.js.map