@soulcraft/brainy 1.5.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/CHANGELOG.md +188 -0
  2. package/LICENSE +2 -2
  3. package/README.md +201 -596
  4. package/bin/brainy-interactive.js +564 -0
  5. package/bin/brainy-ts.js +18 -0
  6. package/bin/brainy.js +672 -81
  7. package/dist/augmentationPipeline.d.ts +48 -220
  8. package/dist/augmentationPipeline.js +60 -508
  9. package/dist/augmentationRegistry.d.ts +22 -31
  10. package/dist/augmentationRegistry.js +28 -79
  11. package/dist/augmentations/apiServerAugmentation.d.ts +108 -0
  12. package/dist/augmentations/apiServerAugmentation.js +502 -0
  13. package/dist/augmentations/batchProcessingAugmentation.d.ts +95 -0
  14. package/dist/augmentations/batchProcessingAugmentation.js +567 -0
  15. package/dist/augmentations/brainyAugmentation.d.ts +153 -0
  16. package/dist/augmentations/brainyAugmentation.js +145 -0
  17. package/dist/augmentations/cacheAugmentation.d.ts +105 -0
  18. package/dist/augmentations/cacheAugmentation.js +238 -0
  19. package/dist/augmentations/conduitAugmentations.d.ts +54 -156
  20. package/dist/augmentations/conduitAugmentations.js +156 -1082
  21. package/dist/augmentations/connectionPoolAugmentation.d.ts +62 -0
  22. package/dist/augmentations/connectionPoolAugmentation.js +316 -0
  23. package/dist/augmentations/defaultAugmentations.d.ts +53 -0
  24. package/dist/augmentations/defaultAugmentations.js +88 -0
  25. package/dist/augmentations/entityRegistryAugmentation.d.ts +126 -0
  26. package/dist/augmentations/entityRegistryAugmentation.js +386 -0
  27. package/dist/augmentations/indexAugmentation.d.ts +117 -0
  28. package/dist/augmentations/indexAugmentation.js +284 -0
  29. package/dist/augmentations/intelligentVerbScoringAugmentation.d.ts +152 -0
  30. package/dist/augmentations/intelligentVerbScoringAugmentation.js +554 -0
  31. package/dist/augmentations/metricsAugmentation.d.ts +202 -0
  32. package/dist/augmentations/metricsAugmentation.js +291 -0
  33. package/dist/augmentations/monitoringAugmentation.d.ts +94 -0
  34. package/dist/augmentations/monitoringAugmentation.js +227 -0
  35. package/dist/augmentations/neuralImport.d.ts +50 -117
  36. package/dist/augmentations/neuralImport.js +255 -629
  37. package/dist/augmentations/requestDeduplicatorAugmentation.d.ts +52 -0
  38. package/dist/augmentations/requestDeduplicatorAugmentation.js +162 -0
  39. package/dist/augmentations/serverSearchAugmentations.d.ts +43 -22
  40. package/dist/augmentations/serverSearchAugmentations.js +125 -72
  41. package/dist/augmentations/storageAugmentation.d.ts +54 -0
  42. package/dist/augmentations/storageAugmentation.js +93 -0
  43. package/dist/augmentations/storageAugmentations.d.ts +96 -0
  44. package/dist/augmentations/storageAugmentations.js +182 -0
  45. package/dist/augmentations/synapseAugmentation.d.ts +156 -0
  46. package/dist/augmentations/synapseAugmentation.js +312 -0
  47. package/dist/augmentations/walAugmentation.d.ts +108 -0
  48. package/dist/augmentations/walAugmentation.js +515 -0
  49. package/dist/brainyData.d.ts +404 -130
  50. package/dist/brainyData.js +1331 -853
  51. package/dist/chat/BrainyChat.d.ts +16 -8
  52. package/dist/chat/BrainyChat.js +60 -32
  53. package/dist/chat/ChatCLI.d.ts +1 -1
  54. package/dist/chat/ChatCLI.js +6 -6
  55. package/dist/cli/catalog.d.ts +3 -3
  56. package/dist/cli/catalog.js +116 -70
  57. package/dist/cli/commands/core.d.ts +61 -0
  58. package/dist/cli/commands/core.js +348 -0
  59. package/dist/cli/commands/neural.d.ts +25 -0
  60. package/dist/cli/commands/neural.js +508 -0
  61. package/dist/cli/commands/utility.d.ts +37 -0
  62. package/dist/cli/commands/utility.js +276 -0
  63. package/dist/cli/index.d.ts +7 -0
  64. package/dist/cli/index.js +167 -0
  65. package/dist/cli/interactive.d.ts +164 -0
  66. package/dist/cli/interactive.js +542 -0
  67. package/dist/cortex/neuralImport.js +5 -5
  68. package/dist/critical/model-guardian.js +11 -4
  69. package/dist/embeddings/lightweight-embedder.d.ts +23 -0
  70. package/dist/embeddings/lightweight-embedder.js +136 -0
  71. package/dist/embeddings/universal-memory-manager.d.ts +38 -0
  72. package/dist/embeddings/universal-memory-manager.js +206 -0
  73. package/dist/embeddings/worker-embedding.d.ts +7 -0
  74. package/dist/embeddings/worker-embedding.js +77 -0
  75. package/dist/embeddings/worker-manager.d.ts +28 -0
  76. package/dist/embeddings/worker-manager.js +162 -0
  77. package/dist/examples/basicUsage.js +7 -7
  78. package/dist/graph/pathfinding.d.ts +78 -0
  79. package/dist/graph/pathfinding.js +393 -0
  80. package/dist/hnsw/hnswIndex.d.ts +13 -0
  81. package/dist/hnsw/hnswIndex.js +35 -0
  82. package/dist/hnsw/hnswIndexOptimized.d.ts +1 -0
  83. package/dist/hnsw/hnswIndexOptimized.js +3 -0
  84. package/dist/index.d.ts +9 -11
  85. package/dist/index.js +21 -11
  86. package/dist/indices/fieldIndex.d.ts +76 -0
  87. package/dist/indices/fieldIndex.js +357 -0
  88. package/dist/mcp/brainyMCPAdapter.js +3 -2
  89. package/dist/mcp/mcpAugmentationToolset.js +11 -17
  90. package/dist/neural/embeddedPatterns.d.ts +41 -0
  91. package/dist/neural/embeddedPatterns.js +4044 -0
  92. package/dist/neural/naturalLanguageProcessor.d.ts +94 -0
  93. package/dist/neural/naturalLanguageProcessor.js +317 -0
  94. package/dist/neural/naturalLanguageProcessorStatic.d.ts +64 -0
  95. package/dist/neural/naturalLanguageProcessorStatic.js +151 -0
  96. package/dist/neural/neuralAPI.d.ts +255 -0
  97. package/dist/neural/neuralAPI.js +612 -0
  98. package/dist/neural/patternLibrary.d.ts +101 -0
  99. package/dist/neural/patternLibrary.js +313 -0
  100. package/dist/neural/patterns.d.ts +27 -0
  101. package/dist/neural/patterns.js +68 -0
  102. package/dist/neural/staticPatternMatcher.d.ts +35 -0
  103. package/dist/neural/staticPatternMatcher.js +153 -0
  104. package/dist/scripts/precomputePatternEmbeddings.d.ts +19 -0
  105. package/dist/scripts/precomputePatternEmbeddings.js +100 -0
  106. package/dist/storage/adapters/fileSystemStorage.d.ts +5 -0
  107. package/dist/storage/adapters/fileSystemStorage.js +20 -0
  108. package/dist/storage/adapters/s3CompatibleStorage.d.ts +5 -0
  109. package/dist/storage/adapters/s3CompatibleStorage.js +16 -0
  110. package/dist/storage/enhancedClearOperations.d.ts +83 -0
  111. package/dist/storage/enhancedClearOperations.js +345 -0
  112. package/dist/storage/storageFactory.js +31 -27
  113. package/dist/triple/TripleIntelligence.d.ts +134 -0
  114. package/dist/triple/TripleIntelligence.js +548 -0
  115. package/dist/types/augmentations.d.ts +45 -344
  116. package/dist/types/augmentations.js +5 -2
  117. package/dist/types/brainyDataInterface.d.ts +20 -10
  118. package/dist/types/graphTypes.d.ts +46 -0
  119. package/dist/types/graphTypes.js +16 -2
  120. package/dist/utils/BoundedRegistry.d.ts +29 -0
  121. package/dist/utils/BoundedRegistry.js +54 -0
  122. package/dist/utils/embedding.js +20 -3
  123. package/dist/utils/hybridModelManager.js +10 -5
  124. package/dist/utils/metadataFilter.d.ts +33 -19
  125. package/dist/utils/metadataFilter.js +58 -23
  126. package/dist/utils/metadataIndex.d.ts +37 -6
  127. package/dist/utils/metadataIndex.js +427 -64
  128. package/dist/utils/requestDeduplicator.d.ts +10 -0
  129. package/dist/utils/requestDeduplicator.js +24 -0
  130. package/dist/utils/unifiedCache.d.ts +103 -0
  131. package/dist/utils/unifiedCache.js +311 -0
  132. package/package.json +43 -128
  133. package/scripts/ensure-models.js +108 -0
  134. package/scripts/prepare-models.js +387 -0
  135. package/OFFLINE_MODELS.md +0 -56
  136. package/dist/intelligence/neuralEngine.d.ts +0 -207
  137. package/dist/intelligence/neuralEngine.js +0 -706
  138. package/dist/utils/modelLoader.d.ts +0 -32
  139. package/dist/utils/modelLoader.js +0 -219
  140. package/dist/utils/modelManager.d.ts +0 -77
  141. package/dist/utils/modelManager.js +0 -219
