envio 3.3.0-alpha.7 → 3.3.0-alpha.9

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 (95) hide show
  1. package/index.d.ts +23 -5
  2. package/package.json +6 -6
  3. package/src/Api.res +1 -1
  4. package/src/Api.res.mjs +1 -1
  5. package/src/ChainFetching.res +21 -10
  6. package/src/ChainFetching.res.mjs +11 -10
  7. package/src/ChainState.res +401 -171
  8. package/src/ChainState.res.mjs +270 -104
  9. package/src/ChainState.resi +19 -7
  10. package/src/Config.res +11 -27
  11. package/src/Config.res.mjs +8 -7
  12. package/src/Core.res +7 -0
  13. package/src/CrossChainState.res +82 -82
  14. package/src/CrossChainState.res.mjs +52 -59
  15. package/src/CrossChainState.resi +1 -1
  16. package/src/Ecosystem.res +3 -3
  17. package/src/Ecosystem.res.mjs +3 -3
  18. package/src/Envio.res +14 -9
  19. package/src/EnvioGlobal.res +53 -0
  20. package/src/EnvioGlobal.res.mjs +31 -0
  21. package/src/EventConfigBuilder.res +117 -69
  22. package/src/EventConfigBuilder.res.mjs +71 -34
  23. package/src/EventProcessing.res +19 -15
  24. package/src/EventProcessing.res.mjs +13 -12
  25. package/src/FetchState.res +410 -185
  26. package/src/FetchState.res.mjs +268 -253
  27. package/src/HandlerLoader.res +8 -113
  28. package/src/HandlerLoader.res.mjs +2 -88
  29. package/src/HandlerRegister.res +518 -144
  30. package/src/HandlerRegister.res.mjs +285 -133
  31. package/src/HandlerRegister.resi +24 -8
  32. package/src/IndexerState.res +6 -3
  33. package/src/IndexerState.res.mjs +3 -3
  34. package/src/IndexerState.resi +1 -1
  35. package/src/IndexingAddresses.res +10 -7
  36. package/src/IndexingAddresses.res.mjs +8 -7
  37. package/src/IndexingAddresses.resi +3 -1
  38. package/src/Internal.res +104 -39
  39. package/src/Internal.res.mjs +11 -1
  40. package/src/LogSelection.res +102 -165
  41. package/src/LogSelection.res.mjs +101 -116
  42. package/src/Main.res +49 -164
  43. package/src/Main.res.mjs +39 -104
  44. package/src/Metrics.res +43 -2
  45. package/src/Metrics.res.mjs +39 -3
  46. package/src/Prometheus.res +0 -35
  47. package/src/Prometheus.res.mjs +33 -68
  48. package/src/RawEvent.res +7 -2
  49. package/src/RawEvent.res.mjs +4 -4
  50. package/src/RollbackCommit.res +4 -1
  51. package/src/RollbackCommit.res.mjs +3 -2
  52. package/src/SimulateItems.res +20 -7
  53. package/src/SimulateItems.res.mjs +7 -11
  54. package/src/TestIndexer.res +1 -1
  55. package/src/TestIndexer.res.mjs +1 -1
  56. package/src/sources/BlockStore.res +46 -0
  57. package/src/sources/BlockStore.res.mjs +24 -0
  58. package/src/sources/EventRouter.res +19 -12
  59. package/src/sources/EventRouter.res.mjs +7 -5
  60. package/src/sources/Evm.res +58 -5
  61. package/src/sources/Evm.res.mjs +44 -5
  62. package/src/sources/EvmChain.res +14 -18
  63. package/src/sources/EvmChain.res.mjs +12 -13
  64. package/src/sources/FieldMask.res +39 -0
  65. package/src/sources/FieldMask.res.mjs +42 -0
  66. package/src/sources/Fuel.res +8 -3
  67. package/src/sources/Fuel.res.mjs +5 -4
  68. package/src/sources/HyperFuelSource.res +31 -40
  69. package/src/sources/HyperFuelSource.res.mjs +52 -44
  70. package/src/sources/HyperSync.res +31 -9
  71. package/src/sources/HyperSync.res.mjs +47 -31
  72. package/src/sources/HyperSync.resi +10 -3
  73. package/src/sources/HyperSyncClient.res +15 -4
  74. package/src/sources/HyperSyncHeightStream.res +1 -8
  75. package/src/sources/HyperSyncHeightStream.res.mjs +0 -2
  76. package/src/sources/HyperSyncSource.res +58 -90
  77. package/src/sources/HyperSyncSource.res.mjs +57 -66
  78. package/src/sources/RpcSource.res +118 -120
  79. package/src/sources/RpcSource.res.mjs +92 -74
  80. package/src/sources/RpcWebSocketHeightStream.res +0 -5
  81. package/src/sources/RpcWebSocketHeightStream.res.mjs +0 -2
  82. package/src/sources/SimulateSource.res +5 -3
  83. package/src/sources/SimulateSource.res.mjs +12 -4
  84. package/src/sources/Source.res +19 -5
  85. package/src/sources/SourceManager.res +60 -10
  86. package/src/sources/SourceManager.res.mjs +54 -8
  87. package/src/sources/SourceManager.resi +10 -0
  88. package/src/sources/Svm.res +14 -10
  89. package/src/sources/Svm.res.mjs +23 -6
  90. package/src/sources/SvmHyperSyncClient.res +5 -6
  91. package/src/sources/SvmHyperSyncSource.res +82 -41
  92. package/src/sources/SvmHyperSyncSource.res.mjs +86 -41
  93. package/src/sources/TransactionStore.res +6 -107
  94. package/src/sources/TransactionStore.res.mjs +5 -86
  95. package/svm.schema.json +19 -0
