@olane/o-node 0.7.42 → 0.7.44
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/o-node-connection.manager.d.ts +6 -7
- package/dist/src/connection/o-node-connection.manager.d.ts.map +1 -1
- package/dist/src/connection/o-node-connection.manager.js +55 -63
- package/dist/src/utils/connection.utils.d.ts.map +1 -1
- package/dist/src/utils/connection.utils.js +8 -8
- package/package.json +7 -7
|
@@ -7,21 +7,20 @@ export declare class oNodeConnectionManager extends oConnectionManager {
|
|
|
7
7
|
protected p2pNode: Libp2p;
|
|
8
8
|
private defaultReadTimeoutMs?;
|
|
9
9
|
private defaultDrainTimeoutMs?;
|
|
10
|
-
private
|
|
11
|
-
private
|
|
10
|
+
private connectionsByAddress;
|
|
11
|
+
private pendingDialsByAddress;
|
|
12
12
|
constructor(config: oNodeConnectionManagerConfig);
|
|
13
13
|
/**
|
|
14
14
|
* Set up listeners to maintain connection cache state
|
|
15
15
|
*/
|
|
16
16
|
private setupConnectionListeners;
|
|
17
17
|
/**
|
|
18
|
-
* Build a stable cache key from
|
|
18
|
+
* Build a stable cache key from an address.
|
|
19
19
|
*
|
|
20
|
-
* We
|
|
21
|
-
*
|
|
22
|
-
* change but the libp2p transports are the true dial targets.
|
|
20
|
+
* We key the cache by address value (e.g., "o://my-tool") to maintain
|
|
21
|
+
* a simple one-to-one mapping between addresses and connections.
|
|
23
22
|
*/
|
|
24
|
-
private
|
|
23
|
+
private getAddressKey;
|
|
25
24
|
/**
|
|
26
25
|
* Extract peer ID string from an address
|
|
27
26
|
* @param address - The address to extract peer ID from
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"o-node-connection.manager.d.ts","sourceRoot":"","sources":["../../../src/connection/o-node-connection.manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAChF,OAAO,EAAE,MAAM,EAAE,UAAU,EAAU,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,4BAA4B,EAAE,MAAM,kDAAkD,CAAC;AAEhG,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,qBAAa,sBAAuB,SAAQ,kBAAkB;IAQhD,QAAQ,CAAC,MAAM,EAAE,4BAA4B;IAPzD,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,oBAAoB,CAAC,CAAS;IACtC,OAAO,CAAC,qBAAqB,CAAC,CAAS;IACvC,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"o-node-connection.manager.d.ts","sourceRoot":"","sources":["../../../src/connection/o-node-connection.manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAChF,OAAO,EAAE,MAAM,EAAE,UAAU,EAAU,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,4BAA4B,EAAE,MAAM,kDAAkD,CAAC;AAEhG,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,qBAAa,sBAAuB,SAAQ,kBAAkB;IAQhD,QAAQ,CAAC,MAAM,EAAE,4BAA4B;IAPzD,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,oBAAoB,CAAC,CAAS;IACtC,OAAO,CAAC,qBAAqB,CAAC,CAAS;IACvC,OAAO,CAAC,oBAAoB,CAAsC;IAClE,OAAO,CAAC,qBAAqB,CACjB;gBAES,MAAM,EAAE,4BAA4B;IAWzD;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAsBhC;;;;;OAKG;IACH,OAAO,CAAC,aAAa;IASrB;;;;OAIG;IACH,OAAO,CAAC,oBAAoB;IAatB,qBAAqB,CACzB,cAAc,EAAE,QAAQ,EACxB,OAAO,EAAE,QAAQ,GAChB,OAAO,CAAC,UAAU,CAAC;YA+DR,WAAW;IAwBnB,MAAM,CACV,MAAM,EAAE,iBAAiB,GAAG;QAAE,aAAa,EAAE,UAAU,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GACzE,OAAO,CAAC,eAAe,CAAC;IAmC3B;;;;OAIG;IACG,OAAO,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,eAAe,CAAC;IA8BlE;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO;IAwCpC;;;;OAIG;IACH,yBAAyB,CAAC,OAAO,EAAE,QAAQ,GAAG,UAAU,GAAG,IAAI;IA+C/D;;;OAGG;IACH,aAAa,IAAI;QACf,iBAAiB,EAAE,MAAM,CAAC;QAC1B,YAAY,EAAE,MAAM,CAAC;QACrB,iBAAiB,EAAE,KAAK,CAAC;YAAE,MAAM,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;KAC9D;IAaD;;;OAGG;IACH,uBAAuB,IAAI,MAAM;CAgBlC"}
|
|
@@ -4,8 +4,8 @@ export class oNodeConnectionManager extends oConnectionManager {
|
|
|
4
4
|
constructor(config) {
|
|
5
5
|
super(config);
|
|
6
6
|
this.config = config;
|
|
7
|
-
this.
|
|
8
|
-
this.
|
|
7
|
+
this.connectionsByAddress = new Map();
|
|
8
|
+
this.pendingDialsByAddress = new Map();
|
|
9
9
|
this.p2pNode = config.p2pNode;
|
|
10
10
|
this.defaultReadTimeoutMs = config.defaultReadTimeoutMs;
|
|
11
11
|
this.defaultDrainTimeoutMs = config.defaultDrainTimeoutMs;
|
|
@@ -22,34 +22,26 @@ export class oNodeConnectionManager extends oConnectionManager {
|
|
|
22
22
|
if (!connection) {
|
|
23
23
|
return;
|
|
24
24
|
}
|
|
25
|
-
for (const [
|
|
25
|
+
for (const [addressKey, cachedConnection,] of this.connectionsByAddress.entries()) {
|
|
26
26
|
if (cachedConnection === connection) {
|
|
27
|
-
this.logger.debug('Connection closed, removing from cache for
|
|
28
|
-
this.
|
|
27
|
+
this.logger.debug('Connection closed, removing from cache for address:', addressKey);
|
|
28
|
+
this.connectionsByAddress.delete(addressKey);
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
});
|
|
32
32
|
}
|
|
33
33
|
/**
|
|
34
|
-
* Build a stable cache key from
|
|
34
|
+
* Build a stable cache key from an address.
|
|
35
35
|
*
|
|
36
|
-
* We
|
|
37
|
-
*
|
|
38
|
-
* change but the libp2p transports are the true dial targets.
|
|
36
|
+
* We key the cache by address value (e.g., "o://my-tool") to maintain
|
|
37
|
+
* a simple one-to-one mapping between addresses and connections.
|
|
39
38
|
*/
|
|
40
|
-
|
|
39
|
+
getAddressKey(address) {
|
|
41
40
|
try {
|
|
42
|
-
|
|
43
|
-
const transports = nodeAddress.libp2pTransports;
|
|
44
|
-
if (!transports?.length) {
|
|
45
|
-
return null;
|
|
46
|
-
}
|
|
47
|
-
// Sort to ensure deterministic keys regardless of transport ordering.
|
|
48
|
-
const parts = transports.map((t) => t.toString()).sort();
|
|
49
|
-
return parts.join('|');
|
|
41
|
+
return address.value || null;
|
|
50
42
|
}
|
|
51
43
|
catch (error) {
|
|
52
|
-
this.logger.debug('Error extracting
|
|
44
|
+
this.logger.debug('Error extracting address key from address:', error);
|
|
53
45
|
return null;
|
|
54
46
|
}
|
|
55
47
|
}
|
|
@@ -75,56 +67,56 @@ export class oNodeConnectionManager extends oConnectionManager {
|
|
|
75
67
|
if (!nextHopAddress) {
|
|
76
68
|
throw new Error('Invalid address passed');
|
|
77
69
|
}
|
|
78
|
-
// Build
|
|
79
|
-
const
|
|
80
|
-
if (!
|
|
81
|
-
throw new Error(`Unable to extract
|
|
70
|
+
// Build an address-based cache key from the next hop address
|
|
71
|
+
const addressKey = this.getAddressKey(nextHopAddress);
|
|
72
|
+
if (!addressKey) {
|
|
73
|
+
throw new Error(`Unable to extract address key from address: ${nextHopAddress.toString()}`);
|
|
82
74
|
}
|
|
83
|
-
// Check if we have a cached connection by
|
|
84
|
-
const cachedConnection = this.
|
|
75
|
+
// Check if we have a cached connection by address key
|
|
76
|
+
const cachedConnection = this.connectionsByAddress.get(addressKey);
|
|
85
77
|
if (cachedConnection && cachedConnection.status === 'open') {
|
|
86
|
-
this.logger.debug('Reusing cached connection for
|
|
78
|
+
this.logger.debug('Reusing cached connection for address:', nextHopAddress?.value);
|
|
87
79
|
return cachedConnection;
|
|
88
80
|
}
|
|
89
81
|
// Clean up stale connection if it exists but is not open
|
|
90
82
|
if (cachedConnection && cachedConnection.status !== 'open') {
|
|
91
|
-
this.logger.debug('Removing stale connection for
|
|
92
|
-
this.
|
|
83
|
+
this.logger.debug('Removing stale connection for address:', addressKey);
|
|
84
|
+
this.connectionsByAddress.delete(addressKey);
|
|
93
85
|
}
|
|
94
86
|
// Check if libp2p has an active connection for this address
|
|
95
87
|
const libp2pConnection = this.getCachedLibp2pConnection(nextHopAddress);
|
|
96
88
|
if (libp2pConnection && libp2pConnection.status === 'open') {
|
|
97
|
-
this.logger.debug('Caching existing libp2p connection for
|
|
98
|
-
this.
|
|
89
|
+
this.logger.debug('Caching existing libp2p connection for address:', addressKey);
|
|
90
|
+
this.connectionsByAddress.set(addressKey, libp2pConnection);
|
|
99
91
|
return libp2pConnection;
|
|
100
92
|
}
|
|
101
|
-
// Check if dial is already in progress for this
|
|
102
|
-
const pendingDial = this.
|
|
93
|
+
// Check if dial is already in progress for this address key
|
|
94
|
+
const pendingDial = this.pendingDialsByAddress.get(addressKey);
|
|
103
95
|
if (pendingDial) {
|
|
104
|
-
this.logger.debug('Awaiting existing dial for
|
|
96
|
+
this.logger.debug('Awaiting existing dial for address:', addressKey);
|
|
105
97
|
return pendingDial;
|
|
106
98
|
}
|
|
107
|
-
// Start new dial and cache the promise by
|
|
108
|
-
const dialPromise = this.performDial(nextHopAddress,
|
|
109
|
-
this.
|
|
99
|
+
// Start new dial and cache the promise by address key
|
|
100
|
+
const dialPromise = this.performDial(nextHopAddress, addressKey);
|
|
101
|
+
this.pendingDialsByAddress.set(addressKey, dialPromise);
|
|
110
102
|
try {
|
|
111
103
|
const connection = await dialPromise;
|
|
112
|
-
// Cache the established connection by
|
|
113
|
-
this.
|
|
104
|
+
// Cache the established connection by address key
|
|
105
|
+
this.connectionsByAddress.set(addressKey, connection);
|
|
114
106
|
return connection;
|
|
115
107
|
}
|
|
116
108
|
finally {
|
|
117
|
-
this.
|
|
109
|
+
this.pendingDialsByAddress.delete(addressKey);
|
|
118
110
|
}
|
|
119
111
|
}
|
|
120
|
-
async performDial(nextHopAddress,
|
|
112
|
+
async performDial(nextHopAddress, addressKey) {
|
|
121
113
|
this.logger.debug('Dialing new connection', {
|
|
122
114
|
address: nextHopAddress.value,
|
|
123
|
-
|
|
115
|
+
addressKey,
|
|
124
116
|
});
|
|
125
117
|
const connection = await this.p2pNode.dial(nextHopAddress.libp2pTransports.map((ma) => ma.toMultiaddr()));
|
|
126
118
|
this.logger.debug('Successfully dialed connection', {
|
|
127
|
-
|
|
119
|
+
addressKey,
|
|
128
120
|
status: connection.status,
|
|
129
121
|
remotePeer: connection.remotePeer?.toString(),
|
|
130
122
|
});
|
|
@@ -145,12 +137,12 @@ export class oNodeConnectionManager extends oConnectionManager {
|
|
|
145
137
|
requestHandler: config.requestHandler ?? undefined,
|
|
146
138
|
reusePolicy: reuse ? 'reuse' : 'none',
|
|
147
139
|
});
|
|
148
|
-
const
|
|
149
|
-
if (
|
|
150
|
-
this.
|
|
140
|
+
const addressKey = this.getAddressKey(nextHopAddress);
|
|
141
|
+
if (addressKey) {
|
|
142
|
+
this.connectionsByAddress.set(addressKey, p2pConnection);
|
|
151
143
|
}
|
|
152
144
|
else {
|
|
153
|
-
this.logger.error('Should not happen! Failed to generate
|
|
145
|
+
this.logger.error('Should not happen! Failed to generate an address key for address:', nextHopAddress);
|
|
154
146
|
}
|
|
155
147
|
return connection;
|
|
156
148
|
}
|
|
@@ -183,12 +175,12 @@ export class oNodeConnectionManager extends oConnectionManager {
|
|
|
183
175
|
*/
|
|
184
176
|
isCached(address) {
|
|
185
177
|
try {
|
|
186
|
-
const
|
|
187
|
-
if (!
|
|
178
|
+
const addressKey = this.getAddressKey(address);
|
|
179
|
+
if (!addressKey) {
|
|
188
180
|
return false;
|
|
189
181
|
}
|
|
190
|
-
// Check our
|
|
191
|
-
const cachedConnection = this.
|
|
182
|
+
// Check our address-based cache first
|
|
183
|
+
const cachedConnection = this.connectionsByAddress.get(addressKey);
|
|
192
184
|
if (cachedConnection?.status === 'open') {
|
|
193
185
|
return true;
|
|
194
186
|
}
|
|
@@ -202,7 +194,7 @@ export class oNodeConnectionManager extends oConnectionManager {
|
|
|
202
194
|
if (hasOpenConnection) {
|
|
203
195
|
const openConnection = connections.find((conn) => conn.status === 'open');
|
|
204
196
|
if (openConnection) {
|
|
205
|
-
this.
|
|
197
|
+
this.connectionsByAddress.set(addressKey, openConnection);
|
|
206
198
|
}
|
|
207
199
|
}
|
|
208
200
|
return hasOpenConnection;
|
|
@@ -219,12 +211,12 @@ export class oNodeConnectionManager extends oConnectionManager {
|
|
|
219
211
|
*/
|
|
220
212
|
getCachedLibp2pConnection(address) {
|
|
221
213
|
try {
|
|
222
|
-
const
|
|
223
|
-
if (!
|
|
214
|
+
const addressKey = this.getAddressKey(address);
|
|
215
|
+
if (!addressKey) {
|
|
224
216
|
return null;
|
|
225
217
|
}
|
|
226
|
-
// Check
|
|
227
|
-
const cachedConnection = this.
|
|
218
|
+
// Check address-based cache first
|
|
219
|
+
const cachedConnection = this.connectionsByAddress.get(addressKey);
|
|
228
220
|
if (cachedConnection?.status === 'open') {
|
|
229
221
|
return cachedConnection;
|
|
230
222
|
}
|
|
@@ -237,14 +229,14 @@ export class oNodeConnectionManager extends oConnectionManager {
|
|
|
237
229
|
const filteredConnections = connections.filter((conn) => conn.remotePeer?.toString() === peerId);
|
|
238
230
|
// Find the first open connection
|
|
239
231
|
const openConnection = filteredConnections.find((conn) => conn.status === 'open');
|
|
240
|
-
// If we found an open connection in libp2p, cache it by
|
|
232
|
+
// If we found an open connection in libp2p, cache it by address key
|
|
241
233
|
if (openConnection) {
|
|
242
|
-
this.
|
|
234
|
+
this.connectionsByAddress.set(addressKey, openConnection);
|
|
243
235
|
return openConnection;
|
|
244
236
|
}
|
|
245
237
|
// Clean up stale cache entry if connection is no longer open
|
|
246
238
|
if (cachedConnection) {
|
|
247
|
-
this.
|
|
239
|
+
this.connectionsByAddress.delete(addressKey);
|
|
248
240
|
}
|
|
249
241
|
return null;
|
|
250
242
|
}
|
|
@@ -259,9 +251,9 @@ export class oNodeConnectionManager extends oConnectionManager {
|
|
|
259
251
|
*/
|
|
260
252
|
getCacheStats() {
|
|
261
253
|
return {
|
|
262
|
-
cachedConnections: this.
|
|
263
|
-
pendingDials: this.
|
|
264
|
-
connectionsByPeer: Array.from(this.
|
|
254
|
+
cachedConnections: this.connectionsByAddress.size,
|
|
255
|
+
pendingDials: this.pendingDialsByAddress.size,
|
|
256
|
+
connectionsByPeer: Array.from(this.connectionsByAddress.values()).map((conn) => ({
|
|
265
257
|
peerId: conn.remotePeer?.toString() ?? 'unknown',
|
|
266
258
|
status: conn.status,
|
|
267
259
|
})),
|
|
@@ -273,9 +265,9 @@ export class oNodeConnectionManager extends oConnectionManager {
|
|
|
273
265
|
*/
|
|
274
266
|
cleanupStaleConnections() {
|
|
275
267
|
let removed = 0;
|
|
276
|
-
for (const [
|
|
268
|
+
for (const [addressKey, connection,] of this.connectionsByAddress.entries()) {
|
|
277
269
|
if (connection.status !== 'open') {
|
|
278
|
-
this.
|
|
270
|
+
this.connectionsByAddress.delete(addressKey);
|
|
279
271
|
removed++;
|
|
280
272
|
}
|
|
281
273
|
}
|
|
@@ -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;WACtB,qBAAqB,CAAC,OAAO,EAAE;QACjD,WAAW,EAAE,GAAG,CAAC;QACjB,UAAU,EAAE,UAAU,CAAC;KACxB;
|
|
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;WACtB,qBAAqB,CAAC,OAAO,EAAE;QACjD,WAAW,EAAE,GAAG,CAAC;QACjB,UAAU,EAAE,UAAU,CAAC;KACxB;CA+DF"}
|
|
@@ -4,12 +4,13 @@ import { oNodeTransport } from '../router/o-node.transport.js';
|
|
|
4
4
|
export class ConnectionUtils extends oObject {
|
|
5
5
|
static async addressFromConnection(options) {
|
|
6
6
|
try {
|
|
7
|
-
console.log('[ConnectionUtils] addressFromConnection');
|
|
8
7
|
const { currentNode, connection } = options;
|
|
9
8
|
const p2pNode = currentNode.p2pNode;
|
|
10
9
|
// Extract the actual olane address from the peer store
|
|
11
10
|
const peers = await p2pNode.peerStore.all();
|
|
12
|
-
const remotePeer = peers.find((peer) =>
|
|
11
|
+
const remotePeer = peers.find((peer) => {
|
|
12
|
+
return peer.id.toString() === connection.remotePeer.toString();
|
|
13
|
+
});
|
|
13
14
|
if (!remotePeer) {
|
|
14
15
|
console.log('Failed to find peer:', remotePeer);
|
|
15
16
|
throw new Error(`Failed to extract remote address, peer ${connection.remotePeer.toString()} not found in peer store.`);
|
|
@@ -19,19 +20,18 @@ export class ConnectionUtils extends oObject {
|
|
|
19
20
|
if (!originAddress) {
|
|
20
21
|
throw new Error('Origin address is not configured');
|
|
21
22
|
}
|
|
22
|
-
const
|
|
23
|
-
const oProtocol = remotePeer.protocols.find((p) => p.startsWith('/o/') && p.startsWith(originProtocol) === false);
|
|
23
|
+
const oProtocol = remotePeer.protocols.find((p) => p.startsWith('/o/'));
|
|
24
24
|
if (!oProtocol) {
|
|
25
25
|
throw new Error('Failed to extract remote address, could not find o-protocol in peer protocols.');
|
|
26
26
|
}
|
|
27
27
|
const address = oNodeAddress.fromProtocol(oProtocol);
|
|
28
|
-
if (remotePeer
|
|
29
|
-
address
|
|
28
|
+
if (remotePeer?.addresses?.length === 0 &&
|
|
29
|
+
address?.value === currentNode?.leader?.value) {
|
|
30
30
|
// leader - use known address
|
|
31
31
|
return currentNode.leader;
|
|
32
32
|
}
|
|
33
|
-
if (remotePeer
|
|
34
|
-
address
|
|
33
|
+
if (remotePeer?.addresses?.length === 0 &&
|
|
34
|
+
address?.value === currentNode?.parent?.value) {
|
|
35
35
|
// leader - use known address
|
|
36
36
|
return currentNode.parent;
|
|
37
37
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@olane/o-node",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.44",
|
|
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.44",
|
|
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.44",
|
|
64
|
+
"@olane/o-core": "0.7.44",
|
|
65
|
+
"@olane/o-protocol": "0.7.44",
|
|
66
|
+
"@olane/o-tool": "0.7.44",
|
|
67
67
|
"debug": "^4.4.1",
|
|
68
68
|
"dotenv": "^16.5.0",
|
|
69
69
|
"json5": "^2.2.3"
|
|
70
70
|
},
|
|
71
|
-
"gitHead": "
|
|
71
|
+
"gitHead": "de7bc5247c97fb219d522cc5874f7459634e03ec"
|
|
72
72
|
}
|