envio 3.9.0 → 3.10.0

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 (110) hide show
  1. package/evm.schema.json +26 -0
  2. package/fuel.schema.json +26 -0
  3. package/index.d.ts +35 -3
  4. package/package.json +6 -7
  5. package/src/Batch.res +9 -0
  6. package/src/ChainState.res +35 -39
  7. package/src/ChainState.res.mjs +14 -11
  8. package/src/ChainState.resi +15 -7
  9. package/src/Config.res +52 -44
  10. package/src/Config.res.mjs +51 -17
  11. package/src/Core.res +4 -0
  12. package/src/CrossChainState.res +15 -23
  13. package/src/CrossChainState.res.mjs +10 -18
  14. package/src/CrossChainState.resi +4 -1
  15. package/src/Ecosystem.res +7 -2
  16. package/src/Envio.res +6 -4
  17. package/src/EventConfigBuilder.res +169 -26
  18. package/src/EventConfigBuilder.res.mjs +124 -15
  19. package/src/HandlerRegister.res +21 -4
  20. package/src/HandlerRegister.res.mjs +24 -5
  21. package/src/InMemoryStore.res +9 -7
  22. package/src/InMemoryStore.res.mjs +3 -3
  23. package/src/IndexerState.res +43 -6
  24. package/src/IndexerState.res.mjs +36 -7
  25. package/src/IndexerState.resi +4 -4
  26. package/src/Internal.res +16 -17
  27. package/src/Metrics.res +72 -6
  28. package/src/Metrics.res.mjs +30 -2
  29. package/src/Persistence.res +36 -30
  30. package/src/Persistence.res.mjs +1 -20
  31. package/src/PgStorage.res +104 -56
  32. package/src/PgStorage.res.mjs +57 -35
  33. package/src/PruneStaleHistory.res +85 -52
  34. package/src/PruneStaleHistory.res.mjs +63 -37
  35. package/src/Rollback.res +68 -45
  36. package/src/Rollback.res.mjs +38 -19
  37. package/src/RollbackCommit.res +7 -9
  38. package/src/RollbackCommit.res.mjs +5 -6
  39. package/src/SafeCheckpointTracking.res +11 -11
  40. package/src/SafeCheckpointTracking.res.mjs +7 -6
  41. package/src/SimulateItems.res +33 -18
  42. package/src/SimulateItems.res.mjs +26 -22
  43. package/src/Sink.res +38 -26
  44. package/src/Sink.res.mjs +21 -16
  45. package/src/TestIndexer.res +5 -5
  46. package/src/TestIndexer.res.mjs +1 -1
  47. package/src/Utils.res +170 -0
  48. package/src/Utils.res.mjs +153 -0
  49. package/src/Writing.res +2 -2
  50. package/src/Writing.res.mjs +1 -1
  51. package/src/bindings/ClickHouse.res +366 -698
  52. package/src/bindings/ClickHouse.res.mjs +371 -421
  53. package/src/bindings/ClickHouseSink.res +337 -0
  54. package/src/bindings/ClickHouseSink.res.mjs +246 -0
  55. package/src/bindings/EventSource.res +8 -2
  56. package/src/bindings/NodeJs.res +6 -0
  57. package/src/bindings/Vitest.res +23 -0
  58. package/src/bindings/Vitest.res.mjs +3 -0
  59. package/src/bindings/WebSocket.res +9 -10
  60. package/src/db/CheckpointBounds.res +53 -0
  61. package/src/db/CheckpointBounds.res.mjs +44 -0
  62. package/src/db/EntityFilter.res +36 -17
  63. package/src/db/EntityFilter.res.mjs +25 -14
  64. package/src/db/EntityHistory.res +47 -22
  65. package/src/db/EntityHistory.res.mjs +19 -12
  66. package/src/db/InternalTable.res +84 -35
  67. package/src/db/InternalTable.res.mjs +56 -23
  68. package/src/db/RollbackFloors.res +55 -0
  69. package/src/db/RollbackFloors.res.mjs +92 -0
  70. package/src/db/Table.res +22 -4
  71. package/src/db/Table.res.mjs +30 -9
  72. package/src/sources/Evm.res +2 -0
  73. package/src/sources/Evm.res.mjs +2 -0
  74. package/src/sources/EvmHyperSyncSource.res +3 -3
  75. package/src/sources/EvmHyperSyncSource.res.mjs +3 -3
  76. package/src/sources/EvmRpcWs.res +124 -0
  77. package/src/sources/EvmRpcWs.res.mjs +117 -0
  78. package/src/sources/Fuel.res +2 -0
  79. package/src/sources/Fuel.res.mjs +2 -0
  80. package/src/sources/FuelHyperSyncSource.res +1 -1
  81. package/src/sources/FuelHyperSyncSource.res.mjs +2 -1
  82. package/src/sources/HeightFeed.res +568 -0
  83. package/src/sources/HeightFeed.res.mjs +452 -0
  84. package/src/sources/HeightStream.res +257 -0
  85. package/src/sources/HeightStream.res.mjs +194 -0
  86. package/src/sources/HyperSync.res +5 -0
  87. package/src/sources/HyperSync.res.mjs +3 -0
  88. package/src/sources/HyperSync.resi +4 -0
  89. package/src/sources/HyperSyncSSE.res +49 -0
  90. package/src/sources/HyperSyncSSE.res.mjs +79 -0
  91. package/src/sources/RpcSource.res +1 -1
  92. package/src/sources/RpcSource.res.mjs +2 -2
  93. package/src/sources/Source.res +54 -1
  94. package/src/sources/Source.res.mjs +25 -0
  95. package/src/sources/SourceManager.res +220 -227
  96. package/src/sources/SourceManager.res.mjs +139 -164
  97. package/src/sources/SourceManager.resi +8 -0
  98. package/src/sources/Svm.res +2 -0
  99. package/src/sources/Svm.res.mjs +2 -0
  100. package/src/sources/SvmHyperSyncClient.res +70 -127
  101. package/src/sources/SvmHyperSyncClient.res.mjs +51 -25
  102. package/src/sources/SvmHyperSyncSource.res +18 -15
  103. package/src/sources/SvmHyperSyncSource.res.mjs +5 -4
  104. package/svm.schema.json +1 -75
  105. package/src/MemoryStorage.res +0 -729
  106. package/src/MemoryStorage.res.mjs +0 -586
  107. package/src/sources/HyperSyncHeightStream.res +0 -129
  108. package/src/sources/HyperSyncHeightStream.res.mjs +0 -110
  109. package/src/sources/RpcWebSocketHeightStream.res +0 -175
  110. package/src/sources/RpcWebSocketHeightStream.res.mjs +0 -180
