@soulcraft/brainy 3.0.0 → 3.0.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.
- package/CHANGELOG.md +53 -3
- package/README.md +353 -110
- package/bin/brainy.js +340 -62
- package/dist/api/ConfigAPI.d.ts +67 -0
- package/dist/api/ConfigAPI.js +166 -0
- package/dist/api/DataAPI.d.ts +123 -0
- package/dist/api/DataAPI.js +391 -0
- package/dist/api/SecurityAPI.d.ts +50 -0
- package/dist/api/SecurityAPI.js +139 -0
- package/dist/api/UniversalImportAPI.d.ts +134 -0
- package/dist/api/UniversalImportAPI.js +615 -0
- package/dist/augmentationManager.js +12 -7
- package/dist/augmentationPipeline.d.ts +0 -61
- package/dist/augmentationPipeline.js +0 -87
- package/dist/augmentationRegistry.d.ts +1 -1
- package/dist/augmentationRegistry.js +1 -1
- package/dist/augmentations/apiServerAugmentation.d.ts +27 -1
- package/dist/augmentations/apiServerAugmentation.js +290 -9
- package/dist/augmentations/auditLogAugmentation.d.ts +109 -0
- package/dist/augmentations/auditLogAugmentation.js +358 -0
- package/dist/augmentations/batchProcessingAugmentation.d.ts +3 -2
- package/dist/augmentations/batchProcessingAugmentation.js +123 -22
- package/dist/augmentations/brainyAugmentation.d.ts +142 -8
- package/dist/augmentations/brainyAugmentation.js +179 -2
- package/dist/augmentations/cacheAugmentation.d.ts +8 -5
- package/dist/augmentations/cacheAugmentation.js +116 -17
- package/dist/augmentations/conduitAugmentations.d.ts +2 -2
- package/dist/augmentations/conduitAugmentations.js +2 -2
- package/dist/augmentations/configResolver.d.ts +122 -0
- package/dist/augmentations/configResolver.js +440 -0
- package/dist/augmentations/connectionPoolAugmentation.d.ts +3 -1
- package/dist/augmentations/connectionPoolAugmentation.js +37 -12
- package/dist/augmentations/defaultAugmentations.d.ts +14 -10
- package/dist/augmentations/defaultAugmentations.js +16 -11
- package/dist/augmentations/discovery/catalogDiscovery.d.ts +142 -0
- package/dist/augmentations/discovery/catalogDiscovery.js +249 -0
- package/dist/augmentations/discovery/localDiscovery.d.ts +84 -0
- package/dist/augmentations/discovery/localDiscovery.js +246 -0
- package/dist/augmentations/discovery/runtimeLoader.d.ts +97 -0
- package/dist/augmentations/discovery/runtimeLoader.js +337 -0
- package/dist/augmentations/discovery.d.ts +152 -0
- package/dist/augmentations/discovery.js +441 -0
- package/dist/augmentations/display/cache.d.ts +130 -0
- package/dist/augmentations/display/cache.js +319 -0
- package/dist/augmentations/display/fieldPatterns.d.ts +52 -0
- package/dist/augmentations/display/fieldPatterns.js +393 -0
- package/dist/augmentations/display/iconMappings.d.ts +57 -0
- package/dist/augmentations/display/iconMappings.js +68 -0
- package/dist/augmentations/display/intelligentComputation.d.ts +109 -0
- package/dist/augmentations/display/intelligentComputation.js +462 -0
- package/dist/augmentations/display/types.d.ts +203 -0
- package/dist/augmentations/display/types.js +7 -0
- package/dist/augmentations/entityRegistryAugmentation.d.ts +3 -1
- package/dist/augmentations/entityRegistryAugmentation.js +5 -1
- package/dist/augmentations/indexAugmentation.d.ts +5 -3
- package/dist/augmentations/indexAugmentation.js +5 -2
- package/dist/augmentations/intelligentVerbScoringAugmentation.d.ts +24 -7
- package/dist/augmentations/intelligentVerbScoringAugmentation.js +111 -27
- package/dist/augmentations/manifest.d.ts +176 -0
- package/dist/augmentations/manifest.js +8 -0
- package/dist/augmentations/marketplace/AugmentationMarketplace.d.ts +168 -0
- package/dist/augmentations/marketplace/AugmentationMarketplace.js +329 -0
- package/dist/augmentations/marketplace/cli.d.ts +47 -0
- package/dist/augmentations/marketplace/cli.js +265 -0
- package/dist/augmentations/metricsAugmentation.d.ts +3 -3
- package/dist/augmentations/metricsAugmentation.js +2 -2
- package/dist/augmentations/monitoringAugmentation.d.ts +3 -3
- package/dist/augmentations/monitoringAugmentation.js +2 -2
- package/dist/augmentations/neuralImport.d.ts +1 -1
- package/dist/augmentations/neuralImport.js +4 -4
- package/dist/augmentations/rateLimitAugmentation.d.ts +82 -0
- package/dist/augmentations/rateLimitAugmentation.js +321 -0
- package/dist/augmentations/requestDeduplicatorAugmentation.d.ts +2 -2
- package/dist/augmentations/requestDeduplicatorAugmentation.js +1 -1
- package/dist/augmentations/storageAugmentation.d.ts +1 -1
- package/dist/augmentations/storageAugmentation.js +2 -2
- package/dist/augmentations/storageAugmentations.d.ts +37 -8
- package/dist/augmentations/storageAugmentations.js +204 -15
- package/dist/augmentations/synapseAugmentation.d.ts +1 -1
- package/dist/augmentations/synapseAugmentation.js +35 -16
- package/dist/augmentations/typeMatching/brainyTypes.d.ts +83 -0
- package/dist/augmentations/typeMatching/brainyTypes.js +425 -0
- package/dist/augmentations/typeMatching/intelligentTypeMatcher.d.ts +39 -59
- package/dist/augmentations/typeMatching/intelligentTypeMatcher.js +103 -389
- package/dist/augmentations/universalDisplayAugmentation.d.ts +191 -0
- package/dist/augmentations/universalDisplayAugmentation.js +371 -0
- package/dist/brainy-unified.d.ts +106 -0
- package/dist/brainy-unified.js +327 -0
- package/dist/brainy.d.ts +273 -0
- package/dist/brainy.js +1181 -0
- package/dist/brainyData.d.ts +56 -111
- package/dist/brainyData.js +912 -756
- package/dist/brainyDataV3.d.ts +186 -0
- package/dist/brainyDataV3.js +337 -0
- package/dist/browserFramework.d.ts +6 -6
- package/dist/browserFramework.js +11 -8
- package/dist/browserFramework.minimal.d.ts +5 -5
- package/dist/browserFramework.minimal.js +11 -8
- package/dist/config/distributedPresets-new.d.ts +118 -0
- package/dist/config/distributedPresets-new.js +318 -0
- package/dist/config/distributedPresets.d.ts +118 -0
- package/dist/config/distributedPresets.js +318 -0
- package/dist/config/extensibleConfig.d.ts +99 -0
- package/dist/config/extensibleConfig.js +268 -0
- package/dist/config/index.d.ts +17 -0
- package/dist/config/index.js +35 -0
- package/dist/config/modelAutoConfig.d.ts +32 -0
- package/dist/config/modelAutoConfig.js +139 -0
- package/dist/config/modelPrecisionManager.d.ts +42 -0
- package/dist/config/modelPrecisionManager.js +98 -0
- package/dist/config/sharedConfigManager.d.ts +67 -0
- package/dist/config/sharedConfigManager.js +215 -0
- package/dist/config/storageAutoConfig.d.ts +41 -0
- package/dist/config/storageAutoConfig.js +328 -0
- package/dist/config/zeroConfig.d.ts +68 -0
- package/dist/config/zeroConfig.js +301 -0
- package/dist/cortex/backupRestore.d.ts +2 -2
- package/dist/cortex/backupRestore.js +85 -27
- package/dist/cortex/healthCheck.d.ts +2 -2
- package/dist/cortex/neuralImport.d.ts +2 -2
- package/dist/cortex/neuralImport.js +18 -13
- package/dist/cortex/performanceMonitor.d.ts +2 -2
- package/dist/critical/model-guardian.d.ts +4 -0
- package/dist/critical/model-guardian.js +31 -11
- package/dist/demo.d.ts +4 -4
- package/dist/demo.js +7 -7
- package/dist/distributed/cacheSync.d.ts +112 -0
- package/dist/distributed/cacheSync.js +265 -0
- package/dist/distributed/coordinator.d.ts +193 -0
- package/dist/distributed/coordinator.js +548 -0
- package/dist/distributed/httpTransport.d.ts +120 -0
- package/dist/distributed/httpTransport.js +446 -0
- package/dist/distributed/index.d.ts +8 -0
- package/dist/distributed/index.js +5 -0
- package/dist/distributed/networkTransport.d.ts +132 -0
- package/dist/distributed/networkTransport.js +633 -0
- package/dist/distributed/queryPlanner.d.ts +104 -0
- package/dist/distributed/queryPlanner.js +327 -0
- package/dist/distributed/readWriteSeparation.d.ts +134 -0
- package/dist/distributed/readWriteSeparation.js +350 -0
- package/dist/distributed/shardManager.d.ts +114 -0
- package/dist/distributed/shardManager.js +357 -0
- package/dist/distributed/shardMigration.d.ts +110 -0
- package/dist/distributed/shardMigration.js +289 -0
- package/dist/distributed/storageDiscovery.d.ts +160 -0
- package/dist/distributed/storageDiscovery.js +551 -0
- package/dist/embeddings/CachedEmbeddings.d.ts +40 -0
- package/dist/embeddings/CachedEmbeddings.js +146 -0
- package/dist/embeddings/EmbeddingManager.d.ts +102 -0
- package/dist/embeddings/EmbeddingManager.js +291 -0
- package/dist/embeddings/SingletonModelManager.d.ts +95 -0
- package/dist/embeddings/SingletonModelManager.js +220 -0
- package/dist/embeddings/index.d.ts +12 -0
- package/dist/embeddings/index.js +16 -0
- package/dist/embeddings/lightweight-embedder.d.ts +0 -1
- package/dist/embeddings/lightweight-embedder.js +4 -12
- package/dist/embeddings/model-manager.d.ts +11 -0
- package/dist/embeddings/model-manager.js +43 -7
- package/dist/embeddings/universal-memory-manager.d.ts +1 -1
- package/dist/embeddings/universal-memory-manager.js +27 -67
- package/dist/embeddings/worker-embedding.js +4 -8
- package/dist/errors/brainyError.d.ts +5 -1
- package/dist/errors/brainyError.js +12 -0
- package/dist/examples/basicUsage.js +7 -4
- package/dist/graph/graphAdjacencyIndex.d.ts +96 -0
- package/dist/graph/graphAdjacencyIndex.js +288 -0
- package/dist/graph/pathfinding.js +4 -2
- package/dist/hnsw/scaledHNSWSystem.js +11 -2
- package/dist/importManager.js +8 -5
- package/dist/index.d.ts +17 -22
- package/dist/index.js +37 -23
- package/dist/mcp/brainyMCPAdapter.d.ts +4 -4
- package/dist/mcp/brainyMCPAdapter.js +5 -5
- package/dist/mcp/brainyMCPService.d.ts +3 -3
- package/dist/mcp/brainyMCPService.js +3 -11
- package/dist/mcp/mcpAugmentationToolset.js +20 -30
- package/dist/neural/embeddedPatterns.d.ts +1 -1
- package/dist/neural/embeddedPatterns.js +2 -2
- package/dist/neural/entityExtractor.d.ts +65 -0
- package/dist/neural/entityExtractor.js +316 -0
- package/dist/neural/improvedNeuralAPI.d.ts +357 -0
- package/dist/neural/improvedNeuralAPI.js +2628 -0
- package/dist/neural/naturalLanguageProcessor.d.ts +155 -10
- package/dist/neural/naturalLanguageProcessor.js +941 -66
- package/dist/neural/naturalLanguageProcessorStatic.d.ts +2 -2
- package/dist/neural/naturalLanguageProcessorStatic.js +3 -3
- package/dist/neural/neuralAPI.js +8 -2
- package/dist/neural/patternLibrary.d.ts +57 -3
- package/dist/neural/patternLibrary.js +348 -13
- package/dist/neural/staticPatternMatcher.d.ts +2 -2
- package/dist/neural/staticPatternMatcher.js +2 -2
- package/dist/neural/types.d.ts +287 -0
- package/dist/neural/types.js +24 -0
- package/dist/shared/default-augmentations.d.ts +3 -3
- package/dist/shared/default-augmentations.js +5 -5
- package/dist/storage/adapters/baseStorageAdapter.d.ts +42 -0
- package/dist/storage/adapters/fileSystemStorage.d.ts +26 -2
- package/dist/storage/adapters/fileSystemStorage.js +218 -15
- package/dist/storage/adapters/memoryStorage.d.ts +4 -4
- package/dist/storage/adapters/memoryStorage.js +17 -12
- package/dist/storage/adapters/opfsStorage.d.ts +2 -2
- package/dist/storage/adapters/opfsStorage.js +2 -2
- package/dist/storage/adapters/s3CompatibleStorage.d.ts +2 -2
- package/dist/storage/adapters/s3CompatibleStorage.js +2 -2
- package/dist/storage/backwardCompatibility.d.ts +10 -78
- package/dist/storage/backwardCompatibility.js +17 -132
- package/dist/storage/baseStorage.d.ts +18 -2
- package/dist/storage/baseStorage.js +74 -3
- package/dist/storage/cacheManager.js +2 -2
- package/dist/storage/readOnlyOptimizations.js +8 -3
- package/dist/streaming/pipeline.d.ts +154 -0
- package/dist/streaming/pipeline.js +551 -0
- package/dist/triple/TripleIntelligence.d.ts +25 -110
- package/dist/triple/TripleIntelligence.js +4 -574
- package/dist/triple/TripleIntelligenceSystem.d.ts +159 -0
- package/dist/triple/TripleIntelligenceSystem.js +519 -0
- package/dist/types/apiTypes.d.ts +278 -0
- package/dist/types/apiTypes.js +33 -0
- package/dist/types/brainy.types.d.ts +308 -0
- package/dist/types/brainy.types.js +8 -0
- package/dist/types/brainyDataInterface.d.ts +5 -8
- package/dist/types/brainyDataInterface.js +2 -2
- package/dist/types/graphTypes.js +2 -2
- package/dist/utils/brainyTypes.d.ts +217 -0
- package/dist/utils/brainyTypes.js +261 -0
- package/dist/utils/cacheAutoConfig.d.ts +3 -3
- package/dist/utils/embedding.d.ts +9 -4
- package/dist/utils/embedding.js +89 -26
- package/dist/utils/enhancedLogger.d.ts +104 -0
- package/dist/utils/enhancedLogger.js +232 -0
- package/dist/utils/hybridModelManager.d.ts +19 -28
- package/dist/utils/hybridModelManager.js +36 -200
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.js +1 -1
- package/dist/utils/intelligentTypeMapper.d.ts +60 -0
- package/dist/utils/intelligentTypeMapper.js +349 -0
- package/dist/utils/metadataIndex.d.ts +118 -1
- package/dist/utils/metadataIndex.js +539 -16
- package/dist/utils/nodeVersionCheck.d.ts +24 -0
- package/dist/utils/nodeVersionCheck.js +65 -0
- package/dist/utils/paramValidation.d.ts +39 -0
- package/dist/utils/paramValidation.js +192 -0
- package/dist/utils/rateLimiter.d.ts +160 -0
- package/dist/utils/rateLimiter.js +271 -0
- package/dist/utils/statistics.d.ts +4 -4
- package/dist/utils/statistics.js +3 -3
- package/dist/utils/structuredLogger.d.ts +146 -0
- package/dist/utils/structuredLogger.js +394 -0
- package/dist/utils/textEncoding.js +2 -1
- package/dist/utils/typeValidation.d.ts +59 -0
- package/dist/utils/typeValidation.js +374 -0
- package/dist/utils/version.js +19 -3
- package/package.json +15 -4
- package/scripts/download-models.cjs +94 -20
- package/dist/augmentations/walAugmentation.d.ts +0 -109
- package/dist/augmentations/walAugmentation.js +0 -516
- package/dist/chat/BrainyChat.d.ts +0 -121
- package/dist/chat/BrainyChat.js +0 -396
- package/dist/chat/ChatCLI.d.ts +0 -61
- package/dist/chat/ChatCLI.js +0 -351
|
@@ -0,0 +1,548 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Distributed Coordinator for Brainy 3.0
|
|
3
|
+
* Provides leader election, consensus, and coordination for distributed instances
|
|
4
|
+
*/
|
|
5
|
+
import { EventEmitter } from 'events';
|
|
6
|
+
import { createHash } from 'crypto';
|
|
7
|
+
/**
|
|
8
|
+
* Distributed Coordinator implementing Raft-like consensus
|
|
9
|
+
*/
|
|
10
|
+
export class DistributedCoordinator extends EventEmitter {
|
|
11
|
+
constructor(config = {}) {
|
|
12
|
+
super();
|
|
13
|
+
this.nodes = new Map();
|
|
14
|
+
this.isRunning = false;
|
|
15
|
+
this.votesReceived = new Set();
|
|
16
|
+
this.currentTerm = 0;
|
|
17
|
+
this.lastLogIndex = -1;
|
|
18
|
+
this.lastLogTerm = 0;
|
|
19
|
+
this.logEntries = [];
|
|
20
|
+
this.transport = null; // For migration proposals
|
|
21
|
+
this.pendingMigrations = new Map();
|
|
22
|
+
this.committedMigrations = new Set();
|
|
23
|
+
// Generate node ID if not provided
|
|
24
|
+
this.nodeId = config.nodeId || this.generateNodeId();
|
|
25
|
+
// Configuration
|
|
26
|
+
this.heartbeatInterval = config.heartbeatInterval || 1000;
|
|
27
|
+
this.electionTimeout = config.electionTimeout || 5000;
|
|
28
|
+
// Initialize consensus state
|
|
29
|
+
this.consensusState = {
|
|
30
|
+
term: 0,
|
|
31
|
+
votedFor: null,
|
|
32
|
+
leader: null,
|
|
33
|
+
state: 'follower'
|
|
34
|
+
};
|
|
35
|
+
// Register this node
|
|
36
|
+
this.nodes.set(this.nodeId, {
|
|
37
|
+
id: this.nodeId,
|
|
38
|
+
address: config.address || 'localhost',
|
|
39
|
+
port: config.port || 3000,
|
|
40
|
+
lastSeen: Date.now(),
|
|
41
|
+
status: 'active',
|
|
42
|
+
state: 'follower',
|
|
43
|
+
lastHeartbeat: Date.now()
|
|
44
|
+
});
|
|
45
|
+
// Register other nodes if provided
|
|
46
|
+
if (config.nodes) {
|
|
47
|
+
this.registerNodes(config.nodes);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Start the coordinator
|
|
52
|
+
*/
|
|
53
|
+
async start(networkTransport) {
|
|
54
|
+
if (this.isRunning)
|
|
55
|
+
return;
|
|
56
|
+
this.isRunning = true;
|
|
57
|
+
this.networkTransport = networkTransport;
|
|
58
|
+
// Setup network message handlers if transport is provided
|
|
59
|
+
if (this.networkTransport) {
|
|
60
|
+
this.setupNetworkHandlers();
|
|
61
|
+
}
|
|
62
|
+
this.emit('started', { nodeId: this.nodeId });
|
|
63
|
+
// Start as follower
|
|
64
|
+
this.becomeFollower();
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Setup network message handlers
|
|
68
|
+
*/
|
|
69
|
+
setupNetworkHandlers() {
|
|
70
|
+
if (!this.networkTransport)
|
|
71
|
+
return;
|
|
72
|
+
// Register message handlers directly on the messageHandlers map
|
|
73
|
+
const handlers = this.networkTransport.messageHandlers;
|
|
74
|
+
// Handle vote requests
|
|
75
|
+
handlers.set('requestVote', async (msg) => {
|
|
76
|
+
const response = await this.handleVoteRequest(msg);
|
|
77
|
+
// Send response back
|
|
78
|
+
if (this.networkTransport) {
|
|
79
|
+
await this.networkTransport.sendToNode(msg.from, 'voteResponse', response);
|
|
80
|
+
}
|
|
81
|
+
return response;
|
|
82
|
+
});
|
|
83
|
+
// Handle vote responses
|
|
84
|
+
handlers.set('voteResponse', async (msg) => {
|
|
85
|
+
this.handleVoteResponse(msg);
|
|
86
|
+
});
|
|
87
|
+
// Handle heartbeats/append entries
|
|
88
|
+
handlers.set('appendEntries', async (msg) => {
|
|
89
|
+
const response = await this.handleAppendEntries(msg);
|
|
90
|
+
// Send response back
|
|
91
|
+
if (this.networkTransport) {
|
|
92
|
+
await this.networkTransport.sendToNode(msg.from, 'appendResponse', response);
|
|
93
|
+
}
|
|
94
|
+
return response;
|
|
95
|
+
});
|
|
96
|
+
// Handle append responses
|
|
97
|
+
handlers.set('appendResponse', async (msg) => {
|
|
98
|
+
this.handleAppendResponse(msg);
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Stop the coordinator
|
|
103
|
+
*/
|
|
104
|
+
async stop() {
|
|
105
|
+
if (!this.isRunning)
|
|
106
|
+
return;
|
|
107
|
+
this.isRunning = false;
|
|
108
|
+
if (this.electionTimer) {
|
|
109
|
+
clearTimeout(this.electionTimer);
|
|
110
|
+
this.electionTimer = undefined;
|
|
111
|
+
}
|
|
112
|
+
if (this.heartbeatTimer) {
|
|
113
|
+
clearInterval(this.heartbeatTimer);
|
|
114
|
+
this.heartbeatTimer = undefined;
|
|
115
|
+
}
|
|
116
|
+
this.emit('stopped');
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Register additional nodes
|
|
120
|
+
*/
|
|
121
|
+
registerNodes(nodes) {
|
|
122
|
+
for (const node of nodes) {
|
|
123
|
+
const [address, port] = node.split(':');
|
|
124
|
+
const nodeId = this.generateNodeId(node);
|
|
125
|
+
if (!this.nodes.has(nodeId)) {
|
|
126
|
+
this.nodes.set(nodeId, {
|
|
127
|
+
id: nodeId,
|
|
128
|
+
address,
|
|
129
|
+
port: parseInt(port || '3000'),
|
|
130
|
+
lastSeen: Date.now(),
|
|
131
|
+
status: 'active',
|
|
132
|
+
state: 'follower'
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Become a follower
|
|
139
|
+
*/
|
|
140
|
+
becomeFollower() {
|
|
141
|
+
this.consensusState.state = 'follower';
|
|
142
|
+
const node = this.nodes.get(this.nodeId);
|
|
143
|
+
if (node) {
|
|
144
|
+
node.state = 'follower';
|
|
145
|
+
}
|
|
146
|
+
this.resetElectionTimeout();
|
|
147
|
+
this.emit('stateChange', 'follower');
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Become a candidate and start election
|
|
151
|
+
*/
|
|
152
|
+
async becomeCandidate() {
|
|
153
|
+
this.consensusState.state = 'candidate';
|
|
154
|
+
this.currentTerm++;
|
|
155
|
+
this.consensusState.term = this.currentTerm;
|
|
156
|
+
this.consensusState.votedFor = this.nodeId;
|
|
157
|
+
this.votesReceived = new Set([this.nodeId]);
|
|
158
|
+
const node = this.nodes.get(this.nodeId);
|
|
159
|
+
if (node) {
|
|
160
|
+
node.state = 'candidate';
|
|
161
|
+
}
|
|
162
|
+
this.emit('stateChange', 'candidate');
|
|
163
|
+
// Request votes from all other nodes
|
|
164
|
+
await this.requestVotes();
|
|
165
|
+
// Reset election timeout
|
|
166
|
+
this.resetElectionTimeout();
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Become the leader
|
|
170
|
+
*/
|
|
171
|
+
becomeLeader() {
|
|
172
|
+
this.consensusState.state = 'leader';
|
|
173
|
+
this.consensusState.leader = this.nodeId;
|
|
174
|
+
const node = this.nodes.get(this.nodeId);
|
|
175
|
+
if (node) {
|
|
176
|
+
node.state = 'leader';
|
|
177
|
+
}
|
|
178
|
+
// Stop election timer as leader
|
|
179
|
+
if (this.electionTimer) {
|
|
180
|
+
clearTimeout(this.electionTimer);
|
|
181
|
+
this.electionTimer = undefined;
|
|
182
|
+
}
|
|
183
|
+
this.emit('stateChange', 'leader');
|
|
184
|
+
this.emit('leaderElected', this.nodeId);
|
|
185
|
+
// Start sending heartbeats
|
|
186
|
+
this.startHeartbeat();
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Request votes from all nodes
|
|
190
|
+
*/
|
|
191
|
+
async requestVotes() {
|
|
192
|
+
if (!this.networkTransport) {
|
|
193
|
+
// Simulate vote for testing
|
|
194
|
+
this.checkVoteMajority();
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
const voteRequest = {
|
|
198
|
+
type: 'requestVote',
|
|
199
|
+
term: this.currentTerm,
|
|
200
|
+
candidateId: this.nodeId,
|
|
201
|
+
lastLogIndex: this.getLastLogIndex(),
|
|
202
|
+
lastLogTerm: this.getLastLogTerm()
|
|
203
|
+
};
|
|
204
|
+
// Send vote requests to all other nodes
|
|
205
|
+
for (const [nodeId] of this.nodes) {
|
|
206
|
+
if (nodeId !== this.nodeId) {
|
|
207
|
+
try {
|
|
208
|
+
await this.networkTransport.sendToNode(nodeId, 'requestVote', voteRequest);
|
|
209
|
+
}
|
|
210
|
+
catch (err) {
|
|
211
|
+
console.error(`Failed to request vote from ${nodeId}:`, err);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Handle vote request from another node
|
|
218
|
+
*/
|
|
219
|
+
async handleVoteRequest(msg) {
|
|
220
|
+
const { term, candidateId, lastLogIndex, lastLogTerm } = msg.data;
|
|
221
|
+
// Update term if necessary
|
|
222
|
+
if (term > this.currentTerm) {
|
|
223
|
+
this.currentTerm = term;
|
|
224
|
+
this.consensusState.term = term;
|
|
225
|
+
this.consensusState.votedFor = null;
|
|
226
|
+
this.becomeFollower();
|
|
227
|
+
}
|
|
228
|
+
// Grant vote if conditions are met
|
|
229
|
+
let voteGranted = false;
|
|
230
|
+
if (term >= this.currentTerm &&
|
|
231
|
+
(!this.consensusState.votedFor || this.consensusState.votedFor === candidateId) &&
|
|
232
|
+
this.isLogUpToDate(lastLogIndex, lastLogTerm)) {
|
|
233
|
+
this.consensusState.votedFor = candidateId;
|
|
234
|
+
voteGranted = true;
|
|
235
|
+
this.resetElectionTimeout();
|
|
236
|
+
}
|
|
237
|
+
return {
|
|
238
|
+
type: 'voteResponse',
|
|
239
|
+
term: this.currentTerm,
|
|
240
|
+
voteGranted
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Handle vote response
|
|
245
|
+
*/
|
|
246
|
+
handleVoteResponse(msg) {
|
|
247
|
+
const { term, voteGranted } = msg.data;
|
|
248
|
+
// Ignore old responses
|
|
249
|
+
if (term < this.currentTerm)
|
|
250
|
+
return;
|
|
251
|
+
// Update term if necessary
|
|
252
|
+
if (term > this.currentTerm) {
|
|
253
|
+
this.currentTerm = term;
|
|
254
|
+
this.consensusState.term = term;
|
|
255
|
+
this.becomeFollower();
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
// Count vote if granted
|
|
259
|
+
if (voteGranted && this.consensusState.state === 'candidate') {
|
|
260
|
+
this.votesReceived.add(msg.from);
|
|
261
|
+
this.checkVoteMajority();
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Check if we have majority votes
|
|
266
|
+
*/
|
|
267
|
+
checkVoteMajority() {
|
|
268
|
+
const majority = Math.floor(this.nodes.size / 2) + 1;
|
|
269
|
+
if (this.votesReceived.size >= majority) {
|
|
270
|
+
this.becomeLeader();
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Handle append entries (heartbeat) from leader
|
|
275
|
+
*/
|
|
276
|
+
async handleAppendEntries(msg) {
|
|
277
|
+
const { term, leaderId, prevLogIndex, prevLogTerm, entries, leaderCommit } = msg.data;
|
|
278
|
+
// Update term if necessary
|
|
279
|
+
if (term > this.currentTerm) {
|
|
280
|
+
this.currentTerm = term;
|
|
281
|
+
this.consensusState.term = term;
|
|
282
|
+
this.consensusState.votedFor = null;
|
|
283
|
+
this.becomeFollower();
|
|
284
|
+
}
|
|
285
|
+
// Reset election timeout when receiving valid heartbeat
|
|
286
|
+
if (term >= this.currentTerm) {
|
|
287
|
+
this.consensusState.leader = leaderId;
|
|
288
|
+
this.resetElectionTimeout();
|
|
289
|
+
// Update leader node's last heartbeat
|
|
290
|
+
const leaderNode = this.nodes.get(leaderId);
|
|
291
|
+
if (leaderNode) {
|
|
292
|
+
leaderNode.lastHeartbeat = Date.now();
|
|
293
|
+
leaderNode.lastSeen = Date.now();
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
// Check log consistency
|
|
297
|
+
let success = false;
|
|
298
|
+
if (term >= this.currentTerm) {
|
|
299
|
+
if (this.checkLogConsistency(prevLogIndex, prevLogTerm)) {
|
|
300
|
+
// Append new entries if any
|
|
301
|
+
if (entries && entries.length > 0) {
|
|
302
|
+
this.appendLogEntries(prevLogIndex, entries);
|
|
303
|
+
}
|
|
304
|
+
success = true;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return {
|
|
308
|
+
type: 'appendResponse',
|
|
309
|
+
term: this.currentTerm,
|
|
310
|
+
success
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Handle append response from follower
|
|
315
|
+
*/
|
|
316
|
+
handleAppendResponse(msg) {
|
|
317
|
+
const { term, success } = msg.data;
|
|
318
|
+
// Update term if necessary
|
|
319
|
+
if (term > this.currentTerm) {
|
|
320
|
+
this.currentTerm = term;
|
|
321
|
+
this.consensusState.term = term;
|
|
322
|
+
this.becomeFollower();
|
|
323
|
+
}
|
|
324
|
+
// Process successful append
|
|
325
|
+
if (success && this.consensusState.state === 'leader') {
|
|
326
|
+
// Update follower's match index
|
|
327
|
+
// In a real implementation, this would track replication progress
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Send heartbeat to followers
|
|
332
|
+
*/
|
|
333
|
+
async sendHeartbeat() {
|
|
334
|
+
if (!this.networkTransport) {
|
|
335
|
+
// Fallback for testing
|
|
336
|
+
await new Promise(resolve => setTimeout(resolve, 10));
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
const heartbeat = {
|
|
340
|
+
type: 'appendEntries',
|
|
341
|
+
term: this.currentTerm,
|
|
342
|
+
leaderId: this.nodeId,
|
|
343
|
+
prevLogIndex: this.getLastLogIndex(),
|
|
344
|
+
prevLogTerm: this.getLastLogTerm(),
|
|
345
|
+
entries: [],
|
|
346
|
+
leaderCommit: 0
|
|
347
|
+
};
|
|
348
|
+
// Send heartbeat to all followers
|
|
349
|
+
for (const [nodeId] of this.nodes) {
|
|
350
|
+
if (nodeId !== this.nodeId) {
|
|
351
|
+
try {
|
|
352
|
+
await this.networkTransport.sendToNode(nodeId, 'appendEntries', heartbeat);
|
|
353
|
+
}
|
|
354
|
+
catch (err) {
|
|
355
|
+
// Node might be down, mark as suspected
|
|
356
|
+
const node = this.nodes.get(nodeId);
|
|
357
|
+
if (node) {
|
|
358
|
+
node.status = 'suspected';
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Start heartbeat timer as leader
|
|
366
|
+
*/
|
|
367
|
+
startHeartbeat() {
|
|
368
|
+
if (this.heartbeatTimer) {
|
|
369
|
+
clearInterval(this.heartbeatTimer);
|
|
370
|
+
}
|
|
371
|
+
this.heartbeatTimer = setInterval(() => {
|
|
372
|
+
this.sendHeartbeat();
|
|
373
|
+
}, this.heartbeatInterval);
|
|
374
|
+
// Send immediate heartbeat
|
|
375
|
+
this.sendHeartbeat();
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Reset election timeout
|
|
379
|
+
*/
|
|
380
|
+
resetElectionTimeout() {
|
|
381
|
+
if (this.electionTimer) {
|
|
382
|
+
clearTimeout(this.electionTimer);
|
|
383
|
+
}
|
|
384
|
+
// Randomize timeout to prevent split votes
|
|
385
|
+
const timeout = this.electionTimeout + Math.random() * this.electionTimeout;
|
|
386
|
+
this.electionTimer = setTimeout(() => {
|
|
387
|
+
if (this.consensusState.state === 'follower') {
|
|
388
|
+
this.becomeCandidate();
|
|
389
|
+
}
|
|
390
|
+
}, timeout);
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Check if log is up to date
|
|
394
|
+
*/
|
|
395
|
+
isLogUpToDate(lastLogIndex, lastLogTerm) {
|
|
396
|
+
const myLastLogTerm = this.getLastLogTerm();
|
|
397
|
+
const myLastLogIndex = this.getLastLogIndex();
|
|
398
|
+
if (lastLogTerm > myLastLogTerm)
|
|
399
|
+
return true;
|
|
400
|
+
if (lastLogTerm < myLastLogTerm)
|
|
401
|
+
return false;
|
|
402
|
+
return lastLogIndex >= myLastLogIndex;
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* Check log consistency
|
|
406
|
+
*/
|
|
407
|
+
checkLogConsistency(prevLogIndex, prevLogTerm) {
|
|
408
|
+
if (prevLogIndex === -1)
|
|
409
|
+
return true;
|
|
410
|
+
if (prevLogIndex >= this.logEntries.length)
|
|
411
|
+
return false;
|
|
412
|
+
const entry = this.logEntries[prevLogIndex];
|
|
413
|
+
return entry && entry.term === prevLogTerm;
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* Append log entries
|
|
417
|
+
*/
|
|
418
|
+
appendLogEntries(prevLogIndex, entries) {
|
|
419
|
+
// Remove conflicting entries
|
|
420
|
+
this.logEntries = this.logEntries.slice(0, prevLogIndex + 1);
|
|
421
|
+
// Append new entries
|
|
422
|
+
for (const entry of entries) {
|
|
423
|
+
this.logEntries.push({
|
|
424
|
+
term: entry.term,
|
|
425
|
+
index: this.logEntries.length,
|
|
426
|
+
data: entry.data
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
this.lastLogIndex = this.logEntries.length - 1;
|
|
430
|
+
if (this.lastLogIndex >= 0) {
|
|
431
|
+
this.lastLogTerm = this.logEntries[this.lastLogIndex].term;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Get last log index
|
|
436
|
+
*/
|
|
437
|
+
getLastLogIndex() {
|
|
438
|
+
return this.lastLogIndex;
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Get last log term
|
|
442
|
+
*/
|
|
443
|
+
getLastLogTerm() {
|
|
444
|
+
return this.lastLogTerm;
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Generate a unique node ID
|
|
448
|
+
*/
|
|
449
|
+
generateNodeId(seed) {
|
|
450
|
+
const source = seed || `${process.pid}-${Date.now()}-${Math.random()}`;
|
|
451
|
+
return createHash('sha256').update(source).digest('hex').substring(0, 16);
|
|
452
|
+
}
|
|
453
|
+
/**
|
|
454
|
+
* Get current leader
|
|
455
|
+
*/
|
|
456
|
+
getLeader() {
|
|
457
|
+
return this.consensusState.leader;
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* Propose a shard migration to the cluster
|
|
461
|
+
*/
|
|
462
|
+
async proposeMigration(migration) {
|
|
463
|
+
if (!this.isLeader()) {
|
|
464
|
+
throw new Error('Only leader can propose migrations');
|
|
465
|
+
}
|
|
466
|
+
// Broadcast migration proposal to all nodes
|
|
467
|
+
const message = {
|
|
468
|
+
type: 'migration-proposal',
|
|
469
|
+
migration,
|
|
470
|
+
timestamp: Date.now()
|
|
471
|
+
};
|
|
472
|
+
await this.transport.broadcast('migration', message);
|
|
473
|
+
// Store migration as pending
|
|
474
|
+
this.pendingMigrations.set(migration.migrationId, {
|
|
475
|
+
...migration,
|
|
476
|
+
status: 'pending'
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* Get migration status
|
|
481
|
+
*/
|
|
482
|
+
async getMigrationStatus(migrationId) {
|
|
483
|
+
const migration = this.pendingMigrations.get(migrationId);
|
|
484
|
+
if (!migration) {
|
|
485
|
+
// Check if it was committed
|
|
486
|
+
return this.committedMigrations.has(migrationId) ? 'committed' : 'rejected';
|
|
487
|
+
}
|
|
488
|
+
return migration.status || 'pending';
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* Check if this node is the leader
|
|
492
|
+
*/
|
|
493
|
+
isLeader() {
|
|
494
|
+
return this.consensusState.state === 'leader';
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* Get all nodes in the cluster
|
|
498
|
+
*/
|
|
499
|
+
getNodes() {
|
|
500
|
+
return Array.from(this.nodes.values());
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Get cluster health status
|
|
504
|
+
*/
|
|
505
|
+
getHealth() {
|
|
506
|
+
const now = Date.now();
|
|
507
|
+
const activeNodes = Array.from(this.nodes.values()).filter(node => now - node.lastSeen < this.electionTimeout).length;
|
|
508
|
+
return {
|
|
509
|
+
healthy: this.consensusState.leader !== null && activeNodes > this.nodes.size / 2,
|
|
510
|
+
leader: this.consensusState.leader,
|
|
511
|
+
nodes: this.nodes.size,
|
|
512
|
+
activeNodes
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* Propose a command to the cluster
|
|
517
|
+
*/
|
|
518
|
+
async proposeCommand(command) {
|
|
519
|
+
if (this.consensusState.state !== 'leader') {
|
|
520
|
+
throw new Error(`Not the leader. Current leader: ${this.consensusState.leader}`);
|
|
521
|
+
}
|
|
522
|
+
// Add to log
|
|
523
|
+
const entry = {
|
|
524
|
+
term: this.currentTerm,
|
|
525
|
+
index: this.logEntries.length,
|
|
526
|
+
data: command
|
|
527
|
+
};
|
|
528
|
+
this.logEntries.push(entry);
|
|
529
|
+
this.lastLogIndex = entry.index;
|
|
530
|
+
this.lastLogTerm = entry.term;
|
|
531
|
+
// Replicate to followers
|
|
532
|
+
await this.sendHeartbeat();
|
|
533
|
+
this.emit('commandProposed', command);
|
|
534
|
+
}
|
|
535
|
+
/**
|
|
536
|
+
* Get current state
|
|
537
|
+
*/
|
|
538
|
+
getState() {
|
|
539
|
+
return { ...this.consensusState };
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* Create a coordinator instance
|
|
544
|
+
*/
|
|
545
|
+
export function createCoordinator(config) {
|
|
546
|
+
return new DistributedCoordinator(config);
|
|
547
|
+
}
|
|
548
|
+
//# sourceMappingURL=coordinator.js.map
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP + SSE Transport for Zero-Config Distributed Brainy
|
|
3
|
+
* Simple, reliable, works everywhere - no WebSocket complexity!
|
|
4
|
+
* REAL PRODUCTION CODE - Handles millions of operations
|
|
5
|
+
*/
|
|
6
|
+
import * as http from 'http';
|
|
7
|
+
import { EventEmitter } from 'events';
|
|
8
|
+
export interface TransportMessage {
|
|
9
|
+
id: string;
|
|
10
|
+
method: string;
|
|
11
|
+
params: any;
|
|
12
|
+
timestamp: number;
|
|
13
|
+
from: string;
|
|
14
|
+
to?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface TransportResponse {
|
|
17
|
+
id: string;
|
|
18
|
+
result?: any;
|
|
19
|
+
error?: {
|
|
20
|
+
code: number;
|
|
21
|
+
message: string;
|
|
22
|
+
data?: any;
|
|
23
|
+
};
|
|
24
|
+
timestamp: number;
|
|
25
|
+
}
|
|
26
|
+
export interface SSEClient {
|
|
27
|
+
id: string;
|
|
28
|
+
response: http.ServerResponse;
|
|
29
|
+
lastPing: number;
|
|
30
|
+
}
|
|
31
|
+
export declare class HTTPTransport extends EventEmitter {
|
|
32
|
+
private server;
|
|
33
|
+
private port;
|
|
34
|
+
private nodeId;
|
|
35
|
+
private endpoints;
|
|
36
|
+
private pendingRequests;
|
|
37
|
+
private sseClients;
|
|
38
|
+
private messageHandlers;
|
|
39
|
+
private isRunning;
|
|
40
|
+
private readonly REQUEST_TIMEOUT;
|
|
41
|
+
private readonly SSE_HEARTBEAT_INTERVAL;
|
|
42
|
+
private sseHeartbeatTimer;
|
|
43
|
+
constructor(nodeId: string);
|
|
44
|
+
/**
|
|
45
|
+
* Start HTTP server with automatic port selection
|
|
46
|
+
*/
|
|
47
|
+
start(): Promise<number>;
|
|
48
|
+
/**
|
|
49
|
+
* Stop HTTP server
|
|
50
|
+
*/
|
|
51
|
+
stop(): Promise<void>;
|
|
52
|
+
/**
|
|
53
|
+
* Register a node endpoint
|
|
54
|
+
*/
|
|
55
|
+
registerEndpoint(nodeId: string, endpoint: string): void;
|
|
56
|
+
/**
|
|
57
|
+
* Register RPC method handler
|
|
58
|
+
*/
|
|
59
|
+
registerHandler(method: string, handler: (params: any, from: string) => Promise<any>): void;
|
|
60
|
+
/**
|
|
61
|
+
* Call RPC method on remote node
|
|
62
|
+
*/
|
|
63
|
+
call(nodeId: string, method: string, params: any): Promise<any>;
|
|
64
|
+
/**
|
|
65
|
+
* Broadcast to all SSE clients
|
|
66
|
+
*/
|
|
67
|
+
broadcast(event: string, data: any): void;
|
|
68
|
+
/**
|
|
69
|
+
* Handle health check
|
|
70
|
+
*/
|
|
71
|
+
private handleHealth;
|
|
72
|
+
/**
|
|
73
|
+
* Handle RPC requests
|
|
74
|
+
*/
|
|
75
|
+
private handleRPC;
|
|
76
|
+
/**
|
|
77
|
+
* Handle SSE connections for real-time updates
|
|
78
|
+
*/
|
|
79
|
+
private handleSSE;
|
|
80
|
+
/**
|
|
81
|
+
* Handle streaming data (for shard migration)
|
|
82
|
+
*/
|
|
83
|
+
private handleStream;
|
|
84
|
+
/**
|
|
85
|
+
* Handle stream upload (receiving data)
|
|
86
|
+
*/
|
|
87
|
+
private handleStreamUpload;
|
|
88
|
+
/**
|
|
89
|
+
* Handle stream download (sending data)
|
|
90
|
+
*/
|
|
91
|
+
private handleStreamDownload;
|
|
92
|
+
/**
|
|
93
|
+
* Send HTTP request to another node
|
|
94
|
+
*/
|
|
95
|
+
private sendHTTPRequest;
|
|
96
|
+
/**
|
|
97
|
+
* Read request body
|
|
98
|
+
*/
|
|
99
|
+
private readBody;
|
|
100
|
+
/**
|
|
101
|
+
* Find an available port
|
|
102
|
+
*/
|
|
103
|
+
private findAvailablePort;
|
|
104
|
+
/**
|
|
105
|
+
* Start SSE heartbeat to keep connections alive
|
|
106
|
+
*/
|
|
107
|
+
private startSSEHeartbeat;
|
|
108
|
+
/**
|
|
109
|
+
* Generate unique ID
|
|
110
|
+
*/
|
|
111
|
+
private generateId;
|
|
112
|
+
/**
|
|
113
|
+
* Get connected nodes count
|
|
114
|
+
*/
|
|
115
|
+
getConnectionCount(): number;
|
|
116
|
+
/**
|
|
117
|
+
* Get SSE client count
|
|
118
|
+
*/
|
|
119
|
+
getSSEClientCount(): number;
|
|
120
|
+
}
|