envio 3.0.0-alpha.2 → 3.0.0-alpha.20

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/README.md +164 -30
  2. package/bin.mjs +49 -0
  3. package/evm.schema.json +79 -169
  4. package/fuel.schema.json +50 -21
  5. package/index.d.ts +497 -1
  6. package/index.js +4 -0
  7. package/package.json +42 -31
  8. package/rescript.json +4 -1
  9. package/src/Batch.res +11 -8
  10. package/src/Batch.res.mjs +11 -9
  11. package/src/ChainFetcher.res +531 -0
  12. package/src/ChainFetcher.res.mjs +339 -0
  13. package/src/ChainManager.res +190 -0
  14. package/src/ChainManager.res.mjs +166 -0
  15. package/src/Change.res +3 -3
  16. package/src/Config.gen.ts +19 -0
  17. package/src/Config.res +737 -22
  18. package/src/Config.res.mjs +703 -26
  19. package/src/{Indexer.res → Ctx.res} +1 -1
  20. package/src/Ecosystem.res +9 -124
  21. package/src/Ecosystem.res.mjs +19 -160
  22. package/src/Env.res +30 -74
  23. package/src/Env.res.mjs +25 -87
  24. package/src/Envio.gen.ts +3 -1
  25. package/src/Envio.res +20 -9
  26. package/src/EventProcessing.res +469 -0
  27. package/src/EventProcessing.res.mjs +337 -0
  28. package/src/EvmTypes.gen.ts +6 -0
  29. package/src/EvmTypes.res +1 -0
  30. package/src/FetchState.res +1256 -639
  31. package/src/FetchState.res.mjs +1135 -612
  32. package/src/GlobalState.res +1190 -0
  33. package/src/GlobalState.res.mjs +1183 -0
  34. package/src/GlobalStateManager.res +68 -0
  35. package/src/GlobalStateManager.res.mjs +75 -0
  36. package/src/GlobalStateManager.resi +7 -0
  37. package/src/HandlerLoader.res +89 -0
  38. package/src/HandlerLoader.res.mjs +79 -0
  39. package/src/HandlerRegister.res +357 -0
  40. package/src/HandlerRegister.res.mjs +299 -0
  41. package/src/{EventRegister.resi → HandlerRegister.resi} +13 -13
  42. package/src/Hasura.res +111 -175
  43. package/src/Hasura.res.mjs +88 -150
  44. package/src/InMemoryStore.res +1 -1
  45. package/src/InMemoryStore.res.mjs +3 -3
  46. package/src/InMemoryTable.res +1 -1
  47. package/src/InMemoryTable.res.mjs +1 -1
  48. package/src/Internal.gen.ts +4 -0
  49. package/src/Internal.res +230 -12
  50. package/src/Internal.res.mjs +115 -1
  51. package/src/LoadLayer.res +444 -0
  52. package/src/LoadLayer.res.mjs +296 -0
  53. package/src/LoadLayer.resi +32 -0
  54. package/src/LogSelection.res +33 -27
  55. package/src/LogSelection.res.mjs +6 -0
  56. package/src/Logging.res +21 -7
  57. package/src/Logging.res.mjs +16 -8
  58. package/src/Main.res +377 -0
  59. package/src/Main.res.mjs +339 -0
  60. package/src/Persistence.res +7 -21
  61. package/src/Persistence.res.mjs +3 -3
  62. package/src/PgStorage.gen.ts +10 -0
  63. package/src/PgStorage.res +116 -69
  64. package/src/PgStorage.res.d.mts +5 -0
  65. package/src/PgStorage.res.mjs +93 -50
  66. package/src/Prometheus.res +294 -224
  67. package/src/Prometheus.res.mjs +353 -340
  68. package/src/ReorgDetection.res +6 -10
  69. package/src/ReorgDetection.res.mjs +6 -6
  70. package/src/SafeCheckpointTracking.res +4 -4
  71. package/src/SafeCheckpointTracking.res.mjs +2 -2
  72. package/src/Sink.res +4 -2
  73. package/src/Sink.res.mjs +2 -1
  74. package/src/TableIndices.res +0 -1
  75. package/src/TestIndexer.res +692 -0
  76. package/src/TestIndexer.res.mjs +527 -0
  77. package/src/TestIndexerProxyStorage.res +205 -0
  78. package/src/TestIndexerProxyStorage.res.mjs +151 -0
  79. package/src/TopicFilter.res +1 -1
  80. package/src/Types.ts +1 -1
  81. package/src/UserContext.res +424 -0
  82. package/src/UserContext.res.mjs +279 -0
  83. package/src/Utils.res +97 -26
  84. package/src/Utils.res.mjs +91 -44
  85. package/src/bindings/BigInt.res +10 -0
  86. package/src/bindings/BigInt.res.mjs +15 -0
  87. package/src/bindings/ClickHouse.res +120 -23
  88. package/src/bindings/ClickHouse.res.mjs +118 -28
  89. package/src/bindings/DateFns.res +74 -0
  90. package/src/bindings/DateFns.res.mjs +22 -0
  91. package/src/bindings/EventSource.res +8 -1
  92. package/src/bindings/EventSource.res.mjs +8 -1
  93. package/src/bindings/Express.res +1 -0
  94. package/src/bindings/Hrtime.res +14 -1
  95. package/src/bindings/Hrtime.res.mjs +22 -2
  96. package/src/bindings/Hrtime.resi +4 -0
  97. package/src/bindings/Lodash.res +0 -1
  98. package/src/bindings/NodeJs.res +49 -3
  99. package/src/bindings/NodeJs.res.mjs +11 -3
  100. package/src/bindings/Pino.res +24 -10
  101. package/src/bindings/Pino.res.mjs +14 -8
  102. package/src/bindings/Postgres.gen.ts +8 -0
  103. package/src/bindings/Postgres.res +5 -1
  104. package/src/bindings/Postgres.res.d.mts +5 -0
  105. package/src/bindings/PromClient.res +0 -10
  106. package/src/bindings/PromClient.res.mjs +0 -3
  107. package/src/bindings/Vitest.res +142 -0
  108. package/src/bindings/Vitest.res.mjs +9 -0
  109. package/src/bindings/WebSocket.res +27 -0
  110. package/src/bindings/WebSocket.res.mjs +2 -0
  111. package/src/bindings/Yargs.res +8 -0
  112. package/src/bindings/Yargs.res.mjs +2 -0
  113. package/src/db/EntityHistory.res +7 -7
  114. package/src/db/EntityHistory.res.mjs +9 -9
  115. package/src/db/InternalTable.res +59 -111
  116. package/src/db/InternalTable.res.mjs +73 -104
  117. package/src/db/Table.res +27 -8
  118. package/src/db/Table.res.mjs +25 -14
  119. package/src/sources/Evm.res +84 -0
  120. package/src/sources/Evm.res.mjs +105 -0
  121. package/src/sources/EvmChain.res +94 -0
  122. package/src/sources/EvmChain.res.mjs +60 -0
  123. package/src/sources/Fuel.res +19 -34
  124. package/src/sources/Fuel.res.mjs +34 -16
  125. package/src/sources/FuelSDK.res +38 -0
  126. package/src/sources/FuelSDK.res.mjs +29 -0
  127. package/src/sources/HyperFuel.res +2 -2
  128. package/src/sources/HyperFuel.resi +1 -1
  129. package/src/sources/HyperFuelClient.res +2 -2
  130. package/src/sources/HyperFuelSource.res +33 -13
  131. package/src/sources/HyperFuelSource.res.mjs +24 -16
  132. package/src/sources/HyperSync.res +36 -6
  133. package/src/sources/HyperSync.res.mjs +9 -7
  134. package/src/sources/HyperSync.resi +4 -0
  135. package/src/sources/HyperSyncClient.res +1 -1
  136. package/src/sources/HyperSyncHeightStream.res +47 -116
  137. package/src/sources/HyperSyncHeightStream.res.mjs +46 -73
  138. package/src/sources/HyperSyncSource.res +118 -139
  139. package/src/sources/HyperSyncSource.res.mjs +104 -121
  140. package/src/sources/Rpc.res +86 -14
  141. package/src/sources/Rpc.res.mjs +101 -9
  142. package/src/sources/RpcSource.res +621 -364
  143. package/src/sources/RpcSource.res.mjs +843 -410
  144. package/src/sources/RpcWebSocketHeightStream.res +181 -0
  145. package/src/sources/RpcWebSocketHeightStream.res.mjs +196 -0
  146. package/src/sources/Source.res +7 -5
  147. package/src/sources/SourceManager.res +325 -225
  148. package/src/sources/SourceManager.res.mjs +314 -171
  149. package/src/sources/SourceManager.resi +17 -6
  150. package/src/sources/Svm.res +81 -0
  151. package/src/sources/Svm.res.mjs +90 -0
  152. package/src/tui/Tui.res +247 -0
  153. package/src/tui/Tui.res.mjs +337 -0
  154. package/src/tui/bindings/Ink.res +371 -0
  155. package/src/tui/bindings/Ink.res.mjs +72 -0
  156. package/src/tui/bindings/Style.res +123 -0
  157. package/src/tui/bindings/Style.res.mjs +2 -0
  158. package/src/tui/components/BufferedProgressBar.res +40 -0
  159. package/src/tui/components/BufferedProgressBar.res.mjs +57 -0
  160. package/src/tui/components/CustomHooks.res +122 -0
  161. package/src/tui/components/CustomHooks.res.mjs +179 -0
  162. package/src/tui/components/Messages.res +41 -0
  163. package/src/tui/components/Messages.res.mjs +75 -0
  164. package/src/tui/components/SyncETA.res +174 -0
  165. package/src/tui/components/SyncETA.res.mjs +263 -0
  166. package/src/tui/components/TuiData.res +47 -0
  167. package/src/tui/components/TuiData.res.mjs +34 -0
  168. package/svm.schema.json +112 -0
  169. package/bin.js +0 -48
  170. package/src/EventRegister.res +0 -241
  171. package/src/EventRegister.res.mjs +0 -240
  172. package/src/bindings/Ethers.gen.ts +0 -14
  173. package/src/bindings/Ethers.res +0 -204
  174. package/src/bindings/Ethers.res.mjs +0 -130
  175. /package/src/{Indexer.res.mjs → Ctx.res.mjs} +0 -0
