envio 3.15.0 → 3.16.0-subgraph

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 (186) hide show
  1. package/README.md +40 -34
  2. package/evm.schema.json +11 -2
  3. package/fuel.schema.json +10 -1
  4. package/index.d.ts +6 -0
  5. package/licenses/README.md +1 -1
  6. package/package.json +10 -9
  7. package/src/Batch.res.mjs +5 -5
  8. package/src/BatchProcessing.res +1 -0
  9. package/src/BatchProcessing.res.mjs +1 -0
  10. package/src/Bin.res +7 -0
  11. package/src/Bin.res.mjs +8 -0
  12. package/src/ChainFetching.res +450 -16
  13. package/src/ChainFetching.res.mjs +403 -32
  14. package/src/ChainState.res +124 -7
  15. package/src/ChainState.res.mjs +128 -67
  16. package/src/ChainState.resi +26 -0
  17. package/src/Clock.res +57 -0
  18. package/src/Clock.res.mjs +72 -0
  19. package/src/Config.res +31 -3
  20. package/src/Config.res.mjs +15 -4
  21. package/src/ContractRegisterContext.res +3 -6
  22. package/src/ContractRegisterContext.res.mjs +4 -2
  23. package/src/Core.res +95 -36
  24. package/src/Core.res.mjs +90 -1
  25. package/src/CrossChainState.res +12 -2
  26. package/src/CrossChainState.res.mjs +3 -3
  27. package/src/Ecosystem.res +7 -4
  28. package/src/Ecosystem.res.mjs +8 -8
  29. package/src/EffectCacheLookup.res +98 -0
  30. package/src/EffectCacheLookup.res.mjs +116 -0
  31. package/src/EffectState.res +10 -2
  32. package/src/EffectState.res.mjs +8 -4
  33. package/src/EffectState.resi +3 -1
  34. package/src/EntityId.res +2 -7
  35. package/src/EntityId.res.mjs +1 -8
  36. package/src/EntityTables.res +4 -1
  37. package/src/EntityTables.res.mjs +1 -1
  38. package/src/Env.res +20 -0
  39. package/src/Env.res.mjs +16 -0
  40. package/src/EventProcessing.res +38 -1
  41. package/src/EventProcessing.res.mjs +28 -1
  42. package/src/FetchState.res +408 -73
  43. package/src/FetchState.res.mjs +361 -91
  44. package/src/FinalizeBackfill.res +2 -4
  45. package/src/FinalizeBackfill.res.mjs +3 -4
  46. package/src/HandlerLoader.res +39 -15
  47. package/src/HandlerLoader.res.mjs +27 -8
  48. package/src/HandlerRegister.res +4 -0
  49. package/src/HandlerRegister.res.mjs +5 -2
  50. package/src/HandlerRegister.resi +2 -0
  51. package/src/InMemoryTable.res +17 -16
  52. package/src/InMemoryTable.res.mjs +14 -15
  53. package/src/IndexerState.res +28 -4
  54. package/src/IndexerState.res.mjs +19 -6
  55. package/src/IndexerState.resi +4 -0
  56. package/src/Internal.res +61 -49
  57. package/src/Internal.res.mjs +36 -80
  58. package/src/LoadLayer.res +54 -15
  59. package/src/LoadLayer.res.mjs +75 -45
  60. package/src/LoadLayer.resi +26 -0
  61. package/src/Main.res +14 -1
  62. package/src/Main.res.mjs +4 -3
  63. package/src/Persistence.res +3 -23
  64. package/src/Persistence.res.mjs +3 -3
  65. package/src/PreloadLookahead.res +202 -0
  66. package/src/PreloadLookahead.res.mjs +218 -0
  67. package/src/Rollback.res +0 -1
  68. package/src/Rollback.res.mjs +1 -1
  69. package/src/RunScope.res +3 -0
  70. package/src/SafeCheckpointTracking.res +4 -4
  71. package/src/SafeCheckpointTracking.res.mjs +1 -1
  72. package/src/SimulateItems.res +42 -26
  73. package/src/SimulateItems.res.mjs +40 -16
  74. package/src/StagedRows.res +106 -0
  75. package/src/StagedRows.res.mjs +102 -0
  76. package/src/Staging.res +32 -14
  77. package/src/Staging.res.mjs +17 -20
  78. package/src/Storage.res +303 -948
  79. package/src/Storage.res.mjs +229 -708
  80. package/src/SubgraphLog.res +19 -0
  81. package/src/SubgraphLog.res.mjs +26 -0
  82. package/src/Supervisor.res +75 -56
  83. package/src/Supervisor.res.mjs +55 -26
  84. package/src/SyncWrites.res +107 -0
  85. package/src/SyncWrites.res.mjs +98 -0
  86. package/src/TestIndexer.res +22 -27
  87. package/src/TestIndexer.res.mjs +20 -17
  88. package/src/Throttler.res +15 -8
  89. package/src/Throttler.res.mjs +9 -6
  90. package/src/Throttler.resi +1 -1
  91. package/src/UserContext.res +419 -46
  92. package/src/UserContext.res.mjs +318 -30
  93. package/src/Utils.res +17 -6
  94. package/src/Utils.res.mjs +12 -6
  95. package/src/Writing.res +0 -1
  96. package/src/Writing.res.mjs +1 -1
  97. package/src/bindings/ClickHouse.res +0 -322
  98. package/src/bindings/ClickHouse.res.mjs +0 -338
  99. package/src/bindings/StorageClient.res +108 -174
  100. package/src/bindings/StorageClient.res.mjs +19 -8
  101. package/src/bindings/Vitest.res +0 -26
  102. package/src/bindings/Vitest.res.mjs +0 -3
  103. package/src/db/Table.res +24 -150
  104. package/src/db/Table.res.mjs +38 -272
  105. package/src/sources/AddressSet.res +2 -0
  106. package/src/sources/AddressStore.res +3 -0
  107. package/src/sources/CallSource.res +274 -0
  108. package/src/sources/CallSource.res.mjs +196 -0
  109. package/src/sources/ChainSources.res +2 -0
  110. package/src/sources/ChainSources.res.mjs +2 -2
  111. package/src/sources/EvmChain.res +10 -1
  112. package/src/sources/EvmChain.res.mjs +6 -3
  113. package/src/sources/EvmHyperSyncSource.res +2 -2
  114. package/src/sources/EvmHyperSyncSource.res.mjs +1 -1
  115. package/src/sources/EvmRpcClient.res +13 -3
  116. package/src/sources/EvmRpcClient.res.mjs +4 -3
  117. package/src/sources/EvmRpcWs.res +4 -3
  118. package/src/sources/EvmRpcWs.res.mjs +2 -2
  119. package/src/sources/HeightFeed.res +31 -10
  120. package/src/sources/HeightFeed.res.mjs +10 -6
  121. package/src/sources/HeightStream.res +32 -17
  122. package/src/sources/HeightStream.res.mjs +10 -10
  123. package/src/sources/HyperSync.res +2 -1
  124. package/src/sources/HyperSync.res.mjs +2 -1
  125. package/src/sources/HyperSyncSSE.res +4 -6
  126. package/src/sources/HyperSyncSSE.res.mjs +2 -2
  127. package/src/sources/RpcSource.res +10 -1
  128. package/src/sources/RpcSource.res.mjs +4 -3
  129. package/src/sources/Source.res +3 -0
  130. package/src/sources/SourceManager.res +84 -77
  131. package/src/sources/SourceManager.res.mjs +17 -20
  132. package/src/sources/SourceManager.resi +3 -4
  133. package/src/sources/StartBlockResolver.res +1 -0
  134. package/src/sources/StartBlockResolver.res.mjs +3 -2
  135. package/src/sources/SvmHyperSyncSource.res +2 -2
  136. package/src/sources/SvmHyperSyncSource.res.mjs +1 -1
  137. package/src/subgraph/abi-types.ts +84 -0
  138. package/src/subgraph/aggregations.ts +745 -0
  139. package/src/subgraph/as-package.ts +143 -0
  140. package/src/subgraph/assemblyscript-regex.ts +67 -0
  141. package/src/subgraph/assemblyscript.ts +731 -0
  142. package/src/subgraph/blocks.ts +398 -0
  143. package/src/subgraph/calls-source.ts +702 -0
  144. package/src/subgraph/calls.ts +258 -0
  145. package/src/subgraph/conformance.ts +106 -0
  146. package/src/subgraph/errors.ts +85 -0
  147. package/src/subgraph/graft.ts +73 -0
  148. package/src/subgraph/graph-cli-worker.mjs +35 -0
  149. package/src/subgraph/graph-cli.ts +900 -0
  150. package/src/subgraph/graph-node-decimal.ts +199 -0
  151. package/src/subgraph/graph-ts-enums.ts +28 -0
  152. package/src/subgraph/graph-ts-types/VERSION +2 -0
  153. package/src/subgraph/graph-ts-types/chain/arweave.d.ts +70 -0
  154. package/src/subgraph/graph-ts-types/chain/cosmos.d.ts +327 -0
  155. package/src/subgraph/graph-ts-types/chain/ethereum.d.ts +233 -0
  156. package/src/subgraph/graph-ts-types/chain/near.d.ts +253 -0
  157. package/src/subgraph/graph-ts-types/chain/starknet.d.ts +32 -0
  158. package/src/subgraph/graph-ts-types/common/collections.d.ts +136 -0
  159. package/src/subgraph/graph-ts-types/common/conversion.d.ts +11 -0
  160. package/src/subgraph/graph-ts-types/common/datasource.d.ts +30 -0
  161. package/src/subgraph/graph-ts-types/common/eager-offset.d.ts +0 -0
  162. package/src/subgraph/graph-ts-types/common/json.d.ts +17 -0
  163. package/src/subgraph/graph-ts-types/common/numbers.d.ts +120 -0
  164. package/src/subgraph/graph-ts-types/common/value.d.ts +120 -0
  165. package/src/subgraph/graph-ts-types/common/yaml.d.ts +90 -0
  166. package/src/subgraph/graph-ts-types/global/global.d.ts +194 -0
  167. package/src/subgraph/graph-ts-types/helper-functions.d.ts +22 -0
  168. package/src/subgraph/graph-ts-types/index.d.ts +102 -0
  169. package/src/subgraph/graph-ts.ts +4339 -0
  170. package/src/subgraph/hosts.ts +554 -0
  171. package/src/subgraph/log.ts +28 -0
  172. package/src/subgraph/receipts.ts +184 -0
  173. package/src/subgraph/register-slots.ts +93 -0
  174. package/src/subgraph/rollup.ts +109 -0
  175. package/src/subgraph/rpc.ts +337 -0
  176. package/src/subgraph/runtime.ts +2059 -0
  177. package/src/subgraph/scope.ts +176 -0
  178. package/src/subgraph/stats.ts +42 -0
  179. package/src/subgraph/template-instances.ts +66 -0
  180. package/src/subgraph/toolchain.ts +327 -0
  181. package/src/subgraph/transient.ts +176 -0
  182. package/svm.schema.json +11 -2
  183. package/src/PgWriting.res +0 -36
  184. package/src/PgWriting.res.mjs +0 -34
  185. package/src/db/IndexDefinition.res +0 -47
  186. package/src/db/IndexDefinition.res.mjs +0 -67
