@olane/o-node 0.7.12-alpha.12 → 0.7.12-alpha.13

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.
@@ -0,0 +1,49 @@
1
+ import { oNotificationManager } from '@olane/o-core';
2
+ import { Libp2p } from '@olane/o-config';
3
+ import { oNodeAddress } from '../router/o-node.address.js';
4
+ /**
5
+ * Interface for nodes that support connection heartbeat monitoring.
6
+ * This interface defines the contract that oConnectionHeartbeatManager needs
7
+ * to access live hierarchy state without holding stale references.
8
+ */
9
+ export interface IHeartbeatableNode {
10
+ /**
11
+ * The node's current address
12
+ */
13
+ address: oNodeAddress;
14
+ /**
15
+ * The notification manager for emitting heartbeat events
16
+ */
17
+ notificationManager: oNotificationManager;
18
+ /**
19
+ * The underlying libp2p node for ping operations
20
+ */
21
+ p2pNode: Libp2p;
22
+ /**
23
+ * The current parent address (with live transport updates)
24
+ * @returns Parent address or null if no parent
25
+ */
26
+ parent: oNodeAddress | null;
27
+ /**
28
+ * Get the current list of leader addresses
29
+ * @returns Array of leader addresses (empty if this node is the leader)
30
+ */
31
+ getLeaders(): oNodeAddress[];
32
+ /**
33
+ * Get the current list of parent addresses
34
+ * @returns Array of parent addresses
35
+ */
36
+ getParents(): oNodeAddress[];
37
+ /**
38
+ * Get the current list of child addresses
39
+ * @returns Array of child addresses
40
+ */
41
+ getChildren(): oNodeAddress[];
42
+ /**
43
+ * Remove a child from the hierarchy
44
+ * @param childAddress The address of the child to remove
45
+ */
46
+ removeChild(childAddress: oNodeAddress): void;
47
+ use(param1: any, param2: any): Promise<any>;
48
+ }
49
+ //# sourceMappingURL=i-heartbeatable-node.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"i-heartbeatable-node.d.ts","sourceRoot":"","sources":["../../../src/interfaces/i-heartbeatable-node.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAE3D;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,OAAO,EAAE,YAAY,CAAC;IAEtB;;OAEG;IACH,mBAAmB,EAAE,oBAAoB,CAAC;IAE1C;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IAE5B;;;OAGG;IACH,UAAU,IAAI,YAAY,EAAE,CAAC;IAE7B;;;OAGG;IACH,UAAU,IAAI,YAAY,EAAE,CAAC;IAE7B;;;OAGG;IACH,WAAW,IAAI,YAAY,EAAE,CAAC;IAE9B;;;OAGG;IACH,WAAW,CAAC,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAE9C,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;CAC7C"}
@@ -0,0 +1 @@
1
+ export {};
@@ -1,8 +1,6 @@
1
- import { Libp2p } from '@olane/o-config';
2
1
  import { oObject } from '@olane/o-core';
3
2
  import { oNodeAddress } from '../router/o-node.address.js';
