@olane/o-node 0.7.53 → 0.7.55

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 (25) hide show
  1. package/dist/src/connection/interfaces/o-node-connection.config.d.ts +2 -1
  2. package/dist/src/connection/interfaces/o-node-connection.config.d.ts.map +1 -1
  3. package/dist/src/connection/interfaces/stream-init-message.d.ts +39 -4
  4. package/dist/src/connection/interfaces/stream-init-message.d.ts.map +1 -1
  5. package/dist/src/connection/interfaces/stream-init-message.js +11 -1
  6. package/dist/src/connection/o-node-connection.d.ts +49 -3
  7. package/dist/src/connection/o-node-connection.d.ts.map +1 -1
  8. package/dist/src/connection/o-node-connection.js +120 -2
  9. package/dist/src/connection/o-node-connection.manager.d.ts +6 -55
  10. package/dist/src/connection/o-node-connection.manager.d.ts.map +1 -1
  11. package/dist/src/connection/o-node-connection.manager.js +47 -183
  12. package/dist/src/connection/o-node-stream.d.ts.map +1 -1
  13. package/dist/src/connection/o-node-stream.js +1 -0
  14. package/dist/src/connection/o-node-stream.manager.d.ts +34 -5
  15. package/dist/src/connection/o-node-stream.manager.d.ts.map +1 -1
  16. package/dist/src/connection/o-node-stream.manager.js +190 -20
  17. package/dist/src/connection/stream-manager.events.d.ts +13 -1
  18. package/dist/src/connection/stream-manager.events.d.ts.map +1 -1
  19. package/dist/src/connection/stream-manager.events.js +2 -0
  20. package/dist/src/o-node.tool.d.ts.map +1 -1
  21. package/dist/src/o-node.tool.js +14 -19
  22. package/dist/src/utils/connection.utils.d.ts +3 -3
  23. package/dist/src/utils/connection.utils.d.ts.map +1 -1
  24. package/dist/src/utils/connection.utils.js +46 -19
  25. package/package.json +7 -7
@@ -1,8 +1,9 @@
1
- import { Connection } from '@olane/o-config';
1
+ import { Connection, Libp2p } from '@olane/o-config';
2
2
  import { oConnectionConfig } from '@olane/o-core';
3
3
  import type { StreamReusePolicy } from '../stream-handler.config.js';
4
4
  export interface oNodeConnectionConfig extends oConnectionConfig {
5
5
  p2pConnection: Connection;
6
+ p2pNode?: Libp2p;
6
7
  runOnLimitedConnection?: boolean;
7
8
  reusePolicy?: StreamReusePolicy;
8
9
  }
@@ -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;AAClD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAErE,MAAM,WAAW,qBAAsB,SAAQ,iBAAiB;IAC9D,aAAa,EAAE,UAAU,CAAC;IAC1B,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,WAAW,CAAC,EAAE,iBAAiB,CAAC;CACjC"}
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,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAErE,MAAM,WAAW,qBAAsB,SAAQ,iBAAiB;IAC9D,aAAa,EAAE,UAAU,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,WAAW,CAAC,EAAE,iBAAiB,CAAC;CACjC"}
@@ -1,6 +1,6 @@
1
1
  /**
2
- * Message sent by limited connection clients to identify their dedicated reader stream
3
- * This allows the receiver to identify which stream to use for sending requests back to the caller
2
+ * Message sent by limited connection clients to identify their dedicated persistent streams
3
+ * This allows the receiver to identify which streams to use for bidirectional communication
4
4
  */
