n8n-mcp 2.13.1 → 2.14.0

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.
Files changed (79) hide show
  1. package/README.md +45 -0
  2. package/data/nodes.db +0 -0
  3. package/dist/database/node-repository.d.ts +5 -0
  4. package/dist/database/node-repository.d.ts.map +1 -1
  5. package/dist/database/node-repository.js +90 -0
  6. package/dist/database/node-repository.js.map +1 -1
  7. package/dist/errors/validation-service-error.d.ts +10 -0
  8. package/dist/errors/validation-service-error.d.ts.map +1 -0
  9. package/dist/errors/validation-service-error.js +26 -0
  10. package/dist/errors/validation-service-error.js.map +1 -0
  11. package/dist/mcp/handlers-n8n-manager.d.ts.map +1 -1
  12. package/dist/mcp/handlers-n8n-manager.js +6 -0
  13. package/dist/mcp/handlers-n8n-manager.js.map +1 -1
  14. package/dist/mcp/index.js +32 -0
  15. package/dist/mcp/index.js.map +1 -1
  16. package/dist/mcp/server.d.ts +2 -0
  17. package/dist/mcp/server.d.ts.map +1 -1
  18. package/dist/mcp/server.js +57 -19
  19. package/dist/mcp/server.js.map +1 -1
  20. package/dist/services/config-validator.d.ts +1 -0
  21. package/dist/services/config-validator.d.ts.map +1 -1
  22. package/dist/services/config-validator.js.map +1 -1
  23. package/dist/services/enhanced-config-validator.d.ts +6 -0
  24. package/dist/services/enhanced-config-validator.d.ts.map +1 -1
  25. package/dist/services/enhanced-config-validator.js +127 -0
  26. package/dist/services/enhanced-config-validator.js.map +1 -1
  27. package/dist/services/operation-similarity-service.d.ts +32 -0
  28. package/dist/services/operation-similarity-service.d.ts.map +1 -0
  29. package/dist/services/operation-similarity-service.js +341 -0
  30. package/dist/services/operation-similarity-service.js.map +1 -0
  31. package/dist/services/resource-similarity-service.d.ts +33 -0
  32. package/dist/services/resource-similarity-service.d.ts.map +1 -0
  33. package/dist/services/resource-similarity-service.js +358 -0
  34. package/dist/services/resource-similarity-service.js.map +1 -0
  35. package/dist/telemetry/batch-processor.d.ts +32 -0
  36. package/dist/telemetry/batch-processor.d.ts.map +1 -0
  37. package/dist/telemetry/batch-processor.js +266 -0
  38. package/dist/telemetry/batch-processor.js.map +1 -0
  39. package/dist/telemetry/config-manager.d.ts +28 -0
  40. package/dist/telemetry/config-manager.d.ts.map +1 -0
  41. package/dist/telemetry/config-manager.js +211 -0
  42. package/dist/telemetry/config-manager.js.map +1 -0
  43. package/dist/telemetry/event-tracker.d.ts +58 -0
  44. package/dist/telemetry/event-tracker.d.ts.map +1 -0
  45. package/dist/telemetry/event-tracker.js +295 -0
  46. package/dist/telemetry/event-tracker.js.map +1 -0
  47. package/dist/telemetry/event-validator.d.ts +78 -0
  48. package/dist/telemetry/event-validator.d.ts.map +1 -0
  49. package/dist/telemetry/event-validator.js +204 -0
  50. package/dist/telemetry/event-validator.js.map +1 -0
  51. package/dist/telemetry/index.d.ts +5 -0
  52. package/dist/telemetry/index.d.ts.map +1 -0
  53. package/dist/telemetry/index.js +11 -0
  54. package/dist/telemetry/index.js.map +1 -0
  55. package/dist/telemetry/performance-monitor.d.ts +113 -0
  56. package/dist/telemetry/performance-monitor.d.ts.map +1 -0
  57. package/dist/telemetry/performance-monitor.js +208 -0
  58. package/dist/telemetry/performance-monitor.js.map +1 -0
  59. package/dist/telemetry/rate-limiter.d.ts +30 -0
  60. package/dist/telemetry/rate-limiter.d.ts.map +1 -0
  61. package/dist/telemetry/rate-limiter.js +103 -0
  62. package/dist/telemetry/rate-limiter.js.map +1 -0
  63. package/dist/telemetry/telemetry-error.d.ts +44 -0
  64. package/dist/telemetry/telemetry-error.d.ts.map +1 -0
  65. package/dist/telemetry/telemetry-error.js +153 -0
  66. package/dist/telemetry/telemetry-error.js.map +1 -0
  67. package/dist/telemetry/telemetry-manager.d.ts +127 -0
  68. package/dist/telemetry/telemetry-manager.d.ts.map +1 -0
  69. package/dist/telemetry/telemetry-manager.js +182 -0
  70. package/dist/telemetry/telemetry-manager.js.map +1 -0
  71. package/dist/telemetry/telemetry-types.d.ts +69 -0
  72. package/dist/telemetry/telemetry-types.d.ts.map +1 -0
  73. package/dist/telemetry/telemetry-types.js +29 -0
  74. package/dist/telemetry/telemetry-types.js.map +1 -0
  75. package/dist/telemetry/workflow-sanitizer.d.ts +33 -0
  76. package/dist/telemetry/workflow-sanitizer.d.ts.map +1 -0
  77. package/dist/telemetry/workflow-sanitizer.js +190 -0
  78. package/dist/telemetry/workflow-sanitizer.js.map +1 -0
  79. package/package.json +2 -1
