@olane/o-node 0.7.54 → 0.7.56

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 (60) hide show
  1. package/dist/src/connection/enums/o-node-message-event.d.ts +14 -0
  2. package/dist/src/connection/enums/o-node-message-event.d.ts.map +1 -0
  3. package/dist/src/connection/enums/o-node-message-event.js +5 -0
  4. package/dist/src/connection/index.d.ts +0 -3
  5. package/dist/src/connection/index.d.ts.map +1 -1
  6. package/dist/src/connection/index.js +0 -3
  7. package/dist/src/connection/interfaces/abort-signal.config.d.ts +5 -0
  8. package/dist/src/connection/interfaces/abort-signal.config.d.ts.map +1 -0
  9. package/dist/src/connection/interfaces/o-node-connection-manager.config.d.ts +13 -1
  10. package/dist/src/connection/interfaces/o-node-connection-manager.config.d.ts.map +1 -1
  11. package/dist/src/connection/interfaces/o-node-connection.config.d.ts +17 -3
  12. package/dist/src/connection/interfaces/o-node-connection.config.d.ts.map +1 -1
  13. package/dist/src/connection/interfaces/o-node-stream.config.d.ts +3 -11
  14. package/dist/src/connection/interfaces/o-node-stream.config.d.ts.map +1 -1
  15. package/dist/src/connection/o-node-connection.d.ts +33 -11
  16. package/dist/src/connection/o-node-connection.d.ts.map +1 -1
  17. package/dist/src/connection/o-node-connection.js +113 -58
  18. package/dist/src/connection/o-node-connection.manager.d.ts +17 -62
  19. package/dist/src/connection/o-node-connection.manager.d.ts.map +1 -1
  20. package/dist/src/connection/o-node-connection.manager.js +65 -189
  21. package/dist/src/connection/o-node-stream.d.ts +48 -15
  22. package/dist/src/connection/o-node-stream.d.ts.map +1 -1
  23. package/dist/src/connection/o-node-stream.js +144 -31
  24. package/dist/src/connection/stream-handler.config.d.ts +0 -11
  25. package/dist/src/connection/stream-handler.config.d.ts.map +1 -1
  26. package/dist/src/connection/stream-manager.events.d.ts +7 -0
  27. package/dist/src/connection/stream-manager.events.d.ts.map +1 -1
  28. package/dist/src/connection/stream-manager.events.js +1 -0
  29. package/dist/src/lib/interfaces/o-node-request-manager.config.d.ts +9 -0
  30. package/dist/src/lib/interfaces/o-node-request-manager.config.d.ts.map +1 -0
  31. package/dist/src/lib/interfaces/o-node-request-manager.config.js +1 -0
  32. package/dist/src/lib/o-node-request-manager.d.ts +46 -0
  33. package/dist/src/lib/o-node-request-manager.d.ts.map +1 -0
  34. package/dist/src/lib/o-node-request-manager.js +173 -0
  35. package/dist/src/managers/o-reconnection.manager.d.ts.map +1 -1
  36. package/dist/src/managers/o-reconnection.manager.js +4 -0
  37. package/dist/src/managers/o-registration.manager.d.ts.map +1 -1
  38. package/dist/src/managers/o-registration.manager.js +9 -4
  39. package/dist/src/o-node.d.ts +6 -7
  40. package/dist/src/o-node.d.ts.map +1 -1
  41. package/dist/src/o-node.js +22 -37
  42. package/dist/src/o-node.tool.d.ts +3 -3
  43. package/dist/src/o-node.tool.d.ts.map +1 -1
  44. package/dist/src/o-node.tool.js +31 -65
  45. package/dist/src/router/o-node.router.d.ts.map +1 -1
  46. package/dist/src/router/o-node.router.js +4 -2
  47. package/dist/src/utils/connection.utils.d.ts +3 -3
  48. package/dist/src/utils/connection.utils.d.ts.map +1 -1
  49. package/dist/src/utils/connection.utils.js +46 -19
  50. package/dist/test/connection-management.spec.js +3 -0
  51. package/package.json +7 -7
  52. package/dist/src/connection/interfaces/stream-init-message.d.ts +0 -64
  53. package/dist/src/connection/interfaces/stream-init-message.d.ts.map +0 -1
  54. package/dist/src/connection/interfaces/stream-init-message.js +0 -18
  55. package/dist/src/connection/interfaces/stream-manager.config.d.ts +0 -8
  56. package/dist/src/connection/interfaces/stream-manager.config.d.ts.map +0 -1
  57. package/dist/src/connection/o-node-stream.manager.d.ts +0 -200
  58. package/dist/src/connection/o-node-stream.manager.d.ts.map +0 -1
  59. package/dist/src/connection/o-node-stream.manager.js +0 -633
  60. /package/dist/src/connection/interfaces/{stream-manager.config.js → abort-signal.config.js} +0 -0
