envio 3.1.1 → 3.2.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 (134) hide show
  1. package/evm.schema.json +83 -11
  2. package/fuel.schema.json +83 -11
  3. package/index.d.ts +184 -3
  4. package/package.json +6 -6
  5. package/src/Batch.res +2 -2
  6. package/src/ChainFetcher.res +27 -3
  7. package/src/ChainFetcher.res.mjs +17 -3
  8. package/src/ChainManager.res +163 -0
  9. package/src/ChainManager.res.mjs +136 -0
  10. package/src/Config.res +213 -30
  11. package/src/Config.res.mjs +102 -41
  12. package/src/Core.res +16 -10
  13. package/src/Ecosystem.res +0 -3
  14. package/src/Env.res +2 -2
  15. package/src/Env.res.mjs +2 -2
  16. package/src/Envio.res +101 -2
  17. package/src/Envio.res.mjs +2 -3
  18. package/src/EventConfigBuilder.res +52 -0
  19. package/src/EventConfigBuilder.res.mjs +32 -0
  20. package/src/EventUtils.res +2 -2
  21. package/src/FetchState.res +126 -71
  22. package/src/FetchState.res.mjs +73 -51
  23. package/src/GlobalState.res +219 -363
  24. package/src/GlobalState.res.mjs +314 -491
  25. package/src/GlobalStateManager.res +49 -59
  26. package/src/GlobalStateManager.res.mjs +5 -4
  27. package/src/GlobalStateManager.resi +1 -1
  28. package/src/HandlerLoader.res +12 -1
  29. package/src/HandlerLoader.res.mjs +6 -1
  30. package/src/HandlerRegister.res +9 -9
  31. package/src/HandlerRegister.res.mjs +9 -9
  32. package/src/Hasura.res +102 -32
  33. package/src/Hasura.res.mjs +88 -34
  34. package/src/InMemoryStore.res +10 -1
  35. package/src/InMemoryStore.res.mjs +4 -1
  36. package/src/InMemoryTable.res +83 -136
  37. package/src/InMemoryTable.res.mjs +57 -86
  38. package/src/Internal.res +54 -5
  39. package/src/Internal.res.mjs +2 -8
  40. package/src/LazyLoader.res +2 -2
  41. package/src/LazyLoader.res.mjs +3 -3
  42. package/src/LoadLayer.res +47 -60
  43. package/src/LoadLayer.res.mjs +28 -50
  44. package/src/LoadLayer.resi +2 -5
  45. package/src/LogSelection.res +4 -4
  46. package/src/LogSelection.res.mjs +5 -7
  47. package/src/Logging.res +1 -1
  48. package/src/Main.res +61 -2
  49. package/src/Main.res.mjs +37 -1
  50. package/src/Persistence.res +3 -16
  51. package/src/PgStorage.res +125 -114
  52. package/src/PgStorage.res.mjs +112 -95
  53. package/src/Ports.res +5 -0
  54. package/src/Ports.res.mjs +9 -0
  55. package/src/Prometheus.res +3 -3
  56. package/src/Prometheus.res.mjs +4 -4
  57. package/src/ReorgDetection.res +4 -4
  58. package/src/ReorgDetection.res.mjs +4 -5
  59. package/src/SafeCheckpointTracking.res +16 -16
  60. package/src/SafeCheckpointTracking.res.mjs +2 -2
  61. package/src/SimulateItems.res +10 -14
  62. package/src/SimulateItems.res.mjs +5 -2
  63. package/src/Sink.res +1 -1
  64. package/src/Sink.res.mjs +1 -2
  65. package/src/SvmTypes.res +9 -0
  66. package/src/SvmTypes.res.mjs +14 -0
  67. package/src/TestIndexer.res +17 -57
  68. package/src/TestIndexer.res.mjs +14 -48
  69. package/src/TestIndexerProxyStorage.res +23 -23
  70. package/src/TestIndexerProxyStorage.res.mjs +12 -15
  71. package/src/Throttler.res +2 -2
  72. package/src/Time.res +2 -2
  73. package/src/Time.res.mjs +2 -2
  74. package/src/UserContext.res +19 -118
  75. package/src/UserContext.res.mjs +10 -66
  76. package/src/Utils.res +15 -15
  77. package/src/Utils.res.mjs +7 -8
  78. package/src/adapters/MarkBatchProcessedAdapter.res +5 -0
  79. package/src/adapters/MarkBatchProcessedAdapter.res.mjs +14 -0
  80. package/src/bindings/BigDecimal.res +1 -1
  81. package/src/bindings/BigDecimal.res.mjs +2 -2
  82. package/src/bindings/ClickHouse.res +8 -6
  83. package/src/bindings/ClickHouse.res.mjs +5 -5
  84. package/src/bindings/Hrtime.res +1 -1
  85. package/src/bindings/Pino.res +2 -2
  86. package/src/bindings/Pino.res.mjs +3 -4
  87. package/src/db/EntityFilter.res +410 -0
  88. package/src/db/EntityFilter.res.mjs +424 -0
  89. package/src/db/EntityHistory.res +1 -1
  90. package/src/db/EntityHistory.res.mjs +1 -1
  91. package/src/db/InternalTable.res +10 -10
  92. package/src/db/InternalTable.res.mjs +41 -45
  93. package/src/db/Schema.res +2 -2
  94. package/src/db/Schema.res.mjs +3 -3
  95. package/src/db/Table.res +106 -22
  96. package/src/db/Table.res.mjs +84 -35
  97. package/src/sources/EventRouter.res +67 -2
  98. package/src/sources/EventRouter.res.mjs +45 -3
  99. package/src/sources/Evm.res +0 -7
  100. package/src/sources/Evm.res.mjs +0 -15
  101. package/src/sources/EvmChain.res +1 -1
  102. package/src/sources/EvmChain.res.mjs +1 -2
  103. package/src/sources/EvmRpcClient.res +42 -0
  104. package/src/sources/EvmRpcClient.res.mjs +64 -0
  105. package/src/sources/Fuel.res +0 -7
  106. package/src/sources/Fuel.res.mjs +0 -15
  107. package/src/sources/HyperFuelSource.res +5 -4
  108. package/src/sources/HyperFuelSource.res.mjs +2 -2
  109. package/src/sources/HyperSyncClient.res +9 -5
  110. package/src/sources/HyperSyncClient.res.mjs +2 -2
  111. package/src/sources/HyperSyncHeightStream.res +2 -2
  112. package/src/sources/HyperSyncHeightStream.res.mjs +2 -2
  113. package/src/sources/HyperSyncSource.res +10 -9
  114. package/src/sources/HyperSyncSource.res.mjs +4 -4
  115. package/src/sources/Rpc.res +1 -5
  116. package/src/sources/Rpc.res.mjs +1 -9
  117. package/src/sources/RpcSource.res +57 -21
  118. package/src/sources/RpcSource.res.mjs +47 -20
  119. package/src/sources/RpcWebSocketHeightStream.res +1 -1
  120. package/src/sources/SourceManager.res +3 -2
  121. package/src/sources/SourceManager.res.mjs +1 -1
  122. package/src/sources/Svm.res +3 -10
  123. package/src/sources/Svm.res.mjs +4 -18
  124. package/src/sources/SvmHyperSyncClient.res +265 -0
  125. package/src/sources/SvmHyperSyncClient.res.mjs +28 -0
  126. package/src/sources/SvmHyperSyncSource.res +638 -0
  127. package/src/sources/SvmHyperSyncSource.res.mjs +557 -0
  128. package/src/tui/Tui.res +9 -2
  129. package/src/tui/Tui.res.mjs +18 -3
  130. package/src/tui/components/BufferedProgressBar.res +2 -2
  131. package/src/tui/components/TuiData.res +3 -0
  132. package/svm.schema.json +523 -14
  133. package/src/TableIndices.res +0 -115
  134. package/src/TableIndices.res.mjs +0 -144