@@ -1,29 +1,24 @@
1
- import { AugmentationType } from '../types/augmentations.js';
1
+ /**
2
+ * Conduit Augmentations - Data Synchronization Bridges
3
+ *
4
+ * These augmentations connect and synchronize data between multiple Brainy instances.
5
+ * Now using the unified BrainyAugmentation interface.
6
+ */
7
+ import { BaseAugmentation } from './brainyAugmentation.js';
2
8
  import { v4 as uuidv4 } from '../universal/uuid.js';
3
9
  /**
4
- * Base class for conduit augmentations that provide data synchronization between Brainy instances
10
+ * Base class for conduit augmentations that sync between Brainy instances
11
+ * Converted to use the unified BrainyAugmentation interface
5
12
  */
6
- class BaseConduitAugmentation {
7
- constructor(name) {
8
- this.description = 'Base conduit augmentation';
9
- this.enabled = true;
10
- this.isInitialized = false;
13
+ class BaseConduitAugmentation extends BaseAugmentation {
14
+ constructor() {
15
+ super(...arguments);
16
+ this.timing = 'after'; // Conduits run after operations to sync
17
+ this.operations = ['addNoun', 'delete', 'addVerb'];
18
+ this.priority = 20; // Medium-low priority
11
19
  this.connections = new Map();
12
- this.name = name;
13
20
  }
14
- async initialize() {
15
- if (this.isInitialized) {
16
- return;
17
- }
18
- try {
19
- this.isInitialized = true;
20
- }
21
- catch (error) {
22
- console.error(`Failed to initialize ${this.name}:`, error);
23
- throw new Error(`Failed to initialize ${this.name}: ${error}`);
24
- }
25
- }
26
- async shutDown() {
21
+ async onShutdown() {
27
22
  // Close all connections
28
23
  for (const [connectionId, connection] of this.connections.entries()) {
29
24
  try {
@@ -32,1127 +27,206 @@ class BaseConduitAugmentation {
32
27
  }
33
28
  }
34
29
  catch (error) {
35
- console.error(`Failed to close connection ${connectionId}:`, error);
30
+ this.log(`Failed to close connection ${connectionId}: ${error}`, 'error');
36
31
  }
37
32
  }
38
33
  this.connections.clear();
39
- this.isInitialized = false;
40
- }
41
- async getStatus() {
42
- return this.isInitialized ? 'active' : 'inactive';
43
- }
44
- async ensureInitialized() {
45
- if (!this.isInitialized) {
46
- await this.initialize();
47
- }
48
34
  }
49
35
  }
50
36
  /**
51
- * WebSocket conduit augmentation for syncing Brainy instances using WebSockets
52
- *
53
- * This conduit is for syncing between browsers and servers, or between servers.
54
- * WebSockets cannot be used for direct browser-to-browser communication without a server in the middle.
37
+ * WebSocket Conduit Augmentation
38
+ * Syncs data between Brainy instances using WebSockets
55
39
  */
56
40
  export class WebSocketConduitAugmentation extends BaseConduitAugmentation {
57
- constructor(name = 'websocket-conduit') {
58
- super(name);
59
- this.description = 'Conduit augmentation that syncs Brainy instances using WebSockets';
41
+ constructor() {
42
+ super(...arguments);
43
+ this.name = 'websocket-conduit';
60
44
  this.webSocketConnections = new Map();
61
45
  this.messageCallbacks = new Map();
62
46
  }
63
- getType() {
64
- return AugmentationType.CONDUIT;
65
- }
66
- /**
67
- * Establishes a connection to another Brainy instance
68
- * @param targetSystemId The URL or identifier of the target system
69
- * @param config Configuration options for the connection
70
- */
71
- async establishConnection(targetSystemId, config) {
72
- await this.ensureInitialized();
73
- try {
74
- // For WebSocket connections, targetSystemId should be a WebSocket URL
75
- const url = targetSystemId;
76
- const protocols = config.protocols;
77
- // Create a WebSocket connection
78
- const connection = await this.connectWebSocket(url, protocols);
79
- // Store the connection
80
- this.connections.set(connection.connectionId, connection);
81
- return {
82
- success: true,
83
- data: connection
84
- };
85
- }
86
- catch (error) {
87
- console.error(`Failed to establish connection to ${targetSystemId}:`, error);
88
- return {
89
- success: false,
90
- data: null,
91
- error: `Failed to establish connection: ${error}`
92
- };
47
+ async execute(operation, params, next) {
48
+ // Execute the operation first
49
+ const result = await next();
50
+ // Then sync to connected instances
51
+ if (this.shouldSync(operation)) {
52
+ await this.syncOperation(operation, params, result);
93
53
  }
54
+ return result;
94
55
  }
95
- /**
96
- * Reads data from a connected Brainy instance
97
- * @param query Query parameters for reading data
98
- * @param options Additional options
99
- */
100
- async readData(query, options) {
101
- await this.ensureInitialized();
102
- try {
103
- const connectionId = query.connectionId;
104
- if (!connectionId) {
105
- throw new Error('connectionId is required for reading data');
106
- }
107
- const connection = this.webSocketConnections.get(connectionId);
108
- if (!connection) {
109
- throw new Error(`Connection ${connectionId} not found`);
110
- }
111
- // Create a request message
112
- const requestMessage = {
113
- type: 'read',
114
- query: query.query || {},
115
- requestId: uuidv4(),
116
- options
117
- };
118
- // Send the request
119
- await this.sendWebSocketMessage(connectionId, requestMessage);
120
- // Return a promise that will be resolved when the response is received
121
- return new Promise((resolve) => {
122
- const responseHandler = (data) => {
123
- // Check if this is the response to our request
124
- const response = data;
125
- if (response && response.type === 'readResponse' && response.requestId === requestMessage.requestId) {
126
- // Remove the handler
127
- this.offWebSocketMessage(connectionId, responseHandler);
128
- // Resolve with the response data
129
- resolve({
130
- success: response.success,
131
- data: response.data,
132
- error: response.error
133
- });
134
- }
135
- };
136
- // Register the response handler
137
- this.onWebSocketMessage(connectionId, responseHandler);
138
- // Set a timeout to prevent hanging
139
- setTimeout(() => {
140
- this.offWebSocketMessage(connectionId, responseHandler);
141
- resolve({
142
- success: false,
143
- data: null,
144
- error: 'Timeout waiting for read response'
145
- });
146
- }, 30000); // 30 second timeout
147
- });
148
- }
149
- catch (error) {
150
- console.error(`Failed to read data:`, error);
151
- return {
152
- success: false,
153
- data: null,
154
- error: `Failed to read data: ${error}`
155
- };
156
- }
56
+ shouldSync(operation) {
57
+ return ['addNoun', 'deleteNoun', 'addVerb'].includes(operation);
157
58
  }
158
- /**
159
- * Writes data to a connected Brainy instance
160
- * @param data The data to write
161
- * @param options Additional options
162
- */
163
- async writeData(data, options) {
164
- await this.ensureInitialized();
165
- try {
166
- const connectionId = data.connectionId;
167
- if (!connectionId) {
168
- throw new Error('connectionId is required for writing data');
169
- }
170
- const connection = this.webSocketConnections.get(connectionId);
171
- if (!connection) {
172
- throw new Error(`Connection ${connectionId} not found`);
173
- }
174
- // Create a write message
175
- const writeMessage = {
176
- type: 'write',
177
- data: data.data || {},
178
- requestId: uuidv4(),
179
- options
180
- };
181
- // Send the write message
182
- await this.sendWebSocketMessage(connectionId, writeMessage);
183
- // Return a promise that will be resolved when the response is received
184
- return new Promise((resolve) => {
185
- const responseHandler = (data) => {
186
- // Check if this is the response to our request
187
- const response = data;
188
- if (response && response.type === 'writeResponse' && response.requestId === writeMessage.requestId) {
189
- // Remove the handler
190
- this.offWebSocketMessage(connectionId, responseHandler);
191
- // Resolve with the response data
192
- resolve({
193
- success: response.success,
194
- data: response.data,
195
- error: response.error
196
- });
197
- }
198
- };
199
- // Register the response handler
200
- this.onWebSocketMessage(connectionId, responseHandler);
201
- // Set a timeout to prevent hanging
202
- setTimeout(() => {
203
- this.offWebSocketMessage(connectionId, responseHandler);
204
- resolve({
205
- success: false,
206
- data: null,
207
- error: 'Timeout waiting for write response'
59
+ async syncOperation(operation, params, result) {
60
+ // Broadcast to all connected WebSocket instances
61
+ for (const [id, connection] of this.webSocketConnections) {
62
+ if (connection.socket && connection.readyState === 1) { // OPEN state
63
+ try {
64
+ const message = JSON.stringify({
65
+ type: 'sync',
66
+ operation,
67
+ params,
68
+ timestamp: Date.now()
208
69
  });
209
- }, 30000); // 30 second timeout
210
- });
211
- }
212
- catch (error) {
213
- console.error(`Failed to write data:`, error);
214
- return {
215
- success: false,
216
- data: null,
217
- error: `Failed to write data: ${error}`
218
- };
219
- }
220
- }
221
- /**
222
- * Monitors a data stream from a connected Brainy instance
223
- * @param streamId The ID of the stream to monitor (usually a connection ID)
224
- * @param callback Function to call when new data is received
225
- */
226
- async monitorStream(streamId, callback) {
227
- await this.ensureInitialized();
228
- try {
229
- const connection = this.webSocketConnections.get(streamId);
230
- if (!connection) {
231
- throw new Error(`Connection ${streamId} not found`);
232
- }
233
- // Register the callback for all messages on this connection
234
- await this.onWebSocketMessage(streamId, callback);
235
- }
236
- catch (error) {
237
- console.error(`Failed to monitor stream ${streamId}:`, error);
238
- throw new Error(`Failed to monitor stream: ${error}`);
239
- }
240
- }
241
- /**
242
- * Establishes a WebSocket connection
243
- * @param url The WebSocket server URL to connect to
244
- * @param protocols Optional subprotocols
245
- */
246
- async connectWebSocket(url, protocols) {
247
- await this.ensureInitialized();
248
- return new Promise((resolve, reject) => {
249
- try {
250
- // Check if WebSocket is available
251
- if (typeof WebSocket === 'undefined') {
252
- throw new Error('WebSocket is not available in this environment');
253
- }
254
- // Create a new WebSocket connection
255
- const ws = new WebSocket(url, protocols);
256
- const connectionId = uuidv4();
257
- // Create a connection object
258
- const connection = {
259
- connectionId,
260
- url,
261
- status: 'disconnected',
262
- send: async (data) => {
263
- if (ws.readyState !== WebSocket.OPEN) {
264
- throw new Error('WebSocket is not open');
265
- }
266
- ws.send(data);
267
- },
268
- close: async () => {
269
- ws.close();
270
- }
271
- };
272
- // Set up event handlers
273
- ws.onopen = () => {
274
- connection.status = 'connected';
275
- resolve(connection);
276
- };
277
- ws.onerror = (error) => {
278
- connection.status = 'error';
279
- console.error(`WebSocket error for ${url}:`, error);
280
- if (ws.readyState !== WebSocket.OPEN) {
281
- reject(new Error(`WebSocket connection failed: ${error}`));
70
+ if (typeof connection.socket.send === 'function') {
71
+ connection.socket.send(message);
282
72
  }
283
- };
284
- ws.onclose = () => {
285
- connection.status = 'disconnected';
286
- // Remove from connections map
287
- this.webSocketConnections.delete(connectionId);
288
- // Remove all callbacks
289
- this.messageCallbacks.delete(connectionId);
290
- };
291
- // Create a message handler wrapper that will call all registered callbacks
292
- const messageHandlerWrapper = (data) => {
293
- const callbacks = this.messageCallbacks.get(connectionId);
294
- if (callbacks) {
295
- for (const callback of callbacks) {
296
- try {
297
- callback(data);
298
- }
299
- catch (error) {
300
- console.error(`Error in WebSocket message callback:`, error);
301
- }
302
- }
303
- }
304
- };
305
- // Store the message handler wrapper
306
- connection._messageHandlerWrapper = messageHandlerWrapper;
307
- // Set up the message handler
308
- ws.onmessage = (event) => {
309
- try {
310
- // Parse the message if it's a string
311
- let data = event.data;
312
- if (typeof data === 'string') {
313
- try {
314
- data = JSON.parse(data);
315
- }
316
- catch {
317
- // If parsing fails, use the raw string
318
- }
319
- }
320
- // Call the message handler wrapper
321
- messageHandlerWrapper(data);
322
- }
323
- catch (error) {
324
- console.error(`Error handling WebSocket message:`, error);
325
- }
326
- };
327
- // Store the stream message handler
328
- connection._streamMessageHandler = (event) => ws.onmessage && ws.onmessage(event);
329
- // Store the connection
330
- this.webSocketConnections.set(connectionId, connection);
331
- // Initialize the callbacks set
332
- this.messageCallbacks.set(connectionId, new Set());
333
- }
334
- catch (error) {
335
- reject(error);
336
- }
337
- });
338
- }
339
- /**
340
- * Sends data through an established WebSocket connection
341
- * @param connectionId The identifier of the established connection
342
- * @param data The data to send (will be serialized if not a string)
343
- */
344
- async sendWebSocketMessage(connectionId, data) {
345
- await this.ensureInitialized();
346
- const connection = this.webSocketConnections.get(connectionId);
347
- if (!connection) {
348
- throw new Error(`WebSocket connection ${connectionId} not found`);
349
- }
350
- if (!connection.send) {
351
- throw new Error(`WebSocket connection ${connectionId} does not support sending messages`);
352
- }
353
- // Serialize the data if it's not already a string or binary
354
- let serializedData;
355
- if (typeof data === 'string' ||
356
- data instanceof ArrayBuffer ||
357
- data instanceof Blob ||
358
- ArrayBuffer.isView(data)) {
359
- serializedData = data;
360
- }
361
- else {
362
- // Convert to JSON string
363
- serializedData = JSON.stringify(data);
364
- }
365
- // Send the data
366
- await connection.send(serializedData);
367
- }
368
- /**
369
- * Registers a callback for incoming WebSocket messages
370
- * @param connectionId The identifier of the established connection
371
- * @param callback The function to call when a message is received
372
- */
373
- async onWebSocketMessage(connectionId, callback) {
374
- await this.ensureInitialized();
375
- const connection = this.webSocketConnections.get(connectionId);
376
- if (!connection) {
377
- throw new Error(`WebSocket connection ${connectionId} not found`);
378
- }
379
- // Get or create the callbacks set for this connection
380
- let callbacks = this.messageCallbacks.get(connectionId);
381
- if (!callbacks) {
382
- callbacks = new Set();
383
- this.messageCallbacks.set(connectionId, callbacks);
384
- }
385
- // Add the callback
386
- callbacks.add(callback);
387
- }
388
- /**
389
- * Removes a callback for incoming WebSocket messages
390
- * @param connectionId The identifier of the established connection
391
- * @param callback The function to remove from the callbacks
392
- */
393
- async offWebSocketMessage(connectionId, callback) {
394
- await this.ensureInitialized();
395
- const callbacks = this.messageCallbacks.get(connectionId);
396
- if (callbacks) {
397
- callbacks.delete(callback);
398
- }
399
- }
400
- /**
401
- * Closes an established WebSocket connection
402
- * @param connectionId The identifier of the established connection
403
- * @param code Optional close code
404
- * @param reason Optional close reason
405
- */
406
- async closeWebSocket(connectionId, code, reason) {
407
- await this.ensureInitialized();
408
- const connection = this.webSocketConnections.get(connectionId);
409
- if (!connection) {
410
- throw new Error(`WebSocket connection ${connectionId} not found`);
411
- }
412
- if (!connection.close) {
413
- throw new Error(`WebSocket connection ${connectionId} does not support closing`);
414
- }
415
- // Close the connection
416
- await connection.close();
417
- // Remove from connections map
418
- this.webSocketConnections.delete(connectionId);
419
- // Remove all callbacks
420
- this.messageCallbacks.delete(connectionId);
421
- }
422
- }
423
- /**
424
- * WebRTC conduit augmentation for syncing Brainy instances using WebRTC
425
- *
426
- * This conduit is for direct peer-to-peer syncing between browsers.
427
- * It is the recommended approach for browser-to-browser communication.
428
- */
429
- export class WebRTCConduitAugmentation extends BaseConduitAugmentation {
430
- constructor(name = 'webrtc-conduit') {
431
- super(name);
432
- this.description = 'Conduit augmentation that syncs Brainy instances using WebRTC';
433
- this.peerConnections = new Map();
434
- this.dataChannels = new Map();
435
- this.webSocketConnections = new Map();
436
- this.messageCallbacks = new Map();
437
- this.signalServer = null;
438
- }
439
- getType() {
440
- return AugmentationType.CONDUIT;
441
- }
442
- async initialize() {
443
- if (this.isInitialized) {
444
- return;
445
- }
446
- try {
447
- // Check if WebRTC is available
448
- if (typeof RTCPeerConnection === 'undefined') {
449
- throw new Error('WebRTC is not available in this environment');
73
+ }
74
+ catch (error) {
75
+ this.log(`Failed to sync to ${id}: ${error}`, 'error');
76
+ }
450
77
  }
451
- this.isInitialized = true;
452
- }
453
- catch (error) {
454
- console.error(`Failed to initialize ${this.name}:`, error);
455
- throw new Error(`Failed to initialize ${this.name}: ${error}`);
456
78
  }
457
79
  }
458
- /**
459
- * Establishes a connection to another Brainy instance using WebRTC
460
- * @param targetSystemId The peer ID or signal server URL
461
- * @param config Configuration options for the connection
462
- */
463
- async establishConnection(targetSystemId, config) {
464
- await this.ensureInitialized();
80
+ async establishConnection(url, config) {
465
81
  try {
466
- // For WebRTC, we need to:
467
- // 1. Connect to a signaling server (if not already connected)
468
- // 2. Create a peer connection
469
- // 3. Create a data channel
470
- // 4. Exchange ICE candidates and SDP offers/answers
471
- // Check if we need to connect to a signaling server
472
- if (!this.signalServer && config.signalServerUrl) {
473
- // Connect to the signaling server
474
- this.signalServer = await this.connectWebSocket(config.signalServerUrl);
475
- // Set up message handling for the signaling server
476
- await this.onWebSocketMessage(this.signalServer.connectionId, async (data) => {
477
- // Handle signaling messages
478
- const message = data;
479
- if (message.type === 'ice-candidate' && message.targetPeerId === config.localPeerId) {
480
- // Add ICE candidate to the appropriate peer connection
481
- const peerConnection = this.peerConnections.get(message.sourcePeerId);
482
- if (peerConnection) {
483
- try {
484
- await peerConnection.addIceCandidate(new RTCIceCandidate(message.candidate));
485
- }
486
- catch (error) {
487
- console.error(`Failed to add ICE candidate:`, error);
488
- }
489
- }
490
- }
491
- else if (message.type === 'offer' && message.targetPeerId === config.localPeerId) {
492
- // Handle incoming offer
493
- await this.handleOffer(message.sourcePeerId, message.offer, config);
494
- }
495
- else if (message.type === 'answer' && message.targetPeerId === config.localPeerId) {
496
- // Handle incoming answer
497
- const peerConnection = this.peerConnections.get(message.sourcePeerId);
498
- if (peerConnection) {
499
- try {
500
- await peerConnection.setRemoteDescription(new RTCSessionDescription(message.answer));
501
- }
502
- catch (error) {
503
- console.error(`Failed to set remote description:`, error);
504
- }
505
- }
506
- }
507
- });
508
- }
509
- // Create a peer connection
510
- const peerConnection = new RTCPeerConnection({
511
- iceServers: config.iceServers || [
512
- { urls: 'stun:stun.l.google.com:19302' }
513
- ]
514
- });
515
- // Generate a connection ID
516
82
  const connectionId = uuidv4();
517
- // Store the peer connection
518
- this.peerConnections.set(targetSystemId, peerConnection);
519
- // Create a data channel
520
- const dataChannel = peerConnection.createDataChannel('brainy-sync', {
521
- ordered: true
522
- });
523
- // Set up data channel event handlers
524
- dataChannel.onopen = () => {
525
- console.log(`Data channel to ${targetSystemId} opened`);
526
- };
527
- dataChannel.onclose = () => {
528
- console.log(`Data channel to ${targetSystemId} closed`);
529
- // Clean up
530
- this.dataChannels.delete(targetSystemId);
531
- this.peerConnections.delete(targetSystemId);
532
- this.webSocketConnections.delete(connectionId);
533
- this.messageCallbacks.delete(connectionId);
534
- };
535
- dataChannel.onerror = (error) => {
536
- console.error(`Data channel error:`, error);
537
- };
538
- // Create a message handler wrapper that will call all registered callbacks
539
- const messageHandlerWrapper = (data) => {
540
- const callbacks = this.messageCallbacks.get(connectionId);
541
- if (callbacks) {
542
- for (const callback of callbacks) {
543
- try {
544
- callback(data);
545
- }
546
- catch (error) {
547
- console.error(`Error in WebRTC message callback:`, error);
548
- }
549
- }
550
- }
551
- };
552
- dataChannel.onmessage = (event) => {
83
+ const protocols = config?.protocols;
84
+ // Create WebSocket based on environment
85
+ let socket;
86
+ if (typeof WebSocket !== 'undefined') {
87
+ // Browser environment
88
+ socket = new WebSocket(url, protocols);
89
+ }
90
+ else {
91
+ // Node.js environment - dynamic import
553
92
  try {
554
- // Parse the message if it's a string
555
- let data = event.data;
556
- if (typeof data === 'string') {
557
- try {
558
- data = JSON.parse(data);
559
- }
560
- catch {
561
- // If parsing fails, use the raw string
562
- }
563
- }
564
- // Call the message handler wrapper
565
- messageHandlerWrapper(data);
93
+ const ws = await import('ws');
94
+ socket = new ws.WebSocket(url, protocols);
566
95
  }
567
- catch (error) {
568
- console.error(`Error handling WebRTC message:`, error);
96
+ catch {
97
+ this.log('WebSocket not available in this environment', 'error');
98
+ return null;
569
99
  }
100
+ }
101
+ // Setup event handlers
102
+ socket.onopen = () => {
103
+ this.log(`Connected to ${url}`);
570
104
  };
571
- // Store the data channel
572
- this.dataChannels.set(targetSystemId, dataChannel);
573
- // Set up ICE candidate handling
574
- peerConnection.onicecandidate = (event) => {
575
- if (event.candidate && this.signalServer) {
576
- // Send the ICE candidate to the peer via the signaling server
577
- this.sendWebSocketMessage(this.signalServer.connectionId, {
578
- type: 'ice-candidate',
579
- sourcePeerId: config.localPeerId,
580
- targetPeerId: targetSystemId,
581
- candidate: event.candidate
582
- });
583
- }
105
+ socket.onmessage = (event) => {
106
+ this.handleMessage(connectionId, event.data);
107
+ };
108
+ socket.onerror = (error) => {
109
+ this.log(`WebSocket error: ${error}`, 'error');
110
+ };
111
+ socket.onclose = () => {
112
+ this.log(`Disconnected from ${url}`);
113
+ this.webSocketConnections.delete(connectionId);
584
114
  };
585
- // Create a WebSocket-like connection object for the WebRTC connection
115
+ // Wait for connection to open
116
+ await new Promise((resolve, reject) => {
117
+ const timeout = setTimeout(() => {
118
+ reject(new Error('Connection timeout'));
119
+ }, 5000);
120
+ socket.onopen = () => {
121
+ clearTimeout(timeout);
122
+ resolve();
123
+ };
124
+ socket.onerror = (error) => {
125
+ clearTimeout(timeout);
126
+ reject(error);
127
+ };
128
+ });
586
129
  const connection = {
587
130
  connectionId,
588
- url: `webrtc://${targetSystemId}`,
589
- status: 'disconnected',
590
- send: async (data) => {
591
- const dc = this.dataChannels.get(targetSystemId);
592
- if (!dc || dc.readyState !== 'open') {
593
- throw new Error('WebRTC data channel is not open');
594
- }
595
- // Send the data
596
- if (typeof data === 'string') {
597
- dc.send(data);
598
- }
599
- else if (data instanceof Blob) {
600
- dc.send(data);
601
- }
602
- else if (data instanceof ArrayBuffer) {
603
- dc.send(new Uint8Array(data));
604
- }
605
- else if (ArrayBuffer.isView(data)) {
606
- dc.send(data);
607
- }
608
- else {
609
- // Convert to JSON string
610
- dc.send(JSON.stringify(data));
611
- }
612
- },
613
- close: async () => {
614
- const dc = this.dataChannels.get(targetSystemId);
615
- if (dc) {
616
- dc.close();
617
- }
618
- const pc = this.peerConnections.get(targetSystemId);
619
- if (pc) {
620
- pc.close();
621
- }
622
- // Clean up
623
- this.dataChannels.delete(targetSystemId);
624
- this.peerConnections.delete(targetSystemId);
625
- this.webSocketConnections.delete(connectionId);
626
- this.messageCallbacks.delete(connectionId);
627
- },
628
- _messageHandlerWrapper: messageHandlerWrapper
131
+ url,
132
+ readyState: socket.readyState,
133
+ socket
629
134
  };
630
- // Store the connection
631
135
  this.webSocketConnections.set(connectionId, connection);
632
- // Initialize the callbacks set
633
- this.messageCallbacks.set(connectionId, new Set());
634
- // Create and send an offer
635
- const offer = await peerConnection.createOffer();
636
- await peerConnection.setLocalDescription(offer);
637
- // Send the offer to the peer via the signaling server
638
- if (this.signalServer) {
639
- await this.sendWebSocketMessage(this.signalServer.connectionId, {
640
- type: 'offer',
641
- sourcePeerId: config.localPeerId,
642
- targetPeerId: targetSystemId,
643
- offer
644
- });
645
- }
646
- // Return the connection
647
- return {
648
- success: true,
649
- data: connection
650
- };
136
+ this.connections.set(connectionId, connection);
137
+ return connection;
651
138
  }
652
139
  catch (error) {
653
- console.error(`Failed to establish WebRTC connection to ${targetSystemId}:`, error);
654
- return {
655
- success: false,
656
- data: null,
657
- error: `Failed to establish WebRTC connection: ${error}`
658
- };
140
+ this.log(`Failed to establish connection to ${url}: ${error}`, 'error');
141
+ return null;
659
142
  }
660
143
  }
661
- /**
662
- * Handles an incoming WebRTC offer
663
- * @param peerId The ID of the peer sending the offer
664
- * @param offer The SDP offer
665
- * @param config Configuration options
666
- */
667
- async handleOffer(peerId, offer, config) {
144
+ handleMessage(connectionId, data) {
668
145
  try {
669
- // Create a peer connection if it doesn't exist
670
- let peerConnection = this.peerConnections.get(peerId);
671
- if (!peerConnection) {
672
- peerConnection = new RTCPeerConnection({
673
- iceServers: config.iceServers || [
674
- { urls: 'stun:stun.l.google.com:19302' }
675
- ]
146
+ const message = typeof data === 'string' ? JSON.parse(data) : data;
147
+ // Handle sync messages from remote instances
148
+ if (message.type === 'sync') {
149
+ // Apply the operation to our local instance
150
+ this.applySyncOperation(message).catch(error => {
151
+ this.log(`Failed to apply sync operation: ${error}`, 'error');
676
152
  });
677
- // Store the peer connection
678
- this.peerConnections.set(peerId, peerConnection);
679
- // Set up ICE candidate handling
680
- peerConnection.onicecandidate = (event) => {
681
- if (event.candidate && this.signalServer) {
682
- // Send the ICE candidate to the peer via the signaling server
683
- this.sendWebSocketMessage(this.signalServer.connectionId, {
684
- type: 'ice-candidate',
685
- sourcePeerId: config.localPeerId,
686
- targetPeerId: peerId,
687
- candidate: event.candidate
688
- });
689
- }
690
- };
691
- // Handle data channel creation by the remote peer
692
- peerConnection.ondatachannel = (event) => {
693
- const dataChannel = event.channel;
694
- // Generate a connection ID
695
- const connectionId = uuidv4();
696
- // Store the data channel
697
- this.dataChannels.set(peerId, dataChannel);
698
- // Set up data channel event handlers
699
- dataChannel.onopen = () => {
700
- console.log(`Data channel from ${peerId} opened`);
701
- };
702
- dataChannel.onclose = () => {
703
- console.log(`Data channel from ${peerId} closed`);
704
- // Clean up
705
- this.dataChannels.delete(peerId);
706
- this.peerConnections.delete(peerId);
707
- this.webSocketConnections.delete(connectionId);
708
- this.messageCallbacks.delete(connectionId);
709
- };
710
- dataChannel.onerror = (error) => {
711
- console.error(`Data channel error:`, error);
712
- };
713
- // Create a message handler wrapper that will call all registered callbacks
714
- const messageHandlerWrapper = (data) => {
715
- const callbacks = this.messageCallbacks.get(connectionId);
716
- if (callbacks) {
717
- for (const callback of callbacks) {
718
- try {
719
- callback(data);
720
- }
721
- catch (error) {
722
- console.error(`Error in WebRTC message callback:`, error);
723
- }
724
- }
725
- }
726
- };
727
- dataChannel.onmessage = (event) => {
728
- try {
729
- // Parse the message if it's a string
730
- let data = event.data;
731
- if (typeof data === 'string') {
732
- try {
733
- data = JSON.parse(data);
734
- }
735
- catch {
736
- // If parsing fails, use the raw string
737
- }
738
- }
739
- // Call the message handler wrapper
740
- messageHandlerWrapper(data);
741
- }
742
- catch (error) {
743
- console.error(`Error handling WebRTC message:`, error);
744
- }
745
- };
746
- // Create a WebSocket-like connection object for the WebRTC connection
747
- const connection = {
748
- connectionId,
749
- url: `webrtc://${peerId}`,
750
- status: 'disconnected',
751
- send: async (data) => {
752
- if (dataChannel.readyState !== 'open') {
753
- throw new Error('WebRTC data channel is not open');
754
- }
755
- // Send the data
756
- if (typeof data === 'string') {
757
- dataChannel.send(data);
758
- }
759
- else if (data instanceof Blob) {
760
- dataChannel.send(data);
761
- }
762
- else if (data instanceof ArrayBuffer) {
763
- dataChannel.send(new Uint8Array(data));
764
- }
765
- else if (ArrayBuffer.isView(data)) {
766
- dataChannel.send(data);
767
- }
768
- else {
769
- // Convert to JSON string
770
- dataChannel.send(JSON.stringify(data));
771
- }
772
- },
773
- close: async () => {
774
- dataChannel.close();
775
- const pc = this.peerConnections.get(peerId);
776
- if (pc) {
777
- pc.close();
778
- }
779
- // Clean up
780
- this.dataChannels.delete(peerId);
781
- this.peerConnections.delete(peerId);
782
- this.webSocketConnections.delete(connectionId);
783
- this.messageCallbacks.delete(connectionId);
784
- },
785
- _messageHandlerWrapper: messageHandlerWrapper
786
- };
787
- // Store the connection
788
- this.webSocketConnections.set(connectionId, connection);
789
- // Initialize the callbacks set
790
- this.messageCallbacks.set(connectionId, new Set());
791
- };
792
153
  }
793
- // Set the remote description (the offer)
794
- await peerConnection.setRemoteDescription(new RTCSessionDescription(offer));
795
- // Create an answer
796
- const answer = await peerConnection.createAnswer();
797
- await peerConnection.setLocalDescription(answer);
798
- // Send the answer to the peer via the signaling server
799
- if (this.signalServer) {
800
- await this.sendWebSocketMessage(this.signalServer.connectionId, {
801
- type: 'answer',
802
- sourcePeerId: config.localPeerId,
803
- targetPeerId: peerId,
804
- answer
805
- });
154
+ // Notify any registered callbacks
155
+ const callbacks = this.messageCallbacks.get(connectionId);
156
+ if (callbacks) {
157
+ callbacks.forEach(callback => callback(message));
806
158
  }
807
159
  }
808
160
  catch (error) {
809
- console.error(`Failed to handle WebRTC offer:`, error);
810
- throw new Error(`Failed to handle WebRTC offer: ${error}`);
811
- }
812
- }
813
- /**
814
- * Reads data from a connected Brainy instance
815
- * @param query Query parameters for reading data
816
- * @param options Additional options
817
- */
818
- async readData(query, options) {
819
- await this.ensureInitialized();
820
- try {
821
- const connectionId = query.connectionId;
822
- if (!connectionId) {
823
- throw new Error('connectionId is required for reading data');
824
- }
825
- const connection = this.webSocketConnections.get(connectionId);
826
- if (!connection) {
827
- throw new Error(`Connection ${connectionId} not found`);
828
- }
829
- // Create a request message
830
- const requestMessage = {
831
- type: 'read',
832
- query: query.query || {},
833
- requestId: uuidv4(),
834
- options
835
- };
836
- // Send the request
837
- await this.sendWebSocketMessage(connectionId, requestMessage);
838
- // Return a promise that will be resolved when the response is received
839
- return new Promise((resolve) => {
840
- const responseHandler = (data) => {
841
- // Check if this is the response to our request
842
- const response = data;
843
- if (response && response.type === 'readResponse' && response.requestId === requestMessage.requestId) {
844
- // Remove the handler
845
- this.offWebSocketMessage(connectionId, responseHandler);
846
- // Resolve with the response data
847
- resolve({
848
- success: response.success,
849
- data: response.data,
850
- error: response.error
851
- });
852
- }
853
- };
854
- // Register the response handler
855
- this.onWebSocketMessage(connectionId, responseHandler);
856
- // Set a timeout to prevent hanging
857
- setTimeout(() => {
858
- this.offWebSocketMessage(connectionId, responseHandler);
859
- resolve({
860
- success: false,
861
- data: null,
862
- error: 'Timeout waiting for read response'
863
- });
864
- }, 30000); // 30 second timeout
865
- });
866
- }
867
- catch (error) {
868
- console.error(`Failed to read data:`, error);
869
- return {
870
- success: false,
871
- data: null,
872
- error: `Failed to read data: ${error}`
873
- };
161
+ this.log(`Failed to handle message: ${error}`, 'error');
874
162
  }
875
163
  }
876
- /**
877
- * Writes data to a connected Brainy instance
878
- * @param data The data to write
879
- * @param options Additional options
880
- */
881
- async writeData(data, options) {
882
- await this.ensureInitialized();
164
+ async applySyncOperation(message) {
165
+ // Apply the synced operation to our local Brainy instance
166
+ const { operation, params } = message;
883
167
  try {
884
- const connectionId = data.connectionId;
885
- if (!connectionId) {
886
- throw new Error('connectionId is required for writing data');
887
- }
888
- const connection = this.webSocketConnections.get(connectionId);
889
- if (!connection) {
890
- throw new Error(`Connection ${connectionId} not found`);
168
+ switch (operation) {
169
+ case 'addNoun':
170
+ await this.context?.brain.addNoun(params.content, params.metadata);
171
+ break;
172
+ case 'deleteNoun':
173
+ await this.context?.brain.deleteNoun(params.id);
174
+ break;
175
+ case 'addVerb':
176
+ await this.context?.brain.addVerb(params.source, params.target, params.verb, params.metadata);
177
+ break;
891
178
  }
892
- // Create a write message
893
- const writeMessage = {
894
- type: 'write',
895
- data: data.data || {},
896
- requestId: uuidv4(),
897
- options
898
- };
899
- // Send the write message
900
- await this.sendWebSocketMessage(connectionId, writeMessage);
901
- // Return a promise that will be resolved when the response is received
902
- return new Promise((resolve) => {
903
- const responseHandler = (data) => {
904
- // Check if this is the response to our request
905
- const response = data;
906
- if (response && response.type === 'writeResponse' && response.requestId === writeMessage.requestId) {
907
- // Remove the handler
908
- this.offWebSocketMessage(connectionId, responseHandler);
909
- // Resolve with the response data
910
- resolve({
911
- success: response.success,
912
- data: response.data,
913
- error: response.error
914
- });
915
- }
916
- };
917
- // Register the response handler
918
- this.onWebSocketMessage(connectionId, responseHandler);
919
- // Set a timeout to prevent hanging
920
- setTimeout(() => {
921
- this.offWebSocketMessage(connectionId, responseHandler);
922
- resolve({
923
- success: false,
924
- data: null,
925
- error: 'Timeout waiting for write response'
926
- });
927
- }, 30000); // 30 second timeout
928
- });
929
179
  }
930
180
  catch (error) {
931
- console.error(`Failed to write data:`, error);
932
- return {
933
- success: false,
934
- data: null,
935
- error: `Failed to write data: ${error}`
936
- };
181
+ this.log(`Failed to apply ${operation}: ${error}`, 'error');
937
182
  }
938
183
  }
939
184
  /**
940
- * Monitors a data stream from a connected Brainy instance
941
- * @param streamId The ID of the stream to monitor (usually a connection ID)
942
- * @param callback Function to call when new data is received
185
+ * Subscribe to messages from a specific connection
943
186
  */
944
- async monitorStream(streamId, callback) {
945
- await this.ensureInitialized();
946
- try {
947
- const connection = this.webSocketConnections.get(streamId);
948
- if (!connection) {
949
- throw new Error(`Connection ${streamId} not found`);
950
- }
951
- // Register the callback for all messages on this connection
952
- await this.onWebSocketMessage(streamId, callback);
953
- }
954
- catch (error) {
955
- console.error(`Failed to monitor stream ${streamId}:`, error);
956
- throw new Error(`Failed to monitor stream: ${error}`);
187
+ onMessage(connectionId, callback) {
188
+ if (!this.messageCallbacks.has(connectionId)) {
189
+ this.messageCallbacks.set(connectionId, new Set());
957
190
  }
191
+ this.messageCallbacks.get(connectionId).add(callback);
958
192
  }
959
193
  /**
960
- * Establishes a WebSocket connection (used for signaling in WebRTC)
961
- * @param url The WebSocket server URL to connect to
962
- * @param protocols Optional subprotocols
194
+ * Send a message to a specific connection
963
195
  */
964
- async connectWebSocket(url, protocols) {
965
- await this.ensureInitialized();
966
- return new Promise((resolve, reject) => {
196
+ sendMessage(connectionId, data) {
197
+ const connection = this.webSocketConnections.get(connectionId);
198
+ if (connection?.socket && connection.readyState === 1) {
967
199
  try {
968
- // Check if WebSocket is available
969
- if (typeof WebSocket === 'undefined') {
970
- throw new Error('WebSocket is not available in this environment');
971
- }
972
- // Create a new WebSocket connection
973
- const ws = new WebSocket(url, protocols);
974
- const connectionId = uuidv4();
975
- // Create a connection object
976
- const connection = {
977
- connectionId,
978
- url,
979
- status: 'disconnected',
980
- send: async (data) => {
981
- if (ws.readyState !== WebSocket.OPEN) {
982
- throw new Error('WebSocket is not open');
983
- }
984
- ws.send(data);
985
- },
986
- close: async () => {
987
- ws.close();
988
- }
989
- };
990
- // Set up event handlers
991
- ws.onopen = () => {
992
- connection.status = 'connected';
993
- resolve(connection);
994
- };
995
- ws.onerror = (error) => {
996
- connection.status = 'error';
997
- console.error(`WebSocket error for ${url}:`, error);
998
- if (ws.readyState !== WebSocket.OPEN) {
999
- reject(new Error(`WebSocket connection failed: ${error}`));
1000
- }
1001
- };
1002
- ws.onclose = () => {
1003
- connection.status = 'disconnected';
1004
- // Remove from connections map
1005
- this.webSocketConnections.delete(connectionId);
1006
- // Remove all callbacks
1007
- this.messageCallbacks.delete(connectionId);
1008
- };
1009
- // Create a message handler wrapper that will call all registered callbacks
1010
- const messageHandlerWrapper = (data) => {
1011
- const callbacks = this.messageCallbacks.get(connectionId);
1012
- if (callbacks) {
1013
- for (const callback of callbacks) {
1014
- try {
1015
- callback(data);
1016
- }
1017
- catch (error) {
1018
- console.error(`Error in WebSocket message callback:`, error);
1019
- }
1020
- }
1021
- }
1022
- };
1023
- // Store the message handler wrapper
1024
- connection._messageHandlerWrapper = messageHandlerWrapper;
1025
- // Set up the message handler
1026
- ws.onmessage = (event) => {
1027
- try {
1028
- // Parse the message if it's a string
1029
- let data = event.data;
1030
- if (typeof data === 'string') {
1031
- try {
1032
- data = JSON.parse(data);
1033
- }
1034
- catch {
1035
- // If parsing fails, use the raw string
1036
- }
1037
- }
1038
- // Call the message handler wrapper
1039
- messageHandlerWrapper(data);
1040
- }
1041
- catch (error) {
1042
- console.error(`Error handling WebSocket message:`, error);
1043
- }
1044
- };
1045
- // Store the stream message handler
1046
- connection._streamMessageHandler = (event) => ws.onmessage && ws.onmessage(event);
1047
- // Store the connection
1048
- this.webSocketConnections.set(connectionId, connection);
1049
- // Initialize the callbacks set
1050
- this.messageCallbacks.set(connectionId, new Set());
200
+ const message = typeof data === 'string' ? data : JSON.stringify(data);
201
+ connection.socket.send(message);
202
+ return true;
1051
203
  }
1052
204
  catch (error) {
1053
- reject(error);
205
+ this.log(`Failed to send message: ${error}`, 'error');
1054
206
  }
1055
- });
1056
- }
1057
- /**
1058
- * Sends data through an established WebSocket or WebRTC connection
1059
- * @param connectionId The identifier of the established connection
1060
- * @param data The data to send (will be serialized if not a string)
1061
- */
1062
- async sendWebSocketMessage(connectionId, data) {
1063
- await this.ensureInitialized();
1064
- const connection = this.webSocketConnections.get(connectionId);
1065
- if (!connection) {
1066
- throw new Error(`Connection ${connectionId} not found`);
1067
- }
1068
- if (!connection.send) {
1069
- throw new Error(`Connection ${connectionId} does not support sending messages`);
1070
207
  }
1071
- // Serialize the data if it's not already a string or binary
1072
- let serializedData;
1073
- if (typeof data === 'string' ||
1074
- data instanceof ArrayBuffer ||
1075
- data instanceof Blob ||
1076
- ArrayBuffer.isView(data)) {
1077
- serializedData = data;
1078
- }
1079
- else {
1080
- // Convert to JSON string
1081
- serializedData = JSON.stringify(data);
1082
- }
1083
- // Send the data
1084
- await connection.send(serializedData);
1085
- }
1086
- /**
1087
- * Registers a callback for incoming WebSocket or WebRTC messages
1088
- * @param connectionId The identifier of the established connection
1089
- * @param callback The function to call when a message is received
1090
- */
1091
- async onWebSocketMessage(connectionId, callback) {
1092
- await this.ensureInitialized();
1093
- const connection = this.webSocketConnections.get(connectionId);
1094
- if (!connection) {
1095
- throw new Error(`Connection ${connectionId} not found`);
1096
- }
1097
- // Get or create the callbacks set for this connection
1098
- let callbacks = this.messageCallbacks.get(connectionId);
1099
- if (!callbacks) {
1100
- callbacks = new Set();
1101
- this.messageCallbacks.set(connectionId, callbacks);
1102
- }
1103
- // Add the callback
1104
- callbacks.add(callback);
1105
- }
1106
- /**
1107
- * Removes a callback for incoming WebSocket or WebRTC messages
1108
- * @param connectionId The identifier of the established connection
1109
- * @param callback The function to remove from the callbacks
1110
- */
1111
- async offWebSocketMessage(connectionId, callback) {
1112
- await this.ensureInitialized();
1113
- const callbacks = this.messageCallbacks.get(connectionId);
1114
- if (callbacks) {
1115
- callbacks.delete(callback);
1116
- }
1117
- }
1118
- /**
1119
- * Closes an established WebSocket or WebRTC connection
1120
- * @param connectionId The identifier of the established connection
1121
- * @param code Optional close code
1122
- * @param reason Optional close reason
1123
- */
1124
- async closeWebSocket(connectionId, code, reason) {
1125
- await this.ensureInitialized();
1126
- const connection = this.webSocketConnections.get(connectionId);
1127
- if (!connection) {
1128
- throw new Error(`Connection ${connectionId} not found`);
1129
- }
1130
- if (!connection.close) {
1131
- throw new Error(`Connection ${connectionId} does not support closing`);
1132
- }
1133
- // Close the connection
1134
- await connection.close();
1135
- // Remove from connections map
1136
- this.webSocketConnections.delete(connectionId);
1137
- // Remove all callbacks
1138
- this.messageCallbacks.delete(connectionId);
208
+ return false;
1139
209
  }
1140
210
  }
1141
211
  /**
1142
- * Factory function to create the appropriate conduit augmentation based on the type
1143
- */
1144
- export async function createConduitAugmentation(type, name, options = {}) {
1145
- switch (type) {
1146
- case 'websocket':
1147
- const wsAugmentation = new WebSocketConduitAugmentation(name || 'websocket-conduit');
1148
- await wsAugmentation.initialize();
1149
- return wsAugmentation;
1150
- case 'webrtc':
1151
- const webrtcAugmentation = new WebRTCConduitAugmentation(name || 'webrtc-conduit');
1152
- await webrtcAugmentation.initialize();
1153
- return webrtcAugmentation;
1154
- default:
1155
- throw new Error(`Unknown conduit augmentation type: ${type}`);
1156
- }
1157
- }
212
+ * Example usage:
213
+ *
214
+ * // Server instance
215
+ * const serverBrain = new BrainyData()
216
+ * serverBrain.augmentations.register(new APIServerAugmentation())
217
+ * await serverBrain.init()
218
+ *
219
+ * // Client instance
220
+ * const clientBrain = new BrainyData()
221
+ * const conduit = new WebSocketConduitAugmentation()
222
+ * clientBrain.augmentations.register(conduit)
223
+ * await clientBrain.init()
224
+ *
225
+ * // Connect client to server
226
+ * await conduit.establishConnection('ws://localhost:3000/ws')
227
+ *
228
+ * // Now operations sync automatically!
229
+ * await clientBrain.addNoun('synced data', { source: 'client' })
230
+ * // This will automatically sync to the server
231
+ */
1158
232
  //# sourceMappingURL=conduitAugmentations.js.map