@olane/o-node 0.7.12-alpha.21 → 0.7.12-alpha.23

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 (175) hide show
  1. package/dist/o-core/src/connection/o-response.d.ts +26 -0
  2. package/dist/o-core/src/connection/o-response.d.ts.map +1 -0
  3. package/dist/o-core/src/connection/o-response.js +45 -0
  4. package/dist/o-core/src/error/enums/codes.error.d.ts +20 -0
  5. package/dist/o-core/src/error/enums/codes.error.d.ts.map +1 -0
  6. package/dist/o-core/src/error/enums/codes.error.js +20 -0
  7. package/dist/o-core/src/error/interfaces/o-error.interface.d.ts +6 -0
  8. package/dist/o-core/src/error/interfaces/o-error.interface.d.ts.map +1 -0
  9. package/dist/o-core/src/error/interfaces/o-error.interface.js +1 -0
  10. package/dist/o-core/src/error/o-error.d.ts +15 -0
  11. package/dist/o-core/src/error/o-error.d.ts.map +1 -0
  12. package/dist/o-core/src/error/o-error.js +27 -0
  13. package/dist/o-core/src/streaming/index.d.ts +11 -0
  14. package/dist/o-core/src/streaming/index.d.ts.map +1 -0
  15. package/dist/o-core/src/streaming/index.js +14 -0
  16. package/dist/o-core/src/streaming/protocol-builder.d.ts +62 -0
  17. package/dist/o-core/src/streaming/protocol-builder.d.ts.map +1 -0
  18. package/dist/o-core/src/streaming/protocol-builder.js +93 -0
  19. package/dist/o-core/src/streaming/stream-config.d.ts +36 -0
  20. package/dist/o-core/src/streaming/stream-config.d.ts.map +1 -0
  21. package/dist/o-core/src/streaming/stream-config.js +19 -0
  22. package/dist/o-core/src/streaming/stream-handler.base.d.ts +85 -0
  23. package/dist/o-core/src/streaming/stream-handler.base.d.ts.map +1 -0
  24. package/dist/o-core/src/streaming/stream-handler.base.js +112 -0
  25. package/dist/o-core/src/streaming/stream-transport.interface.d.ts +61 -0
  26. package/dist/o-core/src/streaming/stream-transport.interface.d.ts.map +1 -0
  27. package/dist/o-core/src/streaming/stream-transport.interface.js +10 -0
  28. package/dist/o-core/src/utils/streaming.utils.d.ts +37 -0
  29. package/dist/o-core/src/utils/streaming.utils.d.ts.map +1 -0
  30. package/dist/o-core/src/utils/streaming.utils.js +71 -0
  31. package/dist/o-node/src/connection/index.d.ts +5 -0
  32. package/dist/o-node/src/connection/index.d.ts.map +1 -0
  33. package/dist/o-node/src/connection/index.js +4 -0
  34. package/dist/o-node/src/connection/interfaces/o-node-connection-manager.config.d.ts +6 -0
  35. package/dist/o-node/src/connection/interfaces/o-node-connection-manager.config.d.ts.map +1 -0
  36. package/dist/o-node/src/connection/interfaces/o-node-connection-manager.config.js +1 -0
  37. package/dist/o-node/src/connection/interfaces/o-node-connection.config.d.ts +6 -0
  38. package/dist/o-node/src/connection/interfaces/o-node-connection.config.d.ts.map +1 -0
  39. package/dist/o-node/src/connection/interfaces/o-node-connection.config.js +1 -0
  40. package/dist/o-node/src/connection/o-node-connection.d.ts +20 -0
  41. package/dist/o-node/src/connection/o-node-connection.d.ts.map +1 -0
  42. package/dist/o-node/src/connection/o-node-connection.js +146 -0
  43. package/dist/o-node/src/connection/o-node-connection.manager.d.ts +19 -0
  44. package/dist/o-node/src/connection/o-node-connection.manager.d.ts.map +1 -0
  45. package/dist/o-node/src/connection/o-node-connection.manager.js +92 -0
  46. package/dist/o-node/src/index.d.ts +10 -0
  47. package/dist/o-node/src/index.d.ts.map +1 -0
  48. package/dist/o-node/src/index.js +9 -0
  49. package/dist/o-node/src/interfaces/i-heartbeatable-node.d.ts +49 -0
  50. package/dist/o-node/src/interfaces/i-heartbeatable-node.d.ts.map +1 -0
  51. package/dist/o-node/src/interfaces/i-heartbeatable-node.js +1 -0
  52. package/dist/o-node/src/interfaces/i-reconnectable-node.d.ts +46 -0
  53. package/dist/o-node/src/interfaces/i-reconnectable-node.d.ts.map +1 -0
  54. package/dist/o-node/src/interfaces/i-reconnectable-node.js +1 -0
  55. package/dist/o-node/src/interfaces/o-node.config.d.ts +66 -0
  56. package/dist/o-node/src/interfaces/o-node.config.d.ts.map +1 -0
  57. package/dist/o-node/src/interfaces/o-node.config.js +1 -0
  58. package/dist/o-node/src/interfaces/o-node.tool-config.d.ts +4 -0
  59. package/dist/o-node/src/interfaces/o-node.tool-config.d.ts.map +1 -0
  60. package/dist/o-node/src/interfaces/o-node.tool-config.js +1 -0
  61. package/dist/o-node/src/lib/network-activity.lib.d.ts +1 -0
  62. package/dist/o-node/src/lib/network-activity.lib.d.ts.map +1 -0
  63. package/dist/o-node/src/lib/network-activity.lib.js +34 -0
  64. package/dist/o-node/src/managers/o-connection-heartbeat.manager.d.ts +62 -0
  65. package/dist/o-node/src/managers/o-connection-heartbeat.manager.d.ts.map +1 -0
  66. package/dist/o-node/src/managers/o-connection-heartbeat.manager.js +213 -0
  67. package/dist/o-node/src/managers/o-reconnection.manager.d.ts +51 -0
  68. package/dist/o-node/src/managers/o-reconnection.manager.d.ts.map +1 -0
  69. package/dist/o-node/src/managers/o-reconnection.manager.js +266 -0
  70. package/dist/o-node/src/nodes/client.node.d.ts +7 -0
  71. package/dist/o-node/src/nodes/client.node.d.ts.map +1 -0
  72. package/dist/o-node/src/nodes/client.node.js +16 -0
  73. package/dist/o-node/src/nodes/index.d.ts +4 -0
  74. package/dist/o-node/src/nodes/index.d.ts.map +1 -0
  75. package/dist/o-node/src/nodes/index.js +3 -0
  76. package/dist/o-node/src/nodes/server.node.d.ts +7 -0
  77. package/dist/o-node/src/nodes/server.node.d.ts.map +1 -0
  78. package/dist/o-node/src/nodes/server.node.js +20 -0
  79. package/dist/o-node/src/nodes/websocket.node.d.ts +7 -0
  80. package/dist/o-node/src/nodes/websocket.node.d.ts.map +1 -0
  81. package/dist/o-node/src/nodes/websocket.node.js +18 -0
  82. package/dist/o-node/src/o-node.d.ts +72 -0
  83. package/dist/o-node/src/o-node.d.ts.map +1 -0
  84. package/dist/o-node/src/o-node.hierarchy-manager.d.ts +15 -0
  85. package/dist/o-node/src/o-node.hierarchy-manager.d.ts.map +1 -0
  86. package/dist/o-node/src/o-node.hierarchy-manager.js +15 -0
  87. package/dist/o-node/src/o-node.js +420 -0
  88. package/dist/o-node/src/o-node.notification-manager.d.ts +52 -0
  89. package/dist/o-node/src/o-node.notification-manager.d.ts.map +1 -0
  90. package/dist/o-node/src/o-node.notification-manager.js +185 -0
  91. package/dist/o-node/src/o-node.tool.d.ts +18 -0
  92. package/dist/o-node/src/o-node.tool.d.ts.map +1 -0
  93. package/dist/o-node/src/o-node.tool.js +116 -0
  94. package/dist/o-node/src/router/index.d.ts +6 -0
  95. package/dist/o-node/src/router/index.d.ts.map +1 -0
  96. package/dist/o-node/src/router/index.js +5 -0
  97. package/dist/o-node/src/router/interfaces/o-node-router.config.d.ts +3 -0
  98. package/dist/o-node/src/router/interfaces/o-node-router.config.d.ts.map +1 -0
  99. package/dist/o-node/src/router/interfaces/o-node-router.config.js +1 -0
  100. package/dist/o-node/src/router/interfaces/o-node-router.response.d.ts +8 -0
  101. package/dist/o-node/src/router/interfaces/o-node-router.response.d.ts.map +1 -0
  102. package/dist/o-node/src/router/interfaces/o-node-router.response.js +1 -0
  103. package/dist/o-node/src/router/o-node.address.d.ts +18 -0
  104. package/dist/o-node/src/router/o-node.address.d.ts.map +1 -0
  105. package/dist/o-node/src/router/o-node.address.js +29 -0
  106. package/dist/o-node/src/router/o-node.router.d.ts +45 -0
  107. package/dist/o-node/src/router/o-node.router.d.ts.map +1 -0
  108. package/dist/o-node/src/router/o-node.router.js +125 -0
  109. package/dist/o-node/src/router/o-node.routing-policy.d.ts +30 -0
  110. package/dist/o-node/src/router/o-node.routing-policy.d.ts.map +1 -0
  111. package/dist/o-node/src/router/o-node.routing-policy.js +57 -0
  112. package/dist/o-node/src/router/o-node.transport.d.ts +11 -0
  113. package/dist/o-node/src/router/o-node.transport.d.ts.map +1 -0
  114. package/dist/o-node/src/router/o-node.transport.js +18 -0
  115. package/dist/o-node/src/router/resolvers/index.d.ts +4 -0
  116. package/dist/o-node/src/router/resolvers/index.d.ts.map +1 -0
  117. package/dist/o-node/src/router/resolvers/index.js +3 -0
  118. package/dist/o-node/src/router/resolvers/o-node.leader-resolver-fallback.d.ts +8 -0
  119. package/dist/o-node/src/router/resolvers/o-node.leader-resolver-fallback.d.ts.map +1 -0
  120. package/dist/o-node/src/router/resolvers/o-node.leader-resolver-fallback.js +35 -0
  121. package/dist/o-node/src/router/resolvers/o-node.resolver.d.ts +11 -0
  122. package/dist/o-node/src/router/resolvers/o-node.resolver.d.ts.map +1 -0
  123. package/dist/o-node/src/router/resolvers/o-node.resolver.js +41 -0
  124. package/dist/o-node/src/router/resolvers/o-node.search-resolver.d.ts +170 -0
  125. package/dist/o-node/src/router/resolvers/o-node.search-resolver.d.ts.map +1 -0
  126. package/dist/o-node/src/router/resolvers/o-node.search-resolver.js +285 -0
  127. package/dist/o-node/src/router/route.request.d.ts +14 -0
  128. package/dist/o-node/src/router/route.request.d.ts.map +1 -0
  129. package/dist/o-node/src/router/route.request.js +1 -0
  130. package/dist/o-node/src/streaming/index.d.ts +10 -0
  131. package/dist/o-node/src/streaming/index.d.ts.map +1 -0
  132. package/dist/o-node/src/streaming/index.js +12 -0
  133. package/dist/o-node/src/streaming/libp2p-stream-transport.d.ts +50 -0
  134. package/dist/o-node/src/streaming/libp2p-stream-transport.d.ts.map +1 -0
  135. package/dist/o-node/src/streaming/libp2p-stream-transport.js +137 -0
  136. package/dist/o-node/src/streaming/node-stream-handler.d.ts +65 -0
  137. package/dist/o-node/src/streaming/node-stream-handler.d.ts.map +1 -0
  138. package/dist/o-node/src/streaming/node-stream-handler.js +101 -0
  139. package/dist/o-node/src/utils/circuit-breaker.d.ts +107 -0
  140. package/dist/o-node/src/utils/circuit-breaker.d.ts.map +1 -0
  141. package/dist/o-node/src/utils/circuit-breaker.js +175 -0
  142. package/dist/o-node/src/utils/circuit-breaker.test.d.ts +2 -0
  143. package/dist/o-node/src/utils/circuit-breaker.test.d.ts.map +1 -0
  144. package/dist/o-node/src/utils/circuit-breaker.test.js +262 -0
  145. package/dist/o-node/src/utils/leader-request-wrapper.d.ts +66 -0
  146. package/dist/o-node/src/utils/leader-request-wrapper.d.ts.map +1 -0
  147. package/dist/o-node/src/utils/leader-request-wrapper.js +160 -0
  148. package/dist/o-node/src/utils/leader-request-wrapper.test.d.ts +1 -0
  149. package/dist/o-node/src/utils/leader-request-wrapper.test.d.ts.map +1 -0
  150. package/dist/o-node/src/utils/leader-request-wrapper.test.js +246 -0
  151. package/dist/o-node/src/utils/network.utils.d.ts +20 -0
  152. package/dist/o-node/src/utils/network.utils.d.ts.map +1 -0
  153. package/dist/o-node/src/utils/network.utils.js +74 -0
  154. package/dist/o-node/test/o-node.spec.d.ts +2 -0
  155. package/dist/o-node/test/o-node.spec.d.ts.map +1 -0
  156. package/dist/o-node/test/o-node.spec.js +20 -0
  157. package/dist/o-node/test/search-resolver.spec.d.ts +2 -0
  158. package/dist/o-node/test/search-resolver.spec.d.ts.map +1 -0
  159. package/dist/o-node/test/search-resolver.spec.js +693 -0
  160. package/dist/src/connection/o-node-connection.d.ts +7 -0
  161. package/dist/src/connection/o-node-connection.d.ts.map +1 -1
  162. package/dist/src/connection/o-node-connection.js +89 -2
  163. package/dist/src/connection/o-node-connection.manager.d.ts +2 -0
  164. package/dist/src/connection/o-node-connection.manager.d.ts.map +1 -1
  165. package/dist/src/connection/o-node-connection.manager.js +5 -1
  166. package/dist/src/interfaces/o-node.config.d.ts +16 -0
  167. package/dist/src/interfaces/o-node.config.d.ts.map +1 -1
  168. package/dist/src/o-node.d.ts +1 -1
  169. package/dist/src/o-node.d.ts.map +1 -1
  170. package/dist/src/o-node.js +5 -1
  171. package/dist/src/o-node.tool.d.ts.map +1 -1
  172. package/dist/src/o-node.tool.js +37 -7
  173. package/dist/src/router/resolvers/o-node.search-resolver.d.ts.map +1 -1
  174. package/dist/src/router/resolvers/o-node.search-resolver.js +10 -3
  175. package/package.json +6 -6
