@olane/o-node 0.7.39 → 0.7.41

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 (38) hide show
  1. package/dist/src/connection/index.d.ts +2 -0
  2. package/dist/src/connection/index.d.ts.map +1 -1
  3. package/dist/src/connection/index.js +2 -0
  4. package/dist/src/connection/interfaces/o-node-connection-stream.config.d.ts +8 -0
  5. package/dist/src/connection/interfaces/o-node-connection-stream.config.d.ts.map +1 -0
  6. package/dist/src/connection/interfaces/o-node-connection-stream.config.js +1 -0
  7. package/dist/src/connection/o-node-connection-stream.d.ts +34 -0
  8. package/dist/src/connection/o-node-connection-stream.d.ts.map +1 -0
  9. package/dist/src/connection/o-node-connection-stream.js +68 -0
  10. package/dist/src/connection/o-node-connection.d.ts +10 -4
  11. package/dist/src/connection/o-node-connection.d.ts.map +1 -1
  12. package/dist/src/connection/o-node-connection.js +51 -26
  13. package/dist/src/connection/o-node-connection.manager.d.ts +4 -0
  14. package/dist/src/connection/o-node-connection.manager.d.ts.map +1 -1
  15. package/dist/src/connection/o-node-connection.manager.js +24 -0
  16. package/dist/src/connection/stream-handler.config.d.ts +11 -0
  17. package/dist/src/connection/stream-handler.config.d.ts.map +1 -1
  18. package/dist/src/connection/stream-handler.d.ts +6 -12
  19. package/dist/src/connection/stream-handler.d.ts.map +1 -1
  20. package/dist/src/connection/stream-handler.js +112 -62
  21. package/dist/src/o-node.tool.d.ts +3 -1
  22. package/dist/src/o-node.tool.d.ts.map +1 -1
  23. package/dist/src/o-node.tool.js +44 -6
  24. package/dist/src/router/o-node.address.d.ts +1 -0
  25. package/dist/src/router/o-node.address.d.ts.map +1 -1
  26. package/dist/src/router/o-node.address.js +4 -0
  27. package/dist/src/utils/connection.utils.d.ts +9 -0
  28. package/dist/src/utils/connection.utils.d.ts.map +1 -0
  29. package/dist/src/utils/connection.utils.js +26 -0
  30. package/dist/src/utils/index.d.ts +1 -0
  31. package/dist/src/utils/index.d.ts.map +1 -1
  32. package/dist/src/utils/index.js +1 -0
  33. package/dist/test/astream-reuse.spec.d.ts +2 -0
  34. package/dist/test/astream-reuse.spec.d.ts.map +1 -0
  35. package/dist/test/astream-reuse.spec.js +107 -0
  36. package/dist/test/connection-management.spec.js +1 -0
  37. package/dist/test/helpers/network-builder.d.ts.map +1 -1
  38. package/package.json +7 -7
@@ -2,4 +2,6 @@ export * from './o-node-connection.js';
2
2
  export * from './o-node-connection.manager.js';
3
3
  export * from './interfaces/o-node-connection.config.js';
4
4
  export * from './interfaces/o-node-connection-manager.config.js';
5
+ export * from './o-node-connection-stream.js';
6
+ export * from './stream-handler.config.js';
5
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/connection/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,0CAA0C,CAAC;AACzD,cAAc,kDAAkD,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/connection/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,0CAA0C,CAAC;AACzD,cAAc,kDAAkD,CAAC;AACjE,cAAc,+BAA+B,CAAC;AAC9C,cAAc,4BAA4B,CAAC"}
@@ -2,3 +2,5 @@ export * from './o-node-connection.js';
2
2
  export * from './o-node-connection.manager.js';
3
3
  export * from './interfaces/o-node-connection.config.js';
4
4
  export * from './interfaces/o-node-connection-manager.config.js';
5
+ export * from './o-node-connection-stream.js';
6
+ export * from './stream-handler.config.js';
@@ -0,0 +1,8 @@
1
+ import { oAddress } from '@olane/o-core';
2
+ import { StreamReusePolicy } from '../stream-handler.config';
3
+ export interface oNodeConnectionStreamConfig {
4
+ direction: 'inbound' | 'outbound';
5
+ reusePolicy: StreamReusePolicy;
6
+ remoteAddress: oAddress;
7
+ }
8
+ //# sourceMappingURL=o-node-connection-stream.config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"o-node-connection-stream.config.d.ts","sourceRoot":"","sources":["../../../../src/connection/interfaces/o-node-connection-stream.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D,MAAM,WAAW,2BAA2B;IAC1C,SAAS,EAAE,SAAS,GAAG,UAAU,CAAC;IAClC,WAAW,EAAE,iBAAiB,CAAC;IAC/B,aAAa,EAAE,QAAQ,CAAC;CACzB"}
@@ -0,0 +1,34 @@
1
+ import type { Stream } from '@libp2p/interface';
2
+ import { oObject } from '@olane/o-core';
3
+ import { oNodeConnectionStreamConfig } from './interfaces/o-node-connection-stream.config.js';
4
+ /**
5
+ * oNodeConnectionStream wraps a libp2p Stream with caller/receiver address metadata
6
+ * to enable proper stream reuse based on address pairs rather than protocol only.
7
+ *
8
+ * Key features:
9
+ * - Bidirectional cache keys: A↔B === B↔A
10
+ * - Automatic reusability checking
11
+ * - Idle time tracking for cleanup
12
+ */
13
+ export declare class oNodeConnectionStream extends oObject {
14
+ readonly p2pStream: Stream;
15
+ readonly config: oNodeConnectionStreamConfig;
16
+ readonly createdAt: number;
17
+ constructor(p2pStream: Stream, config: oNodeConnectionStreamConfig);
18
+ validate(): void;
19
+ /**
20
+ * Checks if the stream is in a valid state:
21
+ * - Stream status is 'open'
22
+ * - Write status is 'writable'
23
+ * - Remote read status is 'readable'
24
+ *
25
+ * @returns true if stream can be used
26
+ */
27
+ get isValid(): boolean;
28
+ /**
29
+ * Gets the age of the stream in milliseconds
30
+ */
31
+ get age(): number;
32
+ close(): Promise<void>;
33
+ }
34
+ //# sourceMappingURL=o-node-connection-stream.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"o-node-connection-stream.d.ts","sourceRoot":"","sources":["../../../src/connection/o-node-connection-stream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAuB,OAAO,EAAiB,MAAM,eAAe,CAAC;AAC5E,OAAO,EAAE,2BAA2B,EAAE,MAAM,iDAAiD,CAAC;AAE9F;;;;;;;;GAQG;AACH,qBAAa,qBAAsB,SAAQ,OAAO;aAI9B,SAAS,EAAE,MAAM;aACjB,MAAM,EAAE,2BAA2B;IAJrD,SAAgB,SAAS,EAAE,MAAM,CAAC;gBAGhB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,2BAA2B;IAOrD,QAAQ;IA6BR;;;;;;;OAOG;IACH,IAAI,OAAO,IAAI,OAAO,CAMrB;IAED;;OAEG;IACH,IAAI,GAAG,IAAI,MAAM,CAEhB;IAEK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAgB7B"}
@@ -0,0 +1,68 @@
1
+ import { oError, oErrorCodes, oObject } from '@olane/o-core';
2
+ /**
3
+ * oNodeConnectionStream wraps a libp2p Stream with caller/receiver address metadata
4
+ * to enable proper stream reuse based on address pairs rather than protocol only.
5
+ *
6
+ * Key features:
7
+ * - Bidirectional cache keys: A↔B === B↔A
8
+ * - Automatic reusability checking
9
+ * - Idle time tracking for cleanup
10
+ */
11
+ export class oNodeConnectionStream extends oObject {
12
+ constructor(p2pStream, config) {
13
+ super();
14
+ this.p2pStream = p2pStream;
15
+ this.config = config;
16
+ this.createdAt = Date.now();
17
+ }
18
+ // callable pattern to disrupt flow if not in valid state
19
+ validate() {
20
+ // do nothing
21
+ if (!this.p2pStream ||
22
+ (this.p2pStream.status !== 'open' && this.p2pStream.status !== 'reset')) {
23
+ throw new oError(oErrorCodes.FAILED_TO_DIAL_TARGET, 'Failed to dial target');
24
+ }
25
+ if (this.p2pStream.status === 'reset') {
26
+ this.logger.debug('P2P stream failed to create, status:', this.p2pStream.status);
27
+ throw new oError(oErrorCodes.CONNECTION_LIMIT_REACHED, 'Connection limit reached or configuration prevented stream creation');
28
+ }
29
+ if (!this.isValid) {
30
+ throw new oError(oErrorCodes.INVALID_STATE, 'Session is not in a valid state');
31
+ }
32
+ }
33
+ /**
34
+ * Checks if the stream is in a valid state:
35
+ * - Stream status is 'open'
36
+ * - Write status is 'writable'
37
+ * - Remote read status is 'readable'
38
+ *
39
+ * @returns true if stream can be used
40
+ */
41
+ get isValid() {
42
+ return (this.p2pStream.status === 'open' &&
43
+ this.p2pStream.writeStatus === 'writable' &&
44
+ this.p2pStream.remoteReadStatus === 'readable');
45
+ }
46
+ /**
47
+ * Gets the age of the stream in milliseconds
48
+ */
49
+ get age() {
50
+ return Date.now() - this.createdAt;
51
+ }
52
+ async close() {
53
+ // Don't close if reuse policy is enabled
54
+ if (this.config.reusePolicy === 'reuse') {
55
+ this.logger.debug('Stream reuse enabled, not closing stream');
56
+ return;
57
+ }
58
+ if (this.p2pStream.status === 'open') {
59
+ try {
60
+ // force the close for now until we can implement a proper close
61
+ await this.p2pStream.abort(new Error('Stream closed'));
62
+ }
63
+ catch (error) {
64
+ this.logger.debug('Error closing stream:', error.message);
65
+ }
66
+ }
67
+ }
68
+ }
@@ -1,18 +1,24 @@
1
- import { Connection, Stream } from '@olane/o-config';
1
+ import { Connection } from '@olane/o-config';
2
2
  import { oConnection, oRequest, oResponse } from '@olane/o-core';
