envio 3.15.0-subgraph → 3.16.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 (186) hide show
  1. package/README.md +40 -34
  2. package/evm.schema.json +3 -3
  3. package/fuel.schema.json +2 -2
  4. package/index.d.ts +3 -3
  5. package/licenses/README.md +1 -1
  6. package/package.json +9 -10
  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 +0 -7
  11. package/src/Bin.res.mjs +0 -8
  12. package/src/ChainFetching.res +17 -456
  13. package/src/ChainFetching.res.mjs +33 -404
  14. package/src/ChainState.res +48 -83
  15. package/src/ChainState.res.mjs +83 -115
  16. package/src/ChainState.resi +0 -26
  17. package/src/Clock.res +57 -0
  18. package/src/Clock.res.mjs +72 -0
  19. package/src/Config.res +7 -16
  20. package/src/Config.res.mjs +4 -11
  21. package/src/ContractRegisterContext.res +6 -3
  22. package/src/ContractRegisterContext.res.mjs +2 -4
  23. package/src/Core.res +5 -136
  24. package/src/Core.res.mjs +1 -90
  25. package/src/CrossChainState.res +2 -8
  26. package/src/CrossChainState.res.mjs +3 -3
  27. package/src/Ecosystem.res +4 -7
  28. package/src/Ecosystem.res.mjs +8 -8
  29. package/src/EffectState.res +10 -2
  30. package/src/EffectState.res.mjs +8 -4
  31. package/src/EffectState.resi +3 -1
  32. package/src/EntityId.res +2 -7
  33. package/src/EntityId.res.mjs +1 -8
  34. package/src/EntityTables.res +4 -1
  35. package/src/EntityTables.res.mjs +1 -1
  36. package/src/Env.res +0 -16
  37. package/src/Env.res.mjs +0 -11
  38. package/src/EventProcessing.res +1 -38
  39. package/src/EventProcessing.res.mjs +1 -28
  40. package/src/FetchState.res +160 -319
  41. package/src/FetchState.res.mjs +182 -292
  42. package/src/FinalizeBackfill.res +2 -4
  43. package/src/FinalizeBackfill.res.mjs +3 -4
  44. package/src/HandlerLoader.res +15 -39
  45. package/src/HandlerLoader.res.mjs +8 -27
  46. package/src/HandlerRegister.res +0 -4
  47. package/src/HandlerRegister.res.mjs +2 -5
  48. package/src/HandlerRegister.resi +0 -2
  49. package/src/InMemoryTable.res +17 -16
  50. package/src/InMemoryTable.res.mjs +14 -15
  51. package/src/IndexerState.res +28 -4
  52. package/src/IndexerState.res.mjs +19 -6
  53. package/src/IndexerState.resi +4 -0
  54. package/src/Internal.res +0 -110
  55. package/src/Internal.res.mjs +1 -115
  56. package/src/LoadLayer.res +21 -47
  57. package/src/LoadLayer.res.mjs +47 -72
  58. package/src/LoadLayer.resi +0 -26
  59. package/src/Main.res +1 -14
  60. package/src/Main.res.mjs +3 -4
  61. package/src/Persistence.res +3 -23
  62. package/src/Persistence.res.mjs +3 -3
  63. package/src/Rollback.res +0 -1
  64. package/src/Rollback.res.mjs +1 -1
  65. package/src/RunScope.res +0 -3
  66. package/src/SafeCheckpointTracking.res +4 -4
  67. package/src/SafeCheckpointTracking.res.mjs +1 -1
  68. package/src/SimulateItems.res +26 -42
  69. package/src/SimulateItems.res.mjs +16 -40
  70. package/src/StagedRows.res +106 -0
  71. package/src/StagedRows.res.mjs +102 -0
  72. package/src/Staging.res +32 -14
  73. package/src/Staging.res.mjs +17 -20
  74. package/src/Storage.res +277 -998
  75. package/src/Storage.res.mjs +216 -731
  76. package/src/Supervisor.res +75 -56
  77. package/src/Supervisor.res.mjs +55 -26
  78. package/src/TestIndexer.res +22 -27
  79. package/src/TestIndexer.res.mjs +20 -17
  80. package/src/Throttler.res +15 -8
  81. package/src/Throttler.res.mjs +9 -6
  82. package/src/Throttler.resi +1 -1
  83. package/src/UserContext.res +46 -410
  84. package/src/UserContext.res.mjs +30 -318
  85. package/src/Utils.res +0 -23
  86. package/src/Utils.res.mjs +1 -17
  87. package/src/Writing.res +0 -1
  88. package/src/Writing.res.mjs +1 -1
  89. package/src/bindings/ClickHouse.res +0 -322
  90. package/src/bindings/ClickHouse.res.mjs +0 -338
  91. package/src/bindings/StorageClient.res +107 -175
  92. package/src/bindings/StorageClient.res.mjs +19 -8
  93. package/src/bindings/Vitest.res +0 -26
  94. package/src/bindings/Vitest.res.mjs +0 -3
  95. package/src/db/Table.res +24 -150
  96. package/src/db/Table.res.mjs +38 -272
  97. package/src/sources/AddressSet.res +0 -2
  98. package/src/sources/AddressStore.res +0 -3
  99. package/src/sources/ChainSources.res +2 -0
  100. package/src/sources/ChainSources.res.mjs +2 -2
  101. package/src/sources/EvmChain.res +4 -7
  102. package/src/sources/EvmChain.res.mjs +5 -4
  103. package/src/sources/EvmHyperSyncSource.res +2 -2
  104. package/src/sources/EvmHyperSyncSource.res.mjs +1 -1
  105. package/src/sources/EvmRpcClient.res +13 -3
  106. package/src/sources/EvmRpcClient.res.mjs +4 -3
  107. package/src/sources/EvmRpcWs.res +4 -3
  108. package/src/sources/EvmRpcWs.res.mjs +2 -2
  109. package/src/sources/HeightFeed.res +31 -10
  110. package/src/sources/HeightFeed.res.mjs +10 -6
  111. package/src/sources/HeightStream.res +32 -17
  112. package/src/sources/HeightStream.res.mjs +10 -10
  113. package/src/sources/HyperSync.res +1 -2
  114. package/src/sources/HyperSync.res.mjs +1 -2
  115. package/src/sources/HyperSyncSSE.res +4 -6
  116. package/src/sources/HyperSyncSSE.res.mjs +2 -2
  117. package/src/sources/RpcSource.res +10 -1
  118. package/src/sources/RpcSource.res.mjs +4 -3
  119. package/src/sources/Source.res +3 -0
  120. package/src/sources/SourceManager.res +85 -104
  121. package/src/sources/SourceManager.res.mjs +18 -37
  122. package/src/sources/SourceManager.resi +3 -5
  123. package/src/sources/StartBlockResolver.res +1 -0
  124. package/src/sources/StartBlockResolver.res.mjs +4 -3
  125. package/src/sources/SvmHyperSyncSource.res +2 -2
  126. package/src/sources/SvmHyperSyncSource.res.mjs +1 -1
  127. package/svm.schema.json +3 -3
  128. package/src/EffectCacheLookup.res +0 -98
  129. package/src/EffectCacheLookup.res.mjs +0 -116
  130. package/src/PgWriting.res +0 -36
  131. package/src/PgWriting.res.mjs +0 -34
  132. package/src/PreloadLookahead.res +0 -184
  133. package/src/PreloadLookahead.res.mjs +0 -197
  134. package/src/SubgraphLog.res +0 -19
  135. package/src/SubgraphLog.res.mjs +0 -26
  136. package/src/SyncWrites.res +0 -101
  137. package/src/SyncWrites.res.mjs +0 -98
  138. package/src/db/IndexDefinition.res +0 -47
  139. package/src/db/IndexDefinition.res.mjs +0 -60
  140. package/src/sources/CallSource.res +0 -274
  141. package/src/sources/CallSource.res.mjs +0 -196
  142. package/src/subgraph/abi-types.ts +0 -84
  143. package/src/subgraph/aggregations.ts +0 -745
  144. package/src/subgraph/as-package.ts +0 -143
  145. package/src/subgraph/assemblyscript-regex.ts +0 -67
  146. package/src/subgraph/assemblyscript.ts +0 -731
  147. package/src/subgraph/blocks.ts +0 -398
  148. package/src/subgraph/calls-source.ts +0 -702
  149. package/src/subgraph/calls.ts +0 -258
  150. package/src/subgraph/conformance.ts +0 -106
  151. package/src/subgraph/errors.ts +0 -85
  152. package/src/subgraph/graft.ts +0 -73
  153. package/src/subgraph/graph-cli-worker.mjs +0 -35
  154. package/src/subgraph/graph-cli.ts +0 -900
  155. package/src/subgraph/graph-node-decimal.ts +0 -199
  156. package/src/subgraph/graph-ts-enums.ts +0 -28
  157. package/src/subgraph/graph-ts-types/VERSION +0 -2
  158. package/src/subgraph/graph-ts-types/chain/arweave.d.ts +0 -70
  159. package/src/subgraph/graph-ts-types/chain/cosmos.d.ts +0 -327
  160. package/src/subgraph/graph-ts-types/chain/ethereum.d.ts +0 -233
  161. package/src/subgraph/graph-ts-types/chain/near.d.ts +0 -253
  162. package/src/subgraph/graph-ts-types/chain/starknet.d.ts +0 -32
  163. package/src/subgraph/graph-ts-types/common/collections.d.ts +0 -136
  164. package/src/subgraph/graph-ts-types/common/conversion.d.ts +0 -11
  165. package/src/subgraph/graph-ts-types/common/datasource.d.ts +0 -30
  166. package/src/subgraph/graph-ts-types/common/eager-offset.d.ts +0 -0
  167. package/src/subgraph/graph-ts-types/common/json.d.ts +0 -17
  168. package/src/subgraph/graph-ts-types/common/numbers.d.ts +0 -120
  169. package/src/subgraph/graph-ts-types/common/value.d.ts +0 -120
  170. package/src/subgraph/graph-ts-types/common/yaml.d.ts +0 -90
  171. package/src/subgraph/graph-ts-types/global/global.d.ts +0 -194
  172. package/src/subgraph/graph-ts-types/helper-functions.d.ts +0 -22
  173. package/src/subgraph/graph-ts-types/index.d.ts +0 -102
  174. package/src/subgraph/graph-ts.ts +0 -4280
  175. package/src/subgraph/hosts.ts +0 -554
  176. package/src/subgraph/log.ts +0 -28
  177. package/src/subgraph/receipts.ts +0 -184
  178. package/src/subgraph/register-slots.ts +0 -93
  179. package/src/subgraph/rollup.ts +0 -109
  180. package/src/subgraph/rpc.ts +0 -337
  181. package/src/subgraph/runtime.ts +0 -2060
  182. package/src/subgraph/scope.ts +0 -177
  183. package/src/subgraph/stats.ts +0 -42
  184. package/src/subgraph/template-instances.ts +0 -66
  185. package/src/subgraph/toolchain.ts +0 -327
  186. package/src/subgraph/transient.ts +0 -176