@@ -0,0 +1,194 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Utils from "../Utils.res.mjs";
4
+ import * as Performance from "../bindings/Performance.res.mjs";
5
+ import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
6
+ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
7
+ import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
8
+ import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
9
+
10
+ function retryDelayFor(count) {
11
+ if (count <= 0) {
12
+ return 0;
13
+ } else {
14
+ return Utils.expBackoff(250, count - 1 | 0, 60000);
15
+ }
16
+ }
17
+
18
+ function truncateDetail(detail) {
19
+ if (detail.length > 200) {
20
+ return detail.slice(0, 200) + "...";
21
+ } else {
22
+ return detail;
23
+ }
24
+ }
25
+
26
+ function subscribe(staleTimeout, onHeight, onStatus, connect) {
27
+ let closeConnectionRef = {
28
+ contents: undefined
29
+ };
30
+ let failureCount = {
31
+ contents: 0
32
+ };
33
+ let generation = {
34
+ contents: 0
35
+ };
36
+ let timeoutId = {
37
+ contents: undefined
38
+ };
39
+ let unreadableDetail = {
40
+ contents: undefined
41
+ };
42
+ let liveAt = {
43
+ contents: undefined
44
+ };
45
+ let minProvenMillis = staleTimeout / 4 | 0;
46
+ let closeSafely = close => {
47
+ try {
48
+ return close();
49
+ } catch (exn) {
50
+ return;
51
+ }
52
+ };
53
+ let closeConnection = () => {
54
+ let close = closeConnectionRef.contents;
55
+ if (close !== undefined) {
56
+ closeSafely(close);
57
+ }
58
+ closeConnectionRef.contents = undefined;
59
+ };
60
+ let armStaleTimeout = () => {
61
+ Utils.clearTimeoutRef(timeoutId);
62
+ timeoutId.contents = Primitive_option.some(setTimeout(() => {
63
+ timeoutId.contents = undefined;
64
+ let detail = unreadableDetail.contents;
65
+ if (detail !== undefined) {
66
+ return fail("Unreadable", detail);
67
+ } else {
68
+ return fail("Stale", undefined);
69
+ }
70
+ }, staleTimeout));
71
+ };
72
+ let fail = (reason, detail) => {
73
+ generation.contents = generation.contents + 1 | 0;
74
+ Utils.clearTimeoutRef(timeoutId);
75
+ closeConnection();
76
+ let since = liveAt.contents;
77
+ let servedMillis = since !== undefined ? Performance.now() - since | 0 : 0;
78
+ let provenMillis = Primitive_int.max(retryDelayFor(failureCount.contents), minProvenMillis);
79
+ failureCount.contents = servedMillis >= provenMillis ? 1 : failureCount.contents + 1 | 0;
80
+ let retryMillis = Utils.jitter(retryDelayFor(failureCount.contents));
81
+ let reason$1;
82
+ reason$1 = typeof reason !== "object" && reason === "Closed" && servedMillis >= provenMillis ? "Rotated" : reason;
83
+ timeoutId.contents = Primitive_option.some(setTimeout(() => {
84
+ timeoutId.contents = undefined;
85
+ start();
86
+ }, retryMillis));
87
+ onStatus({
88
+ TAG: "Down",
89
+ reason: reason$1,
90
+ detail: Stdlib_Option.map(detail, truncateDetail)
91
+ });
92
+ };
93
+ let start = () => {
94
+ generation.contents = generation.contents + 1 | 0;
95
+ unreadableDetail.contents = undefined;
96
+ liveAt.contents = undefined;
97
+ let connectionGeneration = generation.contents;
98
+ armStaleTimeout();
99
+ let goLive = () => {
100
+ armStaleTimeout();
101
+ if (Stdlib_Option.isNone(liveAt.contents)) {
102
+ liveAt.contents = Performance.now();
103
+ return onStatus("Live");
104
+ }
105
+ };
106
+ let driver_onConnected = () => {
107
+ if (generation.contents === connectionGeneration) {
108
+ return goLive();
109
+ }
110
+ };
111
+ let driver_onKeepAlive = () => {
112
+ if (generation.contents === connectionGeneration && Stdlib_Option.isNone(unreadableDetail.contents)) {
113
+ return armStaleTimeout();
114
+ }
115
+ };
116
+ let driver_onHeight = height => {
117
+ if (generation.contents === connectionGeneration) {
118
+ unreadableDetail.contents = undefined;
119
+ goLive();
120
+ return onHeight(height);
121
+ }
122
+ };
123
+ let driver_onUnreadable = detail => {
124
+ if (generation.contents === connectionGeneration) {
125
+ unreadableDetail.contents = detail;
126
+ return;
127
+ }
128
+ };
129
+ let driver_onFailure = (reason, detail) => {
130
+ if (generation.contents === connectionGeneration) {
131
+ return fail(reason, detail);
132
+ }
133
+ };
134
+ let driver = {
135
+ onConnected: driver_onConnected,
136
+ onKeepAlive: driver_onKeepAlive,
137
+ onHeight: driver_onHeight,
138
+ onUnreadable: driver_onUnreadable,
139
+ onFailure: driver_onFailure
140
+ };
141
+ let connected;
142
+ try {
143
+ connected = {
144
+ TAG: "Ok",
145
+ _0: connect(driver)
146
+ };
147
+ } catch (raw_exn) {
148
+ let exn = Primitive_exceptions.internalToException(raw_exn);
149
+ connected = {
150
+ TAG: "Error",
151
+ _0: exn
152
+ };
153
+ }
154
+ if (connected.TAG !== "Ok") {
155
+ if (generation.contents === connectionGeneration) {
156
+ return fail("ConnectFailed", Utils.exnMessage(connected._0));
157
+ } else {
158
+ return;
159
+ }
160
+ }
161
+ let closeCurrentConnection = connected._0;
162
+ if (generation.contents === connectionGeneration) {
163
+ closeConnectionRef.contents = closeCurrentConnection;
164
+ return;
165
+ } else {
166
+ return closeSafely(closeCurrentConnection);
167
+ }
168
+ };
169
+ start();
170
+ return () => {
171
+ generation.contents = generation.contents + 1 | 0;
172
+ Utils.clearTimeoutRef(timeoutId);
173
+ closeConnection();
174
+ };
175
+ }
176
+
177
+ let baseRetryMillis = 250;
178
+
179
+ let maxRetryMillis = 60000;
180
+
181
+ let provenStaleFraction = 4;
182
+
183
+ let maxDetailLength = 200;
184
+
185
+ export {
186
+ baseRetryMillis,
187
+ maxRetryMillis,
188
+ provenStaleFraction,
189
+ maxDetailLength,
190
+ retryDelayFor,
191
+ truncateDetail,
192
+ subscribe,
193
+ }
194
+ /* Utils Not a pure module */
@@ -1,3 +1,8 @@
1
+ // Short enough that a chain at the head is not held up behind it, long enough
2
+ // that a wait polling through a whole block interval is not thousands of
3
+ // requests.
4
+ let pollingInterval = 400
5
+
1
6
  // A napi error carries nothing but a message, so the native clients signal the