4
- import { oNodeHierarchyManager } from '../o-node.hierarchy-manager.js';
5
- import { oNotificationManager } from '@olane/o-core';
3
+ import { IHeartbeatableNode } from '../interfaces/i-heartbeatable-node.js';
6
4
  export interface HeartbeatConfig {
7
5
  enabled: boolean;
8
6
  intervalMs: number;
@@ -35,17 +33,15 @@ export interface ConnectionHealth {
35
33
  * - Emits ParentDisconnectedEvent when parent dies (triggers reconnection)
36
34
  */
37
35
  export declare class oConnectionHeartbeatManager extends oObject {
38
- private p2pNode;
39
- private hierarchyManager;
40
- private notificationManager;
41
- private address;
36
+ private node;
42
37
  private config;
43
38
  private heartbeatInterval?;
44
39
  private healthMap;
45
- constructor(p2pNode: Libp2p, hierarchyManager: oNodeHierarchyManager, notificationManager: oNotificationManager, address: oNodeAddress, config: HeartbeatConfig);
40
+ constructor(node: IHeartbeatableNode, config: HeartbeatConfig);
46
41
  start(): Promise<void>;
47
42
  stop(): Promise<void>;
48
43
  private performHeartbeatCycle;
44
+ private doPing;
49
45
  private pingTarget;
50
46
  private handleConnectionDead;
51
47
  private emitConnectionDegradedEvent;
@@ -1 +1 @@
1
- {"version":3,"file":"o-connection-heartbeat.manager.d.ts","sourceRoot":"","sources":["../../../src/managers/o-connection-heartbeat.manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EACL,OAAO,EAMR,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAErD,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,YAAY,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,kBAAkB,EAAE,MAAM,CAAC;IAC3B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,SAAS,GAAG,UAAU,GAAG,MAAM,CAAC;CACzC;AAED;;;;;;;;;;;;;GAaG;AACH,qBAAa,2BAA4B,SAAQ,OAAO;IAKpD,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,gBAAgB;IACxB,OAAO,CAAC,mBAAmB;IAC3B,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,MAAM;IARhB,OAAO,CAAC,iBAAiB,CAAC,CAAiB;IAC3C,OAAO,CAAC,SAAS,CAAuC;gBAG9C,OAAO,EAAE,MAAM,EACf,gBAAgB,EAAE,qBAAqB,EACvC,mBAAmB,EAAE,oBAAoB,EACzC,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,eAAe;IAK3B,KAAK;IAqBL,IAAI;YAQI,qBAAqB;YAuCrB,UAAU;IA2FxB,OAAO,CAAC,oBAAoB;IAyD5B,OAAO,CAAC,2BAA2B;IAmBnC,OAAO,CAAC,4BAA4B;IAiBpC,OAAO,CAAC,wBAAwB;IAahC;;OAEG;IACH,eAAe,IAAI,gBAAgB,EAAE;IAIrC;;OAEG;IACH,mBAAmB,CAAC,OAAO,EAAE,YAAY,GAAG,gBAAgB,GAAG,SAAS;IAIxE;;OAEG;IACH,SAAS,IAAI,eAAe;CAG7B"}
1
+ {"version":3,"file":"o-connection-heartbeat.manager.d.ts","sourceRoot":"","sources":["../../../src/managers/o-connection-heartbeat.manager.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EAOR,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAE3E,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,YAAY,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,kBAAkB,EAAE,MAAM,CAAC;IAC3B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,SAAS,GAAG,UAAU,GAAG,MAAM,CAAC;CACzC;AAED;;;;;;;;;;;;;GAaG;AACH,qBAAa,2BAA4B,SAAQ,OAAO;IAKpD,OAAO,CAAC,IAAI;IACZ,OAAO,CAAC,MAAM;IALhB,OAAO,CAAC,iBAAiB,CAAC,CAAiB;IAC3C,OAAO,CAAC,SAAS,CAAuC;gBAG9C,IAAI,EAAE,kBAAkB,EACxB,MAAM,EAAE,eAAe;IAK3B,KAAK;IAqBL,IAAI;YAQI,qBAAqB;IA0CnC,OAAO,CAAC,MAAM;YAOA,UAAU;IAuFxB,OAAO,CAAC,oBAAoB;IAyD5B,OAAO,CAAC,2BAA2B;IAmBnC,OAAO,CAAC,4BAA4B;IAiBpC,OAAO,CAAC,wBAAwB;IAahC;;OAEG;IACH,eAAe,IAAI,gBAAgB,EAAE;IAIrC;;OAEG;IACH,mBAAmB,CAAC,OAAO,EAAE,YAAY,GAAG,gBAAgB,GAAG,SAAS;IAIxE;;OAEG;IACH,SAAS,IAAI,eAAe;CAG7B"}
@@ -14,12 +14,9 @@ import { oObject, ChildLeftEvent, ParentDisconnectedEvent, LeaderDisconnectedEve
14
14
  * - Emits ParentDisconnectedEvent when parent dies (triggers reconnection)
15
15
  */
16
16
  export class oConnectionHeartbeatManager extends oObject {
17
- constructor(p2pNode, hierarchyManager, notificationManager, address, config) {
17
+ constructor(node, config) {
18
18
  super();
19
- this.p2pNode = p2pNode;
20
- this.hierarchyManager = hierarchyManager;
21
- this.notificationManager = notificationManager;
22
- this.address = address;
19
+ this.node = node;
23
20
  this.config = config;
24
21
  this.healthMap = new Map();
25
22
  }
@@ -45,24 +42,27 @@ export class oConnectionHeartbeatManager extends oObject {
45
42
  async performHeartbeatCycle() {
46
43
  const targets = [];
47
44
  // Check if this is a leader node (no leader in hierarchy = we are leader)
48
- const isLeaderNode = this.hierarchyManager.getLeaders().length === 0;
45
+ const isLeaderNode = this.node.getLeaders().length === 0;
49
46
  // Collect leader (if enabled and we're not the leader)
50
47
  if (!isLeaderNode) {
51
- const leaders = this.hierarchyManager.getLeaders();
48
+ const leaders = this.node.getLeaders();
52
49
  for (const leader of leaders) {
53
50
  targets.push({ address: leader, role: 'leader' });
54
51
  }
55
52
  }
56
53
  // Collect parent
57
54
  if (this.config.checkParent && !isLeaderNode) {
58
- const parents = this.hierarchyManager.getParents();
59
- for (const parent of parents) {
55
+ // Use this.node.parent getter to get the current parent address with transports
56
+ // rather than getParents() which may have a stale reference
57
+ const parent = this.node.parent;
58
+ this.logger.debug('Parent address:', parent);
59
+ if (parent) {
60
60
  targets.push({ address: parent, role: 'parent' });
61
61
  }
62
62
  }
63
63
  // Collect children
64
64
  if (this.config.checkChildren) {
65
- const children = this.hierarchyManager.getChildren();
65
+ const children = this.node.getChildren();
66
66
  for (const child of children) {
67
67
  targets.push({ address: child, role: 'child' });
68
68
  }
@@ -70,12 +70,17 @@ export class oConnectionHeartbeatManager extends oObject {
70
70
  // Ping all targets in parallel
71
71
  await Promise.allSettled(targets.map((target) => this.pingTarget(target.address, target.role)));
72
72
  }
73
+ doPing(address) {
74
+ return this.node.use(address, {
75
+ method: 'ping',
76
+ params: {},
77
+ });
78
+ }
73
79
  async pingTarget(address, role) {
74
80
  if (!address.libp2pTransports.length) {
75
- this.logger.warn(`No transports found for ${address}`);
81
+ this.logger.debug(`${role} has no transports, skipping ping`, address);
76
82
  return;
77
83
  }
78
- const transports = address.libp2pTransports;
79
84
  const key = address.toString();
80
85
  let health = this.healthMap.get(key);
81
86
  if (!health) {
@@ -98,10 +103,7 @@ export class oConnectionHeartbeatManager extends oObject {
98
103
  });
99
104
  // Race between ping and timeout
100
105
  // The ping service accepts PeerId as string or object
101
- await Promise.race([
102
- this.p2pNode.services.ping.ping(transports[0].toMultiaddr()),
103
- timeoutPromise,
104
- ]);
106
+ await Promise.race([this.doPing(address), timeoutPromise]);
105
107
  const latency = Date.now() - startTime;
106
108
  // Success - update health
107
109
  health.lastSuccessfulPing = Date.now();
@@ -121,7 +123,7 @@ export class oConnectionHeartbeatManager extends oObject {
121
123
  }
122
124
  catch (error) {
123
125
  health.consecutiveFailures++;
124
- this.logger.warn(`Ping failed: ${address} (failures: ${health.consecutiveFailures}/${this.config.failureThreshold})`);
126
+ this.logger.warn(`Ping failed: ${address} (failures: ${health.consecutiveFailures}/${this.config.failureThreshold})`, error);
125
127
  // Update status based on failure count
126
128
  if (health.consecutiveFailures >= this.config.failureThreshold) {
127
129
  this.handleConnectionDead(address, role, health);
@@ -141,20 +143,20 @@ export class oConnectionHeartbeatManager extends oObject {
141
143
  // Emit events based on role
142
144
  if (role === 'child') {
143
145
  // Remove dead child from hierarchy
144
- this.hierarchyManager.removeChild(address);
146
+ this.node.removeChild(address);
145
147
  // Emit child left event
146
- this.notificationManager.emit(new ChildLeftEvent({
147
- source: this.address,
148
+ this.node.notificationManager.emit(new ChildLeftEvent({
149
+ source: this.node.address,
148
150
  childAddress: address,
149
- parentAddress: this.address,
151
+ parentAddress: this.node.address,
150
152
  reason: `heartbeat_failed_${health.consecutiveFailures}_times`,
151
153
  }));
152
154
  this.logger.warn(`Removed dead child: ${address}`);
153
155
  }
154
156
  else if (role === 'parent') {
155
157
  // Emit parent disconnected event
156
- this.notificationManager.emit(new ParentDisconnectedEvent({
157
- source: this.address,
158
+ this.node.notificationManager.emit(new ParentDisconnectedEvent({
159
+ source: this.node.address,
158
160
  parentAddress: address,
159
161
  reason: `heartbeat_failed_${health.consecutiveFailures}_times`,
160
162
  }));
@@ -163,8 +165,8 @@ export class oConnectionHeartbeatManager extends oObject {
163
165
  }
164
166
  else if (role === 'leader') {
165
167
  // Emit leader disconnected event
166
- this.notificationManager.emit(new LeaderDisconnectedEvent({
167
- source: this.address,
168
+ this.node.notificationManager.emit(new LeaderDisconnectedEvent({
169
+ source: this.node.address,
168
170
  leaderAddress: address,
169
171
  reason: `heartbeat_failed_${health.consecutiveFailures}_times`,
170
172
  }));
@@ -175,8 +177,8 @@ export class oConnectionHeartbeatManager extends oObject {
175
177
  emitConnectionDegradedEvent(address, role, failures) {
176
178
  // ConnectionDegradedEvent only supports parent/child, so we map leader to parent
177
179
  const eventRole = role === 'leader' ? 'parent' : role === 'child' ? 'child' : 'parent';
178
- this.notificationManager.emit(new ConnectionDegradedEvent({
179
- source: this.address,
180
+ this.node.notificationManager.emit(new ConnectionDegradedEvent({
181
+ source: this.node.address,
180
182
  targetAddress: address,
181
183
  role: eventRole,
182
184
  consecutiveFailures: failures,
@@ -185,8 +187,8 @@ export class oConnectionHeartbeatManager extends oObject {
185
187
  emitConnectionRecoveredEvent(address, role) {
186
188
  // ConnectionRecoveredEvent only supports parent/child, so we map leader to parent
187
189
  const eventRole = role === 'leader' ? 'parent' : role === 'child' ? 'child' : 'parent';
188
- this.notificationManager.emit(new ConnectionRecoveredEvent({
189
- source: this.address,
190
+ this.node.notificationManager.emit(new ConnectionRecoveredEvent({
191
+ source: this.node.address,
190
192
  targetAddress: address,
191
193
  role: eventRole,
192
194
  }));
@@ -41,7 +41,7 @@ export declare class oReconnectionManager extends oObject {
41
41
  /**
42
42
  * Wait for non-leader parent to appear in registry and reconnect
43
43
  */
44
- private waitForParentAndReconnect;
44
+ waitForParentAndReconnect(): Promise<void>;
45
45
  private handleReconnectionFailure;
46
46
  private calculateNodeLevel;
47
47
  private calculateBackoffDelay;
@@ -1 +1 @@
1
- {"version":3,"file":"o-reconnection.manager.d.ts","sourceRoot":"","sources":["../../../src/managers/o-reconnection.manager.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EAQR,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAI3E,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,yBAAyB,EAAE,MAAM,CAAC;IAClC,yBAAyB,EAAE,MAAM,CAAC;CACnC;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,oBAAqB,SAAQ,OAAO;IAI7C,OAAO,CAAC,IAAI;IACZ,OAAO,CAAC,MAAM;IAJhB,OAAO,CAAC,YAAY,CAAS;gBAGnB,IAAI,EAAE,kBAAkB,EACxB,MAAM,EAAE,kBAAkB;IAMpC,OAAO,CAAC,mBAAmB;YAoBb,wBAAwB;YAaxB,wBAAwB;YAexB,wBAAwB;IAehC,mBAAmB;YAkDX,2BAA2B;YAiB3B,iBAAiB;IAgB/B;;;OAGG;YACW,yBAAyB;IA8EvC;;OAEG;YACW,yBAAyB;IA8FvC,OAAO,CAAC,yBAAyB;IAajC,OAAO,CAAC,kBAAkB;IAI1B,OAAO,CAAC,qBAAqB;IAK7B,OAAO,CAAC,KAAK;CAGd"}
1
+ {"version":3,"file":"o-reconnection.manager.d.ts","sourceRoot":"","sources":["../../../src/managers/o-reconnection.manager.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EAQR,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAI3E,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,yBAAyB,EAAE,MAAM,CAAC;IAClC,yBAAyB,EAAE,MAAM,CAAC;CACnC;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,oBAAqB,SAAQ,OAAO;IAI7C,OAAO,CAAC,IAAI;IACZ,OAAO,CAAC,MAAM;IAJhB,OAAO,CAAC,YAAY,CAAS;gBAGnB,IAAI,EAAE,kBAAkB,EACxB,MAAM,EAAE,kBAAkB;IAMpC,OAAO,CAAC,mBAAmB;YAoBb,wBAAwB;YAaxB,wBAAwB;YAexB,wBAAwB;IAehC,mBAAmB;YAgDX,2BAA2B;YAiB3B,iBAAiB;IAkB/B;;;OAGG;YACW,yBAAyB;IAiFvC;;OAEG;IACG,yBAAyB;IAiG/B,OAAO,CAAC,yBAAyB;IAajC,OAAO,CAAC,kBAAkB;IAI1B,OAAO,CAAC,qBAAqB;IAK7B,OAAO,CAAC,KAAK;CAGd"}
@@ -45,6 +45,7 @@ export declare class oNode extends oToolBase {
45
45
  configure(): Promise<Libp2pConfig>;
46
46
  protected createNode(): Promise<Libp2p>;
47
47
  connect(nextHopAddress: oNodeAddress, targetAddress: oNodeAddress): Promise<oNodeConnection>;
48
+ postInitialize(): Promise<void>;
48
49
  initialize(): Promise<void>;
49
50
  /**
50
51
  * Override use() to wrap leader/registry requests with retry logic
@@ -57,5 +58,9 @@ export declare class oNode extends oToolBase {
57
58
  id?: string;
58
59
  }): Promise<any>;
59
60
  teardown(): Promise<void>;
61
+ getLeaders(): oNodeAddress[];
62
+ getParents(): oNodeAddress[];
63
+ getChildren(): oNodeAddress[];
64
+ removeChild(childAddress: oNodeAddress): void;
60
65
  }
61
66
  //# sourceMappingURL=o-node.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"o-node.d.ts","sourceRoot":"","sources":["../../src/o-node.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,MAAM,EACN,YAAY,EACb,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEzC,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAIL,QAAQ,EACR,QAAQ,EAER,oBAAoB,EACrB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACpE,OAAO,EAAE,sBAAsB,EAAE,MAAM,2CAA2C,CAAC;AAGnF,OAAO,EAAmB,SAAS,EAAE,MAAM,eAAe,CAAC;AAI3D,OAAO,EAAE,2BAA2B,EAAE,MAAM,8CAA8C,CAAC;AAC3F,OAAO,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAC5E,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAEzE,qBAAa,KAAM,SAAQ,SAAS;IAC3B,MAAM,EAAG,MAAM,CAAC;IAChB,OAAO,EAAG,MAAM,CAAC;IACjB,OAAO,EAAG,YAAY,CAAC;IACvB,MAAM,EAAE,WAAW,CAAC;IACpB,iBAAiB,EAAG,sBAAsB,CAAC;IAC3C,gBAAgB,EAAG,qBAAqB,CAAC;IACzC,0BAA0B,CAAC,EAAE,2BAA2B,CAAC;IACzD,mBAAmB,CAAC,EAAE,oBAAoB,CAAC;IAC3C,oBAAoB,EAAG,oBAAoB,CAAC;IACnD,SAAS,CAAC,WAAW,EAAE,OAAO,CAAS;gBAE3B,MAAM,EAAE,WAAW;IAK/B,IAAI,MAAM,IAAI,YAAY,GAAG,IAAI,CAEhC;IAED,IAAI,aAAa,IAAI,YAAY,CAKhC;IAED,IAAI,YAAY,IAAI,MAAM,GAAG,IAAI,CAOhC;IAED,mBAAmB,IAAI,GAAG,EAAE;IAItB,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IASvC,SAAS,CAAC,yBAAyB,IAAI,oBAAoB;IAQ3D,IAAI,aAAa,IAAI,YAAY,CAEhC;IAED,IAAI,gBAAgB,IAAI,cAAc,EAAE,CAEvC;IAED,IAAI,UAAU,IAAI,cAAc,EAAE,CAIjC;IAEK,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAsD3B,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IA2B/B,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAwC/B,aAAa,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM;IAItC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAetB,mBAAmB,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC;IAG1D;;;OAGG;IACG,SAAS,IAAI,OAAO,CAAC,YAAY,CAAC;cA0FxB,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;IAMvC,OAAO,CACX,cAAc,EAAE,YAAY,EAC5B,aAAa,EAAE,YAAY,GAC1B,OAAO,CAAC,eAAe,CAAC;IA0BrB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAyGjC;;OAEG;IACG,GAAG,CACP,OAAO,EAAE,QAAQ,EACjB,IAAI,CAAC,EAAE;QACL,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,MAAM,CAAC,EAAE;YAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;SAAE,CAAC;QAChC,EAAE,CAAC,EAAE,MAAM,CAAC;KACb,GACA,OAAO,CAAC,GAAG,CAAC;IAST,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAYhC"}
1
+ {"version":3,"file":"o-node.d.ts","sourceRoot":"","sources":["../../src/o-node.ts"],"names":[],"mappings":"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"}
@@ -110,11 +110,20 @@ export class oNode extends oToolBase {
110
110
  this.logger.debug('Skipping parent registration, node is leader');
111
111
  return;
112
112
  }
113
+ if (!this.parent?.libp2pTransports?.length) {
114
+ this.logger.debug('Parent has no transports, waiting for reconnection & leader ack');
115
+ if (this.parent?.toString() === oAddress.leader().toString()) {
116
+ this.parent.setTransports(this.leader?.libp2pTransports || []);
117
+ }
118
+ else {
119
+ await this.reconnectionManager?.waitForParentAndReconnect();
120
+ }
121
+ }
113
122
  // if no parent transports, register with the parent to get them
114
123
  // TODO: should we remove the transports check to make this more consistent?
115
- if (this.config.parent && this.config.parent.transports.length === 0) {
124
+ if (this.config.parent) {
116
125
  this.logger.debug('Registering node with parent...', this.config.parent);
117
- const parentRegistration = await this.use(this.config.parent, {
126
+ await this.use(this.config.parent, {
118
127
  method: 'child_register',
119
128
  params: {
120
129
  address: this.address.toString(),
@@ -123,9 +132,6 @@ export class oNode extends oToolBase {
123
132
  _token: this.config.joinToken,
124
133
  },
125
134
  });
126
- const { parentTransports } = parentRegistration.result.data;
127
- // update the parent transports
128
- this.config.parent.setTransports(parentTransports.map((t) => new oNodeTransport(t)));
129
135
  }
130
136
  }
131
137
  async register() {
@@ -281,6 +287,20 @@ export class oNode extends oToolBase {
281
287
  }
282
288
  return connection;
283
289
  }
290
+ async postInitialize() {
291
+ // Initialize connection heartbeat manager
292
+ this.connectionHeartbeatManager = new oConnectionHeartbeatManager(this, {
293
+ enabled: this.config.connectionHeartbeat?.enabled ?? true,
294
+ intervalMs: this.config.connectionHeartbeat?.intervalMs ?? 15000,
295
+ timeoutMs: this.config.connectionHeartbeat?.timeoutMs ?? 15000,
296
+ failureThreshold: this.config.connectionHeartbeat?.failureThreshold ?? 3,
297
+ checkChildren: this.config.connectionHeartbeat?.checkChildren ?? false,
298
+ checkParent: this.config.connectionHeartbeat?.checkParent ?? true,
299
+ checkLeader: true,
300
+ });
301
+ this.logger.info(`Connection heartbeat config: leader=${this.connectionHeartbeatManager.getConfig().checkLeader}, ` +
302
+ `parent=${this.connectionHeartbeatManager.getConfig().checkParent}`);
303
+ }
284
304
  async initialize() {
285
305
  this.logger.debug('Initializing node...');
286
306
  if (this.p2pNode && this.state !== NodeState.STOPPED) {
@@ -328,18 +348,6 @@ export class oNode extends oToolBase {
328
348
  // Read ENABLE_LEADER_HEARTBEAT environment variable
329
349
  const enableLeaderHeartbeat = this.parent?.toString() === oAddress.leader().toString();
330
350
  this.logger.debug(`Enable leader heartbeat: ${enableLeaderHeartbeat}`);
331
- // Initialize connection heartbeat manager
332
- this.connectionHeartbeatManager = new oConnectionHeartbeatManager(this.p2pNode, this.hierarchyManager, this.notificationManager, this.address, {
333
- enabled: this.config.connectionHeartbeat?.enabled ?? true,
334
- intervalMs: this.config.connectionHeartbeat?.intervalMs ?? 15000,
335
- timeoutMs: this.config.connectionHeartbeat?.timeoutMs ?? 5000,
336
- failureThreshold: this.config.connectionHeartbeat?.failureThreshold ?? 3,
337
- checkChildren: this.config.connectionHeartbeat?.checkChildren ?? true,
338
- checkParent: this.config.connectionHeartbeat?.checkParent ?? true,
339
- checkLeader: enableLeaderHeartbeat,
340
- });
341
- this.logger.info(`Connection heartbeat config: leader=${this.connectionHeartbeatManager.getConfig().checkLeader}, ` +
342
- `parent=${this.connectionHeartbeatManager.getConfig().checkParent}`);
343
351
  // Initialize reconnection manager
344
352
  if (this.config.reconnection?.enabled !== false) {
345
353
  this.reconnectionManager = new oReconnectionManager(this, {
@@ -371,4 +379,17 @@ export class oNode extends oToolBase {
371
379
  await this.p2pNode.stop();
372
380
  }
373
381
  }
382
+ // IHeartbeatableNode interface methods
383
+ getLeaders() {
384
+ return [this.leader];
385
+ }
386
+ getParents() {
387
+ return this.hierarchyManager.getParents();
388
+ }
389
+ getChildren() {
390
+ return this.hierarchyManager.getChildren();
391
+ }
392
+ removeChild(childAddress) {
393
+ this.hierarchyManager.removeChild(childAddress);
394
+ }
374
395
  }
@@ -21,7 +21,8 @@ export class oNodeRoutingPolicy extends oRoutingPolicy {
21
21
  nodeAddress.libp2pTransports?.length > 0) {
22
22
  // transports are provided, let's see if they match our known leaders
23
23
  const isLeaderRef = nodeAddress.toString() === oAddress.leader().toString();
24
- const isOurLeaderRef = node.hierarchyManager.leaders.some((l) => l.equals(nodeAddress));
24
+ const isOurLeaderRef = node.address.equals(nodeAddress) ||
25
+ node.hierarchyManager.leaders.some((l) => l.equals(nodeAddress));
25
26
  return isLeaderRef || isOurLeaderRef;
26
27
  }
27
28
  return true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@olane/o-node",
3
- "version": "0.7.12-alpha.12",
3
+ "version": "0.7.12-alpha.13",
4
4
  "type": "module",
5
5
  "main": "dist/src/index.js",
6
6
  "types": "dist/src/index.d.ts",
@@ -54,12 +54,12 @@
54
54
  "typescript": "5.4.5"
55
55
  },
56
56
  "dependencies": {
57
- "@olane/o-config": "0.7.12-alpha.12",
58
- "@olane/o-core": "0.7.12-alpha.12",
59
- "@olane/o-protocol": "0.7.12-alpha.12",
60
- "@olane/o-tool": "0.7.12-alpha.12",
57
+ "@olane/o-config": "0.7.12-alpha.13",
58
+ "@olane/o-core": "0.7.12-alpha.13",
59
+ "@olane/o-protocol": "0.7.12-alpha.13",
60
+ "@olane/o-tool": "0.7.12-alpha.13",
61
61
  "debug": "^4.4.1",
62
62
  "dotenv": "^16.5.0"
63
63
  },
64
- "gitHead": "590e95c1281ce1df427ba57816cd825c9f52154e"
64
+ "gitHead": "dad019b117feb02f74eeec70de9ee82b76b68f6c"
65
65
  }