@@ -0,0 +1,295 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TelemetryEventTracker = void 0;
4
+ const workflow_sanitizer_1 = require("./workflow-sanitizer");
5
+ const rate_limiter_1 = require("./rate-limiter");
6
+ const event_validator_1 = require("./event-validator");
7
+ const telemetry_error_1 = require("./telemetry-error");
8
+ const logger_1 = require("../utils/logger");
9
+ const fs_1 = require("fs");
10
+ const path_1 = require("path");
11
+ class TelemetryEventTracker {
12
+ constructor(getUserId, isEnabled) {
13
+ this.getUserId = getUserId;
14
+ this.isEnabled = isEnabled;
15
+ this.eventQueue = [];
16
+ this.workflowQueue = [];
17
+ this.previousToolTimestamp = 0;
18
+ this.performanceMetrics = new Map();
19
+ this.rateLimiter = new rate_limiter_1.TelemetryRateLimiter();
20
+ this.validator = new event_validator_1.TelemetryEventValidator();
21
+ }
22
+ trackToolUsage(toolName, success, duration) {
23
+ if (!this.isEnabled())
24
+ return;
25
+ if (!this.rateLimiter.allow()) {
26
+ logger_1.logger.debug(`Rate limited: tool_used event for ${toolName}`);
27
+ return;
28
+ }
29
+ if (duration !== undefined) {
30
+ this.recordPerformanceMetric(toolName, duration);
31
+ }
32
+ const event = {
33
+ user_id: this.getUserId(),
34
+ event: 'tool_used',
35
+ properties: {
36
+ tool: toolName.replace(/[^a-zA-Z0-9_-]/g, '_'),
37
+ success,
38
+ duration: duration || 0,
39
+ }
40
+ };
41
+ const validated = this.validator.validateEvent(event);
42
+ if (validated) {
43
+ this.eventQueue.push(validated);
44
+ }
45
+ }
46
+ async trackWorkflowCreation(workflow, validationPassed) {
47
+ if (!this.isEnabled())
48
+ return;
49
+ if (!this.rateLimiter.allow()) {
50
+ logger_1.logger.debug('Rate limited: workflow creation event');
51
+ return;
52
+ }
53
+ if (!validationPassed) {
54
+ this.trackEvent('workflow_validation_failed', {
55
+ nodeCount: workflow.nodes?.length || 0,
56
+ });
57
+ return;
58
+ }
59
+ try {
60
+ const sanitized = workflow_sanitizer_1.WorkflowSanitizer.sanitizeWorkflow(workflow);
61
+ const telemetryData = {
62
+ user_id: this.getUserId(),
63
+ workflow_hash: sanitized.workflowHash,
64
+ node_count: sanitized.nodeCount,
65
+ node_types: sanitized.nodeTypes,
66
+ has_trigger: sanitized.hasTrigger,
67
+ has_webhook: sanitized.hasWebhook,
68
+ complexity: sanitized.complexity,
69
+ sanitized_workflow: {
70
+ nodes: sanitized.nodes,
71
+ connections: sanitized.connections,
72
+ },
73
+ };
74
+ const validated = this.validator.validateWorkflow(telemetryData);
75
+ if (validated) {
76
+ this.workflowQueue.push(validated);
77
+ this.trackEvent('workflow_created', {
78
+ nodeCount: sanitized.nodeCount,
79
+ nodeTypes: sanitized.nodeTypes.length,
80
+ complexity: sanitized.complexity,
81
+ hasTrigger: sanitized.hasTrigger,
82
+ hasWebhook: sanitized.hasWebhook,
83
+ });
84
+ }
85
+ }
86
+ catch (error) {
87
+ logger_1.logger.debug('Failed to track workflow creation:', error);
88
+ throw new telemetry_error_1.TelemetryError(telemetry_error_1.TelemetryErrorType.VALIDATION_ERROR, 'Failed to sanitize workflow', { error: error instanceof Error ? error.message : String(error) });
89
+ }
90
+ }
91
+ trackError(errorType, context, toolName) {
92
+ if (!this.isEnabled())
93
+ return;
94
+ this.trackEvent('error_occurred', {
95
+ errorType: this.sanitizeErrorType(errorType),
96
+ context: this.sanitizeContext(context),
97
+ tool: toolName ? toolName.replace(/[^a-zA-Z0-9_-]/g, '_') : undefined,
98
+ }, false);
99
+ }
100
+ trackEvent(eventName, properties, checkRateLimit = true) {
101
+ if (!this.isEnabled())
102
+ return;
103
+ if (checkRateLimit && !this.rateLimiter.allow()) {
104
+ logger_1.logger.debug(`Rate limited: ${eventName} event`);
105
+ return;
106
+ }
107
+ const event = {
108
+ user_id: this.getUserId(),
109
+ event: eventName,
110
+ properties,
111
+ };
112
+ const validated = this.validator.validateEvent(event);
113
+ if (validated) {
114
+ this.eventQueue.push(validated);
115
+ }
116
+ }
117
+ trackSessionStart() {
118
+ if (!this.isEnabled())
119
+ return;
120
+ this.trackEvent('session_start', {
121
+ version: this.getPackageVersion(),
122
+ platform: process.platform,
123
+ arch: process.arch,
124
+ nodeVersion: process.version,
125
+ });
126
+ }
127
+ trackSearchQuery(query, resultsFound, searchType) {
128
+ if (!this.isEnabled())
129
+ return;
130
+ this.trackEvent('search_query', {
131
+ query: query.substring(0, 100),
132
+ resultsFound,
133
+ searchType,
134
+ hasResults: resultsFound > 0,
135
+ isZeroResults: resultsFound === 0
136
+ });
137
+ }
138
+ trackValidationDetails(nodeType, errorType, details) {
139
+ if (!this.isEnabled())
140
+ return;
141
+ this.trackEvent('validation_details', {
142
+ nodeType: nodeType.replace(/[^a-zA-Z0-9_.-]/g, '_'),
143
+ errorType: this.sanitizeErrorType(errorType),
144
+ errorCategory: this.categorizeError(errorType),
145
+ details
146
+ });
147
+ }
148
+ trackToolSequence(previousTool, currentTool, timeDelta) {
149
+ if (!this.isEnabled())
150
+ return;
151
+ this.trackEvent('tool_sequence', {
152
+ previousTool: previousTool.replace(/[^a-zA-Z0-9_-]/g, '_'),
153
+ currentTool: currentTool.replace(/[^a-zA-Z0-9_-]/g, '_'),
154
+ timeDelta: Math.min(timeDelta, 300000),
155
+ isSlowTransition: timeDelta > 10000,
156
+ sequence: `${previousTool}->${currentTool}`
157
+ });
158
+ }
159
+ trackNodeConfiguration(nodeType, propertiesSet, usedDefaults) {
160
+ if (!this.isEnabled())
161
+ return;
162
+ this.trackEvent('node_configuration', {
163
+ nodeType: nodeType.replace(/[^a-zA-Z0-9_.-]/g, '_'),
164
+ propertiesSet,
165
+ usedDefaults,
166
+ complexity: this.categorizeConfigComplexity(propertiesSet)
167
+ });
168
+ }
169
+ trackPerformanceMetric(operation, duration, metadata) {
170
+ if (!this.isEnabled())
171
+ return;
172
+ this.recordPerformanceMetric(operation, duration);
173
+ this.trackEvent('performance_metric', {
174
+ operation: operation.replace(/[^a-zA-Z0-9_-]/g, '_'),
175
+ duration,
176
+ isSlow: duration > 1000,
177
+ isVerySlow: duration > 5000,
178
+ metadata
179
+ });
180
+ }
181
+ updateToolSequence(toolName) {
182
+ if (this.previousTool) {
183
+ const timeDelta = Date.now() - this.previousToolTimestamp;
184
+ this.trackToolSequence(this.previousTool, toolName, timeDelta);
185
+ }
186
+ this.previousTool = toolName;
187
+ this.previousToolTimestamp = Date.now();
188
+ }
189
+ getEventQueue() {
190
+ return [...this.eventQueue];
191
+ }
192
+ getWorkflowQueue() {
193
+ return [...this.workflowQueue];
194
+ }
195
+ clearEventQueue() {
196
+ this.eventQueue = [];
197
+ }
198
+ clearWorkflowQueue() {
199
+ this.workflowQueue = [];
200
+ }
201
+ getStats() {
202
+ return {
203
+ rateLimiter: this.rateLimiter.getStats(),
204
+ validator: this.validator.getStats(),
205
+ eventQueueSize: this.eventQueue.length,
206
+ workflowQueueSize: this.workflowQueue.length,
207
+ performanceMetrics: this.getPerformanceStats()
208
+ };
209
+ }
210
+ recordPerformanceMetric(operation, duration) {
211
+ if (!this.performanceMetrics.has(operation)) {
212
+ this.performanceMetrics.set(operation, []);
213
+ }
214
+ const metrics = this.performanceMetrics.get(operation);
215
+ metrics.push(duration);
216
+ if (metrics.length > 100) {
217
+ metrics.shift();
218
+ }
219
+ }
220
+ getPerformanceStats() {
221
+ const stats = {};
222
+ for (const [operation, durations] of this.performanceMetrics.entries()) {
223
+ if (durations.length === 0)
224
+ continue;
225
+ const sorted = [...durations].sort((a, b) => a - b);
226
+ const sum = sorted.reduce((a, b) => a + b, 0);
227
+ stats[operation] = {
228
+ count: sorted.length,
229
+ min: sorted[0],
230
+ max: sorted[sorted.length - 1],
231
+ avg: Math.round(sum / sorted.length),
232
+ p50: sorted[Math.floor(sorted.length * 0.5)],
233
+ p95: sorted[Math.floor(sorted.length * 0.95)],
234
+ p99: sorted[Math.floor(sorted.length * 0.99)]
235
+ };
236
+ }
237
+ return stats;
238
+ }
239
+ categorizeError(errorType) {
240
+ const lowerError = errorType.toLowerCase();
241
+ if (lowerError.includes('type'))
242
+ return 'type_error';
243
+ if (lowerError.includes('validation'))
244
+ return 'validation_error';
245
+ if (lowerError.includes('required'))
246
+ return 'required_field_error';
247
+ if (lowerError.includes('connection'))
248
+ return 'connection_error';
249
+ if (lowerError.includes('expression'))
250
+ return 'expression_error';
251
+ return 'other_error';
252
+ }
253
+ categorizeConfigComplexity(propertiesSet) {
254
+ if (propertiesSet === 0)
255
+ return 'defaults_only';
256
+ if (propertiesSet <= 3)
257
+ return 'simple';
258
+ if (propertiesSet <= 10)
259
+ return 'moderate';
260
+ return 'complex';
261
+ }
262
+ getPackageVersion() {
263
+ try {
264
+ const possiblePaths = [
265
+ (0, path_1.resolve)(__dirname, '..', '..', 'package.json'),
266
+ (0, path_1.resolve)(process.cwd(), 'package.json'),
267
+ (0, path_1.resolve)(__dirname, '..', '..', '..', 'package.json')
268
+ ];
269
+ for (const packagePath of possiblePaths) {
270
+ if ((0, fs_1.existsSync)(packagePath)) {
271
+ const packageJson = JSON.parse((0, fs_1.readFileSync)(packagePath, 'utf-8'));
272
+ if (packageJson.version) {
273
+ return packageJson.version;
274
+ }
275
+ }
276
+ }
277
+ return 'unknown';
278
+ }
279
+ catch (error) {
280
+ logger_1.logger.debug('Failed to get package version:', error);
281
+ return 'unknown';
282
+ }
283
+ }
284
+ sanitizeErrorType(errorType) {
285
+ return errorType.replace(/[^a-zA-Z0-9_-]/g, '_').substring(0, 50);
286
+ }
287
+ sanitizeContext(context) {
288
+ return context
289
+ .replace(/https?:\/\/[^\s]+/gi, '[URL]')
290
+ .replace(/[a-zA-Z0-9_-]{32,}/g, '[KEY]')
291
+ .substring(0, 100);
292
+ }
293
+ }
294
+ exports.TelemetryEventTracker = TelemetryEventTracker;
295
+ //# sourceMappingURL=event-tracker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-tracker.js","sourceRoot":"","sources":["../../src/telemetry/event-tracker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,78 @@
1
+ import { z } from 'zod';
2
+ import { TelemetryEvent, WorkflowTelemetry } from './telemetry-types';
3
+ export declare const telemetryEventSchema: z.ZodObject<{
4
+ user_id: z.ZodString;
5
+ event: z.ZodString;
6
+ properties: z.ZodEffects<z.ZodRecord<z.ZodString, z.ZodUnknown>, Record<string, any>, Record<string, unknown>>;
7
+ created_at: z.ZodOptional<z.ZodString>;
8
+ }, "strip", z.ZodTypeAny, {
9
+ properties: Record<string, any>;
10
+ user_id: string;
11
+ event: string;
12
+ created_at?: string | undefined;
13
+ }, {
14
+ properties: Record<string, unknown>;
15
+ user_id: string;
16
+ event: string;
17
+ created_at?: string | undefined;
18
+ }>;
19
+ export declare const workflowTelemetrySchema: z.ZodObject<{
20
+ user_id: z.ZodString;
21
+ workflow_hash: z.ZodString;
22
+ node_count: z.ZodNumber;
23
+ node_types: z.ZodArray<z.ZodString, "many">;
24
+ has_trigger: z.ZodBoolean;
25
+ has_webhook: z.ZodBoolean;
26
+ complexity: z.ZodEnum<["simple", "medium", "complex"]>;
27
+ sanitized_workflow: z.ZodObject<{
28
+ nodes: z.ZodArray<z.ZodAny, "many">;
29
+ connections: z.ZodRecord<z.ZodString, z.ZodAny>;
30
+ }, "strip", z.ZodTypeAny, {
31
+ nodes: any[];
32
+ connections: Record<string, any>;
33
+ }, {
34
+ nodes: any[];
35
+ connections: Record<string, any>;
36
+ }>;
37
+ created_at: z.ZodOptional<z.ZodString>;
38
+ }, "strip", z.ZodTypeAny, {
39
+ complexity: "simple" | "medium" | "complex";
40
+ user_id: string;
41
+ workflow_hash: string;
42
+ node_count: number;
43
+ node_types: string[];
44
+ has_trigger: boolean;
45
+ has_webhook: boolean;
46
+ sanitized_workflow: {
47
+ nodes: any[];
48
+ connections: Record<string, any>;
49
+ };
50
+ created_at?: string | undefined;
51
+ }, {
52
+ complexity: "simple" | "medium" | "complex";
53
+ user_id: string;
54
+ workflow_hash: string;
55
+ node_count: number;
56
+ node_types: string[];
57
+ has_trigger: boolean;
58
+ has_webhook: boolean;
59
+ sanitized_workflow: {
60
+ nodes: any[];
61
+ connections: Record<string, any>;
62
+ };
63
+ created_at?: string | undefined;
64
+ }>;
65
+ export declare class TelemetryEventValidator {
66
+ private validationErrors;
67
+ private validationSuccesses;
68
+ validateEvent(event: TelemetryEvent): TelemetryEvent | null;
69
+ validateWorkflow(workflow: WorkflowTelemetry): WorkflowTelemetry | null;
70
+ getStats(): {
71
+ errors: number;
72
+ successes: number;
73
+ total: number;
74
+ errorRate: number;
75
+ };
76
+ resetStats(): void;
77
+ }
78
+ //# sourceMappingURL=event-validator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-validator.d.ts","sourceRoot":"","sources":["../../src/telemetry/event-validator.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAyCtE,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;EAK/B,CAAC;AAGH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAalC,CAAC;AA4HH,qBAAa,uBAAuB;IAClC,OAAO,CAAC,gBAAgB,CAAa;IACrC,OAAO,CAAC,mBAAmB,CAAa;IAKxC,aAAa,CAAC,KAAK,EAAE,cAAc,GAAG,cAAc,GAAG,IAAI;IAkC3D,gBAAgB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,iBAAiB,GAAG,IAAI;IAmBvE,QAAQ;;;;;;IAYR,UAAU,IAAI,IAAI;CAInB"}
@@ -0,0 +1,204 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TelemetryEventValidator = exports.workflowTelemetrySchema = exports.telemetryEventSchema = void 0;
4
+ const zod_1 = require("zod");
5
+ const logger_1 = require("../utils/logger");
6
+ const sanitizedString = zod_1.z.string().transform(val => {
7
+ let sanitized = val.replace(/https?:\/\/[^\s]+/gi, '[URL]');
8
+ sanitized = sanitized.replace(/[a-zA-Z0-9_-]{32,}/g, '[KEY]');
9
+ sanitized = sanitized.replace(/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g, '[EMAIL]');
10
+ return sanitized;
11
+ });
12
+ const eventPropertiesSchema = zod_1.z.record(zod_1.z.unknown()).transform(obj => {
13
+ const sanitized = {};
14
+ for (const [key, value] of Object.entries(obj)) {
15
+ if (isSensitiveKey(key)) {
16
+ continue;
17
+ }
18
+ if (typeof value === 'string') {
19
+ sanitized[key] = sanitizedString.parse(value);
20
+ }
21
+ else if (typeof value === 'number' || typeof value === 'boolean') {
22
+ sanitized[key] = value;
23
+ }
24
+ else if (value === null || value === undefined) {
25
+ sanitized[key] = null;
26
+ }
27
+ else if (typeof value === 'object') {
28
+ sanitized[key] = sanitizeNestedObject(value, 3);
29
+ }
30
+ }
31
+ return sanitized;
32
+ });
33
+ exports.telemetryEventSchema = zod_1.z.object({
34
+ user_id: zod_1.z.string().min(1).max(64),
35
+ event: zod_1.z.string().min(1).max(100).regex(/^[a-zA-Z0-9_-]+$/),
36
+ properties: eventPropertiesSchema,
37
+ created_at: zod_1.z.string().datetime().optional()
38
+ });
39
+ exports.workflowTelemetrySchema = zod_1.z.object({
40
+ user_id: zod_1.z.string().min(1).max(64),
41
+ workflow_hash: zod_1.z.string().min(1).max(64),
42
+ node_count: zod_1.z.number().int().min(0).max(1000),
43
+ node_types: zod_1.z.array(zod_1.z.string()).max(100),
44
+ has_trigger: zod_1.z.boolean(),
45
+ has_webhook: zod_1.z.boolean(),
46
+ complexity: zod_1.z.enum(['simple', 'medium', 'complex']),
47
+ sanitized_workflow: zod_1.z.object({
48
+ nodes: zod_1.z.array(zod_1.z.any()).max(1000),
49
+ connections: zod_1.z.record(zod_1.z.any())
50
+ }),
51
+ created_at: zod_1.z.string().datetime().optional()
52
+ });
53
+ const toolUsagePropertiesSchema = zod_1.z.object({
54
+ tool: zod_1.z.string().max(100),
55
+ success: zod_1.z.boolean(),
56
+ duration: zod_1.z.number().min(0).max(3600000),
57
+ });
58
+ const searchQueryPropertiesSchema = zod_1.z.object({
59
+ query: zod_1.z.string().max(100).transform(val => {
60
+ let sanitized = val.replace(/https?:\/\/[^\s]+/gi, '[URL]');
61
+ sanitized = sanitized.replace(/[a-zA-Z0-9_-]{32,}/g, '[KEY]');
62
+ sanitized = sanitized.replace(/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g, '[EMAIL]');
63
+ return sanitized;
64
+ }),
65
+ resultsFound: zod_1.z.number().int().min(0),
66
+ searchType: zod_1.z.string().max(50),
67
+ hasResults: zod_1.z.boolean(),
68
+ isZeroResults: zod_1.z.boolean()
69
+ });
70
+ const validationDetailsPropertiesSchema = zod_1.z.object({
71
+ nodeType: zod_1.z.string().max(100),
72
+ errorType: zod_1.z.string().max(100),
73
+ errorCategory: zod_1.z.string().max(50),
74
+ details: zod_1.z.record(zod_1.z.any()).optional()
75
+ });
76
+ const performanceMetricPropertiesSchema = zod_1.z.object({
77
+ operation: zod_1.z.string().max(100),
78
+ duration: zod_1.z.number().min(0).max(3600000),
79
+ isSlow: zod_1.z.boolean(),
80
+ isVerySlow: zod_1.z.boolean(),
81
+ metadata: zod_1.z.record(zod_1.z.any()).optional()
82
+ });
83
+ const EVENT_SCHEMAS = {
84
+ 'tool_used': toolUsagePropertiesSchema,
85
+ 'search_query': searchQueryPropertiesSchema,
86
+ 'validation_details': validationDetailsPropertiesSchema,
87
+ 'performance_metric': performanceMetricPropertiesSchema,
88
+ };
89
+ function isSensitiveKey(key) {
90
+ const sensitivePatterns = [
91
+ 'password', 'passwd', 'pwd',
92
+ 'token', 'jwt', 'bearer',
93
+ 'key', 'apikey', 'api_key', 'api-key',
94
+ 'secret', 'private',
95
+ 'credential', 'cred', 'auth',
96
+ 'url', 'uri', 'endpoint', 'host', 'hostname',
97
+ 'database', 'db', 'connection', 'conn',
98
+ 'slack', 'discord', 'telegram',
99
+ 'oauth', 'client_secret', 'client-secret', 'clientsecret',
100
+ 'access_token', 'access-token', 'accesstoken',
101
+ 'refresh_token', 'refresh-token', 'refreshtoken'
102
+ ];
103
+ const lowerKey = key.toLowerCase();
104
+ if (sensitivePatterns.includes(lowerKey)) {
105
+ return true;
106
+ }
107
+ return sensitivePatterns.some(pattern => {
108
+ const regex = new RegExp(`(?:^|[_-])${pattern}(?:[_-]|$)`, 'i');
109
+ return regex.test(key) || lowerKey.includes(pattern);
110
+ });
111
+ }
112
+ function sanitizeNestedObject(obj, maxDepth) {
113
+ if (maxDepth <= 0 || !obj || typeof obj !== 'object') {
114
+ return '[NESTED]';
115
+ }
116
+ if (Array.isArray(obj)) {
117
+ return obj.slice(0, 10).map(item => typeof item === 'object' ? sanitizeNestedObject(item, maxDepth - 1) : item);
118
+ }
119
+ const sanitized = {};
120
+ let keyCount = 0;
121
+ for (const [key, value] of Object.entries(obj)) {
122
+ if (keyCount++ >= 20) {
123
+ sanitized['...'] = 'truncated';
124
+ break;
125
+ }
126
+ if (isSensitiveKey(key)) {
127
+ continue;
128
+ }
129
+ if (typeof value === 'string') {
130
+ sanitized[key] = sanitizedString.parse(value);
131
+ }
132
+ else if (typeof value === 'object' && value !== null) {
133
+ sanitized[key] = sanitizeNestedObject(value, maxDepth - 1);
134
+ }
135
+ else {
136
+ sanitized[key] = value;
137
+ }
138
+ }
139
+ return sanitized;
140
+ }
141
+ class TelemetryEventValidator {
142
+ constructor() {
143
+ this.validationErrors = 0;
144
+ this.validationSuccesses = 0;
145
+ }
146
+ validateEvent(event) {
147
+ try {
148
+ const specificSchema = EVENT_SCHEMAS[event.event];
149
+ if (specificSchema) {
150
+ const validatedProperties = specificSchema.safeParse(event.properties);
151
+ if (!validatedProperties.success) {
152
+ logger_1.logger.debug(`Event validation failed for ${event.event}:`, validatedProperties.error.errors);
153
+ this.validationErrors++;
154
+ return null;
155
+ }
156
+ event.properties = validatedProperties.data;
157
+ }
158
+ const validated = exports.telemetryEventSchema.parse(event);
159
+ this.validationSuccesses++;
160
+ return validated;
161
+ }
162
+ catch (error) {
163
+ if (error instanceof zod_1.z.ZodError) {
164
+ logger_1.logger.debug('Event validation error:', error.errors);
165
+ }
166
+ else {
167
+ logger_1.logger.debug('Unexpected validation error:', error);
168
+ }
169
+ this.validationErrors++;
170
+ return null;
171
+ }
172
+ }
173
+ validateWorkflow(workflow) {
174
+ try {
175
+ const validated = exports.workflowTelemetrySchema.parse(workflow);
176
+ this.validationSuccesses++;
177
+ return validated;
178
+ }
179
+ catch (error) {
180
+ if (error instanceof zod_1.z.ZodError) {
181
+ logger_1.logger.debug('Workflow validation error:', error.errors);
182
+ }
183
+ else {
184
+ logger_1.logger.debug('Unexpected workflow validation error:', error);
185
+ }
186
+ this.validationErrors++;
187
+ return null;
188
+ }
189
+ }
190
+ getStats() {
191
+ return {
192
+ errors: this.validationErrors,
193
+ successes: this.validationSuccesses,
194
+ total: this.validationErrors + this.validationSuccesses,
195
+ errorRate: this.validationErrors / (this.validationErrors + this.validationSuccesses) || 0
196
+ };
197
+ }
198
+ resetStats() {
199
+ this.validationErrors = 0;
200
+ this.validationSuccesses = 0;
201
+ }
202
+ }
203
+ exports.TelemetryEventValidator = TelemetryEventValidator;
204
+ //# sourceMappingURL=event-validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-validator.js","sourceRoot":"","sources":["../../src/telemetry/event-validator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export { TelemetryManager, telemetry } from './telemetry-manager';
2
+ export { TelemetryConfigManager } from './config-manager';
3
+ export { WorkflowSanitizer } from './workflow-sanitizer';
4
+ export type { TelemetryConfig } from './config-manager';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/telemetry/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,YAAY,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WorkflowSanitizer = exports.TelemetryConfigManager = exports.telemetry = exports.TelemetryManager = void 0;
4
+ var telemetry_manager_1 = require("./telemetry-manager");
5
+ Object.defineProperty(exports, "TelemetryManager", { enumerable: true, get: function () { return telemetry_manager_1.TelemetryManager; } });
6
+ Object.defineProperty(exports, "telemetry", { enumerable: true, get: function () { return telemetry_manager_1.telemetry; } });
7
+ var config_manager_1 = require("./config-manager");
8
+ Object.defineProperty(exports, "TelemetryConfigManager", { enumerable: true, get: function () { return config_manager_1.TelemetryConfigManager; } });
9
+ var workflow_sanitizer_1 = require("./workflow-sanitizer");
10
+ Object.defineProperty(exports, "WorkflowSanitizer", { enumerable: true, get: function () { return workflow_sanitizer_1.WorkflowSanitizer; } });
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/telemetry/index.ts"],"names":[],"mappings":";;;AAKA,yDAAkE;AAAzD,qHAAA,gBAAgB,OAAA;AAAE,8GAAA,SAAS,OAAA;AACpC,mDAA0D;AAAjD,wHAAA,sBAAsB,OAAA;AAC/B,2DAAyD;AAAhD,uHAAA,iBAAiB,OAAA"}