@@ -2,35 +2,18 @@
2
2
 
3
3
  import * as Utils from "./Utils.res.mjs";
4
4
  import * as Logging from "./Logging.res.mjs";
5
+ import * as ChainMap from "./ChainMap.res.mjs";
6
+ import * as EnvioGlobal from "./EnvioGlobal.res.mjs";
7
+ import * as EventRouter from "./sources/EventRouter.res.mjs";
5
8
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
6
9
  import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
7
10
  import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
11
+ import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
12
+ import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
13
+ import * as EventConfigBuilder from "./EventConfigBuilder.res.mjs";
14
+ import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
8
15
 
9
- let version = Utils.EnvioPackage.value.version;
10
-
11
- let existing = globalThis.__envioRegistry;
12
-
13
- let registry;
14
-
15
- if (existing == null) {
16
- let fresh_eventRegistrations = {};
17
- let fresh_activeRegistration = {
18
- contents: undefined
19
- };
20
- let fresh_preRegistered = [];
21
- let fresh = {
22
- version: version,
23
- eventRegistrations: fresh_eventRegistrations,
24
- activeRegistration: fresh_activeRegistration,
25
- preRegistered: fresh_preRegistered
26
- };
27
- globalThis.__envioRegistry = fresh;
28
- registry = fresh;
29
- } else {
30
- registry = existing.version === version ? existing : Stdlib_JsError.throwWithMessage(`Multiple incompatible envio versions loaded in the same process: ` + existing.version + ` and ` + version + `. Deduplicate the 'envio' dependency in your project.`);
31
- }
32
-
33
- let eventRegistrations = registry.eventRegistrations;
16
+ let eventRegistrations = EnvioGlobal.value.eventRegistrations;
34
17
 
