@olane/o-node 0.7.51 → 0.7.53

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 (48) hide show
  1. package/dist/src/connection/index.d.ts +6 -5
  2. package/dist/src/connection/index.d.ts.map +1 -1
  3. package/dist/src/connection/index.js +6 -5
  4. package/dist/src/connection/interfaces/{o-node-connection-stream.config.d.ts → o-node-stream.config.d.ts} +2 -2
  5. package/dist/src/connection/interfaces/o-node-stream.config.d.ts.map +1 -0
  6. package/dist/src/connection/interfaces/stream-init-message.d.ts +29 -0
  7. package/dist/src/connection/interfaces/stream-init-message.d.ts.map +1 -0
  8. package/dist/src/connection/interfaces/stream-init-message.js +8 -0
  9. package/dist/src/connection/interfaces/stream-manager.config.d.ts +8 -0
  10. package/dist/src/connection/interfaces/stream-manager.config.d.ts.map +1 -0
  11. package/dist/src/connection/o-node-connection.d.ts +5 -7
  12. package/dist/src/connection/o-node-connection.d.ts.map +1 -1
  13. package/dist/src/connection/o-node-connection.js +26 -56
  14. package/dist/src/connection/o-node-connection.manager.d.ts +7 -0
  15. package/dist/src/connection/o-node-connection.manager.d.ts.map +1 -1
  16. package/dist/src/connection/o-node-connection.manager.js +23 -5
  17. package/dist/src/connection/{o-node-connection-stream.d.ts → o-node-stream.d.ts} +6 -6
  18. package/dist/src/connection/o-node-stream.d.ts.map +1 -0
  19. package/dist/src/connection/{o-node-connection-stream.js → o-node-stream.js} +2 -2
  20. package/dist/src/connection/o-node-stream.manager.d.ts +181 -0
  21. package/dist/src/connection/o-node-stream.manager.d.ts.map +1 -0
  22. package/dist/src/connection/o-node-stream.manager.js +526 -0
  23. package/dist/src/connection/stream-manager.events.d.ts +83 -0
  24. package/dist/src/connection/stream-manager.events.d.ts.map +1 -0
  25. package/dist/src/connection/stream-manager.events.js +18 -0
  26. package/dist/src/o-node.tool.d.ts +0 -1
  27. package/dist/src/o-node.tool.d.ts.map +1 -1
  28. package/dist/src/o-node.tool.js +30 -20
  29. package/dist/test/helpers/stream-pool-test-helpers.d.ts +0 -75
  30. package/dist/test/helpers/stream-pool-test-helpers.d.ts.map +1 -1
  31. package/dist/test/helpers/stream-pool-test-helpers.js +262 -229
  32. package/dist/test/parent-child-registration.spec.js +2 -1
  33. package/package.json +7 -7
  34. package/dist/src/connection/interfaces/o-node-connection-stream.config.d.ts.map +0 -1
  35. package/dist/src/connection/interfaces/stream-pool-manager.config.d.ts +0 -41
  36. package/dist/src/connection/interfaces/stream-pool-manager.config.d.ts.map +0 -1
  37. package/dist/src/connection/o-node-connection-stream.d.ts.map +0 -1
  38. package/dist/src/connection/stream-handler.d.ts +0 -102
  39. package/dist/src/connection/stream-handler.d.ts.map +0 -1
  40. package/dist/src/connection/stream-handler.js +0 -357
  41. package/dist/src/connection/stream-pool-manager.d.ts +0 -86
  42. package/dist/src/connection/stream-pool-manager.d.ts.map +0 -1
  43. package/dist/src/connection/stream-pool-manager.events.d.ts +0 -57
  44. package/dist/src/connection/stream-pool-manager.events.d.ts.map +0 -1
  45. package/dist/src/connection/stream-pool-manager.events.js +0 -14
  46. package/dist/src/connection/stream-pool-manager.js +0 -356
  47. /package/dist/src/connection/interfaces/{o-node-connection-stream.config.js → o-node-stream.config.js} +0 -0
  48. /package/dist/src/connection/interfaces/{stream-pool-manager.config.js → stream-manager.config.js} +0 -0
