@devilsdev/rag-pipeline-utils 2.2.1 → 2.3.1

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 (40) hide show
  1. package/README.md +260 -19
  2. package/contracts/contract-schema.json +189 -0
  3. package/dist/index.cjs +19 -0
  4. package/dist/index.mjs +15 -1
  5. package/package.json +3 -2
  6. package/src/cli/commands/wizard.js +627 -0
  7. package/src/cli/input-sanitization-middleware.js +356 -0
  8. package/src/cli/templates/development.template.json +64 -0
  9. package/src/cli/templates/minimal.template.json +33 -0
  10. package/src/cli/templates/production.template.json +104 -0
  11. package/src/cli/templates/testing.template.json +45 -0
  12. package/src/config/connection-pool-config.json +259 -0
  13. package/src/config/memory-optimization.js +414 -0
  14. package/src/config/redaction-patterns.json +150 -0
  15. package/src/config/sanitization-rules.json +323 -0
  16. package/src/core/plugin-registry.js +266 -20
  17. package/src/dag/core/error-context.js +391 -0
  18. package/src/dag/core/execution-scheduler.js +350 -0
  19. package/src/dag/core/topology-validation.js +415 -0
  20. package/src/dag/dag-engine.js +26 -424
  21. package/src/dev/README.md +126 -0
  22. package/src/dev/dev-server.js +356 -0
  23. package/src/dev/examples/hot-reload-usage.js +355 -0
  24. package/src/dev/hot-reload.js +807 -0
  25. package/src/enterprise/sso-integration.js +67 -25
  26. package/src/index.js +19 -0
  27. package/src/observability/event-logger.js +62 -2
  28. package/src/plugins/optimized-openai-embedder.js +169 -0
  29. package/src/security/jwt-config.js +431 -0
  30. package/src/security/jwt-validator.js +701 -0
  31. package/src/utils/api-client-pool-integration.js +436 -0
  32. package/src/utils/batch-processor.js +710 -0
  33. package/src/utils/connection-pool.js +605 -0
  34. package/src/utils/contract-validator.js +460 -0
  35. package/src/utils/error-formatter.js +603 -0
  36. package/src/utils/examples/error-formatter-usage.js +351 -0
  37. package/src/utils/input-sanitizer.js +967 -0
  38. package/src/utils/memory-monitor.js +800 -0
  39. package/src/utils/secure-logger-config.js +352 -0
  40. package/src/utils/secure-logger.js +576 -0
