@olane/o-node 0.7.12-alpha.6 → 0.7.12-alpha.61

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 (74) hide show
  1. package/dist/src/connection/interfaces/o-node-connection-manager.config.d.ts +1 -0
  2. package/dist/src/connection/interfaces/o-node-connection-manager.config.d.ts.map +1 -1
  3. package/dist/src/connection/interfaces/o-node-connection.config.d.ts +1 -0
  4. package/dist/src/connection/interfaces/o-node-connection.config.d.ts.map +1 -1
  5. package/dist/src/connection/o-node-connection.d.ts +7 -2
  6. package/dist/src/connection/o-node-connection.d.ts.map +1 -1
  7. package/dist/src/connection/o-node-connection.js +55 -32
  8. package/dist/src/connection/o-node-connection.manager.d.ts +19 -5
  9. package/dist/src/connection/o-node-connection.manager.d.ts.map +1 -1
  10. package/dist/src/connection/o-node-connection.manager.js +81 -65
  11. package/dist/src/connection/o-stream.request.d.ts +11 -0
  12. package/dist/src/connection/o-stream.request.d.ts.map +1 -0
  13. package/dist/src/connection/o-stream.request.js +7 -0
  14. package/dist/src/connection/stream-handler.config.d.ts +46 -0
  15. package/dist/src/connection/stream-handler.config.d.ts.map +1 -0
  16. package/dist/src/connection/stream-handler.config.js +1 -0
  17. package/dist/src/connection/stream-handler.d.ts +97 -0
  18. package/dist/src/connection/stream-handler.d.ts.map +1 -0
  19. package/dist/src/connection/stream-handler.js +303 -0
  20. package/dist/src/index.d.ts +2 -1
  21. package/dist/src/index.d.ts.map +1 -1
  22. package/dist/src/index.js +2 -1
  23. package/dist/src/interfaces/i-heartbeatable-node.d.ts +49 -0
  24. package/dist/src/interfaces/i-heartbeatable-node.d.ts.map +1 -0
  25. package/dist/src/interfaces/i-heartbeatable-node.js +1 -0
  26. package/dist/src/interfaces/i-reconnectable-node.d.ts +5 -0
  27. package/dist/src/interfaces/i-reconnectable-node.d.ts.map +1 -1
  28. package/dist/src/interfaces/o-node.config.d.ts +16 -8
  29. package/dist/src/interfaces/o-node.config.d.ts.map +1 -1
  30. package/dist/src/managers/o-connection-heartbeat.manager.d.ts +5 -9
  31. package/dist/src/managers/o-connection-heartbeat.manager.d.ts.map +1 -1
  32. package/dist/src/managers/o-connection-heartbeat.manager.js +51 -47
  33. package/dist/src/managers/o-reconnection.manager.d.ts +12 -0
  34. package/dist/src/managers/o-reconnection.manager.d.ts.map +1 -1
  35. package/dist/src/managers/o-reconnection.manager.js +138 -22
  36. package/dist/src/o-node.d.ts +22 -11
  37. package/dist/src/o-node.d.ts.map +1 -1
  38. package/dist/src/o-node.js +202 -72
  39. package/dist/src/o-node.notification-manager.d.ts.map +1 -1
  40. package/dist/src/o-node.notification-manager.js +17 -12
  41. package/dist/src/o-node.tool.d.ts +1 -0
  42. package/dist/src/o-node.tool.d.ts.map +1 -1
  43. package/dist/src/o-node.tool.js +18 -34
  44. package/dist/src/router/o-node.router.d.ts +1 -0
  45. package/dist/src/router/o-node.router.d.ts.map +1 -1
  46. package/dist/src/router/o-node.router.js +62 -9
  47. package/dist/src/router/o-node.routing-policy.d.ts.map +1 -1
  48. package/dist/src/router/o-node.routing-policy.js +7 -2
  49. package/dist/src/router/resolvers/o-node.resolver.d.ts.map +1 -1
  50. package/dist/src/router/resolvers/o-node.resolver.js +5 -1
  51. package/dist/src/router/resolvers/o-node.search-resolver.d.ts.map +1 -1
  52. package/dist/src/router/resolvers/o-node.search-resolver.js +34 -9
  53. package/dist/src/utils/index.d.ts +3 -0
  54. package/dist/src/utils/index.d.ts.map +1 -0
  55. package/dist/src/utils/index.js +2 -0
  56. package/dist/src/utils/stream.utils.d.ts +6 -0
  57. package/dist/src/utils/stream.utils.d.ts.map +1 -0
  58. package/dist/src/utils/stream.utils.js +31 -0
  59. package/dist/test/helpers/test-node.tool.d.ts +15 -0
  60. package/dist/test/helpers/test-node.tool.d.ts.map +1 -0
  61. package/dist/test/helpers/test-node.tool.js +27 -0
  62. package/package.json +6 -6
  63. package/dist/src/router/resolvers/o-node.child-resolver.d.ts +0 -11
  64. package/dist/src/router/resolvers/o-node.child-resolver.d.ts.map +0 -1
  65. package/dist/src/router/resolvers/o-node.child-resolver.js +0 -58
  66. package/dist/src/utils/leader-request-wrapper.d.ts +0 -45
  67. package/dist/src/utils/leader-request-wrapper.d.ts.map +0 -1
  68. package/dist/src/utils/leader-request-wrapper.js +0 -89
  69. package/dist/test/o-node.spec.d.ts +0 -2
  70. package/dist/test/o-node.spec.d.ts.map +0 -1
  71. package/dist/test/o-node.spec.js +0 -20
  72. package/dist/test/search-resolver.spec.d.ts +0 -2
  73. package/dist/test/search-resolver.spec.d.ts.map +0 -1
  74. package/dist/test/search-resolver.spec.js +0 -693