@@ -53,11 +53,13 @@ let renderRows = (rows: array<AddressRows.row>, ~config: Config.t) =>
53
53
 
54
54
  // Rows of a per-chain entity are keyed per (chain, id): the same id exists
55
55
  // independently on every chain.
56
- let rowKey = (~scope: Internal.chainScope, ~entityId: EntityId.t) =>
56
+ let rowKey = (~table: Table.table, ~scope: Internal.chainScope, ~entityId: EntityId.t) => {
57
+ let entityKey = table.entityIdToKey(entityId)
57
58
  switch scope {
58
- | CrossChain => entityId->EntityId.toKey
59
- | Chain(chainId) => `${chainId->ChainId.toString}|${entityId->EntityId.toKey}`
59
+ | CrossChain => entityKey
60
+ | Chain(chainId) => `${chainId->ChainId.toString}|${entityKey}`
60
61
  }
62
+ }
61
63
 
62
64
  let readChainId = (entity: Internal.entity, ~field: Table.field): option<ChainId.t> =>
63
65
  entity
@@ -158,19 +160,18 @@ let handleWriteBatch = (
158
160
  switch change {
159
161
  | Set({entityId, entity, checkpointId}) =>
160
162
  // The store keeps decoded entities so load comparisons (bigint /
161
- // BigDecimal) work on real values. Ids are keyed by their string form
162
- // since they may be string/int/bigint.
163
+ // BigDecimal) work on real values.
163
164
  let storedEntity = switch (chainIdField, scope->Internal.chainScopeChainId) {
164
165
  | (Some(field), Some(chainId)) =>
165
166
  entity->Internal.stampChainId(~fieldName=field.fieldName, ~chainId)
166
167
  | _ => entity
167
168
  }
168
- entityDict->Dict.set(rowKey(~scope, ~entityId), storedEntity)
169
+ entityDict->Dict.set(rowKey(~table=entityConfig.table, ~scope, ~entityId), storedEntity)
169
170
  // The change already carries the checkpoint's chainId, so the entity
170
171
  // inside it stays unstamped.
171
172
  entityChangeFor(checkpointId).sets->Array.push(entity->Utils.magic)->ignore
172
173
  | Delete({entityId, checkpointId}) =>
173
- Dict.delete(entityDict->Obj.magic, rowKey(~scope, ~entityId))
174
+ Dict.delete(entityDict->Obj.magic, rowKey(~table=entityConfig.table, ~scope, ~entityId))
174
175
  entityChangeFor(checkpointId).deleted->Array.push(entityId)->ignore
175
176
  }
176
177
  }
