@devilsdev/rag-pipeline-utils 2.1.11 → 2.2.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 (110) hide show
  1. package/.ragrc.schema.json +218 -0
  2. package/README.md +651 -393
  3. package/bin/cli.js +8 -14
  4. package/dist/index.d.ts +237 -0
  5. package/dist/index.mjs +22 -7
  6. package/package.json +17 -13
  7. package/src/ai/adaptive-retrieval.js +191 -0
  8. package/src/ai/federated-learning.js +214 -0
  9. package/src/ai/federation/federated-learning-coordinator.js +345 -0
  10. package/src/ai/federation.js +76 -0
  11. package/src/ai/index-fixed.js +509 -0
  12. package/src/ai/index.js +33 -0
  13. package/src/ai/model-trainer.js +217 -0
  14. package/src/ai/model-training.js +205 -0
  15. package/src/ai/module-template.js +37 -0
  16. package/src/ai/multimodal/multi-modal-processor.js +345 -0
  17. package/src/ai/multimodal-processing.js +268 -0
  18. package/src/ai/multimodal.js +71 -0
  19. package/src/ai/orchestrator.js +70 -0
  20. package/src/ai/retrieval/adaptive-retrieval-engine.js +398 -0
  21. package/src/ai/retrieval-engine.js +69 -0
  22. package/src/ai/training/model-training-orchestrator.js +228 -0
  23. package/src/ci/workflow-analyzer.js +71 -0
  24. package/src/cli/commands/ai-ml.js +967 -0
  25. package/src/cli/commands/docs.js +228 -0
  26. package/src/cli/commands/dx.js +538 -0
  27. package/src/cli/commands/plugin-hub.js +875 -0
  28. package/src/cli/doctor-command.js +639 -0
  29. package/src/cli/enhanced-cli-commands.js +945 -0
  30. package/src/cli/interactive-wizard.js +997 -0
  31. package/src/cli/plugin-marketplace-commands.js +869 -0
  32. package/src/cli.js +17 -0
  33. package/src/config/enhanced-ragrc-schema.js +632 -0
  34. package/src/config/load-config.js +54 -0
  35. package/src/config/load-plugin-config.js +69 -0
  36. package/src/config/normalize-config.js +105 -0
  37. package/src/config/schema-validator.js +315 -0
  38. package/src/config/validate-plugin-schema.js +35 -0
  39. package/src/config/validate-schema.js +113 -0
  40. package/src/contracts/plugin-contracts.js +33 -0
  41. package/src/core/create-pipeline.js +99 -0
  42. package/src/core/dependency-injection.js +242 -0
  43. package/src/core/observability/event-logger.js +241 -0
  44. package/src/core/observability/instrumented-pipeline.js +609 -0
  45. package/src/core/observability/metrics.js +497 -0
  46. package/src/core/observability/tracing.js +781 -0
  47. package/src/core/performance/benchmark.js +516 -0
  48. package/src/core/performance/parallel-processor.js +240 -0
  49. package/src/core/performance/streaming-safeguards.js +611 -0
  50. package/src/core/pipeline-factory.js +60 -0
  51. package/src/core/plugin-contracts.js +89 -0
  52. package/src/core/plugin-marketplace/plugin-metadata.js +485 -0
  53. package/src/core/plugin-marketplace/plugin-publisher.js +574 -0
  54. package/src/core/plugin-marketplace/plugin-registry-format.js +419 -0
  55. package/src/core/plugin-marketplace/version-resolver.js +61 -0
  56. package/src/core/plugin-registry.js +265 -0
  57. package/src/dag/dag-engine.js +954 -0
  58. package/src/dag/dag-node.js +76 -0
  59. package/src/dag/enhanced-dag-engine.js +822 -0
  60. package/src/dx/index.js +40 -0
  61. package/src/dx/integration-templates.js +665 -0
  62. package/src/dx/performance-profiler.js +968 -0
  63. package/src/dx/realtime-debugger.js +755 -0
  64. package/src/dx/visual-pipeline-builder.js +578 -0
  65. package/src/ecosystem/plugin-analytics-dashboard.js +778 -0
  66. package/src/ecosystem/plugin-certification.js +580 -0
  67. package/src/ecosystem/plugin-hub.js +821 -0
  68. package/src/enterprise/audit-logging.js +967 -0
  69. package/src/enterprise/data-governance.js +408 -0
  70. package/src/enterprise/multi-tenancy.js +496 -0
  71. package/src/enterprise/sso-integration.js +903 -0
  72. package/src/evaluate/evaluator.js +52 -0
  73. package/src/evaluate/scoring.js +91 -0
  74. package/src/index.js +67 -0
  75. package/src/ingest.js +59 -0
  76. package/src/loader/csv-loader.js +38 -0
  77. package/src/loader/directory-loader.js +48 -0
  78. package/src/loader/html-loader.js +62 -0
  79. package/src/loader/markdown-loader.js +67 -0
  80. package/src/mocks/openai-embedder.js +119 -0
  81. package/src/mocks/openai-llm.js +77 -0
  82. package/src/mocks/pdf-loader.js +21 -0
  83. package/src/mocks/pinecone-retriever.js +106 -0
  84. package/src/observability/audit-logger.js +758 -0
  85. package/src/observability/dashboard-config.json +675 -0
  86. package/src/observability/event-logger.js +310 -0
  87. package/src/observability/metrics.js +691 -0
  88. package/src/observability/security-monitor.js +830 -0
  89. package/src/observability/slo-monitor.js +319 -0
  90. package/src/observability/telemetry.js +686 -0
  91. package/src/pipeline/pipeline.js +18 -0
  92. package/src/plugins/sample-embedder.js +53 -0
  93. package/src/plugins/sample-llm.js +30 -0
  94. package/src/plugins/sample-loader.js +24 -0
  95. package/src/plugins/sample-retriever.js +84 -0
  96. package/src/query.js +117 -0
  97. package/src/reranker/llm-reranker.js +85 -0
  98. package/src/scripts/script-utilities.js +36 -0
  99. package/src/security/plugin-sandbox.js +586 -0
  100. package/src/security/plugin-signature-verifier.js +414 -0
  101. package/src/security/validator.js +36 -0
  102. package/src/utils/ci/diagnostic-reporter.js +57 -0
  103. package/src/utils/logger.js +211 -0
  104. package/src/utils/performance-monitor.js +561 -0
  105. package/src/utils/plugin-scaffolder.js +447 -0
  106. package/src/utils/retry-policy.js +443 -0
  107. package/src/utils/retry.js +107 -0
  108. package/src/utils/safe-expression-evaluator.js +579 -0
  109. package/src/utils/structured-logger.js +361 -0
  110. package/src/utils/validate-plugin-contract.js +42 -0