@@ -0,0 +1,303 @@
1
+ import { oRequest, CoreUtils, oError, oErrorCodes, Logger, ResponseBuilder, } from '@olane/o-core';
2
+ /**
3
+ * StreamHandler centralizes all stream-related functionality including:
4
+ * - Message type detection (request vs response)
5
+ * - Stream lifecycle management (create, reuse, close)
6
+ * - Backpressure handling
7
+ * - Request/response handling
8
+ * - Stream routing for middleware nodes
9
+ */
10
+ export class StreamHandler {
11
+ constructor(logger) {
12
+ this.logger = logger ?? new Logger('StreamHandler');
13
+ }
14
+ /**
15
+ * Detects if a decoded message is a request
16
+ * Requests have a 'method' field and no 'result' field
17
+ */
18
+ isRequest(message) {
19
+ return typeof message?.method === 'string' && message.result === undefined;
20
+ }
21
+ /**
22
+ * Detects if a decoded message is a response
23
+ * Responses have a 'result' field and no 'method' field
24
+ */
25
+ isResponse(message) {
26
+ return message?.result !== undefined && message.method === undefined;
27
+ }
28
+ /**
29
+ * Decodes a stream message event into a JSON object
30
+ */
31
+ async decodeMessage(event) {
32
+ return CoreUtils.processStream(event);
33
+ }
34
+ /**
35
+ * Gets an existing open stream or creates a new one based on reuse policy
36
+ *
37
+ * @param connection - The libp2p connection
38
+ * @param protocol - The protocol to use for the stream
39
+ * @param config - Stream handler configuration
40
+ */
41
+ async getOrCreateStream(connection, protocol, config = {}) {
42
+ if (connection.status !== 'open') {
43
+ throw new oError(oErrorCodes.INVALID_STATE, 'Connection not open');
44
+ }
45
+ const reusePolicy = config.reusePolicy ?? 'none';
46
+ this.logger.debug('Reuse policy:', reusePolicy);
47
+ // Check for existing stream if reuse is enabled
48
+ if (reusePolicy === 'reuse') {
49
+ this.logger.debug('Reusing existing stream if we can find one. Stream insights:', JSON.stringify({
50
+ streamCount: connection.streams.length,
51
+ protocol: protocol,
52
+ }));
53
+ connection.streams.forEach((stream) => {
54
+ this.logger.debug('Stream re-use option:', stream.protocol, stream.status, stream.direction, stream.remoteWriteStatus, stream.writeStatus, stream.remoteReadStatus, stream.readStatus);
55
+ });
56
+ const existingStream = connection.streams.find((stream) => stream.status === 'open' &&
57
+ stream.protocol === protocol &&
58
+ stream.writeStatus === 'writable' &&
59
+ stream.remoteReadStatus === 'readable');
60
+ if (existingStream) {
61
+ this.logger.debug('Reusing existing stream', existingStream.id, existingStream.direction);
62
+ return existingStream;
63
+ }
64
+ }
65
+ // Create new stream
66
+ this.logger.debug('Creating new stream');
67
+ const stream = await connection.newStream(protocol, {
68
+ signal: config.signal,
69
+ maxOutboundStreams: config.maxOutboundStreams ?? 1000,
70
+ runOnLimitedConnection: config.runOnLimitedConnection ?? false,
71
+ });
72
+ return stream;
73
+ }
74
+ /**
75
+ * Sends data through a stream with backpressure handling
76
+ *
77
+ * @param stream - The stream to send data through
78
+ * @param data - The data to send
79
+ * @param config - Configuration for timeout and other options
80
+ */
81
+ async send(stream, data, config = {}) {
82
+ // Send the data with backpressure handling (libp2p v3 best practice)
83
+ const sent = stream.send(data);
84
+ // If send() returns false, buffer is full - wait for drain
85
+ if (!sent) {
86
+ this.logger.debug('Stream buffer full, waiting for drain...');
87
+ const drainTimeout = config.drainTimeoutMs ?? 30000;
88
+ await stream.onDrain({
89
+ signal: AbortSignal.timeout(drainTimeout),
90
+ });
91
+ this.logger.debug('Stream drained successfully');
92
+ }
93
+ }
94
+ /**
95
+ * Closes a stream safely with error handling
96
+ *
97
+ * @param stream - The stream to close
98
+ * @param config - Configuration including reuse policy
99
+ */
100
+ async close(stream, config = {}) {
101
+ // Don't close if reuse policy is enabled
102
+ if (config.reusePolicy === 'reuse') {
103
+ this.logger.debug('Stream reuse enabled, not closing stream');
104
+ return;
105
+ }
106
+ if (stream.status === 'open') {
107
+ try {
108
+ // force the close for now until we can implement a proper close
109
+ await stream.abort(new Error('Stream closed'));
110
+ this.logger.debug('Stream closed successfully');
111
+ }
112
+ catch (error) {
113
+ this.logger.debug('Error closing stream:', error.message);
114
+ }
115
+ }
116
+ }
117
+ /**
118
+ * Handles an incoming stream on the server side
119
+ * Attaches message listener immediately (libp2p v3 best practice)
120
+ * Routes requests or executes tools based on the message
121
+ *
122
+ * @param stream - The incoming stream
123
+ * @param connection - The connection the stream belongs to
124
+ * @param toolExecutor - Function to execute tools for requests
125
+ */
126
+ async handleIncomingStream(stream, connection, toolExecutor) {
127
+ // CRITICAL: Attach message listener immediately to prevent buffer overflow (libp2p v3)
128
+ const messageHandler = async (event) => {
129
+ try {
130
+ // avoid processing non-olane messages
131
+ if (!event.data) {
132
+ return;
133
+ }
134
+ const messages = await this.decodeMessage(event);
135
+ await Promise.all(messages.map(async (message) => {
136
+ if (this.isRequest(message)) {
137
+ await this.handleRequestMessage(message, stream, toolExecutor);
138
+ }
139
+ else if (this.isResponse(message)) {
140
+ this.logger.warn('Received response message on server-side stream, ignoring', message);
141
+ }
142
+ else {
143
+ this.logger.warn('Received unknown message type', message);
144
+ }
145
+ }));
146
+ }
147
+ catch (error) {
148
+ this.logger.error('Error handling stream message:', error);
149
+ // Error already logged, stream will be closed by remote peer or timeout
150
+ }
151
+ };
152
+ const closeHandler = () => {
153
+ this.logger.debug('Stream closed by remote peer');
154
+ stream.removeEventListener('message', messageHandler);
155
+ stream.removeEventListener('close', closeHandler);
156
+ };
157
+ stream.addEventListener('message', messageHandler);
158
+ stream.addEventListener('close', closeHandler);
159
+ }
160
+ /**
161
+ * Handles a request message by executing the tool and sending response
162
+ *
163
+ * @param message - The decoded request message
164
+ * @param stream - The stream to send the response on
165
+ * @param toolExecutor - Function to execute the tool
166
+ */
167
+ async handleRequestMessage(message, stream, toolExecutor) {
168
+ const request = new oRequest(message);
169
+ const responseBuilder = ResponseBuilder.create();
170
+ try {
171
+ this.logger.debug(`Processing request on stream: method=${request.method}, id=${request.id}`);
172
+ const result = await toolExecutor(request, stream);
173
+ const response = await responseBuilder.build(request, result, null);
174
+ await CoreUtils.sendResponse(response, stream);
175
+ this.logger.debug(`Successfully processed request: method=${request.method}, id=${request.id}`);
176
+ }
177
+ catch (error) {
178
+ this.logger.error(`Error processing request: method=${request.method}, id=${request.id}`, error);
179
+ const errorResponse = await responseBuilder.buildError(request, error);
180
+ await CoreUtils.sendResponse(errorResponse, stream);
181
+ }
182
+ }
183
+ /**
184
+ * Handles an outgoing stream on the client side
185
+ * Listens for response messages and emits them via the event emitter
186
+ * If requestHandler is provided, also processes incoming router requests
187
+ *
188
+ * @param stream - The outgoing stream
189
+ * @param emitter - Event emitter for chunk events
190
+ * @param config - Configuration including abort signal
191
+ * @param requestHandler - Optional handler for processing router requests received on this stream
192
+ * @returns Promise that resolves with the final response
193
+ */
194
+ async handleOutgoingStream(stream, emitter, config = {}, requestHandler) {
195
+ return new Promise((resolve, reject) => {
196
+ let lastResponse;
197
+ const messageHandler = async (event) => {
198
+ // avoid processing non-olane messages
199
+ if (!event.data) {
200
+ return;
201
+ }
202
+ try {
203
+ const messages = await this.decodeMessage(event);
204
+ await Promise.all(messages.map(async (message) => {
205
+ if (this.isResponse(message)) {
206
+ // Emit chunk for streaming responses
207
+ emitter.emit('chunk', message);
208
+ // Check if this is the last chunk
209
+ if (message.result._last || !message.result._isStreaming) {
210
+ lastResponse = message;
211
+ cleanup();
212
+ resolve(message);
213
+ }
214
+ }
215
+ else if (this.isRequest(message)) {
216
+ // Process incoming router requests if handler is provided
217
+ if (requestHandler) {
218
+ this.logger.debug('Received router request on client-side stream, processing...', message);
219
+ await this.handleRequestMessage(message, stream, requestHandler);
220
+ }
221
+ else {
222
+ this.logger.warn('Received request message on client-side stream, ignoring (no handler)', message);
223
+ }
224
+ }
225
+ else {
226
+ this.logger.warn('Received unknown message type', message);
227
+ }
228
+ }));
229
+ }
230
+ catch (error) {
231
+ this.logger.error('Error handling response message:', error);
232
+ cleanup();
233
+ reject(error);
234
+ }
235
+ };
236
+ const closeHandler = () => {
237
+ this.logger.debug('Stream closed by remote peer');
238
+ cleanup();
239
+ if (lastResponse) {
240
+ resolve(lastResponse);
241
+ }
242
+ else {
243
+ reject(new oError(oErrorCodes.TIMEOUT, 'Stream closed before response received'));
244
+ }
245
+ };
246
+ const abortHandler = () => {
247
+ this.logger.debug('Request aborted');
248
+ cleanup();
249
+ try {
250
+ stream.abort(new Error('Request aborted'));
251
+ }
252
+ catch (error) {
253
+ this.logger.debug('Error aborting stream:', error.message);
254
+ }
255
+ reject(new oError(oErrorCodes.TIMEOUT, 'Request aborted'));
256
+ };
257
+ const cleanup = () => {
258
+ stream.removeEventListener('message', messageHandler);
259
+ stream.removeEventListener('close', closeHandler);
260
+ if (config.signal) {
261
+ config.signal.removeEventListener('abort', abortHandler);
262
+ }
263
+ };
264
+ stream.addEventListener('message', messageHandler);
265
+ stream.addEventListener('close', closeHandler);
266
+ if (config.signal) {
267
+ config.signal.addEventListener('abort', abortHandler);
268
+ }
269
+ });
270
+ }
271
+ /**
272
+ * Forwards a request to the next hop and relays response chunks back
273
+ * This implements the middleware/proxy pattern for intermediate nodes
274
+ *
275
+ * @param request - The router request to forward
276
+ * @param incomingStream - The stream to send responses back on
277
+ * @param dialFn - Function to dial the next hop connection
278
+ */
279
+ async forwardRequest(request, incomingStream, dialFn) {
280
+ try {
281
+ // Connect to next hop
282
+ const nextHopConnection = await dialFn(request.params.address);
283
+ // Set up chunk relay - forward responses from next hop back to incoming stream
284
+ nextHopConnection.onChunk(async (response) => {
285
+ try {
286
+ await CoreUtils.sendStreamResponse(response, incomingStream);
287
+ }
288
+ catch (error) {
289
+ this.logger.error('Error forwarding chunk:', error);
290
+ }
291
+ });
292
+ // Transmit the request to next hop
293
+ await nextHopConnection.transmit(request);
294
+ }
295
+ catch (error) {
296
+ this.logger.error('Error forwarding request:', error);
297
+ // Send error response back on incoming stream using ResponseBuilder
298
+ const responseBuilder = ResponseBuilder.create();
299
+ const errorResponse = await responseBuilder.buildError(request, error);
300
+ await CoreUtils.sendResponse(errorResponse, incomingStream);
301
+ }
302
+ }
303
+ }
@@ -1,5 +1,5 @@
1
1
  export * from './o-node.js';