@@ -433,10 +434,15 @@ let getEntityFromState = (
433
434
  )
434
435
  }
435
436
  let entityDict = state.entities->Dict.get(entityConfig.name)->Option.getOr(Dict.make())
437
+ let {entityIdToKey} = entityConfig.table
438
+ let key = entityIdToKey(entityId->EntityId.unsafeOfString)
436
439
  switch entityConfig.table->Table.getChainIdField {
437
- | None => entityDict->Dict.get(entityId)->Option.map(copyEntity)
440
+ | None => entityDict->Dict.get(key)->Option.map(copyEntity)
438
441
  | Some(field) =>
439
- let matches = entityDict->Dict.valuesToArray->Array.filter(entity => entity.id === entityId)
442
+ let matches =
443
+ entityDict
444
+ ->Dict.valuesToArray
445
+ ->Array.filter(entity => entityIdToKey(entity.id->EntityId.unsafeOfString) === key)
440
446
  switch matches {
441
447
  | [] => None
442
448
  | [entity] => Some(copyEntity(entity))
@@ -508,7 +514,7 @@ let makeEntitySet = (~state: testIndexerState, ~entityConfig: Internal.entityCon
508
514
  }
509
515
  }
510
516
  entityDict->Dict.set(
511
- rowKey(~scope, ~entityId=entity.id->EntityId.unsafeOfString),
517
+ rowKey(~table=entityConfig.table, ~scope, ~entityId=entity.id->EntityId.unsafeOfString),
512
518
  copyEntity(entity),
513
519
  )
514
520
  }