5
5
  export interface StreamInitMessage {
6
6
  /**
@@ -9,10 +9,11 @@ export interface StreamInitMessage {
9
9
  type: 'stream-init';
10
10
  /**
11
11
  * Role of this stream
12
- * - 'reader': Dedicated reader stream for receiving requests
12
+ * - 'reader': Dedicated reader stream for receiving requests from receiver
13
+ * - 'writer': Dedicated writer stream for sending responses back to receiver
13
14
  * - 'standard': Standard request-response stream
14
15
  */
15
- role: 'reader' | 'standard';
16
+ role: 'reader' | 'writer' | 'standard';
16
17
  /**
17
18
  * Timestamp when the stream was created
18
19
  */
@@ -26,4 +27,38 @@ export interface StreamInitMessage {
26
27
  * Type guard to check if a message is a StreamInitMessage
27
28
  */
28
29
  export declare function isStreamInitMessage(message: any): message is StreamInitMessage;
30
+ /**
31
+ * Acknowledgment message sent by receiver in response to stream-init
32
+ * This confirms that the receiver has processed and registered the stream
33
+ */
34
+ export interface StreamInitAckMessage {
35
+ /**
36
+ * Message type identifier
37
+ */
38
+ type: 'stream-init-ack';
39
+ /**
40
+ * Status of the initialization
41
+ */
42
+ status: 'success' | 'error';
43
+ /**
44
+ * The stream ID that was registered
45
+ */
46
+ streamId: string;
47
+ /**
48
+ * The role that was registered
49
+ */
50
+ role: 'reader' | 'writer' | 'standard';
51
+ /**
52
+ * Optional error message if status is 'error'
53
+ */
54
+ error?: string;
55
+ /**
56
+ * Timestamp when the ack was sent
57
+ */
58
+ timestamp: number;
59
+ }
60
+ /**
61
+ * Type guard to check if a message is a StreamInitAckMessage
62
+ */
63
+ export declare function isStreamInitAckMessage(message: any): message is StreamInitAckMessage;
29
64
  //# sourceMappingURL=stream-init-message.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"stream-init-message.d.ts","sourceRoot":"","sources":["../../../../src/connection/interfaces/stream-init-message.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,IAAI,EAAE,aAAa,CAAC;IAEpB;;;;OAIG;IACH,IAAI,EAAE,QAAQ,GAAG,UAAU,CAAC;IAE5B;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO,IAAI,iBAAiB,CAM9E"}
1
+ {"version":3,"file":"stream-init-message.d.ts","sourceRoot":"","sources":["../../../../src/connection/interfaces/stream-init-message.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,IAAI,EAAE,aAAa,CAAC;IAEpB;;;;;OAKG;IACH,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,UAAU,CAAC;IAEvC;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO,IAAI,iBAAiB,CAM9E;AAED;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC;;OAEG;IACH,IAAI,EAAE,iBAAiB,CAAC;IAExB;;OAEG;IACH,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC;IAE5B;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,UAAU,CAAC;IAEvC;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,GAAG,GACX,OAAO,IAAI,oBAAoB,CAQjC"}
@@ -3,6 +3,16 @@
3
3
  */
4
4
  export function isStreamInitMessage(message) {
5
5
  return (message?.type === 'stream-init' &&
6
- (message.role === 'reader' || message.role === 'standard') &&
6
+ (message.role === 'reader' || message.role === 'writer' || message.role === 'standard') &&
7
+ typeof message.timestamp === 'number');
8
+ }
9
+ /**
10
+ * Type guard to check if a message is a StreamInitAckMessage
11
+ */
12
+ export function isStreamInitAckMessage(message) {
13
+ return (message?.type === 'stream-init-ack' &&
14
+ (message.status === 'success' || message.status === 'error') &&
15
+ typeof message.streamId === 'string' &&
16
+ (message.role === 'reader' || message.role === 'writer' || message.role === 'standard') &&
7
17
  typeof message.timestamp === 'number');
8
18
  }
@@ -1,27 +1,73 @@
1
- import { Connection } from '@olane/o-config';
2
- import { oConnection, oRequest, oResponse } from '@olane/o-core';
1
+ import { Connection, Libp2p, Multiaddr } from '@olane/o-config';
2
+ import { oAddress, oConnection, oRequest, oResponse } from '@olane/o-core';
3
3
  import { oNodeConnectionConfig } from './interfaces/o-node-connection.config.js';
4
4
  import type { StreamReusePolicy } from './stream-handler.config.js';
5
5
  import { oNodeAddress } from '../router/o-node.address.js';
6
6
  import { oNodeStream } from './o-node-stream.js';
7
7
  import { oNodeStreamManager } from './o-node-stream.manager.js';
8
+ interface CachedIdentifyData {
9
+ protocols: string[];
10
+ agentVersion?: string;
11
+ protocolVersion?: string;
12
+ listenAddrs: Multiaddr[];
13
+ observedAddr?: Multiaddr;
14
+ timestamp: number;
15
+ }
8
16
  export declare class oNodeConnection extends oConnection {
9
17
  protected readonly config: oNodeConnectionConfig;
10
18
  p2pConnection: Connection;
11
19
  protected reusePolicy: StreamReusePolicy;
12
20
  streamManager: oNodeStreamManager;
21
+ protected p2pNode?: Libp2p;
22
+ protected identifyData?: CachedIdentifyData;
23
+ protected identifyListener?: (evt: any) => void;
13
24
  constructor(config: oNodeConnectionConfig);
14
25
  get remotePeerId(): import("@olane/o-config").PeerId;
15
- get remoteAddr(): import("@olane/o-config").Multiaddr;
26
+ get remoteAddr(): Multiaddr;
16
27
  /**
17
28
  * Get the connection configuration for compatibility checking.
18
29
  */
19
30
  get connectionConfig(): oNodeConnectionConfig;
20
31
  supportsAddress(address: oNodeAddress): boolean;
21
32
  get streams(): oNodeStream[];
33
+ /**
34
+ * Get cached identify data for the remote peer.
35
+ * Returns undefined if identify event hasn't been received yet.
36
+ */
37
+ get cachedIdentifyData(): CachedIdentifyData | undefined;
38
+ /**
39
+ * Get protocols supported by the remote peer from cached identify data.
40
+ * Returns empty array if identify data not available yet.
41
+ */
42
+ get remoteProtocols(): string[];
43
+ /**
44
+ * Get agent version of the remote peer from cached identify data.
45
+ */
46
+ get remoteAgentVersion(): string | undefined;
47
+ /**
48
+ * Get protocol version of the remote peer from cached identify data.
49
+ */
50
+ get remoteProtocolVersion(): string | undefined;
51
+ /**
52
+ * Get listen addresses advertised by the remote peer.
53
+ * Returns empty array if identify data not available yet.
54
+ */
55
+ get remoteListenAddrs(): Multiaddr[];
56
+ /**
57
+ * Get our observed address as seen by the remote peer.
58
+ */
59
+ get observedAddress(): Multiaddr | undefined;
60
+ get address(): oAddress;
61
+ get nextHopAddress(): oAddress;
62
+ get callerAddress(): oAddress | undefined;
22
63
  transmit(request: oRequest): Promise<oResponse>;
23
64
  postTransmit(stream: oNodeStream): Promise<void>;
65
+ /**
66
+ * Set up persistent listener for identify events from the remote peer
67
+ */
68
+ protected setupIdentifyListener(): void;
24
69
  abort(error: Error): Promise<void>;
25
70
  close(): Promise<void>;
26
71
  }
72
+ export {};
27
73
  //# sourceMappingURL=o-node-connection.d.ts.map
@@ -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,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,KAAK,EAEV,iBAAiB,EAClB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAEhE,qBAAa,eAAgB,SAAQ,WAAW;IAKlC,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,qBAAqB;IAJrD,aAAa,EAAE,UAAU,CAAC;IACjC,SAAS,CAAC,WAAW,EAAE,iBAAiB,CAAC;IAClC,aAAa,EAAE,kBAAkB,CAAC;gBAEV,MAAM,EAAE,qBAAqB;IAW5D,IAAI,YAAY,qCAEf;IAED,IAAI,UAAU,wCAEb;IAED;;OAEG;IACH,IAAI,gBAAgB,IAAI,qBAAqB,CAE5C;IAED,eAAe,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO;IAM/C,IAAI,OAAO,IAAI,WAAW,EAAE,CAE3B;IAEK,QAAQ,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC;IA2D/C,YAAY,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAKhD,KAAK,CAAC,KAAK,EAAE,KAAK;IAMlB,KAAK;CASZ"}
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,SAAS,EAAU,MAAM,iBAAiB,CAAC;AACxE,OAAO,EAEL,QAAQ,EACR,WAAW,EAGX,QAAQ,EACR,SAAS,EACV,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,qBAAqB,EAAE,MAAM,0CAA0C,CAAC;AACjF,OAAO,KAAK,EAEV,iBAAiB,EAClB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAEhE,UAAU,kBAAkB;IAC1B,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,SAAS,EAAE,CAAC;IACzB,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,eAAgB,SAAQ,WAAW;IAQlC,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,qBAAqB;IAPrD,aAAa,EAAE,UAAU,CAAC;IACjC,SAAS,CAAC,WAAW,EAAE,iBAAiB,CAAC;IAClC,aAAa,EAAE,kBAAkB,CAAC;IACzC,SAAS,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC3B,SAAS,CAAC,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAC5C,SAAS,CAAC,gBAAgB,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAC;gBAEjB,MAAM,EAAE,qBAAqB;IAe5D,IAAI,YAAY,qCAEf;IAED,IAAI,UAAU,cAEb;IAED;;OAEG;IACH,IAAI,gBAAgB,IAAI,qBAAqB,CAE5C;IAED,eAAe,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO;IAM/C,IAAI,OAAO,IAAI,WAAW,EAAE,CAE3B;IAED;;;OAGG;IACH,IAAI,kBAAkB,IAAI,kBAAkB,GAAG,SAAS,CAEvD;IAED;;;OAGG;IACH,IAAI,eAAe,IAAI,MAAM,EAAE,CAE9B;IAED;;OAEG;IACH,IAAI,kBAAkB,IAAI,MAAM,GAAG,SAAS,CAE3C;IAED;;OAEG;IACH,IAAI,qBAAqB,IAAI,MAAM,GAAG,SAAS,CAE9C;IAED;;;OAGG;IACH,IAAI,iBAAiB,IAAI,SAAS,EAAE,CAEnC;IAED;;OAEG;IACH,IAAI,eAAe,IAAI,SAAS,GAAG,SAAS,CAE3C;IAED,IAAI,OAAO,IAAI,QAAQ,CActB;IAED,IAAI,cAAc,IAAI,QAAQ,CAK7B;IAED,IAAI,aAAa,IAAI,QAAQ,GAAG,SAAS,CAMxC;IAEK,QAAQ,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC;IAkF/C,YAAY,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAKtD;;OAEG;IACH,SAAS,CAAC,qBAAqB,IAAI,IAAI;IAsCjC,KAAK,CAAC,KAAK,EAAE,KAAK;IAMlB,KAAK;CAcZ"}
@@ -1,4 +1,5 @@
1
1
  import { oConnection, oError, oErrorCodes, } from '@olane/o-core';
2
+ import { oNodeAddress } from '../router/o-node.address.js';
2
3
  import { oNodeStreamManager } from './o-node-stream.manager.js';
3
4
  export class oNodeConnection extends oConnection {
4
5
  constructor(config) {
@@ -6,10 +7,13 @@ export class oNodeConnection extends oConnection {
6
7
  this.config = config;
7
8
  this.p2pConnection = config.p2pConnection;
8
9
  this.reusePolicy = config.reusePolicy ?? 'none';
10
+ this.p2pNode = config.p2pNode;
9
11
  // Initialize oNodeStreamManager (stream lifecycle and protocol management)
10
12
  this.streamManager = new oNodeStreamManager({
11
13
  p2pConnection: this.p2pConnection,
12
14
  });
15
+ // Set up persistent identify event listener
16
+ this.setupIdentifyListener();
13
17
  }
14
18
  get remotePeerId() {
15
19
  return this.p2pConnection.remotePeer;
@@ -31,11 +35,74 @@ export class oNodeConnection extends oConnection {
31
35
  get streams() {
32
36
  return this.streamManager.getAllStreams();
33
37
  }
38
+ /**
39
+ * Get cached identify data for the remote peer.
40
+ * Returns undefined if identify event hasn't been received yet.
41
+ */
42
+ get cachedIdentifyData() {
43
+ return this.identifyData;
44
+ }
45
+ /**
46
+ * Get protocols supported by the remote peer from cached identify data.
47
+ * Returns empty array if identify data not available yet.
48
+ */
49
+ get remoteProtocols() {
50
+ return this.identifyData?.protocols || [];
51
+ }
52
+ /**
53
+ * Get agent version of the remote peer from cached identify data.
54
+ */
55
+ get remoteAgentVersion() {
56
+ return this.identifyData?.agentVersion;
57
+ }
58
+ /**
59
+ * Get protocol version of the remote peer from cached identify data.
60
+ */
61
+ get remoteProtocolVersion() {
62
+ return this.identifyData?.protocolVersion;
63
+ }
64
+ /**
65
+ * Get listen addresses advertised by the remote peer.
66
+ * Returns empty array if identify data not available yet.
67
+ */
68
+ get remoteListenAddrs() {
69
+ return this.identifyData?.listenAddrs || [];
70
+ }
71
+ /**
72
+ * Get our observed address as seen by the remote peer.
73
+ */
74
+ get observedAddress() {
75
+ return this.identifyData?.observedAddr;
76
+ }
77
+ get address() {
78
+ if (this.identifyData?.protocols &&
79
+ this.identifyData.protocols.length > 0) {
80
+ const filtered = this.identifyData.protocols.filter((p) => p.startsWith('/o/'));
81
+ if (filtered.length > 0) {
82
+ const remoteAddress = oNodeAddress.fromProtocol(filtered[0]);
83
+ return remoteAddress;
84
+ }
85
+ }
86
+ return this.config.address;
87
+ }
88
+ get nextHopAddress() {
89
+ if (this.config.nextHopAddress.value === 'o://unknown') {
90
+ return this.address;
91
+ }
92
+ return this.config.nextHopAddress;
93
+ }
94
+ get callerAddress() {
95
+ if (this.p2pConnection.direction === 'inbound') {
96
+ return this.address;
97
+ }
98
+ return this.config.callerAddress;
99
+ }
34
100
  async transmit(request) {
35
101
  try {
36
102
  // Build protocol string
37
103
  const protocol = this.nextHopAddress.protocol +
38
104
  (this.reusePolicy === 'reuse' ? '/reuse' : '');
105
+ this.logger.debug('Transmitting request on limited connection?', this.config.runOnLimitedConnection);
39
106
  const streamConfig = {
40
107
  signal: this.abortSignal,
41
108
  drainTimeoutMs: this.config.drainTimeoutMs,
@@ -43,7 +110,7 @@ export class oNodeConnection extends oConnection {
43
110
  maxOutboundStreams: process.env.MAX_OUTBOUND_STREAMS
44
111
  ? parseInt(process.env.MAX_OUTBOUND_STREAMS)
45
112
  : 1000,
46
- runOnLimitedConnection: this.config.runOnLimitedConnection ?? true,
113
+ runOnLimitedConnection: this.config.runOnLimitedConnection ?? false,
47
114
  };
48
115
  // Get stream from StreamManager
49
116
  const wrappedStream = await this.streamManager.getOrCreateStream(protocol, this.nextHopAddress, streamConfig);
@@ -53,9 +120,27 @@ export class oNodeConnection extends oConnection {
53
120
  // Send the request with backpressure handling
54
121
  const data = new TextEncoder().encode(request.toString());
55
122
  await this.streamManager.sendLengthPrefixed(stream, data, streamConfig);
123
+ // Determine which stream to wait for response on
124
+ // If _streamId is specified, use that stream (for limited connections with persistent writer stream)
125
+ let responseStream = stream;
126
+ if (request.params._streamId) {
127
+ const specifiedStream = this.streamManager.getStreamById(request.params._streamId);
128
+ if (specifiedStream) {
129
+ responseStream = specifiedStream;
130
+ this.logger.debug('Using specified stream for response', {
131
+ requestStreamId: stream.id,
132
+ responseStreamId: specifiedStream.id,
133
+ });
134
+ }
135
+ else {
136
+ this.logger.warn('Specified response stream not found, using request stream', {
137
+ streamId: request.params._streamId,
138
+ });
139
+ }
140
+ }
56
141
  // Handle response using StreamManager
57
142
  // Pass request ID to enable proper response correlation on shared streams
58
- const response = await this.streamManager.handleOutgoingStream(stream, this.emitter, streamConfig, request.id);
143
+ const response = await this.streamManager.handleOutgoingStream(responseStream, this.emitter, streamConfig, request.id);
59
144
  // Handle cleanup of the stream
60
145
  await this.postTransmit(wrappedStream);
61
146
  return response;
@@ -71,6 +156,35 @@ export class oNodeConnection extends oConnection {
71
156
  // Always cleanup streams (no reuse at base layer)
72
157
  await this.streamManager.releaseStream(stream.p2pStream.id);
73
158
  }
159
+ /**
160
+ * Set up persistent listener for identify events from the remote peer
161
+ */
162
+ setupIdentifyListener() {
163
+ if (!this.p2pNode) {
164
+ return;
165
+ }
166
+ this.identifyListener = (evt) => {
167
+ const { peerId, protocols, agentVersion, protocolVersion, listenAddrs, observedAddr, } = evt.detail;
168
+ // Only cache if this event is for our remote peer
169
+ if (peerId?.toString() === this.remotePeerId.toString()) {
170
+ this.identifyData = {
171
+ protocols: protocols || [],
172
+ agentVersion,
173
+ protocolVersion,
174
+ listenAddrs: listenAddrs || [],
175
+ observedAddr,
176
+ timestamp: Date.now(),
177
+ };
178
+ this.logger.debug('Cached identify data for peer', {
179
+ peerId: peerId.toString(),
180
+ protocols: this.identifyData.protocols,
181
+ agentVersion: this.identifyData.agentVersion,
182
+ });
183
+ }
184
+ };
185
+ this.p2pNode.addEventListener('peer:identify', this.identifyListener);
186
+ this.logger.debug('Identify listener set up for connection');
187
+ }
74
188
  async abort(error) {
75
189
  this.logger.debug('Aborting connection');
76
190
  await this.p2pConnection.abort(error);
@@ -78,6 +192,10 @@ export class oNodeConnection extends oConnection {
78
192
  }
79
193
  async close() {
80
194
  this.logger.debug('Closing connection');
195
+ // Remove identify listener
196
+ if (this.p2pNode && this.identifyListener) {
197
+ this.p2pNode.removeEventListener('peer:identify', this.identifyListener);
198
+ }
81
199
  // Close stream manager (handles all stream cleanup)
82
200
  await this.streamManager.close();
83
201
  await this.p2pConnection.close();
@@ -2,53 +2,34 @@ import { oAddress, oConnectionConfig, oConnectionManager } from '@olane/o-core';
2
2
  import { Libp2p, Connection } from '@olane/o-config';
3
3
  import { oNodeConnectionManagerConfig } from './interfaces/o-node-connection-manager.config.js';
4
4
  import { oNodeConnection } from './o-node-connection.js';
5
+ /**
6
+ * Manages oNodeConnection instances, reusing connections when possible.
7
+ */
5
8
  export declare class oNodeConnectionManager extends oConnectionManager {
6
9
  readonly config: oNodeConnectionManagerConfig;
7
10
  protected p2pNode: Libp2p;
8
11
  protected defaultReadTimeoutMs?: number;
9
12
  protected defaultDrainTimeoutMs?: number;
10
13
  /** Single cache of oNodeConnection instances keyed by address */
11
- protected cachedConnections: Map<string, oNodeConnection[]>;
14
+ protected cachedConnections: Map<string, oNodeConnection>;
12
15
  protected pendingDialsByAddress: Map<string, Promise<Connection>>;
13
16
  constructor(config: oNodeConnectionManagerConfig);
14
17
  /**
15
18
  * Set up listeners to maintain connection cache state
16
19
  */
17
20
  protected setupConnectionListeners(): void;
18
- /**
19
- * Build a stable cache key from an address.
20
- *
21
- * We key the cache by address value (e.g., "o://my-tool") to maintain
22
- * a simple one-to-one mapping between addresses and connections.
23
- */
24
- protected getAddressKey(address: oAddress): string | null;
25
21
  /**
26
22
  * Extract peer ID string from an address
27
23
  * @param address - The address to extract peer ID from
28
24
  * @returns The peer ID string or null if not found
29
25
  */
30
26
  protected getPeerIdFromAddress(address: oAddress): string | null;
31
- /**
32
- * Get the first valid (open) connection for the given address key.
33
- * Cleans up stale connections from the cache automatically.
34
- *
35
- * @param addressKey - The address key to look up
36
- * @returns A valid oNodeConnection or null if none found
37
- */
38
- protected getValidConnection(addressKey: string): oNodeConnection | null;
39
27
  /**
40
28
  * Cache an oNodeConnection by its address key.
41
29
  * @param conn - The oNodeConnection to cache
42
30
  * @param addressKey - The address key to cache under
43
31
  */
44
- protected cacheConnection(conn: oNodeConnection, addressKey: string): void;
45
- /**
46
- * Get oNodeConnection by libp2p Connection reference
47
- * Used to find the correct oNodeConnection for incoming streams
48
- * @param p2pConnection - The libp2p connection to search for
49
- * @returns The oNodeConnection or undefined if not found
50
- */
51
- getConnectionByP2pConnection(p2pConnection: Connection): oNodeConnection | undefined;
32
+ protected cacheConnection(conn: oNodeConnection): void;
52
33
  /**
53
34
  * Get or create a raw p2p connection to the given address.
54
35
  * Subclasses can override connect() and use this method to get the underlying p2p connection.
@@ -59,42 +40,12 @@ export declare class oNodeConnectionManager extends oConnectionManager {
59
40
  p2pConnection: Connection;
60
41
  reuse?: boolean;
61
42
  }): Promise<oNodeConnection>;
43
+ getConnectionFromAddress(address: oAddress): oNodeConnection | null;
62
44
  /**
63
45
  * Connect to a given address, reusing oNodeConnection when possible
64
46
  * @param config - Connection configuration
65
47
  * @returns The connection object
66
48
  */
67
49
  connect(config: oConnectionConfig): Promise<oNodeConnection>;
68
- /**
69
- * Check if we have an active connection to the target peer
70
- * @param address - The address to check
71
- * @returns true if an active connection exists
72
- */
73
- isCached(address: oAddress): boolean;
74
- /**
75
- * Get an existing cached oNodeConnection for the target address
76
- * @param address - The address to get a connection for
77
- * @returns The oNodeConnection or null if not found
78
- */
79
- getCachedConnection(address: oAddress): oNodeConnection | null;
80
- /**
81
- * Get cache statistics for monitoring and debugging
82
- * @returns Object containing cache statistics
83
- */
84
- getCacheStats(): {
85
- cachedAddresses: number;
86
- totalCachedConnections: number;
87
- pendingDials: number;
88
- connectionsByPeer: Array<{
89
- peerId: string;
90
- status: string;
91
- addressKey: string;
92
- }>;
93
- };
94
- /**
95
- * Clean up all stale (non-open) connections from cache
96
- * @returns Number of connections removed
97
- */
98
- cleanupStaleConnections(): number;
99
50
  }
100
51
  //# sourceMappingURL=o-node-connection.manager.d.ts.map
@@ -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,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,4BAA4B,EAAE,MAAM,kDAAkD,CAAC;AAEhG,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD,qBAAa,sBAAuB,SAAQ,kBAAkB;IAQhD,QAAQ,CAAC,MAAM,EAAE,4BAA4B;IAPzD,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IACxC,SAAS,CAAC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IACzC,iEAAiE;IACjE,SAAS,CAAC,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,EAAE,CAAC,CAAa;IACxE,SAAS,CAAC,qBAAqB,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC,CAAa;gBAEzD,MAAM,EAAE,4BAA4B;IAWzD;;OAEG;IACH,SAAS,CAAC,wBAAwB,IAAI,IAAI;IA+B1C;;;;;OAKG;IACH,SAAS,CAAC,aAAa,CAAC,OAAO,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI;IASzD;;;;OAIG;IACH,SAAS,CAAC,oBAAoB,CAAC,OAAO,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI;IAahE;;;;;;OAMG;IACH,SAAS,CAAC,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI;IAkBxE;;;;OAIG;IACH,SAAS,CAAC,eAAe,CAAC,IAAI,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IAY1E;;;;;OAKG;IACH,4BAA4B,CAC1B,aAAa,EAAE,UAAU,GACxB,eAAe,GAAG,SAAS;IAa9B;;;OAGG;cACa,wBAAwB,CACtC,cAAc,EAAE,QAAQ,EACxB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,UAAU,CAAC;cAoCN,WAAW,CACzB,cAAc,EAAE,QAAQ,EACxB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,UAAU,CAAC;IAqBhB,MAAM,CACV,MAAM,EAAE,iBAAiB,GAAG;QAAE,aAAa,EAAE,UAAU,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GACzE,OAAO,CAAC,eAAe,CAAC;IA4D3B;;;;OAIG;IACG,OAAO,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,eAAe,CAAC;IAwDlE;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO;IAcpC;;;;OAIG;IACH,mBAAmB,CAAC,OAAO,EAAE,QAAQ,GAAG,eAAe,GAAG,IAAI;IAc9D;;;OAGG;IACH,aAAa,IAAI;QACf,eAAe,EAAE,MAAM,CAAC;QACxB,sBAAsB,EAAE,MAAM,CAAC;QAC/B,YAAY,EAAE,MAAM,CAAC;QACrB,iBAAiB,EAAE,KAAK,CAAC;YACvB,MAAM,EAAE,MAAM,CAAC;YACf,MAAM,EAAE,MAAM,CAAC;YACf,UAAU,EAAE,MAAM,CAAC;SACpB,CAAC,CAAC;KACJ;IAyBD;;;OAGG;IACH,uBAAuB,IAAI,MAAM;CAuBlC"}
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,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,4BAA4B,EAAE,MAAM,kDAAkD,CAAC;AAEhG,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD;;GAEG;AACH,qBAAa,sBAAuB,SAAQ,kBAAkB;IAQhD,QAAQ,CAAC,MAAM,EAAE,4BAA4B;IAPzD,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IACxC,SAAS,CAAC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IACzC,iEAAiE;IACjE,SAAS,CAAC,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAa;IACtE,SAAS,CAAC,qBAAqB,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC,CAAa;gBAEzD,MAAM,EAAE,4BAA4B;IAWzD;;OAEG;IACH,SAAS,CAAC,wBAAwB,IAAI,IAAI;IAY1C;;;;OAIG;IACH,SAAS,CAAC,oBAAoB,CAAC,OAAO,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI;IAahE;;;;OAIG;IACH,SAAS,CAAC,eAAe,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI;IAWtD;;;OAGG;cACa,wBAAwB,CACtC,cAAc,EAAE,QAAQ,EACxB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,UAAU,CAAC;cAoBN,WAAW,CACzB,cAAc,EAAE,QAAQ,EACxB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,UAAU,CAAC;IAqBhB,MAAM,CACV,MAAM,EAAE,iBAAiB,GAAG;QAAE,aAAa,EAAE,UAAU,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GACzE,OAAO,CAAC,eAAe,CAAC;IAgD3B,wBAAwB,CAAC,OAAO,EAAE,QAAQ,GAAG,eAAe,GAAG,IAAI;IAkBnE;;;;OAIG;IACG,OAAO,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,eAAe,CAAC;CAqDnE"}