3
3
  import { oNodeConnectionConfig } from './interfaces/o-node-connection.config.js';
4
4
  import { StreamHandler } from './stream-handler.js';
5
5
  import type { StreamReusePolicy } from './stream-handler.config.js';
6
+ import { oNodeAddress } from '../router/o-node.address.js';
7
+ import { oNodeConnectionStream } from './o-node-connection-stream.js';
6
8
  export declare class oNodeConnection extends oConnection {
7
9
  protected readonly config: oNodeConnectionConfig;
8
10
  p2pConnection: Connection;
9
11
  protected streamHandler: StreamHandler;
10
12
  protected reusePolicy: StreamReusePolicy;
11
13
  constructor(config: oNodeConnectionConfig);
12
- validate(stream?: Stream): void;
13
- getOrCreateStream(): Promise<Stream>;
14
+ get remotePeerId(): import("@olane/o-config").PeerId;
15
+ get remoteAddr(): import("@olane/o-config").Multiaddr;
16
+ supportsAddress(address: oNodeAddress): boolean;
17
+ getOrCreateStream(): Promise<oNodeConnectionStream>;
18
+ createStream(): Promise<oNodeConnectionStream>;
19
+ get streams(): oNodeConnectionStream[];
14
20
  transmit(request: oRequest): Promise<oResponse>;
15
- postTransmit(stream: Stream): Promise<void>;
21
+ postTransmit(stream: oNodeConnectionStream): Promise<void>;
16
22
  abort(error: Error): Promise<void>;
17
23
  close(): Promise<void>;
18
24
  }
@@ -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;AACpD,OAAO,KAAK,EAEV,iBAAiB,EAClB,MAAM,4BAA4B,CAAC;AAEpC,qBAAa,eAAgB,SAAQ,WAAW;IAKlC,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,qBAAqB;IAJrD,aAAa,EAAE,UAAU,CAAC;IACjC,SAAS,CAAC,aAAa,EAAE,aAAa,CAAC;IACvC,SAAS,CAAC,WAAW,EAAE,iBAAiB,CAAC;gBAEV,MAAM,EAAE,qBAAqB;IAO5D,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM;IAmBlB,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC;IAkBpC,QAAQ,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC;IA2C/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,EAAU,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;AACpD,OAAO,KAAK,EAEV,iBAAiB,EAClB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAGtE,qBAAa,eAAgB,SAAQ,WAAW;IAKlC,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,qBAAqB;IAJrD,aAAa,EAAE,UAAU,CAAC;IACjC,SAAS,CAAC,aAAa,EAAE,aAAa,CAAC;IACvC,SAAS,CAAC,WAAW,EAAE,iBAAiB,CAAC;gBAEV,MAAM,EAAE,qBAAqB;IAO5D,IAAI,YAAY,qCAEf;IAED,IAAI,UAAU,wCAEb;IAED,eAAe,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO;IAMzC,iBAAiB,IAAI,OAAO,CAAC,qBAAqB,CAAC;IAanD,YAAY,IAAI,OAAO,CAAC,qBAAqB,CAAC;IA6BpD,IAAI,OAAO,IAAI,qBAAqB,EAAE,CAcrC;IAEK,QAAQ,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC;IA6C/C,YAAY,CAAC,MAAM,EAAE,qBAAqB;IAI1C,KAAK,CAAC,KAAK,EAAE,KAAK;IAMlB,KAAK;CAKZ"}
@@ -1,5 +1,6 @@
1
1
  import { oConnection, oError, oErrorCodes, } from '@olane/o-core';
2
2
  import { StreamHandler } from './stream-handler.js';