@@ -568,13 +574,7 @@ let makeInMemoryStorage = (~state: testIndexerState): Persistence.storage => {
568
574
  // The runner injects the config-derived initial state by setting
569
575
  // `persistence.storageStatus = Ready(...)` directly, bypassing `Persistence.init`,
570
576
  // so none of these is reached.
571
- initialize: async (
572
- ~chainConfigs as _=?,
573
- ~entities as _=?,
574
- ~enums as _=?,
575
- ~contractMapping as _,
576
- ~envioInfo as _,
577
- ) =>
577
+ initialize: async (~chainConfigs as _=?, ~contractMapping as _, ~envioInfo as _) =>
578
578
  JsError.throwWithMessage(
579
579
  "TestIndexer: initialize should not be called; the initial state is derived from config.",
580
580
  ),
@@ -582,11 +582,11 @@ let makeInMemoryStorage = (~state: testIndexerState): Persistence.storage => {
582
582
  JsError.throwWithMessage(
583
583
  "TestIndexer: readStoredConfig should not be called; the initial state is derived from config.",
584
584
  ),
585
- addChain: async (~chainConfig as _, ~entities as _, ~contractMapping as _) =>
585
+ addChain: async (~chainConfig as _, ~contractMapping as _) =>
586
586
  JsError.throwWithMessage(
587
587
  "TestIndexer: addChain should not be called; the initial state is derived from config.",
588
588
  ),
589
- resumeInitialState: async (~entities as _, ~chainIds as _, ~contractMapping as _) =>
589
+ resumeInitialState: async (~chainIds as _, ~contractMapping as _) =>
590
590
  JsError.throwWithMessage(
591
591
  "TestIndexer: resumeInitialState should not be called; the initial state is derived from config.",
592
592
  ),
@@ -596,13 +596,12 @@ let makeInMemoryStorage = (~state: testIndexerState): Persistence.storage => {
596
596
  ->(Utils.magic: array<Internal.entity> => array<unknown>),
597
597
  // The in-memory storage has no indexes to build, and it's always ready.
598
598
  ensureQueryIndexes: async (~entityConfig as _, ~scope as _, ~filters as _) => (),
599
- ensureSchemaIndexes: async (~entities as _, ~chainIds as _) => (),
600
- finalizeBackfill: async (~entities as _, ~chainIds as _, ~readyAt as _) => (),
599
+ ensureSchemaIndexes: async (~chainIds as _) => (),
600
+ finalizeBackfill: async (~chainIds as _, ~readyAt as _) => (),
601
601
  writeBatch: async (
602
602
  ~batch,
603
603
  ~rollback as _,
604
604
  ~config,
605
- ~allEntities as _,
606
605
  ~updatedEffectsCache as _,
607
606
  ~updatedEntities,
608
607
  ~registeredAddresses,
@@ -623,11 +622,7 @@ let makeInMemoryStorage = (~state: testIndexerState): Persistence.storage => {
623
622
  setChainMeta: async _ => Obj.magic(),
624
623
  pruneStaleCheckpoints: async (~safeCheckpoints as _) => (),
625
624
  pruneStaleEntityHistory: async (~entityConfig as _, ~safeCheckpoints as _) => (),
626
- getRollbackTargetCheckpoint: async (
627
- ~reorgChainId as _,
628
- ~lastKnownValidBlockNumber as _,
629
- ~sequence as _,
630
- ) =>
625
+ getRollbackTargetCheckpoint: async (~reorgChainId as _, ~lastKnownValidBlockNumber as _) =>
631
626
  JsError.throwWithMessage(
632
627
  "TestIndexer: Rollback is not supported. The runner forces rollbackOnReorg off, so this should be unreachable.",
633
628
  ),
@@ -7,7 +7,6 @@ import * as Config from "./Config.res.mjs";
7
7
  import * as Logger from "./Logger.res.mjs";
8
8
  import * as ChainId from "./ChainId.res.mjs";
9
9
  import * as ChainMap from "./ChainMap.res.mjs";
10
- import * as EntityId from "./EntityId.res.mjs";
11
10
  import * as Frontier from "./db/Frontier.res.mjs";
12
11
  import * as Internal from "./Internal.res.mjs";
13
12
  import * as ChainState from "./ChainState.res.mjs";
@@ -39,11 +38,12 @@ function renderRows(rows, config) {
39
38
  return AddressRows.render(rows, config.ecosystem.name, !config.lowercaseAddresses);
40
39
  }
41
40
 
42
- function rowKey(scope, entityId) {
41
+ function rowKey(table, scope, entityId) {
42
+ let entityKey = table.entityIdToKey(entityId);
43
43
  if (scope === "crossChain") {
44
- return EntityId.toKey(entityId);
44
+ return entityKey;
45
45
  } else {
46
- return ChainId.toString(scope) + `|` + EntityId.toKey(entityId);
46
+ return ChainId.toString(scope) + `|` + entityKey;
47
47
  }
48
48
  }
49
49
 
@@ -126,12 +126,12 @@ function handleWriteBatch(state, config, updatedEntities, registeredAddresses, c
126
126
  let entity = change.entity;
127
127
  let match = Internal.chainScopeChainId(scope);
128
128
  let storedEntity = chainIdField !== undefined && match !== undefined ? Internal.stampChainId(entity, chainIdField.fieldName, Primitive_option.valFromOption(match)) : entity;
129
- entityDict[rowKey(scope, change.entityId)] = storedEntity;
129
+ entityDict[rowKey(entityConfig.table, scope, change.entityId)] = storedEntity;
130
130
  entityChangeFor(change.checkpointId).sets.push(entity);
131
131
  return;
132
132
  }
133
133
  let entityId = change.entityId;
134
- Stdlib_Dict.$$delete(entityDict, rowKey(scope, entityId));
134
+ Stdlib_Dict.$$delete(entityDict, rowKey(entityConfig.table, scope, entityId));
135
135
  entityChangeFor(change.checkpointId).deleted.push(entityId);
136
136
  };
137
137
  param.changes.forEach(processChange);
@@ -304,11 +304,14 @@ function getEntityFromState(state, entityConfig, entityId, methodName) {
304
304
  Stdlib_JsError.throwWithMessage(`Cannot call ` + entityConfig.name + `.` + methodName + `() while indexer.process() is running. ` + "Wait for process() to complete before accessing entities directly.");
305
305
  }
306
306
  let entityDict = Stdlib_Option.getOr(state.entities[entityConfig.name], {});
307
+ let match = entityConfig.table;
308
+ let entityIdToKey = match.entityIdToKey;
309
+ let key = entityIdToKey(entityId);
307
310
  let field = Table.getChainIdField(entityConfig.table);
308
311
  if (field === undefined) {
309
- return Stdlib_Option.map(entityDict[entityId], copyEntity);
312
+ return Stdlib_Option.map(entityDict[key], copyEntity);
310
313
  }
311
- let matches = Object.values(entityDict).filter(entity => entity.id === entityId);
314
+ let matches = Object.values(entityDict).filter(entity => entityIdToKey(entity.id) === key);
312
315
  let len = matches.length;
313
316
  if (len !== 1) {
314
317
  if (len === 0) {
@@ -358,7 +361,7 @@ function makeEntitySet(state, entityConfig) {
358
361
  } else {
359
362
  scope = "crossChain";
360
363
  }
361
- entityDict[rowKey(scope, entity.id)] = Utils.Dict.shallowCopy(entity);
364
+ entityDict[rowKey(entityConfig.table, scope, entity.id)] = Utils.Dict.shallowCopy(entity);
362
365
  };
363
366
  }
364
367
 
@@ -388,23 +391,23 @@ function makeInMemoryStorage(state) {
388
391
  name: "test-inmemory",
389
392
  entityStoreName: param => "test-inmemory",
390
393
  holding: async () => "Initialized",
391
- initialize: async (param, param$1, param$2, param$3, param$4) => Stdlib_JsError.throwWithMessage("TestIndexer: initialize should not be called; the initial state is derived from config."),
394
+ initialize: async (param, param$1, param$2) => Stdlib_JsError.throwWithMessage("TestIndexer: initialize should not be called; the initial state is derived from config."),
392
395
  readStoredConfig: async () => Stdlib_JsError.throwWithMessage("TestIndexer: readStoredConfig should not be called; the initial state is derived from config."),
393
- addChain: async (param, param$1, param$2) => Stdlib_JsError.throwWithMessage("TestIndexer: addChain should not be called; the initial state is derived from config."),
394
- resumeInitialState: async (param, param$1, param$2) => Stdlib_JsError.throwWithMessage("TestIndexer: resumeInitialState should not be called; the initial state is derived from config."),
396
+ addChain: async (param, param$1) => Stdlib_JsError.throwWithMessage("TestIndexer: addChain should not be called; the initial state is derived from config."),
397
+ resumeInitialState: async (param, param$1) => Stdlib_JsError.throwWithMessage("TestIndexer: resumeInitialState should not be called; the initial state is derived from config."),
395
398
  loadOrThrow: async (filter, table) => handleLoad(state, table.tableName, filter),
396
399
  ensureQueryIndexes: async (param, param$1, param$2) => {},
397
- ensureSchemaIndexes: async (param, param$1) => {},
398
- finalizeBackfill: async (param, param$1, param$2) => {},
400
+ ensureSchemaIndexes: async param => {},
401
+ finalizeBackfill: async (param, param$1) => {},
399
402
  dumpEffectCache: async () => {},
400
403
  reset: async () => {},
401
404
  setChainMeta: async param => {},
402
405
  pruneStaleCheckpoints: async param => {},
403
406
  pruneStaleEntityHistory: async (param, param$1) => {},
404
- getRollbackTargetCheckpoint: async (param, param$1, param$2) => Stdlib_JsError.throwWithMessage("TestIndexer: Rollback is not supported. The runner forces rollbackOnReorg off, so this should be unreachable."),
407
+ getRollbackTargetCheckpoint: async (param, param$1) => Stdlib_JsError.throwWithMessage("TestIndexer: Rollback is not supported. The runner forces rollbackOnReorg off, so this should be unreachable."),
405
408
  getRollbackProgressDiff: async param => Stdlib_JsError.throwWithMessage("TestIndexer: Rollback is not supported. The runner forces rollbackOnReorg off, so this should be unreachable."),
406
409
  getRollbackData: async (param, param$1) => Stdlib_JsError.throwWithMessage("TestIndexer: Rollback is not supported. The runner forces rollbackOnReorg off, so this should be unreachable."),
407
- writeBatch: async (batch, param, config, param$1, param$2, updatedEntities, registeredAddresses, param$3, param$4) => handleWriteBatch(state, config, updatedEntities, registeredAddresses, batch.checkpointIds, batch.checkpointChainIds, batch.checkpointBlockNumbers, batch.checkpointEventsProcessed),
410
+ writeBatch: async (batch, param, config, param$1, updatedEntities, registeredAddresses, param$2, param$3) => handleWriteBatch(state, config, updatedEntities, registeredAddresses, batch.checkpointIds, batch.checkpointChainIds, batch.checkpointBlockNumbers, batch.checkpointEventsProcessed),
408
411
  close: async () => {}
409
412
  };
410
413
  }
@@ -648,7 +651,7 @@ function createTestIndexer() {
648
651
  let indexerState = IndexerState.makeFromDbState(runConfig, logger$1, persistence, initialState, registrationsByChainId, undefined, undefined, exitAfterFirstEventBlock, undefined, undefined, undefined, errHandler => {
649
652
  ErrorHandling.log(errHandler);
650
653
  reject(ErrorHandling.toExn(errHandler));
651
- }, () => resolve());
654
+ }, () => resolve(), undefined);
652
655
  indexerStateRef.contents = Primitive_option.some(indexerState);
653
656
  IndexerLoop.start(indexerState);
654
657
  });
package/src/Throttler.res CHANGED
@@ -5,27 +5,30 @@ type t = {
5
5
  mutable scheduled: option<unit => promise<unit>>,
6
6
  intervalMillis: float,
7
7
  logger: Logger.t,
8
+ clock: Clock.t,
8
9
  }
9
10
 
10
- let make = (~intervalMillis: int, ~logger) => {
11
- lastRunTimeMillis: 0.,
11
+ let make = (~intervalMillis: int, ~logger, ~clock=Clock.real) => {
12
+ // A clock reads from its own origin, which the first run must not wait on.
13
+ lastRunTimeMillis: -.(intervalMillis->Int.toFloat),
12
14
  isRunning: false,
13
15
  isAwaitingInterval: false,
14
16
  scheduled: None,
15
17
  intervalMillis: intervalMillis->Int.toFloat,
16
18
  logger,
19
+ clock,
17
20
  }
18
21
 
19
22
  let rec startInternal = (throttler: t) => {
20
23
  switch throttler {
21
24
  | {scheduled: Some(fn), isRunning: false, isAwaitingInterval: false} =>
22
- let timeSinceLastRun = Date.now() -. throttler.lastRunTimeMillis
25
+ let timeSinceLastRun = throttler.clock.now() -. throttler.lastRunTimeMillis
23
26
 
24
27
  //Only execute if we are passed the interval
25
28
  if timeSinceLastRun >= throttler.intervalMillis {
26
29
  throttler.isRunning = true
27
30
  throttler.scheduled = None
28
- throttler.lastRunTimeMillis = Date.now()
31
+ throttler.lastRunTimeMillis = throttler.clock.now()
29
32
 
30
33
  // Defer off the schedule call so work queued before it (e.g. a batch) runs first.
31
34
  NodeJs.setImmediate(() => {
@@ -45,10 +48,14 @@ let rec startInternal = (throttler: t) => {
45
48
  } else {
46
49
  //Store isAwaitingInterval in state so that timers don't continuously get created
47
50
  throttler.isAwaitingInterval = true
48
- let _ = setTimeout(() => {
49
- throttler.isAwaitingInterval = false
50
- throttler->startInternal
51
- }, Int.fromFloat(throttler.intervalMillis -. timeSinceLastRun))
51
+ let _ = throttler.clock.setTimeout(
52
+ ~label="throttled write",
53
+ () => {
54
+ throttler.isAwaitingInterval = false
55
+ throttler->startInternal
56
+ },
57
+ Int.fromFloat(throttler.intervalMillis -. timeSinceLastRun),
58
+ )
52
59
  }
53
60
  | _ => ()
54
61
  }
@@ -1,16 +1,19 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
+ import * as Clock from "./Clock.res.mjs";
3
4
  import * as Logger from "./Logger.res.mjs";
4
5
  import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
5
6
 
6
- function make(intervalMillis, logger) {
7
+ function make(intervalMillis, logger, clockOpt) {
8
+ let clock = clockOpt !== undefined ? clockOpt : Clock.real;
7
9
  return {
8
- lastRunTimeMillis: 0,
10
+ lastRunTimeMillis: - intervalMillis,
9
11
  isRunning: false,
10
12
  isAwaitingInterval: false,
11
13
  scheduled: undefined,
12
14
  intervalMillis: intervalMillis,
13
- logger: logger
15
+ logger: logger,
16
+ clock: clock
14
17
  };
15
18
  }
16
19
 
@@ -27,11 +30,11 @@ function startInternal(throttler) {
27
30
  if (fn === undefined) {
28
31
  return;
29
32
  }
30
- let timeSinceLastRun = Date.now() - throttler.lastRunTimeMillis;
33
+ let timeSinceLastRun = throttler.clock.now() - throttler.lastRunTimeMillis;
31
34
  if (timeSinceLastRun >= throttler.intervalMillis) {
32
35
  throttler.isRunning = true;
33
36
  throttler.scheduled = undefined;
34
- throttler.lastRunTimeMillis = Date.now();
37
+ throttler.lastRunTimeMillis = throttler.clock.now();
35
38
  setImmediate(() => {
36
39
  (async () => {
37
40
  try {
@@ -46,7 +49,7 @@ function startInternal(throttler) {
46
49
  });
47
50
  } else {
48
51
  throttler.isAwaitingInterval = true;
49
- setTimeout(() => {
52
+ throttler.clock.setTimeout("throttled write", () => {
50
53
  throttler.isAwaitingInterval = false;
51
54
  startInternal(throttler);
52
55
  }, throttler.intervalMillis - timeSinceLastRun | 0);
@@ -15,7 +15,7 @@ Does NOT queue scheduled functions but rather overwrites them
15
15
  The logger will be used to log any errors that occur in the scheduled
16
16
  functions.
17
17
  */
18
- let make: (~intervalMillis: int, ~logger: Logger.t) => t
18
+ let make: (~intervalMillis: int, ~logger: Logger.t, ~clock: Clock.t=?) => t
19
19
 
20
20
  /**
21
21
  Schedules a function to be run on a throttler, overwriting any