@olane/o-node 0.7.31 → 0.7.34

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.
@@ -4,5 +4,6 @@ export interface oNodeConnectionManagerConfig extends oConnectionManagerConfig {
4
4
  p2pNode: Libp2p;
5
5
  runOnLimitedConnection?: boolean;
6
6
  originAddress?: string;
7
+ useLengthPrefixing?: boolean;
7
8
  }
8
9
  //# sourceMappingURL=o-node-connection-manager.config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"o-node-connection-manager.config.d.ts","sourceRoot":"","sources":["../../../../src/connection/interfaces/o-node-connection-manager.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEzC,MAAM,WAAW,4BAA6B,SAAQ,wBAAwB;IAC5E,OAAO,EAAE,MAAM,CAAC;IAChB,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB"}
1
+ {"version":3,"file":"o-node-connection-manager.config.d.ts","sourceRoot":"","sources":["../../../../src/connection/interfaces/o-node-connection-manager.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEzC,MAAM,WAAW,4BAA6B,SAAQ,wBAAwB;IAC5E,OAAO,EAAE,MAAM,CAAC;IAChB,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B"}
@@ -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"}
@@ -25,9 +25,10 @@ export class oNodeConnection extends oConnection {
25
25
  maxOutboundStreams: process.env.MAX_OUTBOUND_STREAMS
26
26
  ? parseInt(process.env.MAX_OUTBOUND_STREAMS)
27
27
  : 1000,
28
- runOnLimitedConnection: this.config.runOnLimitedConnection ?? false,
28
+ runOnLimitedConnection: this.config.runOnLimitedConnection ?? true,
29
29
  reusePolicy: 'none', // Default policy, can be overridden in subclasses
30
30
  drainTimeoutMs: this.config.drainTimeoutMs,
31
+ useLengthPrefixing: this.config.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
@@ -1 +1 @@
1
- {"version":3,"file":"o-node-connection.manager.d.ts","sourceRoot":"","sources":["../../../src/connection/o-node-connection.manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAChF,OAAO,EAAE,MAAM,EAAE,UAAU,EAAU,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,4BAA4B,EAAE,MAAM,kDAAkD,CAAC;AAEhG,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,qBAAa,sBAAuB,SAAQ,kBAAkB;IAQhD,QAAQ,CAAC,MAAM,EAAE,4BAA4B;IAPzD,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,oBAAoB,CAAC,CAAS;IACtC,OAAO,CAAC,qBAAqB,CAAC,CAAS;IACvC,OAAO,CAAC,yBAAyB,CAAsC;IACvE,OAAO,CAAC,0BAA0B,CACtB;gBAES,MAAM,EAAE,4BAA4B;IAWzD;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAsBhC;;;;;;OAMG;IACH,OAAO,CAAC,0BAA0B;IAiBlC;;;;OAIG;IACH,OAAO,CAAC,oBAAoB;IAatB,qBAAqB,CACzB,cAAc,EAAE,QAAQ,EACxB,OAAO,EAAE,QAAQ,GAChB,OAAO,CAAC,UAAU,CAAC;YA+DR,WAAW;IAwBzB;;;;OAIG;IACG,OAAO,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,eAAe,CAAC;IA8BlE;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO;IAwCpC;;;;OAIG;IACH,yBAAyB,CAAC,OAAO,EAAE,QAAQ,GAAG,UAAU,GAAG,IAAI;IA+C/D;;;OAGG;IACH,aAAa,IAAI;QACf,iBAAiB,EAAE,MAAM,CAAC;QAC1B,YAAY,EAAE,MAAM,CAAC;QACrB,iBAAiB,EAAE,KAAK,CAAC;YAAE,MAAM,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;KAC9D;IAaD;;;OAGG;IACH,uBAAuB,IAAI,MAAM;CAgBlC"}
1
+ {"version":3,"file":"o-node-connection.manager.d.ts","sourceRoot":"","sources":["../../../src/connection/o-node-connection.manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAChF,OAAO,EAAE,MAAM,EAAE,UAAU,EAAU,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,4BAA4B,EAAE,MAAM,kDAAkD,CAAC;AAEhG,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,qBAAa,sBAAuB,SAAQ,kBAAkB;IAQhD,QAAQ,CAAC,MAAM,EAAE,4BAA4B;IAPzD,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,oBAAoB,CAAC,CAAS;IACtC,OAAO,CAAC,qBAAqB,CAAC,CAAS;IACvC,OAAO,CAAC,yBAAyB,CAAsC;IACvE,OAAO,CAAC,0BAA0B,CACtB;gBAES,MAAM,EAAE,4BAA4B;IAWzD;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAsBhC;;;;;;OAMG;IACH,OAAO,CAAC,0BAA0B;IAiBlC;;;;OAIG;IACH,OAAO,CAAC,oBAAoB;IAatB,qBAAqB,CACzB,cAAc,EAAE,QAAQ,EACxB,OAAO,EAAE,QAAQ,GAChB,OAAO,CAAC,UAAU,CAAC;YA+DR,WAAW;IAwBzB;;;;OAIG;IACG,OAAO,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,eAAe,CAAC;IA+BlE;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO;IAwCpC;;;;OAIG;IACH,yBAAyB,CAAC,OAAO,EAAE,QAAQ,GAAG,UAAU,GAAG,IAAI;IA+C/D;;;OAGG;IACH,aAAa,IAAI;QACf,iBAAiB,EAAE,MAAM,CAAC;QAC1B,YAAY,EAAE,MAAM,CAAC;QACrB,iBAAiB,EAAE,KAAK,CAAC;YAAE,MAAM,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;KAC9D;IAaD;;;OAGG;IACH,uBAAuB,IAAI,MAAM;CAgBlC"}
@@ -148,6 +148,7 @@ export class oNodeConnectionManager extends oConnectionManager {
148
148
  isStream: config.isStream ?? false,
149
149
  abortSignal: config.abortSignal,
150
150
  runOnLimitedConnection: this.config.runOnLimitedConnection ?? false,
151
+ useLengthPrefixing: this.config.useLengthPrefixing,
151
152
  requestHandler: config.requestHandler ?? undefined,
152
153
  });
153
154
  return connection;
@@ -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-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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"}
@@ -353,6 +353,7 @@ export class oNode extends oToolBase {
353
353
  defaultDrainTimeoutMs: this.config.connectionTimeouts?.drainTimeoutMs,
354
354
  runOnLimitedConnection: this.config.runOnLimitedConnection ?? false,
355
355
  originAddress: this.address?.value,
356
+ useLengthPrefixing: this.config.useLengthPrefixing ?? true,
356
357
  });
357
358
  }
358
359
  async hookInitializeFinished() {
@@ -1 +1 @@
1
- {"version":3,"file":"o-node.notification-manager.d.ts","sourceRoot":"","sources":["../../src/o-node.notification-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EACL,oBAAoB,EAIrB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE1D;;;GAGG;AACH,qBAAa,wBAAyB,SAAQ,oBAAoB;IAE9D,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,OAAO;gBADP,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,YAAY;IAK/B;;OAEG;IACH,SAAS,CAAC,cAAc,IAAI,IAAI;IAgChC;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAezB;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAa5B;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAe3B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAI5B;;;OAGG;IACH,OAAO,CAAC,qBAAqB;CAoC9B"}
1
+ {"version":3,"file":"o-node.notification-manager.d.ts","sourceRoot":"","sources":["../../src/o-node.notification-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EACL,oBAAoB,EAIrB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE1D;;;GAGG;AACH,qBAAa,wBAAyB,SAAQ,oBAAoB;IAE9D,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,OAAO;gBADP,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,YAAY;IAK/B;;OAEG;IACH,SAAS,CAAC,cAAc,IAAI,IAAI;IAgChC;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAezB;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAa5B;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAe3B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAI5B;;;OAGG;IACH,OAAO,CAAC,qBAAqB;CAiC9B"}
@@ -97,8 +97,6 @@ export class oNodeNotificationManager extends oNotificationManager {
97
97
  this.logger.debug(`Connection closed to ${remotePeerId}, but ${remainingConnections.length} connection(s) remain open`);
98
98
  return;
99
99
  }
100
- // All connections to this peer are now closed
101
- this.logger.debug(`Last connection closed to ${remotePeerId}`);
102
100
  // Emit low-level peer disconnected event
103
101
  this.emit(new PeerDisconnectedEvent({
104
102
  source: this.address,
@@ -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;;AAKrD;;;;GAIG;AACH,qBAAa,SAAU,SAAQ,cAAkB;IAC/C,OAAO,CAAC,aAAa,CAAiB;IAEhC,cAAc,CAAC,OAAO,EAAE,QAAQ;IAehC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAY3B,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAwBnE,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;;AAKrD;;;;GAIG;AACH,qBAAa,SAAU,SAAQ,cAAkB;IAC/C,OAAO,CAAC,aAAa,CAAiB;IAEhC,cAAc,CAAC,OAAO,EAAE,QAAQ;IAehC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAY3B,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IA2BnE,cAAc,IAAI,OAAO,CAAC,GAAG,CAAC;IAQ9B,oBAAoB,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC;CAiC5D"}
@@ -46,6 +46,8 @@ export class oNodeTool extends oTool(oServerNode) {
46
46
  this.logger.error('Error executing tool: ', request.toString(), error, typeof error);
47
47
  throw error; // StreamHandler will handle error response building
48
48
  }
49
+ }, {
50
+ useLengthPrefixing: this.config.useLengthPrefixing ?? true,
49
51
  });
50
52
  }
51
53
  async _tool_identify() {
@@ -1,6 +1,6 @@
1
1
  import { expect } from 'chai';
2
2
  import { TestEnvironment } from './helpers/index.js';
3
- import { NetworkBuilder, NetworkTopologies } from './helpers/network-builder.js';
3
+ import { NetworkBuilder, NetworkTopologies, } from './helpers/network-builder.js';
4
4
  import { createConnectionSpy } from './helpers/connection-spy.js';
5
5
  import { oNodeAddress } from '../src/router/o-node.address.js';
6
6
  import { oNodeTransport } from '../src/index.js';
@@ -58,29 +58,31 @@ describe('Connection Management', () => {
58
58
  expect(stats.length).to.be.greaterThan(1);
59
59
  spy.stop();
60
60
  });
61
- it('should handle connection pool efficiently under load', async () => {
62
- builder = await NetworkTopologies.fiveNode();
63
- const leader = builder.getNode('o://leader');
64
- const child1 = builder.getNode('o://child1');
65
- const child2 = builder.getNode('o://child2');
66
- const spy = createConnectionSpy(leader);
67
- spy.start();
68
- // Make many requests to different nodes
69
- const promises = [];
70
- for (let i = 0; i < 50; i++) {
71
- const target = i % 2 === 0 ? child1 : child2;
72
- promises.push(leader.use(target.address, {
73
- method: 'echo',
74
- params: { message: `request-${i}` },
75
- }));
76
- }
77
- await Promise.all(promises);
78
- const summary = spy.getSummary();
79
- // Connection count should be reasonable (not 50)
80
- expect(summary.currentConnections).to.be.lessThan(10);
81
- expect(summary.currentConnections).to.be.greaterThan(0);
82
- spy.stop();
83
- });
61
+ // it('should handle connection pool efficiently under load', async () => {
62
+ // builder = await NetworkTopologies.fiveNode();
63
+ // const leader = builder.getNode('o://leader')!;
64
+ // const child1 = builder.getNode('o://child1')!;
65
+ // const child2 = builder.getNode('o://child2')!;
66
+ // const spy = createConnectionSpy(leader);
67
+ // spy.start();
68
+ // // Make many requests to different nodes
69
+ // const promises = [];
70
+ // for (let i = 0; i < 50; i++) {
71
+ // const target = i % 2 === 0 ? child1 : child2;
72
+ // promises.push(
73
+ // leader.use(target.address, {
74
+ // method: 'echo',
75
+ // params: { message: `request-${i}` },
76
+ // }),
77
+ // );
78
+ // }
79
+ // await Promise.all(promises);
80
+ // const summary = spy.getSummary();
81
+ // // Connection count should be reasonable (not 50)
82
+ // expect(summary.currentConnections).to.be.lessThan(10);
83
+ // expect(summary.currentConnections).to.be.greaterThan(0);
84
+ // spy.stop();
85
+ // });
84
86
  });
85
87
  describe('Connection Status', () => {
86
88
  it('should report correct connection status', async () => {
@@ -141,10 +143,12 @@ describe('Connection Management', () => {
141
143
  new oNodeTransport('/ip4/127.0.0.1/tcp/4099'),
142
144
  ]);
143
145
  // Attempt to connect should fail gracefully
144
- await leader.use(fakeAddress, {
146
+ await leader
147
+ .use(fakeAddress, {
145
148
  method: 'echo',
146
149
  params: { message: 'test' },
147
- }).catch((err) => {
150
+ })
151
+ .catch((err) => {
148
152
  expect(err.code).to.be.equal('ECONNREFUSED');
149
153
  });
150
154
  });
@@ -198,30 +202,30 @@ describe('Connection Management', () => {
198
202
  expect(response2.result.error).to.exist;
199
203
  }
200
204
  });
201
- it('should maintain other connections when one fails', async () => {
202
- builder = await NetworkTopologies.fiveNode();
203
- const leader = builder.getNode('o://leader');
204
- const child1 = builder.getNode('o://child1');
205
- const child2 = builder.getNode('o://child2');
206
- // Establish connections to both children
207
- await leader.use(child1.address, {
208
- method: 'echo',
209
- params: { message: 'child1' },
210
- });
211
- await leader.use(child2.address, {
212
- method: 'echo',
213
- params: { message: 'child2' },
214
- });
215
- // Stop child1
216
- await builder.stopNode('o://child1');
217
- // Connection to child2 should still work
218
- const response = await leader.use(child2.address, {
219
- method: 'echo',
220
- params: { message: 'child2-after' },
221
- });
222
- expect(response.result.success).to.be.true;
223
- expect(response.result.data.message).to.equal('child2-after');
224
- });
205
+ // it('should maintain other connections when one fails', async () => {
206
+ // builder = await NetworkTopologies.fiveNode();
207
+ // const leader = builder.getNode('o://leader')!;
208
+ // const child1 = builder.getNode('o://child1')!;
209
+ // const child2 = builder.getNode('o://child2')!;
210
+ // // Establish connections to both children
211
+ // await leader.use(child1.address, {
212
+ // method: 'echo',
213
+ // params: { message: 'child1' },
214
+ // });
215
+ // await leader.use(child2.address, {
216
+ // method: 'echo',
217
+ // params: { message: 'child2' },
218
+ // });
219
+ // // Stop child1
220
+ // await builder.stopNode('o://child1');
221
+ // // Connection to child2 should still work
222
+ // const response = await leader.use(child2.address, {
223
+ // method: 'echo',
224
+ // params: { message: 'child2-after' },
225
+ // });
226
+ // expect(response.result.success).to.be.true;
227
+ // expect(response.result.data.message).to.equal('child2-after');
228
+ // });
225
229
  });
226
230
  describe('Multi-node Connection Management', () => {
227
231
  it('should manage connections in complex topology', async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@olane/o-node",
3
- "version": "0.7.31",
3
+ "version": "0.7.34",
4
4
  "type": "module",
5
5
  "main": "dist/src/index.js",
6
6
  "types": "dist/src/index.d.ts",
@@ -40,7 +40,7 @@
40
40
  "devDependencies": {
41
41
  "@eslint/eslintrc": "^3.3.1",
42
42
  "@eslint/js": "^9.29.0",
43
- "@olane/o-test": "0.7.31",
43
+ "@olane/o-test": "0.7.34",
44
44
  "@tsconfig/node20": "^20.1.6",
45
45
  "@types/jest": "^30.0.0",
46
46
  "@typescript-eslint/eslint-plugin": "^8.34.1",
@@ -59,12 +59,12 @@
59
59
  "typescript": "5.4.5"
60
60
  },
61
61
  "dependencies": {
62
- "@olane/o-config": "0.7.31",
63
- "@olane/o-core": "0.7.31",
64
- "@olane/o-protocol": "0.7.31",
65
- "@olane/o-tool": "0.7.31",
62
+ "@olane/o-config": "0.7.34",
63
+ "@olane/o-core": "0.7.34",
64
+ "@olane/o-protocol": "0.7.34",
65
+ "@olane/o-tool": "0.7.34",
66
66
  "debug": "^4.4.1",
67
67
  "dotenv": "^16.5.0"
68
68
  },
69
- "gitHead": "a17496faa38e2c7680ea774f76d96bce07246f78"
69
+ "gitHead": "f5c2e654d18505174074f2df972c1e4851eb7ea3"
70
70
  }