@@ -0,0 +1,526 @@
1
+ import { EventEmitter } from 'events';
2
+ import { oObject, oError, oErrorCodes, oRequest, oResponse, CoreUtils, ResponseBuilder, } from '@olane/o-core';
3
+ import { oNodeStream } from './o-node-stream.js';
4
+ import { StreamManagerEvent, } from './stream-manager.events.js';
5
+ import { isStreamInitMessage, } from './interfaces/stream-init-message.js';
6
+ import { lpStream } from '@olane/o-config';
7
+ import JSON5 from 'json5';
8
+ /**
9
+ * oNodeStreamManager handles the lifecycle and tracking of streams for a single connection.
10
+ * Features:
11
+ * - Tracks all streams by ID
12
+ * - Creates new streams on demand
13
+ * - Manages stream lifecycle (cleanup after use)
14
+ * - Provides events for monitoring
15
+ * - No reuse at base layer (extensible in subclasses)
16
+ */
17
+ export class oNodeStreamManager extends oObject {
18
+ constructor(config) {
19
+ super();
20
+ this.config = config;
21
+ this.streams = new Map();
22
+ this.eventEmitter = new EventEmitter();
23
+ this.isInitialized = false;
24
+ this.activeStreamHandlers = new Map();
25
+ this.p2pConnection = config.p2pConnection;
26
+ }
27
+ /**
28
+ * Initialize the stream manager
29
+ */
30
+ async initialize() {
31
+ if (this.isInitialized) {
32
+ this.logger.debug('Stream manager already initialized');
33
+ return;
34
+ }
35
+ try {
36
+ // Stream manager is now initialized and ready to handle streams
37
+ this.isInitialized = true;
38
+ this.emit(StreamManagerEvent.ManagerInitialized, {});
39
+ this.logger.info('Stream manager initialized', {
40
+ remotePeer: this.p2pConnection.remotePeer.toString(),
41
+ });
42
+ }
43
+ catch (error) {
44
+ this.logger.error('Failed to initialize stream manager:', error);
45
+ throw new oError(oErrorCodes.INTERNAL_ERROR, `Failed to initialize stream manager: ${error.message}`);
46
+ }
47
+ }
48
+ /**
49
+ * Gets or creates a stream for the connection
50
+ * Always creates a new stream (no reuse at base layer)
51
+ *
52
+ * For limited connections (where caller has identified a reader stream):
53
+ * - If callerReaderStream exists, wrap and return it for sending requests
54
+ * - Otherwise, create new stream as normal
55
+ *
56
+ * @param protocol - The protocol string for the stream
57
+ * @param remoteAddress - The remote address for the stream
58
+ * @param config - Stream handler configuration
59
+ * @returns Wrapped stream
60
+ */
61
+ async getOrCreateStream(protocol, remoteAddress, config = {}) {
62
+ this.logger.debug('Getting or creating stream', this.callerReaderStream?.protocol, 'and status', this.callerReaderStream?.status);
63
+ // If we have a caller's reader stream (from limited connection), use it for sending requests
64
+ if (this.callerReaderStream && this.callerReaderStream.status === 'open') {
65
+ this.logger.debug('Using caller reader stream for limited connection', {
66
+ streamId: this.callerReaderStream.id,
67
+ });
68
+ // Wrap the reader stream for use (if not already wrapped)
69
+ const existingWrapped = Array.from(this.streams.values()).find((s) => s.p2pStream.id === this.callerReaderStream.id);
70
+ if (existingWrapped) {
71
+ return existingWrapped;
72
+ }
73
+ // Wrap the reader stream
74
+ const wrappedStream = new oNodeStream(this.callerReaderStream, {
75
+ direction: 'inbound', // It's inbound to us, we write to it
76
+ reusePolicy: 'reuse',
77
+ remoteAddress: remoteAddress,
78
+ streamType: 'request-response',
79
+ });
80
+ this.streams.set(this.callerReaderStream.id, wrappedStream);
81
+ return wrappedStream;
82
+ }
83
+ // Always create new stream (no reuse at base layer)
84
+ return await this.createStream(protocol, remoteAddress, config);
85
+ }
86
+ /**
87
+ * Creates a new stream from the connection
88
+ *
89
+ * @param protocol - The protocol string for the stream
90
+ * @param remoteAddress - The remote address for the stream
91
+ * @param config - Stream handler configuration
92
+ * @returns Wrapped stream
93
+ */
94
+ async createStream(protocol, remoteAddress, config = {}) {
95
+ this.logger.debug('Creating new stream', {
96
+ protocol,
97
+ currentStreamCount: this.streams.size,
98
+ });
99
+ // Create stream from libp2p connection
100
+ const stream = await this.p2pConnection.newStream(protocol, {
101
+ signal: config.signal,
102
+ maxOutboundStreams: config.maxOutboundStreams ?? 1000,
103
+ runOnLimitedConnection: config.runOnLimitedConnection ?? false,
104
+ });
105
+ // Wrap in oNodeStream with metadata
106
+ const wrappedStream = new oNodeStream(stream, {
107
+ direction: 'outbound',
108
+ reusePolicy: 'none', // Always none at base layer
109
+ remoteAddress: remoteAddress,
110
+ streamType: 'request-response',
111
+ });
112
+ // Track the stream
113
+ this.streams.set(stream.id, wrappedStream);
114
+ this.logger.debug('Stream created', {
115
+ streamId: stream.id,
116
+ protocol,
117
+ totalStreams: this.streams.size,
118
+ });
119
+ return wrappedStream;
120
+ }
121
+ /**
122
+ * Releases and cleans up a stream
123
+ *
124
+ * @param streamId - The ID of the stream to release
125
+ */
126
+ async releaseStream(streamId) {
127
+ const wrappedStream = this.streams.get(streamId);
128
+ if (!wrappedStream) {
129
+ this.logger.debug('Stream not found for release', { streamId });
130
+ return;
131
+ }
132
+ this.logger.debug('Releasing stream', { streamId });
133
+ // Remove from tracking
134
+ this.streams.delete(streamId);
135
+ // Close the stream if still open
136
+ if (wrappedStream.p2pStream.status === 'open') {
137
+ try {
138
+ await wrappedStream.p2pStream.close();
139
+ }
140
+ catch (error) {
141
+ this.logger.debug('Error closing stream during release', {
142
+ streamId,
143
+ error: error.message,
144
+ });
145
+ }
146
+ }
147
+ this.logger.debug('Stream released', {
148
+ streamId,
149
+ remainingStreams: this.streams.size,
150
+ });
151
+ }
152
+ /**
153
+ * Gets all tracked streams
154
+ *
155
+ * @returns Array of wrapped streams
156
+ */
157
+ getAllStreams() {
158
+ return Array.from(this.streams.values());
159
+ }
160
+ /**
161
+ * Emits an async event and waits for the first listener to return a result
162
+ * This enables event-based request handling with async responses
163
+ */
164
+ async emitAsync(event, data) {
165
+ const listeners = this.eventEmitter.listeners(event);
166
+ if (listeners.length === 0) {
167
+ throw new oError(oErrorCodes.INTERNAL_ERROR, `No listener registered for event: ${event}`);
168
+ }
169
+ // Call the first listener and await its response
170
+ const listener = listeners[0];
171
+ return await listener(data);
172
+ }
173
+ /**
174
+ * Detects if a decoded message is a request
175
+ * Requests have a 'method' field and no 'result' field
176
+ */
177
+ isRequest(message) {
178
+ return typeof message?.method === 'string' && message.result === undefined;
179
+ }
180
+ /**
181
+ * Detects if a decoded message is a response
182
+ * Responses have a 'result' field and no 'method' field
183
+ */
184
+ isResponse(message) {
185
+ return message?.result !== undefined && message.method === undefined;
186
+ }
187
+ /**
188
+ * Detects if a decoded message is a stream initialization message
189
+ * Uses the imported type guard from stream-init-message.ts
190
+ */
191
+ isStreamInit(message) {
192
+ return isStreamInitMessage(message);
193
+ }
194
+ /**
195
+ * Handles a stream initialization message
196
+ * Stores reference to caller's reader stream for bidirectional communication
197
+ *
198
+ * @param message - The decoded stream init message
199
+ * @param stream - The stream that sent the message
200
+ */
201
+ handleStreamInitMessage(message, stream) {
202
+ if (message.role === 'reader') {
203
+ this.callerReaderStream = stream;
204
+ this.logger.info('Identified caller reader stream', {
205
+ streamId: stream.id,
206
+ connectionId: message.connectionId,
207
+ });
208
+ this.emit(StreamManagerEvent.StreamIdentified, {
209
+ streamId: stream.id,
210
+ role: message.role,
211
+ connectionId: message.connectionId,
212
+ });
213
+ }
214
+ }
215
+ /**
216
+ * Extracts and parses JSON from various formats including:
217
+ * - Already parsed objects
218
+ * - Plain JSON
219
+ * - Markdown code blocks (```json ... ``` or ``` ... ```)
220
+ * - Mixed content with explanatory text
221
+ * - JSON5 format (trailing commas, comments, unquoted keys, etc.)
222
+ *
223
+ * @param decoded - The decoded string that may contain JSON, or an already parsed object
224
+ * @returns Parsed JSON object
225
+ * @throws Error if JSON parsing fails even with JSON5 fallback
226
+ */
227
+ extractAndParseJSON(decoded) {
228
+ // If already an object (not a string), return it directly
229
+ if (typeof decoded !== 'string') {
230
+ return decoded;
231
+ }
232
+ let jsonString = decoded.trim();
233
+ // Attempt standard JSON.parse first
234
+ try {
235
+ return JSON.parse(jsonString);
236
+ }
237
+ catch (jsonError) {
238
+ this.logger.debug('Standard JSON parse failed, trying JSON5', {
239
+ error: jsonError.message,
240
+ position: jsonError.message.match(/position (\d+)/)?.[1],
241
+ preview: jsonString,
242
+ });
243
+ // Fallback to JSON5 for more relaxed parsing
244
+ try {
245
+ return JSON5.parse(jsonString);
246
+ }
247
+ catch (json5Error) {
248
+ // Enhanced error with context
249
+ this.logger.error('JSON5 parse also failed', {
250
+ originalError: jsonError.message,
251
+ json5Error: json5Error.message,
252
+ preview: jsonString.substring(0, 200),
253
+ length: jsonString.length,
254
+ });
255
+ throw new Error(`Failed to parse JSON: ${jsonError.message}\nJSON5 also failed: ${json5Error.message}\nPreview: ${jsonString.substring(0, 200)}${jsonString.length > 200 ? '...' : ''}`);
256
+ }
257
+ }
258
+ }
259
+ /**
260
+ * Sends data through a stream using length-prefixed encoding (libp2p v3 best practice)
261
+ * Each message is automatically prefixed with a varint indicating the message length
262
+ * This ensures proper message boundaries and eliminates concatenation issues
263
+ *
264
+ * @param stream - The stream to send data through
265
+ * @param data - The data to send
266
+ * @param config - Configuration for timeout and other options
267
+ */
268
+ async sendLengthPrefixed(stream, data, config = {}) {
269
+ const lp = lpStream(stream);
270
+ await lp.write(data, { signal: config.signal });
271
+ }
272
+ /**
273
+ * Tracks an active stream handler
274
+ */
275
+ trackStreamHandler(stream, abortController) {
276
+ this.activeStreamHandlers.set(stream.id, { stream, abortController });
277
+ }
278
+ /**
279
+ * Untracks a stream handler
280
+ */
281
+ untrackStreamHandler(streamId) {
282
+ this.activeStreamHandlers.delete(streamId);
283
+ }
284
+ /**
285
+ * Handles an incoming stream on the server side using length-prefixed protocol
286
+ * Uses async read loops instead of event listeners (libp2p v3 best practice)
287
+ * Processes complete messages with proper boundaries
288
+ *
289
+ * @param stream - The incoming stream
290
+ * @param connection - The connection the stream belongs to
291
+ */
292
+ async handleIncomingStream(stream, connection) {
293
+ const lp = lpStream(stream);
294
+ const abortController = new AbortController();
295
+ this.trackStreamHandler(stream, abortController);
296
+ try {
297
+ while (stream.status === 'open' && !abortController.signal.aborted) {
298
+ // Read complete length-prefixed message
299
+ const messageBytes = await lp.read();
300
+ const decoded = new TextDecoder().decode(messageBytes.subarray());
301
+ // Parse JSON (handles markdown blocks, mixed content, and JSON5)
302
+ const message = this.extractAndParseJSON(decoded);
303
+ if (this.isStreamInit(message)) {
304
+ this.handleStreamInitMessage(message, stream);
305
+ // Continue reading for subsequent messages on this stream
306
+ }
307
+ else if (this.isRequest(message)) {
308
+ await this.handleRequestMessage(message, stream, connection);
309
+ }
310
+ else if (this.isResponse(message)) {
311
+ this.logger.warn('Received response message on server-side stream, ignoring', message);
312
+ }
313
+ else {
314
+ this.logger.warn('Received unknown message type', message);
315
+ }
316
+ }
317
+ }
318
+ catch (error) {
319
+ // Stream closed or error occurred
320
+ if (stream.status === 'open') {
321
+ this.logger.error('Error in length-prefixed stream handler:', error);
322
+ this.emit(StreamManagerEvent.StreamError, {
323
+ streamId: stream.id,
324
+ error,
325
+ context: 'incoming',
326
+ });
327
+ }
328
+ }
329
+ finally {
330
+ this.untrackStreamHandler(stream.id);
331
+ }
332
+ }
333
+ /**
334
+ * Handles a request message by emitting an event and sending response
335
+ *
336
+ * @param message - The decoded request message
337
+ * @param stream - The stream to send the response on
338
+ * @param connection - The connection the stream belongs to
339
+ */
340
+ async handleRequestMessage(message, stream, connection) {
341
+ const request = new oRequest(message);
342
+ const responseBuilder = ResponseBuilder.create();
343
+ try {
344
+ // Emit InboundRequest event and wait for handler to process
345
+ const result = await this.emitAsync(StreamManagerEvent.InboundRequest, {
346
+ request,
347
+ stream,
348
+ connection,
349
+ });
350
+ const response = await responseBuilder.build(request, result, null);
351
+ await CoreUtils.sendResponse(response, stream);
352
+ this.logger.debug(`Successfully processed request: method=${request.method}, id=${request.id}`);
353
+ }
354
+ catch (error) {
355
+ this.logger.error(`Error processing request: method=${request.method}, id=${request.id}`, error);
356
+ const errorResponse = await responseBuilder.buildError(request, error);
357
+ await CoreUtils.sendResponse(errorResponse, stream);
358
+ this.emit(StreamManagerEvent.StreamError, {
359
+ streamId: stream.id,
360
+ error: error instanceof Error ? error : new Error(String(error)),
361
+ context: 'incoming',
362
+ });
363
+ }
364
+ }
365
+ /**
366
+ * Handles an outgoing stream on the client side using length-prefixed protocol
367
+ * Uses async read loops to process responses with proper message boundaries
368
+ *
369
+ * @param stream - The outgoing stream
370
+ * @param emitter - Event emitter for chunk events
371
+ * @param config - Configuration including abort signal
372
+ * @param requestId - Optional request ID to filter responses (for stream reuse scenarios)
373
+ * @returns Promise that resolves with the final response
374
+ */
375
+ async handleOutgoingStream(stream, emitter, config = {}, requestId) {
376
+ const lp = lpStream(stream);
377
+ const abortController = new AbortController();
378
+ this.trackStreamHandler(stream, abortController);
379
+ // Combine external signal with our internal abort controller
380
+ const combinedSignal = config.signal
381
+ ? AbortSignal.any([config.signal, abortController.signal])
382
+ : abortController.signal;
383
+ try {
384
+ while (stream.status === 'open' && !combinedSignal.aborted) {
385
+ this.logger.debug('Waiting for response...');
386
+ // Read complete length-prefixed message
387
+ const messageBytes = await lp.read({ signal: combinedSignal });
388
+ const decoded = new TextDecoder().decode(messageBytes.subarray());
389
+ // Parse JSON (handles markdown blocks, mixed content, and JSON5)
390
+ const message = this.extractAndParseJSON(decoded);
391
+ if (this.isResponse(message)) {
392
+ const response = new oResponse({
393
+ ...message.result,
394
+ id: message.id,
395
+ });
396
+ // Filter by request ID if provided
397
+ if (requestId !== undefined && response.id !== requestId) {
398
+ this.logger.debug(`Ignoring response for different request (expected: ${requestId}, received: ${response.id})`);
399
+ continue;
400
+ }
401
+ // Emit chunk for streaming responses
402
+ emitter.emit('chunk', response);
403
+ // Check if this is the last chunk
404
+ if (response.result._last || !response.result._isStreaming) {
405
+ return response;
406
+ }
407
+ }
408
+ else if (this.isRequest(message)) {
409
+ // Process incoming router requests via event emission
410
+ const hasListeners = this.eventEmitter.listenerCount(StreamManagerEvent.InboundRequest) >
411
+ 0;
412
+ if (hasListeners) {
413
+ this.logger.debug('Received router request on client-side stream, processing...', message);
414
+ // Use handleRequestMessage which emits the InboundRequest event
415
+ await this.handleRequestMessage(message, stream, this.p2pConnection);
416
+ }
417
+ else {
418
+ this.logger.warn('Received request message on client-side stream, ignoring (no handler)', message);
419
+ }
420
+ }
421
+ else {
422
+ this.logger.warn('Received unknown message type', message);
423
+ }
424
+ }
425
+ throw new oError(oErrorCodes.TIMEOUT, 'Stream closed before response received');
426
+ }
427
+ catch (error) {
428
+ this.emit(StreamManagerEvent.StreamError, {
429
+ streamId: stream.id,
430
+ error: error instanceof Error ? error : new Error(String(error)),
431
+ context: 'outgoing',
432
+ });
433
+ if (combinedSignal.aborted) {
434
+ throw new oError(oErrorCodes.TIMEOUT, 'Request aborted');
435
+ }
436
+ throw error;
437
+ }
438
+ finally {
439
+ this.untrackStreamHandler(stream.id);
440
+ }
441
+ }
442
+ /**
443
+ * Forwards a request to the next hop and relays response chunks back
444
+ * This implements the middleware/proxy pattern for intermediate nodes
445
+ *
446
+ * @param request - The router request to forward
447
+ * @param incomingStream - The stream to send responses back on
448
+ * @param dialFn - Function to dial the next hop connection
449
+ */
450
+ async forwardRequest(request, incomingStream, dialFn) {
451
+ try {
452
+ // Connect to next hop
453
+ const nextHopConnection = await dialFn(request.params.address);
454
+ // Set up chunk relay - forward responses from next hop back to incoming stream
455
+ nextHopConnection.onChunk(async (response) => {
456
+ try {
457
+ await CoreUtils.sendResponse(response, incomingStream);
458
+ }
459
+ catch (error) {
460
+ this.logger.error('Error forwarding chunk:', error);
461
+ }
462
+ });
463
+ // Transmit the request to next hop
464
+ await nextHopConnection.transmit(request);
465
+ }
466
+ catch (error) {
467
+ this.logger.error('Error forwarding request:', error);
468
+ // Send error response back on incoming stream using ResponseBuilder
469
+ const responseBuilder = ResponseBuilder.create();
470
+ const errorResponse = await responseBuilder.buildError(request, error);
471
+ await CoreUtils.sendResponse(errorResponse, incomingStream);
472
+ }
473
+ }
474
+ /**
475
+ * Close the stream manager and cleanup resources
476
+ */
477
+ async close() {
478
+ this.logger.info('Closing stream manager', {
479
+ activeStreams: this.streams.size,
480
+ activeHandlers: this.activeStreamHandlers.size,
481
+ });
482
+ // Abort all active stream handlers
483
+ for (const [streamId, { abortController },] of this.activeStreamHandlers.entries()) {
484
+ abortController.abort();
485
+ }
486
+ this.activeStreamHandlers.clear();
487
+ // Close all tracked streams
488
+ const closePromises = Array.from(this.streams.values()).map(async (wrappedStream) => {
489
+ try {
490
+ if (wrappedStream.p2pStream.status === 'open') {
491
+ await wrappedStream.p2pStream.close();
492
+ }
493
+ }
494
+ catch (error) {
495
+ this.logger.debug('Error closing stream during manager close', {
496
+ streamId: wrappedStream.p2pStream.id,
497
+ error: error.message,
498
+ });
499
+ }
500
+ });
501
+ await Promise.all(closePromises);
502
+ // Clear tracking
503
+ this.streams.clear();
504
+ this.isInitialized = false;
505
+ this.emit(StreamManagerEvent.ManagerClosed, undefined);
506
+ this.logger.info('Stream manager closed');
507
+ }
508
+ /**
509
+ * Add event listener
510
+ */
511
+ on(event, listener) {
512
+ this.eventEmitter.on(event, listener);
513
+ }
514
+ /**
515
+ * Remove event listener
516
+ */
517
+ off(event, listener) {
518
+ this.eventEmitter.off(event, listener);
519
+ }
520
+ /**
521
+ * Emit event
522
+ */
523
+ emit(event, data) {
524
+ this.eventEmitter.emit(event, data);
525
+ }
526
+ }
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Events emitted by StreamManager
3
+ */
4
+ export declare enum StreamManagerEvent {
5
+ ManagerInitialized = "manager-initialized",
6
+ ManagerClosed = "manager-closed",
7
+ ReaderStarted = "reader-started",
8
+ ReaderFailed = "reader-failed",
9
+ ReaderRecovered = "reader-recovered",
10
+ RecoveryFailed = "recovery-failed",
11
+ StreamReplaced = "stream-replaced",
12
+ StreamFailed = "stream-failed",
13
+ StreamIdentified = "stream-identified",
14
+ InboundRequest = "inbound-request",
15
+ InboundResponse = "inbound-response",
16
+ StreamError = "stream-error"
17
+ }
18
+ /**
19
+ * Event data interfaces
20
+ */
21
+ export interface InitializedData {
22
+ }
23
+ export interface ReaderStartedData {
24
+ streamId: string;
25
+ }
26
+ export interface ReaderFailedData {
27
+ error?: string;
28
+ failureCount: number;
29
+ }
30
+ export interface ReaderRecoveredData {
31
+ failureCount: number;
32
+ }
33
+ export interface RecoveryFailedData {
34
+ error: string;
35
+ failureCount: number;
36
+ }
37
+ export interface StreamReplacedData {
38
+ index: number;
39
+ streamType: string;
40
+ }
41
+ export interface StreamFailedData {
42
+ index: number;
43
+ streamId: string;
44
+ error?: string;
45
+ failureCount: number;
46
+ }
47
+ export interface StreamIdentifiedData {
48
+ streamId: string;
49
+ role: 'reader' | 'standard';
50
+ connectionId?: string;
51
+ }
52
+ export interface InboundRequestData {
53
+ request: any;
54
+ stream: any;
55
+ connection: any;
56
+ }
57
+ export interface InboundResponseData {
58
+ response: any;
59
+ streamId: string;
60
+ }
61
+ export interface StreamErrorData {
62
+ streamId: string;
63
+ error: Error;
64
+ context: 'incoming' | 'outgoing' | 'general';
65
+ }
66
+ /**
67
+ * Mapped type for type-safe event listeners
68
+ */
69
+ export type StreamManagerEventData = {
70
+ [StreamManagerEvent.ManagerInitialized]: InitializedData;
71
+ [StreamManagerEvent.ManagerClosed]: void;
72
+ [StreamManagerEvent.ReaderStarted]: ReaderStartedData;
73
+ [StreamManagerEvent.ReaderFailed]: ReaderFailedData;
74
+ [StreamManagerEvent.ReaderRecovered]: ReaderRecoveredData;
75
+ [StreamManagerEvent.RecoveryFailed]: RecoveryFailedData;
76
+ [StreamManagerEvent.StreamReplaced]: StreamReplacedData;
77
+ [StreamManagerEvent.StreamFailed]: StreamFailedData;
78
+ [StreamManagerEvent.StreamIdentified]: StreamIdentifiedData;
79
+ [StreamManagerEvent.InboundRequest]: InboundRequestData;
80
+ [StreamManagerEvent.InboundResponse]: InboundResponseData;
81
+ [StreamManagerEvent.StreamError]: StreamErrorData;
82
+ };
83
+ //# sourceMappingURL=stream-manager.events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream-manager.events.d.ts","sourceRoot":"","sources":["../../../src/connection/stream-manager.events.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,oBAAY,kBAAkB;IAC5B,kBAAkB,wBAAwB;IAC1C,aAAa,mBAAmB;IAChC,aAAa,mBAAmB;IAChC,YAAY,kBAAkB;IAC9B,eAAe,qBAAqB;IACpC,cAAc,oBAAoB;IAClC,cAAc,oBAAoB;IAClC,YAAY,kBAAkB;IAC9B,gBAAgB,sBAAsB;IACtC,cAAc,oBAAoB;IAClC,eAAe,qBAAqB;IACpC,WAAW,iBAAiB;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;CAAG;AAEnC,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,QAAQ,GAAG,UAAU,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,GAAG,CAAC;IACb,MAAM,EAAE,GAAG,CAAC;IACZ,UAAU,EAAE,GAAG,CAAC;CACjB;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,GAAG,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,KAAK,CAAC;IACb,OAAO,EAAE,UAAU,GAAG,UAAU,GAAG,SAAS,CAAC;CAC9C;AAED;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,CAAC,kBAAkB,CAAC,kBAAkB,CAAC,EAAE,eAAe,CAAC;IACzD,CAAC,kBAAkB,CAAC,aAAa,CAAC,EAAE,IAAI,CAAC;IACzC,CAAC,kBAAkB,CAAC,aAAa,CAAC,EAAE,iBAAiB,CAAC;IACtD,CAAC,kBAAkB,CAAC,YAAY,CAAC,EAAE,gBAAgB,CAAC;IACpD,CAAC,kBAAkB,CAAC,eAAe,CAAC,EAAE,mBAAmB,CAAC;IAC1D,CAAC,kBAAkB,CAAC,cAAc,CAAC,EAAE,kBAAkB,CAAC;IACxD,CAAC,kBAAkB,CAAC,cAAc,CAAC,EAAE,kBAAkB,CAAC;IACxD,CAAC,kBAAkB,CAAC,YAAY,CAAC,EAAE,gBAAgB,CAAC;IACpD,CAAC,kBAAkB,CAAC,gBAAgB,CAAC,EAAE,oBAAoB,CAAC;IAC5D,CAAC,kBAAkB,CAAC,cAAc,CAAC,EAAE,kBAAkB,CAAC;IACxD,CAAC,kBAAkB,CAAC,eAAe,CAAC,EAAE,mBAAmB,CAAC;IAC1D,CAAC,kBAAkB,CAAC,WAAW,CAAC,EAAE,eAAe,CAAC;CACnD,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Events emitted by StreamManager
3
+ */
4
+ export var StreamManagerEvent;
5
+ (function (StreamManagerEvent) {
6
+ StreamManagerEvent["ManagerInitialized"] = "manager-initialized";
7
+ StreamManagerEvent["ManagerClosed"] = "manager-closed";
8
+ StreamManagerEvent["ReaderStarted"] = "reader-started";
9
+ StreamManagerEvent["ReaderFailed"] = "reader-failed";
10
+ StreamManagerEvent["ReaderRecovered"] = "reader-recovered";
11
+ StreamManagerEvent["RecoveryFailed"] = "recovery-failed";
12
+ StreamManagerEvent["StreamReplaced"] = "stream-replaced";
13
+ StreamManagerEvent["StreamFailed"] = "stream-failed";
14
+ StreamManagerEvent["StreamIdentified"] = "stream-identified";
15
+ StreamManagerEvent["InboundRequest"] = "inbound-request";
16
+ StreamManagerEvent["InboundResponse"] = "inbound-response";
17
+ StreamManagerEvent["StreamError"] = "stream-error";
18
+ })(StreamManagerEvent || (StreamManagerEvent = {}));
@@ -8,7 +8,6 @@ declare const oNodeTool_base: typeof oServerNode;
8
8
  * @returns A new class that extends the base class and implements the oTool interface