package/src/Internal.res CHANGED
@@ -724,12 +724,6 @@ type onBlockArgs = {
724
724
  context: handlerContext,
725
725
  }
726
726
 
727
- type onBlockContractRegisterArgs = {
728
- slot?: int,
729
- block?: eventBlock,
730
- context: contractRegisterContext,
731
- }
732
-
733
727
  type onBlockRegistration = {
734
728
  // When there are multiple onBlock handlers per chain,
735
729
  // we want to use the order they are defined for sorting
@@ -744,14 +738,6 @@ type onBlockRegistration = {
744
738
  // `None` when the handler reads only the block's key, which needs nothing
745
739
  // from a source: its items are generated locally, block by block.
746
740
  blockFieldMask: option<float>,
747
- // Subgraph mode only: a `once` block handler, whose trigger graph-node runs
748
- // ahead of everything else in its block (`EthereumBlockTriggerType::Start`).
749
- runsFirst?: bool,
750
- // Subgraph mode only: the register pass of a block handler that can create a
751
- // data source. It runs for each of the handler's blocks at fetch time, and no
752
- // block item is processed until every pass up to its block has run and what
753
- // they registered is fetched, as an event's contractRegister.
754
- contractRegister?: onBlockContractRegisterArgs => promise<unit>,
755
741
  }
756
742
 
757
743
  @tag("kind")
@@ -799,53 +785,6 @@ external getItemOrderPath: item => Nullable.t<array<int>> = "orderPath"
799
785
  // block ahead of that block's handlers without a `switch`.
800
786
  @get
801
787
  external getItemKind: item => int = "kind"
802
- // Set only in subgraph mode, on an event of an address registered in the very
803
- // block it was logged in: graph-node runs a new data source's creation-block
804
- // events after everything else in that block. The value is the round, as
805
- // graph-node counts them: 1 for a data source a block's own triggers created,
806
- // 2 for one that round-1 handlers created, and so on.
807
- @get
808
- external getItemCreationRound: item => option<int> = "runsAfterBlock"
809
- @set
810
- external markItemCreationRound: (item, int) => unit = "runsAfterBlock"
811
-
812
- let itemRunsFirst = (item: item) =>
813
- switch item {
814
- | Block({onBlockRegistration: {runsFirst: true}}) => true
815
- | _ => false
816
- }
817
-
818
- // Subgraph mode only. A call trigger travels through fetch and batching as an
819
- // event item (see `subgraph/calls-source.ts`), and graph-node orders it by its
820
- // transaction among the logs, so its item carries a rank: 1 for a call
821
- // handler's, 2 for the `filter: call` block handler's. Absent on every log.
822
- @get
823
- external getItemCallRank: item => option<int> = "callRank"
824
- @set
825
- external setItemCallRank: (item, int) => unit = "callRank"
826
- @get
827
- external getItemTransactionIndex: item => int = "transactionIndex"
828
-
829
- // Flips on when the first call item is built, so a run without call triggers
830
- // compares items exactly as before.
831
- let callOrderingActive = ref(false)
832
-
833
- // The call trigger an event of this name is, if it is one: the subgraph
834
- // translator names them `__envio_call_<selector>_<function>`, and the block
835
- // handler's `__envio_call_any`. No log carries either name.
836
- let callRankOfEventName = (name: string): option<int> =>
837
- if name->String.startsWith("__envio_call_any") {
838
- Some(2)
839
- } else if name->String.startsWith("__envio_call_") {
840
- Some(1)
841
- } else {
842
- None
843
- }
844
-
845
- let markItemCall = (item, ~rank) => {
846
- item->setItemCallRank(rank)
847
- callOrderingActive := true
848
- }
849
788
 
850
789
  let getItemChainId = item =>
851
790
  switch item {
@@ -1011,55 +950,6 @@ module EffectCache = {
1011
950
  | CrossChain => cacheTablePrefix ++ effectName
1012
951
  | Chain(chainId) => `envio_${chainId->ChainId.toString}_effect_${effectName}`
1013
952
  }
1014
-
1015
- // Only accepts a canonical decimal chain id ("7", not "007" or "1foo") —
1016
- // the schema's parser follows parseFloat semantics and accepts both.
1017
- let parseChainId = str =>
1018
- switch try Some(str->ChainId.normalizeOrThrow) catch {
1019
- | _ => None
1020
- } {
1021
- | Some(chainId) if chainId->ChainId.toString === str => Some(chainId)
1022
- | _ => None
1023
- }
1024
-
1025
- let chainScopedRe = /^envio_([0-9]+)_effect_(.+)$/
1026
- let crossChainRe = /^envio_effect_(.+)$/
1027
-
1028
- // Inverse of toTableName. Returns None for any table name that isn't a cache
1029
- // table. Chain-scoped is tried first: the `_effect_` separator keeps effect
1030
- // names that themselves start with digits unambiguous.
1031
- let fromTableName = (tableName): option<(string, chainScope)> =>
1032
- switch RegExp.exec(chainScopedRe, tableName) {
1033
- | Some(result) =>
1034
- switch (
1035
- RegExp.Result.matches(result)->Array.get(0),
1036
- RegExp.Result.matches(result)->Array.get(1),
1037
- ) {
1038
- | (Some(Some(chainIdStr)), Some(Some(effectName))) =>
1039
- switch parseChainId(chainIdStr) {
1040
- | Some(chainId) => Some((effectName, Chain(chainId)))
1041
- | None => None
1042
- }
1043
- | _ => None
1044
- }
1045
- | None =>
1046
- switch RegExp.exec(crossChainRe, tableName) {
1047
- | Some(result) =>
1048
- switch RegExp.Result.matches(result)->Array.get(0) {
1049
- | Some(Some(effectName)) => Some((effectName, CrossChain))
1050
- | _ => None
1051
- }
1052
- | None => None
1053
- }
1054
- }
1055
-
1056
- // Relative posix path within .envio/cache. Chain-scoped caches live one
1057
- // directory level deep, named by chain id.
1058
- let toCachePath = (~effectName, ~scope) =>
1059
- switch scope {
1060
- | CrossChain => effectName ++ ".tsv"
1061
- | Chain(chainId) => `${chainId->ChainId.toString}/${effectName}.tsv`
1062
- }
1063
953
  }
1064
954
 
1065
955
  let cacheOutputSchema = S.json(~validate=false)->(Utils.magic: S.t<JSON.t> => S.t<effectOutput>)
@@ -188,37 +188,6 @@ function eventItemFieldsJson(eventItem, address) {
188
188
  return `{` + contractAndEventJson(eventItem.onEventRegistration.eventConfig) + `,"block":` + eventItem.blockNumber.toString() + `,"logIndex":` + eventItem.logIndex.toString() + `,"address":` + JSON.stringify(address) + `}`;
189
189
  }
190
190
 
191
- function itemRunsFirst(item) {
192
- if (item.kind === 0) {
193
- return false;
194
- }
195
- let match = item.onBlockRegistration.runsFirst;
196
- if (match !== undefined) {
197
- return match;
198
- } else {
199
- return false;
200
- }
201
- }
202
-
203
- let callOrderingActive = {
204
- contents: false
205
- };
206
-
207
- function callRankOfEventName(name) {
208
- if (name.startsWith("__envio_call_any")) {
209
- return 2;
210
- } else if (name.startsWith("__envio_call_")) {
211
- return 1;
212
- } else {
213
- return;
214
- }
215
- }
216
-
217
- function markItemCall(item, rank) {
218
- item.callRank = rank;
219
- callOrderingActive.contents = true;
220
- }
221
-
222
191
  function getItemChainId(item) {
223
192
  if (item.kind === 0) {
224
193
  return item.chainId;
@@ -271,87 +240,8 @@ function toTableName(effectName, scope) {
271
240
  }
272
241
  }
273
242
 
274
- function parseChainId(str) {
275
- let chainId;
276
- try {
277
- chainId = Primitive_option.some(ChainId.normalizeOrThrow(str));
278
- } catch (exn) {
279
- chainId = undefined;
280
- }
281
- if (chainId === undefined) {
282
- return;
283
- }
284
- let chainId$1 = Primitive_option.valFromOption(chainId);
285
- if (ChainId.toString(chainId$1) === str) {
286
- return Primitive_option.some(chainId$1);
287
- }
288
- }
289
-
290
- let chainScopedRe = /^envio_([0-9]+)_effect_(.+)$/;
291
-
292
- let crossChainRe = /^envio_effect_(.+)$/;
293
-
294
- function fromTableName(tableName) {
295
- let result = chainScopedRe.exec(tableName);
296
- if (result == null) {
297
- let result$1 = crossChainRe.exec(tableName);
298
- if (result$1 == null) {
299
- return;
300
- }
301
- let match = result$1.slice(1)[0];
302
- if (match === undefined) {
303
- return;
304
- }
305
- let effectName = Primitive_option.valFromOption(match);
306
- if (effectName !== undefined) {
307
- return [
308
- effectName,
309
- "crossChain"
310
- ];
311
- } else {
312
- return;
313
- }
314
- }
315
- let match$1 = result.slice(1)[0];
316
- let match$2 = result.slice(1)[1];
317
- if (match$1 === undefined) {
318
- return;
319
- }
320
- let chainIdStr = Primitive_option.valFromOption(match$1);
321
- if (chainIdStr === undefined) {
322
- return;
323
- }
324
- if (match$2 === undefined) {
325
- return;
326
- }
327
- let effectName$1 = Primitive_option.valFromOption(match$2);
328
- if (effectName$1 === undefined) {
329
- return;
330
- }
331
- let chainId = parseChainId(chainIdStr);
332
- if (chainId !== undefined) {
333
- return [
334
- effectName$1,
335
- Primitive_option.valFromOption(chainId)
336
- ];
337
- }
338
- }
339
-
340
- function toCachePath(effectName, scope) {
341
- if (scope === "crossChain") {
342
- return effectName + ".tsv";
343
- } else {
344
- return ChainId.toString(scope) + `/` + effectName + `.tsv`;
345
- }
346
- }
347
-
348
243
  let EffectCache = {
349
- toTableName: toTableName,
350
- parseChainId: parseChainId,
351
- chainScopedRe: chainScopedRe,
352
- crossChainRe: crossChainRe,
353
- fromTableName: fromTableName,
354
- toCachePath: toCachePath
244
+ toTableName: toTableName
355
245
  };
356
246
 
357
247
  let cacheOutputSchema = S$RescriptSchema.json(false);
@@ -387,10 +277,6 @@ export {
387
277
  dependsOnAddresses,
388
278
  svmAccountSlotName,
389
279
  eventItemFieldsJson,
390
- itemRunsFirst,
391
- callOrderingActive,
392
- callRankOfEventName,
393
- markItemCall,
394
280
  getItemChainId,
395
281
  fuelSupplyParamsSchema,
396
282
  fuelTransferParamsSchema,
package/src/LoadLayer.res CHANGED
@@ -16,7 +16,12 @@ let loadById = (
16
16
  ~entityId,
17
17
  ) => {
18
18
  let inMemTable = indexerState->InMemoryStore.getInMemTable(~entityConfig, ~scope)
19
- switch inMemTable.latestEntityChangeById->Utils.Dict.dangerouslyGetNonOption(entityId) {
19
+ // The ids here are typed as strings but hold whatever scalar the id is.
20
+ let entityIdToKey =
21
+ inMemTable.entityIdToKey->(Utils.magic: (EntityId.t => string) => string => string)
22
+ switch inMemTable.latestEntityChangeById->Utils.Dict.dangerouslyGetNonOption(
23
+ entityIdToKey(entityId),
24
+ ) {
20
25
  // A row already in memory is final, so even a grouped call skips the load
21
26
  // manager: grouping it would only resolve it a tick later to the same value.
22
27
  | Some(change) => Promise.resolve(change->InMemoryTable.Entity.mapChangeToEntity)
@@ -53,14 +58,14 @@ let loadById = (
53
58
  //Set the entity in the in memory store
54
59
  for idx in 0 to dbEntities->Array.length - 1 {
55
60
  let entity = dbEntities->Array.getUnsafe(idx)
56
- entitiesMap->Dict.set(entity.id, entity)
61
+ entitiesMap->Dict.set(entityIdToKey(entity.id), entity)
57
62
  }
58
63
  let committedCheckpointId = indexerState->IndexerState.committedCheckpointIdFor(~scope)
59
64
  idsToLoad->Array.forEach(entityId => {
60
65
  inMemTable->InMemoryTable.Entity.initValue(
61
66
  ~committedCheckpointId,
62
- ~key=entityId,
63
- ~entity=entitiesMap->Utils.Dict.dangerouslyGetNonOption(entityId),
67
+ ~entityId=entityId->EntityId.unsafeOfString,
68
+ ~entity=entitiesMap->Utils.Dict.dangerouslyGetNonOption(entityIdToKey(entityId)),
64
69
  )
65
70
  })
66
71
 
@@ -77,7 +82,7 @@ let loadById = (
77
82
  ~key,
78
83
  ~load,
79
84
  ~shouldGroup,
80
- ~hasher=LoadManager.noopHasher,
85
+ ~hasher=entityIdToKey,
81
86
  ~getUnsafeInMemory=inMemTable->InMemoryTable.Entity.getUnsafe,
82
87
  ~hasInMemory=hash => inMemTable.latestEntityChangeById->Dict.has(hash),
83
88
  ~input=entityId,
@@ -140,7 +145,7 @@ let rec executeWithRateLimit = (
140
145
  }
141
146
 
142
147
  | Some(state) =>
143
- let now = Date.now()
148
+ let now = state.clock.now()
144
149
 
145
150
  // Check if we need to reset the window
146
151
  if now >= state.windowStartTime +. state.durationMs->Int.toFloat {
@@ -188,7 +193,8 @@ let rec executeWithRateLimit = (
188
193
  | None =>
189
194
  millisUntilReset :=
190
195
  (state.windowStartTime +. state.durationMs->Int.toFloat -. now)->Float.toInt
191
- let p = Utils.delay(millisUntilReset.contents)
196
+ let p =
197
+ state.clock->Clock.delay(~label="effect rate limit window", millisUntilReset.contents)
192
198
  state.nextWindowPromise = Some(p)
193
199
  p
194
200
  }
@@ -335,44 +341,6 @@ let loadEffect = (
335
341
  )
336
342
  }
337
343
 
338
- // Keying an _in walks every value, so it's computed once and handed on rather
339
- // than recomputed by each reader. Before answering "not in memory", the rows
340
- // already loaded for other filters are checked: they may cover this one.
341
- let indexFilter = (inMemTable, ~filter, ~table) => {
342
- let filterKey = filter->EntityFilter.toString(~table)
343
- if !(inMemTable->InMemoryTable.Entity.hasIndex)(filterKey) {
344
- inMemTable->InMemoryTable.Entity.tryIndexFromLoadedValues(~filter, ~table)
345
- }
346
- filterKey
347
- }
348
-
349
- // A recorded absence is an answer too: `Some(None)` means the entity is known
350
- // not to exist, so no load is needed to say so.
351
- let getByIdInMemory = (
352
- ~entityConfig: Internal.entityConfig,
353
- ~scope,
354
- ~indexerState,
355
- ~entityId: string,
356
- ) => {
357
- let inMemTable = indexerState->InMemoryStore.getInMemTable(~entityConfig, ~scope)
358
- inMemTable.latestEntityChangeById->Dict.has(entityId)
359
- ? Some((inMemTable->InMemoryTable.Entity.getUnsafe)(entityId))
360
- : None
361
- }
362
-
363
- let getByFilterInMemory = (
364
- ~entityConfig: Internal.entityConfig,
365
- ~scope,
366
- ~indexerState,
367
- ~filter: EntityFilter.t,
368
- ) => {
369
- let inMemTable = indexerState->InMemoryStore.getInMemTable(~entityConfig, ~scope)
370
- let filterKey = inMemTable->indexFilter(~filter, ~table=entityConfig.table)
371
- (inMemTable->InMemoryTable.Entity.hasIndex)(filterKey)
372
- ? Some((inMemTable->InMemoryTable.Entity.getUnsafeOnIndex)(filterKey))
373
- : None
374
- }
375
-
376
344
  let loadByParsedFilter = (
377
345
  ~loadManager,
378
346
  ~persistence: Persistence.t,
@@ -425,7 +393,7 @@ let loadByParsedFilter = (
425
393
  entities->Array.forEach(entity => {
426
394
  inMemTable->InMemoryTable.Entity.initValue(
427
395
  ~committedCheckpointId,
428
- ~key=entity.id,
396
+ ~entityId=entity.id->EntityId.unsafeOfString,
429
397
  ~entity=Some(entity),
430
398
  )
431
399
  })
@@ -463,7 +431,13 @@ let loadByParsedFilter = (
463
431
  )
464
432
  }
465
433
 
466
- let filterKey = inMemTable->indexFilter(~filter, ~table=entityConfig.table)
434
+ // Keying an _in walks every value, so it's computed once here and handed to
435
+ // the load manager rather than recomputed by the hasher.
436
+ let filterKey = filter->EntityFilter.toString(~table=entityConfig.table)
437
+
438
+ if !(inMemTable->InMemoryTable.Entity.hasIndex)(filterKey) {
439
+ inMemTable->InMemoryTable.Entity.tryIndexFromLoadedValues(~filter, ~table=entityConfig.table)
440
+ }
467
441
 
468
442
  loadManager->LoadManager.call(
469
443
  ~key,
@@ -1,5 +1,6 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
+ import * as Clock from "./Clock.res.mjs";
3
4
  import * as Utils from "./Utils.res.mjs";
4
5
  import * as Logger from "./Logger.res.mjs";
5
6
  import * as ChainId from "./ChainId.res.mjs";
@@ -14,7 +15,6 @@ import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
14
15
  import * as ErrorHandling from "./ErrorHandling.res.mjs";
15
16
  import * as InMemoryStore from "./InMemoryStore.res.mjs";
16
17
  import * as InMemoryTable from "./InMemoryTable.res.mjs";
17
- import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
18
18
  import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
19
19
  import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
20
20
 
@@ -28,7 +28,8 @@ function scopeKeySuffix(scope) {
28
28
 
29
29
  function loadById(loadManager, persistence, entityConfig, scope, indexerState, shouldGroup, entityId) {
30
30
  let inMemTable = InMemoryStore.getInMemTable(indexerState, entityConfig, scope);
31
- let change = inMemTable.latestEntityChangeById[entityId];
31
+ let entityIdToKey = inMemTable.entityIdToKey;
32
+ let change = inMemTable.latestEntityChangeById[entityIdToKey(entityId)];
32
33
  if (change !== undefined) {
33
34
  return Promise.resolve(InMemoryTable.Entity.mapChangeToEntity(change));
34
35
  }
@@ -51,13 +52,13 @@ function loadById(loadManager, persistence, entityConfig, scope, indexerState, s
51
52
  let entitiesMap = {};
52
53
  for (let idx = 0, idx_finish = dbEntities.length; idx < idx_finish; ++idx) {
53
54
  let entity = dbEntities[idx];
54
- entitiesMap[entity.id] = entity;
55
+ entitiesMap[entityIdToKey(entity.id)] = entity;
55
56
  }
56
57
  let committedCheckpointId = IndexerState.committedCheckpointIdFor(indexerState, scope);
57
- idsToLoad.forEach(entityId => InMemoryTable.Entity.initValue(inMemTable, committedCheckpointId, entityId, entitiesMap[entityId]));
58
+ idsToLoad.forEach(entityId => InMemoryTable.Entity.initValue(inMemTable, committedCheckpointId, entityId, entitiesMap[entityIdToKey(entityId)]));
58
59
  return IndexerState.endStorageLoad(indexerState, timerRef, storageName, key, idsToLoad.length, dbEntities.length);
59
60
  };
60
- return LoadManager.call(loadManager, entityId, key, load, LoadManager.noopHasher, shouldGroup, hash => hash in inMemTable.latestEntityChangeById, InMemoryTable.Entity.getUnsafe(inMemTable));
61
+ return LoadManager.call(loadManager, entityId, key, load, entityIdToKey, shouldGroup, hash => hash in inMemTable.latestEntityChangeById, InMemoryTable.Entity.getUnsafe(inMemTable));
61
62
  }
62
63
 
63
64
  function callEffect(effect, arg, inMemTable, timerRef, onError) {
@@ -70,7 +71,7 @@ function executeWithRateLimit(effect, effectArgs, inMemTable, onError, isFromQue
70
71
  let promises = [];
71
72
  let state = inMemTable.rateLimitState;
72
73
  if (state !== undefined) {
73
- let now = Date.now();
74
+ let now = state.clock.now();
74
75
  if (now >= state.windowStartTime + state.durationMs) {
75
76
  state.availableCalls = state.callsPerDuration;
76
77
  state.windowStartTime = now;
@@ -99,7 +100,7 @@ function executeWithRateLimit(effect, effectArgs, inMemTable, onError, isFromQue
99
100
  nextWindowPromise = p;
100
101
  } else {
101
102
  millisUntilReset.contents = state.windowStartTime + state.durationMs - now | 0;
102
- let p$1 = Utils.delay(millisUntilReset.contents);
103
+ let p$1 = Clock.delay(state.clock, "effect rate limit window", millisUntilReset.contents);
103
104
  state.nextWindowPromise = p$1;
104
105
  nextWindowPromise = p$1;
105
106
  }
@@ -185,70 +186,47 @@ function loadEffect(loadManager, persistence, effect, effectArgs, scope, indexer
185
186
  return LoadManager.call(loadManager, effectArgs, key, load, args => args.cacheKey, shouldGroup, hash => InMemoryStore.hasEffectOutput(inMemTable, hash), hash => InMemoryStore.getEffectOutputUnsafe(inMemTable, hash));
186
187
  }
187
188
 
188
- function indexFilter(inMemTable, filter, table) {
189
- let filterKey = EntityFilter.toString(filter, table);
190
- if (!InMemoryTable.Entity.hasIndex(inMemTable)(filterKey)) {
191
- InMemoryTable.Entity.tryIndexFromLoadedValues(inMemTable, filter, table);
192
- }
193
- return filterKey;
194
- }
195
-
196
- function getByIdInMemory(entityConfig, scope, indexerState, entityId) {
197
- let inMemTable = InMemoryStore.getInMemTable(indexerState, entityConfig, scope);
198
- if (entityId in inMemTable.latestEntityChangeById) {
199
- return Primitive_option.some(InMemoryTable.Entity.getUnsafe(inMemTable)(entityId));
200
- }
201
- }
202
-
203
- function getByFilterInMemory(entityConfig, scope, indexerState, filter) {
204
- let inMemTable = InMemoryStore.getInMemTable(indexerState, entityConfig, scope);
205
- let filterKey = indexFilter(inMemTable, filter, entityConfig.table);
206
- if (InMemoryTable.Entity.hasIndex(inMemTable)(filterKey)) {
207
- return InMemoryTable.Entity.getUnsafeOnIndex(inMemTable)(filterKey);
208
- }
209
- }
210
-
211
- function loadByParsedFilter(loadManager, persistence, entityConfig, scope, indexerState, shouldGroup, filter) {
212
- let key = EntityFilter.toOperationKey(filter, entityConfig.name) + scopeKeySuffix(scope);
213
- let inMemTable = InMemoryStore.getInMemTable(indexerState, entityConfig, scope);
214
- let load = async (filters, param) => {
215
- let storage = Persistence.getInitializedStorageOrThrow(persistence);
216
- let storageName = storage.entityStoreName(entityConfig);
217
- let timerRef = IndexerState.startStorageLoad(indexerState, storageName, key);
218
- let size = {
219
- contents: 0
220
- };
221
- filters.forEach(filter => InMemoryTable.Entity.addEmptyIndex(inMemTable, filter, entityConfig.table));
222
- await storage.ensureQueryIndexes(entityConfig, scope, filters);
223
- let queries = EntityFilter.merge(filters);
224
- await Promise.all(queries.map(async filter => {
225
- try {
226
- let entities = await storage.loadOrThrow(EntityFilter.scoped(filter, entityConfig.table, scope), entityConfig.table);
227
- let committedCheckpointId = IndexerState.committedCheckpointIdFor(indexerState, scope);
228
- entities.forEach(entity => InMemoryTable.Entity.initValue(inMemTable, committedCheckpointId, entity.id, entity));
229
- InMemoryTable.Entity.recordLoadedValues(inMemTable, filter, entityConfig.table);
230
- size.contents = size.contents + entities.length | 0;
231
- return;
232
- } catch (raw_exn) {
233
- let exn = Primitive_exceptions.internalToException(raw_exn);
234
- if (exn.RE_EXN_ID === Persistence.StorageError) {
235
- return ErrorHandling.mkLogAndRaise(Logger.withFields(IndexerState.loggerForScope(indexerState, scope), {
236
- operation: key,
237
- params: EntityFilter.getParams(filter)
238
- }), exn.message, exn.reason);
239
- }
240
- throw exn;
241
- }
242
- }));
243
- return IndexerState.endStorageLoad(indexerState, timerRef, storageName, key, Stdlib_Array.reduce(queries, 0, (acc, query) => acc + EntityFilter.valuesCount(query) | 0), size.contents);
244
- };
245
- let filterKey = indexFilter(inMemTable, filter, entityConfig.table);
246
- return LoadManager.call(loadManager, filter, key, load, param => filterKey, shouldGroup, InMemoryTable.Entity.hasIndex(inMemTable), InMemoryTable.Entity.getUnsafeOnIndex(inMemTable));
247
- }
248
-
249
189
  function loadByFilter(loadManager, persistence, entityConfig, scope, indexerState, shouldGroup, filter) {
250
190
  try {
251
- return loadByParsedFilter(loadManager, persistence, entityConfig, scope, indexerState, shouldGroup, EntityFilter.parseOrThrow(filter, entityConfig.name, entityConfig.table));
191
+ let filter$1 = EntityFilter.parseOrThrow(filter, entityConfig.name, entityConfig.table);
192
+ let key = EntityFilter.toOperationKey(filter$1, entityConfig.name) + scopeKeySuffix(scope);
193
+ let inMemTable = InMemoryStore.getInMemTable(indexerState, entityConfig, scope);
194
+ let load = async (filters, param) => {
195
+ let storage = Persistence.getInitializedStorageOrThrow(persistence);
196
+ let storageName = storage.entityStoreName(entityConfig);
197
+ let timerRef = IndexerState.startStorageLoad(indexerState, storageName, key);
198
+ let size = {
199
+ contents: 0
200
+ };
201
+ filters.forEach(filter => InMemoryTable.Entity.addEmptyIndex(inMemTable, filter, entityConfig.table));
202
+ await storage.ensureQueryIndexes(entityConfig, scope, filters);
203
+ let queries = EntityFilter.merge(filters);
204
+ await Promise.all(queries.map(async filter => {
205
+ try {
206
+ let entities = await storage.loadOrThrow(EntityFilter.scoped(filter, entityConfig.table, scope), entityConfig.table);
207
+ let committedCheckpointId = IndexerState.committedCheckpointIdFor(indexerState, scope);
208
+ entities.forEach(entity => InMemoryTable.Entity.initValue(inMemTable, committedCheckpointId, entity.id, entity));
209
+ InMemoryTable.Entity.recordLoadedValues(inMemTable, filter, entityConfig.table);
210
+ size.contents = size.contents + entities.length | 0;
211
+ return;
212
+ } catch (raw_exn) {
213
+ let exn = Primitive_exceptions.internalToException(raw_exn);
214
+ if (exn.RE_EXN_ID === Persistence.StorageError) {
215
+ return ErrorHandling.mkLogAndRaise(Logger.withFields(IndexerState.loggerForScope(indexerState, scope), {
216
+ operation: key,
217
+ params: EntityFilter.getParams(filter)
218
+ }), exn.message, exn.reason);
219
+ }
220
+ throw exn;
221
+ }
222
+ }));
223
+ return IndexerState.endStorageLoad(indexerState, timerRef, storageName, key, Stdlib_Array.reduce(queries, 0, (acc, query) => acc + EntityFilter.valuesCount(query) | 0), size.contents);
224
+ };
225
+ let filterKey = EntityFilter.toString(filter$1, entityConfig.table);
226
+ if (!InMemoryTable.Entity.hasIndex(inMemTable)(filterKey)) {
227
+ InMemoryTable.Entity.tryIndexFromLoadedValues(inMemTable, filter$1, entityConfig.table);
228
+ }
229
+ return LoadManager.call(loadManager, filter$1, key, load, param => filterKey, shouldGroup, InMemoryTable.Entity.hasIndex(inMemTable), InMemoryTable.Entity.getUnsafeOnIndex(inMemTable));
252
230
  } catch (raw_exn) {
253
231
  let exn = Primitive_exceptions.internalToException(raw_exn);
254
232
  return Promise.reject(Utils.prettifyExn(exn));
@@ -258,9 +236,6 @@ function loadByFilter(loadManager, persistence, entityConfig, scope, indexerStat
258
236
  export {
259
237
  loadById,
260
238
  loadByFilter,
261
- loadByParsedFilter,
262
- getByIdInMemory,
263
- getByFilterInMemory,
264
239
  loadEffect,
265
240
  }
266
241
  /* Utils Not a pure module */
@@ -18,32 +18,6 @@ let loadByFilter: (
18
18
  ~filter: dict<dict<unknown>>,
19
19
  ) => promise<array<Internal.entity>>
20
20
 
21
- let loadByParsedFilter: (
22
- ~loadManager: LoadManager.t,
23
- ~persistence: Persistence.t,
24
- ~entityConfig: Internal.entityConfig,
25
- ~scope: Internal.chainScope,
26
- ~indexerState: IndexerState.t,
27
- ~shouldGroup: bool,
28
- ~filter: EntityFilter.t,
29
- ) => promise<array<Internal.entity>>
30
-
31
- // What a get or getWhere answers without a load, or None when it would need
32
- // one. The sync context reads through these and suspends on None.
33
- let getByIdInMemory: (
34
- ~entityConfig: Internal.entityConfig,
35
- ~scope: Internal.chainScope,
36
- ~indexerState: IndexerState.t,
37
- ~entityId: string,
38
- ) => option<option<Internal.entity>>
39
-
40
- let getByFilterInMemory: (
41
- ~entityConfig: Internal.entityConfig,
42
- ~scope: Internal.chainScope,
43
- ~indexerState: IndexerState.t,
44
- ~filter: EntityFilter.t,
45
- ) => option<array<Internal.entity>>
46
-
47
21
  let loadEffect: (
48
22
  ~loadManager: LoadManager.t,
49
23
  ~persistence: Persistence.t,
package/src/Main.res CHANGED
@@ -303,25 +303,12 @@ let getGlobalIndexer = (): 'indexer => {
303
303
 
304
304
  let onBlockFn = (rawOptions: 'a, handler: 'b) => {
305
305
  HandlerRegister.throwIfFinishedRegistration(~methodName="onBlock")
306
- let raw =
307
- rawOptions->(
308
- Utils.magic: 'a => {
309
- "name": string,
310
- "where": unknown,
311
- "fields": unknown,
312
- "runsFirst": option<bool>,
313
- "contractRegister": option<Internal.onBlockContractRegisterArgs => promise<unit>>,
314
- }
315
- )
306
+ let raw = rawOptions->(Utils.magic: 'a => {"name": string, "where": unknown, "fields": unknown})
316
307
  HandlerRegister.registerOnBlock(
317
308
  ~name=raw["name"],
318
309
  ~where=raw["where"],
319
310
  ~fields=raw["fields"],
320
311
  ~handler=handler->(Utils.magic: 'b => Internal.onBlockArgs => promise<unit>),
321
- // Not part of the public API: the subgraph runtime's `once` handlers, and
322
- // the register passes of block handlers that create data sources.
323
- ~runsFirst=Env.subgraphMode.contents && raw["runsFirst"] === Some(true),
324
- ~contractRegister=?Env.subgraphMode.contents ? raw["contractRegister"] : None,
325
312
  ~getChainsObject=config => {
326
313
  let (chains, _) = buildChainsObject(~config)
327
314
  chains->(Utils.magic: {..} => dict<unknown>)
package/src/Main.res.mjs CHANGED
@@ -1,6 +1,5 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
- import * as Env from "./Env.res.mjs";
4
3
  import * as Tui from "./tui/Tui.res.mjs";
5
4
  import * as Utils from "./Utils.res.mjs";
6
5
  import * as Config from "./Config.res.mjs";
@@ -256,7 +255,7 @@ function getGlobalIndexer() {
256
255
  };
257
256
  let onBlockFn = (rawOptions, handler) => {
258
257
  HandlerRegister.throwIfFinishedRegistration("onBlock");
259
- HandlerRegister.registerOnBlock(rawOptions.name, rawOptions.where, rawOptions.fields, handler, Env.subgraphMode.contents && rawOptions.runsFirst === true, Env.subgraphMode.contents ? rawOptions.contractRegister : undefined, config => buildChainsObject(config)[0]);
258
+ HandlerRegister.registerOnBlock(rawOptions.name, rawOptions.where, rawOptions.fields, handler, config => buildChainsObject(config)[0]);
260
259
  };
261
260
  let keysMemo = {
262
261
  contents: undefined
@@ -414,7 +413,7 @@ async function startIndexer(config, logger, persistence, resetOpt, isTestOpt, ex
414
413
  Metrics.startRuntimeCollectors();
415
414
  Server.startServer(logger, getMetrics, envioVersion, () => Persistence.getInitializedStorageOrThrow(persistence$1).dumpEffectCache().then(prim => {}), Metrics.collectRuntime, isDevelopmentMode);
416
415
  }
417
- let state = IndexerState.makeFromDbState(config$2, logger, persistence$1, Persistence.getInitializedState(persistence$1), registrationsByChainId, isDevelopmentMode, shouldUseTui, exitAfterFirstEventBlock, undefined, undefined, Stdlib_Option.mapOr(Worker.config, false, worker => worker.holdRealtime), onError, undefined);
416
+ let state = IndexerState.makeFromDbState(config$2, logger, persistence$1, Persistence.getInitializedState(persistence$1), registrationsByChainId, isDevelopmentMode, shouldUseTui, exitAfterFirstEventBlock, undefined, undefined, Stdlib_Option.mapOr(Worker.config, false, worker => worker.holdRealtime), onError, undefined, undefined);
418
417
  if (shouldUseTui) {
419
418
  Tui.start(config$2, logger, () => IndexerState.toMetrics(state));
420
419
  }
@@ -455,4 +454,4 @@ export {
455
454
  FatalError,
456
455
  start,
457
456
  }
458
- /* Env Not a pure module */
457
+ /* Tui Not a pure module */