@@ -9,6 +9,7 @@ import * as $$Promise from "../bindings/Promise.res.mjs";
9
9
  import * as HyperFuel from "./HyperFuel.res.mjs";
10
10
  import * as HyperSync from "./HyperSync.res.mjs";
11
11
  import * as Belt_Array from "rescript/lib/es6/belt_Array.js";
12
+ import * as Prometheus from "../Prometheus.res.mjs";
12
13
  import * as Belt_Option from "rescript/lib/es6/belt_Option.js";
13
14
  import * as EventRouter from "./EventRouter.res.mjs";
14
15
  import * as ErrorHandling from "../ErrorHandling.res.mjs";
@@ -185,8 +186,9 @@ function memoGetSelectionConfig(chain) {
185
186
  function make(param) {
186
187
  var endpointUrl = param.endpointUrl;
187
188
  var chain = param.chain;
189
+ var name = "HyperFuel";
188
190
  var getSelectionConfig = memoGetSelectionConfig(chain);
189
- var getItemsOrThrow = async function (fromBlock, toBlock, addressesByContractName, indexingContracts, currentBlockHeight, param, selection, retry, logger) {
191
+ var getItemsOrThrow = async function (fromBlock, toBlock, addressesByContractName, indexingContracts, knownHeight, param, selection, retry, logger) {
190
192
  var mkLogAndRaise = function (extra, extra$1) {
191
193
  return ErrorHandling.mkLogAndRaise(logger, extra, extra$1);
192
194
  };
@@ -194,6 +196,7 @@ function make(param) {
194
196
  var selectionConfig = getSelectionConfig(selection);
195
197
  var recieptsSelection = selectionConfig.getRecieptsSelection(addressesByContractName);
196
198
  var startFetchingBatchTimeRef = Hrtime.makeTimer();
199
+ Prometheus.SourceRequestCount.increment(name, chain, "getLogs");
197
200
  var pageUnsafe;
198
201
  try {
199
202
  pageUnsafe = await HyperFuel.GetLogs.query(endpointUrl, fromBlock, toBlock, recieptsSelection);
@@ -221,7 +224,7 @@ function make(param) {
221
224
  _1: {
222
225
  TAG: "FailedGettingItems",
223
226
  exn: null,
224
- attemptedToBlock: Belt_Option.getWithDefault(toBlock, currentBlockHeight),
227
+ attemptedToBlock: Belt_Option.getWithDefault(toBlock, knownHeight),
225
228
  retry: tmp
226
229
  },
227
230
  Error: new Error()
@@ -232,7 +235,7 @@ function make(param) {
232
235
  _1: {
233
236
  TAG: "FailedGettingItems",
234
237
  exn: error,
235
- attemptedToBlock: Belt_Option.getWithDefault(toBlock, currentBlockHeight),
238
+ attemptedToBlock: Belt_Option.getWithDefault(toBlock, knownHeight),
236
239
  retry: {
237
240
  TAG: "WithBackoff",
238
241
  message: "Unexpected issue while fetching events from HyperFuel client. Attempt a retry.",
@@ -242,8 +245,8 @@ function make(param) {
242
245
  Error: new Error()
243
246
  };
244
247
  }
245
- var pageFetchTime = Hrtime.intFromMillis(Hrtime.toMillis(Hrtime.timeSince(startFetchingBatchTimeRef)));
246
- var currentBlockHeight$1 = pageUnsafe.archiveHeight;
248
+ var pageFetchTime = Hrtime.toSecondsFloat(Hrtime.timeSince(startFetchingBatchTimeRef));
249
+ var knownHeight$1 = pageUnsafe.archiveHeight;
247
250
  var heighestBlockQueried = pageUnsafe.nextBlock - 1 | 0;
248
251
  var match = Belt_Array.get(pageUnsafe.items, pageUnsafe.items.length - 1 | 0);
249
252
  var lastBlockQueriedPromise;
@@ -392,22 +395,22 @@ function make(param) {
392
395
  }
393
396
  };
394
397
  }));
395
- var parsingTimeElapsed = Hrtime.intFromMillis(Hrtime.toMillis(Hrtime.timeSince(parsingTimeRef)));
398
+ var parsingTimeElapsed = Hrtime.toSecondsFloat(Hrtime.timeSince(parsingTimeRef));
396
399
  var rangeLastBlock = await lastBlockQueriedPromise;
397
400
  var reorgGuard = {
398
401
  rangeLastBlock: rangeLastBlock,
399
402
  prevRangeLastBlock: undefined
400
403
  };
401
- var totalTimeElapsed = Hrtime.intFromMillis(Hrtime.toMillis(Hrtime.timeSince(totalTimeRef)));
402
- var stats_parsing$unknowntime$unknown$lparms$rpar = parsingTimeElapsed;
403
- var stats_page$unknownfetch$unknowntime$unknown$lparms$rpar = pageFetchTime;
404
+ var totalTimeElapsed = Hrtime.toSecondsFloat(Hrtime.timeSince(totalTimeRef));
405
+ var stats_parsing$unknowntime$unknown$lpars$rpar = parsingTimeElapsed;
406
+ var stats_page$unknownfetch$unknowntime$unknown$lpars$rpar = pageFetchTime;
404
407
  var stats = {
405
- "total time elapsed (ms)": totalTimeElapsed,
406
- "parsing time (ms)": stats_parsing$unknowntime$unknown$lparms$rpar,
407
- "page fetch time (ms)": stats_page$unknownfetch$unknowntime$unknown$lparms$rpar
408
+ "total time elapsed (s)": totalTimeElapsed,
409
+ "parsing time (s)": stats_parsing$unknowntime$unknown$lpars$rpar,
410
+ "page fetch time (s)": stats_page$unknownfetch$unknowntime$unknown$lpars$rpar
408
411
  };
409
412
  return {
410
- currentBlockHeight: currentBlockHeight$1,
413
+ knownHeight: knownHeight$1,
411
414
  reorgGuard: reorgGuard,
412
415
  parsedQueueItems: parsedQueueItems,
413
416
  fromBlockQueried: fromBlock,
@@ -421,14 +424,19 @@ function make(param) {
421
424
  };
422
425
  var jsonApiClient = Rest.client(endpointUrl, undefined);
423
426
  return {
424
- name: "HyperFuel",
427
+ name: name,
425
428
  sourceFor: "Sync",
426
429
  chain: chain,
427
430
  poweredByHyperSync: true,
428
431
  pollingInterval: 100,
429
432
  getBlockHashes: getBlockHashes,
430
- getHeightOrThrow: (function () {
431
- return Rest.$$fetch(HyperFuel.heightRoute, undefined, jsonApiClient);
433
+ getHeightOrThrow: (async function () {
434
+ var timerRef = Hrtime.makeTimer();
435
+ var height = await Rest.$$fetch(HyperFuel.heightRoute, undefined, jsonApiClient);
436
+ var seconds = Hrtime.toSecondsFloat(Hrtime.timeSince(timerRef));
437
+ Prometheus.SourceRequestCount.increment(name, chain, "getHeight");
438
+ Prometheus.SourceRequestCount.addSeconds(name, chain, "getHeight", seconds);
439
+ return height;
432
440
  }),
433
441
  getItemsOrThrow: getItemsOrThrow
434
442
  };
@@ -114,7 +114,7 @@ module GetLogs = {
114
114
  }
115
115
 
116
116
  //Topics can be nullable and still need to be filtered
117
- let logUnsanitized: Log.t = event.log->Utils.magic
117
+ let logUnsanitized: Log.t = event.log->(Utils.magic: HyperSyncClient.ResponseTypes.log => Log.t)
118
118
  let topics = event.log.topics->Option.getUnsafe->Array.keepMap(Js.Nullable.toOption)
119
119
  let address = event.log.address->Option.getUnsafe
120
120
  let log = {
@@ -125,8 +125,14 @@ module GetLogs = {
125
125
 
126
126
  {
127
127
  log,
128
- block: event.block->Utils.magic,
129
- transaction: event.transaction->Utils.magic,
128
+ block: event.block->(
129
+ Utils.magic: option<
130
+ HyperSyncClient.ResponseTypes.block,
131
+ > => HyperSyncClient.ResponseTypes.block
132
+ ),
133
+ transaction: event.transaction->(
134
+ Utils.magic: option<HyperSyncClient.ResponseTypes.transaction> => Internal.eventTransaction
135
+ ),
130
136
  }
131
137
  }
132
138
 
@@ -245,6 +251,8 @@ module BlockData = {
245
251
  ~apiToken,
246
252
  ~fromBlock,
247
253
  ~toBlock,
254
+ ~sourceName,
255
+ ~chainId,
248
256
  ~logger,
249
257
  ): queryResponse<array<ReorgDetection.blockDataWithTimestamp>> => {
250
258
  let body = makeRequestBody(~fromBlock, ~toBlock)
@@ -258,6 +266,7 @@ module BlockData = {
258
266
  },
259
267
  )
260
268
 
269
+ Prometheus.SourceRequestCount.increment(~sourceName, ~chainId, ~method="getBlockHashes")
261
270
  let maybeSuccessfulRes = switch await Time.retryAsyncWithExponentialBackOff(() =>
262
271
  HyperSyncJsonApi.queryRoute->Rest.fetch(
263
272
  {
@@ -281,7 +290,15 @@ module BlockData = {
281
290
  `Block #${fromBlock->Int.toString} not found in HyperSync. HyperSync has multiple instances and it's possible that they drift independently slightly from the head. Indexing should continue correctly after retrying the query in ${delayMilliseconds->Int.toString}ms.`,
282
291
  )
283
292
  await Time.resolvePromiseAfterDelay(~delayMilliseconds)
284
- await queryBlockData(~serverUrl, ~apiToken, ~fromBlock, ~toBlock, ~logger)
293
+ await queryBlockData(
294
+ ~serverUrl,
295
+ ~apiToken,
296
+ ~fromBlock,
297
+ ~toBlock,
298
+ ~sourceName,
299
+ ~chainId,
300
+ ~logger,
301
+ )
285
302
  }
286
303
  | Some(res) =>
287
304
  switch res->convertResponse {
@@ -292,6 +309,8 @@ module BlockData = {
292
309
  ~apiToken,
293
310
  ~fromBlock=res.nextBlock,
294
311
  ~toBlock,
312
+ ~sourceName,
313
+ ~chainId,
295
314
  ~logger,
296
315
  )
297
316
  restRes->Result.map(rest => datas->Array.concat(rest))
@@ -301,7 +320,14 @@ module BlockData = {
301
320
  }
302
321
  }
303
322
 
304
- let queryBlockDataMulti = async (~serverUrl, ~apiToken, ~blockNumbers, ~logger) => {
323
+ let queryBlockDataMulti = async (
324
+ ~serverUrl,
325
+ ~apiToken,
326
+ ~blockNumbers,
327
+ ~sourceName,
328
+ ~chainId,
329
+ ~logger,
330
+ ) => {
305
331
  switch blockNumbers->Array.get(0) {
306
332
  | None => Ok([])
307
333
  | Some(firstBlock) => {
@@ -328,6 +354,8 @@ module BlockData = {
328
354
  ~toBlock=toBlock.contents,
329
355
  ~serverUrl,
330
356
  ~apiToken,
357
+ ~sourceName,
358
+ ~chainId,
331
359
  ~logger,
332
360
  )
333
361
  let filtered = res->Result.map(datas => {
@@ -346,12 +374,14 @@ module BlockData = {
346
374
  }
347
375
  }
348
376
 
349
- let queryBlockData = (~serverUrl, ~apiToken, ~blockNumber, ~logger) =>
377
+ let queryBlockData = (~serverUrl, ~apiToken, ~blockNumber, ~sourceName, ~chainId, ~logger) =>
350
378
  BlockData.queryBlockData(
351
379
  ~serverUrl,
352
380
  ~apiToken,
353
381
  ~fromBlock=blockNumber,
354
382
  ~toBlock=blockNumber,
383
+ ~sourceName,
384
+ ~chainId,
355
385
  ~logger,
356
386
  )->Promise.thenResolve(res => res->Result.map(res => res->Array.get(0)))
357
387
  let queryBlockDataMulti = BlockData.queryBlockDataMulti
@@ -7,6 +7,7 @@ import * as $$BigInt from "../bindings/BigInt.res.mjs";
7
7
  import * as Js_exn from "rescript/lib/es6/js_exn.js";
8
8
  import * as Logging from "../Logging.res.mjs";
9
9
  import * as Belt_Array from "rescript/lib/es6/belt_Array.js";
10
+ import * as Prometheus from "../Prometheus.res.mjs";
10
11
  import * as Belt_Option from "rescript/lib/es6/belt_Option.js";
11
12
  import * as Belt_Result from "rescript/lib/es6/belt_Result.js";
12
13
  import * as Caml_option from "rescript/lib/es6/caml_option.js";
@@ -226,13 +227,14 @@ function convertResponse(res) {
226
227
  })));
227
228
  }
228
229
 
229
- async function queryBlockData(serverUrl, apiToken, fromBlock, toBlock, logger) {
230
+ async function queryBlockData(serverUrl, apiToken, fromBlock, toBlock, sourceName, chainId, logger) {
230
231
  var body = makeRequestBody$1(fromBlock, toBlock);
231
232
  var logger$1 = Logging.createChildFrom(logger, {
232
233
  logType: "HyperSync get block hash query",
233
234
  fromBlock: fromBlock,
234
235
  toBlock: toBlock
235
236
  });
237
+ Prometheus.SourceRequestCount.increment(sourceName, chainId, "getBlockHashes");
236
238
  var maybeSuccessfulRes;
237
239
  var exit = 0;
238
240
  var res;
@@ -260,7 +262,7 @@ async function queryBlockData(serverUrl, apiToken, fromBlock, toBlock, logger) {
260
262
  return err;
261
263
  }
262
264
  var datas = err._0;
263
- var restRes = await queryBlockData(serverUrl, apiToken, maybeSuccessfulRes.nextBlock, toBlock, logger$1);
265
+ var restRes = await queryBlockData(serverUrl, apiToken, maybeSuccessfulRes.nextBlock, toBlock, sourceName, chainId, logger$1);
264
266
  return Belt_Result.map(restRes, (function (rest) {
265
267
  return Belt_Array.concat(datas, rest);
266
268
  }));
@@ -270,10 +272,10 @@ async function queryBlockData(serverUrl, apiToken, fromBlock, toBlock, logger) {
270
272
  });
271
273
  Logging.childInfo(logger$2, "Block #" + String(fromBlock) + " not found in HyperSync. HyperSync has multiple instances and it's possible that they drift independently slightly from the head. Indexing should continue correctly after retrying the query in " + String(100) + "ms.");
272
274
  await Time.resolvePromiseAfterDelay(100);
273
- return await queryBlockData(serverUrl, apiToken, fromBlock, toBlock, logger$2);
275
+ return await queryBlockData(serverUrl, apiToken, fromBlock, toBlock, sourceName, chainId, logger$2);
274
276
  }
275
277
 
276
- async function queryBlockDataMulti(serverUrl, apiToken, blockNumbers, logger) {
278
+ async function queryBlockDataMulti(serverUrl, apiToken, blockNumbers, sourceName, chainId, logger) {
277
279
  var firstBlock = Belt_Array.get(blockNumbers, 0);
278
280
  if (firstBlock === undefined) {
279
281
  return {
@@ -297,7 +299,7 @@ async function queryBlockDataMulti(serverUrl, apiToken, blockNumbers, logger) {
297
299
  if ((toBlock - fromBlock | 0) > 1000) {
298
300
  Js_exn.raiseError("Invalid block data request. Range of block numbers is too large. Max range is 1000. Requested range: " + String(fromBlock) + "-" + String(toBlock));
299
301
  }
300
- var res = await queryBlockData(serverUrl, apiToken, fromBlock, toBlock, logger);
302
+ var res = await queryBlockData(serverUrl, apiToken, fromBlock, toBlock, sourceName, chainId, logger);
301
303
  var filtered = Belt_Result.map(res, (function (datas) {
302
304
  return Belt_Array.keep(datas, (function (data) {
303
305
  return set.delete(data.blockNumber);
@@ -309,8 +311,8 @@ async function queryBlockDataMulti(serverUrl, apiToken, blockNumbers, logger) {
309
311
  return filtered;
310
312
  }
311
313
 
312
- function queryBlockData$1(serverUrl, apiToken, blockNumber, logger) {
313
- return queryBlockData(serverUrl, apiToken, blockNumber, blockNumber, logger).then(function (res) {
314
+ function queryBlockData$1(serverUrl, apiToken, blockNumber, sourceName, chainId, logger) {
315
+ return queryBlockData(serverUrl, apiToken, blockNumber, blockNumber, sourceName, chainId, logger).then(function (res) {
314
316
  return Belt_Result.map(res, (function (res) {
315
317
  return Belt_Array.get(res, 0);
316
318
  }));
@@ -56,6 +56,8 @@ let queryBlockData: (
56
56
  ~serverUrl: string,
57
57
  ~apiToken: string,
58
58
  ~blockNumber: int,
59
+ ~sourceName: string,
60
+ ~chainId: int,
59
61
  ~logger: Pino.t,
60
62
  ) => promise<queryResponse<option<ReorgDetection.blockDataWithTimestamp>>>
61
63
 
@@ -63,6 +65,8 @@ let queryBlockDataMulti: (
63
65
  ~serverUrl: string,
64
66
  ~apiToken: string,
65
67
  ~blockNumbers: array<int>,
68
+ ~sourceName: string,
69
+ ~chainId: int,
66
70
  ~logger: Pino.t,
67
71
  ) => promise<queryResponse<array<ReorgDetection.blockDataWithTimestamp>>>
68
72
 
@@ -390,7 +390,7 @@ module ResponseTypes = {
390
390
  l1Fee?: bigint,
391
391
  l1GasPrice?: bigint,
392
392
  l1GasUsed?: bigint,
393
- l1FeeScalar?: int,
393
+ l1FeeScalar?: float,
394
394
  gasUsedForL1?: bigint,
395
395
  authorizationList?: array<authorizationList>,
396
396
  }
@@ -1,28 +1,15 @@
1
1
  /*
2
- Pure js implementation of the HyperSync height stream.
2
+ Pure subscription-based implementation of the HyperSync height stream.
3
3
  */
4
4
 
5
- type t = {
6
- heightRef: ref<int>,
7
- errorRef: ref<option<string>>,
8
- timeoutIdRef: ref<Js.Global.timeoutId>,
9
- eventsourceRef: ref<option<EventSource.t>>,
10
- }
11
-
12
- let make = (~hyperSyncUrl, ~apiToken) => {
13
- /**
14
- On every successful ping or height event, clear the timeout and set a new one.
5
+ let subscribe = (~hyperSyncUrl, ~apiToken, ~chainId, ~onHeight: int => unit): (unit => unit) => {
6
+ let eventsourceRef = ref(None)
7
+ // Timeout doesn't do anything for initialization
8
+ let timeoutIdRef = ref(Js.Global.setTimeout(() => (), 0))
15
9
 
16
- if the timeout lapses, close and reconnect the EventSource.
17
- */
18
- let rec updateTimeoutId = (
19
- ~eventsourceRef: ref<option<EventSource.t>>,
20
- ~timeoutIdRef: ref<Js.Global.timeoutId>,
21
- ~hyperSyncUrl,
22
- ~apiToken,
23
- ~heightRef: ref<int>,
24
- ~errorRef: ref<option<string>>,
25
- ) => {
10
+ // On every successful ping or height event, clear the timeout and set a new one.
11
+ // If the timeout lapses, close and reconnect the EventSource.
12
+ let rec updateTimeoutId = () => {
26
13
  timeoutIdRef.contents->Js.Global.clearTimeout
27
14
 
28
15
  // Should receive a ping at least every 5s, so 15s is a safe margin
@@ -34,31 +21,15 @@ let make = (~hyperSyncUrl, ~apiToken) => {
34
21
  "url": hyperSyncUrl,
35
22
  "staleTimeMillis": staleTimeMillis,
36
23
  })
37
- refreshEventSource(
38
- ~eventsourceRef,
39
- ~hyperSyncUrl,
40
- ~apiToken,
41
- ~heightRef,
42
- ~errorRef,
43
- ~timeoutIdRef,
44
- )
24
+ refreshEventSource()
45
25
  }, staleTimeMillis)
46
26
 
47
27
  timeoutIdRef := newTimeoutId
48
28
  }
49
- and /**
50
- Instantiate a new EventSource and set it to the shared refs.
51
- Add the necessary event listeners, handle errors
52
- and update the timeout.
53
- */
54
- refreshEventSource = (
55
- ~eventsourceRef: ref<option<EventSource.t>>,
56
- ~hyperSyncUrl,
57
- ~apiToken,
58
- ~heightRef: ref<int>,
59
- ~errorRef: ref<option<string>>,
60
- ~timeoutIdRef: ref<Js.Global.timeoutId>,
61
- ) => {
29
+ // Instantiate a new EventSource and set it to the shared refs.
30
+ // Add the necessary event listeners, handle errors
31
+ // and update the timeout.
32
+ and refreshEventSource = () => {
62
33
  // Close the old EventSource if it exists (on a new connection after timeout)
63
34
  switch eventsourceRef.contents {
64
35
  | Some(es) => es->EventSource.close
@@ -69,17 +40,25 @@ let make = (~hyperSyncUrl, ~apiToken) => {
69
40
  let es = EventSource.create(
70
41
  ~url=`${hyperSyncUrl}/height/sse`,
71
42
  ~options={
72
- headers: Js.Dict.fromArray([
73
- ("Authorization", `Bearer ${apiToken}`),
74
- ("User-Agent", userAgent),
75
- ]),
43
+ fetch: (url, ~args) => {
44
+ EventSource.Fetch.fetch(
45
+ url,
46
+ ~args={
47
+ ...args,
48
+ headers: Js.Dict.fromArray([
49
+ ("Authorization", `Bearer ${apiToken}`),
50
+ ("User-Agent", userAgent),
51
+ ]),
52
+ },
53
+ )
54
+ },
76
55
  },
77
56
  )
78
57
 
79
58
  // Set the new EventSource to the shared ref
80
59
  eventsourceRef := Some(es)
81
60
  // Update the timeout in case connection goes stale
82
- updateTimeoutId(~eventsourceRef, ~timeoutIdRef, ~hyperSyncUrl, ~apiToken, ~heightRef, ~errorRef)
61
+ updateTimeoutId()
83
62
 
84
63
  es->EventSource.onopen(_ => {
85
64
  Logging.trace({"msg": "SSE connection opened for height stream", "url": hyperSyncUrl})
@@ -90,90 +69,42 @@ let make = (~hyperSyncUrl, ~apiToken) => {
90
69
  "msg": "EventSource error",
91
70
  "error": error->Js.Exn.message,
92
71
  })
93
- // On errors, set the error ref
94
- // so that getHeight can raise an error
95
- errorRef :=
96
- Some(error->Js.Exn.message->Belt.Option.getWithDefault("Unexpected no error.message"))
97
72
  })
98
73
 
99
74
  es->EventSource.addEventListener("ping", _event => {
100
75
  // ping lets us know from the server that the connection is still alive
101
- // and that the height hasn't updated for 5seconds
76
+ // and that the height hasn't updated for 5 seconds
102
77
  // update the timeout on each successful ping received
103
- updateTimeoutId(
104
- ~eventsourceRef,
105
- ~timeoutIdRef,
106
- ~hyperSyncUrl,
107
- ~apiToken,
108
- ~heightRef,
109
- ~errorRef,
110
- )
111
- // reset the error ref, since we had a successful ping
112
- errorRef := None
78
+ updateTimeoutId()
113
79
  })
114
80
 
115
81
  es->EventSource.addEventListener("height", event => {
116
82
  switch event.data->Belt.Int.fromString {
117
83
  | Some(height) =>
118
- // On a successful height event, update the timeout
119
- // and reset the error ref
120
- updateTimeoutId(
121
- ~eventsourceRef,
122
- ~timeoutIdRef,
123
- ~hyperSyncUrl,
124
- ~apiToken,
125
- ~heightRef,
126
- ~errorRef,
84
+ // Track the SSE height event
85
+ Prometheus.SourceRequestCount.increment(
86
+ ~sourceName="HyperSync",
87
+ ~chainId,
88
+ ~method="heightStream",
127
89
  )
128
- errorRef := None
129
- // Set the actual height ref
130
- heightRef := height
131
- | None =>
132
- Logging.trace({"msg": "Height was not a number in event.data", "data": event.data})
133
- errorRef := Some("Height was not a number in event.data")
90
+ // On a successful height event, update the timeout
91
+ updateTimeoutId()
92
+ // Call the callback with the new height
93
+ onHeight(height)
94
+ | None => Logging.trace({"msg": "Height was not a number in event.data", "data": event.data})
134
95
  }
135
96
  })
136
97
  }
137
98
 
138
- // Refs used between the functions
99
+ // Start the EventSource connection
100
+ refreshEventSource()
139
101
 
140
- let heightRef = ref(0)
141
- let errorRef = ref(None)
142
- let eventsourceRef = ref(None)
143
- // Timeout doesn't do anything for initalization
144
- let timeoutIdRef = ref(Js.Global.setTimeout(() => (), 0))
145
- refreshEventSource(
146
- ~eventsourceRef,
147
- ~hyperSyncUrl,
148
- ~apiToken,
149
- ~heightRef,
150
- ~errorRef,
151
- ~timeoutIdRef,
152
- )
153
-
154
- {
155
- heightRef,
156
- errorRef,
157
- timeoutIdRef,
158
- eventsourceRef,
159
- }
160
- }
161
-
162
- let getHeight = async (t: t) => {
163
- while t.heightRef.contents == 0 && t.errorRef.contents == None {
164
- // Poll internally until height is over 0
165
- await Utils.delay(200)
166
- }
167
- switch t.errorRef.contents {
168
- | None => t.heightRef.contents
169
- | Some(error) => Js.Exn.raiseError(error)
170
- }
171
- }
172
-
173
- let close = t => {
174
- t.timeoutIdRef.contents->Js.Global.clearTimeout
175
- switch t.eventsourceRef.contents {
176
- | Some(es) => es->EventSource.close
177
- | None => ()
102
+ // Return unsubscribe function
103
+ () => {
104
+ timeoutIdRef.contents->Js.Global.clearTimeout
105
+ switch eventsourceRef.contents {
106
+ | Some(es) => es->EventSource.close
107
+ | None => ()
108
+ }
178
109
  }
179
110
  }