3
+ import { oNodeConnectionStream } from './o-node-connection-stream.js';
3
4
  export class oNodeConnection extends oConnection {
4
5
  constructor(config) {
5
6
  super(config);
@@ -8,37 +9,64 @@ export class oNodeConnection extends oConnection {
8
9
  this.streamHandler = new StreamHandler(this.logger);
9
10
  this.reusePolicy = config.reusePolicy ?? 'none';
10
11
  }
11
- validate(stream) {
12
- if (this.config.p2pConnection.status !== 'open') {
13
- throw new Error('Connection is not valid');
14
- }
15
- // do nothing
16
- if (!stream || (stream.status !== 'open' && stream.status !== 'reset')) {
17
- throw new oError(oErrorCodes.FAILED_TO_DIAL_TARGET, 'Failed to dial target');
18
- }
19
- if (stream.status === 'reset') {
20
- throw new oError(oErrorCodes.CONNECTION_LIMIT_REACHED, 'Connection limit reached');
21
- }
12
+ get remotePeerId() {
13
+ return this.p2pConnection.remotePeer;
14
+ }
15
+ get remoteAddr() {
16
+ return this.p2pConnection.remoteAddr;
17
+ }
18
+ supportsAddress(address) {
19
+ return address.libp2pTransports.some((transport) => {
20
+ return transport.toString() === this.remoteAddr.toString();
21
+ });
22
22
  }
23
23
  async getOrCreateStream() {
24
- const streamConfig = {
24
+ if (this.reusePolicy === 'reuse' && this.streams.length > 0) {
25
+ this.logger.debug('Returning reuse stream: ', this.streams[0].p2pStream.protocol);
26
+ // search for streams that allow re-use
27
+ return this.streams[0];
28
+ }
29
+ return this.createStream();
30
+ }
31
+ async createStream() {
32
+ const protocol = this.nextHopAddress.protocol +
33
+ (this.reusePolicy === 'reuse' ? '/reuse' : ''); // connect specifically to the reuse protocol version if desired
34
+ this.logger.debug('Creating stream for protocol:', protocol);
35
+ const stream = await this.p2pConnection.newStream(protocol, {
25
36
  signal: this.abortSignal,
26
37
  maxOutboundStreams: process.env.MAX_OUTBOUND_STREAMS
27
38
  ? parseInt(process.env.MAX_OUTBOUND_STREAMS)
28
39
  : 1000,
29
40
  runOnLimitedConnection: this.config.runOnLimitedConnection ?? true,
30
- reusePolicy: this.reusePolicy,
31
- drainTimeoutMs: this.config.drainTimeoutMs,
32
- };
33
- return this.streamHandler.getOrCreateStream(this.p2pConnection, this.nextHopAddress.protocol, streamConfig);
41
+ });
42
+ const managedStream = new oNodeConnectionStream(stream, {
43
+ direction: stream.direction,
44
+ reusePolicy: this.config.reusePolicy ?? 'none', // default to no re-use stream
45
+ remoteAddress: this.nextHopAddress,
46
+ });
47
+ // print the num streams
48
+ const numStreams = this.streams.map((s) => s.isValid).length;
49
+ this.logger.debug(`Connection spawned new stream: ${stream.id}. Connection now has ${numStreams} total streams open`);
50
+ return managedStream;
51
+ }
52
+ get streams() {
53
+ return (this.p2pConnection?.streams
54
+ ?.filter((s) => {
55
+ return s.protocol.includes('/o/');
56
+ })
57
+ .map((s) => {
58
+ return new oNodeConnectionStream(s, {
59
+ direction: s.direction,
60
+ reusePolicy: this.config.reusePolicy ?? 'none', // default to no re-use stream
61
+ remoteAddress: this.nextHopAddress,
62
+ });
63
+ }) || []);
34
64
  }
35
65
  async transmit(request) {
36
66
  try {
37
- // if (this.config.runOnLimitedConnection) {
38
- // this.logger.debug('Running on limited connection...');
39
- // }
40
67
  const stream = await this.getOrCreateStream();
41
- this.validate(stream);
68
+ // ensure stream is valid
69
+ stream.validate();
42
70
  const streamConfig = {
43
71
  signal: this.abortSignal,
44
72
  drainTimeoutMs: this.config.drainTimeoutMs,
@@ -46,11 +74,11 @@ export class oNodeConnection extends oConnection {
46
74
  };
47
75
  // Send the request with backpressure handling
48
76
  const data = new TextEncoder().encode(request.toString());
49
- await this.streamHandler.sendLengthPrefixed(stream, data, streamConfig);
77
+ await this.streamHandler.sendLengthPrefixed(stream.p2pStream, data, streamConfig);
50
78
  // Handle response using StreamHandler
51
79
  // Pass request handler if configured to enable bidirectional stream processing
52
80
  // Pass request ID to enable proper response correlation on shared streams
53
- const response = await this.streamHandler.handleOutgoingStream(stream, this.emitter, streamConfig, this.config.requestHandler, request.id);
81
+ const response = await this.streamHandler.handleOutgoingStream(stream.p2pStream, this.emitter, streamConfig, this.config.requestHandler, request.id);
54
82
  // Handle cleanup of the stream
55
83
  await this.postTransmit(stream);
56
84
  return response;
@@ -63,10 +91,7 @@ export class oNodeConnection extends oConnection {
63
91
  }
64
92
  }
65
93
  async postTransmit(stream) {
66
- const streamConfig = {
67
- reusePolicy: this.reusePolicy,
68
- };
69
- await this.streamHandler.close(stream, streamConfig);
94
+ await stream.close();
70
95
  }
71
96
  async abort(error) {
72
97
  this.logger.debug('Aborting connection');
@@ -30,6 +30,10 @@ export declare class oNodeConnectionManager extends oConnectionManager {
30
30
  private getPeerIdFromAddress;
31
31
  getOrCreateConnection(nextHopAddress: oAddress, address: oAddress): Promise<Connection>;
32
32
  private performDial;
33
+ answer(config: oConnectionConfig & {
34
+ p2pConnection: Connection;
35
+ reuse?: boolean;
36
+ }): Promise<oNodeConnection>;
33
37
  /**
34
38
  * Connect to a given address, reusing libp2p connections when possible
35
39
  * @param config - Connection configuration
@@ -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;IAwBnB,MAAM,CACV,MAAM,EAAE,iBAAiB,GAAG;QAAE,aAAa,EAAE,UAAU,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GACzE,OAAO,CAAC,eAAe,CAAC;IAmC3B;;;;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"}
@@ -130,6 +130,30 @@ export class oNodeConnectionManager extends oConnectionManager {
130
130
  });
131
131
  return connection;
132
132
  }
133
+ async answer(config) {
134
+ const { address, nextHopAddress, callerAddress, readTimeoutMs, drainTimeoutMs, p2pConnection, reuse, } = config;
135
+ const connection = new oNodeConnection({
136
+ nextHopAddress: nextHopAddress,
137
+ address: address,
138
+ p2pConnection: p2pConnection,
139
+ callerAddress: callerAddress,
140
+ readTimeoutMs: readTimeoutMs ?? this.defaultReadTimeoutMs,
141
+ drainTimeoutMs: drainTimeoutMs ?? this.defaultDrainTimeoutMs,
142
+ isStream: config.isStream ?? false,
143
+ abortSignal: config.abortSignal,
144
+ runOnLimitedConnection: this.config.runOnLimitedConnection ?? false,
145
+ requestHandler: config.requestHandler ?? undefined,
146
+ reusePolicy: reuse ? 'reuse' : 'none',
147
+ });
148
+ const transportKey = this.getTransportKeyFromAddress(nextHopAddress);
149
+ if (transportKey) {
150
+ this.connectionsByTransportKey.set(transportKey, p2pConnection);
151
+ }
152
+ else {
153
+ this.logger.error('Should not happen! Failed to generate a transport key for address:', nextHopAddress);
154
+ }
155
+ return connection;
156
+ }
133
157
  /**
134
158
  * Connect to a given address, reusing libp2p connections when possible
135
159
  * @param config - Connection configuration
@@ -34,6 +34,17 @@ export interface StreamHandlerConfig {
34
34
  * AbortSignal for cancellation
35
35
  */
36
36
  signal?: AbortSignal;
37
+ /**
38
+ * Maximum number of streams to cache
39
+ * Older streams will be evicted when limit is reached
40
+ * @default unlimited
41
+ */
42
+ maxCachedStreams?: number;
43
+ /**
44
+ * Time in milliseconds after which idle cached streams are closed
45
+ * @default unlimited (streams remain cached until closed by peer)
46
+ */
47
+ streamIdleTimeout?: number;
37
48
  }
38
49
  /**
39
50
  * 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;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,mBAAmB,CAAC;CAC7B"}
@@ -41,13 +41,14 @@ export declare class StreamHandler {
41
41
  */
42
42
  private extractAndParseJSON;
43
43
  /**
44
- * Gets an existing open stream or creates a new one based on reuse policy
44
+ * Builds a bidirectional cache key from caller and receiver addresses
45
+ * The key is symmetric: A↔B === B↔A
45
46
  *
46
- * @param connection - The libp2p connection
47
- * @param protocol - The protocol to use for the stream
48
- * @param config - Stream handler configuration
47
+ * @param callerAddress - The caller's address
48
+ * @param receiverAddress - The receiver's address
49
+ * @returns Cache key string
49
50
  */
50
- getOrCreateStream(connection: Connection, protocol: string, config?: StreamHandlerConfig): Promise<Stream>;
51
+ private buildCacheKey;
51
52
  /**
52
53
  * Sends data through a stream using length-prefixed encoding (libp2p v3 best practice)
53
54
  * Each message is automatically prefixed with a varint indicating the message length
@@ -58,13 +59,6 @@ export declare class StreamHandler {
58
59
  * @param config - Configuration for timeout and other options
59
60
  */
60
61
  sendLengthPrefixed(stream: Stream, data: Uint8Array, config?: StreamHandlerConfig): Promise<void>;
61
- /**
62
- * Closes a stream safely with error handling
63
- *
64
- * @param stream - The stream to close
65
- * @param config - Configuration including reuse policy
66
- */
67
- close(stream: Stream, config?: StreamHandlerConfig): Promise<void>;
68
62
  /**
69
63
  * Handles an incoming stream on the server side using length-prefixed protocol
70
64
  * Uses async read loops instead of event listeners (libp2p v3 best practice)
@@ -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;AAItE;;;;;;;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;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,mBAAmB;IAqC3B;;;;;;OAMG;IACG,iBAAiB,CACrB,UAAU,EAAE,UAAU,EACtB,QAAQ,EAAE,MAAM,EAChB,MAAM,GAAE,mBAAwB,GAC/B,OAAO,CAAC,MAAM,CAAC;IAwDlB;;;;;;;;OAQG;IACG,kBAAkB,CACtB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,UAAU,EAChB,MAAM,GAAE,mBAAwB,GAC/B,OAAO,CAAC,IAAI,CAAC;IAKhB;;;;;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;IA+BhB;;;;;;OAMG;YACW,oBAAoB;IA6BlC;;;;;;;;;;OAUG;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;IAiErB;;;;;;;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":";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;AAEjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,KAAK,EACV,mBAAmB,EAEpB,MAAM,4BAA4B,CAAC;AAKpC;;;;;;;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;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,mBAAmB;IAqC3B;;;;;;;OAOG;IACH,OAAO,CAAC,aAAa;IA0HrB;;;;;;;;OAQG;IACG,kBAAkB,CACtB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,UAAU,EAChB,MAAM,GAAE,mBAAwB,GAC/B,OAAO,CAAC,IAAI,CAAC;IAKhB;;;;;;;;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;IA+BhB;;;;;;OAMG;YACW,oBAAoB;IA6BlC;;;;;;;;;;OAUG;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;IAiErB;;;;;;;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"}
@@ -72,49 +72,121 @@ export class StreamHandler {
72
72
  }
73
73
  }
74
74
  /**
75
- * Gets an existing open stream or creates a new one based on reuse policy
75
+ * Builds a bidirectional cache key from caller and receiver addresses
76
+ * The key is symmetric: A↔B === B↔A
76
77
  *
77
- * @param connection - The libp2p connection
78
- * @param protocol - The protocol to use for the stream
79
- * @param config - Stream handler configuration
78
+ * @param callerAddress - The caller's address
79
+ * @param receiverAddress - The receiver's address
80
+ * @returns Cache key string
80
81
  */
81
- async getOrCreateStream(connection, protocol, config = {}) {
82
- this.logger.debug(`Getting or creating stream for protocol: ${protocol}, connection`, {
83
- status: connection.status,
84
- remoteAddr: connection.remoteAddr.toString(),
85
- streamCount: connection.streams.length,
86
- reusePolicy: config.reusePolicy ?? 'none',
87
- });
88
- if (connection.status !== 'open') {
89
- throw new oError(oErrorCodes.INVALID_STATE, 'Connection not open');
90
- }
91
- const reusePolicy = config.reusePolicy ?? 'none';
92
- this.logger.debug('Checking for existing reusable stream', connection.streams.map((s) => ({
93
- status: s.status,
94
- protocol: s.protocol,
95
- writeStatus: s.writeStatus,
96
- remoteReadStatus: s.remoteReadStatus,
97
- id: s.id,
98
- })));
99
- // Check for existing stream if reuse is enabled
100
- if (reusePolicy === 'reuse') {
101
- const existingStream = connection.streams.find((stream) => stream.status === 'open' &&
102
- stream.protocol === protocol &&
103
- stream.writeStatus === 'writable' &&
104
- stream.remoteReadStatus === 'readable');
105
- if (existingStream) {
106
- this.logger.debug('Reusing existing stream', existingStream.id, existingStream.direction);
107
- return existingStream;
108
- }
109
- }
110
- // Create new stream
111
- const stream = await connection.newStream(protocol, {
112
- signal: config.signal,
113
- maxOutboundStreams: config.maxOutboundStreams ?? 1000,
114
- runOnLimitedConnection: config.runOnLimitedConnection ?? false,
115
- });
116
- return stream;
82
+ buildCacheKey(callerAddress, receiverAddress) {
83
+ const addresses = [callerAddress.value, receiverAddress.value].sort();
84
+ return `${addresses[0]}↔${addresses[1]}`;
117
85
  }
86
+ // /**
87
+ // * Gets an existing open stream or creates a new one based on reuse policy
88
+ // *
89
+ // * @param connection - The libp2p connection
90
+ // * @param protocol - The protocol to use for the stream
91
+ // * @param config - Stream handler configuration
92
+ // * @param streamAddresses - Optional addresses for address-based stream reuse
93
+ // */
94
+ // async getOrCreateStream(
95
+ // connection: Connection,
96
+ // protocol: string,
97
+ // config: StreamHandlerConfig = {},
98
+ // streamAddresses?: {
99
+ // callerAddress: oAddress;
100
+ // receiverAddress: oAddress;
101
+ // direction: 'inbound' | 'outbound';
102
+ // },
103
+ // ): Promise<Stream> {
104
+ // this.logger.debug(
105
+ // `Getting or creating stream for protocol: ${protocol}, connection`,
106
+ // {
107
+ // status: connection.status,
108
+ // remoteAddr: connection.remoteAddr.toString(),
109
+ // streamCount: connection.streams.length,
110
+ // reusePolicy: config.reusePolicy ?? 'none',
111
+ // hasAddresses: !!streamAddresses,
112
+ // },
113
+ // );
114
+ // if (connection.status !== 'open') {
115
+ // throw new oError(oErrorCodes.INVALID_STATE, 'Connection not open');
116
+ // }
117
+ // const reusePolicy = config.reusePolicy ?? 'none';
118
+ // // Check address-based cache if reuse is enabled and addresses provided
119
+ // if (reusePolicy === 'reuse' && streamAddresses) {
120
+ // const cacheKey = this.buildCacheKey(
121
+ // streamAddresses.callerAddress,
122
+ // streamAddresses.receiverAddress,
123
+ // );
124
+ // const cachedStream = this.streamCache.get(cacheKey);
125
+ // if (cachedStream?.isReusable) {
126
+ // this.logger.debug('Reusing cached stream by address', {
127
+ // cacheKey,
128
+ // streamId: cachedStream.stream.id,
129
+ // direction: cachedStream.direction,
130
+ // });
131
+ // cachedStream.updateLastUsed();
132
+ // return cachedStream.stream;
133
+ // } else if (cachedStream) {
134
+ // // Stream exists but not reusable, remove from cache
135
+ // this.logger.debug('Removing non-reusable stream from cache', {
136
+ // cacheKey,
137
+ // status: cachedStream.stream.status,
138
+ // });
139
+ // this.streamCache.delete(cacheKey);
140
+ // }
141
+ // }
142
+ // this.logger.debug(
143
+ // 'No reusable cached stream found, checking connection streams',
144
+ // connection.streams.map((s) => ({
145
+ // status: s.status,
146
+ // protocol: s.protocol,
147
+ // writeStatus: s.writeStatus,
148
+ // remoteReadStatus: s.remoteReadStatus,
149
+ // id: s.id,
150
+ // })),
151
+ // );
152
+ // // Fallback to protocol-based check (legacy behavior)
153
+ // if (reusePolicy === 'reuse' && !streamAddresses) {
154
+ // const existingStream = connection.streams.find(
155
+ // (stream) =>
156
+ // stream.status === 'open' &&
157
+ // stream.protocol === protocol &&
158
+ // stream.writeStatus === 'writable' &&
159
+ // stream.remoteReadStatus === 'readable',
160
+ // );
161
+ // if (existingStream) {
162
+ // this.logger.debug(
163
+ // 'Reusing existing stream by protocol (legacy)',
164
+ // existingStream.id,
165
+ // existingStream.direction,
166
+ // );
167
+ // return existingStream;
168
+ // }
169
+ // }
170
+ // // Create new stream
171
+ // this.logger.debug('Creating new stream', { protocol });
172
+ // const stream = await connection.newStream(protocol, {
173
+ // signal: config.signal,
174
+ // maxOutboundStreams: config.maxOutboundStreams ?? 1000,
175
+ // runOnLimitedConnection: config.runOnLimitedConnection ?? false,
176
+ // });
177
+ // // Cache the stream if reuse is enabled and addresses are provided
178
+ // if (reusePolicy === 'reuse' && streamAddresses) {
179
+ // const managedStream = new oNodeConnectionStream(
180
+ // stream,
181
+ // streamAddresses.callerAddress,
182
+ // streamAddresses.receiverAddress,
183
+ // streamAddresses.direction,
184
+ // );
185
+ // this.cacheStream(managedStream);
186
+ // this.setupStreamCleanup(stream);
187
+ // }
188
+ // return stream;
189
+ // }
118
190
  /**
119
191
  * Sends data through a stream using length-prefixed encoding (libp2p v3 best practice)
120
192
  * Each message is automatically prefixed with a varint indicating the message length
@@ -128,28 +200,6 @@ export class StreamHandler {
128
200
  const lp = lpStream(stream);
129
201
  await lp.write(data, { signal: config.signal });
130
202
  }
131
- /**
132
- * Closes a stream safely with error handling
133
- *
134
- * @param stream - The stream to close
135
- * @param config - Configuration including reuse policy
136
- */
137
- async close(stream, config = {}) {
138
- // Don't close if reuse policy is enabled
139
- if (config.reusePolicy === 'reuse') {
140
- this.logger.debug('Stream reuse enabled, not closing stream');
141
- return;
142
- }
143
- if (stream.status === 'open') {
144
- try {
145
- // force the close for now until we can implement a proper close
146
- await stream.abort(new Error('Stream closed'));
147
- }
148
- catch (error) {
149
- this.logger.debug('Error closing stream:', error.message);
150
- }
151
- }
152
- }
153
203
  /**
154
204
  * Handles an incoming stream on the server side using length-prefixed protocol
155
205
  * Uses async read loops instead of event listeners (libp2p v3 best practice)
@@ -9,9 +9,11 @@ declare const oNodeTool_base: typeof oServerNode;
9
9
  */
10
10
  export declare class oNodeTool extends oNodeTool_base {
11
11
  private streamHandler;
12
+ handleProtocolReuse(address: oAddress): Promise<void>;
12
13
  handleProtocol(address: oAddress): Promise<void>;
13
14
  initialize(): Promise<void>;
14
- handleStream(stream: Stream, connection: Connection): Promise<void>;
15
+ handleStreamReuse(stream: Stream, connection: Connection): Promise<void>;
16
+ handleStream(stream: Stream, connection: Connection, reuse?: boolean): Promise<void>;
15
17
  _tool_identify(): Promise<any>;
16
18
  _tool_child_register(request: oRequest): Promise<any>;
17
19
  }
@@ -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;;AAMrD;;;;GAIG;AACH,qBAAa,SAAU,SAAQ,cAAkB;IAC/C,OAAO,CAAC,aAAa,CAAiB;IAEhC,mBAAmB,CAAC,OAAO,EAAE,QAAQ;IAgBrC,cAAc,CAAC,OAAO,EAAE,QAAQ;IAoBhC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAY3B,iBAAiB,CACrB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC,IAAI,CAAC;IAIV,YAAY,CAChB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,UAAU,EACtB,KAAK,CAAC,EAAE,OAAO,GACd,OAAO,CAAC,IAAI,CAAC;IAwCV,cAAc,IAAI,OAAO,CAAC,GAAG,CAAC;IAQ9B,oBAAoB,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC;CAgC5D"}
@@ -4,25 +4,46 @@ import { oServerNode } from './nodes/server.node.js';
4
4
  import { oNodeTransport } from './router/o-node.transport.js';
5
5
  import { oNodeAddress } from './router/o-node.address.js';
6
6
  import { StreamHandler } from './connection/stream-handler.js';
7
+ import { ConnectionUtils } from './utils/connection.utils.js';
7
8
  /**
8
9
  * oTool is a mixin that extends the base class and implements the oTool interface
9
10
  * @param Base - The base class to extend
10
11
  * @returns A new class that extends the base class and implements the oTool interface
11
12
  */
12
13
  export class oNodeTool extends oTool(oServerNode) {
14
+ async handleProtocolReuse(address) {
15
+ const reuseProtocol = address.protocol + '/reuse';
16
+ const protocols = this.p2pNode.getProtocols();
17
+ if (protocols.find((p) => p === reuseProtocol)) {
18
+ // already handling
19
+ return;
20
+ }
21
+ const maxOutboundsStreams = process.env.MAX_OUTBOUND_STREAMS
22
+ ? parseInt(process.env.MAX_OUTBOUND_STREAMS)
23
+ : 1000;
24
+ await this.p2pNode.handle(reuseProtocol, this.handleStream.bind(this), {
25
+ maxInboundStreams: 10000,
26
+ maxOutboundStreams: maxOutboundsStreams,
27
+ });
28
+ }
13
29
  async handleProtocol(address) {
14
30
  const protocols = this.p2pNode.getProtocols();
15
31
  if (protocols.find((p) => p === address.protocol)) {
16
32
  // already handling
17
33
  return;
18
34
  }
19
- this.logger.debug('Handling protocol: ' + address.protocol);
35
+ const maxOutboundsStreams = process.env.MAX_OUTBOUND_STREAMS
36
+ ? parseInt(process.env.MAX_OUTBOUND_STREAMS)
37
+ : 1000;
38
+ this.logger.debug('Handling protocol: ' + address.protocol, {
39
+ maxInboundStreams: 10000,
40
+ maxOutboundStreams: maxOutboundsStreams,
41
+ });
20
42
  await this.p2pNode.handle(address.protocol, this.handleStream.bind(this), {
21
43
  maxInboundStreams: 10000,
22
- maxOutboundStreams: process.env.MAX_OUTBOUND_STREAMS
23
- ? parseInt(process.env.MAX_OUTBOUND_STREAMS)
24
- : 1000,
44
+ maxOutboundStreams: maxOutboundsStreams,
25
45
  });
46
+ await this.handleProtocolReuse(address);
26
47
  }
27
48
  async initialize() {
28
49
  await super.initialize();
@@ -33,7 +54,25 @@ export class oNodeTool extends oTool(oServerNode) {
33
54
  await this.handleProtocol(this.staticAddress);
34
55
  }
35
56
  }
36
- async handleStream(stream, connection) {
57
+ async handleStreamReuse(stream, connection) {
58
+ return this.handleStream(stream, connection, true);
59
+ }
60
+ async handleStream(stream, connection, reuse) {
61
+ if (reuse) {
62
+ this.logger.debug('Handle stream with reuse = true');
63
+ }
64
+ // record inbound connection to manager
65
+ const remoteAddress = await ConnectionUtils.addressFromConnection({
66
+ currentNode: this,
67
+ connection: connection,
68
+ });
69
+ this.connectionManager.answer({
70
+ nextHopAddress: remoteAddress,
71
+ address: remoteAddress,
72
+ callerAddress: this.address,
73
+ p2pConnection: connection,
74
+ reuse,
75
+ });
37
76
  // Use StreamHandler for consistent stream handling
38
77
  // This follows libp2p v3 best practices for length-prefixed streaming
39
78
  await this.streamHandler.handleIncomingStream(stream, connection, async (request, stream) => {
@@ -56,7 +95,6 @@ export class oNodeTool extends oTool(oServerNode) {
56
95
  };
57
96
  }
58
97
  async _tool_child_register(request) {
59
- this.logger.debug('Child register: ', request.params);
60
98
  const { address, transports } = request.params;
61
99
  const childAddress = new oNodeAddress(address, transports.map((t) => new oNodeTransport(t)));
62
100
  // Add child to hierarchy
@@ -14,5 +14,6 @@ export declare class oNodeAddress extends oAddress {
14
14
  toString(): string;
15
15
  toMultiaddr(): Multiaddr;
16
16
  static fromMultiaddr(ma: Multiaddr): oAddress;
17
+ static fromProtocol(protocol: string): oAddress;
17
18
  }
18
19
  //# sourceMappingURL=o-node.address.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"o-node.address.d.ts","sourceRoot":"","sources":["../../../src/router/o-node.address.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAa,MAAM,iBAAiB,CAAC;AAEvD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAqB,QAAQ,EAAiB,MAAM,eAAe,CAAC;AAE3E,qBAAa,YAAa,SAAQ,QAAQ;aAItB,KAAK,EAAE,MAAM;IAHxB,UAAU,EAAE,cAAc,EAAE,CAAM;gBAGvB,KAAK,EAAE,MAAM,EAC7B,UAAU,GAAE,cAAc,EAAO;IAMnC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE;QACpB,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,EAAE,MAAM,EAAE,GAAG,SAAS,EAAE,CAAC;KACpC,GAAG,YAAY;IAShB,IAAI,gBAAgB,IAAI,cAAc,EAAE,CAEvC;IAED,IAAI,gBAAgB,IAAI,cAAc,EAAE,CAEvC;IAED,QAAQ,IAAI,MAAM;IAIlB,WAAW,IAAI,SAAS;IAIxB,MAAM,CAAC,aAAa,CAAC,EAAE,EAAE,SAAS,GAAG,QAAQ;CAG9C"}
1
+ {"version":3,"file":"o-node.address.d.ts","sourceRoot":"","sources":["../../../src/router/o-node.address.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAa,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAiB,MAAM,eAAe,CAAC;AAExD,qBAAa,YAAa,SAAQ,QAAQ;aAItB,KAAK,EAAE,MAAM;IAHxB,UAAU,EAAE,cAAc,EAAE,CAAM;gBAGvB,KAAK,EAAE,MAAM,EAC7B,UAAU,GAAE,cAAc,EAAO;IAMnC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE;QACpB,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,EAAE,MAAM,EAAE,GAAG,SAAS,EAAE,CAAC;KACpC,GAAG,YAAY;IAShB,IAAI,gBAAgB,IAAI,cAAc,EAAE,CAEvC;IAED,IAAI,gBAAgB,IAAI,cAAc,EAAE,CAEvC;IAED,QAAQ,IAAI,MAAM;IAIlB,WAAW,IAAI,SAAS;IAIxB,MAAM,CAAC,aAAa,CAAC,EAAE,EAAE,SAAS,GAAG,QAAQ;IAI7C,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ;CAIhD"}
@@ -26,4 +26,8 @@ export class oNodeAddress extends oAddress {
26
26
  static fromMultiaddr(ma) {
27
27
  return new oAddress(ma.toString().replace('/o/', 'o://'));
28
28
  }
29
+ static fromProtocol(protocol) {
30
+ const addressInput = protocol.replace('/o/', 'o://');
31
+ return new oAddress(addressInput);
32
+ }
29
33
  }
@@ -0,0 +1,9 @@
1
+ import { Connection } from '@olane/o-config';
2
+ import { oObject } from '@olane/o-core';
3
+ export declare class ConnectionUtils extends oObject {
4
+ static addressFromConnection(options: {
5
+ currentNode: any;
6
+ connection: Connection;
7
+ }): Promise<import("@olane/o-core").oAddress>;
8
+ }
9
+ //# sourceMappingURL=connection.utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection.utils.d.ts","sourceRoot":"","sources":["../../../src/utils/connection.utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAGxC,qBAAa,eAAgB,SAAQ,OAAO;WACtB,qBAAqB,CAAC,OAAO,EAAE;QACjD,WAAW,EAAE,GAAG,CAAC;QACjB,UAAU,EAAE,UAAU,CAAC;KACxB;CAsCF"}
@@ -0,0 +1,26 @@
1
+ import { oObject } from '@olane/o-core';
2
+ import { oNodeAddress } from '../router/o-node.address.js';
3
+ export class ConnectionUtils extends oObject {
4
+ static async addressFromConnection(options) {
5
+ const { currentNode, connection } = options;
6
+ const p2pNode = currentNode.p2pNode;
7
+ // Extract the actual olane address from the peer store
8
+ const peers = await p2pNode.peerStore.all();
9
+ const remotePeer = peers.find((peer) => peer.id.toString() === connection.remotePeer.toString());
10
+ if (!remotePeer) {
11
+ console.log('Failed to find peer:', remotePeer);
12
+ throw new Error(`Failed to extract remote address, peer ${connection.remotePeer.toString()} not found in peer store.`);
13
+ }
14
+ // Get origin address for comparison
15
+ const originAddress = currentNode.address?.value;
16
+ if (!originAddress) {
17
+ throw new Error('Origin address is not configured');
18
+ }
19
+ const originProtocol = originAddress.toString();
20
+ const oProtocol = remotePeer.protocols.find((p) => p.startsWith('/o/') && p.startsWith(originProtocol) === false);
21
+ if (!oProtocol) {
22
+ throw new Error('Failed to extract remote address, could not find o-protocol in peer protocols.');
23
+ }
24
+ return oNodeAddress.fromProtocol(oProtocol);
25
+ }
26
+ }
@@ -1,3 +1,4 @@
1
1
  export * from './stream.utils.js';
2
2
  export * from './network.utils.js';
3
+ export * from './connection.utils.js';
3
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC"}
@@ -1,2 +1,3 @@
1
1
  export * from './stream.utils.js';
2
2
  export * from './network.utils.js';
3
+ export * from './connection.utils.js';
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=astream-reuse.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"astream-reuse.spec.d.ts","sourceRoot":"","sources":["../../test/astream-reuse.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,107 @@
1
+ import { expect } from 'chai';
2
+ import { TestEnvironment } from './helpers/index.js';
3
+ import { NetworkTopologies, } from './helpers/network-builder.js';
4
+ import { oNodeAddress } from '../src/router/o-node.address.js';
5
+ describe('Stream Reuse', () => {
6
+ const env = new TestEnvironment();
7
+ let builder;
8
+ afterEach(async () => {
9
+ if (builder) {
10
+ await builder.cleanup();
11
+ }
12
+ await env.cleanup();
13
+ });
14
+ describe('Stream Reuse with reusePolicy="reuse"', () => {
15
+ it('should reuse the same stream across multiple requests', async () => {
16
+ builder = await NetworkTopologies.twoNode();
17
+ const leader = builder.getNode('o://leader');
18
+ const child = builder.getNode('o://child');
19
+ // Track stream IDs
20
+ const streamIds = [];
21
+ // Make first request
22
+ const response1 = await leader.use(new oNodeAddress(child.address.toString(), child.address.libp2pTransports), {
23
+ method: 'echo',
24
+ params: { message: 'first' },
25
+ });
26
+ expect(response1.result.success).to.be.true;
27
+ // Get active connection to inspect streams
28
+ const connectionManager = leader.connectionManager;
29
+ const connection = connectionManager.getCachedLibp2pConnection(child.address);
30
+ connection.reusePolicy;
31
+ if (connection) {
32
+ // Store initial stream count and first stream ID
33
+ const initialStreamCount = connection.streams.length;
34
+ if (connection.streams.length > 0) {
35
+ streamIds.push(connection.streams[0].id);
36
+ }
37
+ // Make second request
38
+ const response2 = await leader.use(new oNodeAddress(child.address.toString(), child.address.libp2pTransports), {
39
+ method: 'echo',
40
+ params: { message: 'second' },
41
+ });
42
+ expect(response2.result.success).to.be.true;
43
+ // Get stream count after second request
44
+ const finalStreamCount = connection.streams.length;
45
+ if (connection.streams.length > 0) {
46
+ streamIds.push(connection.streams[0].id);
47
+ }
48
+ // With default behavior (reusePolicy='none'), new streams are created
49
+ // This test verifies current behavior
50
+ expect(streamIds.length).to.be.greaterThan(0);
51
+ expect(finalStreamCount).to.be.greaterThan(0);
52
+ }
53
+ });
54
+ });
55
+ describe('Stream Creation with reusePolicy="none"', () => {
56
+ it('should create new streams for each request', async () => {
57
+ builder = await NetworkTopologies.twoNode();
58
+ const leader = builder.getNode('o://leader');
59
+ const child = builder.getNode('o://child');
60
+ // Make multiple requests
61
+ for (let i = 0; i < 3; i++) {
62
+ const response = await leader.use(new oNodeAddress(child.address.toString(), child.address.libp2pTransports), {
63
+ method: 'echo',
64
+ params: { message: `request-${i}` },
65
+ });
66
+ expect(response.result.success).to.be.true;
67
+ }
68
+ // Get connection to verify stream behavior
69
+ const connectionManager = leader.connectionManager;
70
+ const connection = connectionManager.getCachedLibp2pConnection(child.address);
71
+ // With default reusePolicy='none', streams are closed after each request
72
+ // So we expect minimal open streams
73
+ expect(connection).to.exist;
74
+ if (connection) {
75
+ // The number of open streams should be limited since old ones are closed
76
+ expect(connection.streams.length).to.be.lessThan(10);
77
+ }
78
+ });
79
+ });
80
+ describe('Stream Persistence After Transmission', () => {
81
+ it('should close streams after transmission with reusePolicy="none"', async () => {
82
+ builder = await NetworkTopologies.twoNode();
83
+ const leader = builder.getNode('o://leader');
84
+ const child = builder.getNode('o://child');
85
+ // Make a request
86
+ const response = await leader.use(new oNodeAddress(child.address.toString(), child.address.libp2pTransports), {
87
+ method: 'echo',
88
+ params: { message: 'test' },
89
+ });
90
+ expect(response.result.success).to.be.true;
91
+ // Get connection
92
+ const connectionManager = leader.connectionManager;
93
+ const connection = connectionManager.getCachedLibp2pConnection(child.address);
94
+ expect(connection).to.exist;
95
+ if (connection) {
96
+ // Make another request to verify new stream can be created
97
+ const response2 = await leader.use(new oNodeAddress(child.address.toString(), child.address.libp2pTransports), {
98
+ method: 'echo',
99
+ params: { message: 'test2' },
100
+ });
101
+ expect(response2.result.success).to.be.true;
102
+ // Verify connection is still functional
103
+ expect(connection.status).to.equal('open');
104
+ }
105
+ });
106
+ });
107
+ });
@@ -16,6 +16,7 @@ describe('Connection Management', () => {
16
16
  describe('Connection Pooling', () => {
17
17
  it('should cache and reuse connections', async () => {
18
18
  builder = await NetworkTopologies.twoNode();
19
+ console.log('Built the 2 node network, starting test');
19
20
  const leader = builder.getNode('o://leader');
20
21
  const child = builder.getNode('o://child');
21
22
  const spy = createConnectionSpy(leader);
@@ -1 +1 @@
1
- {"version":3,"file":"network-builder.d.ts","sourceRoot":"","sources":["../../../test/helpers/network-builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,4CAA4C,CAAC;AAC7E,OAAO,EAAY,QAAQ,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C;;GAEG;AACH,qBAAa,QAAS,SAAQ,SAAS;IAC9B,SAAS,SAAK;gBAET,MAAM,EAAE,eAAe,GAAG;QAAE,OAAO,EAAE,YAAY,CAAA;KAAE;IAIzD,SAAS,IAAI,OAAO,CAAC,YAAY,CAAC;IAelC,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAwC/B,UAAU,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC;IAS3C,cAAc,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC;IAS9C,YAAY,CAAC,OAAO,EAAE,QAAQ,GAAG,cAAc,CAAC,GAAG,CAAC;CAY5D;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAAoC;IACjD,OAAO,CAAC,YAAY,CAA0B;IAE9C;;;OAGG;IACG,OAAO,CACX,OAAO,EAAE,MAAM,EACf,aAAa,CAAC,EAAE,MAAM,EACtB,MAAM,GAAE,OAAO,CAAC,UAAU,CAAM,GAC/B,OAAO,CAAC,QAAQ,CAAC;IAqCpB;;OAEG;IACG,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB/C;;OAEG;IACG,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAc9C;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAU9B;;OAEG;IACH,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS;IAI9C;;OAEG;IACH,WAAW,IAAI,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC;IAIpC;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAyC7B;;OAEG;YACW,iBAAiB;IAkB/B;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAK/B;AAED;;;;GAIG;AACH,qBAAa,iBAAiB;IAC5B;;;OAGG;WACU,OAAO,IAAI,OAAO,CAAC,cAAc,CAAC;IAO/C;;;OAGG;WACU,SAAS,IAAI,OAAO,CAAC,cAAc,CAAC;IAQjD;;;;OAIG;WACU,QAAQ,IAAI,OAAO,CAAC,cAAc,CAAC;IAUhD;;OAEG;WACU,aAAa,IAAI,OAAO,CAAC,cAAc,CAAC;IAOrD;;;;;OAKG;WACU,OAAO,IAAI,OAAO,CAAC,cAAc,CAAC;CAmBhD"}
1
+ {"version":3,"file":"network-builder.d.ts","sourceRoot":"","sources":["../../../test/helpers/network-builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,4CAA4C,CAAC;AAC7E,OAAO,EAAY,QAAQ,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C;;GAEG;AACH,qBAAa,QAAS,SAAQ,SAAS;IAC9B,SAAS,SAAK;gBAET,MAAM,EAAE,eAAe,GAAG;QAAE,OAAO,EAAE,YAAY,CAAA;KAAE;IAIzD,SAAS,IAAI,OAAO,CAAC,YAAY,CAAC;IAelC,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAuC/B,UAAU,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC;IAS3C,cAAc,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC;IAS9C,YAAY,CAAC,OAAO,EAAE,QAAQ,GAAG,cAAc,CAAC,GAAG,CAAC;CAY5D;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAAoC;IACjD,OAAO,CAAC,YAAY,CAA0B;IAE9C;;;OAGG;IACG,OAAO,CACX,OAAO,EAAE,MAAM,EACf,aAAa,CAAC,EAAE,MAAM,EACtB,MAAM,GAAE,OAAO,CAAC,UAAU,CAAM,GAC/B,OAAO,CAAC,QAAQ,CAAC;IAqCpB;;OAEG;IACG,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiB/C;;OAEG;IACG,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAc9C;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAU9B;;OAEG;IACH,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS;IAI9C;;OAEG;IACH,WAAW,IAAI,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC;IAIpC;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAyC7B;;OAEG;YACW,iBAAiB;IAkB/B;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAK/B;AAED;;;;GAIG;AACH,qBAAa,iBAAiB;IAC5B;;;OAGG;WACU,OAAO,IAAI,OAAO,CAAC,cAAc,CAAC;IAO/C;;;OAGG;WACU,SAAS,IAAI,OAAO,CAAC,cAAc,CAAC;IAQjD;;;;OAIG;WACU,QAAQ,IAAI,OAAO,CAAC,cAAc,CAAC;IAUhD;;OAEG;WACU,aAAa,IAAI,OAAO,CAAC,cAAc,CAAC;IAOrD;;;;;OAKG;WACU,OAAO,IAAI,OAAO,CAAC,cAAc,CAAC;CAmBhD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@olane/o-node",
3
- "version": "0.7.39",
3
+ "version": "0.7.41",
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.39",
43
+ "@olane/o-test": "0.7.41",
44
44
  "@tsconfig/node20": "^20.1.6",
45
45
  "@types/jest": "^30.0.0",
46
46
  "@types/json5": "^2.2.0",
@@ -60,13 +60,13 @@
60
60
  "typescript": "5.4.5"
61
61
  },
62
62
  "dependencies": {
63
- "@olane/o-config": "0.7.39",
64
- "@olane/o-core": "0.7.39",
65
- "@olane/o-protocol": "0.7.39",
66
- "@olane/o-tool": "0.7.39",
63
+ "@olane/o-config": "0.7.41",
64
+ "@olane/o-core": "0.7.41",
65
+ "@olane/o-protocol": "0.7.41",
66
+ "@olane/o-tool": "0.7.41",
67
67
  "debug": "^4.4.1",
68
68
  "dotenv": "^16.5.0",
69
69
  "json5": "^2.2.3"
70
70
  },
71
- "gitHead": "9c992e3bda91a7d2b587392a1db5cff47a2ca23a"
71
+ "gitHead": "f705ab1099e0df6220c8f1d9a44e5b6cd09eb224"
72
72
  }