@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.
Files changed (260) hide show
  1. package/CHANGELOG.md +53 -3
  2. package/README.md +353 -110
  3. package/bin/brainy.js +340 -62
  4. package/dist/api/ConfigAPI.d.ts +67 -0
  5. package/dist/api/ConfigAPI.js +166 -0
  6. package/dist/api/DataAPI.d.ts +123 -0
  7. package/dist/api/DataAPI.js +391 -0
  8. package/dist/api/SecurityAPI.d.ts +50 -0
  9. package/dist/api/SecurityAPI.js +139 -0
  10. package/dist/api/UniversalImportAPI.d.ts +134 -0
  11. package/dist/api/UniversalImportAPI.js +615 -0
  12. package/dist/augmentationManager.js +12 -7
  13. package/dist/augmentationPipeline.d.ts +0 -61
  14. package/dist/augmentationPipeline.js +0 -87
  15. package/dist/augmentationRegistry.d.ts +1 -1
  16. package/dist/augmentationRegistry.js +1 -1
  17. package/dist/augmentations/apiServerAugmentation.d.ts +27 -1
  18. package/dist/augmentations/apiServerAugmentation.js +290 -9
  19. package/dist/augmentations/auditLogAugmentation.d.ts +109 -0
  20. package/dist/augmentations/auditLogAugmentation.js +358 -0
  21. package/dist/augmentations/batchProcessingAugmentation.d.ts +3 -2
  22. package/dist/augmentations/batchProcessingAugmentation.js +123 -22
  23. package/dist/augmentations/brainyAugmentation.d.ts +142 -8
  24. package/dist/augmentations/brainyAugmentation.js +179 -2
  25. package/dist/augmentations/cacheAugmentation.d.ts +8 -5
  26. package/dist/augmentations/cacheAugmentation.js +116 -17
  27. package/dist/augmentations/conduitAugmentations.d.ts +2 -2
  28. package/dist/augmentations/conduitAugmentations.js +2 -2
  29. package/dist/augmentations/configResolver.d.ts +122 -0
  30. package/dist/augmentations/configResolver.js +440 -0
  31. package/dist/augmentations/connectionPoolAugmentation.d.ts +3 -1
  32. package/dist/augmentations/connectionPoolAugmentation.js +37 -12
  33. package/dist/augmentations/defaultAugmentations.d.ts +14 -10
  34. package/dist/augmentations/defaultAugmentations.js +16 -11
  35. package/dist/augmentations/discovery/catalogDiscovery.d.ts +142 -0
  36. package/dist/augmentations/discovery/catalogDiscovery.js +249 -0
  37. package/dist/augmentations/discovery/localDiscovery.d.ts +84 -0
  38. package/dist/augmentations/discovery/localDiscovery.js +246 -0
  39. package/dist/augmentations/discovery/runtimeLoader.d.ts +97 -0
  40. package/dist/augmentations/discovery/runtimeLoader.js +337 -0
  41. package/dist/augmentations/discovery.d.ts +152 -0
  42. package/dist/augmentations/discovery.js +441 -0
  43. package/dist/augmentations/display/cache.d.ts +130 -0
  44. package/dist/augmentations/display/cache.js +319 -0
  45. package/dist/augmentations/display/fieldPatterns.d.ts +52 -0
  46. package/dist/augmentations/display/fieldPatterns.js +393 -0
  47. package/dist/augmentations/display/iconMappings.d.ts +57 -0
  48. package/dist/augmentations/display/iconMappings.js +68 -0
  49. package/dist/augmentations/display/intelligentComputation.d.ts +109 -0
  50. package/dist/augmentations/display/intelligentComputation.js +462 -0
  51. package/dist/augmentations/display/types.d.ts +203 -0
  52. package/dist/augmentations/display/types.js +7 -0
  53. package/dist/augmentations/entityRegistryAugmentation.d.ts +3 -1
  54. package/dist/augmentations/entityRegistryAugmentation.js +5 -1
  55. package/dist/augmentations/indexAugmentation.d.ts +5 -3
  56. package/dist/augmentations/indexAugmentation.js +5 -2
  57. package/dist/augmentations/intelligentVerbScoringAugmentation.d.ts +24 -7
  58. package/dist/augmentations/intelligentVerbScoringAugmentation.js +111 -27
  59. package/dist/augmentations/manifest.d.ts +176 -0
  60. package/dist/augmentations/manifest.js +8 -0
  61. package/dist/augmentations/marketplace/AugmentationMarketplace.d.ts +168 -0
  62. package/dist/augmentations/marketplace/AugmentationMarketplace.js +329 -0
  63. package/dist/augmentations/marketplace/cli.d.ts +47 -0
  64. package/dist/augmentations/marketplace/cli.js +265 -0
  65. package/dist/augmentations/metricsAugmentation.d.ts +3 -3
  66. package/dist/augmentations/metricsAugmentation.js +2 -2
  67. package/dist/augmentations/monitoringAugmentation.d.ts +3 -3
  68. package/dist/augmentations/monitoringAugmentation.js +2 -2
  69. package/dist/augmentations/neuralImport.d.ts +1 -1
  70. package/dist/augmentations/neuralImport.js +4 -4
  71. package/dist/augmentations/rateLimitAugmentation.d.ts +82 -0
  72. package/dist/augmentations/rateLimitAugmentation.js +321 -0
  73. package/dist/augmentations/requestDeduplicatorAugmentation.d.ts +2 -2
  74. package/dist/augmentations/requestDeduplicatorAugmentation.js +1 -1
  75. package/dist/augmentations/storageAugmentation.d.ts +1 -1
  76. package/dist/augmentations/storageAugmentation.js +2 -2
  77. package/dist/augmentations/storageAugmentations.d.ts +37 -8
  78. package/dist/augmentations/storageAugmentations.js +204 -15
  79. package/dist/augmentations/synapseAugmentation.d.ts +1 -1
  80. package/dist/augmentations/synapseAugmentation.js +35 -16
  81. package/dist/augmentations/typeMatching/brainyTypes.d.ts +83 -0
  82. package/dist/augmentations/typeMatching/brainyTypes.js +425 -0
  83. package/dist/augmentations/typeMatching/intelligentTypeMatcher.d.ts +39 -59
  84. package/dist/augmentations/typeMatching/intelligentTypeMatcher.js +103 -389
  85. package/dist/augmentations/universalDisplayAugmentation.d.ts +191 -0
  86. package/dist/augmentations/universalDisplayAugmentation.js +371 -0
  87. package/dist/brainy-unified.d.ts +106 -0
  88. package/dist/brainy-unified.js +327 -0
  89. package/dist/brainy.d.ts +273 -0
  90. package/dist/brainy.js +1181 -0
  91. package/dist/brainyData.d.ts +56 -111
  92. package/dist/brainyData.js +912 -756
  93. package/dist/brainyDataV3.d.ts +186 -0
  94. package/dist/brainyDataV3.js +337 -0
  95. package/dist/browserFramework.d.ts +6 -6
  96. package/dist/browserFramework.js +11 -8
  97. package/dist/browserFramework.minimal.d.ts +5 -5
  98. package/dist/browserFramework.minimal.js +11 -8
  99. package/dist/config/distributedPresets-new.d.ts +118 -0
  100. package/dist/config/distributedPresets-new.js +318 -0
  101. package/dist/config/distributedPresets.d.ts +118 -0
  102. package/dist/config/distributedPresets.js +318 -0
  103. package/dist/config/extensibleConfig.d.ts +99 -0
  104. package/dist/config/extensibleConfig.js +268 -0
  105. package/dist/config/index.d.ts +17 -0
  106. package/dist/config/index.js +35 -0
  107. package/dist/config/modelAutoConfig.d.ts +32 -0
  108. package/dist/config/modelAutoConfig.js +139 -0
  109. package/dist/config/modelPrecisionManager.d.ts +42 -0
  110. package/dist/config/modelPrecisionManager.js +98 -0
  111. package/dist/config/sharedConfigManager.d.ts +67 -0
  112. package/dist/config/sharedConfigManager.js +215 -0
  113. package/dist/config/storageAutoConfig.d.ts +41 -0
  114. package/dist/config/storageAutoConfig.js +328 -0
  115. package/dist/config/zeroConfig.d.ts +68 -0
  116. package/dist/config/zeroConfig.js +301 -0
  117. package/dist/cortex/backupRestore.d.ts +2 -2
  118. package/dist/cortex/backupRestore.js +85 -27
  119. package/dist/cortex/healthCheck.d.ts +2 -2
  120. package/dist/cortex/neuralImport.d.ts +2 -2
  121. package/dist/cortex/neuralImport.js +18 -13
  122. package/dist/cortex/performanceMonitor.d.ts +2 -2
  123. package/dist/critical/model-guardian.d.ts +4 -0
  124. package/dist/critical/model-guardian.js +31 -11
  125. package/dist/demo.d.ts +4 -4
  126. package/dist/demo.js +7 -7
  127. package/dist/distributed/cacheSync.d.ts +112 -0
  128. package/dist/distributed/cacheSync.js +265 -0
  129. package/dist/distributed/coordinator.d.ts +193 -0
  130. package/dist/distributed/coordinator.js +548 -0
  131. package/dist/distributed/httpTransport.d.ts +120 -0
  132. package/dist/distributed/httpTransport.js +446 -0
  133. package/dist/distributed/index.d.ts +8 -0
  134. package/dist/distributed/index.js +5 -0
  135. package/dist/distributed/networkTransport.d.ts +132 -0
  136. package/dist/distributed/networkTransport.js +633 -0
  137. package/dist/distributed/queryPlanner.d.ts +104 -0
  138. package/dist/distributed/queryPlanner.js +327 -0
  139. package/dist/distributed/readWriteSeparation.d.ts +134 -0
  140. package/dist/distributed/readWriteSeparation.js +350 -0
  141. package/dist/distributed/shardManager.d.ts +114 -0
  142. package/dist/distributed/shardManager.js +357 -0
  143. package/dist/distributed/shardMigration.d.ts +110 -0
  144. package/dist/distributed/shardMigration.js +289 -0
  145. package/dist/distributed/storageDiscovery.d.ts +160 -0
  146. package/dist/distributed/storageDiscovery.js +551 -0
  147. package/dist/embeddings/CachedEmbeddings.d.ts +40 -0
  148. package/dist/embeddings/CachedEmbeddings.js +146 -0
  149. package/dist/embeddings/EmbeddingManager.d.ts +102 -0
  150. package/dist/embeddings/EmbeddingManager.js +291 -0
  151. package/dist/embeddings/SingletonModelManager.d.ts +95 -0
  152. package/dist/embeddings/SingletonModelManager.js +220 -0
  153. package/dist/embeddings/index.d.ts +12 -0
  154. package/dist/embeddings/index.js +16 -0
  155. package/dist/embeddings/lightweight-embedder.d.ts +0 -1
  156. package/dist/embeddings/lightweight-embedder.js +4 -12
  157. package/dist/embeddings/model-manager.d.ts +11 -0
  158. package/dist/embeddings/model-manager.js +43 -7
  159. package/dist/embeddings/universal-memory-manager.d.ts +1 -1
  160. package/dist/embeddings/universal-memory-manager.js +27 -67
  161. package/dist/embeddings/worker-embedding.js +4 -8
  162. package/dist/errors/brainyError.d.ts +5 -1
  163. package/dist/errors/brainyError.js +12 -0
  164. package/dist/examples/basicUsage.js +7 -4
  165. package/dist/graph/graphAdjacencyIndex.d.ts +96 -0
  166. package/dist/graph/graphAdjacencyIndex.js +288 -0
  167. package/dist/graph/pathfinding.js +4 -2
  168. package/dist/hnsw/scaledHNSWSystem.js +11 -2
  169. package/dist/importManager.js +8 -5
  170. package/dist/index.d.ts +17 -22
  171. package/dist/index.js +37 -23
  172. package/dist/mcp/brainyMCPAdapter.d.ts +4 -4
  173. package/dist/mcp/brainyMCPAdapter.js +5 -5
  174. package/dist/mcp/brainyMCPService.d.ts +3 -3
  175. package/dist/mcp/brainyMCPService.js +3 -11
  176. package/dist/mcp/mcpAugmentationToolset.js +20 -30
  177. package/dist/neural/embeddedPatterns.d.ts +1 -1
  178. package/dist/neural/embeddedPatterns.js +2 -2
  179. package/dist/neural/entityExtractor.d.ts +65 -0
  180. package/dist/neural/entityExtractor.js +316 -0
  181. package/dist/neural/improvedNeuralAPI.d.ts +357 -0
  182. package/dist/neural/improvedNeuralAPI.js +2628 -0
  183. package/dist/neural/naturalLanguageProcessor.d.ts +155 -10
  184. package/dist/neural/naturalLanguageProcessor.js +941 -66
  185. package/dist/neural/naturalLanguageProcessorStatic.d.ts +2 -2
  186. package/dist/neural/naturalLanguageProcessorStatic.js +3 -3
  187. package/dist/neural/neuralAPI.js +8 -2
  188. package/dist/neural/patternLibrary.d.ts +57 -3
  189. package/dist/neural/patternLibrary.js +348 -13
  190. package/dist/neural/staticPatternMatcher.d.ts +2 -2
  191. package/dist/neural/staticPatternMatcher.js +2 -2
  192. package/dist/neural/types.d.ts +287 -0
  193. package/dist/neural/types.js +24 -0
  194. package/dist/shared/default-augmentations.d.ts +3 -3
  195. package/dist/shared/default-augmentations.js +5 -5
  196. package/dist/storage/adapters/baseStorageAdapter.d.ts +42 -0
  197. package/dist/storage/adapters/fileSystemStorage.d.ts +26 -2
  198. package/dist/storage/adapters/fileSystemStorage.js +218 -15
  199. package/dist/storage/adapters/memoryStorage.d.ts +4 -4
  200. package/dist/storage/adapters/memoryStorage.js +17 -12
  201. package/dist/storage/adapters/opfsStorage.d.ts +2 -2
  202. package/dist/storage/adapters/opfsStorage.js +2 -2
  203. package/dist/storage/adapters/s3CompatibleStorage.d.ts +2 -2
  204. package/dist/storage/adapters/s3CompatibleStorage.js +2 -2
  205. package/dist/storage/backwardCompatibility.d.ts +10 -78
  206. package/dist/storage/backwardCompatibility.js +17 -132
  207. package/dist/storage/baseStorage.d.ts +18 -2
  208. package/dist/storage/baseStorage.js +74 -3
  209. package/dist/storage/cacheManager.js +2 -2
  210. package/dist/storage/readOnlyOptimizations.js +8 -3
  211. package/dist/streaming/pipeline.d.ts +154 -0
  212. package/dist/streaming/pipeline.js +551 -0
  213. package/dist/triple/TripleIntelligence.d.ts +25 -110
  214. package/dist/triple/TripleIntelligence.js +4 -574
  215. package/dist/triple/TripleIntelligenceSystem.d.ts +159 -0
  216. package/dist/triple/TripleIntelligenceSystem.js +519 -0
  217. package/dist/types/apiTypes.d.ts +278 -0
  218. package/dist/types/apiTypes.js +33 -0
  219. package/dist/types/brainy.types.d.ts +308 -0
  220. package/dist/types/brainy.types.js +8 -0
  221. package/dist/types/brainyDataInterface.d.ts +5 -8
  222. package/dist/types/brainyDataInterface.js +2 -2
  223. package/dist/types/graphTypes.js +2 -2
  224. package/dist/utils/brainyTypes.d.ts +217 -0
  225. package/dist/utils/brainyTypes.js +261 -0
  226. package/dist/utils/cacheAutoConfig.d.ts +3 -3
  227. package/dist/utils/embedding.d.ts +9 -4
  228. package/dist/utils/embedding.js +89 -26
  229. package/dist/utils/enhancedLogger.d.ts +104 -0
  230. package/dist/utils/enhancedLogger.js +232 -0
  231. package/dist/utils/hybridModelManager.d.ts +19 -28
  232. package/dist/utils/hybridModelManager.js +36 -200
  233. package/dist/utils/index.d.ts +1 -1
  234. package/dist/utils/index.js +1 -1
  235. package/dist/utils/intelligentTypeMapper.d.ts +60 -0
  236. package/dist/utils/intelligentTypeMapper.js +349 -0
  237. package/dist/utils/metadataIndex.d.ts +118 -1
  238. package/dist/utils/metadataIndex.js +539 -16
  239. package/dist/utils/nodeVersionCheck.d.ts +24 -0
  240. package/dist/utils/nodeVersionCheck.js +65 -0
  241. package/dist/utils/paramValidation.d.ts +39 -0
  242. package/dist/utils/paramValidation.js +192 -0
  243. package/dist/utils/rateLimiter.d.ts +160 -0
  244. package/dist/utils/rateLimiter.js +271 -0
  245. package/dist/utils/statistics.d.ts +4 -4
  246. package/dist/utils/statistics.js +3 -3
  247. package/dist/utils/structuredLogger.d.ts +146 -0
  248. package/dist/utils/structuredLogger.js +394 -0
  249. package/dist/utils/textEncoding.js +2 -1
  250. package/dist/utils/typeValidation.d.ts +59 -0
  251. package/dist/utils/typeValidation.js +374 -0
  252. package/dist/utils/version.js +19 -3
  253. package/package.json +15 -4
  254. package/scripts/download-models.cjs +94 -20
  255. package/dist/augmentations/walAugmentation.d.ts +0 -109
  256. package/dist/augmentations/walAugmentation.js +0 -516
  257. package/dist/chat/BrainyChat.d.ts +0 -121
  258. package/dist/chat/BrainyChat.js +0 -396
  259. package/dist/chat/ChatCLI.d.ts +0 -61
  260. package/dist/chat/ChatCLI.js +0 -351