35
18
  function getKey(contractName, eventName) {
36
19
  return contractName + "." + eventName;
@@ -53,12 +36,10 @@ function set(contractName, eventName, registration) {
53
36
  eventRegistrations[getKey(contractName, eventName)] = registration;
54
37
  }
55
38
 
56
- let activeRegistration = registry.activeRegistration;
57
-
58
- let preRegistered = registry.preRegistered;
39
+ let preRegistered = EnvioGlobal.value.preRegistered;
59
40
 
60
41
  function withRegistration(fn) {
61
- let r = activeRegistration.contents;
42
+ let r = EnvioGlobal.value.activeRegistration;
62
43
  if (r !== undefined) {
63
44
  if (r.finished) {
64
45
  return Stdlib_JsError.throwWithMessage("The indexer finished initializing, so no more handlers can be registered. Make sure the handlers are registered on the top level of the file.");
@@ -71,15 +52,13 @@ function withRegistration(fn) {
71
52
  }
72
53
  }
73
54
 
74
- function startRegistration(ecosystem) {
55
+ function startRegistration(config) {
75
56
  let r = {
76
- ecosystem: ecosystem,
77
- registrations: {
78
- onBlockByChainId: {}
79
- },
57
+ config: config,
58
+ registrationsByChainId: {},
80
59
  finished: false
81
60
  };
82
- activeRegistration.contents = r;
61
+ EnvioGlobal.value.activeRegistration = Primitive_option.some(r);
83
62
  while (preRegistered.length !== 0) {
84
63
  let fn = preRegistered.pop();
85
64
  if (fn !== undefined) {
@@ -88,51 +67,37 @@ function startRegistration(ecosystem) {
88
67
  };
89
68
  }
90
69
 
91
- function finishRegistration() {
92
- let r = activeRegistration.contents;
93
- if (r !== undefined) {
94
- r.finished = true;
95
- return r.registrations;
96
- } else {
97
- return Stdlib_JsError.throwWithMessage("The indexer has not started registering handlers, so can't finish it.");
98
- }
99
- }
100
-
101
- function isPendingRegistration() {
102
- let r = activeRegistration.contents;
103
- if (r !== undefined) {
104
- return !r.finished;
105
- } else {
106
- return false;
70
+ function getPendingChainRegistrations(r, chainId) {
71
+ let key = chainId.toString();
72
+ let pending = r.registrationsByChainId[key];
73
+ if (pending !== undefined) {
74
+ return pending;
107
75
  }
76
+ let fresh_onEventRegistrations = {};
77
+ let fresh_onBlockRegistrations = [];
78
+ let fresh = {
79
+ onEventRegistrations: fresh_onEventRegistrations,
80
+ onBlockRegistrations: fresh_onBlockRegistrations
81
+ };
82
+ r.registrationsByChainId[key] = fresh;
83
+ return fresh;
108
84
  }
109
85
 
110
- function throwIfFinishedRegistration(methodName) {
111
- let match = activeRegistration.contents;
112
- if (match === undefined) {
113
- return;
114
- }
115
- let match$1 = match.finished;
116
- if (match$1) {
117
- return Stdlib_JsError.throwWithMessage(`Cannot call \`indexer.` + methodName + `\` after the indexer has started. Make sure all handlers are registered at the top level of your handler module.`);
86
+ function buildOnEventRegistrationWith(config, chainId, eventConfig, isWildcard, handler, contractRegister, where, startBlock) {
87
+ let match = config.ecosystem.name;
88
+ switch (match) {
89
+ case "evm" :
90
+ return EventConfigBuilder.buildEvmOnEventRegistration(eventConfig, isWildcard, handler, contractRegister, where, chainId, config.ecosystem.onEventBlockFilterSchema, startBlock);
91
+ case "fuel" :
92
+ return EventConfigBuilder.buildFuelOnEventRegistration(eventConfig, isWildcard, handler, contractRegister, startBlock);
93
+ case "svm" :
94
+ return EventConfigBuilder.buildSvmOnEventRegistration(eventConfig, isWildcard, handler, contractRegister, startBlock);
118
95
  }
119
96
  }
120
97
 
121
- function registerOnBlock(name, chainId, interval, startBlock, endBlock, handler) {
122
- withRegistration(registration => {
123
- let onBlockByChainId = registration.registrations.onBlockByChainId;
124
- let key = chainId.toString();
125
- let index = Stdlib_Option.mapOr(onBlockByChainId[key], 0, configs => configs.length);
126
- Utils.Dict.push(onBlockByChainId, key, {
127
- index: index,
128
- name: name,
129
- chainId: chainId,
130
- startBlock: startBlock,
131
- endBlock: endBlock,
132
- interval: interval,
133
- handler: handler
134
- });
135
- });
98
+ function buildOnEventRegistration(config, chainId, eventConfig, startBlock) {
99
+ let t = get(eventConfig.contractName, eventConfig.name);
100
+ return buildOnEventRegistrationWith(config, chainId, eventConfig, Stdlib_Option.getOr(Stdlib_Option.flatMap(t.eventOptions, v => v.wildcard), false), t.handler, t.contractRegister, Stdlib_Option.flatMap(t.eventOptions, v => v.where), startBlock);
136
101
  }
137
102
 
138
103
  function getHandler(contractName, eventName) {
@@ -143,10 +108,6 @@ function getContractRegister(contractName, eventName) {
143
108
  return get(contractName, eventName).contractRegister;
144
109
  }
145
110
 
146
- function getOnEventWhere(contractName, eventName) {
147
- return Stdlib_Option.flatMap(get(contractName, eventName).eventOptions, value => value.where);
148
- }
149
-
150
111
  function isWildcard(contractName, eventName) {
151
112
  return Stdlib_Option.getOr(Stdlib_Option.flatMap(get(contractName, eventName).eventOptions, value => value.wildcard), false);
152
113
  }
@@ -171,22 +132,8 @@ function raiseDuplicateRegistration(contractName, eventName, msg, logger) {
171
132
 
172
133
  function eventOptionsMatch(existing, incoming) {
173
134
  if (existing !== undefined) {
174
- if (incoming !== undefined && existing.wildcard === incoming.wildcard) {
175
- let a = existing.where;
176
- let b = incoming.where;
177
- if (a !== undefined) {
178
- if (b !== undefined) {
179
- if (typeof a === "function" || typeof b === "function") {
180
- return a === b;
181
- } else {
182
- return Primitive_object.equal(a, b);
183
- }
184
- } else {
185
- return false;
186
- }
187
- } else {
188
- return b === undefined;
189
- }
135
+ if (incoming !== undefined) {
136
+ return existing.wildcard === incoming.wildcard;
190
137
  } else {
191
138
  return false;
192
139
  }
@@ -195,6 +142,31 @@ function eventOptionsMatch(existing, incoming) {
195
142
  }
196
143
  }
197
144
 
145
+ function syncOnEventRegistrations(r, contractName, eventName, where, duplicateMsg, logger) {
146
+ let config = r.config;
147
+ let t = get(contractName, eventName);
148
+ let isWildcard = Stdlib_Option.getOr(Stdlib_Option.flatMap(t.eventOptions, v => v.wildcard), false);
149
+ let key = getKey(contractName, eventName);
150
+ ChainMap.values(config.chainMap).forEach(chainConfig => {
151
+ chainConfig.contracts.forEach(contract => {
152
+ if (contract.name !== contractName) {
153
+ return;
154
+ }
155
+ let eventConfig = contract.events.find(e => e.name === eventName);
156
+ if (eventConfig === undefined) {
157
+ return;
158
+ }
159
+ let newRegistration = buildOnEventRegistrationWith(config, chainConfig.id, eventConfig, isWildcard, t.handler, t.contractRegister, where, contract.startBlock);
160
+ let pending = getPendingChainRegistrations(r, chainConfig.id);
161
+ let existing = pending.onEventRegistrations[key];
162
+ if (existing !== undefined && config.ecosystem.name === "evm" && !Primitive_object.equal(existing.resolvedWhere, newRegistration.resolvedWhere)) {
163
+ raiseDuplicateRegistration(contractName, eventName, duplicateMsg, logger);
164
+ }
165
+ pending.onEventRegistrations[key] = newRegistration;
166
+ });
167
+ });
168
+ }
169
+
198
170
  function setEventOptions(contractName, eventName, eventOptions, loggerOpt) {
199
171
  let logger = loggerOpt !== undefined ? loggerOpt : Logging.getLogger();
200
172
  if (eventOptions === undefined) {
@@ -219,76 +191,256 @@ function setEventOptions(contractName, eventName, eventOptions, loggerOpt) {
219
191
 
220
192
  function setHandler(contractName, eventName, handler, eventOptions, loggerOpt) {
221
193
  let logger = loggerOpt !== undefined ? loggerOpt : Logging.getLogger();
222
- withRegistration(_registration => {
194
+ withRegistration(registration => {
223
195
  let t = get(contractName, eventName);
196
+ let incomingEventOptions = Stdlib_Option.map(eventOptions, v => v);
224
197
  let prevHandler = t.handler;
225
198
  if (prevHandler !== undefined) {
226
- let incomingEventOptions = Stdlib_Option.map(eventOptions, v => v);
227
- if (!eventOptionsMatch(t.eventOptions, incomingEventOptions)) {
228
- return raiseDuplicateRegistration(contractName, eventName, "Cannot register a second handler with different options. Make sure all handlers for the same event use identical options (wildcard, where)", logger);
199
+ if (eventOptionsMatch(t.eventOptions, incomingEventOptions)) {
200
+ let composedHandler = async args => {
201
+ await prevHandler(args);
202
+ return await handler(args);
203
+ };
204
+ set(contractName, eventName, {
205
+ handler: composedHandler,
206
+ contractRegister: t.contractRegister,
207
+ eventOptions: t.eventOptions
208
+ });
209
+ } else {
210
+ raiseDuplicateRegistration(contractName, eventName, "Cannot register a second handler with different options. Make sure all handlers for the same event use identical options (wildcard, where)", logger);
229
211
  }
230
- let composedHandler = async args => {
231
- await prevHandler(args);
232
- return await handler(args);
233
- };
234
- return set(contractName, eventName, {
235
- handler: composedHandler,
236
- contractRegister: t.contractRegister,
237
- eventOptions: t.eventOptions
212
+ } else {
213
+ setEventOptions(contractName, eventName, eventOptions, logger);
214
+ let t$1 = get(contractName, eventName);
215
+ set(contractName, eventName, {
216
+ handler: handler,
217
+ contractRegister: t$1.contractRegister,
218
+ eventOptions: t$1.eventOptions
238
219
  });
239
220
  }
240
- setEventOptions(contractName, eventName, eventOptions, logger);
241
- let t$1 = get(contractName, eventName);
242
- set(contractName, eventName, {
243
- handler: handler,
244
- contractRegister: t$1.contractRegister,
245
- eventOptions: t$1.eventOptions
246
- });
221
+ syncOnEventRegistrations(registration, contractName, eventName, Stdlib_Option.flatMap(incomingEventOptions, v => v.where), "Cannot register a second handler with different options. Make sure all handlers for the same event use identical options (wildcard, where)", logger);
247
222
  });
248
223
  }
249
224
 
250
225
  function setContractRegister(contractName, eventName, contractRegister, eventOptions, loggerOpt) {
251
226
  let logger = loggerOpt !== undefined ? loggerOpt : Logging.getLogger();
252
- withRegistration(_registration => {
227
+ withRegistration(registration => {
253
228
  let t = get(contractName, eventName);
229
+ let incomingEventOptions = Stdlib_Option.map(eventOptions, v => v);
254
230
  let prevContractRegister = t.contractRegister;
255
231
  if (prevContractRegister !== undefined) {
256
- let incomingEventOptions = Stdlib_Option.map(eventOptions, v => v);
257
- if (!eventOptionsMatch(t.eventOptions, incomingEventOptions)) {
258
- return raiseDuplicateRegistration(contractName, eventName, "Cannot register a second contractRegister with different options. Make sure all handlers for the same event use identical options (wildcard, where)", logger);
232
+ if (eventOptionsMatch(t.eventOptions, incomingEventOptions)) {
233
+ let composedContractRegister = async args => {
234
+ await prevContractRegister(args);
235
+ return await contractRegister(args);
236
+ };
237
+ set(contractName, eventName, {
238
+ handler: t.handler,
239
+ contractRegister: composedContractRegister,
240
+ eventOptions: t.eventOptions
241
+ });
242
+ } else {
243
+ raiseDuplicateRegistration(contractName, eventName, "Cannot register a second contractRegister with different options. Make sure all handlers for the same event use identical options (wildcard, where)", logger);
259
244
  }
260
- let composedContractRegister = async args => {
261
- await prevContractRegister(args);
262
- return await contractRegister(args);
263
- };
264
- return set(contractName, eventName, {
265
- handler: t.handler,
266
- contractRegister: composedContractRegister,
267
- eventOptions: t.eventOptions
245
+ } else {
246
+ setEventOptions(contractName, eventName, eventOptions, logger);
247
+ let t$1 = get(contractName, eventName);
248
+ set(contractName, eventName, {
249
+ handler: t$1.handler,
250
+ contractRegister: contractRegister,
251
+ eventOptions: t$1.eventOptions
268
252
  });
269
253
  }
270
- setEventOptions(contractName, eventName, eventOptions, logger);
271
- let t$1 = get(contractName, eventName);
272
- set(contractName, eventName, {
273
- handler: t$1.handler,
274
- contractRegister: contractRegister,
275
- eventOptions: t$1.eventOptions
254
+ syncOnEventRegistrations(registration, contractName, eventName, Stdlib_Option.flatMap(incomingEventOptions, v => v.where), "Cannot register a second contractRegister with different options. Make sure all handlers for the same event use identical options (wildcard, where)", logger);
255
+ });
256
+ }
257
+
258
+ let blockRangeSchema = S$RescriptSchema.strict(S$RescriptSchema.object(s => ({
259
+ _gte: s.f("_gte", S$RescriptSchema.option(S$RescriptSchema.int)),
260
+ _lte: s.f("_lte", S$RescriptSchema.option(S$RescriptSchema.int)),
261
+ _every: s.f("_every", S$RescriptSchema.Option.getOr(S$RescriptSchema.option(S$RescriptSchema.intMin(S$RescriptSchema.int, 1, undefined)), 1))
262
+ })));
263
+
264
+ let defaultBlockRange = {
265
+ _gte: undefined,
266
+ _lte: undefined,
267
+ _every: 1
268
+ };
269
+
270
+ function extractRange(filter, name, ecosystem) {
271
+ try {
272
+ let inner = S$RescriptSchema.parseOrThrow(filter, ecosystem.onBlockFilterSchema);
273
+ if (inner !== undefined) {
274
+ return S$RescriptSchema.parseOrThrow(Primitive_option.valFromOption(inner), blockRangeSchema);
275
+ } else {
276
+ return defaultBlockRange;
277
+ }
278
+ } catch (raw_exn) {
279
+ let exn = Primitive_exceptions.internalToException(raw_exn);
280
+ if (exn.RE_EXN_ID === S$RescriptSchema.Raised) {
281
+ return Stdlib_JsError.throwWithMessage(`\`indexer.` + ecosystem.onBlockMethodName + `("` + name + `")\` \`where\` returned an invalid filter: ` + Utils.prettifyExn(exn._1));
282
+ }
283
+ throw exn;
284
+ }
285
+ }
286
+
287
+ function registerOnBlock(name, where, handler, getChainsObject) {
288
+ withRegistration(registration => {
289
+ let config = registration.config;
290
+ let ecosystem = config.ecosystem;
291
+ let chainsDict = getChainsObject(config);
292
+ let logger = Logging.createChild({
293
+ onBlock: name
276
294
  });
295
+ let where$1 = where === undefined || where === null ? undefined : (
296
+ typeof where === "function" ? where : Stdlib_JsError.throwWithMessage(`\`indexer.` + ecosystem.onBlockMethodName + `("` + name + `")\` expected \`where\` to be a function or omitted, but got ` + typeof where + `.`)
297
+ );
298
+ let matchedAny = {
299
+ contents: false
300
+ };
301
+ ChainMap.values(config.chainMap).forEach(chainConfig => {
302
+ let chainId = chainConfig.id;
303
+ let chainObj = chainsDict[chainId.toString()];
304
+ let result = where$1 !== undefined ? where$1({
305
+ chain: chainObj
306
+ }) : true;
307
+ let match = result === true ? [
308
+ true,
309
+ defaultBlockRange
310
+ ] : (
311
+ result === false ? [
312
+ false,
313
+ defaultBlockRange
314
+ ] : (
315
+ typeof result === "object" && !Array.isArray(result) && result !== null ? [
316
+ true,
317
+ extractRange(result, name, ecosystem)
318
+ ] : Stdlib_JsError.throwWithMessage(`\`indexer.` + ecosystem.onBlockMethodName + `("` + name + `")\` \`where\` predicate returned an invalid value of type ` + typeof result + `. Expected boolean or a filter object.`)
319
+ )
320
+ );
321
+ if (!match[0]) {
322
+ return;
323
+ }
324
+ let range = match[1];
325
+ matchedAny.contents = true;
326
+ if (Stdlib_Option.getOr(range._gte, chainConfig.startBlock) < chainConfig.startBlock) {
327
+ Stdlib_JsError.throwWithMessage(`The start block for onBlock handler "` + name + `" is less than the chain start block (` + chainConfig.startBlock.toString() + `). This is not supported yet.`);
328
+ }
329
+ let chainEndBlock = chainConfig.endBlock;
330
+ if (chainEndBlock !== undefined && Stdlib_Option.getOr(range._lte, chainEndBlock) > chainEndBlock) {
331
+ Stdlib_JsError.throwWithMessage(`The end block for onBlock handler "` + name + `" is greater than the chain end block (` + chainEndBlock.toString() + `). This is not supported yet.`);
332
+ }
333
+ let pending = getPendingChainRegistrations(registration, chainId);
334
+ pending.onBlockRegistrations.push({
335
+ index: pending.onBlockRegistrations.length,
336
+ name: name,
337
+ chainId: chainId,
338
+ startBlock: range._gte,
339
+ endBlock: range._lte,
340
+ interval: range._every,
341
+ handler: handler
342
+ });
343
+ });
344
+ if (!matchedAny.contents) {
345
+ return Logging.childWarn(logger, `\`indexer.` + ecosystem.onBlockMethodName + `\` matched 0 chains. Check the \`where\` predicate.`);
346
+ }
277
347
  });
278
348
  }
279
349
 
350
+ function finishRegistration(config) {
351
+ let r = EnvioGlobal.value.activeRegistration;
352
+ if (r === undefined) {
353
+ return Stdlib_JsError.throwWithMessage("The indexer has not started registering handlers, so can't finish it.");
354
+ }
355
+ r.finished = true;
356
+ let notRegisteredEventsByContract = {};
357
+ let registrationsByChainId = {};
358
+ ChainMap.values(config.chainMap).forEach(chainConfig => {
359
+ let key = chainConfig.id.toString();
360
+ let pending = r.registrationsByChainId[key];
361
+ let eventRouter = EventRouter.empty();
362
+ let onEventRegistrations = [];
363
+ chainConfig.contracts.forEach(contract => {
364
+ let contractName = contract.name;
365
+ contract.events.forEach(eventConfig => {
366
+ let eventName = eventConfig.name;
367
+ let registration = Stdlib_Option.flatMap(pending, pending => pending.onEventRegistrations[getKey(contractName, eventName)]);
368
+ EventRouter.addOrThrow(eventRouter, eventConfig.id, undefined, contractName, registration !== undefined ? registration.isWildcard : isWildcard(contractName, eventName), eventName, ChainMap.Chain.makeUnsafe(chainConfig.id));
369
+ let registration$1;
370
+ if (registration !== undefined) {
371
+ registration$1 = registration;
372
+ } else if (hasRegistration(contractName, eventName) || config.enableRawEvents) {
373
+ registration$1 = buildOnEventRegistration(config, chainConfig.id, eventConfig, contract.startBlock);
374
+ } else {
375
+ let set = notRegisteredEventsByContract[contractName];
376
+ let eventNames;
377
+ if (set !== undefined) {
378
+ eventNames = Primitive_option.valFromOption(set);
379
+ } else {
380
+ let set$1 = new Set();
381
+ notRegisteredEventsByContract[contractName] = set$1;
382
+ eventNames = set$1;
383
+ }
384
+ eventNames.add(eventName);
385
+ registration$1 = undefined;
386
+ }
387
+ if (registration$1 === undefined) {
388
+ return;
389
+ }
390
+ let isDroppedByWhere = config.ecosystem.name === "evm" && Utils.$$Array.isEmpty(registration$1.resolvedWhere.topicSelections);
391
+ if (!isDroppedByWhere) {
392
+ onEventRegistrations.push(registration$1);
393
+ return;
394
+ }
395
+ });
396
+ });
397
+ registrationsByChainId[key] = {
398
+ onEventRegistrations: onEventRegistrations,
399
+ onBlockRegistrations: pending !== undefined ? pending.onBlockRegistrations : []
400
+ };
401
+ });
402
+ let notRegisteredEntries = Object.entries(notRegisteredEventsByContract);
403
+ if (Utils.$$Array.notEmpty(notRegisteredEntries)) {
404
+ let groups = notRegisteredEntries.map(param => param[0] + ` (` + Array.from(param[1]).join(", ") + `)`).join(", ");
405
+ Logging.childInfo(Logging.getLogger(), `Events without a handler, skipped for indexing: ` + groups);
406
+ }
407
+ return registrationsByChainId;
408
+ }
409
+
410
+ function isPendingRegistration() {
411
+ let r = EnvioGlobal.value.activeRegistration;
412
+ if (r !== undefined) {
413
+ return !r.finished;
414
+ } else {
415
+ return false;
416
+ }
417
+ }
418
+
419
+ function throwIfFinishedRegistration(methodName) {
420
+ let match = EnvioGlobal.value.activeRegistration;
421
+ if (match === undefined) {
422
+ return;
423
+ }
424
+ let match$1 = match.finished;
425
+ if (match$1) {
426
+ return Stdlib_JsError.throwWithMessage(`Cannot call \`indexer.` + methodName + `\` after the indexer has started. Make sure all handlers are registered at the top level of your handler module.`);
427
+ }
428
+ }
429
+
280
430
  export {
281
431
  startRegistration,
282
432
  isPendingRegistration,
283
433
  finishRegistration,
284
434
  throwIfFinishedRegistration,
435
+ buildOnEventRegistration,
285
436
  setHandler,
286
437
  setContractRegister,
287
438
  getHandler,
288
439
  getContractRegister,
289
- getOnEventWhere,
290
440
  isWildcard,
291
441
  hasRegistration,
442
+ blockRangeSchema,
443
+ defaultBlockRange,
292
444
  registerOnBlock,
293
445
  }
294
- /* existing Not a pure module */
446
+ /* blockRangeSchema Not a pure module */
@@ -1,10 +1,21 @@
1
- type registrations = {onBlockByChainId: dict<array<Internal.onBlockConfig>>}
1
+ type chainRegistrations = {
2
+ onEventRegistrations: array<Internal.onEventRegistration>,
3
+ onBlockRegistrations: array<Internal.onBlockRegistration>,
4
+ }
5
+ type registrationsByChainId = dict<chainRegistrations>
2
6
 
3
- let startRegistration: (~ecosystem: Ecosystem.t) => unit
7
+ let startRegistration: (~config: Config.t) => unit
4
8
  let isPendingRegistration: unit => bool
5
- let finishRegistration: unit => registrations
9
+ let finishRegistration: (~config: Config.t) => registrationsByChainId
6
10
  let throwIfFinishedRegistration: (~methodName: string) => unit
7
11
 
12
+ let buildOnEventRegistration: (
13
+ ~config: Config.t,
14
+ ~chainId: int,
15
+ ~eventConfig: Internal.eventConfig,
16
+ ~startBlock: int=?,
17
+ ) => Internal.onEventRegistration
18
+
8
19
  let setHandler: (
9
20
  ~contractName: string,
10
21
  ~eventName: string,
@@ -24,15 +35,20 @@ let getContractRegister: (
24
35
  ~contractName: string,
25
36
  ~eventName: string,
26
37
  ) => option<Internal.contractRegister>
27
- let getOnEventWhere: (~contractName: string, ~eventName: string) => option<JSON.t>
28
38
  let isWildcard: (~contractName: string, ~eventName: string) => bool
29
39
  let hasRegistration: (~contractName: string, ~eventName: string) => bool
30
40
 
41
+ type blockRange = {
42
+ _gte: option<int>,
43
+ _lte: option<int>,
44
+ _every: int,
45
+ }
46
+ let blockRangeSchema: S.t<blockRange>
47
+ let defaultBlockRange: blockRange
48
+
31
49
  let registerOnBlock: (
32
50
  ~name: string,
33
- ~chainId: int,
34
- ~interval: int,
35
- ~startBlock: option<int>,
36
- ~endBlock: option<int>,
51
+ ~where: unknown,
37
52
  ~handler: Internal.onBlockArgs => promise<unit>,
53
+ ~getChainsObject: Config.t => dict<unknown>,
38
54
  ) => unit
@@ -188,7 +188,7 @@ let makeFromDbState = (
188
188
  ~config: Config.t,
189
189
  ~persistence: Persistence.t,
190
190
  ~initialState: Persistence.initialState,
191
- ~registrations,
191
+ ~registrationsByChainId,
192
192
  ~isDevelopmentMode=false,
193
193
  ~shouldUseTui=false,
194
194
  ~exitAfterFirstEventBlock=false,
@@ -234,7 +234,7 @@ let makeFromDbState = (
234
234
  ~isInReorgThreshold,
235
235
  ~isRealtime,
236
236
  ~config,
237
- ~registrations,
237
+ ~registrationsByChainId,
238
238
  ~reducedPollingInterval?,
239
239
  ),
240
240
  )
@@ -362,7 +362,10 @@ let clearRollback = (state: t) => state.rollbackState = NoRollback
362
362
  let invalidateInflight = (state: t) => state.epoch = state.epoch + 1
363
363
 
364
364
  let applyBatchProgress = (state: t, ~batch: Batch.t) =>
365
- state.crossChainState->CrossChainState.applyBatchProgress(~batch)
365
+ state.crossChainState->CrossChainState.applyBatchProgress(
366
+ ~batch,
367
+ ~blockTimestampName=state.config.ecosystem.blockTimestampName,
368
+ )
366
369
 
367
370
  // Processing-loop mutex. Guards ProcessEventBatch re-entry so only one
368
371
  // processing loop runs at a time.
@@ -97,7 +97,7 @@ function make$2(config, persistence, chainStates, isInReorgThreshold, isRealtime
97
97
  };
98
98
  }
99
99
 
100
- function makeFromDbState(config, persistence, initialState, registrations, isDevelopmentModeOpt, shouldUseTuiOpt, exitAfterFirstEventBlockOpt, reducedPollingInterval, targetBufferSizeOpt, onError) {
100
+ function makeFromDbState(config, persistence, initialState, registrationsByChainId, isDevelopmentModeOpt, shouldUseTuiOpt, exitAfterFirstEventBlockOpt, reducedPollingInterval, targetBufferSizeOpt, onError) {
101
101
  let isDevelopmentMode = isDevelopmentModeOpt !== undefined ? isDevelopmentModeOpt : false;
102
102
  let shouldUseTui = shouldUseTuiOpt !== undefined ? shouldUseTuiOpt : false;
103
103
  let exitAfterFirstEventBlock = exitAfterFirstEventBlockOpt !== undefined ? exitAfterFirstEventBlockOpt : false;
@@ -123,7 +123,7 @@ function makeFromDbState(config, persistence, initialState, registrations, isDev
123
123
  initialState.chains.forEach(resumedChainState => {
124
124
  let chain = Config.getChain(config, resumedChainState.id);
125
125
  let chainConfig = ChainMap.get(config.chainMap, chain);
126
- chainStates[resumedChainState.id] = ChainState.makeFromDbState(chainConfig, resumedChainState, initialState.reorgCheckpoints, isInReorgThreshold, isRealtime, config, registrations, reducedPollingInterval);
126
+ chainStates[resumedChainState.id] = ChainState.makeFromDbState(chainConfig, resumedChainState, initialState.reorgCheckpoints, isInReorgThreshold, isRealtime, config, registrationsByChainId, reducedPollingInterval);
127
127
  });
128
128
  let allChainsReady = {
129
129
  contents: initialState.chains.length !== 0
@@ -231,7 +231,7 @@ function invalidateInflight(state) {
231
231
  }
232
232
 
233
233
  function applyBatchProgress(state, batch) {
234
- CrossChainState.applyBatchProgress(state.crossChainState, batch);
234
+ CrossChainState.applyBatchProgress(state.crossChainState, batch, state.config.ecosystem.blockTimestampName);
235
235
  }
236
236
 
237
237
  function isProcessing(state) {
@@ -44,7 +44,7 @@ let makeFromDbState: (
44
44
  ~config: Config.t,
45
45
  ~persistence: Persistence.t,
46
46
  ~initialState: Persistence.initialState,
47
- ~registrations: HandlerRegister.registrations,
47
+ ~registrationsByChainId: HandlerRegister.registrationsByChainId,
48
48
  ~isDevelopmentMode: bool=?,
49
49
  ~shouldUseTui: bool=?,
50
50
  ~exitAfterFirstEventBlock: bool=?,
@@ -8,15 +8,18 @@ let deriveEffectiveStartBlock = (~registrationBlock: int, ~contractStartBlock: o
8
8
  Pervasives.max(Pervasives.max(registrationBlock, 0), contractStartBlock->Option.getOr(0))
9
9
  }
10
10
 
11
- let makeContractConfigs = (~eventConfigs: array<Internal.eventConfig>): dict<contractConfig> => {
11
+ let makeContractConfigs = (~onEventRegistrations: array<Internal.onEventRegistration>): dict<
12
+ contractConfig,
13
+ > => {
12
14
  let contractConfigs: dict<contractConfig> = Dict.make()
13
- eventConfigs->Array.forEach(ec => {
14
- switch contractConfigs->Utils.Dict.dangerouslyGetNonOption(ec.contractName) {
15
+ onEventRegistrations->Array.forEach(reg => {
16
+ let contractName = reg.eventConfig.contractName
17
+ switch contractConfigs->Utils.Dict.dangerouslyGetNonOption(contractName) {
15
18
  | Some({startBlock}) =>
16
19
  contractConfigs->Dict.set(
17
- ec.contractName,
20
+ contractName,
18
21
  {
19
- startBlock: switch (startBlock, ec.startBlock) {
22
+ startBlock: switch (startBlock, reg.startBlock) {
20
23
  | (Some(a), Some(b)) => Some(Pervasives.min(a, b))
21
24
  | (Some(_) as s, None) | (None, Some(_) as s) => s
22
25
  | (None, None) => None
@@ -25,9 +28,9 @@ let makeContractConfigs = (~eventConfigs: array<Internal.eventConfig>): dict<con
25
28
  )
26
29
  | None =>
27
30
  contractConfigs->Dict.set(
28
- ec.contractName,
31
+ contractName,
29
32
  {
30
- startBlock: ec.startBlock,
33
+ startBlock: reg.startBlock,
31
34
  },
32
35
  )
33
36
  }