@@ -1,14 +1,14 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
+ import * as Table from "./db/Table.res.mjs";
3
4
  import * as Utils from "./Utils.res.mjs";
4
5
  import * as Hrtime from "./bindings/Hrtime.res.mjs";
5
6
  import * as Logging from "./Logging.res.mjs";
6
- import * as Internal from "./Internal.res.mjs";
7
- import * as Belt_Array from "@rescript/runtime/lib/es6/Belt_Array.js";
8
7
  import * as Prometheus from "./Prometheus.res.mjs";
9
8
  import * as LoadManager from "./LoadManager.res.mjs";
10
9
  import * as Persistence from "./Persistence.res.mjs";
11
- import * as TableIndices from "./TableIndices.res.mjs";
10
+ import * as EntityFilter from "./db/EntityFilter.res.mjs";
11
+ import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
12
12
  import * as ErrorHandling from "./ErrorHandling.res.mjs";
13
13
  import * as InMemoryStore from "./InMemoryStore.res.mjs";
14
14
  import * as InMemoryTable from "./InMemoryTable.res.mjs";
@@ -23,7 +23,11 @@ function loadById(loadManager, persistence, entityConfig, inMemoryStore, shouldG
23
23
  let timerRef = Prometheus.StorageLoad.startOperation(storage.name, key);
24
24
  let dbEntities;
25
25
  try {
26
- dbEntities = await storage.loadByIdsOrThrow(idsToLoad, entityConfig.table, entityConfig.rowsSchema);
26
+ dbEntities = await storage.loadOrThrow({
27
+ operator: "in",
28
+ fieldName: Table.idFieldName,
29
+ fieldValue: idsToLoad
30
+ }, entityConfig.table);
27
31
  } catch (raw_exn) {
28
32
  let exn = Primitive_exceptions.internalToException(raw_exn);
29
33
  if (exn.RE_EXN_ID === Persistence.StorageError) {
@@ -79,8 +83,8 @@ function executeWithRateLimit(effect, effectArgs, inMemTable, onError, isFromQue
79
83
  state.nextWindowPromise = undefined;
80
84
  }
81
85
  let immediateCount = Math.min(state.availableCalls, effectArgs.length);
82
- let immediateArgs = Belt_Array.slice(effectArgs, 0, immediateCount);
83
- let queuedArgs = Belt_Array.sliceToEnd(effectArgs, immediateCount);
86
+ let immediateArgs = effectArgs.slice(0, immediateCount);
87
+ let queuedArgs = effectArgs.slice(immediateCount);
84
88
  state.availableCalls = state.availableCalls - immediateCount | 0;
85
89
  for (let idx = 0, idx_finish = immediateArgs.length; idx < idx_finish; ++idx) {
86
90
  promises.push(callEffect(effect, immediateArgs[idx], inMemTable, timerRef, onError));
@@ -139,7 +143,11 @@ function loadEffect(loadManager, persistence, effect, effectArgs, inMemoryStore,
139
143
  let outputSchema = match$1.outputSchema;
140
144
  let dbEntities;
141
145
  try {
142
- dbEntities = await storage.loadByIdsOrThrow(idsToLoad, match$1.table, Internal.effectCacheItemRowsSchema);
146
+ dbEntities = await storage.loadOrThrow({
147
+ operator: "in",
148
+ fieldName: Table.idFieldName,
149
+ fieldValue: idsToLoad
150
+ }, match$1.table);
143
151
  } catch (raw_exn) {
144
152
  let exn = Primitive_exceptions.internalToException(raw_exn);
145
153
  Logging.childWarn(Logging.getItemLogger(item), {
@@ -189,48 +197,20 @@ function loadEffect(loadManager, persistence, effect, effectArgs, inMemoryStore,
189
197
  return LoadManager.call(loadManager, effectArgs, key, load, args => args.cacheKey, shouldGroup, hash => InMemoryStore.hasEffectOutput(inMemTable, hash), hash => InMemoryStore.getEffectOutputUnsafe(inMemTable, hash));
190
198
  }
191
199
 
192
- function loadByField(loadManager, persistence, operator, entityConfig, inMemoryStore, fieldName, fieldValueSchema, shouldGroup, item, fieldValue) {
193
- let operatorCallName;
194
- switch (operator) {
195
- case "Eq" :
196
- operatorCallName = "eq";
197
- break;
198
- case "Gt" :
199
- operatorCallName = "gt";
200
- break;
201
- case "Lt" :
202
- operatorCallName = "lt";
203
- break;
204
- }
205
- let key = entityConfig.name + `.getWhere.` + fieldName + `.` + operatorCallName;
200
+ function loadByFilter(loadManager, persistence, entityConfig, inMemoryStore, shouldGroup, item, filter) {
201
+ let key = EntityFilter.toOperationKey(filter, entityConfig.name);
206
202
  let inMemTable = InMemoryStore.getInMemTable(inMemoryStore, entityConfig);
207
- let load = async (fieldValues, param) => {
203
+ let load = async (filters, param) => {
208
204
  let storage = Persistence.getInitializedStorageOrThrow(persistence);
209
205
  let timerRef = Prometheus.StorageLoad.startOperation(storage.name, key);
210
206
  let size = {
211
207
  contents: 0
212
208
  };
213
- let indiciesToLoad = fieldValues.map(fieldValue => ({
214
- fieldName: fieldName,
215
- fieldValue: fieldValue,
216
- operator: operator
217
- }));
218
- await Promise.all(indiciesToLoad.map(async index => {
219
- InMemoryTable.Entity.addEmptyIndex(inMemTable, index);
209
+ filters.forEach(filter => InMemoryTable.Entity.addEmptyIndex(inMemTable, filter));
210
+ let queries = EntityFilter.merge(filters);
211
+ await Promise.all(queries.map(async filter => {
220
212
  try {
221
- let tmp;
222
- switch (index.operator) {
223
- case "Eq" :
224
- tmp = "=";
225
- break;
226
- case "Gt" :
227
- tmp = ">";
228
- break;
229
- case "Lt" :
230
- tmp = "<";
231
- break;
232
- }
233
- let entities = await storage.loadByFieldOrThrow(TableIndices.Index.getFieldName(index), fieldValueSchema, index.fieldValue, tmp, entityConfig.table, entityConfig.rowsSchema);
213
+ let entities = await storage.loadOrThrow(filter, entityConfig.table);
234
214
  entities.forEach(entity => InMemoryTable.Entity.initValue(inMemTable, inMemoryStore.committedCheckpointId, entity.id, entity));
235
215
  size.contents = size.contents + entities.length | 0;
236
216
  return;
@@ -238,23 +218,21 @@ function loadByField(loadManager, persistence, operator, entityConfig, inMemoryS
238
218
  let exn = Primitive_exceptions.internalToException(raw_exn);
239
219
  if (exn.RE_EXN_ID === Persistence.StorageError) {
240
220
  return ErrorHandling.mkLogAndRaise(Logging.createChildFrom(Logging.getItemLogger(item), {
241
- operator: operatorCallName,
242
- tableName: entityConfig.table.tableName,
243
- fieldName: fieldName,
244
- fieldValue: fieldValue
221
+ operation: key,
222
+ params: EntityFilter.getParams(filter)
245
223
  }), exn.message, exn.reason);
246
224
  }
247
225
  throw exn;
248
226
  }
249
227
  }));
250
- return Prometheus.StorageLoad.endOperation(timerRef, storage.name, key, fieldValues.length, size.contents);
228
+ return Prometheus.StorageLoad.endOperation(timerRef, storage.name, key, Stdlib_Array.reduce(queries, 0, (acc, query) => acc + EntityFilter.valuesCount(query) | 0), size.contents);
251
229
  };
252
- return LoadManager.call(loadManager, fieldValue, key, load, fieldValue => TableIndices.FieldValue.toString(fieldValue), shouldGroup, InMemoryTable.Entity.hasIndex(inMemTable, fieldName, operator), InMemoryTable.Entity.getUnsafeOnIndex(inMemTable, fieldName, operator));
230
+ return LoadManager.call(loadManager, filter, key, load, EntityFilter.toString, shouldGroup, InMemoryTable.Entity.hasIndex(inMemTable), InMemoryTable.Entity.getUnsafeOnIndex(inMemTable));
253
231
  }
254
232
 
255
233
  export {
256
234
  loadById,
257
- loadByField,
235
+ loadByFilter,
258
236
  loadEffect,
259
237
  }
260
- /* Utils Not a pure module */
238
+ /* Table Not a pure module */
@@ -8,17 +8,14 @@ let loadById: (
8
8
  ~entityId: string,
9
9
  ) => promise<option<Internal.entity>>
10
10
 
11
- let loadByField: (
11
+ let loadByFilter: (
12
12
  ~loadManager: LoadManager.t,
13
13
  ~persistence: Persistence.t,
14
- ~operator: TableIndices.Operator.t,
15
14
  ~entityConfig: Internal.entityConfig,
16
15
  ~inMemoryStore: InMemoryStore.t,
17
- ~fieldName: string,
18
- ~fieldValueSchema: RescriptSchema.S.t<'fieldValue>,
19
16
  ~shouldGroup: bool,
20
17
  ~item: Internal.item,
21
- ~fieldValue: 'fieldValue,
18
+ ~filter: EntityFilter.t,
22
19
  ) => promise<array<Internal.entity>>
23
20
 
24
21
  let loadEffect: (
@@ -12,7 +12,7 @@ let makeTopicSelection = (~topic0, ~topic1=[], ~topic2=[], ~topic3=[]) =>
12
12
  }
13
13
 
14
14
  let hasFilters = ({topic1, topic2, topic3}: Internal.topicSelection) => {
15
- [topic1, topic2, topic3]->Array.find(topic => !Utils.Array.isEmpty(topic))->Belt.Option.isSome
15
+ [topic1, topic2, topic3]->Array.find(topic => !Utils.Array.isEmpty(topic))->Option.isSome
16
16
  }
17
17
 
18
18
  /**
@@ -24,11 +24,11 @@ let compressTopicSelections = (topicSelections: array<Internal.topicSelection>)
24
24
 
25
25
  let selectionsWithFilters = []
26
26
 
27
- topicSelections->Belt.Array.forEach(selection => {
27
+ topicSelections->Array.forEach(selection => {
28
28
  if selection->hasFilters {
29
29
  selectionsWithFilters->Array.push(selection)->ignore
30
30
  } else {
31
- selection.topic0->Belt.Array.forEach(topic0 => {
31
+ selection.topic0->Array.forEach(topic0 => {
32
32
  topic0sOfSelectionsWithoutFilters->Array.push(topic0)->ignore
33
33
  })
34
34
  }
@@ -43,7 +43,7 @@ let compressTopicSelections = (topicSelections: array<Internal.topicSelection>)
43
43
  topic2: [],
44
44
  topic3: [],
45
45
  }
46
- Belt.Array.concat([selectionWithoutFilters], selectionsWithFilters)
46
+ Array.concat([selectionWithoutFilters], selectionsWithFilters)
47
47
  }
48
48
  }
49
49
 
@@ -1,8 +1,7 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
3
  import * as Utils from "./Utils.res.mjs";
4
- import * as Belt_Array from "@rescript/runtime/lib/es6/Belt_Array.js";
5
- import * as Belt_Option from "@rescript/runtime/lib/es6/Belt_Option.js";
4
+ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
6
5
  import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
7
6
  import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
8
7
  import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
@@ -35,7 +34,7 @@ function makeTopicSelection(topic0, topic1Opt, topic2Opt, topic3Opt) {
35
34
  }
36
35
 
37
36
  function hasFilters(param) {
38
- return Belt_Option.isSome([
37
+ return Stdlib_Option.isSome([
39
38
  param.topic1,
40
39
  param.topic2,
41
40
  param.topic3
@@ -45,12 +44,11 @@ function hasFilters(param) {
45
44
  function compressTopicSelections(topicSelections) {
46
45
  let topic0sOfSelectionsWithoutFilters = [];
47
46
  let selectionsWithFilters = [];
48
- Belt_Array.forEach(topicSelections, selection => {
47
+ topicSelections.forEach(selection => {
49
48
  if (hasFilters(selection)) {
50
49
  selectionsWithFilters.push(selection);
51
- return;
52
50
  } else {
53
- return Belt_Array.forEach(selection.topic0, topic0 => {
51
+ selection.topic0.forEach(topic0 => {
54
52
  topic0sOfSelectionsWithoutFilters.push(topic0);
55
53
  });
56
54
  }
@@ -67,7 +65,7 @@ function compressTopicSelections(topicSelections) {
67
65
  topic2: selectionWithoutFilters_topic2,
68
66
  topic3: selectionWithoutFilters_topic3
69
67
  };
70
- return Belt_Array.concat([selectionWithoutFilters], selectionsWithFilters);
68
+ return [selectionWithoutFilters].concat(selectionsWithFilters);
71
69
  }
72
70
 
73
71
  function make(addresses, topicSelections) {
package/src/Logging.res CHANGED
@@ -172,7 +172,7 @@ let getItemLogger = {
172
172
  "chainId": chain->ChainMap.Chain.toChainId,
173
173
  "block": blockNumber,
174
174
  "logIndex": logIndex,
175
- "address": event.srcAddress,
175
+ "address": (event->Internal.toGenericEvent).srcAddress,
176
176
  }->createChildParams
177
177
  | Block({blockNumber, onBlockConfig}) =>
178
178
  {
package/src/Main.res CHANGED
@@ -296,6 +296,59 @@ let getGlobalIndexer = (): 'indexer => {
296
296
  )
297
297
  }
298
298
 
299
+ // SVM identity: `{program, instruction}` from TS or
300
+ // `{instruction: GADT{contract, _0}}` from ReScript. Same two-format dance
301
+ // as the EVM `parseIdentityConfig`, but reading the SVM-native field names.
302
+ let parseSvmIdentityConfig = (identityConfig: 'a) => {
303
+ let raw =
304
+ identityConfig->(
305
+ Utils.magic: 'a => {"program": unknown, "instruction": unknown, "where": option<JSON.t>}
306
+ )
307
+ let (programName, instructionName) = if typeof(raw["program"]) === #string {
308
+ (
309
+ raw["program"]->(Utils.magic: unknown => string),
310
+ raw["instruction"]->(Utils.magic: unknown => string),
311
+ )
312
+ } else {
313
+ let inst = raw["instruction"]->(Utils.magic: unknown => {"contract": string, "_0": string})
314
+ (inst["contract"], inst["_0"])
315
+ }
316
+ let where = raw["where"]
317
+ let eventOptions: option<Internal.eventOptions<_>> = switch where {
318
+ | None => None
319
+ | Some(_) =>
320
+ Some({
321
+ where: ?(where->(Utils.magic: option<JSON.t> => option<_>)),
322
+ })
323
+ }
324
+ (programName, instructionName, eventOptions)
325
+ }
326
+
327
+ // onInstruction: delegates to HandlerRegister.setHandler. The SVM analog of
328
+ // onEvent; the registration store keys on `(contractName, eventName)` which
329
+ // for SVM is `(programName, instructionName)`.
330
+ let onInstructionFn = (identityConfig: 'a, handler: 'b) => {
331
+ HandlerRegister.throwIfFinishedRegistration(~methodName="onInstruction")
332
+ let (programName, instructionName, eventOptions) = parseSvmIdentityConfig(identityConfig)
333
+ // The generic dispatch hands every handler `{event, context}`. SVM handlers
334
+ // receive the instruction under `instruction`, so remap the field here; the
335
+ // payload object itself is the `svmInstruction` built in SvmHyperSyncSource.
336
+ let userHandler =
337
+ handler->(
338
+ Utils.magic: 'b => Envio.svmOnInstructionArgs<Internal.handlerContext> => promise<unit>
339
+ )
340
+ HandlerRegister.setHandler(
341
+ ~contractName=programName,
342
+ ~eventName=instructionName,
343
+ (args: Internal.genericHandlerArgs<Internal.event, Internal.handlerContext>) =>
344
+ userHandler({
345
+ instruction: args.event->(Utils.magic: Internal.event => Envio.svmInstruction),
346
+ context: args.context,
347
+ }),
348
+ ~eventOptions,
349
+ )
350
+ }
351
+
299
352
  // contractRegister: delegates to HandlerRegister.setContractRegister
300
353
  let contractRegisterFn = (identityConfig: 'a, handler: 'b) => {
301
354
  HandlerRegister.throwIfFinishedRegistration(~methodName="contractRegister")
@@ -467,6 +520,7 @@ let getGlobalIndexer = (): 'indexer => {
467
520
  "description",
468
521
  "chainIds",
469
522
  "chains",
523
+ "onInstruction",
470
524
  "onSlot",
471
525
  "~internalAndWillBeRemovedSoon_onRollbackCommit",
472
526
  ]
@@ -490,6 +544,7 @@ let getGlobalIndexer = (): 'indexer => {
490
544
  chains->(Utils.magic: {..} => unknown)
491
545
  }
492
546
  | "onEvent" => onEventFn->Utils.magic
547
+ | "onInstruction" => onInstructionFn->Utils.magic
493
548
  | "contractRegister" => contractRegisterFn->Utils.magic
494
549
  | "onBlock" | "onSlot" => onBlockFn->Utils.magic
495
550
  | "~internalAndWillBeRemovedSoon_onRollbackCommit" => onRollbackCommitFn->Utils.magic
@@ -791,8 +846,12 @@ let start = async (
791
846
  ~onError,
792
847
  )
793
848
  let gsManager =
794
- globalState->GlobalStateManager.make(~onError=exn =>
795
- onError(exn->ErrorHandling.make(~msg="Indexer has failed with an unexpected error"))
849
+ globalState->GlobalStateManager.make(
850
+ ~reducers=GlobalState.makeReducers(
851
+ ~markBatchProcessed=MarkBatchProcessedAdapter.make(~inMemoryStore=ctx.inMemoryStore),
852
+ ),
853
+ ~onError=exn =>
854
+ onError(exn->ErrorHandling.make(~msg="Indexer has failed with an unexpected error")),
796
855
  )
797
856
  if shouldUseTui {
798
857
  let _rerender = Tui.start(~getState=() => gsManager->GlobalStateManager.getState)
package/src/Main.res.mjs CHANGED
@@ -32,6 +32,7 @@ import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js
32
32
  import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
33
33
  import * as GlobalStateManager from "./GlobalStateManager.res.mjs";
34
34
  import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
35
+ import * as MarkBatchProcessedAdapter from "./adapters/MarkBatchProcessedAdapter.res.mjs";
35
36
 
36
37
  let chainDataSchema = S$RescriptSchema.schema(s => ({
37
38
  chainId: s.m(S$RescriptSchema.float),
@@ -251,6 +252,38 @@ function getGlobalIndexer() {
251
252
  let match = parseIdentityConfig(identityConfig);
252
253
  HandlerRegister.setHandler(match[0], match[1], handler, match[2], undefined);
253
254
  };
255
+ let parseSvmIdentityConfig = identityConfig => {
256
+ let match;
257
+ if (typeof identityConfig.program === "string") {
258
+ match = [
259
+ identityConfig.program,
260
+ identityConfig.instruction
261
+ ];
262
+ } else {
263
+ let inst = identityConfig.instruction;
264
+ match = [
265
+ inst.contract,
266
+ inst._0
267
+ ];
268
+ }
269
+ let where = identityConfig.where;
270
+ let eventOptions = where !== undefined ? ({
271
+ where: where
272
+ }) : undefined;
273
+ return [
274
+ match[0],
275
+ match[1],
276
+ eventOptions
277
+ ];
278
+ };
279
+ let onInstructionFn = (identityConfig, handler) => {
280
+ HandlerRegister.throwIfFinishedRegistration("onInstruction");
281
+ let match = parseSvmIdentityConfig(identityConfig);
282
+ HandlerRegister.setHandler(match[0], match[1], args => handler({
283
+ instruction: args.event,
284
+ context: args.context
285
+ }), match[2], undefined);
286
+ };
254
287
  let contractRegisterFn = (identityConfig, handler) => {
255
288
  HandlerRegister.throwIfFinishedRegistration("contractRegister");
256
289
  let match = parseIdentityConfig(identityConfig);
@@ -346,6 +379,7 @@ function getGlobalIndexer() {
346
379
  "description",
347
380
  "chainIds",
348
381
  "chains",
382
+ "onInstruction",
349
383
  "onSlot",
350
384
  "~internalAndWillBeRemovedSoon_onRollbackCommit"
351
385
  ];
@@ -380,6 +414,8 @@ function getGlobalIndexer() {
380
414
  return Config.loadWithoutRegistrations().name;
381
415
  case "onEvent" :
382
416
  return onEventFn;
417
+ case "onInstruction" :
418
+ return onInstructionFn;
383
419
  case "onBlock" :
384
420
  case "onSlot" :
385
421
  return onBlockFn;
@@ -587,7 +623,7 @@ async function start(persistence, resetOpt, isTestOpt, exitAfterFirstEventBlockO
587
623
  }
588
624
  let chainManager = ChainManager.makeFromDbState(Persistence.getInitializedState(persistence$1), config$2, registrations, undefined);
589
625
  let globalState = GlobalState.make(ctx, chainManager, isDevelopmentMode, shouldUseTui, exitAfterFirstEventBlock, onError);
590
- let gsManager = GlobalStateManager.make(globalState, exn => onError(ErrorHandling.make(exn, undefined, "Indexer has failed with an unexpected error")));
626
+ let gsManager = GlobalStateManager.make(globalState, GlobalState.makeReducers(undefined, undefined, undefined, MarkBatchProcessedAdapter.make(ctx_inMemoryStore)), exn => onError(ErrorHandling.make(exn, undefined, "Indexer has failed with an unexpected error")));
591
627
  if (shouldUseTui) {
592
628
  Tui.start(() => GlobalStateManager.getState(gsManager));
593
629
  }
@@ -40,8 +40,6 @@ type initialState = {
40
40
  envioInfo: option<JSON.t>,
41
41
  }
42
42
 
43
- type operator = [#">" | #"=" | #"<"]
44
-
45
43
  type updatedEffectCache = {
46
44
  effect: Internal.effect,
47
45
  items: array<Internal.effectCacheItem>,
@@ -78,21 +76,10 @@ type storage = {
78
76
  ~envioInfo: JSON.t,
79
77
  ) => promise<initialState>,
80
78
  resumeInitialState: unit => promise<initialState>,
79
+ // Returns rows matching the filter.
80
+ // Field values are serialized and rows parsed with the table's field schemas.
81
81
  @raises("StorageError")
82
- loadByIdsOrThrow: 'item. (
83
- ~ids: array<string>,
84
- ~table: Table.table,
85
- ~rowsSchema: S.t<array<'item>>,
86
- ) => promise<array<'item>>,
87
- @raises("StorageError")
88
- loadByFieldOrThrow: 'item 'value. (
89
- ~fieldName: string,
90
- ~fieldSchema: S.t<'value>,
91
- ~fieldValue: 'value,
92
- ~operator: operator,
93
- ~table: Table.table,
94
- ~rowsSchema: S.t<array<'item>>,
95
- ) => promise<array<'item>>,
82
+ loadOrThrow: (~filter: EntityFilter.t, ~table: Table.table) => promise<array<unknown>>,
96
83
  // This is to download cache from the database to .envio/cache
97
84
  dumpEffectCache: unit => promise<unit>,
98
85
  reset: unit => promise<unit>,