@@ -0,0 +1,551 @@
1
+ /**
2
+ * Storage-based Discovery for Zero-Config Distributed Brainy
3
+ * Uses shared storage (S3/GCS/R2) as coordination point
4
+ * REAL PRODUCTION CODE - No mocks, no stubs!
5
+ */
6
+ import { EventEmitter } from 'events';
7
+ import * as os from 'os';
8
+ export class StorageDiscovery extends EventEmitter {
9
+ constructor(storage, nodeId) {
10
+ super();
11
+ this.clusterConfig = null;
12
+ this.heartbeatInterval = null;
13
+ this.discoveryInterval = null;
14
+ this.endpoint = '';
15
+ this.isRunning = false;
16
+ this.HEARTBEAT_INTERVAL = 5000; // 5 seconds
17
+ this.DISCOVERY_INTERVAL = 2000; // 2 seconds
18
+ this.NODE_TIMEOUT = 30000; // 30 seconds until node considered dead
19
+ this.CLUSTER_PATH = '_cluster';
20
+ this.storage = storage;
21
+ this.nodeId = nodeId || this.generateNodeId();
22
+ // Initialize node info with REAL system data
23
+ this.nodeInfo = {
24
+ id: this.nodeId,
25
+ endpoint: '', // Will be set when HTTP server starts
26
+ hostname: os.hostname(),
27
+ started: Date.now(),
28
+ lastSeen: Date.now(),
29
+ role: 'candidate',
30
+ shards: [],
31
+ capacity: {
32
+ cpu: os.cpus().length,
33
+ memory: Math.floor(os.totalmem() / 1024 / 1024), // MB
34
+ storage: 0 // Will be updated based on actual usage
35
+ },
36
+ stats: {
37
+ nouns: 0,
38
+ verbs: 0,
39
+ queries: 0,
40
+ latency: 0
41
+ }
42
+ };
43
+ }
44
+ /**
45
+ * Start discovery and registration
46
+ */
47
+ async start(httpPort) {
48
+ if (this.isRunning)
49
+ return this.clusterConfig;
50
+ this.isRunning = true;
51
+ // Set our endpoint
52
+ this.endpoint = await this.detectEndpoint(httpPort);
53
+ this.nodeInfo.endpoint = this.endpoint;
54
+ // Try to load existing cluster config
55
+ this.clusterConfig = await this.loadClusterConfig();
56
+ if (!this.clusterConfig) {
57
+ // We're the first node - initialize cluster
58
+ await this.initializeCluster();
59
+ }
60
+ else {
61
+ // Join existing cluster
62
+ await this.joinCluster();
63
+ }
64
+ // Start heartbeat to keep our node alive
65
+ this.startHeartbeat();
66
+ // Start discovery to find other nodes
67
+ this.startDiscovery();
68
+ this.emit('started', this.nodeInfo);
69
+ return this.clusterConfig;
70
+ }
71
+ /**
72
+ * Stop discovery and unregister
73
+ */
74
+ async stop() {
75
+ if (!this.isRunning)
76
+ return;
77
+ this.isRunning = false;
78
+ // Stop intervals
79
+ if (this.heartbeatInterval) {
80
+ clearInterval(this.heartbeatInterval);
81
+ this.heartbeatInterval = null;
82
+ }
83
+ if (this.discoveryInterval) {
84
+ clearInterval(this.discoveryInterval);
85
+ this.discoveryInterval = null;
86
+ }
87
+ // Remove ourselves from cluster
88
+ await this.leaveCluster();
89
+ this.emit('stopped');
90
+ }
91
+ /**
92
+ * Initialize a new cluster (we're the first node)
93
+ */
94
+ async initializeCluster() {
95
+ console.log(`[${this.nodeId}] Initializing new cluster as first node`);
96
+ this.nodeInfo.role = 'primary';
97
+ this.clusterConfig = {
98
+ version: 1,
99
+ created: Date.now(),
100
+ updated: Date.now(),
101
+ leader: this.nodeId,
102
+ nodes: {
103
+ [this.nodeId]: this.nodeInfo
104
+ },
105
+ shards: {
106
+ count: 64, // Default shard count
107
+ assignments: {}
108
+ },
109
+ settings: {
110
+ replicationFactor: 3,
111
+ shardCount: 64,
112
+ autoRebalance: true,
113
+ minNodes: 1,
114
+ maxNodesPerShard: 5
115
+ }
116
+ };
117
+ // Assign all shards to ourselves initially
118
+ for (let i = 0; i < this.clusterConfig.shards.count; i++) {
119
+ const shardId = `shard-${i.toString().padStart(3, '0')}`;
120
+ this.clusterConfig.shards.assignments[shardId] = [this.nodeId];
121
+ this.nodeInfo.shards.push(shardId);
122
+ }
123
+ // Save cluster config
124
+ await this.saveClusterConfig();
125
+ // Register ourselves
126
+ await this.registerNode();
127
+ this.emit('clusterInitialized', this.clusterConfig);
128
+ }
129
+ /**
130
+ * Join an existing cluster
131
+ */
132
+ async joinCluster() {
133
+ console.log(`[${this.nodeId}] Joining existing cluster`);
134
+ if (!this.clusterConfig)
135
+ throw new Error('No cluster config');
136
+ // Add ourselves to the cluster
137
+ this.clusterConfig.nodes[this.nodeId] = this.nodeInfo;
138
+ // Determine our role based on cluster state
139
+ const nodeCount = Object.keys(this.clusterConfig.nodes).length;
140
+ if (!this.clusterConfig.leader || !this.clusterConfig.nodes[this.clusterConfig.leader]) {
141
+ // No leader or leader is gone - trigger election
142
+ await this.triggerLeaderElection();
143
+ }
144
+ else {
145
+ // Become replica
146
+ this.nodeInfo.role = 'replica';
147
+ }
148
+ // Register ourselves
149
+ await this.registerNode();
150
+ // Request shard assignment if auto-rebalance is enabled
151
+ if (this.clusterConfig.settings.autoRebalance) {
152
+ await this.requestShardAssignment();
153
+ }
154
+ this.emit('clusterJoined', this.clusterConfig);
155
+ }
156
+ /**
157
+ * Leave cluster cleanly
158
+ */
159
+ async leaveCluster() {
160
+ if (!this.clusterConfig)
161
+ return;
162
+ console.log(`[${this.nodeId}] Leaving cluster`);
163
+ // Remove ourselves from node registry
164
+ try {
165
+ // Mark as deleted rather than actually deleting
166
+ const deadNode = { ...this.nodeInfo, lastSeen: 0, status: 'inactive' };
167
+ await this.storage.saveMetadata(`${this.CLUSTER_PATH}/nodes/${this.nodeId}.json`, deadNode);
168
+ }
169
+ catch (err) {
170
+ // Ignore errors during shutdown
171
+ }
172
+ // If we're the leader, trigger new election
173
+ if (this.clusterConfig.leader === this.nodeId) {
174
+ this.clusterConfig.leader = null;
175
+ await this.saveClusterConfig();
176
+ }
177
+ this.emit('clusterLeft');
178
+ }
179
+ /**
180
+ * Register node in storage
181
+ */
182
+ async registerNode() {
183
+ const path = `${this.CLUSTER_PATH}/nodes/${this.nodeId}.json`;
184
+ await this.storage.saveMetadata(path, this.nodeInfo);
185
+ // Also update registry
186
+ await this.updateNodeRegistry(this.nodeId);
187
+ }
188
+ /**
189
+ * Heartbeat to keep node alive
190
+ */
191
+ startHeartbeat() {
192
+ this.heartbeatInterval = setInterval(async () => {
193
+ try {
194
+ this.nodeInfo.lastSeen = Date.now();
195
+ await this.registerNode();
196
+ // Also update cluster config if we're the leader
197
+ if (this.clusterConfig && this.clusterConfig.leader === this.nodeId) {
198
+ await this.saveClusterConfig();
199
+ }
200
+ }
201
+ catch (err) {
202
+ console.error(`[${this.nodeId}] Heartbeat failed:`, err);
203
+ }
204
+ }, this.HEARTBEAT_INTERVAL);
205
+ }
206
+ /**
207
+ * Discover other nodes and monitor health
208
+ */
209
+ startDiscovery() {
210
+ this.discoveryInterval = setInterval(async () => {
211
+ try {
212
+ await this.discoverNodes();
213
+ await this.checkNodeHealth();
214
+ // Check if we need to rebalance
215
+ if (this.shouldRebalance()) {
216
+ await this.triggerRebalance();
217
+ }
218
+ }
219
+ catch (err) {
220
+ console.error(`[${this.nodeId}] Discovery failed:`, err);
221
+ }
222
+ }, this.DISCOVERY_INTERVAL);
223
+ }
224
+ /**
225
+ * Discover nodes from storage
226
+ */
227
+ async discoverNodes() {
228
+ try {
229
+ // Since we can't list arbitrary paths, we'll use a registry approach
230
+ // Each node registers in a central registry file
231
+ const registry = await this.loadNodeRegistry();
232
+ const now = Date.now();
233
+ let updated = false;
234
+ for (const nodeId of registry) {
235
+ if (nodeId === this.nodeId)
236
+ continue;
237
+ try {
238
+ const nodeInfo = await this.storage.getMetadata(`${this.CLUSTER_PATH}/nodes/${nodeId}.json`);
239
+ // Check if node is alive
240
+ if (now - nodeInfo.lastSeen < this.NODE_TIMEOUT) {
241
+ if (!this.clusterConfig.nodes[nodeId]) {
242
+ // New node discovered!
243
+ console.log(`[${this.nodeId}] Discovered new node: ${nodeId}`);
244
+ this.clusterConfig.nodes[nodeId] = nodeInfo;
245
+ updated = true;
246
+ this.emit('nodeDiscovered', nodeInfo);
247
+ }
248
+ else {
249
+ // Update existing node info
250
+ this.clusterConfig.nodes[nodeId] = nodeInfo;
251
+ }
252
+ }
253
+ }
254
+ catch (err) {
255
+ // Node file might be corrupted or deleted
256
+ console.warn(`[${this.nodeId}] Failed to read node ${nodeId}:`, err);
257
+ }
258
+ }
259
+ if (updated) {
260
+ this.clusterConfig.version++;
261
+ this.clusterConfig.updated = Date.now();
262
+ }
263
+ }
264
+ catch (err) {
265
+ // Storage might be unavailable
266
+ console.error(`[${this.nodeId}] Failed to discover nodes:`, err);
267
+ }
268
+ }
269
+ /**
270
+ * Load node registry from storage
271
+ */
272
+ async loadNodeRegistry() {
273
+ try {
274
+ const registry = await this.storage.getMetadata(`${this.CLUSTER_PATH}/registry.json`);
275
+ return registry?.nodes || [];
276
+ }
277
+ catch (err) {
278
+ return [];
279
+ }
280
+ }
281
+ /**
282
+ * Update node registry in storage
283
+ */
284
+ async updateNodeRegistry(add, remove) {
285
+ try {
286
+ let registry = await this.loadNodeRegistry();
287
+ if (add && !registry.includes(add)) {
288
+ registry.push(add);
289
+ }
290
+ if (remove) {
291
+ registry = registry.filter(id => id !== remove);
292
+ }
293
+ await this.storage.saveMetadata(`${this.CLUSTER_PATH}/registry.json`, {
294
+ nodes: registry,
295
+ updated: Date.now()
296
+ });
297
+ }
298
+ catch (err) {
299
+ console.error(`[${this.nodeId}] Failed to update registry:`, err);
300
+ }
301
+ }
302
+ /**
303
+ * Check health of known nodes
304
+ */
305
+ async checkNodeHealth() {
306
+ if (!this.clusterConfig)
307
+ return;
308
+ const now = Date.now();
309
+ const deadNodes = [];
310
+ for (const [nodeId, nodeInfo] of Object.entries(this.clusterConfig.nodes)) {
311
+ if (nodeId === this.nodeId)
312
+ continue;
313
+ if (now - nodeInfo.lastSeen > this.NODE_TIMEOUT) {
314
+ console.log(`[${this.nodeId}] Node ${nodeId} is dead (last seen ${now - nodeInfo.lastSeen}ms ago)`);
315
+ deadNodes.push(nodeId);
316
+ }
317
+ }
318
+ // Remove dead nodes
319
+ for (const nodeId of deadNodes) {
320
+ delete this.clusterConfig.nodes[nodeId];
321
+ this.emit('nodeLost', nodeId);
322
+ // If dead node was leader, trigger election
323
+ if (this.clusterConfig.leader === nodeId) {
324
+ await this.triggerLeaderElection();
325
+ }
326
+ }
327
+ if (deadNodes.length > 0) {
328
+ // Trigger rebalance to reassign shards from dead nodes
329
+ await this.triggerRebalance();
330
+ }
331
+ }
332
+ /**
333
+ * Load cluster configuration from storage
334
+ */
335
+ async loadClusterConfig() {
336
+ try {
337
+ const config = await this.storage.getMetadata(`${this.CLUSTER_PATH}/config.json`);
338
+ return config;
339
+ }
340
+ catch (err) {
341
+ // No cluster config exists yet
342
+ return null;
343
+ }
344
+ }
345
+ /**
346
+ * Save cluster configuration to storage
347
+ */
348
+ async saveClusterConfig() {
349
+ if (!this.clusterConfig)
350
+ return;
351
+ await this.storage.saveMetadata(`${this.CLUSTER_PATH}/config.json`, this.clusterConfig);
352
+ }
353
+ /**
354
+ * Trigger leader election (simplified - not full Raft)
355
+ */
356
+ async triggerLeaderElection() {
357
+ console.log(`[${this.nodeId}] Triggering leader election`);
358
+ // Simple election: node with lowest ID wins
359
+ // In production, use proper Raft consensus
360
+ const activeNodes = Object.entries(this.clusterConfig.nodes)
361
+ .filter(([_, info]) => Date.now() - info.lastSeen < this.NODE_TIMEOUT)
362
+ .sort(([a], [b]) => a.localeCompare(b));
363
+ if (activeNodes.length > 0) {
364
+ const [leaderId, leaderInfo] = activeNodes[0];
365
+ this.clusterConfig.leader = leaderId;
366
+ if (leaderId === this.nodeId) {
367
+ console.log(`[${this.nodeId}] Became leader`);
368
+ this.nodeInfo.role = 'primary';
369
+ this.emit('becameLeader');
370
+ }
371
+ else {
372
+ console.log(`[${this.nodeId}] Node ${leaderId} is the new leader`);
373
+ this.nodeInfo.role = 'replica';
374
+ this.emit('leaderElected', leaderId);
375
+ }
376
+ await this.saveClusterConfig();
377
+ }
378
+ }
379
+ /**
380
+ * Request shard assignment for this node
381
+ */
382
+ async requestShardAssignment() {
383
+ if (!this.clusterConfig)
384
+ return;
385
+ // Calculate how many shards each node should have
386
+ const nodeCount = Object.keys(this.clusterConfig.nodes).length;
387
+ const shardsPerNode = Math.ceil(this.clusterConfig.shards.count / nodeCount);
388
+ // Find shards that need assignment
389
+ const unassignedShards = [];
390
+ for (let i = 0; i < this.clusterConfig.shards.count; i++) {
391
+ const shardId = `shard-${i.toString().padStart(3, '0')}`;
392
+ if (!this.clusterConfig.shards.assignments[shardId] ||
393
+ this.clusterConfig.shards.assignments[shardId].length === 0) {
394
+ unassignedShards.push(shardId);
395
+ }
396
+ }
397
+ // Assign some shards to ourselves
398
+ const ourShare = unassignedShards.slice(0, shardsPerNode);
399
+ for (const shardId of ourShare) {
400
+ this.clusterConfig.shards.assignments[shardId] = [this.nodeId];
401
+ this.nodeInfo.shards.push(shardId);
402
+ }
403
+ if (ourShare.length > 0) {
404
+ console.log(`[${this.nodeId}] Assigned ${ourShare.length} shards`);
405
+ await this.saveClusterConfig();
406
+ }
407
+ }
408
+ /**
409
+ * Check if rebalancing is needed
410
+ */
411
+ shouldRebalance() {
412
+ if (!this.clusterConfig || !this.clusterConfig.settings.autoRebalance) {
413
+ return false;
414
+ }
415
+ // Check if shards are evenly distributed
416
+ const nodeCount = Object.keys(this.clusterConfig.nodes).length;
417
+ if (nodeCount <= 1)
418
+ return false;
419
+ const targetShardsPerNode = Math.ceil(this.clusterConfig.shards.count / nodeCount);
420
+ const variance = 2; // Allow some variance
421
+ for (const nodeInfo of Object.values(this.clusterConfig.nodes)) {
422
+ const shardCount = nodeInfo.shards.length;
423
+ if (Math.abs(shardCount - targetShardsPerNode) > variance) {
424
+ return true;
425
+ }
426
+ }
427
+ return false;
428
+ }
429
+ /**
430
+ * Trigger shard rebalancing
431
+ */
432
+ async triggerRebalance() {
433
+ // Only leader can trigger rebalance
434
+ if (this.clusterConfig?.leader !== this.nodeId)
435
+ return;
436
+ console.log(`[${this.nodeId}] Triggering shard rebalance`);
437
+ // This will be implemented with actual data migration
438
+ // For now, just redistribute shard assignments
439
+ await this.redistributeShards();
440
+ this.emit('rebalanceTriggered');
441
+ }
442
+ /**
443
+ * Redistribute shards among active nodes
444
+ */
445
+ async redistributeShards() {
446
+ if (!this.clusterConfig)
447
+ return;
448
+ const activeNodes = Object.keys(this.clusterConfig.nodes)
449
+ .filter(id => Date.now() - this.clusterConfig.nodes[id].lastSeen < this.NODE_TIMEOUT);
450
+ if (activeNodes.length === 0)
451
+ return;
452
+ const shardsPerNode = Math.ceil(this.clusterConfig.shards.count / activeNodes.length);
453
+ const newAssignments = {};
454
+ // Clear current shard assignments from nodes
455
+ for (const nodeInfo of Object.values(this.clusterConfig.nodes)) {
456
+ nodeInfo.shards = [];
457
+ }
458
+ // Redistribute shards
459
+ let nodeIndex = 0;
460
+ for (let i = 0; i < this.clusterConfig.shards.count; i++) {
461
+ const shardId = `shard-${i.toString().padStart(3, '0')}`;
462
+ const primaryNode = activeNodes[nodeIndex % activeNodes.length];
463
+ // Assign primary
464
+ newAssignments[shardId] = [primaryNode];
465
+ this.clusterConfig.nodes[primaryNode].shards.push(shardId);
466
+ // Assign replicas
467
+ const replicas = [];
468
+ for (let r = 1; r < Math.min(this.clusterConfig.settings.replicationFactor, activeNodes.length); r++) {
469
+ const replicaNode = activeNodes[(nodeIndex + r) % activeNodes.length];
470
+ if (replicaNode !== primaryNode) {
471
+ replicas.push(replicaNode);
472
+ }
473
+ }
474
+ if (replicas.length > 0) {
475
+ newAssignments[shardId].push(...replicas);
476
+ }
477
+ nodeIndex++;
478
+ }
479
+ this.clusterConfig.shards.assignments = newAssignments;
480
+ this.clusterConfig.version++;
481
+ this.clusterConfig.updated = Date.now();
482
+ await this.saveClusterConfig();
483
+ console.log(`[${this.nodeId}] Rebalanced ${this.clusterConfig.shards.count} shards across ${activeNodes.length} nodes`);
484
+ }
485
+ /**
486
+ * Detect our public endpoint
487
+ */
488
+ async detectEndpoint(port) {
489
+ // Try to detect public IP
490
+ const interfaces = os.networkInterfaces();
491
+ let ip = '127.0.0.1';
492
+ // Find first non-internal IPv4 address
493
+ for (const iface of Object.values(interfaces)) {
494
+ if (!iface)
495
+ continue;
496
+ for (const addr of iface) {
497
+ if (addr.family === 'IPv4' && !addr.internal) {
498
+ ip = addr.address;
499
+ break;
500
+ }
501
+ }
502
+ }
503
+ // In cloud environments, might need to detect public IP differently
504
+ if (process.env.PUBLIC_IP) {
505
+ ip = process.env.PUBLIC_IP;
506
+ }
507
+ else if (process.env.KUBERNETES_SERVICE_HOST) {
508
+ // In Kubernetes, use pod IP
509
+ ip = process.env.POD_IP || ip;
510
+ }
511
+ return `http://${ip}:${port}`;
512
+ }
513
+ /**
514
+ * Generate unique node ID
515
+ */
516
+ generateNodeId() {
517
+ const hostname = os.hostname();
518
+ const pid = process.pid;
519
+ const random = Math.random().toString(36).substring(2, 8);
520
+ return `${hostname}-${pid}-${random}`;
521
+ }
522
+ /**
523
+ * Get current cluster configuration
524
+ */
525
+ getClusterConfig() {
526
+ return this.clusterConfig;
527
+ }
528
+ /**
529
+ * Get active nodes
530
+ */
531
+ getActiveNodes() {
532
+ if (!this.clusterConfig)
533
+ return [];
534
+ const now = Date.now();
535
+ return Object.values(this.clusterConfig.nodes)
536
+ .filter(node => now - node.lastSeen < this.NODE_TIMEOUT);
537
+ }
538
+ /**
539
+ * Get shards assigned to this node
540
+ */
541
+ getMyShards() {
542
+ return this.nodeInfo.shards;
543
+ }
544
+ /**
545
+ * Update node statistics
546
+ */
547
+ updateStats(stats) {
548
+ Object.assign(this.nodeInfo.stats, stats);
549
+ }
550
+ }
551
+ //# sourceMappingURL=storageDiscovery.js.map
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Cached Embeddings - Performance Optimization Layer
3
+ *
4
+ * Provides pre-computed embeddings for common terms to avoid
5
+ * unnecessary model calls. Falls back to EmbeddingManager for
6
+ * unknown terms.
7
+ *
8
+ * This is purely a performance optimization - it doesn't affect
9
+ * the consistency or accuracy of embeddings.
10
+ */
11
+ import { Vector } from '../coreTypes.js';
12
+ /**
13
+ * Cached Embeddings with fallback to EmbeddingManager
14
+ */
15
+ export declare class CachedEmbeddings {
16
+ private stats;
17
+ /**
18
+ * Generate embedding with caching
19
+ */
20
+ embed(text: string | string[]): Promise<Vector | Vector[]>;
21
+ /**
22
+ * Embed single text with cache lookup
23
+ */
24
+ private embedSingle;
25
+ /**
26
+ * Get cache statistics
27
+ */
28
+ getStats(): {
29
+ totalEmbeddings: number;
30
+ cacheHitRate: number;
31
+ cacheHits: number;
32
+ simpleComputes: number;
33
+ modelCalls: number;
34
+ };
35
+ /**
36
+ * Add custom pre-computed embeddings
37
+ */
38
+ addPrecomputed(term: string, embedding: Vector): void;
39
+ }
40
+ export declare const cachedEmbeddings: CachedEmbeddings;