2
- export * from './utils/network.utils.js';
2
+ export * from './utils/index.js';
3
3
  export * from './o-node.hierarchy-manager.js';
4
4
  export * from './interfaces/o-node.config.js';
5
5
  export * from './connection/index.js';
@@ -7,4 +7,5 @@ export * from './o-node.tool.js';
7
7
  export * from './nodes/index.js';
8
8
  export * from './interfaces/o-node.tool-config.js';
9
9
  export * from './router/index.js';
10
+ export * from './connection/o-stream.request.js';
10
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,0BAA0B,CAAC;AACzC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,oCAAoC,CAAC;AACnD,cAAc,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,oCAAoC,CAAC;AACnD,cAAc,mBAAmB,CAAC;AAClC,cAAc,kCAAkC,CAAC"}
package/dist/src/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  export * from './o-node.js';
2
- export * from './utils/network.utils.js';
2
+ export * from './utils/index.js';
3
3
  export * from './o-node.hierarchy-manager.js';
4
4
  export * from './interfaces/o-node.config.js';
5
5
  export * from './connection/index.js';
@@ -7,3 +7,4 @@ export * from './o-node.tool.js';
7
7
  export * from './nodes/index.js';
8
8
  export * from './interfaces/o-node.tool-config.js';
9
9
  export * from './router/index.js';