2
7
  // recoverable conditions SourceManager knows how to retry as a `PREFIX:<int>`
3
8
  // marker. Keep in sync with `request_stats.rs`.
@@ -159,7 +159,10 @@ let GetLogs = {
159
159
  query: query
160
160
  };
161
161
 
162
+ let pollingInterval = 400;
163
+
162
164
  export {
165
+ pollingInterval,
163
166
  mapNativeFailure,
164
167
  mapNativeFailureExn,
165
168
  reraiseIfRecoverable,
@@ -6,6 +6,10 @@ type logsQueryPage = {
6
6
  blockStore: BlockStore.t,
7
7
  }
8
8
 
9
+ // How often a HyperSync source is asked for the height while nothing is pushing
10
+ // one. Every ecosystem's client talks to the same service, so they wait alike.
11
+ let pollingInterval: int
12
+
9
13
  // Map a native client's `PREFIX:<int>` failure marker onto the exception
10
14
  // SourceManager retries on (`RateLimited` / `SourceBehindHead`), falling back to
11
15
  // the original cause.
@@ -0,0 +1,49 @@
1
+ // The server pings every 5s, so 15s is a safe margin before treating the
2
+ // connection as dead.
3
+ let staleTimeout = 15_000
4
+
5
+ let failure = (error: EventSource.errorEvent): (
6
+ Source.heightSubscriptionDownReason,
7
+ option<string>,
8
+ ) =>
9
+ switch (error.code, error.message) {
10
+ | (Some(code), message) => (Http(code), message)
11
+ | (None, Some(message)) => (TransportError, Some(message))
12
+ // The stream ended without an HTTP error, which is how a load balancer
13
+ // rotating connections shows up.
14
+ | (None, None) => (Closed, None)
15
+ }
16
+
17
+ let subscribe = (~hyperSyncUrl, ~apiToken, ~onHeight, ~onStatus) =>
18
+ HeightStream.subscribe(~staleTimeout, ~onHeight, ~onStatus, ~connect=driver => {
19
+ let userAgent = `hyperindex/${Utils.EnvioPackage.value.version}`
20
+ let es = EventSource.create(
21
+ ~url=`${hyperSyncUrl}/height/sse`,
22
+ ~options={
23
+ fetch: (url, ~args) => {
24
+ let headers =
25
+ args.headers
26
+ ->Option.getOr(Dict.make())
27
+ ->Utils.Dict.merge(
28
+ Dict.fromArray([("Authorization", `Bearer ${apiToken}`), ("User-Agent", userAgent)]),
29
+ )
30
+ EventSource.Fetch.fetch(url, ~args={...args, headers: headers})
31
+ },
32
+ },
33
+ )
34
+
35
+ es->EventSource.onopen(_ => driver.onConnected())
36
+ es->EventSource.onerror(error => {
37
+ let (reason, detail) = error->failure
38
+ driver.onFailure(~reason, ~detail?)
39
+ })
40
+ es->EventSource.addEventListener("ping", _ => driver.onKeepAlive())
41
+ es->EventSource.addEventListener("height", event =>
42
+ switch event.data->Int.fromString {
43
+ | Some(height) => driver.onHeight(height)
44
+ | None => driver.onUnreadable(~detail=event.data)
45
+ }
46
+ )
47
+
48
+ () => es->EventSource.close
49
+ })
@@ -0,0 +1,79 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Utils from "../Utils.res.mjs";
4
+ import * as Stdlib_Int from "@rescript/runtime/lib/es6/Stdlib_Int.js";
5
+ import * as Eventsource from "eventsource";
6
+ import * as HeightStream from "./HeightStream.res.mjs";
7
+ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
8
+
9
+ function failure(error) {
10
+ let match = error.code;
11
+ let match$1 = error.message;
12
+ if (match !== undefined) {
13
+ return [
14
+ {
15
+ TAG: "Http",
16
+ _0: match
17
+ },
18
+ match$1
19
+ ];
20
+ } else if (match$1 !== undefined) {
21
+ return [
22
+ "TransportError",
23
+ match$1
24
+ ];
25
+ } else {
26
+ return [
27
+ "Closed",
28
+ undefined
29
+ ];
30
+ }
31
+ }
32
+
33
+ function subscribe(hyperSyncUrl, apiToken, onHeight, onStatus) {
34
+ return HeightStream.subscribe(15000, onHeight, onStatus, driver => {
35
+ let userAgent = `hyperindex/` + Utils.EnvioPackage.value.version;
36
+ let es = new Eventsource.EventSource(hyperSyncUrl + `/height/sse`, {
37
+ fetch: (url, args) => {
38
+ let headers = Utils.Dict.merge(Stdlib_Option.getOr(args.headers, {}), Object.fromEntries([
39
+ [
40
+ "Authorization",
41
+ `Bearer ` + apiToken
42
+ ],
43
+ [
44
+ "User-Agent",
45
+ userAgent
46
+ ]
47
+ ]));
48
+ let newrecord = {...args};
49
+ return fetch(url, (newrecord.headers = headers, newrecord));
50
+ }
51
+ });
52
+ es.onopen = () => driver.onConnected();
53
+ es.onerror = error => {
54
+ let match = failure(error);
55
+ driver.onFailure(match[0], match[1]);
56
+ };
57
+ es.addEventListener("ping", param => driver.onKeepAlive());
58
+ es.addEventListener("height", event => {
59
+ let height = Stdlib_Int.fromString(event.data, undefined);
60
+ if (height !== undefined) {
61
+ return driver.onHeight(height);
62
+ } else {
63
+ return driver.onUnreadable(event.data);
64
+ }
65
+ });
66
+ return () => {
67
+ es.close();
68
+ };
69
+ });
70
+ }
71
+
72
+ let staleTimeout = 15000;
73
+
74
+ export {
75
+ staleTimeout,
76
+ failure,
77
+ subscribe,
78
+ }
79
+ /* Utils Not a pure module */
@@ -1129,7 +1129,7 @@ let make = (
1129
1129
 
1130
1130
  let createHeightSubscription =
1131
1131
  ws->Option.map(wsUrl =>
1132
- (~onHeight) => RpcWebSocketHeightStream.subscribe(~wsUrl, ~chainId, ~onHeight)
1132
+ (~onHeight, ~onStatus) => EvmRpcWs.subscribe(~wsUrl, ~onHeight, ~onStatus)
1133
1133
  )
1134
1134
 
1135
1135
  {
@@ -8,6 +8,7 @@ import * as Source from "./Source.res.mjs";
8
8
  import * as Address from "../Address.res.mjs";
9
9
  import * as ChainId from "../ChainId.res.mjs";
10
10
  import * as Logging from "../Logging.res.mjs";
11
+ import * as EvmRpcWs from "./EvmRpcWs.res.mjs";
11
12
  import * as Internal from "../Internal.res.mjs";
12
13
  import * as BlockStore from "./BlockStore.res.mjs";
13
14
  import * as LazyLoader from "../LazyLoader.res.mjs";
@@ -24,7 +25,6 @@ import * as HyperSyncClient from "./HyperSyncClient.res.mjs";
24
25
  import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
25
26
  import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
26
27
  import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
27
- import * as RpcWebSocketHeightStream from "./RpcWebSocketHeightStream.res.mjs";
28
28
 
29
29
  let TransactionDataNotFound = /* @__PURE__ */Primitive_exceptions.create("RpcSource.TransactionDataNotFound");
30
30
 
@@ -1069,7 +1069,7 @@ function make(param) {
1069
1069
  },
1070
1070
  requestStats: drainRequestStats()
1071
1071
  }));