@@ -0,0 +1,266 @@
1
+ import { oObject, oAddress, NodeState, } from '@olane/o-core';
2
+ import { oNodeAddress } from '../router/o-node.address.js';
3
+ import { oNodeTransport } from '../router/o-node.transport.js';
4
+ /**
5
+ * Reconnection Manager
6
+ *
7
+ * Automatically attempts to reconnect to parent when connection is lost.
8
+ *
9
+ * Strategy:
10
+ * 1. Listen for ParentDisconnectedEvent (from heartbeat or libp2p)
11
+ * 2. Attempt direct reconnection with exponential backoff
12
+ * 3. If direct reconnection fails, query leader for new parent
13
+ * 4. Register with new parent and continue operation
14
+ * 5. If all attempts fail, transition node to ERROR state
15
+ */
16
+ export class oReconnectionManager extends oObject {
17
+ constructor(node, config) {
18
+ super();
19
+ this.node = node;
20
+ this.config = config;
21
+ this.reconnecting = false;
22
+ this.setupEventListeners();
23
+ }
24
+ setupEventListeners() {
25
+ // Listen for parent disconnection (from heartbeat or libp2p)
26
+ this.node.notificationManager.on('parent:disconnected', this.handleParentDisconnected.bind(this));
27
+ // Listen for leader disconnection (from heartbeat)
28
+ this.node.notificationManager.on('leader:disconnected', this.handleLeaderDisconnected.bind(this));
29
+ // Listen for connection degradation as early warning
30
+ this.node.notificationManager.on('connection:degraded', this.handleConnectionDegraded.bind(this));
31
+ this.node.notificationManager.on('node:connected', this.handleNodeConnected.bind(this));
32
+ }
33
+ async handleNodeConnected(event) {
34
+ const connectedEvent = event;
35
+ if (connectedEvent.nodeAddress.toString() === oAddress.leader().toString()) {
36
+ // the leader is back online, let's re-register & tell sub-graphs to re-register
37
+ await this.node.useSelf({
38
+ method: 'register_leader',
39
+ params: {},
40
+ });
41
+ }
42
+ }
43
+ async handleConnectionDegraded(event) {
44
+ const degradedEvent = event;
45
+ if (degradedEvent.role !== 'parent')
46
+ return;
47
+ this.logger.warn(`Parent connection degraded: ${degradedEvent.targetAddress} ` +
48
+ `(failures: ${degradedEvent.consecutiveFailures})`);
49
+ // Could implement pre-emptive parent discovery here
50
+ // For now, just log the warning and wait for full disconnection
51
+ }
52
+ async handleLeaderDisconnected(event) {
53
+ const disconnectEvent = event;
54
+ this.logger.warn(`Leader disconnected: ${disconnectEvent.leaderAddress} (reason: ${disconnectEvent.reason})`);
55
+ // Don't attempt reconnection for leader - the LeaderRequestWrapper
56
+ // will handle retries automatically when we make requests
57
+ // Just log the event for observability
58
+ this.logger.info('Leader requests will use automatic retry mechanism (LeaderRequestWrapper)');
59
+ }
60
+ async handleParentDisconnected(event) {
61
+ const disconnectEvent = event;
62
+ if (this.reconnecting) {
63
+ this.logger.debug('Already reconnecting, ignoring duplicate event');
64
+ return;
65
+ }
66
+ this.logger.warn(`Parent disconnected: ${disconnectEvent.parentAddress} (reason: ${disconnectEvent.reason})`);
67
+ await this.attemptReconnection();
68
+ }
69
+ async attemptReconnection() {
70
+ if (!this.config.enabled) {
71
+ this.logger.warn('Reconnection disabled - node will remain disconnected');
72
+ return;
73
+ }
74
+ this.reconnecting = true;
75
+ let attempt = 0;
76
+ while (attempt < this.config.maxAttempts) {
77
+ attempt++;
78
+ this.logger.info(`Reconnection attempt ${attempt}/${this.config.maxAttempts} to parent: ${this.node.config.parent}`);
79
+ try {
80
+ // Strategy 1: Try direct parent reconnection
81
+ await this.tryDirectParentReconnection();
82
+ // Success!
83
+ this.reconnecting = false;
84
+ this.logger.info(`Successfully reconnected to parent after ${attempt} attempts`);
85
+ return;
86
+ }
87
+ catch (error) {
88
+ this.logger.warn(`Reconnection attempt ${attempt} failed:`, error instanceof Error ? error.message : error);
89
+ if (attempt < this.config.maxAttempts) {
90
+ const delay = this.calculateBackoffDelay(attempt);
91
+ this.logger.debug(`Waiting ${delay}ms before next attempt...`);
92
+ await this.sleep(delay);
93
+ }
94
+ }
95
+ }
96
+ // All direct attempts failed - try leader fallback
97
+ if (this.config.useLeaderFallback) {
98
+ await this.tryLeaderFallback();
99
+ }
100
+ else {
101
+ this.handleReconnectionFailure();
102
+ }
103
+ }
104
+ async tryDirectParentReconnection() {
105
+ if (!this.node.config.parent) {
106
+ throw new Error('No parent configured');
107
+ }
108
+ // Re-register with parent (might have new transports)
109
+ await this.node.registerParent();
110
+ // Verify connection works with a ping
111
+ await this.node.use(this.node.config.parent, {
112
+ method: 'ping',
113
+ params: {},
114
+ });
115
+ this.logger.info('Direct parent reconnection successful');
116
+ }
117
+ async tryLeaderFallback() {
118
+ // Check if parent is the leader - special case
119
+ const parentIsLeader = this.node.config.parent?.toString() === oAddress.leader().toString();
120
+ if (parentIsLeader) {
121
+ this.logger.info('Parent is the leader - waiting for leader to become available');
122
+ await this.waitForLeaderAndReconnect();
123
+ }
124
+ else {
125
+ this.logger.info('Starting infinite parent discovery via leader registry');
126
+ await this.waitForParentAndReconnect();
127
+ }
128
+ }
129
+ /**
130
+ * Wait for leader to become available and reconnect
131
+ * Leader transports are static (configured), so we just need to detect when it's back
132
+ */
133
+ async waitForLeaderAndReconnect() {
134
+ const startTime = Date.now();
135
+ let attempt = 0;
136
+ let currentDelay = this.config.parentDiscoveryIntervalMs;
137
+ // Infinite retry loop - keep trying until leader is back
138
+ while (true) {
139
+ attempt++;
140
+ const elapsedMinutes = Math.floor((Date.now() - startTime) / 60000);
141
+ this.logger.info(`Leader discovery attempt ${attempt} (elapsed: ${elapsedMinutes}m)`);
142
+ try {
143
+ // Try to ping the leader using its configured transports
144
+ // The leader address should already have transports configured
145
+ await this.node.use(this.node.config.parent, {
146
+ method: 'ping',
147
+ params: {},
148
+ });
149
+ // Leader is back! Now re-register with parent and registry
150
+ this.logger.info(`Leader is back online after ${elapsedMinutes}m, re-registering...`);
151
+ try {
152
+ // Register with parent (leader)
153
+ await this.node.registerParent();
154
+ // Force re-registration with registry by resetting the flag
155
+ this.node.didRegister = false;
156
+ await this.node.register();
157
+ // Success!
158
+ this.reconnecting = false;
159
+ this.logger.info(`Successfully reconnected to leader and re-registered after ${elapsedMinutes}m`);
160
+ return;
161
+ }
162
+ catch (registrationError) {
163
+ this.logger.warn('Leader online but registration failed, will retry:', registrationError instanceof Error
164
+ ? registrationError.message
165
+ : registrationError);
166
+ // Fall through to retry with backoff
167
+ }
168
+ }
169
+ catch (error) {
170
+ // Leader not yet available
171
+ this.logger.debug(`Leader not yet available (will retry): ${error instanceof Error ? error.message : error}`);
172
+ }
173
+ // Calculate backoff delay
174
+ const delay = Math.min(currentDelay, this.config.parentDiscoveryMaxDelayMs);
175
+ // Log periodic status updates (every 5 minutes)
176
+ if (attempt % 30 === 0) {
177
+ this.logger.info(`Still waiting for leader to come back online... (${elapsedMinutes}m elapsed, ${attempt} attempts)`);
178
+ }
179
+ this.logger.debug(`Waiting ${delay}ms before next discovery attempt...`);
180
+ await this.sleep(delay);
181
+ // Exponential backoff for next iteration
182
+ currentDelay = Math.min(currentDelay * 2, this.config.parentDiscoveryMaxDelayMs);
183
+ }
184
+ }
185
+ /**
186
+ * Wait for non-leader parent to appear in registry and reconnect
187
+ */
188
+ async waitForParentAndReconnect() {
189
+ const startTime = Date.now();
190
+ let attempt = 0;
191
+ let currentDelay = this.config.parentDiscoveryIntervalMs;
192
+ // Infinite retry loop - keep trying until parent is found
193
+ while (true) {
194
+ attempt++;
195
+ const elapsedMinutes = Math.floor((Date.now() - startTime) / 60000);
196
+ this.logger.info(`Parent discovery attempt ${attempt} (elapsed: ${elapsedMinutes}m)`);
197
+ try {
198
+ // Query registry for parent by its known address
199
+ const response = await this.node.use(oAddress.registry(), {
200
+ method: 'find_available_parent',
201
+ params: {
202
+ parentAddress: this.node.config.parent?.toString(),
203
+ },
204
+ });
205
+ const { parentAddress, parentTransports } = response.result.data;
206
+ // Check if parent was found in registry
207
+ if (parentAddress && parentTransports && parentTransports.length > 0) {
208
+ this.logger.info(`Parent found in registry: ${parentAddress} with ${parentTransports.length} transports`);
209
+ // Update parent reference with fresh transports
210
+ this.node.config.parent = new oNodeAddress(parentAddress, parentTransports.map((t) => new oNodeTransport(t.value)));
211
+ // Attempt to register with parent and re-register with registry
212
+ try {
213
+ await this.tryDirectParentReconnection();
214
+ // Force re-registration with registry by resetting the flag
215
+ this.node.didRegister = false;
216
+ await this.node.register();
217
+ // Success!
218
+ this.reconnecting = false;
219
+ this.logger.info(`Successfully reconnected to parent and re-registered after ${elapsedMinutes}m of discovery attempts`);
220
+ return;
221
+ }
222
+ catch (registrationError) {
223
+ this.logger.warn('Parent found but registration failed, will retry:', registrationError instanceof Error
224
+ ? registrationError.message
225
+ : registrationError);
226
+ // Fall through to retry with backoff
227
+ }
228
+ }
229
+ else {
230
+ this.logger.debug(`Parent not yet available in registry: ${this.node.config.parent?.toString()}`);
231
+ }
232
+ }
233
+ catch (error) {
234
+ // Network error communicating with leader/registry
235
+ this.logger.warn('Error querying registry for parent (will retry):', error instanceof Error ? error.message : error);
236
+ }
237
+ // Calculate backoff delay with exponential increase, capped at max
238
+ const delay = Math.min(currentDelay, this.config.parentDiscoveryMaxDelayMs);
239
+ // Log periodic status updates (every 5 minutes)
240
+ if (attempt % 30 === 0) {
241
+ this.logger.info(`Still waiting for parent to appear in registry... (${elapsedMinutes}m elapsed, ${attempt} attempts)`);
242
+ }
243
+ this.logger.debug(`Waiting ${delay}ms before next discovery attempt...`);
244
+ await this.sleep(delay);
245
+ // Exponential backoff for next iteration
246
+ currentDelay = Math.min(currentDelay * 2, this.config.parentDiscoveryMaxDelayMs);
247
+ }
248
+ }
249
+ handleReconnectionFailure() {
250
+ this.reconnecting = false;
251
+ this.logger.error('Failed to reconnect to parent after all attempts - node in ERROR state');
252
+ // Transition to error state
253
+ this.node.state = NodeState.ERROR;
254
+ // Could emit custom event here for monitoring
255
+ }
256
+ calculateNodeLevel() {
257
+ return this.node.address.paths.length;
258
+ }
259
+ calculateBackoffDelay(attempt) {
260
+ const delay = this.config.baseDelayMs * Math.pow(2, attempt - 1);
261
+ return Math.min(delay, this.config.maxDelayMs);
262
+ }
263
+ sleep(ms) {
264
+ return new Promise((resolve) => setTimeout(resolve, ms));
265
+ }
266
+ }
@@ -0,0 +1,7 @@
1
+ import { oNode } from '../o-node.js';
2
+ import { oNodeConfig } from '../interfaces/o-node.config.js';
3
+ export declare class oClientNode extends oNode {
4
+ constructor(config: oNodeConfig);
5
+ configureTransports(): any[];
6
+ }
7
+ //# sourceMappingURL=client.node.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.node.d.ts","sourceRoot":"","sources":["../../../../src/nodes/client.node.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AACrC,OAAO,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAE7D,qBAAa,WAAY,SAAQ,KAAK;gBACxB,MAAM,EAAE,WAAW;IAU/B,mBAAmB,IAAI,GAAG,EAAE;CAG7B"}
@@ -0,0 +1,16 @@
1
+ import { defaultLibp2pConfig } from '@olane/o-config';
2
+ import { oNode } from '../o-node.js';
3
+ export class oClientNode extends oNode {
4
+ constructor(config) {
5
+ super({
6
+ ...config,
7
+ network: {
8
+ // clients cannot be dialed
9
+ listeners: [],
10
+ },
11
+ });
12
+ }
13
+ configureTransports() {
14
+ return [...(defaultLibp2pConfig.transports || [])];
15
+ }
16
+ }
@@ -0,0 +1,4 @@
1
+ export * from './client.node.js';
2
+ export * from './server.node.js';
3
+ export * from './websocket.node.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/nodes/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC"}
@@ -0,0 +1,3 @@
1
+ export * from './client.node.js';
2
+ export * from './server.node.js';
3
+ export * from './websocket.node.js';
@@ -0,0 +1,7 @@
1
+ import { oNode } from '../o-node.js';
2
+ import { oNodeConfig } from '../interfaces/o-node.config.js';
3
+ export declare class oServerNode extends oNode {
4
+ constructor(config: oNodeConfig);
5
+ configureTransports(): any[];
6
+ }
7
+ //# sourceMappingURL=server.node.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.node.d.ts","sourceRoot":"","sources":["../../../../src/nodes/server.node.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AACrC,OAAO,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAE7D,qBAAa,WAAY,SAAQ,KAAK;gBACxB,MAAM,EAAE,WAAW;IAc/B,mBAAmB,IAAI,GAAG,EAAE;CAG7B"}
@@ -0,0 +1,20 @@
1
+ import { defaultLibp2pConfig } from '@olane/o-config';
2
+ import { oNode } from '../o-node.js';
3
+ export class oServerNode extends oNode {
4
+ constructor(config) {
5
+ super({
6
+ ...config,
7
+ network: {
8
+ listeners: config.network?.listeners || [
9
+ '/ip4/0.0.0.0/tcp/0', // Plain TCP
10
+ '/ip4/0.0.0.0/tcp/0/ws', // WebSockets over TCP
11
+ '/ip6/::/tcp/0', // IPv6 TCP
12
+ '/ip6/::/tcp/0/ws', // IPv6 WebSockets
13
+ ],
14
+ },
15
+ });
16
+ }
17
+ configureTransports() {
18
+ return [...(defaultLibp2pConfig.transports || [])];
19
+ }
20
+ }
@@ -0,0 +1,7 @@
1
+ import { oNode } from '../o-node.js';
2
+ import { oNodeConfig } from '../interfaces/o-node.config.js';
3
+ export declare class oWebsocketNode extends oNode {
4
+ constructor(config: oNodeConfig);
5
+ configureTransports(): any[];
6
+ }
7
+ //# sourceMappingURL=websocket.node.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websocket.node.d.ts","sourceRoot":"","sources":["../../../../src/nodes/websocket.node.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AACrC,OAAO,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAE7D,qBAAa,cAAe,SAAQ,KAAK;gBAC3B,MAAM,EAAE,WAAW;IAY/B,mBAAmB,IAAI,GAAG,EAAE;CAG7B"}
@@ -0,0 +1,18 @@
1
+ import { defaultLibp2pConfig } from '@olane/o-config';
2
+ import { oNode } from '../o-node.js';
3
+ export class oWebsocketNode extends oNode {
4
+ constructor(config) {
5
+ super({
6
+ ...config,
7
+ network: {
8
+ listeners: config.network?.listeners || [
9
+ '/ip4/0.0.0.0/tcp/0/ws', // WebSockets over TCP
10
+ '/ip6/::/tcp/0/ws', // IPv6 WebSockets
11
+ ],
12
+ },
13
+ });
14
+ }
15
+ configureTransports() {
16
+ return [...(defaultLibp2pConfig.transports || [])];
17
+ }
18
+ }
@@ -0,0 +1,72 @@
1
+ import { Libp2p, Libp2pConfig } from '@olane/o-config';
2
+ import { PeerId } from '@olane/o-config';
3
+ import { oNodeHierarchyManager } from './o-node.hierarchy-manager.js';
4
+ import { oNodeConfig } from './interfaces/o-node.config.js';
5
+ import { oNodeTransport } from './router/o-node.transport.js';
6
+ import { oAddress, oRequest, oNotificationManager } from '@olane/o-core';
7
+ import { oNodeAddress } from './router/o-node.address.js';
8
+ import { oNodeConnection } from './connection/o-node-connection.js';
9
+ import { oNodeConnectionManager } from './connection/o-node-connection.manager.js';
10
+ import { oToolBase } from '@olane/o-tool';
11
+ import { oConnectionHeartbeatManager } from './managers/o-connection-heartbeat.manager.js';
12
+ import { oReconnectionManager } from './managers/o-reconnection.manager.js';
13
+ import { LeaderRequestWrapper } from './utils/leader-request-wrapper.js';
14
+ export declare class oNode extends oToolBase {
15
+ peerId: PeerId;
16
+ p2pNode: Libp2p;
17
+ address: oNodeAddress;
18
+ config: oNodeConfig;
19
+ connectionManager: oNodeConnectionManager;
20
+ hierarchyManager: oNodeHierarchyManager;
21
+ connectionHeartbeatManager?: oConnectionHeartbeatManager;
22
+ reconnectionManager?: oReconnectionManager;
23
+ leaderRequestWrapper: LeaderRequestWrapper;
24
+ protected didRegister: boolean;
25
+ constructor(config: oNodeConfig);
26
+ get leader(): oNodeAddress | null;
27
+ get networkConfig(): Libp2pConfig;
28
+ get parentPeerId(): string | null;
29
+ configureTransports(): any[];
30
+ initializeRouter(): Promise<void>;
31
+ protected createNotificationManager(): oNotificationManager;
32
+ get staticAddress(): oNodeAddress;
33
+ get parentTransports(): oNodeTransport[];
34
+ get transports(): oNodeTransport[];
35
+ unregister(): Promise<void>;
36
+ registerParent(): Promise<void>;
37
+ registerLeader(): Promise<void>;
38
+ register(): Promise<void>;
39
+ extractMethod(address: oNodeAddress): string;
40
+ start(): Promise<void>;
41
+ validateJoinRequest(request: oRequest): Promise<any>;
42
+ /**
43
+ * Configure the libp2p node
44
+ * @returns The libp2p config
45
+ */
46
+ configure(): Promise<Libp2pConfig>;
47
+ protected createNode(): Promise<Libp2p>;
48
+ connect(nextHopAddress: oNodeAddress, targetAddress: oNodeAddress, readTimeoutMs?: number, drainTimeoutMs?: number): Promise<oNodeConnection>;
49
+ initConnectionManager(): Promise<void>;
50
+ initReconnectionManager(): Promise<void>;
51
+ hookInitializeFinished(): Promise<void>;
52
+ hookStartFinished(): Promise<void>;
53
+ initialize(): Promise<void>;
54
+ /**
55
+ * Override use() to wrap leader/registry requests with retry logic
56
+ */
57
+ use(address: oAddress, data?: {
58
+ method?: string;
59
+ params?: {
60
+ [key: string]: any;
61
+ };
62
+ id?: string;
63
+ }, options?: {
64
+ noRouting?: boolean;
65
+ }): Promise<any>;
66
+ teardown(): Promise<void>;
67
+ getLeaders(): oNodeAddress[];
68
+ getParents(): oNodeAddress[];
69
+ getChildren(): oNodeAddress[];
70
+ removeChild(childAddress: oNodeAddress): void;
71
+ }
72
+ //# sourceMappingURL=o-node.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"o-node.d.ts","sourceRoot":"","sources":["../../../src/o-node.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { oHierarchyManager, oHierarchyManagerConfig } from '@olane/o-core';
2
+ import { oNodeAddress } from './router/o-node.address.js';
3
+ export interface oNodeHierarchyManagerConfig extends oHierarchyManagerConfig {
4
+ leaders: oNodeAddress[];
5
+ children: oNodeAddress[];
6
+ parents: oNodeAddress[];
7
+ }
8
+ export declare class oNodeHierarchyManager extends oHierarchyManager {
9
+ leaders: oNodeAddress[];
10
+ children: oNodeAddress[];
11
+ parents: oNodeAddress[];
12
+ constructor(config: oNodeHierarchyManagerConfig);
13
+ get leader(): oNodeAddress | null;
14
+ }
15
+ //# sourceMappingURL=o-node.hierarchy-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"o-node.hierarchy-manager.d.ts","sourceRoot":"","sources":["../../../src/o-node.hierarchy-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAC3E,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE1D,MAAM,WAAW,2BAA4B,SAAQ,uBAAuB;IAC1E,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,OAAO,EAAE,YAAY,EAAE,CAAC;CACzB;AAED,qBAAa,qBAAsB,SAAQ,iBAAiB;IACnD,OAAO,EAAE,YAAY,EAAE,CAAM;IAC7B,QAAQ,EAAE,YAAY,EAAE,CAAM;IAC9B,OAAO,EAAE,YAAY,EAAE,CAAM;gBAExB,MAAM,EAAE,2BAA2B;IAO/C,IAAI,MAAM,IAAI,YAAY,GAAG,IAAI,CAEhC;CACF"}
@@ -0,0 +1,15 @@
1
+ import { oHierarchyManager } from '@olane/o-core';
2
+ export class oNodeHierarchyManager extends oHierarchyManager {
3
+ constructor(config) {
4
+ super(config);
5
+ this.leaders = [];
6
+ this.children = [];
7
+ this.parents = [];
8
+ this.leaders = config.leaders || [];
9
+ this.children = config.children || [];
10
+ this.parents = config.parents || [];
11
+ }
12
+ get leader() {
13
+ return this.leaders.length > 0 ? this.leaders[0] : null;
14
+ }
15
+ }