@@ -0,0 +1,603 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Error Formatter Utility
5
+ *
6
+ * Provides enhanced error messages with actionable suggestions,
7
+ * context, and documentation references.
8
+ *
9
+ * @module utils/error-formatter
10
+ * @since 2.4.0
11
+ */
12
+
13
+ /**
14
+ * Error codes organized by category
15
+ */
16
+ const ERROR_CODES = {
17
+ // Configuration errors (CONFIG_*)
18
+ CONFIG_NOT_FOUND: 'CONFIG_NOT_FOUND',
19
+ CONFIG_INVALID_JSON: 'CONFIG_INVALID_JSON',
20
+ CONFIG_VALIDATION_FAILED: 'CONFIG_VALIDATION_FAILED',
21
+ CONFIG_MISSING_REQUIRED: 'CONFIG_MISSING_REQUIRED',
22
+ CONFIG_INVALID_TYPE: 'CONFIG_INVALID_TYPE',
23
+ CONFIG_INVALID_VALUE: 'CONFIG_INVALID_VALUE',
24
+
25
+ // Plugin errors (PLUGIN_*)
26
+ PLUGIN_NOT_FOUND: 'PLUGIN_NOT_FOUND',
27
+ PLUGIN_LOAD_FAILED: 'PLUGIN_LOAD_FAILED',
28
+ PLUGIN_INVALID_EXPORT: 'PLUGIN_INVALID_EXPORT',
29
+ PLUGIN_EXECUTION_FAILED: 'PLUGIN_EXECUTION_FAILED',
30
+ PLUGIN_INITIALIZATION_FAILED: 'PLUGIN_INITIALIZATION_FAILED',
31
+ PLUGIN_CONTRACT_VIOLATION: 'PLUGIN_CONTRACT_VIOLATION',
32
+ PLUGIN_DEPENDENCY_MISSING: 'PLUGIN_DEPENDENCY_MISSING',
33
+
34
+ // Pipeline errors (PIPELINE_*)
35
+ PIPELINE_CREATION_FAILED: 'PIPELINE_CREATION_FAILED',
36
+ PIPELINE_EXECUTION_FAILED: 'PIPELINE_EXECUTION_FAILED',
37
+ PIPELINE_STAGE_FAILED: 'PIPELINE_STAGE_FAILED',
38
+ PIPELINE_INVALID_STAGE: 'PIPELINE_INVALID_STAGE',
39
+
40
+ // Validation errors (VALIDATION_*)
41
+ VALIDATION_FAILED: 'VALIDATION_FAILED',
42
+ VALIDATION_SCHEMA_ERROR: 'VALIDATION_SCHEMA_ERROR',
43
+ VALIDATION_CONSTRAINT_ERROR: 'VALIDATION_CONSTRAINT_ERROR',
44
+
45
+ // File system errors (FS_*)
46
+ FS_FILE_NOT_FOUND: 'FS_FILE_NOT_FOUND',
47
+ FS_DIRECTORY_NOT_FOUND: 'FS_DIRECTORY_NOT_FOUND',
48
+ FS_PERMISSION_DENIED: 'FS_PERMISSION_DENIED',
49
+ FS_READ_ERROR: 'FS_READ_ERROR',
50
+ FS_WRITE_ERROR: 'FS_WRITE_ERROR',
51
+
52
+ // Network errors (NETWORK_*)
53
+ NETWORK_REQUEST_FAILED: 'NETWORK_REQUEST_FAILED',
54
+ NETWORK_TIMEOUT: 'NETWORK_TIMEOUT',
55
+ NETWORK_INVALID_RESPONSE: 'NETWORK_INVALID_RESPONSE',
56
+
57
+ // Hot reload errors (HOT_RELOAD_*)
58
+ HOT_RELOAD_FAILED: 'HOT_RELOAD_FAILED',
59
+ HOT_RELOAD_STATE_ERROR: 'HOT_RELOAD_STATE_ERROR',
60
+ HOT_RELOAD_WATCH_ERROR: 'HOT_RELOAD_WATCH_ERROR',
61
+
62
+ // DAG errors (DAG_*)
63
+ DAG_CYCLE_DETECTED: 'DAG_CYCLE_DETECTED',
64
+ DAG_NODE_NOT_FOUND: 'DAG_NODE_NOT_FOUND',
65
+ DAG_EXECUTION_FAILED: 'DAG_EXECUTION_FAILED',
66
+ DAG_INVALID_TOPOLOGY: 'DAG_INVALID_TOPOLOGY',
67
+
68
+ // Authentication/Authorization errors (AUTH_*)
69
+ AUTH_INVALID_TOKEN: 'AUTH_INVALID_TOKEN',
70
+ AUTH_TOKEN_EXPIRED: 'AUTH_TOKEN_EXPIRED',
71
+ AUTH_INSUFFICIENT_PERMISSIONS: 'AUTH_INSUFFICIENT_PERMISSIONS',
72
+
73
+ // Generic errors
74
+ UNKNOWN_ERROR: 'UNKNOWN_ERROR',
75
+ };
76
+
77
+ /**
78
+ * Error message templates with suggestions
79
+ */
80
+ const ERROR_TEMPLATES = {
81
+ [ERROR_CODES.CONFIG_NOT_FOUND]: {
82
+ message: 'Configuration file not found at \'{path}\'',
83
+ suggestions: [
84
+ 'Create a .ragrc.json file in the project root',
85
+ 'Specify the config path using --config flag',
86
+ 'Run \'rag-pipeline init\' to create a default configuration',
87
+ ],
88
+ documentation: 'configuration.md#getting-started',
89
+ },
90
+
91
+ [ERROR_CODES.CONFIG_INVALID_JSON]: {
92
+ message: 'Invalid JSON in configuration file \'{path}\'',
93
+ suggestions: [
94
+ 'Validate JSON syntax using a JSON validator',
95
+ 'Check for missing commas, quotes, or brackets',
96
+ 'Use an IDE with JSON validation support',
97
+ 'Review the error details: {details}',
98
+ ],
99
+ documentation: 'configuration.md#json-format',
100
+ },
101
+
102
+ [ERROR_CODES.CONFIG_VALIDATION_FAILED]: {
103
+ message: 'Configuration validation failed: {reason}',
104
+ suggestions: [
105
+ 'Review the validation errors listed above',
106
+ 'Check the configuration schema documentation',
107
+ 'Ensure all required fields are present: {requiredFields}',
108
+ 'Validate configuration using: rag-pipeline validate',
109
+ ],
110
+ documentation: 'configuration.md#schema-validation',
111
+ },
112
+
113
+ [ERROR_CODES.CONFIG_MISSING_REQUIRED]: {
114
+ message: 'Missing required configuration field: \'{field}\'',
115
+ suggestions: [
116
+ 'Add the \'{field}\' field to your .ragrc.json',
117
+ 'Check the configuration examples in documentation',
118
+ 'Required type: {expectedType}',
119
+ ],
120
+ documentation: 'configuration.md#required-fields',
121
+ },
122
+
123
+ [ERROR_CODES.CONFIG_INVALID_TYPE]: {
124
+ message:
125
+ 'Invalid type for configuration field \'{field}\': expected {expected}, got {actual}',
126
+ suggestions: [
127
+ 'Change \'{field}\' to type {expected}',
128
+ 'Review the configuration schema for correct types',
129
+ 'Current value: {currentValue}',
130
+ ],
131
+ documentation: 'configuration.md#field-types',
132
+ },
133
+
134
+ [ERROR_CODES.PLUGIN_NOT_FOUND]: {
135
+ message: 'Plugin \'{plugin}\' not found',
136
+ suggestions: [
137
+ 'Check if the plugin is installed: npm list {plugin}',
138
+ 'Install the plugin: npm install {plugin}',
139
+ 'Verify the plugin path in configuration: {path}',
140
+ 'Check for typos in the plugin name',
141
+ ],
142
+ documentation: 'plugins.md#installation',
143
+ },
144
+
145
+ [ERROR_CODES.PLUGIN_LOAD_FAILED]: {
146
+ message: 'Failed to load plugin \'{plugin}\': {reason}',
147
+ suggestions: [
148
+ 'Check if the plugin file exists at: {path}',
149
+ 'Verify the plugin exports a valid module',
150
+ 'Install plugin dependencies: npm install',
151
+ 'Review the plugin error: {details}',
152
+ ],
153
+ documentation: 'plugins.md#troubleshooting',
154
+ },
155
+
156
+ [ERROR_CODES.PLUGIN_INVALID_EXPORT]: {
157
+ message: 'Plugin \'{plugin}\' does not export a valid structure',
158
+ suggestions: [
159
+ 'Ensure the plugin exports a class or function',
160
+ 'Check that required methods are implemented: {requiredMethods}',
161
+ 'Review plugin contract documentation',
162
+ 'Example: module.exports = class MyPlugin { execute() {} }',
163
+ ],
164
+ documentation: 'plugins.md#plugin-contract',
165
+ },
166
+
167
+ [ERROR_CODES.PLUGIN_EXECUTION_FAILED]: {
168
+ message: 'Plugin \'{plugin}\' execution failed: {reason}',
169
+ suggestions: [
170
+ 'Check plugin input data matches expected format',
171
+ 'Review plugin error logs above',
172
+ 'Verify plugin dependencies are installed',
173
+ 'Try running plugin in isolation for debugging',
174
+ 'Input received: {input}',
175
+ ],
176
+ documentation: 'plugins.md#debugging',
177
+ },
178
+
179
+ [ERROR_CODES.PLUGIN_CONTRACT_VIOLATION]: {
180
+ message: 'Plugin \'{plugin}\' violates contract: {violation}',
181
+ suggestions: [
182
+ 'Implement required method: {missingMethod}',
183
+ 'Return expected type: {expectedType}',
184
+ 'Review plugin contract documentation',
185
+ 'Check plugin certification requirements',
186
+ ],
187
+ documentation: 'plugins.md#contract-requirements',
188
+ },
189
+
190
+ [ERROR_CODES.PLUGIN_DEPENDENCY_MISSING]: {
191
+ message: 'Plugin \'{plugin}\' missing dependency: {dependency}',
192
+ suggestions: [
193
+ 'Install missing dependency: npm install {dependency}',
194
+ 'Check plugin\'s package.json for required dependencies',
195
+ 'Verify dependency version compatibility: {requiredVersion}',
196
+ ],
197
+ documentation: 'plugins.md#dependencies',
198
+ },
199
+
200
+ [ERROR_CODES.PIPELINE_CREATION_FAILED]: {
201
+ message: 'Failed to create pipeline: {reason}',
202
+ suggestions: [
203
+ 'Verify configuration is valid: rag-pipeline validate',
204
+ 'Check all plugins are installed and accessible',
205
+ 'Review pipeline stages configuration',
206
+ 'Ensure all required stages are defined: {requiredStages}',
207
+ ],
208
+ documentation: 'pipeline.md#creation',
209
+ },
210
+
211
+ [ERROR_CODES.PIPELINE_EXECUTION_FAILED]: {
212
+ message: 'Pipeline execution failed at stage \'{stage}\': {reason}',
213
+ suggestions: [
214
+ 'Check input data format for stage \'{stage}\'',
215
+ 'Review plugin configuration for this stage',
216
+ 'Enable verbose logging: pipeline.execute({ verbose: true })',
217
+ 'Check previous stage outputs',
218
+ ],
219
+ documentation: 'pipeline.md#execution-errors',
220
+ },
221
+
222
+ [ERROR_CODES.PIPELINE_STAGE_FAILED]: {
223
+ message: 'Stage \'{stage}\' failed: {reason}',
224
+ suggestions: [
225
+ 'Verify stage configuration is correct',
226
+ 'Check stage dependencies are met',
227
+ 'Review stage plugin logs',
228
+ 'Input data: {input}',
229
+ ],
230
+ documentation: 'pipeline.md#stage-configuration',
231
+ },
232
+
233
+ [ERROR_CODES.FS_FILE_NOT_FOUND]: {
234
+ message: 'File not found: {path}',
235
+ suggestions: [
236
+ 'Verify the file path is correct: {path}',
237
+ 'Check file permissions and access rights',
238
+ 'Ensure the file has not been moved or deleted',
239
+ 'Use absolute path instead of relative path',
240
+ ],
241
+ documentation: 'troubleshooting.md#file-errors',
242
+ },
243
+
244
+ [ERROR_CODES.FS_DIRECTORY_NOT_FOUND]: {
245
+ message: 'Directory not found: {path}',
246
+ suggestions: [
247
+ 'Create the directory: mkdir -p {path}',
248
+ 'Verify the directory path is correct',
249
+ 'Check parent directory exists and is accessible',
250
+ ],
251
+ documentation: 'troubleshooting.md#file-errors',
252
+ },
253
+
254
+ [ERROR_CODES.FS_PERMISSION_DENIED]: {
255
+ message: 'Permission denied accessing: {path}',
256
+ suggestions: [
257
+ 'Check file/directory permissions: ls -la {path}',
258
+ 'Ensure your user has read/write access',
259
+ 'Try running with appropriate permissions',
260
+ 'Contact system administrator if needed',
261
+ ],
262
+ documentation: 'troubleshooting.md#permission-errors',
263
+ },
264
+
265
+ [ERROR_CODES.HOT_RELOAD_FAILED]: {
266
+ message: 'Hot reload failed for \'{path}\': {reason}',
267
+ suggestions: [
268
+ 'Check for syntax errors in the modified file',
269
+ 'Ensure the file is within watched paths: {watchPaths}',
270
+ 'Try manual reload: hotReload.triggerReload(\'{path}\')',
271
+ 'Review error details above',
272
+ ],
273
+ documentation: 'hot-reload.md#troubleshooting',
274
+ },
275
+
276
+ [ERROR_CODES.HOT_RELOAD_STATE_ERROR]: {
277
+ message: 'Failed to preserve/restore state during reload: {reason}',
278
+ suggestions: [
279
+ 'Check that state is serializable (no functions, circular refs)',
280
+ 'Implement getState/setState methods in your plugin',
281
+ 'Disable state preservation if not needed: preserveState: false',
282
+ 'Review state preservation documentation',
283
+ ],
284
+ documentation: 'hot-reload.md#state-preservation',
285
+ },
286
+
287
+ [ERROR_CODES.DAG_CYCLE_DETECTED]: {
288
+ message: 'Cycle detected in DAG: {cycle}',
289
+ suggestions: [
290
+ 'Review the dependency chain: {cycle}',
291
+ 'Remove circular dependencies between nodes',
292
+ 'Ensure all edges form a directed acyclic graph',
293
+ 'Use topological sort to verify order',
294
+ ],
295
+ documentation: 'dag.md#cycles',
296
+ },
297
+
298
+ [ERROR_CODES.DAG_NODE_NOT_FOUND]: {
299
+ message: 'DAG node \'{node}\' not found',
300
+ suggestions: [
301
+ 'Check node ID is correct: {node}',
302
+ 'Verify node was added to DAG before execution',
303
+ 'List all nodes: dag.getNodes()',
304
+ 'Available nodes: {availableNodes}',
305
+ ],
306
+ documentation: 'dag.md#nodes',
307
+ },
308
+
309
+ [ERROR_CODES.VALIDATION_FAILED]: {
310
+ message: 'Validation failed: {reason}',
311
+ suggestions: [
312
+ 'Review validation errors: {errors}',
313
+ 'Check input data against schema',
314
+ 'Use validation tools to verify format',
315
+ ],
316
+ documentation: 'validation.md',
317
+ },
318
+
319
+ [ERROR_CODES.AUTH_INVALID_TOKEN]: {
320
+ message: 'Invalid authentication token',
321
+ suggestions: [
322
+ 'Check token format and signature',
323
+ 'Verify token hasn\'t been tampered with',
324
+ 'Ensure token is properly encoded',
325
+ 'Generate new token if needed',
326
+ ],
327
+ documentation: 'security.md#authentication',
328
+ },
329
+
330
+ [ERROR_CODES.AUTH_TOKEN_EXPIRED]: {
331
+ message: 'Authentication token expired at {expiredAt}',
332
+ suggestions: [
333
+ 'Generate a new authentication token',
334
+ 'Increase token expiration time in configuration',
335
+ 'Implement token refresh mechanism',
336
+ 'Check system clock is synchronized',
337
+ ],
338
+ documentation: 'security.md#token-expiration',
339
+ },
340
+
341
+ [ERROR_CODES.UNKNOWN_ERROR]: {
342
+ message: 'An unexpected error occurred: {reason}',
343
+ suggestions: [
344
+ 'Check application logs for more details',
345
+ 'Enable verbose logging for debugging',
346
+ 'Report this issue if it persists',
347
+ 'Include error details in bug report',
348
+ ],
349
+ documentation: 'troubleshooting.md',
350
+ },
351
+ };
352
+
353
+ /**
354
+ * Enhanced Error class with code and context
355
+ */
356
+ class EnhancedError extends Error {
357
+ constructor(code, context = {}, originalError = null) {
358
+ const formattedMessage = formatError(code, context);
359
+ super(formattedMessage.message);
360
+
361
+ this.name = 'EnhancedError';
362
+ this.code = code;
363
+ this.context = context;
364
+ this.suggestions = formattedMessage.suggestions;
365
+ this.documentation = formattedMessage.documentation;
366
+ this.originalError = originalError;
367
+ this.timestamp = new Date().toISOString();
368
+
369
+ // Capture stack trace
370
+ if (Error.captureStackTrace) {
371
+ Error.captureStackTrace(this, EnhancedError);
372
+ }
373
+ }
374
+
375
+ /**
376
+ * Get formatted error message with all details
377
+ */
378
+ getFormattedMessage() {
379
+ return formatErrorMessage(this);
380
+ }
381
+
382
+ /**
383
+ * Convert to JSON for logging
384
+ */
385
+ toJSON() {
386
+ return {
387
+ name: this.name,
388
+ code: this.code,
389
+ message: this.message,
390
+ suggestions: this.suggestions,
391
+ documentation: this.documentation,
392
+ context: this.context,
393
+ timestamp: this.timestamp,
394
+ stack: this.stack,
395
+ originalError: this.originalError
396
+ ? {
397
+ message: this.originalError.message,
398
+ stack: this.originalError.stack,
399
+ }
400
+ : null,
401
+ };
402
+ }
403
+ }
404
+
405
+ /**
406
+ * Format an error message with context
407
+ *
408
+ * @param {string} code - Error code
409
+ * @param {object} context - Context variables
410
+ * @returns {object} Formatted error details
411
+ */
412
+ function formatError(code, context = {}) {
413
+ const template =
414
+ ERROR_TEMPLATES[code] || ERROR_TEMPLATES[ERROR_CODES.UNKNOWN_ERROR];
415
+
416
+ // Replace placeholders in message
417
+ let message = template.message;
418
+ for (const [key, value] of Object.entries(context)) {
419
+ message = message.replace(`{${key}}`, String(value));
420
+ }
421
+
422
+ // Replace placeholders in suggestions
423
+ const suggestions = template.suggestions.map((suggestion) => {
424
+ let formatted = suggestion;
425
+ for (const [key, value] of Object.entries(context)) {
426
+ formatted = formatted.replace(`{${key}}`, String(value));
427
+ }
428
+ return formatted;
429
+ });
430
+
431
+ return {
432
+ code,
433
+ message,
434
+ suggestions,
435
+ documentation: template.documentation,
436
+ context,
437
+ };
438
+ }
439
+
440
+ /**
441
+ * Format error message for display
442
+ *
443
+ * @param {Error|EnhancedError} error - Error to format
444
+ * @param {object} options - Formatting options
445
+ * @returns {string} Formatted error message
446
+ */
447
+ function formatErrorMessage(error, options = {}) {
448
+ const {
449
+ includeCode = true,
450
+ includeSuggestions = true,
451
+ includeDocumentation = true,
452
+ includeContext = false,
453
+ includeStack = false,
454
+ color = false,
455
+ } = options;
456
+
457
+ let output = [];
458
+
459
+ // Error header
460
+ if (includeCode && error.code) {
461
+ output.push(`Error [${error.code}]: ${error.message}`);
462
+ } else {
463
+ output.push(`Error: ${error.message}`);
464
+ }
465
+
466
+ // Context (optional)
467
+ if (
468
+ includeContext &&
469
+ error.context &&
470
+ Object.keys(error.context).length > 0
471
+ ) {
472
+ output.push('\nContext:');
473
+ for (const [key, value] of Object.entries(error.context)) {
474
+ output.push(` ${key}: ${JSON.stringify(value)}`);
475
+ }
476
+ }
477
+
478
+ // Suggestions
479
+ if (includeSuggestions && error.suggestions && error.suggestions.length > 0) {
480
+ output.push('\nSuggestions:');
481
+ error.suggestions.forEach((suggestion, index) => {
482
+ output.push(` ${index + 1}. ${suggestion}`);
483
+ });
484
+ }
485
+
486
+ // Documentation link
487
+ if (includeDocumentation && error.documentation) {
488
+ output.push(
489
+ `\nDocumentation: https://docs.rag-pipeline-utils.dev/${error.documentation}`,
490
+ );
491
+ }
492
+
493
+ // Stack trace (optional)
494
+ if (includeStack && error.stack) {
495
+ output.push('\nStack Trace:');
496
+ output.push(error.stack);
497
+ }
498
+
499
+ return output.join('\n');
500
+ }
501
+
502
+ /**
503
+ * Create an enhanced error
504
+ *
505
+ * @param {string} code - Error code
506
+ * @param {object} context - Context variables
507
+ * @param {Error} originalError - Original error (optional)
508
+ * @returns {EnhancedError} Enhanced error instance
509
+ */
510
+ function createError(code, context = {}, originalError = null) {
511
+ return new EnhancedError(code, context, originalError);
512
+ }
513
+
514
+ /**
515
+ * Wrap an existing error with enhanced context
516
+ *
517
+ * @param {Error} error - Original error
518
+ * @param {string} code - Error code
519
+ * @param {object} context - Additional context
520
+ * @returns {EnhancedError} Enhanced error
521
+ */
522
+ function wrapError(error, code, context = {}) {
523
+ return new EnhancedError(
524
+ code,
525
+ {
526
+ ...context,
527
+ originalMessage: error.message,
528
+ },
529
+ error,
530
+ );
531
+ }
532
+
533
+ /**
534
+ * Check if an error is an EnhancedError
535
+ *
536
+ * @param {*} error - Value to check
537
+ * @returns {boolean} True if enhanced error
538
+ */
539
+ function isEnhancedError(error) {
540
+ return error instanceof EnhancedError;
541
+ }
542
+
543
+ /**
544
+ * Get error severity level
545
+ *
546
+ * @param {string} code - Error code
547
+ * @returns {string} Severity level (critical, error, warning)
548
+ */
549
+ function getErrorSeverity(code) {
550
+ const critical = [
551
+ ERROR_CODES.PIPELINE_CREATION_FAILED,
552
+ ERROR_CODES.CONFIG_NOT_FOUND,
553
+ ERROR_CODES.FS_PERMISSION_DENIED,
554
+ ERROR_CODES.AUTH_INVALID_TOKEN,
555
+ ];
556
+
557
+ const warnings = [
558
+ ERROR_CODES.HOT_RELOAD_FAILED,
559
+ ERROR_CODES.HOT_RELOAD_STATE_ERROR,
560
+ ];
561
+
562
+ if (critical.includes(code)) return 'critical';
563
+ if (warnings.includes(code)) return 'warning';
564
+ return 'error';
565
+ }
566
+
567
+ /**
568
+ * Log error with appropriate formatting
569
+ *
570
+ * @param {Error|EnhancedError} error - Error to log
571
+ * @param {object} logger - Logger instance (optional)
572
+ */
573
+ function logError(error, logger = console) {
574
+ const severity = isEnhancedError(error)
575
+ ? getErrorSeverity(error.code)
576
+ : 'error';
577
+ const formatted = formatErrorMessage(error, {
578
+ includeSuggestions: true,
579
+ includeDocumentation: true,
580
+ includeStack: severity === 'critical',
581
+ });
582
+
583
+ if (severity === 'critical') {
584
+ logger.error(formatted);
585
+ } else if (severity === 'warning') {
586
+ logger.warn(formatted);
587
+ } else {
588
+ logger.error(formatted);
589
+ }
590
+ }
591
+
592
+ module.exports = {
593
+ ERROR_CODES,
594
+ ERROR_TEMPLATES,
595
+ EnhancedError,
596
+ createError,
597
+ wrapError,
598
+ formatError,
599
+ formatErrorMessage,
600
+ isEnhancedError,
601
+ getErrorSeverity,
602
+ logError,
603
+ };