@devilsdev/rag-pipeline-utils 2.2.1 → 2.3.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.
- package/README.md +244 -11
- package/contracts/contract-schema.json +189 -0
- package/dist/index.cjs +19 -0
- package/dist/index.mjs +15 -1
- package/package.json +3 -2
- package/src/cli/commands/wizard.js +627 -0
- package/src/cli/input-sanitization-middleware.js +356 -0
- package/src/cli/templates/development.template.json +64 -0
- package/src/cli/templates/minimal.template.json +33 -0
- package/src/cli/templates/production.template.json +104 -0
- package/src/cli/templates/testing.template.json +45 -0
- package/src/config/connection-pool-config.json +259 -0
- package/src/config/memory-optimization.js +414 -0
- package/src/config/redaction-patterns.json +150 -0
- package/src/config/sanitization-rules.json +323 -0
- package/src/core/plugin-registry.js +266 -20
- package/src/dag/core/error-context.js +391 -0
- package/src/dag/core/execution-scheduler.js +350 -0
- package/src/dag/core/topology-validation.js +415 -0
- package/src/dag/dag-engine.js +26 -424
- package/src/dev/README.md +126 -0
- package/src/dev/dev-server.js +356 -0
- package/src/dev/examples/hot-reload-usage.js +355 -0
- package/src/dev/hot-reload.js +807 -0
- package/src/enterprise/sso-integration.js +67 -25
- package/src/index.js +19 -0
- package/src/observability/event-logger.js +62 -2
- package/src/plugins/optimized-openai-embedder.js +169 -0
- package/src/security/jwt-config.js +431 -0
- package/src/security/jwt-validator.js +701 -0
- package/src/utils/api-client-pool-integration.js +436 -0
- package/src/utils/batch-processor.js +710 -0
- package/src/utils/connection-pool.js +605 -0
- package/src/utils/contract-validator.js +460 -0
- package/src/utils/error-formatter.js +603 -0
- package/src/utils/examples/error-formatter-usage.js +351 -0
- package/src/utils/input-sanitizer.js +967 -0
- package/src/utils/memory-monitor.js +800 -0
- package/src/utils/secure-logger-config.js +352 -0
- 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
|
+
};
|