@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.
- package/dist/src/connection/enums/o-node-message-event.d.ts +14 -0
- package/dist/src/connection/enums/o-node-message-event.d.ts.map +1 -0
- package/dist/src/connection/enums/o-node-message-event.js +5 -0
- package/dist/src/connection/index.d.ts +0 -3
- package/dist/src/connection/index.d.ts.map +1 -1
- package/dist/src/connection/index.js +0 -3
- package/dist/src/connection/interfaces/abort-signal.config.d.ts +5 -0
- package/dist/src/connection/interfaces/abort-signal.config.d.ts.map +1 -0
- package/dist/src/connection/interfaces/o-node-connection-manager.config.d.ts +13 -1
- package/dist/src/connection/interfaces/o-node-connection-manager.config.d.ts.map +1 -1
- package/dist/src/connection/interfaces/o-node-connection.config.d.ts +17 -3
- package/dist/src/connection/interfaces/o-node-connection.config.d.ts.map +1 -1
- package/dist/src/connection/interfaces/o-node-stream.config.d.ts +3 -11
- package/dist/src/connection/interfaces/o-node-stream.config.d.ts.map +1 -1
- package/dist/src/connection/o-node-connection.d.ts +33 -11
- package/dist/src/connection/o-node-connection.d.ts.map +1 -1
- package/dist/src/connection/o-node-connection.js +113 -58
- package/dist/src/connection/o-node-connection.manager.d.ts +17 -62
- package/dist/src/connection/o-node-connection.manager.d.ts.map +1 -1
- package/dist/src/connection/o-node-connection.manager.js +65 -189
- package/dist/src/connection/o-node-stream.d.ts +48 -15
- package/dist/src/connection/o-node-stream.d.ts.map +1 -1
- package/dist/src/connection/o-node-stream.js +144 -31
- package/dist/src/connection/stream-handler.config.d.ts +0 -11
- package/dist/src/connection/stream-handler.config.d.ts.map +1 -1
- package/dist/src/connection/stream-manager.events.d.ts +7 -0
- package/dist/src/connection/stream-manager.events.d.ts.map +1 -1
- package/dist/src/connection/stream-manager.events.js +1 -0
- package/dist/src/lib/interfaces/o-node-request-manager.config.d.ts +9 -0
- package/dist/src/lib/interfaces/o-node-request-manager.config.d.ts.map +1 -0
- package/dist/src/lib/interfaces/o-node-request-manager.config.js +1 -0
- package/dist/src/lib/o-node-request-manager.d.ts +46 -0
- package/dist/src/lib/o-node-request-manager.d.ts.map +1 -0
- package/dist/src/lib/o-node-request-manager.js +173 -0
- package/dist/src/managers/o-reconnection.manager.d.ts.map +1 -1
- package/dist/src/managers/o-reconnection.manager.js +4 -0
- package/dist/src/managers/o-registration.manager.d.ts.map +1 -1
- package/dist/src/managers/o-registration.manager.js +9 -4
- package/dist/src/o-node.d.ts +6 -7
- package/dist/src/o-node.d.ts.map +1 -1
- package/dist/src/o-node.js +22 -37
- package/dist/src/o-node.tool.d.ts +3 -3
- package/dist/src/o-node.tool.d.ts.map +1 -1
- package/dist/src/o-node.tool.js +31 -65
- package/dist/src/router/o-node.router.d.ts.map +1 -1
- package/dist/src/router/o-node.router.js +4 -2
- package/dist/src/utils/connection.utils.d.ts +3 -3
- package/dist/src/utils/connection.utils.d.ts.map +1 -1
- package/dist/src/utils/connection.utils.js +46 -19
- package/dist/test/connection-management.spec.js +3 -0
- package/package.json +7 -7
- package/dist/src/connection/interfaces/stream-init-message.d.ts +0 -64
- package/dist/src/connection/interfaces/stream-init-message.d.ts.map +0 -1
- package/dist/src/connection/interfaces/stream-init-message.js +0 -18
- package/dist/src/connection/interfaces/stream-manager.config.d.ts +0 -8
- package/dist/src/connection/interfaces/stream-manager.config.d.ts.map +0 -1
- package/dist/src/connection/o-node-stream.manager.d.ts +0 -200
- package/dist/src/connection/o-node-stream.manager.d.ts.map +0 -1
- package/dist/src/connection/o-node-stream.manager.js +0 -633
- /package/dist/src/connection/interfaces/{stream-manager.config.js → abort-signal.config.js} +0 -0
package/dist/src/o-node.tool.js
CHANGED
|
@@ -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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
|
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
|
|
66
|
-
return this.
|
|
67
|
-
|
|
68
|
-
|
|
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;
|
|
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
|
-
|
|
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
|
|
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
|
|
6
|
-
*
|
|
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
|
|
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,
|
|
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
|
|
7
|
-
*
|
|
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
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
const
|
|
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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
-
//
|
|
28
|
-
|
|
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
|
|
36
|
-
// This
|
|
37
|
-
const remotePeer = await this.
|
|
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.
|
|
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.
|
|
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.
|
|
64
|
-
"@olane/o-core": "0.7.
|
|
65
|
-
"@olane/o-protocol": "0.7.
|
|
66
|
-
"@olane/o-tool": "0.7.
|
|
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": "
|
|
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 +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":";AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EACL,OAAO,EAGP,QAAQ,EACR,SAAS,EAGV,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjE,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,uCAAuC,CAAC;AAC5E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,EACL,kBAAkB,EAClB,sBAAsB,EACvB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,iBAAiB,EAIlB,MAAM,qCAAqC,CAAC;AAI7C;;;;;;;;GAQG;AACH,qBAAa,kBAAmB,SAAQ,OAAO;IAYjC,QAAQ,CAAC,MAAM,EAAE,mBAAmB;IAXhD,OAAO,CAAC,OAAO,CAAuC;IACtD,SAAS,CAAC,YAAY,EAAE,YAAY,CAAsB;IACnD,aAAa,EAAE,OAAO,CAAS;IACtC,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,oBAAoB,CAGd;IACd,SAAS,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACtC,SAAS,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;gBAEjB,MAAM,EAAE,mBAAmB;IAKhD;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAsBjC;;;;;;;;;;;;OAYG;IACG,iBAAiB,CACrB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,GAAG,EAClB,MAAM,GAAE,mBAAwB,GAC/B,OAAO,CAAC,WAAW,CAAC;IAsCvB;;;;;;;OAOG;IACG,YAAY,CAChB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,GAAG,EAClB,MAAM,GAAE,mBAAwB,GAC/B,OAAO,CAAC,WAAW,CAAC;IAiCvB;;;;OAIG;IACG,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA+BpD;;;;OAIG;IACH,aAAa,IAAI,WAAW,EAAE;IAI9B;;;;;;OAMG;IACH,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAgBnD;;;OAGG;YACW,SAAS;IAevB;;;OAGG;IACH,SAAS,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO;IAIhC;;;OAGG;IACH,UAAU,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO;IAIjC;;;OAGG;IACH,YAAY,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO,IAAI,iBAAiB;IAIxD;;;;;;;OAOG;cACa,uBAAuB,CACrC,OAAO,EAAE,iBAAiB,EAC1B,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC;IAsEhB;;;;;;;;;;;OAWG;IACH,SAAS,CAAC,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,GAAG,GAAG,GAAG;IAqCzD;;;;;;;;OAQG;IACG,kBAAkB,CACtB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,UAAU,EAChB,MAAM,GAAE,mBAAwB,GAC/B,OAAO,CAAC,IAAI,CAAC;IAKhB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAO1B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAI5B;;;;;;;OAOG;IACG,oBAAoB,CACxB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC,IAAI,CAAC;IA2ChB;;;;;;;OAOG;IACH,SAAS,CAAC,iBAAiB,CACzB,OAAO,EAAE,QAAQ,EACjB,aAAa,EAAE,MAAM,GACpB,MAAM;IAoCT;;;;;;OAMG;cACa,oBAAoB,CAClC,OAAO,EAAE,GAAG,EACZ,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC,IAAI,CAAC;IAwChB;;;;;;;;;OASG;IACG,oBAAoB,CACxB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,YAAY,EACrB,MAAM,GAAE,mBAAwB,EAChC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,GAC1B,OAAO,CAAC,SAAS,CAAC;IAwFrB;;;;;;;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;IA0BhB;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAyC5B;;OAEG;IACH,EAAE,CAAC,CAAC,SAAS,kBAAkB,EAC7B,KAAK,EAAE,CAAC,GAAG,MAAM,EACjB,QAAQ,EAAE,CAAC,IAAI,EAAE,sBAAsB,CAAC,CAAC,CAAC,KAAK,IAAI,GAClD,IAAI;IAIP;;OAEG;IACH,GAAG,CAAC,CAAC,SAAS,kBAAkB,EAC9B,KAAK,EAAE,CAAC,GAAG,MAAM,EACjB,QAAQ,EAAE,CAAC,IAAI,EAAE,sBAAsB,CAAC,CAAC,CAAC,KAAK,IAAI,GAClD,IAAI;IAIP;;OAEG;IACH,OAAO,CAAC,IAAI;CAMb"}
|