9
9
  */
10
10
  export declare class oNodeTool extends oNodeTool_base {
11
- private streamHandler;
12
11
  handleProtocolReuse(address: oAddress): Promise<void>;
13
12
  handleProtocol(address: oAddress): Promise<void>;
14
13
  initializeProtocols(): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"o-node.tool.d.ts","sourceRoot":"","sources":["../../src/o-node.tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAoB,MAAM,eAAe,CAAC;AAErE,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;;AAMrD;;;;GAIG;AACH,qBAAa,SAAU,SAAQ,cAAkB;IAC/C,OAAO,CAAC,aAAa,CAAiB;IAEhC,mBAAmB,CAAC,OAAO,EAAE,QAAQ;IAuBrC,cAAc,CAAC,OAAO,EAAE,QAAQ;IAsBhC,mBAAmB;IAWnB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAM3B,iBAAiB,CACrB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC,IAAI,CAAC;IAIV,YAAY,CAChB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,UAAU,EACtB,KAAK,CAAC,EAAE,OAAO,GACd,OAAO,CAAC,IAAI,CAAC;IAyCV,cAAc,IAAI,OAAO,CAAC,GAAG,CAAC;IAQ9B,oBAAoB,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC;CAiC5D"}
1
+ {"version":3,"file":"o-node.tool.d.ts","sourceRoot":"","sources":["../../src/o-node.tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAoB,MAAM,eAAe,CAAC;AAErE,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;;AAOrD;;;;GAIG;AACH,qBAAa,SAAU,SAAQ,cAAkB;IACzC,mBAAmB,CAAC,OAAO,EAAE,QAAQ;IAuBrC,cAAc,CAAC,OAAO,EAAE,QAAQ;IAsBhC,mBAAmB;IAWnB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAK3B,iBAAiB,CACrB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC,IAAI,CAAC;IAIV,YAAY,CAChB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,UAAU,EACtB,KAAK,CAAC,EAAE,OAAO,GACd,OAAO,CAAC,IAAI,CAAC;IAwDV,cAAc,IAAI,OAAO,CAAC,GAAG,CAAC;IAQ9B,oBAAoB,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC;CAiC5D"}