@@ -0,0 +1,579 @@
1
+ /**
2
+ * @fileoverview Safe Expression Evaluator
3
+ * Safely evaluates simple expressions without allowing arbitrary code execution
4
+ * Replaces dangerous eval() and Function() usage with a restricted parser
5
+ *
6
+ * @author DevilsDev Team
7
+ * @since 2.1.8
8
+ */
9
+
10
+ /**
11
+ * Safe expression evaluator for debugging conditions
12
+ * Only allows simple property access, comparisons, and basic operations
13
+ */
14
+ class SafeExpressionEvaluator {
15
+ constructor(options = {}) {
16
+ // Dynamic production check
17
+ const productionEnabled = process.env.NODE_ENV !== 'production';
18
+ this.enabled = options.enabled !== false && productionEnabled;
19
+ this.maxDepth = options.maxDepth || 5;
20
+ this.maxExpression = options.maxExpression || 200;
21
+
22
+ // Allowed operators for expressions
23
+ this.allowedOperators = new Set([
24
+ '==',
25
+ '===',
26
+ '!=',
27
+ '!==',
28
+ '<',
29
+ '>',
30
+ '<=',
31
+ '>=',
32
+ '&&',
33
+ '||',
34
+ '!',
35
+ '+',
36
+ '-',
37
+ '*',
38
+ '/',
39
+ '%',
40
+ ]);
41
+
42
+ // Allowed property access patterns
43
+ this.allowedPropertyPattern = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
44
+
45
+ // Dangerous identifiers that should never be accessible
46
+ this.blockedIdentifiers = new Set([
47
+ 'globalThis',
48
+ 'global',
49
+ 'process',
50
+ 'require',
51
+ 'module',
52
+ 'console',
53
+ 'eval',
54
+ 'Function',
55
+ 'window',
56
+ 'document',
57
+ ]);
58
+ }
59
+
60
+ /**
61
+ * Evaluate a safe expression
62
+ * @param {string} expression - Expression to evaluate
63
+ * @param {object} context - Safe context object
64
+ * @returns {any} Evaluation result
65
+ */
66
+ evaluate(expression, context = {}) {
67
+ if (!this.enabled) {
68
+ throw new Error('Safe evaluator is disabled in production for security');
69
+ }
70
+
71
+ if (typeof expression !== 'string') {
72
+ throw new Error('Expression must be a string');
73
+ }
74
+
75
+ if (expression.length > this.maxExpression) {
76
+ throw new Error('Expression too long');
77
+ }
78
+
79
+ // Parse and validate the expression
80
+ const tokens = this.tokenize(expression);
81
+ const ast = this.parse(tokens);
82
+
83
+ return this.evaluateNode(ast, context);
84
+ }
85
+
86
+ /**
87
+ * Tokenize expression into safe tokens
88
+ * @param {string} expression - Expression to tokenize
89
+ * @returns {Array} Array of tokens
90
+ */
91
+ tokenize(expression) {
92
+ const tokens = [];
93
+ let i = 0;
94
+
95
+ while (i < expression.length) {
96
+ const char = expression[i];
97
+
98
+ // Skip whitespace
99
+ if (/\s/.test(char)) {
100
+ i++;
101
+ continue;
102
+ }
103
+
104
+ // Numbers
105
+ if (/\d/.test(char)) {
106
+ let number = '';
107
+ while (i < expression.length && /[\d.]/.test(expression[i])) {
108
+ number += expression[i];
109
+ i++;
110
+ }
111
+ tokens.push({ type: 'NUMBER', value: parseFloat(number) });
112
+ continue;
113
+ }
114
+
115
+ // Identifiers and property access
116
+ if (/[a-zA-Z_$]/.test(char)) {
117
+ let identifier = '';
118
+ while (i < expression.length && /[a-zA-Z0-9_$]/.test(expression[i])) {
119
+ identifier += expression[i];
120
+ i++;
121
+ }
122
+
123
+ // Check for boolean literals
124
+ if (identifier === 'true') {
125
+ tokens.push({ type: 'BOOLEAN', value: true });
126
+ } else if (identifier === 'false') {
127
+ tokens.push({ type: 'BOOLEAN', value: false });
128
+ } else if (identifier === 'null') {
129
+ tokens.push({ type: 'NULL', value: null });
130
+ } else if (identifier === 'undefined') {
131
+ tokens.push({ type: 'UNDEFINED', value: undefined });
132
+ } else {
133
+ tokens.push({ type: 'IDENTIFIER', value: identifier });
134
+ }
135
+ continue;
136
+ }
137
+
138
+ // String literals
139
+ if (char === '"' || char === '\'') {
140
+ const quote = char;
141
+ let string = '';
142
+ i++; // Skip opening quote
143
+
144
+ while (i < expression.length && expression[i] !== quote) {
145
+ if (expression[i] === '\\' && i + 1 < expression.length) {
146
+ // Handle escape sequences
147
+ const nextChar = expression[i + 1];
148
+ if (nextChar === quote || nextChar === '\\') {
149
+ string += nextChar;
150
+ i += 2;
151
+ } else {
152
+ string += expression[i];
153
+ i++;
154
+ }
155
+ } else {
156
+ string += expression[i];
157
+ i++;
158
+ }
159
+ }
160
+
161
+ if (i >= expression.length) {
162
+ throw new Error('Unterminated string literal');
163
+ }
164
+
165
+ i++; // Skip closing quote
166
+ tokens.push({ type: 'STRING', value: string });
167
+ continue;
168
+ }
169
+
170
+ // Operators
171
+ if (char === '=' && expression[i + 1] === '=') {
172
+ if (expression[i + 2] === '=') {
173
+ tokens.push({ type: 'OPERATOR', value: '===' });
174
+ i += 3;
175
+ } else {
176
+ tokens.push({ type: 'OPERATOR', value: '==' });
177
+ i += 2;
178
+ }
179
+ continue;
180
+ }
181
+
182
+ if (char === '!' && expression[i + 1] === '=') {
183
+ if (expression[i + 2] === '=') {
184
+ tokens.push({ type: 'OPERATOR', value: '!==' });
185
+ i += 3;
186
+ } else {
187
+ tokens.push({ type: 'OPERATOR', value: '!=' });
188
+ i += 2;
189
+ }
190
+ continue;
191
+ }
192
+
193
+ if (char === '<' || char === '>') {
194
+ if (expression[i + 1] === '=') {
195
+ tokens.push({ type: 'OPERATOR', value: char + '=' });
196
+ i += 2;
197
+ } else {
198
+ tokens.push({ type: 'OPERATOR', value: char });
199
+ i++;
200
+ }
201
+ continue;
202
+ }
203
+
204
+ if (char === '&' && expression[i + 1] === '&') {
205
+ tokens.push({ type: 'OPERATOR', value: '&&' });
206
+ i += 2;
207
+ continue;
208
+ }
209
+
210
+ if (char === '|' && expression[i + 1] === '|') {
211
+ tokens.push({ type: 'OPERATOR', value: '||' });
212
+ i += 2;
213
+ continue;
214
+ }
215
+
216
+ // Single character operators and punctuation
217
+ if ('!+-*/%().'.includes(char)) {
218
+ if (char === '.') {
219
+ tokens.push({ type: 'DOT', value: '.' });
220
+ } else if (char === '(' || char === ')') {
221
+ tokens.push({ type: 'PAREN', value: char });
222
+ } else {
223
+ tokens.push({ type: 'OPERATOR', value: char });
224
+ }
225
+ i++;
226
+ continue;
227
+ }
228
+
229
+ throw new Error(`Unexpected character: ${char}`);
230
+ }
231
+
232
+ return tokens;
233
+ }
234
+
235
+ /**
236
+ * Parse tokens into AST
237
+ * @param {Array} tokens - Tokens to parse
238
+ * @returns {object} AST node
239
+ */
240
+ parse(tokens) {
241
+ let index = 0;
242
+
243
+ const parseExpression = () => {
244
+ return parseLogicalOr();
245
+ };
246
+
247
+ const parseLogicalOr = () => {
248
+ let left = parseLogicalAnd();
249
+
250
+ while (index < tokens.length && tokens[index].value === '||') {
251
+ const operator = tokens[index].value;
252
+ index++;
253
+ const right = parseLogicalAnd();
254
+ left = { type: 'BinaryExpression', operator, left, right };
255
+ }
256
+
257
+ return left;
258
+ };
259
+
260
+ const parseLogicalAnd = () => {
261
+ let left = parseEquality();
262
+
263
+ while (index < tokens.length && tokens[index].value === '&&') {
264
+ const operator = tokens[index].value;
265
+ index++;
266
+ const right = parseEquality();
267
+ left = { type: 'BinaryExpression', operator, left, right };
268
+ }
269
+
270
+ return left;
271
+ };
272
+
273
+ const parseEquality = () => {
274
+ let left = parseComparison();
275
+
276
+ while (
277
+ index < tokens.length &&
278
+ ['==', '===', '!=', '!=='].includes(tokens[index].value)
279
+ ) {
280
+ const operator = tokens[index].value;
281
+ index++;
282
+ const right = parseComparison();
283
+ left = { type: 'BinaryExpression', operator, left, right };
284
+ }
285
+
286
+ return left;
287
+ };
288
+
289
+ const parseComparison = () => {
290
+ let left = parseAdditive();
291
+
292
+ while (
293
+ index < tokens.length &&
294
+ ['<', '>', '<=', '>='].includes(tokens[index].value)
295
+ ) {
296
+ const operator = tokens[index].value;
297
+ index++;
298
+ const right = parseAdditive();
299
+ left = { type: 'BinaryExpression', operator, left, right };
300
+ }
301
+
302
+ return left;
303
+ };
304
+
305
+ const parseAdditive = () => {
306
+ let left = parseMultiplicative();
307
+
308
+ while (
309
+ index < tokens.length &&
310
+ ['+', '-'].includes(tokens[index].value)
311
+ ) {
312
+ const operator = tokens[index].value;
313
+ index++;
314
+ const right = parseMultiplicative();
315
+ left = { type: 'BinaryExpression', operator, left, right };
316
+ }
317
+
318
+ return left;
319
+ };
320
+
321
+ const parseMultiplicative = () => {
322
+ let left = parseUnary();
323
+
324
+ while (
325
+ index < tokens.length &&
326
+ ['*', '/', '%'].includes(tokens[index].value)
327
+ ) {
328
+ const operator = tokens[index].value;
329
+ index++;
330
+ const right = parseUnary();
331
+ left = { type: 'BinaryExpression', operator, left, right };
332
+ }
333
+
334
+ return left;
335
+ };
336
+
337
+ const parseUnary = () => {
338
+ if (index < tokens.length && tokens[index].value === '!') {
339
+ const operator = tokens[index].value;
340
+ index++;
341
+ const argument = parseUnary();
342
+ return { type: 'UnaryExpression', operator, argument };
343
+ }
344
+
345
+ return parseMemberAccess();
346
+ };
347
+
348
+ const parseMemberAccess = () => {
349
+ let object = parsePrimary();
350
+
351
+ while (index < tokens.length && tokens[index].type === 'DOT') {
352
+ index++; // Skip dot
353
+ if (index >= tokens.length || tokens[index].type !== 'IDENTIFIER') {
354
+ throw new Error('Expected property name after dot');
355
+ }
356
+ const property = tokens[index].value;
357
+ index++;
358
+ object = { type: 'MemberExpression', object, property };
359
+ }
360
+
361
+ return object;
362
+ };
363
+
364
+ const parsePrimary = () => {
365
+ if (index >= tokens.length) {
366
+ throw new Error('Unexpected end of expression');
367
+ }
368
+
369
+ const token = tokens[index];
370
+
371
+ if (token.type === 'NUMBER') {
372
+ index++;
373
+ return { type: 'Literal', value: token.value };
374
+ }
375
+
376
+ if (token.type === 'STRING') {
377
+ index++;
378
+ return { type: 'Literal', value: token.value };
379
+ }
380
+
381
+ if (token.type === 'BOOLEAN') {
382
+ index++;
383
+ return { type: 'Literal', value: token.value };
384
+ }
385
+
386
+ if (token.type === 'NULL') {
387
+ index++;
388
+ return { type: 'Literal', value: null };
389
+ }
390
+
391
+ if (token.type === 'UNDEFINED') {
392
+ index++;
393
+ return { type: 'Literal', value: undefined };
394
+ }
395
+
396
+ if (token.type === 'IDENTIFIER') {
397
+ index++;
398
+ return { type: 'Identifier', name: token.value };
399
+ }
400
+
401
+ if (token.type === 'PAREN' && token.value === '(') {
402
+ index++; // Skip opening paren
403
+ const expr = parseExpression();
404
+ if (index >= tokens.length || tokens[index].value !== ')') {
405
+ throw new Error('Expected closing parenthesis');
406
+ }
407
+ index++; // Skip closing paren
408
+ return expr;
409
+ }
410
+
411
+ throw new Error(`Unexpected token: ${token.value}`);
412
+ };
413
+
414
+ const ast = parseExpression();
415
+
416
+ if (index < tokens.length) {
417
+ throw new Error(
418
+ `Unexpected token after expression: ${tokens[index].value}`,
419
+ );
420
+ }
421
+
422
+ return ast;
423
+ }
424
+
425
+ /**
426
+ * Evaluate AST node
427
+ * @param {object} node - AST node
428
+ * @param {object} context - Evaluation context
429
+ * @param {number} depth - Current recursion depth
430
+ * @returns {any} Evaluation result
431
+ */
432
+ evaluateNode(node, context, depth = 0) {
433
+ if (depth > this.maxDepth) {
434
+ throw new Error('Expression too complex');
435
+ }
436
+
437
+ switch (node.type) {
438
+ case 'Literal':
439
+ return node.value;
440
+
441
+ case 'Identifier':
442
+ // Block dangerous identifiers
443
+ if (this.blockedIdentifiers.has(node.name)) {
444
+ return undefined;
445
+ }
446
+ if (!Object.prototype.hasOwnProperty.call(context, node.name)) {
447
+ return undefined;
448
+ }
449
+ return context[node.name];
450
+
451
+ case 'MemberExpression': {
452
+ const object = this.evaluateNode(node.object, context, depth + 1);
453
+ if (object == null) {
454
+ return undefined;
455
+ }
456
+
457
+ // Allow specific properties on arrays
458
+ if (Array.isArray(object)) {
459
+ if (node.property === 'length') {
460
+ return object.length;
461
+ }
462
+ if (node.property === 'first') {
463
+ return object[0];
464
+ }
465
+ if (node.property === 'last') {
466
+ return object[object.length - 1];
467
+ }
468
+ // Block other array access
469
+ return undefined;
470
+ }
471
+
472
+ // Only allow simple property access on plain objects
473
+ if (typeof object !== 'object') {
474
+ return undefined;
475
+ }
476
+
477
+ // Validate property name - block dangerous properties
478
+ if (
479
+ !this.allowedPropertyPattern.test(node.property) ||
480
+ node.property.startsWith('__') ||
481
+ ['constructor', 'prototype', '__proto__'].includes(node.property)
482
+ ) {
483
+ throw new Error('Invalid property name');
484
+ }
485
+
486
+ // Only access own properties
487
+ if (!Object.prototype.hasOwnProperty.call(object, node.property)) {
488
+ return undefined;
489
+ }
490
+
491
+ return object[node.property];
492
+ }
493
+
494
+ case 'BinaryExpression': {
495
+ const left = this.evaluateNode(node.left, context, depth + 1);
496
+ const right = this.evaluateNode(node.right, context, depth + 1);
497
+
498
+ switch (node.operator) {
499
+ case '==':
500
+ return left == right; // eslint-disable-line eqeqeq
501
+ case '===':
502
+ return left === right;
503
+ case '!=':
504
+ return left != right; // eslint-disable-line eqeqeq
505
+ case '!==':
506
+ return left !== right;
507
+ case '<':
508
+ return left < right;
509
+ case '>':
510
+ return left > right;
511
+ case '<=':
512
+ return left <= right;
513
+ case '>=':
514
+ return left >= right;
515
+ case '&&':
516
+ return left && right;
517
+ case '||':
518
+ return left || right;
519
+ case '+':
520
+ return left + right;
521
+ case '-':
522
+ return left - right;
523
+ case '*':
524
+ return left * right;
525
+ case '/':
526
+ return left / right;
527
+ case '%':
528
+ return left % right;
529
+ default:
530
+ throw new Error(`Unknown operator: ${node.operator}`);
531
+ }
532
+ }
533
+
534
+ case 'UnaryExpression': {
535
+ const argument = this.evaluateNode(node.argument, context, depth + 1);
536
+
537
+ switch (node.operator) {
538
+ case '!':
539
+ return !argument;
540
+ default:
541
+ throw new Error(`Unknown unary operator: ${node.operator}`);
542
+ }
543
+ }
544
+
545
+ default:
546
+ throw new Error(`Unknown node type: ${node.type}`);
547
+ }
548
+ }
549
+ }
550
+
551
+ /**
552
+ * Create a safe evaluator instance
553
+ * @param {object} options - Configuration options
554
+ * @returns {SafeExpressionEvaluator} Evaluator instance
555
+ */
556
+ function createSafeEvaluator(options = {}) {
557
+ return new SafeExpressionEvaluator(options);
558
+ }
559
+
560
+ /**
561
+ * Evaluate expression safely
562
+ * @param {string} expression - Expression to evaluate
563
+ * @param {object} context - Context object
564
+ * @param {object} options - Options
565
+ * @returns {any} Evaluation result
566
+ */
567
+ function evaluateExpression(expression, context = {}, options = {}) {
568
+ const evaluator = createSafeEvaluator(options);
569
+ return evaluator.evaluate(expression, context);
570
+ }
571
+
572
+ module.exports = {
573
+ SafeExpressionEvaluator,
574
+ createSafeEvaluator,
575
+ evaluateExpression,
576
+ };
577
+
578
+ // CommonJS/ESM interop
579
+ module.exports.default = module.exports;