@olane/o-node 0.7.29 → 0.7.33

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 (28) hide show
  1. package/dist/src/connection/interfaces/o-node-connection.config.d.ts +5 -0
  2. package/dist/src/connection/interfaces/o-node-connection.config.d.ts.map +1 -1
  3. package/dist/src/connection/o-node-connection.d.ts.map +1 -1
  4. package/dist/src/connection/o-node-connection.js +10 -1
  5. package/dist/src/connection/stream-handler.config.d.ts +13 -0
  6. package/dist/src/connection/stream-handler.config.d.ts.map +1 -1
  7. package/dist/src/connection/stream-handler.d.ts +35 -1
  8. package/dist/src/connection/stream-handler.d.ts.map +1 -1
  9. package/dist/src/connection/stream-handler.js +143 -5
  10. package/dist/src/interfaces/o-node.config.d.ts +7 -0
  11. package/dist/src/interfaces/o-node.config.d.ts.map +1 -1
  12. package/dist/src/managers/o-connection-heartbeat.manager.d.ts.map +1 -1
  13. package/dist/src/managers/o-connection-heartbeat.manager.js +6 -3
  14. package/dist/src/managers/o-reconnection.manager.d.ts.map +1 -1
  15. package/dist/src/managers/o-reconnection.manager.js +34 -21
  16. package/dist/src/o-node.d.ts +6 -2
  17. package/dist/src/o-node.d.ts.map +1 -1
  18. package/dist/src/o-node.hierarchy-manager.d.ts +41 -0
  19. package/dist/src/o-node.hierarchy-manager.d.ts.map +1 -1
  20. package/dist/src/o-node.hierarchy-manager.js +170 -1
  21. package/dist/src/o-node.js +71 -29
  22. package/dist/src/o-node.notification-manager.d.ts +6 -17
  23. package/dist/src/o-node.notification-manager.d.ts.map +1 -1
  24. package/dist/src/o-node.notification-manager.js +38 -119
  25. package/dist/src/o-node.tool.d.ts.map +1 -1
  26. package/dist/src/o-node.tool.js +8 -1
  27. package/dist/test/connection-management.spec.js +54 -50
  28. package/package.json +7 -7
@@ -3,5 +3,10 @@ import { oConnectionConfig } from '@olane/o-core';
3
3
  export interface oNodeConnectionConfig extends oConnectionConfig {
4
4
  p2pConnection: Connection;
5
5
  runOnLimitedConnection?: boolean;
6
+ /**
7
+ * Enable length-prefixed streaming (libp2p v3 best practice)
8
+ * @default false (for backward compatibility)
9
+ */
10
+ useLengthPrefixing?: boolean;
6
11
  }
7
12
  //# sourceMappingURL=o-node-connection.config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"o-node-connection.config.d.ts","sourceRoot":"","sources":["../../../../src/connection/interfaces/o-node-connection.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAElD,MAAM,WAAW,qBAAsB,SAAQ,iBAAiB;IAC9D,aAAa,EAAE,UAAU,CAAC;IAC1B,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC"}