10
+ export * from './connection/o-stream.request.js';
@@ -0,0 +1,49 @@
1
+ import { oNotificationManager } from '@olane/o-core';
2
+ import { Libp2p } from '@olane/o-config';
3
+ import { oNodeAddress } from '../router/o-node.address.js';
4
+ /**
5
+ * Interface for nodes that support connection heartbeat monitoring.
6
+ * This interface defines the contract that oConnectionHeartbeatManager needs
7
+ * to access live hierarchy state without holding stale references.
8
+ */
9
+ export interface IHeartbeatableNode {
10
+ /**
11
+ * The node's current address
12
+ */
13
+ address: oNodeAddress;
14
+ /**
15
+ * The notification manager for emitting heartbeat events
16
+ */
17
+ notificationManager: oNotificationManager;
18
+ /**
19
+ * The underlying libp2p node for ping operations
20
+ */
21
+ p2pNode: Libp2p;
22
+ /**
23
+ * The current parent address (with live transport updates)
24
+ * @returns Parent address or null if no parent
25
+ */
26
+ parent: oNodeAddress | null;
27
+ /**
28
+ * Get the current list of leader addresses
29
+ * @returns Array of leader addresses (empty if this node is the leader)
30
+ */
31
+ getLeaders(): oNodeAddress[];
32
+ /**
33
+ * Get the current list of parent addresses
34
+ * @returns Array of parent addresses
35
+ */
36
+ getParents(): oNodeAddress[];
37
+ /**
38
+ * Get the current list of child addresses
39
+ * @returns Array of child addresses
40
+ */
41
+ getChildren(): oNodeAddress[];
42
+ /**
43
+ * Remove a child from the hierarchy
44
+ * @param childAddress The address of the child to remove
45
+ */
46
+ removeChild(childAddress: oNodeAddress): void;
47
+ use(param1: any, param2: any): Promise<any>;
48
+ }
49
+ //# sourceMappingURL=i-heartbeatable-node.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"i-heartbeatable-node.d.ts","sourceRoot":"","sources":["../../../src/interfaces/i-heartbeatable-node.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAE3D;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,OAAO,EAAE,YAAY,CAAC;IAEtB;;OAEG;IACH,mBAAmB,EAAE,oBAAoB,CAAC;IAE1C;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IAE5B;;;OAGG;IACH,UAAU,IAAI,YAAY,EAAE,CAAC;IAE7B;;;OAGG;IACH,UAAU,IAAI,YAAY,EAAE,CAAC;IAE7B;;;OAGG;IACH,WAAW,IAAI,YAAY,EAAE,CAAC;IAE9B;;;OAGG;IACH,WAAW,CAAC,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAE9C,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;CAC7C"}
@@ -0,0 +1 @@
1
+ export {};
@@ -27,6 +27,11 @@ export interface IReconnectableNode {
27
27
  * Register with the parent node
28
28
  */
29
29
  registerParent(): Promise<void>;
30
+ /**
31
+ * Register with the leader's global registry
32
+ */
33
+ register(): Promise<void>;
34
+ useSelf(request?: any): Promise<any>;
30
35
  /**
31
36
  * Execute a method on another node
32
37
  */
@@ -1 +1 @@
1
- {"version":3,"file":"i-reconnectable-node.d.ts","sourceRoot":"","sources":["../../../src/interfaces/i-reconnectable-node.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,MAAM,EAAE,WAAW,CAAC;IAEpB;;OAEG;IACH,OAAO,EAAE,YAAY,CAAC;IAEtB;;OAEG;IACH,KAAK,EAAE,SAAS,CAAC;IAEjB;;OAEG;IACH,mBAAmB,EAAE,oBAAoB,CAAC;IAE1C;;OAEG;IACH,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEhC;;OAEG;IACH,GAAG,CACD,OAAO,EAAE,QAAQ,EACjB,IAAI,CAAC,EAAE;QACL,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,MAAM,CAAC,EAAE;YAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;SAAE,CAAC;QAChC,EAAE,CAAC,EAAE,MAAM,CAAC;KACb,GACA,OAAO,CAAC,GAAG,CAAC,CAAC;CACjB"}
1
+ {"version":3,"file":"i-reconnectable-node.d.ts","sourceRoot":"","sources":["../../../src/interfaces/i-reconnectable-node.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,SAAS,EACT,oBAAoB,EAErB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,MAAM,EAAE,WAAW,CAAC;IAEpB;;OAEG;IACH,OAAO,EAAE,YAAY,CAAC;IAEtB;;OAEG;IACH,KAAK,EAAE,SAAS,CAAC;IAEjB;;OAEG;IACH,mBAAmB,EAAE,oBAAoB,CAAC;IAE1C;;OAEG;IACH,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEhC;;OAEG;IACH,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAE1B,OAAO,CAAC,OAAO,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAErC;;OAEG;IACH,GAAG,CACD,OAAO,EAAE,QAAQ,EACjB,IAAI,CAAC,EAAE;QACL,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,MAAM,CAAC,EAAE;YAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;SAAE,CAAC;QAChC,EAAE,CAAC,EAAE,MAAM,CAAC;KACb,GACA,OAAO,CAAC,GAAG,CAAC,CAAC;CACjB"}
@@ -26,17 +26,25 @@ export interface oNodeConfig extends oCoreConfig {
26
26
  baseDelayMs?: number;
27
27
  maxDelayMs?: number;
28
28
  useLeaderFallback?: boolean;
29
+ parentDiscoveryIntervalMs?: number;
30
+ parentDiscoveryMaxDelayMs?: number;
29
31
  };
30
32
  /**
31
- * Leader request retry configuration
32
- * Handles temporary leader unavailability (healing, maintenance)
33
+ * Connection timeout configuration
34
+ * Controls timeouts for stream read and drain operations in connections
33
35
  */
34
- leaderRetry?: {
35
- enabled?: boolean;
36
- maxAttempts?: number;
37
- baseDelayMs?: number;
38
- maxDelayMs?: number;
39
- timeoutMs?: number;
36
+ connectionTimeouts?: {
37
+ /**
38
+ * Timeout in milliseconds for reading response data from a stream
39
+ * Default: 120000 (2 minutes)
40
+ */
41
+ readTimeoutMs?: number;
42
+ /**
43
+ * Timeout in milliseconds for waiting for stream buffer to drain when backpressure occurs
44
+ * Default: 30000 (30 seconds)
45
+ */
46
+ drainTimeoutMs?: number;
40
47
  };
48
+ runOnLimitedConnection?: boolean;
41
49
  }
42
50
  //# 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,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,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,YAAY,CAAC,EAAE;QACb,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,iBAAiB,CAAC,EAAE,OAAO,CAAC;KAC7B,CAAC;IAEF;;;OAGG;IACH,WAAW,CAAC,EAAE;QACZ,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;CACH"}
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,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,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,YAAY,CAAC,EAAE;QACb,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,iBAAiB,CAAC,EAAE,OAAO,CAAC;QAC5B,yBAAyB,CAAC,EAAE,MAAM,CAAC;QACnC,yBAAyB,CAAC,EAAE,MAAM,CAAC;KACpC,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,8 +1,6 @@
1
- import { Libp2p } from '@olane/o-config';
2
1
  import { oObject } from '@olane/o-core';
3
2
  import { oNodeAddress } from '../router/o-node.address.js';
4
- import { oNodeHierarchyManager } from '../o-node.hierarchy-manager.js';
5
- import { oNotificationManager } from '@olane/o-core';
3
+ import { IHeartbeatableNode } from '../interfaces/i-heartbeatable-node.js';
6
4
  export interface HeartbeatConfig {
7
5
  enabled: boolean;
8
6
  intervalMs: number;
@@ -35,22 +33,20 @@ export interface ConnectionHealth {
35
33
  * - Emits ParentDisconnectedEvent when parent dies (triggers reconnection)
36
34
  */
37
35
  export declare class oConnectionHeartbeatManager extends oObject {
38
- private p2pNode;
39
- private hierarchyManager;
40
- private notificationManager;
41
- private address;
36
+ private node;
42
37
  private config;
43
38
  private heartbeatInterval?;
44
39
  private healthMap;
45
- constructor(p2pNode: Libp2p, hierarchyManager: oNodeHierarchyManager, notificationManager: oNotificationManager, address: oNodeAddress, config: HeartbeatConfig);
40
+ private isRunning;
41
+ constructor(node: IHeartbeatableNode, config: HeartbeatConfig);
46
42
  start(): Promise<void>;
47
43
  stop(): Promise<void>;
48
44
  private performHeartbeatCycle;
45
+ private doPing;
49
46
  private pingTarget;
50
47
  private handleConnectionDead;
51
48
  private emitConnectionDegradedEvent;
52
49
  private emitConnectionRecoveredEvent;
53
- private extractPeerIdFromAddress;
54
50
  /**
55
51
  * Get current health status of all connections
56
52
  */
@@ -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,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EACL,OAAO,EAMR,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAErD,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,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;;;;;;;;;;;;;GAaG;AACH,qBAAa,2BAA4B,SAAQ,OAAO;IAKpD,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,gBAAgB;IACxB,OAAO,CAAC,mBAAmB;IAC3B,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,MAAM;IARhB,OAAO,CAAC,iBAAiB,CAAC,CAAiB;IAC3C,OAAO,CAAC,SAAS,CAAuC;gBAG9C,OAAO,EAAE,MAAM,EACf,gBAAgB,EAAE,qBAAqB,EACvC,mBAAmB,EAAE,oBAAoB,EACzC,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,eAAe;IAK3B,KAAK;IAqBL,IAAI;YAQI,qBAAqB;YAuCrB,UAAU;IAyFxB,OAAO,CAAC,oBAAoB;IAyD5B,OAAO,CAAC,2BAA2B;IAmBnC,OAAO,CAAC,4BAA4B;IAiBpC,OAAO,CAAC,wBAAwB;IAahC;;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,SAAS,EAAE,MAAM,CAAC;IAClB,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;;;;;;;;;;;;;GAaG;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,qBAAqB;IAgDnC,OAAO,CAAC,MAAM;YAcA,UAAU;IAuFxB,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"}