1072
- let createHeightSubscription = Stdlib_Option.map(param.ws, wsUrl => (onHeight => RpcWebSocketHeightStream.subscribe(wsUrl, chainId, onHeight)));
1072
+ let createHeightSubscription = Stdlib_Option.map(param.ws, wsUrl => ((onHeight, onStatus) => EvmRpcWs.subscribe(wsUrl, onHeight, onStatus)));
1073
1073
  return {
1074
1074
  name: name,
1075
1075
  sourceFor: param.sourceFor,
@@ -130,6 +130,56 @@ exception GetItemsError(getItemsError)
130
130
 
131
131
  type sourceFor = Sync | Fallback | Realtime
132
132
 
133
+ // Why a height subscription's connection ended. Closed, so a consumer decides
134
+ // what a failure means by matching on it rather than by recognising a string,
135
+ // and so every transport describes an outage in the same words.
136
+ type heightSubscriptionDownReason =
137
+ // Ended cleanly after serving long enough to have been worth making: a load
138
+ // balancer moving a connection, and routine.
139
+ | Rotated
140
+ // Ended cleanly without having served: a server dropping connections it
141
+ // ought to be keeping.
142
+ | Closed
143
+ // Delivered nothing at all for a whole staleness window.
144
+ | Stale
145
+ // Sent frames the transport could not read. Alone among these it never heals
146
+ // on its own, which is why consumers tell an operator about it.
147
+ | Unreadable
148
+ // No connection was established to begin with.
149
+ | ConnectFailed
150
+ // The provider refused the subscription.
151
+ | SubscribeRejected
152
+ // The socket itself reported an error.
153
+ | TransportError
154
+ // Refused with an HTTP status, which is the whole of what an SSE stream is
155
+ // told about a refusal.
156
+ | Http(int)
157
+ // The consumer gave the source up. Not an outage, but the connection is gone
158
+ // and a count that omitted it would leave the source looking connected.
159
+ | Unsubscribed
160
+
161
+ // Bounded, so it is safe as a metric label. Whatever the provider said about
162
+ // one failure belongs in `detail` and in a log line, never here.
163
+ let downReasonLabel = reason =>
164
+ switch reason {
165
+ | Rotated => "rotated"
166
+ | Closed => "closed"
167
+ | Stale => "stale"
168
+ | Unreadable => "unreadable"
169
+ | ConnectFailed => "connect-failed"
170
+ | SubscribeRejected => "subscribe-rejected"
171
+ | TransportError => "error"
172
+ | Http(code) => `http-${code->Int.toString}`
173
+ | Unsubscribed => "unsubscribed"
174
+ }
175
+
176
+ // Connection state of a height subscription, reported by every transport.
177
+ // `Down` repeats on each failed retry while the stream stays broken, and `Live`
178
+ // fires on every (re)connect, so consumers must treat both as idempotent.
179
+ // `detail` is whatever the provider said for this one failure — an error
180
+ // message, or the frame nobody could read.
181
+ type heightSubscriptionStatus = Live | Down({reason: heightSubscriptionDownReason, detail?: string})
182
+
133
183
  type t = {
134
184
  name: string,
135
185
  sourceFor: sourceFor,
@@ -160,7 +210,10 @@ type t = {
160
210
  ~retry: int,
161
211
  ~logger: Pino.t,
162
212
  ) => promise<blockRangeFetchResponse>,
163
- createHeightSubscription?: (~onHeight: int => unit) => unit => unit,
213
+ createHeightSubscription?: (
214
+ ~onHeight: int => unit,
215
+ ~onStatus: heightSubscriptionStatus => unit,
216
+ ) => unit => unit,
164
217
  // Invoked when a reorg or internally inconsistent response means local state
165
218
  // may point at an orphaned chain (e.g. the RPC block cache): drop all of it.
166
219
  // Deliberately takes no rollback target — the deepest reorged block isn't
@@ -50,6 +50,30 @@ let RateLimited = /* @__PURE__ */Primitive_exceptions.create("Source.RateLimited
50
50
 
51
51
  let GetItemsError = /* @__PURE__ */Primitive_exceptions.create("Source.GetItemsError");
52
52
 
53
+ function downReasonLabel(reason) {
54
+ if (typeof reason === "object") {
55
+ return `http-` + reason._0.toString();
56
+ }
57
+ switch (reason) {
58
+ case "Rotated" :
59
+ return "rotated";
60
+ case "Closed" :
61
+ return "closed";
62
+ case "Stale" :
63
+ return "stale";
64
+ case "Unreadable" :
65
+ return "unreadable";
66
+ case "ConnectFailed" :
67
+ return "connect-failed";
68
+ case "SubscribeRejected" :
69
+ return "subscribe-rejected";
70
+ case "TransportError" :
71
+ return "error";
72
+ case "Unsubscribed" :
73
+ return "unsubscribed";
74
+ }
75
+ }
76
+
53
77
  export {
54
78
  nativeFailurePrefix,
55
79
  nativeFailurePayloadSchema,
@@ -58,5 +82,6 @@ export {
58
82
  SourceBehindHead,
59
83
  RateLimited,
60
84
  GetItemsError,
85
+ downReasonLabel,
61
86
  }
62
87
  /* nativeFailurePayloadSchema Not a pure module */