1
+ {"version":3,"file":"o-node-connection.config.d.ts","sourceRoot":"","sources":["../../../../src/connection/interfaces/o-node-connection.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAElD,MAAM,WAAW,qBAAsB,SAAQ,iBAAiB;IAC9D,aAAa,EAAE,UAAU,CAAC;IAC1B,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC;;;OAGG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B"}
@@ -1 +1 @@
1
- {"version":3,"file":"o-node-connection.d.ts","sourceRoot":"","sources":["../../../src/connection/o-node-connection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAEL,WAAW,EAGX,QAAQ,EACR,SAAS,EACV,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,qBAAqB,EAAE,MAAM,0CAA0C,CAAC;AACjF,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGpD,qBAAa,eAAgB,SAAQ,WAAW;IAIlC,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,qBAAqB;IAHrD,aAAa,EAAE,UAAU,CAAC;IACjC,SAAS,CAAC,aAAa,EAAE,aAAa,CAAC;gBAER,MAAM,EAAE,qBAAqB;IAM5D,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM;IAmBlB,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC;IAkBpC,QAAQ,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC;IA0C/C,YAAY,CAAC,MAAM,EAAE,MAAM;IAQ3B,KAAK,CAAC,KAAK,EAAE,KAAK;IAMlB,KAAK;CAKZ"}
1
+ {"version":3,"file":"o-node-connection.d.ts","sourceRoot":"","sources":["../../../src/connection/o-node-connection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAEL,WAAW,EAGX,QAAQ,EACR,SAAS,EACV,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,qBAAqB,EAAE,MAAM,0CAA0C,CAAC;AACjF,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGpD,qBAAa,eAAgB,SAAQ,WAAW;IAIlC,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,qBAAqB;IAHrD,aAAa,EAAE,UAAU,CAAC;IACjC,SAAS,CAAC,aAAa,EAAE,aAAa,CAAC;gBAER,MAAM,EAAE,qBAAqB;IAM5D,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM;IAmBlB,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC;IAmBpC,QAAQ,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC;IAkD/C,YAAY,CAAC,MAAM,EAAE,MAAM;IAQ3B,KAAK,CAAC,KAAK,EAAE,KAAK;IAMlB,KAAK;CAKZ"}
@@ -28,6 +28,7 @@ export class oNodeConnection extends oConnection {
28
28
  runOnLimitedConnection: this.config.runOnLimitedConnection ?? false,
29
29
  reusePolicy: 'none', // Default policy, can be overridden in subclasses
30
30
  drainTimeoutMs: this.config.drainTimeoutMs,
31
+ useLengthPrefixing: true,
31
32
  };
32
33
  return this.streamHandler.getOrCreateStream(this.p2pConnection, this.nextHopAddress.protocol, streamConfig);
33
34
  }
@@ -42,10 +43,18 @@ export class oNodeConnection extends oConnection {
42
43
  signal: this.abortSignal,
43
44
  drainTimeoutMs: this.config.drainTimeoutMs,
44
45
  reusePolicy: 'none', // Default policy
46
+ useLengthPrefixing: this.config.useLengthPrefixing ?? true,
45
47
  };
46
48
  // Send the request with backpressure handling
47
49
  const data = new TextEncoder().encode(request.toString());
48
- await this.streamHandler.send(stream, data, streamConfig);
50
+ // Use length-prefixed encoding if enabled
51
+ if (streamConfig.useLengthPrefixing) {
52
+ this.logger.info('Length prefix enabled...');
53
+ await this.streamHandler.sendLengthPrefixed(stream, data, streamConfig);
54
+ }
55
+ else {
56
+ await this.streamHandler.send(stream, data, streamConfig);
57
+ }
49
58
  // Handle response using StreamHandler
50
59
  // Pass request handler if configured to enable bidirectional stream processing
51
60
  // Pass request ID to enable proper response correlation on shared streams
@@ -34,6 +34,19 @@ export interface StreamHandlerConfig {
34
34
  * AbortSignal for cancellation
35
35
  */
36
36
  signal?: AbortSignal;
37
+ /**
38
+ * Enable length-prefixed streaming (libp2p v3 best practice)
39
+ * When enabled, all messages are prefixed with a varint indicating message length
40
+ * This provides proper message boundaries and eliminates concatenation issues
41
+ * @default false (for backward compatibility)
42
+ */
43
+ useLengthPrefixing?: boolean;
44
+ /**
45
+ * Auto-detect protocol (length-prefixed vs raw JSON)
46
+ * When enabled, automatically detects the protocol by examining first byte
47
+ * @default false
48
+ */
49
+ autoDetectProtocol?: boolean;
37
50
  }
38
51
  /**
39
52
  * Context for stream lifecycle operations
@@ -1 +1 @@
1
- {"version":3,"file":"stream-handler.config.d.ts","sourceRoot":"","sources":["../../../src/connection/stream-handler.config.ts"],"names":[],"mappings":";AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEhD;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;AAE1D;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;;OAKG;IACH,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAEhC;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;;OAGG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAEjC;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAE5B;;OAEG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,mBAAmB,CAAC;CAC7B"}
1
+ {"version":3,"file":"stream-handler.config.d.ts","sourceRoot":"","sources":["../../../src/connection/stream-handler.config.ts"],"names":[],"mappings":";AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEhD;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;AAE1D;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;;OAKG;IACH,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAEhC;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;;OAGG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAEjC;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAE5B;;OAEG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;IAErB;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAE7B;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,mBAAmB,CAAC;CAC7B"}
@@ -47,6 +47,16 @@ export declare class StreamHandler {
47
47
  * @param config - Configuration for timeout and other options
48
48
  */
49
49
  send(stream: Stream, data: Uint8Array, config?: StreamHandlerConfig): Promise<void>;
50
+ /**
51
+ * Sends data through a stream using length-prefixed encoding (libp2p v3 best practice)
52
+ * Each message is automatically prefixed with a varint indicating the message length
53
+ * This ensures proper message boundaries and eliminates concatenation issues
54
+ *
55
+ * @param stream - The stream to send data through
56
+ * @param data - The data to send
57
+ * @param config - Configuration for timeout and other options
58
+ */
59
+ sendLengthPrefixed(stream: Stream, data: Uint8Array, config?: StreamHandlerConfig): Promise<void>;
50
60
  /**
51
61
  * Closes a stream safely with error handling
52
62
  *
@@ -54,6 +64,16 @@ export declare class StreamHandler {
54
64
  * @param config - Configuration including reuse policy
55
65
  */
56
66
  close(stream: Stream, config?: StreamHandlerConfig): Promise<void>;
67
+ /**
68
+ * Handles an incoming stream on the server side using length-prefixed protocol
69
+ * Uses async read loops instead of event listeners (libp2p v3 best practice)
70
+ * Processes complete messages with proper boundaries
71
+ *
72
+ * @param stream - The incoming stream
73
+ * @param connection - The connection the stream belongs to
74
+ * @param toolExecutor - Function to execute tools for requests
75
+ */
76
+ handleIncomingStreamLP(stream: Stream, connection: Connection, toolExecutor: (request: oRequest, stream: Stream) => Promise<RunResult>): Promise<void>;
57
77
  /**
58
78
  * Handles an incoming stream on the server side
59
79
  * Attaches message listener immediately (libp2p v3 best practice)
@@ -62,16 +82,30 @@ export declare class StreamHandler {
62
82
  * @param stream - The incoming stream
63
83
  * @param connection - The connection the stream belongs to
64
84
  * @param toolExecutor - Function to execute tools for requests
85
+ * @param config - Configuration to determine protocol handling
65
86
  */
66
- handleIncomingStream(stream: Stream, connection: Connection, toolExecutor: (request: oRequest, stream: Stream) => Promise<RunResult>): Promise<void>;
87
+ handleIncomingStream(stream: Stream, connection: Connection, toolExecutor: (request: oRequest, stream: Stream) => Promise<RunResult>, config?: StreamHandlerConfig): Promise<void>;
67
88
  /**
68
89
  * Handles a request message by executing the tool and sending response
69
90
  *
70
91
  * @param message - The decoded request message
71
92
  * @param stream - The stream to send the response on
72
93
  * @param toolExecutor - Function to execute the tool
94
+ * @param useLengthPrefixing - Whether to use length-prefixed response encoding
73
95
  */
74
96
  private handleRequestMessage;
97
+ /**
98
+ * Handles an outgoing stream on the client side using length-prefixed protocol
99
+ * Uses async read loops to process responses with proper message boundaries
100
+ *
101
+ * @param stream - The outgoing stream
102
+ * @param emitter - Event emitter for chunk events
103
+ * @param config - Configuration including abort signal
104
+ * @param requestHandler - Optional handler for processing router requests received on this stream
105
+ * @param requestId - Optional request ID to filter responses (for stream reuse scenarios)
106
+ * @returns Promise that resolves with the final response
107
+ */
108
+ handleOutgoingStreamLP(stream: Stream, emitter: EventEmitter, config?: StreamHandlerConfig, requestHandler?: (request: oRequest, stream: Stream) => Promise<RunResult>, requestId?: string | number): Promise<oResponse>;
75
109
  /**
76
110
  * Handles an outgoing stream on the client side
77
111
  * Listens for response messages and emits them via the event emitter
@@ -1 +1 @@
1
- {"version":3,"file":"stream-handler.d.ts","sourceRoot":"","sources":["../../../src/connection/stream-handler.ts"],"names":[],"mappings":";AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EACL,QAAQ,EACR,SAAS,EAIT,MAAM,EAEP,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAGtE;;;;;;;GAOG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAS;gBAEX,MAAM,CAAC,EAAE,MAAM;IAI3B;;;OAGG;IACH,SAAS,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO;IAIhC;;;OAGG;IACH,UAAU,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO;IAIjC;;OAEG;IACG,aAAa,CAAC,KAAK,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IAI7C;;;;;;OAMG;IACG,iBAAiB,CACrB,UAAU,EAAE,UAAU,EACtB,QAAQ,EAAE,MAAM,EAChB,MAAM,GAAE,mBAAwB,GAC/B,OAAO,CAAC,MAAM,CAAC;IAoClB;;;;;;OAMG;IACG,IAAI,CACR,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,UAAU,EAChB,MAAM,GAAE,mBAAwB,GAC/B,OAAO,CAAC,IAAI,CAAC;IAiBhB;;;;;OAKG;IACG,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,GAAE,mBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC;IAiB5E;;;;;;;;OAQG;IACG,oBAAoB,CACxB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,UAAU,EACtB,YAAY,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,GACtE,OAAO,CAAC,IAAI,CAAC;IAsChB;;;;;;OAMG;YACW,oBAAoB;IA4BlC;;;;;;;;;;;OAWG;IACG,oBAAoB,CACxB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,YAAY,EACrB,MAAM,GAAE,mBAAwB,EAChC,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,EAC1E,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,GAC1B,OAAO,CAAC,SAAS,CAAC;IA8GrB;;;;;;;OAOG;IACG,cAAc,CAClB,OAAO,EAAE,cAAc,EACvB,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,CAAC,GAChD,OAAO,CAAC,IAAI,CAAC;CAyBjB"}
1
+ {"version":3,"file":"stream-handler.d.ts","sourceRoot":"","sources":["../../../src/connection/stream-handler.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
- import { oRequest, CoreUtils, oError, oErrorCodes, Logger, ResponseBuilder, } from '@olane/o-core';
1
+ import { oRequest, oResponse, CoreUtils, oError, oErrorCodes, Logger, ResponseBuilder, } from '@olane/o-core';
2
+ import { lpStream } from '@olane/o-config';
2
3
  /**
3
4
  * StreamHandler centralizes all stream-related functionality including:
4
5
  * - Message type detection (request vs response)
@@ -82,6 +83,19 @@ export class StreamHandler {
82
83
  this.logger.debug('Stream drained successfully');
83
84
  }
84
85
  }
86
+ /**
87
+ * Sends data through a stream using length-prefixed encoding (libp2p v3 best practice)
88
+ * Each message is automatically prefixed with a varint indicating the message length
89
+ * This ensures proper message boundaries and eliminates concatenation issues
90
+ *
91
+ * @param stream - The stream to send data through
92
+ * @param data - The data to send
93
+ * @param config - Configuration for timeout and other options
94
+ */
95
+ async sendLengthPrefixed(stream, data, config = {}) {
96
+ const lp = lpStream(stream);
97
+ await lp.write(data, { signal: config.signal });
98
+ }
85
99
  /**
86
100
  * Closes a stream safely with error handling
87
101
  *
@@ -104,6 +118,45 @@ export class StreamHandler {
104
118
  }
105
119
  }
106
120
  }
121
+ /**
122
+ * Handles an incoming stream on the server side using length-prefixed protocol
123
+ * Uses async read loops instead of event listeners (libp2p v3 best practice)
124
+ * Processes complete messages with proper boundaries
125
+ *
126
+ * @param stream - The incoming stream
127
+ * @param connection - The connection the stream belongs to
128
+ * @param toolExecutor - Function to execute tools for requests
129
+ */
130
+ async handleIncomingStreamLP(stream, connection, toolExecutor) {
131
+ const lp = lpStream(stream);
132
+ try {
133
+ while (stream.status === 'open') {
134
+ // Read complete length-prefixed message
135
+ const messageBytes = await lp.read();
136
+ const decoded = new TextDecoder().decode(messageBytes.subarray());
137
+ // Ignore non-JSON messages
138
+ if (!decoded.startsWith('{')) {
139
+ continue;
140
+ }
141
+ const message = JSON.parse(decoded);
142
+ if (this.isRequest(message)) {
143
+ await this.handleRequestMessage(message, stream, toolExecutor, true);
144
+ }
145
+ else if (this.isResponse(message)) {
146
+ this.logger.warn('Received response message on server-side stream, ignoring', message);
147
+ }
148
+ else {
149
+ this.logger.warn('Received unknown message type', message);
150
+ }
151
+ }
152
+ }
153
+ catch (error) {
154
+ // Stream closed or error occurred
155
+ if (stream.status === 'open') {
156
+ this.logger.error('Error in length-prefixed stream handler:', error);
157
+ }
158
+ }
159
+ }
107
160
  /**
108
161
  * Handles an incoming stream on the server side
109
162
  * Attaches message listener immediately (libp2p v3 best practice)
@@ -112,8 +165,13 @@ export class StreamHandler {
112
165
  * @param stream - The incoming stream
113
166
  * @param connection - The connection the stream belongs to
114
167
  * @param toolExecutor - Function to execute tools for requests
168
+ * @param config - Configuration to determine protocol handling
115
169
  */
116
- async handleIncomingStream(stream, connection, toolExecutor) {
170
+ async handleIncomingStream(stream, connection, toolExecutor, config = {}) {
171
+ // Route to length-prefixed handler if enabled
172
+ if (config.useLengthPrefixing) {
173
+ return this.handleIncomingStreamLP(stream, connection, toolExecutor);
174
+ }
117
175
  // CRITICAL: Attach message listener immediately to prevent buffer overflow (libp2p v3)
118
176
  const messageHandler = async (event) => {
119
177
  try {
@@ -153,8 +211,9 @@ export class StreamHandler {
153
211
  * @param message - The decoded request message
154
212
  * @param stream - The stream to send the response on
155
213
  * @param toolExecutor - Function to execute the tool
214
+ * @param useLengthPrefixing - Whether to use length-prefixed response encoding
156
215
  */
157
- async handleRequestMessage(message, stream, toolExecutor) {
216
+ async handleRequestMessage(message, stream, toolExecutor, useLengthPrefixing = false) {
158
217
  const request = new oRequest(message);
159
218
  const responseBuilder = ResponseBuilder.create();
160
219
  try {
@@ -163,13 +222,88 @@ export class StreamHandler {
163
222
  // );
164
223
  const result = await toolExecutor(request, stream);
165
224
  const response = await responseBuilder.build(request, result, null);
166
- await CoreUtils.sendResponse(response, stream);
225
+ // Use length-prefixed encoding if enabled
226
+ if (useLengthPrefixing) {
227
+ await CoreUtils.sendResponseLP(response, stream);
228
+ }
229
+ else {
230
+ await CoreUtils.sendResponse(response, stream);
231
+ }
167
232
  this.logger.debug(`Successfully processed request: method=${request.method}, id=${request.id}`);
168
233
  }
169
234
  catch (error) {
170
235
  this.logger.error(`Error processing request: method=${request.method}, id=${request.id}`, error);
171
236
  const errorResponse = await responseBuilder.buildError(request, error);
172
- await CoreUtils.sendResponse(errorResponse, stream);
237
+ // Use length-prefixed encoding if enabled
238
+ if (useLengthPrefixing) {
239
+ await CoreUtils.sendResponseLP(errorResponse, stream);
240
+ }
241
+ else {
242
+ await CoreUtils.sendResponse(errorResponse, stream);
243
+ }
244
+ }
245
+ }
246
+ /**
247
+ * Handles an outgoing stream on the client side using length-prefixed protocol
248
+ * Uses async read loops to process responses with proper message boundaries
249
+ *
250
+ * @param stream - The outgoing stream
251
+ * @param emitter - Event emitter for chunk events
252
+ * @param config - Configuration including abort signal
253
+ * @param requestHandler - Optional handler for processing router requests received on this stream
254
+ * @param requestId - Optional request ID to filter responses (for stream reuse scenarios)
255
+ * @returns Promise that resolves with the final response
256
+ */
257
+ async handleOutgoingStreamLP(stream, emitter, config = {}, requestHandler, requestId) {
258
+ const lp = lpStream(stream);
259
+ try {
260
+ while (stream.status === 'open') {
261
+ // Read complete length-prefixed message
262
+ const messageBytes = await lp.read({ signal: config.signal });
263
+ const decoded = new TextDecoder().decode(messageBytes.subarray());
264
+ // Ignore non-JSON messages
265
+ if (!decoded.startsWith('{')) {
266
+ continue;
267
+ }
268
+ const message = JSON.parse(decoded);
269
+ if (this.isResponse(message)) {
270
+ const response = new oResponse({
271
+ ...message.result,
272
+ id: message.id,
273
+ });
274
+ // Filter by request ID if provided
275
+ if (requestId !== undefined && response.id !== requestId) {
276
+ this.logger.debug(`Ignoring response for different request (expected: ${requestId}, received: ${response.id})`);
277
+ continue;
278
+ }
279
+ // Emit chunk for streaming responses
280
+ emitter.emit('chunk', response);
281
+ // Check if this is the last chunk
282
+ if (response.result._last || !response.result._isStreaming) {
283
+ return response;
284
+ }
285
+ }
286
+ else if (this.isRequest(message)) {
287
+ // Process incoming router requests if handler is provided
288
+ if (requestHandler) {
289
+ this.logger.debug('Received router request on client-side stream, processing...', message);
290
+ await this.handleRequestMessage(message, stream, requestHandler, true);
291
+ }
292
+ else {
293
+ this.logger.warn('Received request message on client-side stream, ignoring (no handler)', message);
294
+ }
295
+ }
296
+ else {
297
+ this.logger.warn('Received unknown message type', message);
298
+ }
299
+ }
300
+ throw new oError(oErrorCodes.TIMEOUT, 'Stream closed before response received');
301
+ }
302
+ catch (error) {
303
+ if (config.signal?.aborted) {
304
+ throw new oError(oErrorCodes.TIMEOUT, 'Request aborted');
305
+ }
306
+ throw error;
173
307
  }
174
308
  }
175
309
  /**
@@ -185,6 +319,10 @@ export class StreamHandler {
185
319
  * @returns Promise that resolves with the final response
186
320
  */
187
321
  async handleOutgoingStream(stream, emitter, config = {}, requestHandler, requestId) {
322
+ // Route to length-prefixed handler if enabled
323
+ if (config.useLengthPrefixing) {
324
+ return this.handleOutgoingStreamLP(stream, emitter, config, requestHandler, requestId);
325
+ }
188
326
  return new Promise((resolve, reject) => {
189
327
  let lastResponse;
190
328
  const messageHandler = async (event) => {
@@ -32,5 +32,12 @@ export interface oNodeConfig extends oCoreConfig {
32
32
  drainTimeoutMs?: number;
33
33
  };
34
34
  runOnLimitedConnection?: boolean;
35
+ /**
36
+ * Enable length-prefixed streaming (libp2p v3 best practice)
37
+ * When enabled, all messages are prefixed with a varint indicating message length
38
+ * This provides proper message boundaries and eliminates concatenation issues
39
+ * @default false (for backward compatibility)
40
+ */
41
+ useLengthPrefixing?: boolean;
35
42
  }
36
43
  //# sourceMappingURL=o-node.config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"o-node.config.d.ts","sourceRoot":"","sources":["../../../src/interfaces/o-node.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAE3D,MAAM,WAAW,WAAY,SAAQ,WAAW;IAC9C,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IAC5B,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IAE5B;;;OAGG;IACH,mBAAmB,CAAC,EAAE;QACpB,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,aAAa,CAAC,EAAE,OAAO,CAAC;QACxB,WAAW,CAAC,EAAE,OAAO,CAAC;QACtB,WAAW,CAAC,EAAE,OAAO,CAAC;KACvB,CAAC;IAEF;;;OAGG;IACH,kBAAkB,CAAC,EAAE;QACnB;;;WAGG;QACH,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB;;;WAGG;QACH,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,CAAC;IAEF,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC"}
1
+ {"version":3,"file":"o-node.config.d.ts","sourceRoot":"","sources":["../../../src/interfaces/o-node.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAE3D,MAAM,WAAW,WAAY,SAAQ,WAAW;IAC9C,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IAC5B,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IAE5B;;;OAGG;IACH,mBAAmB,CAAC,EAAE;QACpB,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,aAAa,CAAC,EAAE,OAAO,CAAC;QACxB,WAAW,CAAC,EAAE,OAAO,CAAC;QACtB,WAAW,CAAC,EAAE,OAAO,CAAC;KACvB,CAAC;IAEF;;;OAGG;IACH,kBAAkB,CAAC,EAAE;QACnB;;;WAGG;QACH,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB;;;WAGG;QACH,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,CAAC;IAEF,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAEjC;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B"}
@@ -1 +1 @@
1
- {"version":3,"file":"o-connection-heartbeat.manager.d.ts","sourceRoot":"","sources":["../../../src/managers/o-connection-heartbeat.manager.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EAOR,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAE3E,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,YAAY,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,kBAAkB,EAAE,MAAM,CAAC;IAC3B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,SAAS,GAAG,UAAU,GAAG,MAAM,CAAC;CACzC;AAED;;;;;;;;;;;;;;GAcG;AACH,qBAAa,2BAA4B,SAAQ,OAAO;IAMpD,OAAO,CAAC,IAAI;IACZ,OAAO,CAAC,MAAM;IANhB,OAAO,CAAC,iBAAiB,CAAC,CAAiB;IAC3C,OAAO,CAAC,SAAS,CAAuC;IACxD,OAAO,CAAC,SAAS,CAAS;gBAGhB,IAAI,EAAE,kBAAkB,EACxB,MAAM,EAAE,eAAe;IAK3B,KAAK;IAqBL,IAAI;YAQI,uBAAuB;IAgDrC;;;OAGG;IACH,OAAO,CAAC,qBAAqB;YA8Cf,WAAW;IAoEzB,OAAO,CAAC,oBAAoB;IAyD5B,OAAO,CAAC,2BAA2B;IAmBnC,OAAO,CAAC,4BAA4B;IAiBpC;;OAEG;IACH,eAAe,IAAI,gBAAgB,EAAE;IAIrC;;OAEG;IACH,mBAAmB,CAAC,OAAO,EAAE,YAAY,GAAG,gBAAgB,GAAG,SAAS;IAIxE;;OAEG;IACH,SAAS,IAAI,eAAe;CAG7B"}
1
+ {"version":3,"file":"o-connection-heartbeat.manager.d.ts","sourceRoot":"","sources":["../../../src/managers/o-connection-heartbeat.manager.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EAOR,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAE3E,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,YAAY,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,kBAAkB,EAAE,MAAM,CAAC;IAC3B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,SAAS,GAAG,UAAU,GAAG,MAAM,CAAC;CACzC;AAED;;;;;;;;;;;;;;GAcG;AACH,qBAAa,2BAA4B,SAAQ,OAAO;IAMpD,OAAO,CAAC,IAAI;IACZ,OAAO,CAAC,MAAM;IANhB,OAAO,CAAC,iBAAiB,CAAC,CAAiB;IAC3C,OAAO,CAAC,SAAS,CAAuC;IACxD,OAAO,CAAC,SAAS,CAAS;gBAGhB,IAAI,EAAE,kBAAkB,EACxB,MAAM,EAAE,eAAe;IAK3B,KAAK;IAqBL,IAAI;YAQI,uBAAuB;IAgDrC;;;OAGG;IACH,OAAO,CAAC,qBAAqB;YAgDf,WAAW;IAoEzB,OAAO,CAAC,oBAAoB;IAyD5B,OAAO,CAAC,2BAA2B;IAmBnC,OAAO,CAAC,4BAA4B;IAiBpC;;OAEG;IACH,eAAe,IAAI,gBAAgB,EAAE;IAIrC;;OAEG;IACH,mBAAmB,CAAC,OAAO,EAAE,YAAY,GAAG,gBAAgB,GAAG,SAAS;IAIxE;;OAEG;IACH,SAAS,IAAI,eAAe;CAG7B"}
@@ -1,4 +1,5 @@
1
1
  import { oObject, ChildLeftEvent, ParentDisconnectedEvent, LeaderDisconnectedEvent, ConnectionDegradedEvent, ConnectionRecoveredEvent, oAddress, } from '@olane/o-core';
2
+ import { oNodeAddress } from '../router/o-node.address.js';
2
3
  /**
3
4
  * Connection Health Monitor
4
5
  *
@@ -100,9 +101,11 @@ export class oConnectionHeartbeatManager extends oObject {
100
101
  return true;
101
102
  }
102
103
  // check via ping
103
- const pingResponse = this.node.use(address, {
104
- method: 'ping'
105
- }).catch((err) => {
104
+ const pingResponse = this.node
105
+ .use(new oNodeAddress(address?.value), {
106
+ method: 'ping',
107
+ })
108
+ .catch((err) => {
106
109
  if (err.message === 'Can not dial self') {
107
110
  return true;
108
111
  }
@@ -1 +1 @@
1
- {"version":3,"file":"o-reconnection.manager.d.ts","sourceRoot":"","sources":["../../../src/managers/o-reconnection.manager.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EASR,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAI3E,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,yBAAyB,EAAE,MAAM,CAAC;IAClC,yBAAyB,EAAE,MAAM,CAAC;CACnC;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,oBAAqB,SAAQ,OAAO;IAI7C,OAAO,CAAC,IAAI;IACZ,OAAO,CAAC,MAAM;IAJhB,OAAO,CAAC,YAAY,CAAS;gBAGnB,IAAI,EAAE,kBAAkB,EACxB,MAAM,EAAE,kBAAkB;IAMpC,OAAO,CAAC,mBAAmB;IAyBrB,mBAAmB,CAAC,KAAK,EAAE,GAAG;YAatB,wBAAwB;YAaxB,wBAAwB;YAexB,wBAAwB;IAehC,mBAAmB;YAgDX,2BAA2B;YAiB3B,iBAAiB;IAkB/B;;;OAGG;YACW,yBAAyB;IAiFvC;;OAEG;IACG,yBAAyB;IAwG/B,OAAO,CAAC,yBAAyB;IAajC,OAAO,CAAC,kBAAkB;IAI1B,OAAO,CAAC,qBAAqB;IAK7B,OAAO,CAAC,KAAK;CAGd"}
1
+ {"version":3,"file":"o-reconnection.manager.d.ts","sourceRoot":"","sources":["../../../src/managers/o-reconnection.manager.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EASR,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAI3E,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,yBAAyB,EAAE,MAAM,CAAC;IAClC,yBAAyB,EAAE,MAAM,CAAC;CACnC;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,oBAAqB,SAAQ,OAAO;IAI7C,OAAO,CAAC,IAAI;IACZ,OAAO,CAAC,MAAM;IAJhB,OAAO,CAAC,YAAY,CAAS;gBAGnB,IAAI,EAAE,kBAAkB,EACxB,MAAM,EAAE,kBAAkB;IAMpC,OAAO,CAAC,mBAAmB;IAyBrB,mBAAmB,CAAC,KAAK,EAAE,GAAG;YAoBtB,wBAAwB;YAaxB,wBAAwB;YAexB,wBAAwB;IAehC,mBAAmB;YAgDX,2BAA2B;YAiB3B,iBAAiB;IAkB/B;;;OAGG;YACW,yBAAyB;IAiFvC;;OAEG;IACG,yBAAyB;IA4G/B,OAAO,CAAC,yBAAyB;IAajC,OAAO,CAAC,kBAAkB;IAI1B,OAAO,CAAC,qBAAqB;IAK7B,OAAO,CAAC,KAAK;CAGd"}
@@ -32,6 +32,7 @@ export class oReconnectionManager extends oObject {
32
32
  }
33
33
  async handleNodeConnected(event) {
34
34
  const connectedEvent = event;
35
+ // if leader is back online re-register
35
36
  if (connectedEvent.nodeAddress.toString() === oAddress.leader().toString()) {
36
37
  // the leader is back online, let's re-register & tell sub-graphs to re-register
37
38
  await this.node.useSelf({
@@ -39,6 +40,10 @@ export class oReconnectionManager extends oObject {
39
40
  params: {},
40
41
  });
41
42
  }
43
+ if (connectedEvent.nodeAddress.toString() === this.node.config.parent?.value) {
44
+ // connect to the parent and register
45
+ await this.node.registerParent();
46
+ }
42
47
  }
43
48
  async handleConnectionDegraded(event) {
44
49
  const degradedEvent = event;
@@ -73,26 +78,32 @@ export class oReconnectionManager extends oObject {
73
78
  }
74
79
  this.reconnecting = true;
75
80
  let attempt = 0;
76
- while (attempt < this.config.maxAttempts) {
77
- attempt++;
78
- this.logger.info(`Reconnection attempt ${attempt}/${this.config.maxAttempts} to parent: ${this.node.config.parent}`);
79
- try {
80
- // Strategy 1: Try direct parent reconnection
81
- await this.tryDirectParentReconnection();
82
- // Success!
83
- this.reconnecting = false;
84
- this.logger.info(`Successfully reconnected to parent after ${attempt} attempts`);
85
- return;
86
- }
87
- catch (error) {
88
- this.logger.warn(`Reconnection attempt ${attempt} failed:`, error instanceof Error ? error.message : error);
89
- if (attempt < this.config.maxAttempts) {
90
- const delay = this.calculateBackoffDelay(attempt);
91
- this.logger.debug(`Waiting ${delay}ms before next attempt...`);
92
- await this.sleep(delay);
93
- }
94
- }
95
- }
81
+ // while (attempt < this.config.maxAttempts) {
82
+ // attempt++;
83
+ // this.logger.info(
84
+ // `Reconnection attempt ${attempt}/${this.config.maxAttempts} to parent: ${this.node.config.parent}`,
85
+ // );
86
+ // try {
87
+ // // Strategy 1: Try direct parent reconnection
88
+ // await this.tryDirectParentReconnection();
89
+ // // Success!
90
+ // this.reconnecting = false;
91
+ // this.logger.info(
92
+ // `Successfully reconnected to parent after ${attempt} attempts`,
93
+ // );
94
+ // return;
95
+ // } catch (error) {
96
+ // this.logger.warn(
97
+ // `Reconnection attempt ${attempt} failed:`,
98
+ // error instanceof Error ? error.message : error,
99
+ // );
100
+ // if (attempt < this.config.maxAttempts) {
101
+ // const delay = this.calculateBackoffDelay(attempt);
102
+ // this.logger.debug(`Waiting ${delay}ms before next attempt...`);
103
+ // await this.sleep(delay);
104
+ // }
105
+ // }
106
+ // }
96
107
  // All direct attempts failed - try leader fallback
97
108
  if (this.config.useLeaderFallback) {
98
109
  await this.tryLeaderFallback();
@@ -186,6 +197,7 @@ export class oReconnectionManager extends oObject {
186
197
  * Wait for non-leader parent to appear in registry and reconnect
187
198
  */
188
199
  async waitForParentAndReconnect() {
200
+ this.logger.debug('waitForParentAndReconnect...');
189
201
  const startTime = Date.now();
190
202
  let attempt = 0;
191
203
  let currentDelay = this.config.parentDiscoveryIntervalMs;
@@ -202,7 +214,8 @@ export class oReconnectionManager extends oObject {
202
214
  if (!this.node.config.parent) {
203
215
  throw new Error('Invalid parent definition');
204
216
  }
205
- const response = await this.node.use(this.node.config.parent, {
217
+ this.logger.debug('Calling parent identify');
218
+ const response = await this.node.use(new oNodeAddress(this.node.config.parent.value), {
206
219
  method: 'identify',
207
220
  params: {},
208
221
  });
@@ -21,6 +21,8 @@ export declare class oNode extends oToolBase {
21
21
  connectionHeartbeatManager?: oConnectionHeartbeatManager;
22
22
  protected reconnectionManager?: oReconnectionManager;
23
23
  protected didRegister: boolean;
24
+ protected hooksStartFinished: any[];
25
+ protected hooksInitFinished: any[];
24
26
  constructor(config: oNodeConfig);
25
27
  get leader(): oNodeAddress | null;
26
28
  get networkConfig(): Libp2pConfig;
@@ -47,8 +49,10 @@ export declare class oNode extends oToolBase {
47
49
  protected createNode(): Promise<Libp2p>;
48
50
  connect(config: oNodeConnectionConfig): Promise<oNodeConnection>;
49
51
  initConnectionManager(): Promise<void>;
50
- hookInitializeFinished(): Promise<void>;
51
- hookStartFinished(): Promise<void>;
52
+ protected hookInitializeFinished(): Promise<void>;
53
+ onInitFinished(cb: Function): void;
54
+ onStartFinished(cb: Function): void;
55
+ protected hookStartFinished(): Promise<void>;
52
56
  /**
53
57
  * Validates that if a leader address is defined, it has associated transports.
54
58
  * This is critical for non-leader nodes to be able to connect to their leader.
@@ -1 +1 @@
1
- {"version":3,"file":"o-node.d.ts","sourceRoot":"","sources":["../../src/o-node.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"o-node.d.ts","sourceRoot":"","sources":["../../src/o-node.ts"],"names":[],"mappings":"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"}
@@ -1,15 +1,56 @@
1
1
  import { oHierarchyManager, oHierarchyManagerConfig } from '@olane/o-core';
2
2
  import { oNodeAddress } from './router/o-node.address.js';
3
+ import { oNodeNotificationManager } from './o-node.notification-manager.js';
3
4
  export interface oNodeHierarchyManagerConfig extends oHierarchyManagerConfig {
4
5
  leaders: oNodeAddress[];
5
6
  children: oNodeAddress[];
6
7
  parents: oNodeAddress[];
8
+ notificationManager?: oNodeNotificationManager;
9
+ address: oNodeAddress;
7
10
  }
8
11
  export declare class oNodeHierarchyManager extends oHierarchyManager {
9
12
  leaders: oNodeAddress[];
10
13
  children: oNodeAddress[];
11
14
  parents: oNodeAddress[];
15
+ private notificationManager?;
16
+ private address;
12
17
  constructor(config: oNodeHierarchyManagerConfig);
18
+ /**
19
+ * Set up event listeners to react to notification manager's peer events
20
+ */
21
+ setupEventListeners(notificationManager: oNodeNotificationManager): void;
13
22
  get leader(): oNodeAddress | null;
23
+ /**
24
+ * Handle peer connected event from notification manager
25
+ * Resolves peer ID to address and emits hierarchy-aware events
26
+ */
27
+ private handlePeerConnected;
28
+ /**
29
+ * Handle peer disconnected event from notification manager
30
+ * Resolves peer ID to address and emits hierarchy-aware events
31
+ */
32
+ private handlePeerDisconnected;
33
+ /**
34
+ * Handle peer discovered event from notification manager
35
+ * Resolves peer ID to address and emits node discovered event
36
+ */
37
+ private handlePeerDiscovered;
38
+ /**
39
+ * Resolve a libp2p peer ID to an Olane address
40
+ * Checks children, parents, and leaders for matching transports
41
+ */
42
+ peerIdToAddress(peerId: string): oNodeAddress | null;
43
+ /**
44
+ * Check if an address is a direct child
45
+ */
46
+ isChild(address: oNodeAddress): boolean;
47
+ /**
48
+ * Check if an address is a parent
49
+ */
50
+ isParent(address: oNodeAddress): boolean;
51
+ /**
52
+ * Check if an address is a leader
53
+ */
54
+ isLeader(address: oNodeAddress): boolean;
14
55
  }
15
56
  //# sourceMappingURL=o-node.hierarchy-manager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"o-node.hierarchy-manager.d.ts","sourceRoot":"","sources":["../../src/o-node.hierarchy-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAC3E,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE1D,MAAM,WAAW,2BAA4B,SAAQ,uBAAuB;IAC1E,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,OAAO,EAAE,YAAY,EAAE,CAAC;CACzB;AAED,qBAAa,qBAAsB,SAAQ,iBAAiB;IACnD,OAAO,EAAE,YAAY,EAAE,CAAM;IAC7B,QAAQ,EAAE,YAAY,EAAE,CAAM;IAC9B,OAAO,EAAE,YAAY,EAAE,CAAM;gBAExB,MAAM,EAAE,2BAA2B;IAO/C,IAAI,MAAM,IAAI,YAAY,GAAG,IAAI,CAEhC;CACF"}
1
+ {"version":3,"file":"o-node.hierarchy-manager.d.ts","sourceRoot":"","sources":["../../src/o-node.hierarchy-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,uBAAuB,EAaxB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAE5E,MAAM,WAAW,2BAA4B,SAAQ,uBAAuB;IAC1E,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,mBAAmB,CAAC,EAAE,wBAAwB,CAAC;IAC/C,OAAO,EAAE,YAAY,CAAC;CACvB;AAED,qBAAa,qBAAsB,SAAQ,iBAAiB;IACnD,OAAO,EAAE,YAAY,EAAE,CAAM;IAC7B,QAAQ,EAAE,YAAY,EAAE,CAAM;IAC9B,OAAO,EAAE,YAAY,EAAE,CAAM;IACpC,OAAO,CAAC,mBAAmB,CAAC,CAA2B;IACvD,OAAO,CAAC,OAAO,CAAe;gBAElB,MAAM,EAAE,2BAA2B;IAW/C;;OAEG;IACH,mBAAmB,CAAC,mBAAmB,EAAE,wBAAwB,GAAG,IAAI;IAqBxE,IAAI,MAAM,IAAI,YAAY,GAAG,IAAI,CAEhC;IAED;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IA8C3B;;;OAGG;IACH,OAAO,CAAC,sBAAsB;IAuD9B;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAmB5B;;;OAGG;IACH,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI;IAqCpD;;OAEG;IACH,OAAO,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO;IAMvC;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO;IAMxC;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO;CAKzC"}