agentic-qe 2.5.5 → 2.5.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/agents/n8n/n8n-base-agent.md +376 -0
- package/.claude/agents/n8n/n8n-bdd-scenario-tester.md +613 -0
- package/.claude/agents/n8n/n8n-chaos-tester.md +654 -0
- package/.claude/agents/n8n/n8n-ci-orchestrator.md +850 -0
- package/.claude/agents/n8n/n8n-compliance-validator.md +685 -0
- package/.claude/agents/n8n/n8n-expression-validator.md +560 -0
- package/.claude/agents/n8n/n8n-integration-test.md +602 -0
- package/.claude/agents/n8n/n8n-monitoring-validator.md +589 -0
- package/.claude/agents/n8n/n8n-node-validator.md +455 -0
- package/.claude/agents/n8n/n8n-performance-tester.md +630 -0
- package/.claude/agents/n8n/n8n-security-auditor.md +786 -0
- package/.claude/agents/n8n/n8n-trigger-test.md +500 -0
- package/.claude/agents/n8n/n8n-unit-tester.md +633 -0
- package/.claude/agents/n8n/n8n-version-comparator.md +567 -0
- package/.claude/agents/n8n/n8n-workflow-executor.md +392 -0
- package/.claude/skills/n8n-expression-testing/SKILL.md +434 -0
- package/.claude/skills/n8n-integration-testing-patterns/SKILL.md +540 -0
- package/.claude/skills/n8n-security-testing/SKILL.md +599 -0
- package/.claude/skills/n8n-trigger-testing-strategies/SKILL.md +541 -0
- package/.claude/skills/n8n-workflow-testing-fundamentals/SKILL.md +447 -0
- package/CHANGELOG.md +111 -0
- package/README.md +7 -4
- package/dist/adapters/MemoryStoreAdapter.d.ts +75 -123
- package/dist/adapters/MemoryStoreAdapter.d.ts.map +1 -1
- package/dist/adapters/MemoryStoreAdapter.js +204 -219
- package/dist/adapters/MemoryStoreAdapter.js.map +1 -1
- package/dist/agents/AccessibilityAllyAgent.d.ts.map +1 -1
- package/dist/agents/AccessibilityAllyAgent.js +17 -1
- package/dist/agents/AccessibilityAllyAgent.js.map +1 -1
- package/dist/agents/BaseAgent.d.ts +18 -250
- package/dist/agents/BaseAgent.d.ts.map +1 -1
- package/dist/agents/BaseAgent.js +122 -520
- package/dist/agents/BaseAgent.js.map +1 -1
- package/dist/agents/n8n/N8nAPIClient.d.ts +121 -0
- package/dist/agents/n8n/N8nAPIClient.d.ts.map +1 -0
- package/dist/agents/n8n/N8nAPIClient.js +367 -0
- package/dist/agents/n8n/N8nAPIClient.js.map +1 -0
- package/dist/agents/n8n/N8nAuditPersistence.d.ts +120 -0
- package/dist/agents/n8n/N8nAuditPersistence.d.ts.map +1 -0
- package/dist/agents/n8n/N8nAuditPersistence.js +473 -0
- package/dist/agents/n8n/N8nAuditPersistence.js.map +1 -0
- package/dist/agents/n8n/N8nBDDScenarioTesterAgent.d.ts +159 -0
- package/dist/agents/n8n/N8nBDDScenarioTesterAgent.d.ts.map +1 -0
- package/dist/agents/n8n/N8nBDDScenarioTesterAgent.js +697 -0
- package/dist/agents/n8n/N8nBDDScenarioTesterAgent.js.map +1 -0
- package/dist/agents/n8n/N8nBaseAgent.d.ts +126 -0
- package/dist/agents/n8n/N8nBaseAgent.d.ts.map +1 -0
- package/dist/agents/n8n/N8nBaseAgent.js +446 -0
- package/dist/agents/n8n/N8nBaseAgent.js.map +1 -0
- package/dist/agents/n8n/N8nCIOrchestratorAgent.d.ts +164 -0
- package/dist/agents/n8n/N8nCIOrchestratorAgent.d.ts.map +1 -0
- package/dist/agents/n8n/N8nCIOrchestratorAgent.js +610 -0
- package/dist/agents/n8n/N8nCIOrchestratorAgent.js.map +1 -0
- package/dist/agents/n8n/N8nChaosTesterAgent.d.ts +205 -0
- package/dist/agents/n8n/N8nChaosTesterAgent.d.ts.map +1 -0
- package/dist/agents/n8n/N8nChaosTesterAgent.js +729 -0
- package/dist/agents/n8n/N8nChaosTesterAgent.js.map +1 -0
- package/dist/agents/n8n/N8nComplianceValidatorAgent.d.ts +228 -0
- package/dist/agents/n8n/N8nComplianceValidatorAgent.d.ts.map +1 -0
- package/dist/agents/n8n/N8nComplianceValidatorAgent.js +986 -0
- package/dist/agents/n8n/N8nComplianceValidatorAgent.js.map +1 -0
- package/dist/agents/n8n/N8nContractTesterAgent.d.ts +213 -0
- package/dist/agents/n8n/N8nContractTesterAgent.d.ts.map +1 -0
- package/dist/agents/n8n/N8nContractTesterAgent.js +989 -0
- package/dist/agents/n8n/N8nContractTesterAgent.js.map +1 -0
- package/dist/agents/n8n/N8nExpressionValidatorAgent.d.ts +99 -0
- package/dist/agents/n8n/N8nExpressionValidatorAgent.d.ts.map +1 -0
- package/dist/agents/n8n/N8nExpressionValidatorAgent.js +632 -0
- package/dist/agents/n8n/N8nExpressionValidatorAgent.js.map +1 -0
- package/dist/agents/n8n/N8nFailureModeTesterAgent.d.ts +238 -0
- package/dist/agents/n8n/N8nFailureModeTesterAgent.d.ts.map +1 -0
- package/dist/agents/n8n/N8nFailureModeTesterAgent.js +956 -0
- package/dist/agents/n8n/N8nFailureModeTesterAgent.js.map +1 -0
- package/dist/agents/n8n/N8nIdempotencyTesterAgent.d.ts +242 -0
- package/dist/agents/n8n/N8nIdempotencyTesterAgent.d.ts.map +1 -0
- package/dist/agents/n8n/N8nIdempotencyTesterAgent.js +992 -0
- package/dist/agents/n8n/N8nIdempotencyTesterAgent.js.map +1 -0
- package/dist/agents/n8n/N8nIntegrationTestAgent.d.ts +104 -0
- package/dist/agents/n8n/N8nIntegrationTestAgent.d.ts.map +1 -0
- package/dist/agents/n8n/N8nIntegrationTestAgent.js +653 -0
- package/dist/agents/n8n/N8nIntegrationTestAgent.js.map +1 -0
- package/dist/agents/n8n/N8nMonitoringValidatorAgent.d.ts +210 -0
- package/dist/agents/n8n/N8nMonitoringValidatorAgent.d.ts.map +1 -0
- package/dist/agents/n8n/N8nMonitoringValidatorAgent.js +669 -0
- package/dist/agents/n8n/N8nMonitoringValidatorAgent.js.map +1 -0
- package/dist/agents/n8n/N8nNodeValidatorAgent.d.ts +142 -0
- package/dist/agents/n8n/N8nNodeValidatorAgent.d.ts.map +1 -0
- package/dist/agents/n8n/N8nNodeValidatorAgent.js +1090 -0
- package/dist/agents/n8n/N8nNodeValidatorAgent.js.map +1 -0
- package/dist/agents/n8n/N8nPerformanceTesterAgent.d.ts +198 -0
- package/dist/agents/n8n/N8nPerformanceTesterAgent.d.ts.map +1 -0
- package/dist/agents/n8n/N8nPerformanceTesterAgent.js +653 -0
- package/dist/agents/n8n/N8nPerformanceTesterAgent.js.map +1 -0
- package/dist/agents/n8n/N8nReplayabilityTesterAgent.d.ts +245 -0
- package/dist/agents/n8n/N8nReplayabilityTesterAgent.d.ts.map +1 -0
- package/dist/agents/n8n/N8nReplayabilityTesterAgent.js +952 -0
- package/dist/agents/n8n/N8nReplayabilityTesterAgent.js.map +1 -0
- package/dist/agents/n8n/N8nSecretsHygieneAuditorAgent.d.ts +325 -0
- package/dist/agents/n8n/N8nSecretsHygieneAuditorAgent.d.ts.map +1 -0
- package/dist/agents/n8n/N8nSecretsHygieneAuditorAgent.js +1187 -0
- package/dist/agents/n8n/N8nSecretsHygieneAuditorAgent.js.map +1 -0
- package/dist/agents/n8n/N8nSecurityAuditorAgent.d.ts +91 -0
- package/dist/agents/n8n/N8nSecurityAuditorAgent.d.ts.map +1 -0
- package/dist/agents/n8n/N8nSecurityAuditorAgent.js +825 -0
- package/dist/agents/n8n/N8nSecurityAuditorAgent.js.map +1 -0
- package/dist/agents/n8n/N8nTestHarness.d.ts +131 -0
- package/dist/agents/n8n/N8nTestHarness.d.ts.map +1 -0
- package/dist/agents/n8n/N8nTestHarness.js +456 -0
- package/dist/agents/n8n/N8nTestHarness.js.map +1 -0
- package/dist/agents/n8n/N8nTriggerTestAgent.d.ts +119 -0
- package/dist/agents/n8n/N8nTriggerTestAgent.d.ts.map +1 -0
- package/dist/agents/n8n/N8nTriggerTestAgent.js +652 -0
- package/dist/agents/n8n/N8nTriggerTestAgent.js.map +1 -0
- package/dist/agents/n8n/N8nUnitTesterAgent.d.ts +130 -0
- package/dist/agents/n8n/N8nUnitTesterAgent.d.ts.map +1 -0
- package/dist/agents/n8n/N8nUnitTesterAgent.js +522 -0
- package/dist/agents/n8n/N8nUnitTesterAgent.js.map +1 -0
- package/dist/agents/n8n/N8nVersionComparatorAgent.d.ts +201 -0
- package/dist/agents/n8n/N8nVersionComparatorAgent.d.ts.map +1 -0
- package/dist/agents/n8n/N8nVersionComparatorAgent.js +645 -0
- package/dist/agents/n8n/N8nVersionComparatorAgent.js.map +1 -0
- package/dist/agents/n8n/N8nWorkflowExecutorAgent.d.ts +120 -0
- package/dist/agents/n8n/N8nWorkflowExecutorAgent.d.ts.map +1 -0
- package/dist/agents/n8n/N8nWorkflowExecutorAgent.js +347 -0
- package/dist/agents/n8n/N8nWorkflowExecutorAgent.js.map +1 -0
- package/dist/agents/n8n/index.d.ts +119 -0
- package/dist/agents/n8n/index.d.ts.map +1 -0
- package/dist/agents/n8n/index.js +298 -0
- package/dist/agents/n8n/index.js.map +1 -0
- package/dist/agents/n8n/types.d.ts +486 -0
- package/dist/agents/n8n/types.d.ts.map +1 -0
- package/dist/agents/n8n/types.js +8 -0
- package/dist/agents/n8n/types.js.map +1 -0
- package/dist/agents/utils/generators.d.ts +30 -0
- package/dist/agents/utils/generators.d.ts.map +1 -0
- package/dist/agents/utils/generators.js +44 -0
- package/dist/agents/utils/generators.js.map +1 -0
- package/dist/agents/utils/index.d.ts +10 -0
- package/dist/agents/utils/index.d.ts.map +1 -0
- package/dist/agents/utils/index.js +19 -0
- package/dist/agents/utils/index.js.map +1 -0
- package/dist/agents/utils/validation.d.ts +72 -0
- package/dist/agents/utils/validation.d.ts.map +1 -0
- package/dist/agents/utils/validation.js +75 -0
- package/dist/agents/utils/validation.js.map +1 -0
- package/dist/cli/init/agents.d.ts.map +1 -1
- package/dist/cli/init/agents.js +29 -0
- package/dist/cli/init/agents.js.map +1 -1
- package/dist/cli/init/skills.d.ts.map +1 -1
- package/dist/cli/init/skills.js +7 -1
- package/dist/cli/init/skills.js.map +1 -1
- package/dist/core/memory/HNSWVectorMemory.js +1 -1
- package/dist/core/memory/SwarmMemoryManager.d.ts +114 -90
- package/dist/core/memory/SwarmMemoryManager.d.ts.map +1 -1
- package/dist/core/memory/SwarmMemoryManager.js +277 -235
- package/dist/core/memory/SwarmMemoryManager.js.map +1 -1
- package/dist/learning/baselines/StandardTaskSuite.d.ts.map +1 -1
- package/dist/learning/baselines/StandardTaskSuite.js +38 -0
- package/dist/learning/baselines/StandardTaskSuite.js.map +1 -1
- package/dist/mcp/server-instructions.d.ts +1 -1
- package/dist/mcp/server-instructions.js +1 -1
- package/dist/types/memory-interfaces.d.ts +76 -68
- package/dist/types/memory-interfaces.d.ts.map +1 -1
- package/dist/types/memory-interfaces.js +3 -0
- package/dist/types/memory-interfaces.js.map +1 -1
- package/docs/reference/agents.md +91 -2
- package/docs/reference/skills.md +97 -2
- package/package.json +2 -2
|
@@ -0,0 +1,669 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* N8nMonitoringValidatorAgent
|
|
4
|
+
*
|
|
5
|
+
* Validates monitoring and observability configuration:
|
|
6
|
+
* - Logging configuration validation
|
|
7
|
+
* - Alerting rule verification
|
|
8
|
+
* - Metrics collection validation
|
|
9
|
+
* - SLA compliance checking
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.N8nMonitoringValidatorAgent = void 0;
|
|
13
|
+
const N8nBaseAgent_1 = require("./N8nBaseAgent");
|
|
14
|
+
// Standard metrics that should be collected
|
|
15
|
+
const REQUIRED_METRICS = [
|
|
16
|
+
{ name: 'n8n_workflow_executions_total', type: 'counter', description: 'Total workflow executions' },
|
|
17
|
+
{ name: 'n8n_workflow_execution_duration_seconds', type: 'histogram', description: 'Workflow execution duration' },
|
|
18
|
+
{ name: 'n8n_workflow_execution_errors_total', type: 'counter', description: 'Total workflow errors' },
|
|
19
|
+
{ name: 'n8n_node_execution_duration_seconds', type: 'histogram', description: 'Node execution duration' },
|
|
20
|
+
{ name: 'n8n_workflow_active_executions', type: 'gauge', description: 'Currently active executions' },
|
|
21
|
+
];
|
|
22
|
+
class N8nMonitoringValidatorAgent extends N8nBaseAgent_1.N8nBaseAgent {
|
|
23
|
+
constructor(config) {
|
|
24
|
+
const capabilities = [
|
|
25
|
+
{
|
|
26
|
+
name: 'logging-validation',
|
|
27
|
+
version: '1.0.0',
|
|
28
|
+
description: 'Validate logging configuration',
|
|
29
|
+
parameters: {},
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
name: 'alerting-validation',
|
|
33
|
+
version: '1.0.0',
|
|
34
|
+
description: 'Validate alerting rules',
|
|
35
|
+
parameters: {},
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: 'metrics-validation',
|
|
39
|
+
version: '1.0.0',
|
|
40
|
+
description: 'Validate metrics collection',
|
|
41
|
+
parameters: {},
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: 'sla-compliance',
|
|
45
|
+
version: '1.0.0',
|
|
46
|
+
description: 'Check SLA compliance',
|
|
47
|
+
parameters: {},
|
|
48
|
+
},
|
|
49
|
+
];
|
|
50
|
+
super({
|
|
51
|
+
...config,
|
|
52
|
+
type: 'n8n-monitoring-validator',
|
|
53
|
+
capabilities: [...capabilities, ...(config.capabilities || [])],
|
|
54
|
+
});
|
|
55
|
+
this.monitoringExecutionHistory = new Map();
|
|
56
|
+
}
|
|
57
|
+
async performTask(task) {
|
|
58
|
+
const monitoringTask = task;
|
|
59
|
+
if (monitoringTask.type !== 'monitoring-validation') {
|
|
60
|
+
throw new Error(`Unsupported task type: ${monitoringTask.type}`);
|
|
61
|
+
}
|
|
62
|
+
return this.validateMonitoring(monitoringTask.target, monitoringTask.options);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Validate monitoring configuration
|
|
66
|
+
*
|
|
67
|
+
* PRODUCTION DEFAULT: Runtime validation and SLA checking are ENABLED by default.
|
|
68
|
+
* This ensures actual metrics are collected and validated, not just configuration.
|
|
69
|
+
* Set executeRuntimeValidation: false to skip if workflow cannot be executed.
|
|
70
|
+
*/
|
|
71
|
+
async validateMonitoring(workflowId, options) {
|
|
72
|
+
const workflow = await this.getWorkflow(workflowId);
|
|
73
|
+
// Validate logging (static analysis)
|
|
74
|
+
const loggingValidation = options?.validateLogging !== false
|
|
75
|
+
? this.validateLogging(workflow)
|
|
76
|
+
: this.getDefaultLoggingResult();
|
|
77
|
+
// Validate alerting (static analysis)
|
|
78
|
+
const alertingValidation = options?.validateAlerting !== false
|
|
79
|
+
? this.validateAlerting(workflow)
|
|
80
|
+
: this.getDefaultAlertingResult();
|
|
81
|
+
// Validate metrics (static analysis)
|
|
82
|
+
const metricsValidation = options?.validateMetrics !== false
|
|
83
|
+
? this.validateMetrics(workflow)
|
|
84
|
+
: this.getDefaultMetricsResult();
|
|
85
|
+
// Runtime validation - ENABLED BY DEFAULT
|
|
86
|
+
// Actually execute workflows to collect real metrics
|
|
87
|
+
// Set executeRuntimeValidation: false explicitly to skip
|
|
88
|
+
if (options?.executeRuntimeValidation !== false) {
|
|
89
|
+
try {
|
|
90
|
+
await this.executeRuntimeMetricsValidation(workflowId, options?.testInput, options?.iterations || 5);
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
// If runtime execution fails, emit warning but continue with static results
|
|
94
|
+
this.emitEvent('monitoring.runtime.skipped', {
|
|
95
|
+
workflowId,
|
|
96
|
+
reason: error instanceof Error ? error.message : 'Runtime metrics validation failed',
|
|
97
|
+
note: 'Static monitoring analysis completed, but runtime metrics collection was skipped',
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// Check SLA compliance - ENABLED BY DEFAULT for production
|
|
102
|
+
// Real execution data is used if runtime validation was run
|
|
103
|
+
// Set checkSLACompliance: false explicitly to skip
|
|
104
|
+
let slaCompliance;
|
|
105
|
+
if (options?.checkSLACompliance !== false) {
|
|
106
|
+
slaCompliance = await this.checkSLACompliance(workflowId, options?.slaThresholds || this.getDefaultSLAThresholds());
|
|
107
|
+
}
|
|
108
|
+
// Generate recommendations
|
|
109
|
+
const recommendations = this.generateRecommendations(loggingValidation, alertingValidation, metricsValidation, slaCompliance);
|
|
110
|
+
// Calculate overall score
|
|
111
|
+
const overallScore = this.calculateOverallScore(loggingValidation, alertingValidation, metricsValidation, slaCompliance);
|
|
112
|
+
const result = {
|
|
113
|
+
workflowId,
|
|
114
|
+
loggingValidation,
|
|
115
|
+
alertingValidation,
|
|
116
|
+
metricsValidation,
|
|
117
|
+
slaCompliance,
|
|
118
|
+
recommendations,
|
|
119
|
+
overallScore,
|
|
120
|
+
};
|
|
121
|
+
// Store result
|
|
122
|
+
await this.storeTestResult(`monitoring-validation:${workflowId}`, result);
|
|
123
|
+
// Emit event
|
|
124
|
+
this.emitEvent('monitoring.validation.completed', {
|
|
125
|
+
workflowId,
|
|
126
|
+
overallScore,
|
|
127
|
+
recommendationCount: recommendations.length,
|
|
128
|
+
slaCompliant: slaCompliance?.isCompliant ?? true,
|
|
129
|
+
});
|
|
130
|
+
return result;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Validate logging configuration
|
|
134
|
+
*/
|
|
135
|
+
validateLogging(workflow) {
|
|
136
|
+
const issues = [];
|
|
137
|
+
let nodesWithLogging = 0;
|
|
138
|
+
// Check workflow-level settings
|
|
139
|
+
const loggingLevel = workflow.settings?.saveExecutionProgress ? 'detailed' :
|
|
140
|
+
workflow.settings?.saveDataErrorExecution ? 'errors' : 'minimal';
|
|
141
|
+
// Check node-level logging
|
|
142
|
+
for (const node of workflow.nodes) {
|
|
143
|
+
const hasLogging = this.nodeHasLogging(node);
|
|
144
|
+
if (hasLogging) {
|
|
145
|
+
nodesWithLogging++;
|
|
146
|
+
}
|
|
147
|
+
// Check for sensitive data logging
|
|
148
|
+
if (this.nodeLogsSensitiveData(node)) {
|
|
149
|
+
issues.push({
|
|
150
|
+
type: 'sensitive-data',
|
|
151
|
+
severity: 'high',
|
|
152
|
+
location: node.name,
|
|
153
|
+
description: 'Node may log sensitive data',
|
|
154
|
+
recommendation: 'Add data masking or reduce log verbosity',
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
// Check for missing error logging
|
|
159
|
+
const errorNodes = workflow.nodes.filter(n => n.type.includes('Error') || n.type.includes('error'));
|
|
160
|
+
if (errorNodes.length === 0) {
|
|
161
|
+
issues.push({
|
|
162
|
+
type: 'missing',
|
|
163
|
+
severity: 'medium',
|
|
164
|
+
location: 'workflow',
|
|
165
|
+
description: 'No explicit error handling/logging nodes',
|
|
166
|
+
recommendation: 'Add error trigger node to capture and log errors',
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
// Check for insufficient logging
|
|
170
|
+
if (loggingLevel === 'minimal' && workflow.nodes.length > 5) {
|
|
171
|
+
issues.push({
|
|
172
|
+
type: 'insufficient',
|
|
173
|
+
severity: 'medium',
|
|
174
|
+
location: 'workflow',
|
|
175
|
+
description: 'Complex workflow with minimal logging',
|
|
176
|
+
recommendation: 'Enable saveExecutionProgress for debugging',
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
return {
|
|
180
|
+
isConfigured: loggingLevel !== 'minimal',
|
|
181
|
+
level: loggingLevel,
|
|
182
|
+
issues,
|
|
183
|
+
coverage: {
|
|
184
|
+
nodesWithLogging,
|
|
185
|
+
totalNodes: workflow.nodes.length,
|
|
186
|
+
percentage: workflow.nodes.length > 0
|
|
187
|
+
? (nodesWithLogging / workflow.nodes.length) * 100
|
|
188
|
+
: 0,
|
|
189
|
+
},
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Check if node has logging configured
|
|
194
|
+
*/
|
|
195
|
+
nodeHasLogging(node) {
|
|
196
|
+
// Check for explicit logging configuration
|
|
197
|
+
const params = node.parameters;
|
|
198
|
+
return !!(params.onError ||
|
|
199
|
+
params.logging ||
|
|
200
|
+
params.debug ||
|
|
201
|
+
node.type.includes('log') ||
|
|
202
|
+
node.type.includes('debug'));
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Check if node might log sensitive data
|
|
206
|
+
*/
|
|
207
|
+
nodeLogsSensitiveData(node) {
|
|
208
|
+
const sensitivePatterns = ['password', 'token', 'secret', 'key', 'credential'];
|
|
209
|
+
const paramsStr = JSON.stringify(node.parameters).toLowerCase();
|
|
210
|
+
return sensitivePatterns.some(p => paramsStr.includes(p));
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Validate alerting configuration
|
|
214
|
+
*/
|
|
215
|
+
validateAlerting(workflow) {
|
|
216
|
+
const rules = [];
|
|
217
|
+
const issues = [];
|
|
218
|
+
// Check for error workflow
|
|
219
|
+
const errorWorkflow = workflow.settings?.errorWorkflow;
|
|
220
|
+
if (errorWorkflow) {
|
|
221
|
+
rules.push({
|
|
222
|
+
name: 'Error Workflow Trigger',
|
|
223
|
+
type: 'error',
|
|
224
|
+
condition: 'Workflow execution fails',
|
|
225
|
+
channels: ['error-workflow'],
|
|
226
|
+
severity: 'error',
|
|
227
|
+
isValid: true,
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
issues.push({
|
|
232
|
+
type: 'missing',
|
|
233
|
+
severity: 'high',
|
|
234
|
+
description: 'No error workflow configured',
|
|
235
|
+
recommendation: 'Configure an error workflow to handle failures',
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
// Check for notification nodes
|
|
239
|
+
const notificationNodes = workflow.nodes.filter(n => n.type.includes('slack') ||
|
|
240
|
+
n.type.includes('email') ||
|
|
241
|
+
n.type.includes('telegram') ||
|
|
242
|
+
n.type.includes('webhook'));
|
|
243
|
+
for (const node of notificationNodes) {
|
|
244
|
+
// Check if it's in error handling path
|
|
245
|
+
const isErrorHandler = this.isInErrorHandlingPath(workflow, node);
|
|
246
|
+
if (isErrorHandler) {
|
|
247
|
+
rules.push({
|
|
248
|
+
name: `Alert: ${node.name}`,
|
|
249
|
+
type: 'error',
|
|
250
|
+
condition: 'Error detected',
|
|
251
|
+
channels: [node.type],
|
|
252
|
+
severity: 'warning',
|
|
253
|
+
isValid: true,
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
// Check coverage
|
|
258
|
+
const hasErrorAlerts = rules.some(r => r.type === 'error');
|
|
259
|
+
const hasPerformanceAlerts = rules.some(r => r.type === 'performance');
|
|
260
|
+
const hasBusinessAlerts = rules.some(r => r.type === 'business');
|
|
261
|
+
if (!hasPerformanceAlerts) {
|
|
262
|
+
issues.push({
|
|
263
|
+
type: 'blind-spot',
|
|
264
|
+
severity: 'medium',
|
|
265
|
+
description: 'No performance alerting configured',
|
|
266
|
+
recommendation: 'Add alerts for slow execution or timeout',
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
return {
|
|
270
|
+
isConfigured: rules.length > 0,
|
|
271
|
+
rules,
|
|
272
|
+
issues,
|
|
273
|
+
coverage: {
|
|
274
|
+
errorAlerts: hasErrorAlerts,
|
|
275
|
+
performanceAlerts: hasPerformanceAlerts,
|
|
276
|
+
businessAlerts: hasBusinessAlerts,
|
|
277
|
+
},
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Check if node is in error handling path
|
|
282
|
+
*/
|
|
283
|
+
isInErrorHandlingPath(workflow, node) {
|
|
284
|
+
// Simplified check - look for connection from error nodes
|
|
285
|
+
for (const [sourceNode, outputs] of Object.entries(workflow.connections)) {
|
|
286
|
+
const sourceNodeDef = workflow.nodes.find(n => n.id === sourceNode || n.name === sourceNode);
|
|
287
|
+
if (sourceNodeDef?.type.includes('Error')) {
|
|
288
|
+
for (const outputType of Object.values(outputs)) {
|
|
289
|
+
for (const connections of outputType) {
|
|
290
|
+
if (connections.some(c => c.node === node.id || c.node === node.name)) {
|
|
291
|
+
return true;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
return false;
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Validate metrics configuration
|
|
301
|
+
*/
|
|
302
|
+
validateMetrics(workflow) {
|
|
303
|
+
const metrics = [];
|
|
304
|
+
const issues = [];
|
|
305
|
+
// Check for standard metrics (these would be collected by n8n)
|
|
306
|
+
for (const requiredMetric of REQUIRED_METRICS) {
|
|
307
|
+
metrics.push({
|
|
308
|
+
...requiredMetric,
|
|
309
|
+
type: requiredMetric.type,
|
|
310
|
+
labels: ['workflow_id', 'workflow_name'],
|
|
311
|
+
isCollected: true, // Assume n8n collects these
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
// Check for custom metrics in code nodes
|
|
315
|
+
const codeNodes = workflow.nodes.filter(n => n.type === 'n8n-nodes-base.code');
|
|
316
|
+
for (const node of codeNodes) {
|
|
317
|
+
const code = node.parameters.jsCode || '';
|
|
318
|
+
if (code.includes('metrics') || code.includes('counter') || code.includes('gauge')) {
|
|
319
|
+
metrics.push({
|
|
320
|
+
name: `custom_${node.name}_metric`,
|
|
321
|
+
type: 'custom',
|
|
322
|
+
description: 'Custom metric in code node',
|
|
323
|
+
labels: [],
|
|
324
|
+
isCollected: true,
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
// Check for high cardinality
|
|
329
|
+
const httpNodes = workflow.nodes.filter(n => n.type.includes('httpRequest'));
|
|
330
|
+
if (httpNodes.length > 0) {
|
|
331
|
+
issues.push({
|
|
332
|
+
type: 'cardinality',
|
|
333
|
+
severity: 'medium',
|
|
334
|
+
description: 'HTTP request nodes may generate high cardinality metrics',
|
|
335
|
+
recommendation: 'Use bucketed labels for URL paths',
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
// Check coverage
|
|
339
|
+
const hasExecutionMetrics = metrics.some(m => m.name.includes('execution'));
|
|
340
|
+
const hasNodeMetrics = metrics.some(m => m.name.includes('node'));
|
|
341
|
+
const hasBusinessMetrics = metrics.some(m => !m.name.startsWith('n8n_'));
|
|
342
|
+
if (!hasBusinessMetrics) {
|
|
343
|
+
issues.push({
|
|
344
|
+
type: 'coverage',
|
|
345
|
+
severity: 'low',
|
|
346
|
+
description: 'No business-specific metrics defined',
|
|
347
|
+
recommendation: 'Consider adding custom metrics for business KPIs',
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
return {
|
|
351
|
+
isConfigured: metrics.length > 0,
|
|
352
|
+
metrics,
|
|
353
|
+
issues,
|
|
354
|
+
coverage: {
|
|
355
|
+
executionMetrics: hasExecutionMetrics,
|
|
356
|
+
nodeMetrics: hasNodeMetrics,
|
|
357
|
+
businessMetrics: hasBusinessMetrics,
|
|
358
|
+
},
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Check SLA compliance
|
|
363
|
+
*/
|
|
364
|
+
async checkSLACompliance(workflowId, thresholds) {
|
|
365
|
+
// Get recent executions
|
|
366
|
+
const executions = this.monitoringExecutionHistory.get(workflowId) || [];
|
|
367
|
+
// Calculate actual metrics
|
|
368
|
+
const durations = executions
|
|
369
|
+
.filter(e => e.stoppedAt)
|
|
370
|
+
.map(e => new Date(e.stoppedAt).getTime() - new Date(e.startedAt).getTime());
|
|
371
|
+
const successCount = executions.filter(e => e.status === 'success').length;
|
|
372
|
+
const errorCount = executions.filter(e => e.status === 'failed' || e.status === 'crashed').length;
|
|
373
|
+
const totalCount = executions.length || 1;
|
|
374
|
+
const avgExecutionTime = durations.length > 0
|
|
375
|
+
? durations.reduce((a, b) => a + b, 0) / durations.length
|
|
376
|
+
: 0;
|
|
377
|
+
const sortedDurations = [...durations].sort((a, b) => a - b);
|
|
378
|
+
const p99Index = Math.floor(sortedDurations.length * 0.99);
|
|
379
|
+
const p99Latency = sortedDurations[p99Index] || avgExecutionTime;
|
|
380
|
+
const actualMetrics = {
|
|
381
|
+
avgExecutionTime,
|
|
382
|
+
successRate: (successCount / totalCount) * 100,
|
|
383
|
+
errorRate: (errorCount / totalCount) * 100,
|
|
384
|
+
p99Latency,
|
|
385
|
+
throughput: totalCount, // executions in sample period
|
|
386
|
+
};
|
|
387
|
+
// Check violations
|
|
388
|
+
const violations = [];
|
|
389
|
+
if (thresholds.maxExecutionTime && avgExecutionTime > thresholds.maxExecutionTime) {
|
|
390
|
+
violations.push({
|
|
391
|
+
metric: 'avgExecutionTime',
|
|
392
|
+
threshold: thresholds.maxExecutionTime,
|
|
393
|
+
actual: avgExecutionTime,
|
|
394
|
+
severity: avgExecutionTime > thresholds.maxExecutionTime * 2 ? 'critical' : 'major',
|
|
395
|
+
timestamp: new Date(),
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
if (thresholds.minSuccessRate && actualMetrics.successRate < thresholds.minSuccessRate) {
|
|
399
|
+
violations.push({
|
|
400
|
+
metric: 'successRate',
|
|
401
|
+
threshold: thresholds.minSuccessRate,
|
|
402
|
+
actual: actualMetrics.successRate,
|
|
403
|
+
severity: actualMetrics.successRate < thresholds.minSuccessRate - 10 ? 'critical' : 'major',
|
|
404
|
+
timestamp: new Date(),
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
if (thresholds.maxErrorRate && actualMetrics.errorRate > thresholds.maxErrorRate) {
|
|
408
|
+
violations.push({
|
|
409
|
+
metric: 'errorRate',
|
|
410
|
+
threshold: thresholds.maxErrorRate,
|
|
411
|
+
actual: actualMetrics.errorRate,
|
|
412
|
+
severity: actualMetrics.errorRate > thresholds.maxErrorRate * 2 ? 'critical' : 'major',
|
|
413
|
+
timestamp: new Date(),
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
if (thresholds.maxP99Latency && p99Latency > thresholds.maxP99Latency) {
|
|
417
|
+
violations.push({
|
|
418
|
+
metric: 'p99Latency',
|
|
419
|
+
threshold: thresholds.maxP99Latency,
|
|
420
|
+
actual: p99Latency,
|
|
421
|
+
severity: 'major',
|
|
422
|
+
timestamp: new Date(),
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
return {
|
|
426
|
+
isCompliant: violations.length === 0,
|
|
427
|
+
thresholds,
|
|
428
|
+
actualMetrics,
|
|
429
|
+
violations,
|
|
430
|
+
trend: 'stable', // Would need historical data for real trend
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Get default SLA thresholds
|
|
435
|
+
*/
|
|
436
|
+
getDefaultSLAThresholds() {
|
|
437
|
+
return {
|
|
438
|
+
maxExecutionTime: 30000, // 30 seconds
|
|
439
|
+
minSuccessRate: 99, // 99%
|
|
440
|
+
maxErrorRate: 1, // 1%
|
|
441
|
+
maxP99Latency: 60000, // 60 seconds
|
|
442
|
+
minThroughput: 10, // 10 per hour
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Generate recommendations
|
|
447
|
+
*/
|
|
448
|
+
generateRecommendations(logging, alerting, metrics, sla) {
|
|
449
|
+
const recommendations = [];
|
|
450
|
+
// Logging recommendations
|
|
451
|
+
for (const issue of logging.issues) {
|
|
452
|
+
recommendations.push({
|
|
453
|
+
priority: issue.severity === 'high' ? 'high' : 'medium',
|
|
454
|
+
category: 'logging',
|
|
455
|
+
issue: issue.description,
|
|
456
|
+
recommendation: issue.recommendation,
|
|
457
|
+
impact: 'Improved debugging and troubleshooting',
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
// Alerting recommendations
|
|
461
|
+
for (const issue of alerting.issues) {
|
|
462
|
+
recommendations.push({
|
|
463
|
+
priority: issue.severity === 'high' ? 'high' : 'medium',
|
|
464
|
+
category: 'alerting',
|
|
465
|
+
issue: issue.description,
|
|
466
|
+
recommendation: issue.recommendation,
|
|
467
|
+
impact: 'Faster incident detection and response',
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
// Metrics recommendations
|
|
471
|
+
for (const issue of metrics.issues) {
|
|
472
|
+
recommendations.push({
|
|
473
|
+
priority: issue.severity === 'high' ? 'high' : 'low',
|
|
474
|
+
category: 'metrics',
|
|
475
|
+
issue: issue.description,
|
|
476
|
+
recommendation: issue.recommendation,
|
|
477
|
+
impact: 'Better observability and performance insights',
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
// SLA recommendations
|
|
481
|
+
if (sla && !sla.isCompliant) {
|
|
482
|
+
for (const violation of sla.violations) {
|
|
483
|
+
recommendations.push({
|
|
484
|
+
priority: violation.severity === 'critical' ? 'critical' : 'high',
|
|
485
|
+
category: 'sla',
|
|
486
|
+
issue: `SLA violation: ${violation.metric} is ${violation.actual.toFixed(2)}, threshold is ${violation.threshold}`,
|
|
487
|
+
recommendation: `Investigate and optimize ${violation.metric} to meet SLA`,
|
|
488
|
+
impact: 'Meeting business SLAs and customer expectations',
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
// Sort by priority
|
|
493
|
+
const priorityOrder = {
|
|
494
|
+
critical: 0,
|
|
495
|
+
high: 1,
|
|
496
|
+
medium: 2,
|
|
497
|
+
low: 3,
|
|
498
|
+
};
|
|
499
|
+
recommendations.sort((a, b) => priorityOrder[a.priority] - priorityOrder[b.priority]);
|
|
500
|
+
return recommendations;
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Calculate overall score
|
|
504
|
+
*/
|
|
505
|
+
calculateOverallScore(logging, alerting, metrics, sla) {
|
|
506
|
+
let score = 100;
|
|
507
|
+
// Logging deductions
|
|
508
|
+
if (!logging.isConfigured)
|
|
509
|
+
score -= 15;
|
|
510
|
+
score -= logging.issues.filter(i => i.severity === 'high').length * 10;
|
|
511
|
+
score -= logging.issues.filter(i => i.severity === 'medium').length * 5;
|
|
512
|
+
// Alerting deductions
|
|
513
|
+
if (!alerting.isConfigured)
|
|
514
|
+
score -= 20;
|
|
515
|
+
if (!alerting.coverage.errorAlerts)
|
|
516
|
+
score -= 10;
|
|
517
|
+
if (!alerting.coverage.performanceAlerts)
|
|
518
|
+
score -= 5;
|
|
519
|
+
score -= alerting.issues.filter(i => i.severity === 'high').length * 10;
|
|
520
|
+
// Metrics deductions
|
|
521
|
+
if (!metrics.isConfigured)
|
|
522
|
+
score -= 10;
|
|
523
|
+
if (!metrics.coverage.executionMetrics)
|
|
524
|
+
score -= 5;
|
|
525
|
+
score -= metrics.issues.filter(i => i.severity === 'high').length * 5;
|
|
526
|
+
// SLA deductions
|
|
527
|
+
if (sla && !sla.isCompliant) {
|
|
528
|
+
score -= sla.violations.filter(v => v.severity === 'critical').length * 15;
|
|
529
|
+
score -= sla.violations.filter(v => v.severity === 'major').length * 10;
|
|
530
|
+
}
|
|
531
|
+
return Math.max(0, Math.min(100, score));
|
|
532
|
+
}
|
|
533
|
+
/**
|
|
534
|
+
* Get default results
|
|
535
|
+
*/
|
|
536
|
+
getDefaultLoggingResult() {
|
|
537
|
+
return {
|
|
538
|
+
isConfigured: false,
|
|
539
|
+
level: 'unknown',
|
|
540
|
+
issues: [],
|
|
541
|
+
coverage: { nodesWithLogging: 0, totalNodes: 0, percentage: 0 },
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
getDefaultAlertingResult() {
|
|
545
|
+
return {
|
|
546
|
+
isConfigured: false,
|
|
547
|
+
rules: [],
|
|
548
|
+
issues: [],
|
|
549
|
+
coverage: { errorAlerts: false, performanceAlerts: false, businessAlerts: false },
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
getDefaultMetricsResult() {
|
|
553
|
+
return {
|
|
554
|
+
isConfigured: false,
|
|
555
|
+
metrics: [],
|
|
556
|
+
issues: [],
|
|
557
|
+
coverage: { executionMetrics: false, nodeMetrics: false, businessMetrics: false },
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* Record execution for SLA tracking
|
|
562
|
+
*/
|
|
563
|
+
recordExecution(workflowId, execution) {
|
|
564
|
+
const executions = this.monitoringExecutionHistory.get(workflowId) || [];
|
|
565
|
+
executions.push(execution);
|
|
566
|
+
// Keep last 100 executions
|
|
567
|
+
if (executions.length > 100) {
|
|
568
|
+
executions.shift();
|
|
569
|
+
}
|
|
570
|
+
this.monitoringExecutionHistory.set(workflowId, executions);
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* Execute workflows multiple times to collect real metrics
|
|
574
|
+
* This validates that metrics are actually being collected correctly
|
|
575
|
+
*/
|
|
576
|
+
async executeRuntimeMetricsValidation(workflowId, testInput, iterations = 5) {
|
|
577
|
+
const input = testInput || { test: true, timestamp: Date.now() };
|
|
578
|
+
for (let i = 0; i < iterations; i++) {
|
|
579
|
+
try {
|
|
580
|
+
// Execute workflow
|
|
581
|
+
const execution = await this.executeWorkflow(workflowId, {
|
|
582
|
+
...input,
|
|
583
|
+
iteration: i + 1,
|
|
584
|
+
}, {
|
|
585
|
+
waitForCompletion: true,
|
|
586
|
+
timeout: 30000,
|
|
587
|
+
});
|
|
588
|
+
// Wait for completion
|
|
589
|
+
const completedExecution = await this.waitForExecution(execution.id, 30000);
|
|
590
|
+
// Record the execution for metrics
|
|
591
|
+
this.recordExecution(workflowId, completedExecution);
|
|
592
|
+
// Verify that execution metadata is captured
|
|
593
|
+
this.verifyExecutionMetadata(completedExecution, i + 1);
|
|
594
|
+
}
|
|
595
|
+
catch (error) {
|
|
596
|
+
// Record failed execution too - important for error rate
|
|
597
|
+
const failedExecution = {
|
|
598
|
+
id: `failed-${Date.now()}-${i}`,
|
|
599
|
+
finished: true,
|
|
600
|
+
status: 'failed',
|
|
601
|
+
mode: 'manual',
|
|
602
|
+
startedAt: new Date().toISOString(),
|
|
603
|
+
stoppedAt: new Date().toISOString(),
|
|
604
|
+
workflowId,
|
|
605
|
+
data: {
|
|
606
|
+
resultData: {
|
|
607
|
+
error: {
|
|
608
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
609
|
+
node: 'unknown',
|
|
610
|
+
},
|
|
611
|
+
runData: {},
|
|
612
|
+
lastNodeExecuted: '',
|
|
613
|
+
},
|
|
614
|
+
},
|
|
615
|
+
};
|
|
616
|
+
this.recordExecution(workflowId, failedExecution);
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
/**
|
|
621
|
+
* Verify execution has proper metadata for monitoring
|
|
622
|
+
*/
|
|
623
|
+
verifyExecutionMetadata(execution, iteration) {
|
|
624
|
+
const issues = [];
|
|
625
|
+
// Check for required fields
|
|
626
|
+
if (!execution.startedAt) {
|
|
627
|
+
issues.push('Missing startedAt timestamp');
|
|
628
|
+
}
|
|
629
|
+
if (!execution.stoppedAt && execution.finished) {
|
|
630
|
+
issues.push('Missing stoppedAt timestamp');
|
|
631
|
+
}
|
|
632
|
+
if (!execution.workflowId) {
|
|
633
|
+
issues.push('Missing workflowId');
|
|
634
|
+
}
|
|
635
|
+
// Check run data for node metrics
|
|
636
|
+
const runData = execution.data?.resultData?.runData;
|
|
637
|
+
if (runData) {
|
|
638
|
+
for (const [nodeName, nodeRuns] of Object.entries(runData)) {
|
|
639
|
+
for (const run of nodeRuns) {
|
|
640
|
+
if (!run.startTime) {
|
|
641
|
+
issues.push(`Node ${nodeName}: Missing startTime`);
|
|
642
|
+
}
|
|
643
|
+
if (run.executionStatus === undefined) {
|
|
644
|
+
issues.push(`Node ${nodeName}: Missing executionStatus`);
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
if (issues.length > 0) {
|
|
650
|
+
console.warn(`Execution ${execution.id} (iteration ${iteration}) has monitoring issues:`, issues);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
/**
|
|
654
|
+
* Wait for workflow execution to complete
|
|
655
|
+
*/
|
|
656
|
+
async waitForExecution(executionId, timeoutMs) {
|
|
657
|
+
const startTime = Date.now();
|
|
658
|
+
while (Date.now() - startTime < timeoutMs) {
|
|
659
|
+
const execution = await this.getExecution(executionId);
|
|
660
|
+
if (execution.status !== 'running' && execution.status !== 'waiting') {
|
|
661
|
+
return execution;
|
|
662
|
+
}
|
|
663
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
664
|
+
}
|
|
665
|
+
throw new Error(`Execution ${executionId} timed out after ${timeoutMs}ms`);
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
exports.N8nMonitoringValidatorAgent = N8nMonitoringValidatorAgent;
|
|
669
|
+
//# sourceMappingURL=N8nMonitoringValidatorAgent.js.map
|