@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,137 @@
1
+ import { StreamStatus, } from '../../../o-core/src/streaming/index.js';
2
+ /**
3
+ * Default configuration for libp2p stream transport
4
+ */
5
+ const DEFAULT_CONFIG = {
6
+ drainTimeoutMs: 30000, // 30 seconds
7
+ readTimeoutMs: 120000, // 2 minutes
8
+ };
9
+ /**
10
+ * libp2p-specific implementation of IStreamTransport.
11
+ * Wraps a libp2p Stream and handles backpressure, message listening,
12
+ * and stream lifecycle management.
13
+ */
14
+ export class Libp2pStreamTransport {
15
+ constructor(stream, config) {
16
+ this.stream = stream;
17
+ this.config = {
18
+ ...DEFAULT_CONFIG,
19
+ ...config,
20
+ };
21
+ }
22
+ /**
23
+ * Get the underlying libp2p Stream (useful for advanced use cases)
24
+ */
25
+ getStream() {
26
+ return this.stream;
27
+ }
28
+ /**
29
+ * Send data through the stream with backpressure handling
30
+ */
31
+ async send(data) {
32
+ // Check stream status before sending
33
+ if (this.stream.status !== 'open') {
34
+ throw new Error(`Cannot send on stream with status: ${this.stream.status}`);
35
+ }
36
+ try {
37
+ // Attempt to send the data
38
+ const sent = this.stream.send(data);
39
+ // Handle backpressure if the buffer is full
40
+ if (!sent) {
41
+ // Wait for the stream to drain with timeout
42
+ await this.stream.onDrain({
43
+ signal: AbortSignal.timeout(this.config.drainTimeoutMs),
44
+ });
45
+ }
46
+ }
47
+ catch (error) {
48
+ throw new Error(`Failed to send data: ${error}`);
49
+ }
50
+ }
51
+ /**
52
+ * Set up a message handler for incoming data.
53
+ * IMPORTANT: For libp2p v3, this must be called synchronously after
54
+ * receiving the stream to prevent buffer overflow.
55
+ */
56
+ onMessage(handler) {
57
+ this.messageHandler = handler;
58
+ // Attach the message listener to the stream
59
+ // This is synchronous and must be done immediately for libp2p v3
60
+ this.stream.addEventListener('message', (event) => {
61
+ if (this.messageHandler) {
62
+ // Extract the data from the event
63
+ const data = event.detail;
64
+ this.messageHandler(data);
65
+ }
66
+ });
67
+ }
68
+ /**
69
+ * Remove the message handler
70
+ */
71
+ removeMessageHandler() {
72
+ this.messageHandler = undefined;
73
+ // Note: We don't remove the event listener because libp2p doesn't
74
+ // provide a clean way to do this. The handler being undefined
75
+ // effectively disables it.
76
+ }
77
+ /**
78
+ * Close the stream and clean up resources
79
+ */
80
+ async close() {
81
+ try {
82
+ if (this.stream.status === 'open' || this.stream.status === 'closing') {
83
+ await this.stream.close();
84
+ }
85
+ }
86
+ catch (error) {
87
+ console.error('Error closing stream:', error);
88
+ // Don't throw - closing errors are not critical
89
+ }
90
+ finally {
91
+ this.removeMessageHandler();
92
+ }
93
+ }
94
+ /**
95
+ * Get the current status of the stream
96
+ */
97
+ getStatus() {
98
+ // Map libp2p status to our StreamStatus enum
99
+ const status = this.stream.status;
100
+ switch (status) {
101
+ case 'open':
102
+ return StreamStatus.OPEN;
103
+ case 'closing':
104
+ return StreamStatus.CLOSING;
105
+ case 'closed':
106
+ return StreamStatus.CLOSED;
107
+ case 'reset':
108
+ return StreamStatus.RESET;
109
+ default:
110
+ return StreamStatus.CLOSED;
111
+ }
112
+ }
113
+ /**
114
+ * Check if the stream is in a usable state
115
+ */
116
+ isOpen() {
117
+ return this.stream.status === 'open';
118
+ }
119
+ /**
120
+ * Wait for the first message with timeout
121
+ * @param timeoutMs - Optional timeout in milliseconds (defaults to config.readTimeoutMs)
122
+ * @returns Promise that resolves with the first message
123
+ */
124
+ async waitForMessage(timeoutMs) {
125
+ const timeout = timeoutMs ?? this.config.readTimeoutMs;
126
+ return new Promise((resolve, reject) => {
127
+ const timer = setTimeout(() => {
128
+ this.removeMessageHandler();
129
+ reject(new Error(`Timeout waiting for message after ${timeout}ms`));
130
+ }, timeout);
131
+ this.onMessage((data) => {
132
+ clearTimeout(timer);
133
+ resolve(data);
134
+ });
135
+ });
136
+ }
137
+ }
@@ -0,0 +1,65 @@
1
+ import { StreamHandlerBase, StreamHandlerOptions } from '../../../o-core/src/streaming/index.js';
2
+ import { oRequest } from '@olane/o-protocol';
3
+ import { Libp2pStreamTransport } from './libp2p-stream-transport.js';
4
+ /**
5
+ * Options for NodeStreamHandler
6
+ */
7
+ export interface NodeStreamHandlerOptions extends StreamHandlerOptions {
8
+ /**
9
+ * Enable success count tracking
10
+ */
11
+ trackSuccessCount?: boolean;
12
+ /**
13
+ * Enable error count tracking
14
+ */
15
+ trackErrorCount?: boolean;
16
+ }
17
+ /**
18
+ * o-node specific implementation of StreamHandlerBase.
19
+ * Integrates with libp2p streams and tracks metrics for o-node tools.
20
+ */
21
+ export declare class NodeStreamHandler extends StreamHandlerBase {
22
+ private successCount;
23
+ private errorCount;
24
+ private transport;
25
+ private nodeOptions;
26
+ constructor(transport: Libp2pStreamTransport, options?: NodeStreamHandlerOptions);
27
+ /**
28
+ * Get the success count (number of chunks successfully sent)
29
+ */
30
+ getSuccessCount(): number;
31
+ /**
32
+ * Get the error count
33
+ */
34
+ getErrorCount(): number;
35
+ /**
36
+ * Reset metrics
37
+ */
38
+ resetMetrics(): void;
39
+ /**
40
+ * Implementation of sendChunk using libp2p transport and protocol builder
41
+ */
42
+ protected sendChunk(chunk: unknown, sequence: number, isLast: boolean, request: oRequest): Promise<void>;
43
+ /**
44
+ * Hook: Called when streaming starts
45
+ */
46
+ protected onStreamStart(request: oRequest): void;
47
+ /**
48
+ * Hook: Called when streaming completes successfully
49
+ */
50
+ protected onStreamComplete(request: oRequest, totalChunks: number): void;
51
+ /**
52
+ * Hook: Called when streaming encounters an error
53
+ */
54
+ protected onStreamError(request: oRequest, error: any): void;
55
+ /**
56
+ * Reset the handler for reuse with a new transport
57
+ */
58
+ reset(): void;
59
+ /**
60
+ * Create a new NodeStreamHandler with a different transport
61
+ * (useful for handling multiple streams)
62
+ */
63
+ static create(transport: Libp2pStreamTransport, options?: NodeStreamHandlerOptions): NodeStreamHandler;
64
+ }
65
+ //# sourceMappingURL=node-stream-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-stream-handler.d.ts","sourceRoot":"","sources":["../../../../src/streaming/node-stream-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EAErB,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAErE;;GAEG;AACH,MAAM,WAAW,wBAAyB,SAAQ,oBAAoB;IACpE;;OAEG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAE5B;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED;;;GAGG;AACH,qBAAa,iBAAkB,SAAQ,iBAAiB;IACtD,OAAO,CAAC,YAAY,CAAa;IACjC,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,SAAS,CAAwB;IACzC,OAAO,CAAC,WAAW,CAA2B;gBAG5C,SAAS,EAAE,qBAAqB,EAChC,OAAO,GAAE,wBAA6B;IAWxC;;OAEG;IACI,eAAe,IAAI,MAAM;IAIhC;;OAEG;IACI,aAAa,IAAI,MAAM;IAI9B;;OAEG;IACI,YAAY,IAAI,IAAI;IAK3B;;OAEG;cACa,SAAS,CACvB,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,OAAO,EACf,OAAO,EAAE,QAAQ,GAChB,OAAO,CAAC,IAAI,CAAC;IA0BhB;;OAEG;cACgB,aAAa,CAAC,OAAO,EAAE,QAAQ,GAAG,IAAI;IAOzD;;OAEG;cACgB,gBAAgB,CAAC,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI;IASjF;;OAEG;cACgB,aAAa,CAAC,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI;IAUrE;;OAEG;IACI,KAAK,IAAI,IAAI;IAOpB;;;OAGG;WACW,MAAM,CAClB,SAAS,EAAE,qBAAqB,EAChC,OAAO,CAAC,EAAE,wBAAwB,GACjC,iBAAiB;CAGrB"}
@@ -0,0 +1,101 @@
1
+ import { StreamHandlerBase, ProtocolBuilder, } from '../../../o-core/src/streaming/index.js';
2
+ /**
3
+ * o-node specific implementation of StreamHandlerBase.
4
+ * Integrates with libp2p streams and tracks metrics for o-node tools.
5
+ */
6
+ export class NodeStreamHandler extends StreamHandlerBase {
7
+ constructor(transport, options = {}) {
8
+ super(options);
9
+ this.successCount = 0;
10
+ this.errorCount = 0;
11
+ this.transport = transport;
12
+ this.nodeOptions = {
13
+ trackSuccessCount: true,
14
+ trackErrorCount: true,
15
+ ...options,
16
+ };
17
+ }
18
+ /**
19
+ * Get the success count (number of chunks successfully sent)
20
+ */
21
+ getSuccessCount() {
22
+ return this.successCount;
23
+ }
24
+ /**
25
+ * Get the error count
26
+ */
27
+ getErrorCount() {
28
+ return this.errorCount;
29
+ }
30
+ /**
31
+ * Reset metrics
32
+ */
33
+ resetMetrics() {
34
+ this.successCount = 0;
35
+ this.errorCount = 0;
36
+ }
37
+ /**
38
+ * Implementation of sendChunk using libp2p transport and protocol builder
39
+ */
40
+ async sendChunk(chunk, sequence, isLast, request) {
41
+ // Build the JSON-RPC streaming chunk message
42
+ const message = ProtocolBuilder.buildStreamChunkFromRequest(chunk, sequence, isLast, request);
43
+ // Encode the message to bytes
44
+ const encoded = ProtocolBuilder.encodeMessage(message);
45
+ // Send through the transport (handles backpressure)
46
+ await this.transport.send(encoded);
47
+ // Track metrics if enabled
48
+ if (this.nodeOptions.trackSuccessCount) {
49
+ this.successCount++;
50
+ }
51
+ // Close the stream if this is the last chunk
52
+ if (isLast) {
53
+ await this.transport.close();
54
+ }
55
+ }
56
+ /**
57
+ * Hook: Called when streaming starts
58
+ */
59
+ onStreamStart(request) {
60
+ // Reset metrics for this stream
61
+ if (this.nodeOptions.enableMetrics) {
62
+ this.resetMetrics();
63
+ }
64
+ }
65
+ /**
66
+ * Hook: Called when streaming completes successfully
67
+ */
68
+ onStreamComplete(request, totalChunks) {
69
+ // Log completion if metrics enabled
70
+ if (this.nodeOptions.enableMetrics) {
71
+ console.log(`Stream completed for ${request.method}: ${totalChunks} chunks sent`);
72
+ }
73
+ }
74
+ /**
75
+ * Hook: Called when streaming encounters an error
76
+ */
77
+ onStreamError(request, error) {
78
+ // Track error count
79
+ if (this.nodeOptions.trackErrorCount) {
80
+ this.errorCount++;
81
+ }
82
+ // Log error
83
+ console.error(`Stream error for ${request.method}:`, error);
84
+ }
85
+ /**
86
+ * Reset the handler for reuse with a new transport
87
+ */
88
+ reset() {
89
+ // Call parent reset
90
+ this.state = 0; // Reset state (IDLE)
91
+ this.currentSequence = 0;
92
+ this.resetMetrics();
93
+ }
94
+ /**
95
+ * Create a new NodeStreamHandler with a different transport
96
+ * (useful for handling multiple streams)
97
+ */
98
+ static create(transport, options) {
99
+ return new NodeStreamHandler(transport, options);
100
+ }
101
+ }
@@ -0,0 +1,107 @@
1
+ import { oObject } from '@olane/o-core';
2
+ export declare enum CircuitState {
3
+ CLOSED = "CLOSED",// Normal operation, requests pass through
4
+ OPEN = "OPEN",// Circuit broken, requests fast-fail
5
+ HALF_OPEN = "HALF_OPEN"
6
+ }
7
+ export interface CircuitBreakerConfig {
8
+ failureThreshold: number;
9
+ openTimeoutMs: number;
10
+ halfOpenMaxAttempts: number;
11
+ enabled: boolean;
12
+ }
13
+ export interface CircuitStats {
14
+ state: CircuitState;
15
+ consecutiveFailures: number;
16
+ totalFailures: number;
17
+ totalSuccesses: number;
18
+ lastFailureTime?: number;
19
+ lastSuccessTime?: number;
20
+ openedAt?: number;
21
+ }
22
+ /**
23
+ * Circuit Breaker Pattern Implementation
24
+ *
25
+ * Prevents cascading failures by "breaking the circuit" when a service
26
+ * experiences persistent failures. This allows the system to fail fast
27
+ * rather than wasting resources on retries that are likely to fail.
28
+ *
29
+ * States:
30
+ * - CLOSED: Normal operation, all requests pass through
31
+ * - OPEN: Circuit broken due to failures, requests fail immediately
32
+ * - HALF_OPEN: Testing recovery, limited requests allowed
33
+ *
34
+ * Flow:
35
+ * 1. CLOSED -> OPEN: After N consecutive failures
36
+ * 2. OPEN -> HALF_OPEN: After timeout period
37
+ * 3. HALF_OPEN -> CLOSED: After successful request
38
+ * 4. HALF_OPEN -> OPEN: After failure in recovery
39
+ *
40
+ * @example
41
+ * ```typescript
42
+ * const breaker = new CircuitBreaker('registry', {
43
+ * failureThreshold: 3,
44
+ * openTimeoutMs: 30000,
45
+ * halfOpenMaxAttempts: 1,
46
+ * enabled: true,
47
+ * });
48
+ *
49
+ * // Before making request
50
+ * if (!breaker.shouldAllowRequest()) {
51
+ * throw new Error('Circuit breaker is open');
52
+ * }
53
+ *
54
+ * try {
55
+ * const result = await makeRequest();
56
+ * breaker.recordSuccess();
57
+ * return result;
58
+ * } catch (error) {
59
+ * breaker.recordFailure();
60
+ * throw error;
61
+ * }
62
+ * ```
63
+ */
64
+ export declare class CircuitBreaker extends oObject {
65
+ private readonly serviceName;
66
+ private readonly config;
67
+ private state;
68
+ private consecutiveFailures;
69
+ private totalFailures;
70
+ private totalSuccesses;
71
+ private lastFailureTime?;
72
+ private lastSuccessTime?;
73
+ private openedAt?;
74
+ private halfOpenAttempts;
75
+ constructor(serviceName: string, config: CircuitBreakerConfig);
76
+ /**
77
+ * Check if a request should be allowed through the circuit breaker
78
+ * @returns true if request should proceed, false if should fast-fail
79
+ */
80
+ shouldAllowRequest(): boolean;
81
+ /**
82
+ * Record a successful request
83
+ */
84
+ recordSuccess(): void;
85
+ /**
86
+ * Record a failed request
87
+ */
88
+ recordFailure(): void;
89
+ /**
90
+ * Get current statistics
91
+ */
92
+ getStats(): CircuitStats;
93
+ /**
94
+ * Get current circuit state
95
+ */
96
+ getState(): CircuitState;
97
+ /**
98
+ * Force reset the circuit breaker to CLOSED state
99
+ * Use with caution - mainly for testing or manual recovery
100
+ */
101
+ reset(): void;
102
+ /**
103
+ * Transition to a new state
104
+ */
105
+ private transitionTo;
106
+ }
107
+ //# sourceMappingURL=circuit-breaker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"circuit-breaker.d.ts","sourceRoot":"","sources":["../../../../src/utils/circuit-breaker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAExC,oBAAY,YAAY;IACtB,MAAM,WAAW,CAAE,0CAA0C;IAC7D,IAAI,SAAS,CAAE,qCAAqC;IACpD,SAAS,cAAc;CACxB;AAED,MAAM,WAAW,oBAAoB;IACnC,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,YAAY,CAAC;IACpB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,qBAAa,cAAe,SAAQ,OAAO;IAWvC,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,MAAM;IAXzB,OAAO,CAAC,KAAK,CAAqC;IAClD,OAAO,CAAC,mBAAmB,CAAa;IACxC,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,cAAc,CAAa;IACnC,OAAO,CAAC,eAAe,CAAC,CAAS;IACjC,OAAO,CAAC,eAAe,CAAC,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,CAAS;IAC1B,OAAO,CAAC,gBAAgB,CAAa;gBAGlB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,oBAAoB;IAW/C;;;OAGG;IACH,kBAAkB,IAAI,OAAO;IA2C7B;;OAEG;IACH,aAAa,IAAI,IAAI;IAkBrB;;OAEG;IACH,aAAa,IAAI,IAAI;IA+BrB;;OAEG;IACH,QAAQ,IAAI,YAAY;IAYxB;;OAEG;IACH,QAAQ,IAAI,YAAY;IAIxB;;;OAGG;IACH,KAAK,IAAI,IAAI;IAQb;;OAEG;IACH,OAAO,CAAC,YAAY;CAOrB"}
@@ -0,0 +1,175 @@
1
+ import { oObject } from '@olane/o-core';
2
+ export var CircuitState;
3
+ (function (CircuitState) {
4
+ CircuitState["CLOSED"] = "CLOSED";
5
+ CircuitState["OPEN"] = "OPEN";
6
+ CircuitState["HALF_OPEN"] = "HALF_OPEN";
7
+ })(CircuitState || (CircuitState = {}));
8
+ /**
9
+ * Circuit Breaker Pattern Implementation
10
+ *
11
+ * Prevents cascading failures by "breaking the circuit" when a service
12
+ * experiences persistent failures. This allows the system to fail fast
13
+ * rather than wasting resources on retries that are likely to fail.
14
+ *
15
+ * States:
16
+ * - CLOSED: Normal operation, all requests pass through
17
+ * - OPEN: Circuit broken due to failures, requests fail immediately
18
+ * - HALF_OPEN: Testing recovery, limited requests allowed
19
+ *
20
+ * Flow:
21
+ * 1. CLOSED -> OPEN: After N consecutive failures
22
+ * 2. OPEN -> HALF_OPEN: After timeout period
23
+ * 3. HALF_OPEN -> CLOSED: After successful request
24
+ * 4. HALF_OPEN -> OPEN: After failure in recovery
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * const breaker = new CircuitBreaker('registry', {
29
+ * failureThreshold: 3,
30
+ * openTimeoutMs: 30000,
31
+ * halfOpenMaxAttempts: 1,
32
+ * enabled: true,
33
+ * });
34
+ *
35
+ * // Before making request
36
+ * if (!breaker.shouldAllowRequest()) {
37
+ * throw new Error('Circuit breaker is open');
38
+ * }
39
+ *
40
+ * try {
41
+ * const result = await makeRequest();
42
+ * breaker.recordSuccess();
43
+ * return result;
44
+ * } catch (error) {
45
+ * breaker.recordFailure();
46
+ * throw error;
47
+ * }
48
+ * ```
49
+ */
50
+ export class CircuitBreaker extends oObject {
51
+ constructor(serviceName, config) {
52
+ super();
53
+ this.serviceName = serviceName;
54
+ this.config = config;
55
+ this.state = CircuitState.CLOSED;
56
+ this.consecutiveFailures = 0;
57
+ this.totalFailures = 0;
58
+ this.totalSuccesses = 0;
59
+ this.halfOpenAttempts = 0;
60
+ this.logger.debug(`Circuit breaker initialized for ${serviceName}:`, `threshold=${config.failureThreshold},`, `timeout=${config.openTimeoutMs}ms,`, `enabled=${config.enabled}`);
61
+ }
62
+ /**
63
+ * Check if a request should be allowed through the circuit breaker
64
+ * @returns true if request should proceed, false if should fast-fail
65
+ */
66
+ shouldAllowRequest() {
67
+ if (!this.config.enabled) {
68
+ return true;
69
+ }
70
+ const now = Date.now();
71
+ switch (this.state) {
72
+ case CircuitState.CLOSED:
73
+ return true;
74
+ case CircuitState.OPEN:
75
+ // Check if timeout period has elapsed
76
+ if (this.openedAt &&
77
+ now - this.openedAt >= this.config.openTimeoutMs) {
78
+ this.logger.info(`Circuit breaker for ${this.serviceName} entering HALF_OPEN state`);
79
+ this.transitionTo(CircuitState.HALF_OPEN);
80
+ this.halfOpenAttempts = 0;
81
+ return true;
82
+ }
83
+ // Circuit still open, fast-fail
84
+ this.logger.debug(`Circuit breaker for ${this.serviceName} is OPEN, rejecting request`);
85
+ return false;
86
+ case CircuitState.HALF_OPEN:
87
+ // Allow limited attempts in HALF_OPEN state
88
+ if (this.halfOpenAttempts < this.config.halfOpenMaxAttempts) {
89
+ this.halfOpenAttempts++;
90
+ return true;
91
+ }
92
+ this.logger.debug(`Circuit breaker for ${this.serviceName} HALF_OPEN max attempts reached`);
93
+ return false;
94
+ }
95
+ }
96
+ /**
97
+ * Record a successful request
98
+ */
99
+ recordSuccess() {
100
+ if (!this.config.enabled) {
101
+ return;
102
+ }
103
+ this.totalSuccesses++;
104
+ this.lastSuccessTime = Date.now();
105
+ this.consecutiveFailures = 0;
106
+ if (this.state === CircuitState.HALF_OPEN) {
107
+ this.logger.info(`Circuit breaker for ${this.serviceName} recovered, closing circuit`);
108
+ this.transitionTo(CircuitState.CLOSED);
109
+ this.halfOpenAttempts = 0;
110
+ }
111
+ }
112
+ /**
113
+ * Record a failed request
114
+ */
115
+ recordFailure() {
116
+ if (!this.config.enabled) {
117
+ return;
118
+ }
119
+ this.totalFailures++;
120
+ this.consecutiveFailures++;
121
+ this.lastFailureTime = Date.now();
122
+ if (this.state === CircuitState.HALF_OPEN) {
123
+ this.logger.warn(`Circuit breaker for ${this.serviceName} failed in HALF_OPEN, reopening circuit`);
124
+ this.transitionTo(CircuitState.OPEN);
125
+ this.openedAt = Date.now();
126
+ this.halfOpenAttempts = 0;
127
+ return;
128
+ }
129
+ if (this.state === CircuitState.CLOSED &&
130
+ this.consecutiveFailures >= this.config.failureThreshold) {
131
+ this.logger.error(`Circuit breaker for ${this.serviceName} opening after ${this.consecutiveFailures} consecutive failures`);
132
+ this.transitionTo(CircuitState.OPEN);
133
+ this.openedAt = Date.now();
134
+ }
135
+ }
136
+ /**
137
+ * Get current statistics
138
+ */
139
+ getStats() {
140
+ return {
141
+ state: this.state,
142
+ consecutiveFailures: this.consecutiveFailures,
143
+ totalFailures: this.totalFailures,
144
+ totalSuccesses: this.totalSuccesses,
145
+ lastFailureTime: this.lastFailureTime,
146
+ lastSuccessTime: this.lastSuccessTime,
147
+ openedAt: this.openedAt,
148
+ };
149
+ }
150
+ /**
151
+ * Get current circuit state
152
+ */
153
+ getState() {
154
+ return this.state;
155
+ }
156
+ /**
157
+ * Force reset the circuit breaker to CLOSED state
158
+ * Use with caution - mainly for testing or manual recovery
159
+ */
160
+ reset() {
161
+ this.logger.info(`Circuit breaker for ${this.serviceName} manually reset`);
162
+ this.transitionTo(CircuitState.CLOSED);
163
+ this.consecutiveFailures = 0;
164
+ this.halfOpenAttempts = 0;
165
+ this.openedAt = undefined;
166
+ }
167
+ /**
168
+ * Transition to a new state
169
+ */
170
+ transitionTo(newState) {
171
+ const oldState = this.state;
172
+ this.state = newState;
173
+ this.logger.debug(`Circuit breaker for ${this.serviceName}: ${oldState} -> ${newState}`);
174
+ }
175
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=circuit-breaker.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"circuit-breaker.test.d.ts","sourceRoot":"","sources":["../../../../src/utils/circuit-breaker.test.ts"],"names":[],"mappings":""}