@@ -3,35 +3,40 @@ import { oTool } from '@olane/o-tool';
3
3
  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
- import { ConnectionUtils } from './utils/connection.utils.js';
7
- import { StreamManagerEvent } from './connection/stream-manager.events.js';
8
6
  /**
9
7
  * oTool is a mixin that extends the base class and implements the oTool interface
10
8
  * @param Base - The base class to extend
11
9
  * @returns A new class that extends the base class and implements the oTool interface
12
10
  */
13
11
  export class oNodeTool extends oTool(oServerNode) {
14
- async handleProtocolReuse(address) {
15
- const reuseProtocol = address.protocol + '/reuse';
16
- this.logger.debug('Handling protocol reuse: ' + reuseProtocol);
17
- const protocols = this.p2pNode.getProtocols();
18
- if (protocols.find((p) => p === reuseProtocol)) {
19
- // already handling
20
- return;
21
- }
22
- const maxOutboundsStreams = process.env.MAX_OUTBOUND_STREAMS
23
- ? parseInt(process.env.MAX_OUTBOUND_STREAMS)
24
- : 1000;
25
- await this.p2pNode.handle(reuseProtocol, this.handleStreamReuse.bind(this), {
26
- maxInboundStreams: 10000,
27
- maxOutboundStreams: maxOutboundsStreams,
28
- runOnLimitedConnection: true, // reuse is always on limited connections
29
- });
30
- this.logger.debug('Handled protocol reuse: ' + reuseProtocol);
31
- }
12
+ // async handleProtocolReuse(address: oAddress) {
13
+ // const reuseProtocol = address.protocol + '/reuse';
14
+ // this.logger.debug('Handling protocol reuse: ' + reuseProtocol);
15
+ // const protocols = this.p2pNode.getProtocols();
16
+ // if (protocols.find((p) => p === reuseProtocol)) {
17
+ // // already handling
18
+ // return;
19
+ // }
20
+ // const maxOutboundsStreams = process.env.MAX_OUTBOUND_STREAMS
21
+ // ? parseInt(process.env.MAX_OUTBOUND_STREAMS)
22
+ // : 1000;
23
+ // await this.p2pNode.handle(
24
+ // reuseProtocol,
25
+ // this.handleStreamReuse.bind(this),
26
+ // {
27
+ // maxInboundStreams: 10_000,
28
+ // maxOutboundStreams: maxOutboundsStreams,
29
+ // runOnLimitedConnection: true, // reuse is always on limited connections
30
+ // },
31
+ // );
32
+ // this.logger.debug('Handled protocol reuse: ' + reuseProtocol);
33
+ // }
32
34
  async handleProtocol(address) {
35
+ if (!address || !address.protocol) {
36
+ throw new Error('Invalid address passed: ' + address);
37
+ }
33
38
  const protocols = this.p2pNode.getProtocols();
34
- if (protocols.find((p) => p === address.protocol)) {
39
+ if (protocols.find((p) => p === address?.protocol)) {
35
40
  // already handling
36
41
  return;
37
42
  }
@@ -48,7 +53,7 @@ export class oNodeTool extends oTool(oServerNode) {
48
53
  maxOutboundStreams: maxOutboundsStreams,
49
54
  runOnLimitedConnection: this.config.runOnLimitedConnection,
50
55
  });
51
- await this.handleProtocolReuse(address);
56
+ // await this.handleProtocolReuse(address);
52
57
  }
53
58
  async initializeProtocols() {
54
59
  this.logger.info('Initializing custom protocols for node...');
@@ -62,50 +67,11 @@ export class oNodeTool extends oTool(oServerNode) {
62
67
  await super.initialize();
63
68
  await this.initializeProtocols();
64
69
  }
65
- async handleStreamReuse(stream, connection) {
66
- return this.handleStream(stream, connection, true);
67
- }
68
- async handleStream(stream, connection, reuse) {
69
- if (reuse) {
70
- this.logger.debug('Handle stream with reuse = true');
71
- // record inbound connection to manager
72
- }
73
- const remoteAddress = await ConnectionUtils.addressFromConnection({
74
- currentNode: this,
75
- connection: connection,
76
- });
77
- await this.connectionManager.answer({
78
- nextHopAddress: remoteAddress,
79
- address: remoteAddress,
80
- callerAddress: this.address,
81
- p2pConnection: connection,
82
- reuse,
83
- });
84
- // Get the oNodeConnection for this libp2p connection
85
- const oConnection = this.connectionManager.getConnectionByP2pConnection(connection);
86
- if (!oConnection) {
87
- this.logger.error('No oNodeConnection found for incoming stream', {
88
- remotePeer: connection.remotePeer.toString(),
89
- connectionId: connection.id,
90
- });
91
- return;
92
- }
93
- // Subscribe to InboundRequest events from the stream manager
94
- // This follows an event-driven pattern for handling incoming requests
95
- oConnection.streamManager.on(StreamManagerEvent.InboundRequest, async (data) => {
96
- try {
97
- const result = await this.execute(data.request, data.stream);
98
- // Return the raw result - StreamManager will build and send the response
99
- return result;
100
- }
101
- catch (error) {
102
- this.logger.error('Error executing tool: ', data.request.toString(), error, typeof error);
103
- throw error; // StreamManager will handle error response building
104
- }
70
+ async handleStream(stream, connection) {
71
+ return this.requestManager.receiveStream({
72
+ stream,
73
+ connection,
105
74
  });
106
- // Use the connection's StreamManager for consistent stream handling
107
- // This follows libp2p v3 best practices for length-prefixed streaming
108
- await oConnection.streamManager.handleIncomingStream(stream, connection);
109
75
  }
110
76
  async _tool_identify() {
111
77
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"o-node.router.d.ts","sourceRoot":"","sources":["../../../src/router/o-node.router.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAML,cAAc,EAGd,aAAa,EACd,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAM5C,qBAAa,WAAY,SAAQ,WAAW;IAC1C,OAAO,CAAC,aAAa,CAAqB;;IAO1C;;;;;;;;OAQG;cACa,OAAO,CACrB,OAAO,EAAE,YAAY,EACrB,OAAO,EAAE,cAAc,EACvB,IAAI,EAAE,KAAK,GACV,OAAO,CAAC,GAAG,CAAC;IA6Bf;;;OAGG;YACW,kBAAkB;IA8DhC;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAS5B;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAWhC;;OAEG;YACW,eAAe;IA4C7B;;;OAGG;IACG,SAAS,CAAC,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,KAAK,GAAG,OAAO,CAAC,aAAa,CAAC;IA+B3E;;;OAGG;IACH,UAAU,CAAC,qBAAqB,EAAE,YAAY,EAAE,IAAI,EAAE,KAAK,GAAG,OAAO;CAGtE"}
1
+ {"version":3,"file":"o-node.router.d.ts","sourceRoot":"","sources":["../../../src/router/o-node.router.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAML,cAAc,EAGd,aAAa,EACd,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAM5C,qBAAa,WAAY,SAAQ,WAAW;IAC1C,OAAO,CAAC,aAAa,CAAqB;;IAO1C;;;;;;;;OAQG;cACa,OAAO,CACrB,OAAO,EAAE,YAAY,EACrB,OAAO,EAAE,cAAc,EACvB,IAAI,EAAE,KAAK,GACV,OAAO,CAAC,GAAG,CAAC;IA6Bf;;;OAGG;YACW,kBAAkB;IA8DhC;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAS5B;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAWhC;;OAEG;YACW,eAAe;IA+C7B;;;OAGG;IACG,SAAS,CAAC,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,KAAK,GAAG,OAAO,CAAC,aAAa,CAAC;IA+B3E;;;OAGG;IACH,UAAU,CAAC,qBAAqB,EAAE,YAAY,EAAE,IAAI,EAAE,KAAK,GAAG,OAAO;CAGtE"}
@@ -122,7 +122,7 @@ export class oNodeRouter extends oToolRouter {
122
122
  request.params.payload?.params?._isStreaming;
123
123
  const nodeConnection = await node.connectionManager.connect({
124
124
  nextHopAddress: address,
125
- address: node.address,
125
+ targetAddress: node.address,
126
126
  callerAddress: node.address,
127
127
  isStream: isStream,
128
128
  });
@@ -136,7 +136,9 @@ export class oNodeRouter extends oToolRouter {
136
136
  });
137
137
  // allow this to continue as we will tell the transmitter to stream the response and we will intercept via the above listener
138
138
  }
139
- const response = await nodeConnection.transmit(request);
139
+ const stream = await nodeConnection.transmit(request, {});
140
+ const response = await stream.waitForResponse(String(request.id));
141
+ stream.close();
140
142
  return response.result.data;
141
143
  }
142
144
  catch (error) {
@@ -2,10 +2,10 @@ import { Connection } from '@olane/o-config';
2
2
  import { oObject } from '@olane/o-core';
3
3
  export declare class ConnectionUtils extends oObject {
4
4
  /**
5
- * Waits for a peer to appear in the peer store with sufficient protocol information.
6
- * Implements retry logic to handle race conditions where peer store is not immediately populated.
5
+ * Waits for a peer to be identified via the identify protocol.
6
+ * Uses event-driven approach listening to peer store protocol updates.
7
7
  */
8
- private static waitForPeerInStore;
8
+ private static waitForPeerIdentify;
9
9
  static addressFromConnection(options: {
10
10
  currentNode: any;
11
11
  connection: Connection;
@@ -1 +1 @@
1
- {"version":3,"file":"connection.utils.d.ts","sourceRoot":"","sources":["../../../src/utils/connection.utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAA2B,MAAM,iBAAiB,CAAC;AACtE,OAAO,EAAuB,OAAO,EAAE,MAAM,eAAe,CAAC;AAI7D,qBAAa,eAAgB,SAAQ,OAAO;IAC1C;;;OAGG;mBACkB,kBAAkB;WAgCnB,qBAAqB,CAAC,OAAO,EAAE;QACjD,WAAW,EAAE,GAAG,CAAC;QACjB,UAAU,EAAE,UAAU,CAAC;KACxB;CA0DF"}
1
+ {"version":3,"file":"connection.utils.d.ts","sourceRoot":"","sources":["../../../src/utils/connection.utils.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EAKX,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAuB,OAAO,EAAE,MAAM,eAAe,CAAC;AAI7D,qBAAa,eAAgB,SAAQ,OAAO;IAC1C;;;OAGG;mBACkB,mBAAmB;WA0EpB,qBAAqB,CAAC,OAAO,EAAE;QACjD,WAAW,EAAE,GAAG,CAAC;QACjB,UAAU,EAAE,UAAU,CAAC;KACxB;CA4DF"}
@@ -3,38 +3,64 @@ import { oNodeAddress } from '../router/o-node.address.js';
3
3
  import { oNodeTransport } from '../router/o-node.transport.js';
4
4
  export class ConnectionUtils extends oObject {
5
5
  /**
6
- * Waits for a peer to appear in the peer store with sufficient protocol information.
7
- * Implements retry logic to handle race conditions where peer store is not immediately populated.
6
+ * Waits for a peer to be identified via the identify protocol.
7
+ * Uses event-driven approach listening to peer store protocol updates.
8
8
  */
9
- static async waitForPeerInStore(p2pNode, remotePeerId) {
10
- const MAX_RETRIES = 100; // 5 seconds total (100 * 50ms)
11
- const RETRY_DELAY_MS = 50;
12
- const MIN_PROTOCOLS = 2;
13
- for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
9
+ static async waitForPeerIdentify(p2pNode, remotePeerId, nodeProtocol) {
10
+ const TIMEOUT_MS = 5000; // 5 seconds timeout
11
+ // Helper to check if peer has sufficient protocols
12
+ const checkPeerProtocols = async () => {
14
13
  const peers = await p2pNode.peerStore.all();
15
14
  const remotePeer = peers.find((peer) => {
16
15
  return peer.id.toString() === remotePeerId.toString();
17
16
  });
18
- // Check if peer exists and has sufficient protocol information
19
- if (remotePeer && remotePeer.protocols.length > MIN_PROTOCOLS) {
20
- return remotePeer;
21
- }
22
- // Wait before next retry
23
- if (attempt < MAX_RETRIES - 1) {
24
- await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY_MS));
17
+ if (remotePeer) {
18
+ const oProtocols = remotePeer.protocols.filter((p) => p.startsWith('/o/') && p.startsWith(nodeProtocol) === false) || [];
19
+ console.log('Found o-protocols for peer:', oProtocols, 'with node address:', nodeProtocol);
20
+ if (oProtocols.length > 0) {
21
+ return remotePeer;
22
+ }
25
23
  }
24
+ return null;
25
+ };
26
+ // Check if peer already has sufficient protocols
27
+ const existingPeer = await checkPeerProtocols();
28
+ if (existingPeer) {
29
+ return existingPeer;
26
30
  }
27
- // Timeout exceeded
28
- throw new Error(`Timeout waiting for peer ${remotePeerId.toString()} to appear in peer store with sufficient protocols (waited ${MAX_RETRIES * RETRY_DELAY_MS}ms)`);
31
+ // Wait for peer store protocol update event
32
+ return new Promise((resolve, reject) => {
33
+ const timeoutId = setTimeout(() => {
34
+ // TypeScript doesn't have types for peerStore events, but they exist at runtime
35
+ p2pNode.removeEventListener('peer:identify', protocolChangeHandler);
36
+ reject(new Error(`Timeout waiting for peer ${remotePeerId.toString()} to be identified (waited ${TIMEOUT_MS}ms)`));
37
+ }, TIMEOUT_MS);
38
+ const protocolChangeHandler = async (evt) => {
39
+ const { peerId } = evt.detail;
40
+ console.log('evt.detail:', evt.detail);
41
+ // Check if this is the peer we're waiting for
42
+ if (peerId?.toString() === remotePeerId.toString()) {
43
+ const peer = await checkPeerProtocols();
44
+ if (peer) {
45
+ clearTimeout(timeoutId);
46
+ // TypeScript doesn't have types for peerStore events, but they exist at runtime
47
+ p2pNode.removeEventListener('peer:identify', protocolChangeHandler);
48
+ resolve(peer);
49
+ }
50
+ }
51
+ };
52
+ // TypeScript doesn't have types for peerStore events, but they exist at runtime
53
+ p2pNode.addEventListener('peer:identify', protocolChangeHandler);
54
+ });
29
55
  }
30
56
  // TODO: improve this logic (poor implementation for now)
31
57
  static async addressFromConnection(options) {
32
58
  try {
33
59
  const { currentNode, connection } = options;
34
60
  const p2pNode = currentNode.p2pNode;
35
- // Wait for peer to appear in peer store with sufficient protocol information
36
- // This handles race conditions where peer store is not immediately populated
37
- const remotePeer = await this.waitForPeerInStore(p2pNode, connection.remotePeer);
61
+ // Wait for peer to be identified via the identify protocol
62
+ // This uses an event-driven approach to detect when the peer store is updated
63
+ const remotePeer = await this.waitForPeerIdentify(p2pNode, connection.remotePeer, currentNode.address.protocol);
38
64
  // Get origin address for comparison
39
65
  const originAddress = currentNode.address?.value;
40
66
  if (!originAddress) {
@@ -43,6 +69,7 @@ export class ConnectionUtils extends oObject {
43
69
  const oProtocol = remotePeer.protocols.find((p) => p.startsWith('/o/') &&
44
70
  p.includes(currentNode?.address?.protocol) === false);
45
71
  if (!oProtocol) {
72
+ console.log('Remote peer protocols:', remotePeer.protocols);
46
73
  throw new Error('Failed to extract remote address, could not find o-protocol in peer protocols.');
47
74
  }
48
75
  const address = oNodeAddress.fromProtocol(oProtocol);
@@ -14,11 +14,14 @@ describe('Connection Management', () => {
14
14
  await env.cleanup();
15
15
  });
16
16
  describe('Connection Pooling', () => {
17
+ // TODO: add more concurrency tests for first connection to a node since there is a race condition issue with 2 connections being possible (discovered when reviewing the event response mechanism for parent connection detected = retry register. Bandaid workaround currently working where we simply prevent trying in the reconnection manager)
17
18
  it('should cache and reuse connections', async () => {
18
19
  builder = await NetworkTopologies.twoNode();
19
20
  console.log('Built the 2 node network, starting test');
20
21
  const leader = builder.getNode('o://leader');
21
22
  const child = builder.getNode('o://child');
23
+ // at most there should only be 1 connection (the parent / leader shared)
24
+ expect(child.requestManager.connectionManager.connectionCount).to.equal(1);
22
25
  const spy = createConnectionSpy(leader);
23
26
  spy.start();
24
27
  // Make first request (establishes connection)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@olane/o-node",
3
- "version": "0.7.54",
3
+ "version": "0.7.56",
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.54",
43
+ "@olane/o-test": "0.7.56",
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.54",
64
- "@olane/o-core": "0.7.54",
65
- "@olane/o-protocol": "0.7.54",
66
- "@olane/o-tool": "0.7.54",
63
+ "@olane/o-config": "0.7.56",
64
+ "@olane/o-core": "0.7.56",
65
+ "@olane/o-protocol": "0.7.56",
66
+ "@olane/o-tool": "0.7.56",
67
67
  "debug": "^4.4.1",
68
68
  "dotenv": "^16.5.0",
69
69
  "json5": "^2.2.3"
70
70
  },
71
- "gitHead": "8e527a1481c6aeaf0840ea30198500a9baef1e98"
71
+ "gitHead": "f1dadd9c39f33d1279345546df8e1bf63481e5e1"
72
72
  }
@@ -1,64 +0,0 @@
1
- /**
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
- */
5
- export interface StreamInitMessage {
6
- /**
7
- * Message type identifier
8
- */
9
- type: 'stream-init';
10
- /**
11
- * Role of this stream
12
- * - 'reader': Dedicated reader stream for receiving requests from receiver
13
- * - 'writer': Dedicated writer stream for sending responses back to receiver
14
- * - 'standard': Standard request-response stream
15
- */
16
- role: 'reader' | 'writer' | 'standard';
17
- /**
18
- * Timestamp when the stream was created
19
- */
20
- timestamp: number;
21
- /**
22
- * Optional connection identifier for correlation
23
- */
24
- connectionId?: string;
25
- }
26
- /**
27
- * Type guard to check if a message is a StreamInitMessage
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;
64
- //# sourceMappingURL=stream-init-message.d.ts.map
@@ -1 +0,0 @@
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"}
@@ -1,18 +0,0 @@
1
- /**
2
- * Type guard to check if a message is a StreamInitMessage
3
- */
4
- export function isStreamInitMessage(message) {
5
- return (message?.type === 'stream-init' &&
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') &&
17
- typeof message.timestamp === 'number');
18
- }
@@ -1,8 +0,0 @@
1
- import type { Connection } from '@libp2p/interface';
2
- export interface StreamManagerConfig {
3
- /**
4
- * The libp2p connection this manager handles streams for
5
- */
6
- p2pConnection: Connection;
7
- }
8
- //# sourceMappingURL=stream-manager.config.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"stream-manager.config.d.ts","sourceRoot":"","sources":["../../../../src/connection/interfaces/stream-manager.config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,MAAM,WAAW,mBAAmB;IAClC;;OAEG;IACH,aAAa,EAAE,UAAU,CAAC;CAC3B"}
@@ -1,200 +0,0 @@
1
- /// <reference types="node" />
2
- import { EventEmitter } from 'events';
3
- import type { Connection, Stream } from '@libp2p/interface';
4
- import { oObject, oRequest, oResponse } from '@olane/o-core';
5
- import type { oRouterRequest, oConnection } from '@olane/o-core';
6
- import { oNodeStream } from './o-node-stream.js';
7
- import { StreamManagerConfig } from './interfaces/stream-manager.config.js';
8
- import type { StreamHandlerConfig } from './stream-handler.config.js';
9
- import { StreamManagerEvent, StreamManagerEventData } from './stream-manager.events.js';
10
- import { StreamInitMessage } from './interfaces/stream-init-message.js';
11
- /**
12
- * oNodeStreamManager handles the lifecycle and tracking of streams for a single connection.
13
- * Features:
14
- * - Tracks all streams by ID
15
- * - Creates new streams on demand
16
- * - Manages stream lifecycle (cleanup after use)
17
- * - Provides events for monitoring
18
- * - No reuse at base layer (extensible in subclasses)
19
- */
20
- export declare class oNodeStreamManager extends oObject {
21
- readonly config: StreamManagerConfig;
22
- private streams;
23
- protected eventEmitter: EventEmitter;
24
- isInitialized: boolean;
25
- private p2pConnection;
26
- private activeStreamHandlers;
27
- protected callerReaderStream?: Stream;
28
- protected callerWriterStream?: Stream;
29
- constructor(config: StreamManagerConfig);
30
- /**
31
- * Initialize the stream manager
32
- */
33
- initialize(): Promise<void>;
34
- /**
35
- * Gets or creates a stream for the connection
36
- * Always creates a new stream (no reuse at base layer)
37
- *
38
- * For limited connections (where caller has identified a reader stream):
39
- * - If callerReaderStream exists, wrap and return it for sending requests
40
- * - Otherwise, create new stream as normal
41
- *
42
- * @param protocol - The protocol string for the stream
43
- * @param remoteAddress - The remote address for the stream
44
- * @param config - Stream handler configuration
45
- * @returns Wrapped stream
46
- */
47
- getOrCreateStream(protocol: string, remoteAddress: any, config?: StreamHandlerConfig): Promise<oNodeStream>;
48
- /**
49
- * Creates a new stream from the connection
50
- *
51
- * @param protocol - The protocol string for the stream
52
- * @param remoteAddress - The remote address for the stream
53
- * @param config - Stream handler configuration
54
- * @returns Wrapped stream
55
- */
56
- createStream(protocol: string, remoteAddress: any, config?: StreamHandlerConfig): Promise<oNodeStream>;
57
- /**
58
- * Releases and cleans up a stream
59
- *
60
- * @param streamId - The ID of the stream to release
61
- */
62
- releaseStream(streamId: string): Promise<void>;
63
- /**
64
- * Gets all tracked streams
65
- *
66
- * @returns Array of wrapped streams
67
- */
68
- getAllStreams(): oNodeStream[];
69
- /**
70
- * Gets a stream by its ID
71
- * Checks persistent caller streams (reader/writer) and tracked streams
72
- *
73
- * @param streamId - The ID of the stream to retrieve
74
- * @returns The libp2p Stream or undefined if not found
75
- */
76
- getStreamById(streamId: string): Stream | undefined;
77
- /**
78
- * Emits an async event and waits for the first listener to return a result
79
- * This enables event-based request handling with async responses
80
- */
81
- private emitAsync;
82
- /**
83
- * Detects if a decoded message is a request
84
- * Requests have a 'method' field and no 'result' field
85
- */
86
- isRequest(message: any): boolean;
87
- /**
88
- * Detects if a decoded message is a response
89
- * Responses have a 'result' field and no 'method' field
90
- */
91
- isResponse(message: any): boolean;
92
- /**
93
- * Detects if a decoded message is a stream initialization message
94
- * Uses the imported type guard from stream-init-message.ts
95
- */
96
- isStreamInit(message: any): message is StreamInitMessage;
97
- /**
98
- * Handles a stream initialization message
99
- * Stores reference to caller's reader stream for bidirectional communication
100
- * Sends acknowledgment back to confirm stream registration
101
- *
102
- * @param message - The decoded stream init message
103
- * @param stream - The stream that sent the message
104
- */
105
- protected handleStreamInitMessage(message: StreamInitMessage, stream: Stream): Promise<void>;
106
- /**
107
- * Extracts and parses JSON from various formats including:
108
- * - Already parsed objects
109
- * - Plain JSON
110
- * - Markdown code blocks (```json ... ``` or ``` ... ```)
111
- * - Mixed content with explanatory text
112
- * - JSON5 format (trailing commas, comments, unquoted keys, etc.)
113
- *
114
- * @param decoded - The decoded string that may contain JSON, or an already parsed object
115
- * @returns Parsed JSON object
116
- * @throws Error if JSON parsing fails even with JSON5 fallback
117
- */
118
- protected extractAndParseJSON(decoded: string | any): any;
119
- /**
120
- * Sends data through a stream using length-prefixed encoding (libp2p v3 best practice)
121
- * Each message is automatically prefixed with a varint indicating the message length
122
- * This ensures proper message boundaries and eliminates concatenation issues
123
- *
124
- * @param stream - The stream to send data through
125
- * @param data - The data to send
126
- * @param config - Configuration for timeout and other options
127
- */
128
- sendLengthPrefixed(stream: Stream, data: Uint8Array, config?: StreamHandlerConfig): Promise<void>;
129
- /**
130
- * Tracks an active stream handler
131
- */
132
- private trackStreamHandler;
133
- /**
134
- * Untracks a stream handler
135
- */
136
- private untrackStreamHandler;
137
- /**
138
- * Handles an incoming stream on the server side using length-prefixed protocol
139
- * Uses async read loops instead of event listeners (libp2p v3 best practice)
140
- * Processes complete messages with proper boundaries
141
- *
142
- * @param stream - The incoming stream
143
- * @param connection - The connection the stream belongs to
144
- */
145
- handleIncomingStream(stream: Stream, connection: Connection): Promise<void>;
146
- /**
147
- * Determines which stream to use for sending the response
148
- * Checks for _streamId in request params and routes accordingly
149
- *
150
- * @param request - The incoming request
151
- * @param defaultStream - The stream the request came on (fallback)
152
- * @returns The stream to use for the response
153
- */
154
- protected getResponseStream(request: oRequest, defaultStream: Stream): Stream;
155
- /**
156
- * Handles a request message by emitting an event and sending response
157
- *
158
- * @param message - The decoded request message
159
- * @param stream - The stream to send the response on
160
- * @param connection - The connection the stream belongs to
161
- */
162
- protected handleRequestMessage(message: any, stream: Stream, connection: Connection): Promise<void>;
163
- /**
164
- * Handles an outgoing stream on the client side using length-prefixed protocol
165
- * Uses async read loops to process responses with proper message boundaries
166
- *
167
- * @param stream - The outgoing stream
168
- * @param emitter - Event emitter for chunk events
169
- * @param config - Configuration including abort signal
170
- * @param requestId - Optional request ID to filter responses (for stream reuse scenarios)
171
- * @returns Promise that resolves with the final response
172
- */
173
- handleOutgoingStream(stream: Stream, emitter: EventEmitter, config?: StreamHandlerConfig, requestId?: string | number): Promise<oResponse>;
174
- /**
175
- * Forwards a request to the next hop and relays response chunks back
176
- * This implements the middleware/proxy pattern for intermediate nodes
177
- *
178
- * @param request - The router request to forward
179
- * @param incomingStream - The stream to send responses back on
180
- * @param dialFn - Function to dial the next hop connection
181
- */
182
- forwardRequest(request: oRouterRequest, incomingStream: Stream, dialFn: (address: string) => Promise<oConnection>): Promise<void>;
183
- /**
184
- * Close the stream manager and cleanup resources
185
- */
186
- close(): Promise<void>;
187
- /**
188
- * Add event listener
189
- */
190
- on<K extends StreamManagerEvent>(event: K | string, listener: (data: StreamManagerEventData[K]) => void): void;
191
- /**
192
- * Remove event listener
193
- */
194
- off<K extends StreamManagerEvent>(event: K | string, listener: (data: StreamManagerEventData[K]) => void): void;
195
- /**
196
- * Emit event
197
- */
198
- private emit;
199
- }
200
- //# sourceMappingURL=o-node-stream.manager.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"o-node-stream.manager.d.ts","sourceRoot":"","sources":["../../../src/connection/o-node-stream.manager.ts"],"names":[],"mappings":"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"}