@devilsdev/rag-pipeline-utils 2.4.5 → 2.5.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/.ragrc.schema.json +83 -192
- package/CHANGELOG.md +345 -0
- package/README.md +418 -117
- package/SECURITY.md +5 -5
- package/dist/experimental.cjs +2 -0
- package/dist/experimental.d.ts +1 -0
- package/dist/experimental.mjs +5 -0
- package/dist/index.cjs +4992 -1242
- package/dist/index.d.ts +80 -2
- package/dist/index.mjs +1 -1
- package/dist/types/agentic/agentic-pipeline.d.ts +103 -0
- package/dist/types/agentic/iterative-retriever.d.ts +85 -0
- package/dist/types/agentic/query-planner.d.ts +145 -0
- package/dist/types/agentic/self-critique.d.ts +45 -0
- package/dist/types/ai/adaptive-retrieval.d.ts +44 -0
- package/dist/types/ai/federation/federated-learning-coordinator.d.ts +62 -0
- package/dist/types/ai/multimodal-processing.d.ts +32 -0
- package/dist/types/ai/multimodal.d.ts +39 -0
- package/dist/types/ai/retrieval-engine.d.ts +37 -0
- package/dist/types/ai/training/model-training-orchestrator.d.ts +31 -0
- package/dist/types/chunking/chunking-engine.d.ts +70 -0
- package/dist/types/chunking/strategies/fixed-size.d.ts +17 -0
- package/dist/types/chunking/strategies/recursive.d.ts +20 -0
- package/dist/types/chunking/strategies/semantic.d.ts +19 -0
- package/dist/types/chunking/strategies/sentence.d.ts +13 -0
- package/dist/types/chunking/strategies/structure-aware.d.ts +19 -0
- package/dist/types/citation/citation-tracker.d.ts +64 -0
- package/dist/types/citation/hallucination-detector.d.ts +40 -0
- package/dist/types/citation/source-mapper.d.ts +37 -0
- package/dist/types/connectors/anthropic-connector.d.ts +92 -0
- package/dist/types/connectors/base-connector.d.ts +87 -0
- package/dist/types/connectors/cohere-connector.d.ts +89 -0
- package/dist/types/connectors/connector-utils.d.ts +110 -0
- package/dist/types/connectors/local-embedder.d.ts +86 -0
- package/dist/types/connectors/memory-retriever.d.ts +91 -0
- package/dist/types/connectors/ollama-connector.d.ts +110 -0
- package/dist/types/connectors/openai-connector.d.ts +114 -0
- package/dist/types/connectors/rag-prompt.d.ts +40 -0
- package/dist/types/cost/cost-calculator.d.ts +152 -0
- package/dist/types/cost/cost-tracker.d.ts +126 -0
- package/dist/types/cost/token-budget.d.ts +110 -0
- package/dist/types/dag/core/error-context.d.ts +239 -0
- package/dist/types/dag/core/execution-scheduler.d.ts +191 -0
- package/dist/types/dag/core/topology-validation.d.ts +226 -0
- package/dist/types/dag/dag-engine.d.ts +156 -0
- package/dist/types/dag/dag-node.d.ts +37 -0
- package/dist/types/dashboard/dashboard-generator.d.ts +127 -0
- package/dist/types/dashboard/metrics-aggregator.d.ts +218 -0
- package/dist/types/debug/execution-tracer.d.ts +57 -0
- package/dist/types/debug/trace-inspector.d.ts +31 -0
- package/dist/types/ecosystem/plugin-certification.d.ts +169 -0
- package/dist/types/enterprise/data-governance.d.ts +203 -0
- package/dist/types/enterprise/multi-tenancy.d.ts +137 -0
- package/dist/types/enterprise/sso-integration.d.ts +420 -0
- package/dist/types/evaluate/context-metrics.d.ts +55 -0
- package/dist/types/evaluate/faithfulness.d.ts +41 -0
- package/dist/types/evaluate/groundedness.d.ts +60 -0
- package/dist/types/evaluate/pipeline-evaluator.d.ts +88 -0
- package/dist/types/evaluate/relevance.d.ts +21 -0
- package/dist/types/evaluate/scoring.d.ts +123 -0
- package/dist/types/experimental.d.ts +15 -0
- package/dist/types/graph/entity-extractor.d.ts +84 -0
- package/dist/types/graph/graph-index.d.ts +49 -0
- package/dist/types/graph/graph-retriever.d.ts +81 -0
- package/dist/types/graph/knowledge-graph.d.ts +129 -0
- package/dist/types/guardrails/guardrails-pipeline.d.ts +63 -0
- package/dist/types/guardrails/injection-detector.d.ts +47 -0
- package/dist/types/guardrails/post-generation-guard.d.ts +61 -0
- package/dist/types/guardrails/pre-retrieval-guard.d.ts +64 -0
- package/dist/types/guardrails/retrieval-guard.d.ts +57 -0
- package/dist/types/mcp/mcp-server.d.ts +85 -0
- package/dist/types/mcp/mcp-tool-builder.d.ts +55 -0
- package/dist/types/reranker/cascade-reranker.d.ts +40 -0
- package/dist/types/reranker/embedding-reranker.d.ts +77 -0
- package/dist/types/reranker/scoring-reranker.d.ts +41 -0
- package/dist/types/retrieval/bm25-search.d.ts +43 -0
- package/dist/types/retrieval/file-vector-store.d.ts +87 -0
- package/dist/types/retrieval/hybrid-retriever.d.ts +35 -0
- package/dist/types/retrieval/rank-fusion.d.ts +10 -0
- package/dist/types/security/jwt-config.d.ts +80 -0
- package/dist/types/security/jwt-validator.d.ts +195 -0
- package/dist/types/security/plugin-sandbox.d.ts +158 -0
- package/dist/types/security/plugin-signature-verifier.d.ts +139 -0
- package/dist/types/security/validator.d.ts +5 -0
- package/dist/types/streaming/embedding-stream.d.ts +65 -0
- package/dist/types/streaming/sse-adapter.d.ts +59 -0
- package/dist/types/streaming/stream-router.d.ts +88 -0
- package/dist/types/streaming/streaming-embedder.d.ts +99 -0
- package/dist/types/streaming/websocket-adapter.d.ts +71 -0
- package/dist/types/templates/scaffold.d.ts +55 -0
- package/dist/types/templates/template-registry.d.ts +63 -0
- package/dist/types/utils/embed-query.d.ts +20 -0
- package/dist/types/utils/logger.d.ts +50 -0
- package/dist/types/utils/rate-limiter.d.ts +66 -0
- package/dist/types/utils/retry.d.ts +27 -0
- package/dist/types/utils/run-abort.d.ts +34 -0
- package/dist/types/utils/secure-logging.d.ts +51 -0
- package/dist/types/utils/structured-logger.d.ts +126 -0
- package/package.json +53 -29
- package/src/agentic/agentic-pipeline.js +75 -7
- package/src/agentic/iterative-retriever.js +47 -10
- package/src/agentic/query-planner.js +329 -78
- package/src/citation/citation-tracker.js +6 -4
- package/src/citation/hallucination-detector.js +2 -2
- package/src/citation/source-mapper.js +15 -28
- package/src/cli/commands/ai.js +101 -0
- package/src/cli/commands/plugin-hub/event-handlers.js +6 -0
- package/src/cli/commands/plugin-hub/hub-commands.js +0 -74
- package/src/cli/commands/plugin-hub/local-commands.js +143 -0
- package/src/cli/commands/plugin-hub.js +96 -36
- package/src/cli/diagnostics/config-checker.js +76 -63
- package/src/cli/diagnostics/environment-checker.js +62 -31
- package/src/cli/diagnostics/plugin-checker.js +36 -89
- package/src/cli/doctor-command.js +39 -5
- package/src/cli/enhanced-cli-commands.js +72 -217
- package/src/cli/handlers/ai-handler.js +364 -0
- package/src/cli/handlers/diagnostics-handler.js +78 -31
- package/src/cli/handlers/ingest-handler.js +28 -22
- package/src/cli/handlers/init-handler.js +148 -25
- package/src/cli/handlers/query-handler.js +41 -26
- package/src/cli/handlers/run-handler.js +16 -167
- package/src/cli/handlers/serve-handler.js +60 -0
- package/src/cli/services/bench-stats.js +54 -0
- package/src/cli/services/benchmark.js +161 -0
- package/src/cli/services/feedback.js +155 -0
- package/src/cli/services/rag-service.js +322 -0
- package/src/cli/shared/cli-utils.js +24 -7
- package/src/cli/shared/config-context.js +21 -0
- package/src/cli/wizard/config-builder.js +81 -0
- package/src/cli/wizard/init-wizard.js +617 -0
- package/src/config/component-factory.js +125 -0
- package/src/config/load-config.js +29 -10
- package/src/config/load-plugin-config.js +46 -2
- package/src/connectors/anthropic-connector.js +93 -55
- package/src/connectors/base-connector.js +74 -19
- package/src/connectors/cohere-connector.js +88 -32
- package/src/connectors/connector-utils.js +302 -0
- package/src/connectors/local-embedder.js +43 -5
- package/src/connectors/memory-retriever.js +108 -15
- package/src/connectors/ollama-connector.js +83 -49
- package/src/connectors/openai-connector.js +108 -44
- package/src/connectors/rag-prompt.js +88 -0
- package/src/core/create-pipeline.js +209 -60
- package/src/core/plugin-registry.js +87 -11
- package/src/cost/cost-calculator.js +205 -32
- package/src/dev/dev-server.js +166 -11
- package/src/dev/hot-reload.js +40 -1
- package/src/ecosystem/plugin-checks.js +181 -0
- package/src/ecosystem/plugin-hub.js +50 -125
- package/src/ecosystem/plugin-installer.js +298 -0
- package/src/ecosystem/plugin-probe.js +127 -0
- package/src/ecosystem/plugin-scanner.js +185 -0
- package/src/ecosystem/tar-extract.js +114 -0
- package/src/enterprise/audit-logging.js +158 -29
- package/src/enterprise/sso-integration.js +715 -228
- package/src/evaluate/context-metrics.js +28 -16
- package/src/evaluate/evaluator.js +3 -3
- package/src/evaluate/faithfulness.js +18 -14
- package/src/evaluate/groundedness.js +43 -12
- package/src/evaluate/pipeline-evaluator.js +35 -8
- package/src/evaluate/scoring.js +251 -3
- package/src/experimental.js +71 -0
- package/src/guardrails/guardrails-pipeline.js +69 -7
- package/src/guardrails/injection-detector.js +283 -0
- package/src/guardrails/post-generation-guard.js +19 -0
- package/src/guardrails/pre-retrieval-guard.js +36 -36
- package/src/guardrails/retrieval-guard.js +58 -8
- package/src/index.js +36 -1
- package/src/loader/document-reader.js +91 -0
- package/src/reranker/cascade-reranker.js +3 -0
- package/src/reranker/embedding-reranker.js +136 -21
- package/src/reranker/llm-reranker.js +79 -12
- package/src/reranker/scoring-reranker.js +3 -0
- package/src/retrieval/bm25-search.js +12 -6
- package/src/retrieval/file-vector-store.js +212 -0
- package/src/retrieval/hybrid-retriever.js +22 -19
- package/src/security/jwt-config.js +13 -2
- package/src/security/jwt-validator.js +134 -30
- package/src/security/plugin-sandbox.js +18 -1
- package/src/security/plugin-signature-verifier.js +245 -70
- package/src/utils/deprecate.js +69 -0
- package/src/utils/embed-query.js +33 -0
- package/src/utils/input-sanitizer.js +19 -4
- package/src/utils/logger.js +34 -4
- package/src/utils/run-abort.js +102 -0
- package/src/ai/federated-learning.js +0 -211
- package/src/ai/federation.js +0 -71
- package/src/ai/index.js +0 -22
- package/src/ai/model-trainer.js +0 -217
- package/src/ai/model-training.js +0 -202
- package/src/ai/multimodal/multi-modal-processor.js +0 -345
- package/src/ai/orchestrator.js +0 -65
- package/src/ai/retrieval/adaptive-retrieval-engine.js +0 -398
- package/src/cli/commands/ai-ml/adaptive-commands.js +0 -178
- package/src/cli/commands/ai-ml/federated-commands.js +0 -207
- package/src/cli/commands/ai-ml/index.js +0 -17
- package/src/cli/commands/ai-ml/multimodal-commands.js +0 -187
- package/src/cli/commands/ai-ml/shared.js +0 -51
- package/src/cli/commands/ai-ml/training-commands.js +0 -228
- package/src/cli/commands/ai-ml.js +0 -386
- package/src/cli/commands/docs.js +0 -228
- package/src/cli/commands/dx.js +0 -538
- package/src/cli/commands/wizard.js +0 -627
- package/src/cli/input-sanitization-middleware.js +0 -356
- package/src/cli/interactive-wizard.js +0 -373
- package/src/cli/templates/development.template.json +0 -64
- package/src/cli/templates/minimal.template.json +0 -33
- package/src/cli/templates/production.template.json +0 -104
- package/src/cli/templates/testing.template.json +0 -45
- package/src/cli/wizard/configuration.js +0 -148
- package/src/cli/wizard/observability.js +0 -79
- package/src/cli/wizard/performance.js +0 -76
- package/src/cli/wizard/plugin-selection.js +0 -297
- package/src/cli/wizard/preview-save.js +0 -172
- package/src/cli/wizard/project-setup.js +0 -66
- package/src/core/pipeline-factory.js +0 -59
- package/src/dag/enhanced-dag-engine.js +0 -894
- package/src/dx/index.js +0 -40
- package/src/dx/integration-templates.js +0 -662
- package/src/dx/performance-profiler.js +0 -968
- package/src/dx/realtime-debugger.js +0 -755
- package/src/dx/visual-pipeline-builder.js +0 -578
- package/src/ingest.js +0 -59
- package/src/pipeline/pipeline.js +0 -18
- package/src/query.js +0 -117
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
export = ExecutionScheduler;
|
|
2
|
+
/**
|
|
3
|
+
* ExecutionScheduler class for managing DAG node execution
|
|
4
|
+
*
|
|
5
|
+
* Provides stateless execution scheduling with:
|
|
6
|
+
* - Concurrency control via semaphore
|
|
7
|
+
* - Timeout enforcement
|
|
8
|
+
* - Retry logic with exponential backoff
|
|
9
|
+
* - Dependency resolution
|
|
10
|
+
* - Error handling and reporting
|
|
11
|
+
*
|
|
12
|
+
* @class
|
|
13
|
+
* @since 2.2.3
|
|
14
|
+
*/
|
|
15
|
+
declare class ExecutionScheduler {
|
|
16
|
+
/**
|
|
17
|
+
* Create an ExecutionScheduler instance
|
|
18
|
+
*
|
|
19
|
+
* @param {Object} options - Scheduler configuration
|
|
20
|
+
* @param {Function} options.getSinkIds - Function to get sink node IDs
|
|
21
|
+
* @param {Object} [options.logger] - Logger instance for debugging
|
|
22
|
+
*/
|
|
23
|
+
constructor(options?: {
|
|
24
|
+
getSinkIds: Function;
|
|
25
|
+
logger?: any;
|
|
26
|
+
});
|
|
27
|
+
getSinkIds: Function;
|
|
28
|
+
logger: any;
|
|
29
|
+
errorContext: ErrorContext;
|
|
30
|
+
/**
|
|
31
|
+
* Schedule and execute all nodes with concurrency management
|
|
32
|
+
*
|
|
33
|
+
* Executes nodes in topological order, respecting dependencies and
|
|
34
|
+
* managing concurrency via semaphore. Each node is executed only after
|
|
35
|
+
* all its dependencies have completed or failed.
|
|
36
|
+
*
|
|
37
|
+
* @param {DAGNode[]} order - Topologically sorted array of nodes
|
|
38
|
+
* @param {Object} context - Execution context
|
|
39
|
+
* @param {number} [context.concurrency] - Maximum concurrent executions
|
|
40
|
+
* @param {Map} context.results - Results map (node ID -> result)
|
|
41
|
+
* @param {Map} context.errors - Errors map (node ID -> error)
|
|
42
|
+
* @param {Map} context.fwd - Forward adjacency map
|
|
43
|
+
* @param {boolean} [context.continueOnError] - Continue on non-critical errors
|
|
44
|
+
* @param {Set} context.requiredIds - Set of required node IDs
|
|
45
|
+
* @param {any} context.seed - Initial seed value
|
|
46
|
+
* @param {boolean} [context.gracefulDegradation] - Enable graceful degradation
|
|
47
|
+
* @param {string[]} [context.requiredNodes] - Array of required node IDs
|
|
48
|
+
* @param {boolean} [context.retryFailedNodes] - Enable retry for failed nodes
|
|
49
|
+
* @param {number} [context.maxRetries] - Maximum retry attempts
|
|
50
|
+
* @returns {Promise<void>}
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* const scheduler = new ExecutionScheduler({ getSinkIds });
|
|
54
|
+
* await scheduler.scheduleExecution(sortedNodes, {
|
|
55
|
+
* concurrency: 5,
|
|
56
|
+
* results: new Map(),
|
|
57
|
+
* errors: new Map(),
|
|
58
|
+
* fwd: adjacencyMap,
|
|
59
|
+
* requiredIds: new Set(['critical-node']),
|
|
60
|
+
* seed: initialInput
|
|
61
|
+
* });
|
|
62
|
+
*
|
|
63
|
+
* @performance O(V) where V = number of nodes
|
|
64
|
+
* @since 2.2.3
|
|
65
|
+
*/
|
|
66
|
+
scheduleExecution(order: DAGNode[], context: {
|
|
67
|
+
concurrency?: number;
|
|
68
|
+
results: Map<any, any>;
|
|
69
|
+
errors: Map<any, any>;
|
|
70
|
+
fwd: Map<any, any>;
|
|
71
|
+
continueOnError?: boolean;
|
|
72
|
+
requiredIds: Set<any>;
|
|
73
|
+
seed: any;
|
|
74
|
+
gracefulDegradation?: boolean;
|
|
75
|
+
requiredNodes?: string[];
|
|
76
|
+
retryFailedNodes?: boolean;
|
|
77
|
+
maxRetries?: number;
|
|
78
|
+
}): Promise<void>;
|
|
79
|
+
/**
|
|
80
|
+
* Execute a single DAG node with retry logic and error handling
|
|
81
|
+
*
|
|
82
|
+
* Executes node.run() with comprehensive error handling:
|
|
83
|
+
* - Validates node.run is a function
|
|
84
|
+
* - Determines node criticality
|
|
85
|
+
* - Prepares input from dependencies
|
|
86
|
+
* - Implements retry logic with configurable attempts
|
|
87
|
+
* - Reports errors with downstream impact analysis
|
|
88
|
+
*
|
|
89
|
+
* @param {DAGNode} node - Node to execute
|
|
90
|
+
* @param {Object} context - Execution context
|
|
91
|
+
* @param {Map} context.results - Results map
|
|
92
|
+
* @param {Map} context.errors - Errors map
|
|
93
|
+
* @param {Map} context.fwd - Forward adjacency map
|
|
94
|
+
* @param {boolean} [context.continueOnError] - Continue on non-critical errors
|
|
95
|
+
* @param {Set} context.requiredIds - Required node IDs
|
|
96
|
+
* @param {any} context.seed - Seed value for source nodes
|
|
97
|
+
* @param {boolean} [context.gracefulDegradation] - Enable graceful degradation
|
|
98
|
+
* @param {string[]} [context.requiredNodes] - Required node IDs array
|
|
99
|
+
* @param {boolean} [context.retryFailedNodes] - Enable retry
|
|
100
|
+
* @param {number} [context.maxRetries] - Max retry attempts
|
|
101
|
+
* @returns {Promise<any>} Node execution result or Symbol('failed-optional-node')
|
|
102
|
+
*
|
|
103
|
+
* @throws {Error} Node execution error (if node is critical)
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* const result = await scheduler.executeNode(myNode, {
|
|
107
|
+
* results: new Map(),
|
|
108
|
+
* errors: new Map(),
|
|
109
|
+
* fwd: adjacencyMap,
|
|
110
|
+
* requiredIds: new Set(),
|
|
111
|
+
* seed: initialData,
|
|
112
|
+
* retryFailedNodes: true,
|
|
113
|
+
* maxRetries: 3
|
|
114
|
+
* });
|
|
115
|
+
*
|
|
116
|
+
* @performance O(1) for single execution, O(k) for k retry attempts
|
|
117
|
+
* @complexity Cyclomatic complexity: 12 (acceptable for critical execution path)
|
|
118
|
+
* @since 2.2.3
|
|
119
|
+
*/
|
|
120
|
+
executeNode(node: DAGNode, context: {
|
|
121
|
+
results: Map<any, any>;
|
|
122
|
+
errors: Map<any, any>;
|
|
123
|
+
fwd: Map<any, any>;
|
|
124
|
+
continueOnError?: boolean;
|
|
125
|
+
requiredIds: Set<any>;
|
|
126
|
+
seed: any;
|
|
127
|
+
gracefulDegradation?: boolean;
|
|
128
|
+
requiredNodes?: string[];
|
|
129
|
+
retryFailedNodes?: boolean;
|
|
130
|
+
maxRetries?: number;
|
|
131
|
+
}): Promise<any>;
|
|
132
|
+
/**
|
|
133
|
+
* Execute function with optional timeout enforcement
|
|
134
|
+
*
|
|
135
|
+
* Uses Promise.race to enforce execution timeout. If timeout is not specified
|
|
136
|
+
* or is <= 0, executes without timeout constraint.
|
|
137
|
+
*
|
|
138
|
+
* @param {Function} runFn - Async function to execute
|
|
139
|
+
* @param {number} [timeout] - Timeout in milliseconds (0 or undefined = no timeout)
|
|
140
|
+
* @returns {Promise<void>}
|
|
141
|
+
*
|
|
142
|
+
* @throws {Error} 'Execution timeout' if execution exceeds timeout
|
|
143
|
+
*
|
|
144
|
+
* @example
|
|
145
|
+
* await scheduler.executeWithTimeout(
|
|
146
|
+
* () => executeLongRunningTask(),
|
|
147
|
+
* 30000 // 30 second timeout
|
|
148
|
+
* );
|
|
149
|
+
*
|
|
150
|
+
* @performance O(1) overhead for timeout setup
|
|
151
|
+
* @since 2.2.3
|
|
152
|
+
*/
|
|
153
|
+
executeWithTimeout(runFn: Function, timeout?: number): Promise<void>;
|
|
154
|
+
/**
|
|
155
|
+
* Check if a node can be executed based on dependency satisfaction
|
|
156
|
+
*
|
|
157
|
+
* A node can execute if all its input dependencies have either:
|
|
158
|
+
* - Completed successfully (have a result)
|
|
159
|
+
* - Failed (have an error)
|
|
160
|
+
* - Are optional (graceful degradation enabled and not in required nodes)
|
|
161
|
+
*
|
|
162
|
+
* @param {DAGNode} node - Node to check
|
|
163
|
+
* @param {Object} context - Execution context
|
|
164
|
+
* @param {Map} context.results - Results map
|
|
165
|
+
* @param {Map} context.errors - Errors map
|
|
166
|
+
* @param {boolean} [context.gracefulDegradation] - Enable graceful degradation
|
|
167
|
+
* @param {string[]} [context.requiredNodes] - Required node IDs
|
|
168
|
+
* @returns {boolean} True if node can execute, false otherwise
|
|
169
|
+
*
|
|
170
|
+
* @example
|
|
171
|
+
* const canRun = scheduler.canExecuteNode(myNode, {
|
|
172
|
+
* results: new Map([['dep1', result1]]),
|
|
173
|
+
* errors: new Map(),
|
|
174
|
+
* gracefulDegradation: true,
|
|
175
|
+
* requiredNodes: ['critical-dep']
|
|
176
|
+
* });
|
|
177
|
+
*
|
|
178
|
+
* @performance O(d) where d = number of input dependencies
|
|
179
|
+
* @since 2.2.3
|
|
180
|
+
*/
|
|
181
|
+
canExecuteNode(node: DAGNode, context: {
|
|
182
|
+
results: Map<any, any>;
|
|
183
|
+
errors: Map<any, any>;
|
|
184
|
+
gracefulDegradation?: boolean;
|
|
185
|
+
requiredNodes?: string[];
|
|
186
|
+
}): boolean;
|
|
187
|
+
}
|
|
188
|
+
declare namespace ExecutionScheduler {
|
|
189
|
+
export { ExecutionScheduler as default };
|
|
190
|
+
}
|
|
191
|
+
import ErrorContext = require("./error-context.js");
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview DAG Topology Validation Module
|
|
3
|
+
*
|
|
4
|
+
* Provides topology validation utilities for Directed Acyclic Graphs (DAGs),
|
|
5
|
+
* including cycle detection, topological sorting, and structural validation.
|
|
6
|
+
*
|
|
7
|
+
* @module dag/core/topology-validation
|
|
8
|
+
* @author Ali Kahwaji
|
|
9
|
+
* @since 2.2.2
|
|
10
|
+
* @version 1.0.0
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Builds forward and reverse adjacency maps for a DAG
|
|
14
|
+
*
|
|
15
|
+
* Creates two Maps:
|
|
16
|
+
* - Forward: Maps each node ID to a Set of its children (outgoing edges)
|
|
17
|
+
* - Reverse: Maps each node ID to a Set of its parents (incoming edges)
|
|
18
|
+
*
|
|
19
|
+
* @param {Map<string, DAGNode>} nodes - Map of node IDs to DAGNode instances
|
|
20
|
+
* @returns {{fwd: Map<string, Set<string>>, rev: Map<string, Set<string>>}}
|
|
21
|
+
* Adjacency maps for forward and reverse traversal
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* const nodes = new Map([
|
|
25
|
+
* ['A', nodeA],
|
|
26
|
+
* ['B', nodeB],
|
|
27
|
+
* ['C', nodeC]
|
|
28
|
+
* ]);
|
|
29
|
+
* const { fwd, rev } = buildAdjacency(nodes);
|
|
30
|
+
* // fwd.get('A') => Set(['B', 'C']) - A points to B and C
|
|
31
|
+
* // rev.get('B') => Set(['A']) - B is pointed to by A
|
|
32
|
+
*
|
|
33
|
+
* @performance O(V + E) where V = number of nodes, E = number of edges
|
|
34
|
+
* @since 2.2.2
|
|
35
|
+
*/
|
|
36
|
+
export function buildAdjacency(nodes: Map<string, DAGNode>): {
|
|
37
|
+
fwd: Map<string, Set<string>>;
|
|
38
|
+
rev: Map<string, Set<string>>;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Gets sink node IDs (nodes with no outgoing edges)
|
|
42
|
+
*
|
|
43
|
+
* Sink nodes are terminal nodes in the DAG that have no children.
|
|
44
|
+
* They represent final outputs of the pipeline.
|
|
45
|
+
*
|
|
46
|
+
* @param {Map<string, Set<string>>} fwd - Forward adjacency map
|
|
47
|
+
* @returns {string[]} Array of sink node IDs
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* const fwd = new Map([
|
|
51
|
+
* ['A', new Set(['B'])],
|
|
52
|
+
* ['B', new Set()], // B is a sink
|
|
53
|
+
* ['C', new Set()] // C is a sink
|
|
54
|
+
* ]);
|
|
55
|
+
* const sinks = getSinkIds(fwd);
|
|
56
|
+
* console.log(sinks); // ['B', 'C']
|
|
57
|
+
*
|
|
58
|
+
* @performance O(V) where V = number of nodes
|
|
59
|
+
* @since 2.2.2
|
|
60
|
+
*/
|
|
61
|
+
export function getSinkIds(fwd: Map<string, Set<string>>): string[];
|
|
62
|
+
/**
|
|
63
|
+
* Performs topological sort with comprehensive cycle detection
|
|
64
|
+
*
|
|
65
|
+
* Uses depth-first search (DFS) with path tracking to detect cycles.
|
|
66
|
+
* If a cycle is detected, the error includes the complete cycle path.
|
|
67
|
+
*
|
|
68
|
+
* @param {Map<string, DAGNode>} nodes - Map of node IDs to DAGNode instances
|
|
69
|
+
* @returns {DAGNode[]} Topologically sorted array of nodes
|
|
70
|
+
*
|
|
71
|
+
* @throws {Error} If a cycle is detected. Error includes:
|
|
72
|
+
* - message: Description with cycle path (e.g., "Cycle detected involving node: A -> B -> C -> A")
|
|
73
|
+
* - cycle: Array of node IDs forming the cycle
|
|
74
|
+
* @throws {Error} If topological sort fails for other reasons
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* // Valid DAG
|
|
78
|
+
* const nodes = new Map([
|
|
79
|
+
* ['A', nodeA], // A -> B
|
|
80
|
+
* ['B', nodeB], // B -> C
|
|
81
|
+
* ['C', nodeC] // C (sink)
|
|
82
|
+
* ]);
|
|
83
|
+
* const sorted = topologicalSort(nodes);
|
|
84
|
+
* console.log(sorted.map(n => n.id)); // ['C', 'B', 'A'] (reverse dependency order)
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* // Cyclic DAG (throws error)
|
|
88
|
+
* const nodes = new Map([
|
|
89
|
+
* ['A', nodeA], // A -> B
|
|
90
|
+
* ['B', nodeB], // B -> C
|
|
91
|
+
* ['C', nodeC] // C -> A (creates cycle)
|
|
92
|
+
* ]);
|
|
93
|
+
* try {
|
|
94
|
+
* topologicalSort(nodes);
|
|
95
|
+
* } catch (error) {
|
|
96
|
+
* console.log(error.message); // "Cycle detected involving node: A -> B -> C -> A"
|
|
97
|
+
* console.log(error.cycle); // ['A', 'B', 'C', 'A']
|
|
98
|
+
* }
|
|
99
|
+
*
|
|
100
|
+
* @algorithm
|
|
101
|
+
* 1. Initialize empty order array, visited set, and visiting set
|
|
102
|
+
* 2. For each unvisited node, perform DFS:
|
|
103
|
+
* a. If node is currently being visited (in visiting set), cycle detected
|
|
104
|
+
* b. Mark node as visiting
|
|
105
|
+
* c. Recursively visit all input nodes (dependencies)
|
|
106
|
+
* d. Mark node as visited, remove from visiting
|
|
107
|
+
* e. Add node to order array
|
|
108
|
+
* 3. Return order array (nodes in reverse topological order)
|
|
109
|
+
*
|
|
110
|
+
* @performance O(V + E) where V = number of nodes, E = number of edges
|
|
111
|
+
* @complexity Cyclomatic complexity: 6 (within acceptable limits)
|
|
112
|
+
* @since 2.2.2
|
|
113
|
+
*/
|
|
114
|
+
export function topologicalSort(nodes: Map<string, DAGNode>): DAGNode[];
|
|
115
|
+
/**
|
|
116
|
+
* Validates basic DAG structure
|
|
117
|
+
*
|
|
118
|
+
* Performs fundamental validation checks:
|
|
119
|
+
* - DAG is not empty
|
|
120
|
+
* - No cycles exist (via topological sort)
|
|
121
|
+
* - At least one sink node exists
|
|
122
|
+
*
|
|
123
|
+
* This is the primary validation method called before DAG execution.
|
|
124
|
+
*
|
|
125
|
+
* @param {Map<string, DAGNode>} nodes - Map of node IDs to DAGNode instances
|
|
126
|
+
* @returns {boolean} True if validation passes
|
|
127
|
+
*
|
|
128
|
+
* @throws {Error} If DAG is empty - "DAG is empty - no nodes to execute"
|
|
129
|
+
* @throws {Error} If cycle detected - "DAG validation failed: DAG topological sort failed: Cycle detected involving node: ..."
|
|
130
|
+
* - error.cycle: Array of node IDs forming the cycle
|
|
131
|
+
* @throws {Error} If no sink nodes - "DAG has no sink nodes - no final output available"
|
|
132
|
+
* @throws {Error} For other validation failures
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* // Valid DAG
|
|
136
|
+
* const nodes = new Map([
|
|
137
|
+
* ['load', loadNode],
|
|
138
|
+
* ['process', processNode],
|
|
139
|
+
* ['save', saveNode]
|
|
140
|
+
* ]);
|
|
141
|
+
* const isValid = validateDAG(nodes); // true
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* // Empty DAG
|
|
145
|
+
* try {
|
|
146
|
+
* validateDAG(new Map());
|
|
147
|
+
* } catch (error) {
|
|
148
|
+
* console.log(error.message); // "DAG is empty - no nodes to execute"
|
|
149
|
+
* }
|
|
150
|
+
*
|
|
151
|
+
* @example
|
|
152
|
+
* // No sink nodes (all nodes have outputs)
|
|
153
|
+
* const nodes = new Map([
|
|
154
|
+
* ['A', nodeA] // A -> B
|
|
155
|
+
* ]);
|
|
156
|
+
* // Assuming all nodes have outputs
|
|
157
|
+
* try {
|
|
158
|
+
* validateDAG(nodes);
|
|
159
|
+
* } catch (error) {
|
|
160
|
+
* console.log(error.message); // "DAG has no sink nodes - no final output available"
|
|
161
|
+
* }
|
|
162
|
+
*
|
|
163
|
+
* @performance O(V + E) due to topological sort
|
|
164
|
+
* @since 2.2.2
|
|
165
|
+
*/
|
|
166
|
+
export function validateDAG(nodes: Map<string, DAGNode>): boolean;
|
|
167
|
+
/**
|
|
168
|
+
* Validates DAG topology with advanced options and warnings
|
|
169
|
+
*
|
|
170
|
+
* Performs comprehensive validation including:
|
|
171
|
+
* - Empty DAG check
|
|
172
|
+
* - Self-loop detection
|
|
173
|
+
* - Cycle detection via topological sort
|
|
174
|
+
* - Isolated node detection (nodes with no connections)
|
|
175
|
+
*
|
|
176
|
+
* Supports strict and non-strict modes. In non-strict mode, some issues
|
|
177
|
+
* (like isolated nodes) generate warnings instead of throwing errors.
|
|
178
|
+
*
|
|
179
|
+
* @param {Map<string, DAGNode>} nodes - Map of node IDs to DAGNode instances
|
|
180
|
+
* @param {Object} options - Validation options
|
|
181
|
+
* @param {boolean} [options.strict=true] - If true, throw errors for all issues.
|
|
182
|
+
* If false, return warnings for non-critical issues
|
|
183
|
+
* @returns {string[]} Array of warning messages (empty if no warnings in strict mode)
|
|
184
|
+
*
|
|
185
|
+
* @throws {Error} If DAG is empty - "DAG cannot be empty"
|
|
186
|
+
* @throws {Error} If self-loop detected - "Self-loop detected"
|
|
187
|
+
* @throws {Error} If cycle detected - "Cycle detected in DAG"
|
|
188
|
+
* - error.cycle: Array of node IDs forming the cycle
|
|
189
|
+
* @throws {Error} If orphaned node found in strict mode
|
|
190
|
+
*
|
|
191
|
+
* @example
|
|
192
|
+
* // Strict mode (default)
|
|
193
|
+
* const nodes = new Map([['isolated', isolatedNode]]);
|
|
194
|
+
* try {
|
|
195
|
+
* validateTopology(nodes, { strict: true });
|
|
196
|
+
* } catch (error) {
|
|
197
|
+
* console.log(error.message); // "Orphaned node detected: isolated"
|
|
198
|
+
* }
|
|
199
|
+
*
|
|
200
|
+
* @example
|
|
201
|
+
* // Non-strict mode (warnings)
|
|
202
|
+
* const nodes = new Map([
|
|
203
|
+
* ['A', nodeA],
|
|
204
|
+
* ['isolated', isolatedNode]
|
|
205
|
+
* ]);
|
|
206
|
+
* const warnings = validateTopology(nodes, { strict: false });
|
|
207
|
+
* console.log(warnings); // ["Orphaned node detected: isolated"]
|
|
208
|
+
*
|
|
209
|
+
* @example
|
|
210
|
+
* // Self-loop detection
|
|
211
|
+
* const nodeWithSelfLoop = new DAGNode('X', () => {});
|
|
212
|
+
* nodeWithSelfLoop.outputs.push(nodeWithSelfLoop);
|
|
213
|
+
* const nodes = new Map([['X', nodeWithSelfLoop]]);
|
|
214
|
+
* try {
|
|
215
|
+
* validateTopology(nodes);
|
|
216
|
+
* } catch (error) {
|
|
217
|
+
* console.log(error.message); // "Self-loop detected"
|
|
218
|
+
* }
|
|
219
|
+
*
|
|
220
|
+
* @performance O(V + E) due to topological sort and graph traversal
|
|
221
|
+
* @complexity Cyclomatic complexity: 5 (within acceptable limits)
|
|
222
|
+
* @since 2.2.2
|
|
223
|
+
*/
|
|
224
|
+
export function validateTopology(nodes: Map<string, DAGNode>, options?: {
|
|
225
|
+
strict?: boolean;
|
|
226
|
+
}): string[];
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
export class DAG {
|
|
2
|
+
nodes: Map<any, any>;
|
|
3
|
+
scheduler: ExecutionScheduler;
|
|
4
|
+
errorContext: ErrorContext;
|
|
5
|
+
addNode(id: any, _fn: any, options?: {}): DAGNode;
|
|
6
|
+
connect(fromId: any, toId: any): void;
|
|
7
|
+
/**
|
|
8
|
+
* Parse and normalize execute parameters
|
|
9
|
+
* @param {any} seedOrOptions - Seed data or options object
|
|
10
|
+
* @param {Object} _options - Additional options (if first param is seed)
|
|
11
|
+
* @returns {Object} - Normalized {seed, options} object
|
|
12
|
+
*/
|
|
13
|
+
_parseExecuteParams(seedOrOptions: any, _options?: any): any;
|
|
14
|
+
/**
|
|
15
|
+
* Execute all nodes in topological order with concurrency control
|
|
16
|
+
* @param {Array} order - Topologically sorted nodes
|
|
17
|
+
* @param {Object} context - Execution context
|
|
18
|
+
* @returns {Promise<void>}
|
|
19
|
+
*/
|
|
20
|
+
_runAllNodes(order: any[], context: any): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* Check if a node can be executed based on dependency satisfaction
|
|
23
|
+
* @param {DAGNode} node - Node to check
|
|
24
|
+
* @param {Object} context - Execution context
|
|
25
|
+
* @returns {boolean}
|
|
26
|
+
*/
|
|
27
|
+
_canExecuteNode(node: DAGNode, context: any): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Initialize execution state and validate DAG
|
|
30
|
+
* @returns {Object} - Execution state object
|
|
31
|
+
*/
|
|
32
|
+
_initializeExecutionState(): any;
|
|
33
|
+
/**
|
|
34
|
+
* Handle execution errors with appropriate wrapping
|
|
35
|
+
* @param {Error} error - Error to handle
|
|
36
|
+
* @throws {Error} - Appropriately wrapped error
|
|
37
|
+
*/
|
|
38
|
+
_handleExecutionError(error: Error): void;
|
|
39
|
+
/**
|
|
40
|
+
* Execute function with optional timeout
|
|
41
|
+
* @param {Function} runFn - Function to execute
|
|
42
|
+
* @param {number} timeout - Timeout in milliseconds
|
|
43
|
+
* @returns {Promise<void>}
|
|
44
|
+
*/
|
|
45
|
+
_executeWithTimeout(runFn: Function, timeout: number): Promise<void>;
|
|
46
|
+
/**
|
|
47
|
+
* Process execution results and handle checkpointing
|
|
48
|
+
* @param {Map} results - Node execution results
|
|
49
|
+
* @param {Map} errors - Node execution errors
|
|
50
|
+
* @param {Map} fwd - Forward adjacency map
|
|
51
|
+
* @param {Object} options - Processing options
|
|
52
|
+
* @returns {any} - Processed results
|
|
53
|
+
*/
|
|
54
|
+
_processResults(results: Map<any, any>, errors: Map<any, any>, fwd: Map<any, any>, options: any): any;
|
|
55
|
+
/**
|
|
56
|
+
* Executes the DAG with optional seed data and configuration
|
|
57
|
+
* @param {any} seedOrOptions - Seed data or options object
|
|
58
|
+
* @param {Object} _options - Additional options (if first param is seed)
|
|
59
|
+
* @returns {Promise<any>} - Execution results
|
|
60
|
+
*/
|
|
61
|
+
execute(seedOrOptions: any, _options?: any): Promise<any>;
|
|
62
|
+
/**
|
|
63
|
+
* Helper for running with optional global timeout
|
|
64
|
+
* @param {Function} runFn - Function to run
|
|
65
|
+
* @param {number} timeout - Timeout in milliseconds
|
|
66
|
+
* @returns {Promise} - Promise that resolves/rejects with timeout handling
|
|
67
|
+
*/
|
|
68
|
+
_runWithOptionalGlobalTimeout(runFn: Function, timeout: number): Promise<any>;
|
|
69
|
+
/**
|
|
70
|
+
* Build adjacency lists for the DAG
|
|
71
|
+
* @returns {Object} - Object with fwd and rev adjacency maps
|
|
72
|
+
*/
|
|
73
|
+
_buildAdjacency(): any;
|
|
74
|
+
/**
|
|
75
|
+
* Get sink node IDs (nodes with no outgoing edges)
|
|
76
|
+
* @param {Map} fwd - Forward adjacency map
|
|
77
|
+
* @returns {Array} - Array of sink node IDs
|
|
78
|
+
*/
|
|
79
|
+
_getSinkIds(fwd: Map<any, any>): any[];
|
|
80
|
+
/**
|
|
81
|
+
* Get required node IDs (all sinks + all their ancestors)
|
|
82
|
+
* @param {Map} fwd - Forward adjacency map
|
|
83
|
+
* @param {Map} rev - Reverse adjacency map
|
|
84
|
+
* @returns {Set} - Set of required node IDs
|
|
85
|
+
*/
|
|
86
|
+
_getRequiredIds(fwd: Map<any, any>, rev: Map<any, any>): Set<any>;
|
|
87
|
+
/**
|
|
88
|
+
* Build adjacency list for the DAG (legacy method for compatibility)
|
|
89
|
+
* @returns {Map} - Adjacency list mapping node IDs to arrays of dependent node IDs
|
|
90
|
+
*/
|
|
91
|
+
buildAdjacencyList(): Map<any, any>;
|
|
92
|
+
/**
|
|
93
|
+
* Validates the DAG structure
|
|
94
|
+
* @returns {boolean} - True if valid
|
|
95
|
+
* @throws {Error} - If validation fails
|
|
96
|
+
*/
|
|
97
|
+
validate(): boolean;
|
|
98
|
+
/**
|
|
99
|
+
* Execute a single node with input data
|
|
100
|
+
* @param {DAGNode} node - Node to execute
|
|
101
|
+
* @param {Object} context - Execution context
|
|
102
|
+
* @returns {Promise<any>} Node execution result
|
|
103
|
+
*/
|
|
104
|
+
executeNode(node: DAGNode, context: any): Promise<any>;
|
|
105
|
+
/**
|
|
106
|
+
* Validate topology with advanced options
|
|
107
|
+
* @param {Object} _options - Validation options
|
|
108
|
+
* @returns {Array} - Array of warnings (empty if no issues)
|
|
109
|
+
*/
|
|
110
|
+
validateTopology(_options?: any): any[];
|
|
111
|
+
/**
|
|
112
|
+
* Performs topological sort with cycle detection
|
|
113
|
+
* @returns {DAGNode[]} Topologically sorted nodes
|
|
114
|
+
* @throws {Error} If cycles are detected
|
|
115
|
+
*/
|
|
116
|
+
topoSort(): DAGNode[];
|
|
117
|
+
/**
|
|
118
|
+
* Resume execution from checkpoint data
|
|
119
|
+
* @param {Object} checkpointData - Checkpoint data to resume from
|
|
120
|
+
* @returns {Promise<Map>} - Results Map from resumed execution
|
|
121
|
+
*/
|
|
122
|
+
resume(checkpointData?: any): Promise<Map<any, any>>;
|
|
123
|
+
/**
|
|
124
|
+
* Save execution checkpoint
|
|
125
|
+
* @param {string} checkpointId - Unique checkpoint identifier
|
|
126
|
+
* @param {Object} state - Execution state to save
|
|
127
|
+
*/
|
|
128
|
+
saveCheckpoint(checkpointId: string, state: any): void;
|
|
129
|
+
checkpoints: Map<any, any>;
|
|
130
|
+
/**
|
|
131
|
+
* Load execution checkpoint
|
|
132
|
+
* @param {string} checkpointId - Unique checkpoint identifier
|
|
133
|
+
* @returns {Object|null} - Saved execution state or null if not found
|
|
134
|
+
*/
|
|
135
|
+
loadCheckpoint(checkpointId: string): any | null;
|
|
136
|
+
/**
|
|
137
|
+
* List all available checkpoints
|
|
138
|
+
* @returns {Array} - Array of checkpoint IDs with metadata
|
|
139
|
+
*/
|
|
140
|
+
listCheckpoints(): any[];
|
|
141
|
+
/**
|
|
142
|
+
* Clear execution checkpoint
|
|
143
|
+
* @param {string} checkpointId - Unique checkpoint identifier
|
|
144
|
+
*/
|
|
145
|
+
clearCheckpoint(checkpointId: string): void;
|
|
146
|
+
/**
|
|
147
|
+
* Get all downstream nodes that depend on the given node
|
|
148
|
+
* @param {DAGNode} node - Node to find downstream dependencies for
|
|
149
|
+
* @returns {DAGNode[]} Array of downstream nodes
|
|
150
|
+
*/
|
|
151
|
+
getDownstreamNodes(node: DAGNode): DAGNode[];
|
|
152
|
+
}
|
|
153
|
+
import DAGNode = require("./dag-node.js");
|
|
154
|
+
import ExecutionScheduler = require("./core/execution-scheduler.js");
|
|
155
|
+
import ErrorContext = require("./core/error-context.js");
|
|
156
|
+
export { DAGNode };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export = DAGNode;
|
|
2
|
+
/**
|
|
3
|
+
* Version: 2.0.2
|
|
4
|
+
* Path: /src/dag/dag-node.js
|
|
5
|
+
* Description: DAG node class for representing individual nodes in the DAG
|
|
6
|
+
* Author: Ali Kahwaji
|
|
7
|
+
*/
|
|
8
|
+
declare class DAGNode {
|
|
9
|
+
constructor(id: any, run: any, options?: {});
|
|
10
|
+
id: any;
|
|
11
|
+
run: any;
|
|
12
|
+
inputs: any[];
|
|
13
|
+
outputs: any[];
|
|
14
|
+
timeout: any;
|
|
15
|
+
retries: any;
|
|
16
|
+
priority: any;
|
|
17
|
+
/**
|
|
18
|
+
* Add an output connection to another node
|
|
19
|
+
* @param {DAGNode} node - Target node to connect to
|
|
20
|
+
*/
|
|
21
|
+
addOutput(node: DAGNode): this;
|
|
22
|
+
/**
|
|
23
|
+
* Add an input connection from another node
|
|
24
|
+
* @param {DAGNode} node - Source node to connect from
|
|
25
|
+
*/
|
|
26
|
+
addInput(node: DAGNode): this;
|
|
27
|
+
/**
|
|
28
|
+
* Remove an output connection
|
|
29
|
+
* @param {DAGNode} node - Target node to disconnect from
|
|
30
|
+
*/
|
|
31
|
+
removeOutput(node: DAGNode): this;
|
|
32
|
+
/**
|
|
33
|
+
* Remove an input connection
|
|
34
|
+
* @param {DAGNode} node - Source node to disconnect from
|
|
35
|
+
*/
|
|
36
|
+
removeInput(node: DAGNode): this;
|
|
37
|
+
}
|