n8n
Version:
n8n Workflow Automation Tool
210 lines • 8.91 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.reconcileAiGatewayMarkers = reconcileAiGatewayMarkers;
exports.autoPopulateNodeCredentials = autoPopulateNodeCredentials;
exports.trackAutoassignOutcomes = trackAutoassignOutcomes;
exports.stripNullCredentialStubs = stripNullCredentialStubs;
const n8n_workflow_1 = require("n8n-workflow");
const ai_gateway_eligibility_1 = require("./ai-gateway-eligibility");
const mcp_constants_1 = require("../../mcp.constants");
const AI_GATEWAY_CREDENTIAL_NAME = 'n8n credits';
const HTTP_NODE_TYPES = new Set([
'n8n-nodes-base.httpRequest',
'@n8n/n8n-nodes-langchain.toolHttpRequest',
'n8n-nodes-base.httpRequestTool',
]);
function reconcileAiGatewayMarkers(nodes, nodeTypes, aiGatewayConfig) {
for (const node of nodes) {
if (!node.credentials)
continue;
const credentials = node.credentials;
const markerTypes = Object.keys(credentials).filter((credentialType) => credentials[credentialType]?.__aiGatewayManaged);
if (markerTypes.length === 0)
continue;
const nodeParameters = aiGatewayConfig ? resolveNodeParameters(node, nodeTypes) : undefined;
if (!aiGatewayConfig || !nodeParameters) {
for (const credentialType of markerTypes)
delete credentials[credentialType];
continue;
}
for (const credentialType of markerTypes) {
if ((0, ai_gateway_eligibility_1.checkAiGatewayEligibility)(node, credentialType, aiGatewayConfig, nodeParameters).eligible) {
credentials[credentialType] = {
id: null,
name: AI_GATEWAY_CREDENTIAL_NAME,
__aiGatewayManaged: true,
};
}
else {
delete credentials[credentialType];
}
}
}
}
function resolveNodeParameters(node, nodeTypes) {
let description;
try {
description = nodeTypes.getByNameAndVersion(node.type, node.typeVersion).description;
}
catch {
return undefined;
}
return (n8n_workflow_1.NodeHelpers.getNodeParameters(description.properties, node.parameters, true, false, node, description) ?? node.parameters);
}
async function autoPopulateNodeCredentials(workflow, user, nodeTypes, credentialsService, projectId, aiGatewayService) {
const usableCredentials = await credentialsService.getCredentialsAUserCanUseInAWorkflow(user, {
projectId,
});
const credentialsByType = new Map();
for (const cred of usableCredentials) {
const list = credentialsByType.get(cred.type) ?? [];
list.push({ id: cred.id, name: cred.name });
credentialsByType.set(cred.type, list);
}
const availability = aiGatewayService
? await aiGatewayService.isAvailable()
: { available: false };
const aiGatewayConfig = availability.available
? availability.config
: undefined;
reconcileAiGatewayMarkers(workflow.nodes, nodeTypes, aiGatewayConfig);
const assignments = [];
const skippedHttpNodes = [];
const outcomes = [];
for (const node of workflow.nodes) {
if (node.disabled)
continue;
if (HTTP_NODE_TYPES.has(node.type)) {
skippedHttpNodes.push(node.name);
continue;
}
let nodeTypeDescription;
try {
const nodeType = nodeTypes.getByNameAndVersion(node.type, node.typeVersion);
nodeTypeDescription = nodeType.description;
}
catch {
continue;
}
const credentialDescriptions = nodeTypeDescription.credentials;
if (!credentialDescriptions?.length)
continue;
const nodeParametersWithDefaults = n8n_workflow_1.NodeHelpers.getNodeParameters(nodeTypeDescription.properties, node.parameters, true, false, node, nodeTypeDescription) ?? node.parameters;
for (const credDesc of credentialDescriptions) {
const shouldDisplay = n8n_workflow_1.NodeHelpers.displayParameter(nodeParametersWithDefaults, credDesc, node, nodeTypeDescription);
if (!shouldDisplay)
continue;
const existing = node.credentials?.[credDesc.name];
if (existing?.id)
continue;
if (existing?.__aiGatewayManaged)
continue;
const userCandidates = credentialsByType.get(credDesc.name);
const hadUserCredential = !!userCandidates?.length;
if (hadUserCredential) {
node.credentials = node.credentials ?? {};
node.credentials[credDesc.name] = {
id: userCandidates[0].id,
name: userCandidates[0].name,
};
assignments.push({
nodeName: node.name,
credentialName: userCandidates[0].name,
credentialType: credDesc.name,
source: 'user',
});
outcomes.push({
nodeName: node.name,
credentialType: credDesc.name,
source: 'user',
hadUserCredential: true,
aiGatewayAvailable: !!aiGatewayConfig,
});
continue;
}
if (aiGatewayConfig) {
const eligibility = (0, ai_gateway_eligibility_1.checkAiGatewayEligibility)(node, credDesc.name, aiGatewayConfig, nodeParametersWithDefaults);
if (eligibility.eligible) {
node.credentials = node.credentials ?? {};
node.credentials[credDesc.name] = {
id: null,
name: AI_GATEWAY_CREDENTIAL_NAME,
__aiGatewayManaged: true,
};
assignments.push({
nodeName: node.name,
credentialName: AI_GATEWAY_CREDENTIAL_NAME,
credentialType: credDesc.name,
source: 'aiGateway',
});
outcomes.push({
nodeName: node.name,
credentialType: credDesc.name,
source: 'aiGateway',
hadUserCredential: false,
aiGatewayAvailable: true,
});
continue;
}
outcomes.push({
nodeName: node.name,
credentialType: credDesc.name,
source: 'none',
hadUserCredential: false,
aiGatewayAvailable: true,
reasonNotAiGateway: eligibility.reason,
});
continue;
}
outcomes.push({
nodeName: node.name,
credentialType: credDesc.name,
source: 'none',
hadUserCredential: false,
aiGatewayAvailable: false,
reasonNotAiGateway: 'notAvailable',
});
}
}
return { assignments, skippedHttpNodes, outcomes };
}
function trackAutoassignOutcomes(telemetry, userId, toolName, outcomes, nodesByName, workflowId) {
for (const outcome of outcomes) {
const nodeType = nodesByName?.get(outcome.nodeName) ?? outcome.nodeName;
const payload = {
user_id: userId,
tool_name: toolName,
node_type: nodeType,
credential_type: outcome.credentialType,
source: outcome.source,
had_user_credential: outcome.hadUserCredential,
ai_gateway_available: outcome.aiGatewayAvailable,
...(outcome.reasonNotAiGateway ? { reason_not_ai_gateway: outcome.reasonNotAiGateway } : {}),
};
telemetry.track(mcp_constants_1.MCP_CREDENTIALS_AUTOASSIGN_EVENT, payload);
if (outcome.source !== 'none') {
telemetry.track('Node credential assigned', {
credential_type: outcome.credentialType,
node_type: nodeType,
workflow_id: workflowId ?? '',
credential_kind: outcome.source === 'aiGateway' ? 'n8n_connect' : 'own',
source: 'mcp',
});
}
}
}
function stripNullCredentialStubs(nodes) {
for (const node of nodes) {
if (node.credentials) {
for (const key of Object.keys(node.credentials)) {
if (node.credentials[key] == null) {
delete node.credentials[key];
}
}
if (Object.keys(node.credentials).length === 0) {
node.credentials = undefined;
}
}
}
}
//# sourceMappingURL=credentials-auto-assign.js.map