envio 3.3.0-alpha.8 → 3.3.0-rc.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 (107) hide show
  1. package/index.d.ts +19 -0
  2. package/licenses/CLA.md +35 -0
  3. package/licenses/EULA.md +67 -0
  4. package/licenses/LICENSE.md +45 -0
  5. package/licenses/README.md +35 -0
  6. package/package.json +9 -8
  7. package/src/Batch.res.mjs +1 -1
  8. package/src/BatchProcessing.res +0 -7
  9. package/src/BatchProcessing.res.mjs +1 -8
  10. package/src/ChainFetching.res +30 -18
  11. package/src/ChainFetching.res.mjs +23 -13
  12. package/src/ChainState.res +205 -59
  13. package/src/ChainState.res.mjs +130 -27
  14. package/src/ChainState.resi +16 -1
  15. package/src/Config.res +9 -5
  16. package/src/Config.res.mjs +2 -2
  17. package/src/Core.res +20 -0
  18. package/src/Core.res.mjs +12 -0
  19. package/src/CrossChainState.res +147 -39
  20. package/src/CrossChainState.res.mjs +42 -10
  21. package/src/EffectState.res +100 -0
  22. package/src/EffectState.res.mjs +74 -0
  23. package/src/EffectState.resi +32 -0
  24. package/src/Envio.res +25 -7
  25. package/src/Envio.res.mjs +15 -19
  26. package/src/EnvioGlobal.res +53 -0
  27. package/src/EnvioGlobal.res.mjs +31 -0
  28. package/src/EventConfigBuilder.res +30 -56
  29. package/src/EventConfigBuilder.res.mjs +24 -30
  30. package/src/EventProcessing.res +8 -5
  31. package/src/EventProcessing.res.mjs +2 -1
  32. package/src/FetchState.res +842 -474
  33. package/src/FetchState.res.mjs +545 -356
  34. package/src/HandlerLoader.res +1 -1
  35. package/src/HandlerLoader.res.mjs +1 -1
  36. package/src/HandlerRegister.res +478 -305
  37. package/src/HandlerRegister.res.mjs +277 -209
  38. package/src/HandlerRegister.resi +11 -6
  39. package/src/InMemoryStore.res +14 -26
  40. package/src/InMemoryStore.res.mjs +6 -19
  41. package/src/IndexerState.res +15 -39
  42. package/src/IndexerState.res.mjs +18 -29
  43. package/src/IndexerState.resi +2 -10
  44. package/src/Internal.res +121 -18
  45. package/src/Internal.res.mjs +96 -2
  46. package/src/LoadLayer.res +44 -24
  47. package/src/LoadLayer.res.mjs +43 -20
  48. package/src/LoadLayer.resi +1 -0
  49. package/src/LogSelection.res +92 -217
  50. package/src/LogSelection.res.mjs +95 -184
  51. package/src/Main.res +29 -143
  52. package/src/Main.res.mjs +25 -88
  53. package/src/Metrics.res +1 -1
  54. package/src/Metrics.res.mjs +1 -1
  55. package/src/Persistence.res +12 -3
  56. package/src/PgStorage.res +155 -82
  57. package/src/PgStorage.res.mjs +130 -77
  58. package/src/Prometheus.res +20 -10
  59. package/src/Prometheus.res.mjs +22 -10
  60. package/src/PruneStaleHistory.res +146 -35
  61. package/src/PruneStaleHistory.res.mjs +114 -20
  62. package/src/RawEvent.res +2 -2
  63. package/src/Rollback.res +32 -13
  64. package/src/Rollback.res.mjs +24 -11
  65. package/src/RollbackCommit.res +4 -1
  66. package/src/RollbackCommit.res.mjs +3 -2
  67. package/src/SimulateDeadInputTracker.res +1 -1
  68. package/src/SimulateItems.res +39 -7
  69. package/src/SimulateItems.res.mjs +28 -9
  70. package/src/TestIndexer.res +2 -2
  71. package/src/TestIndexer.res.mjs +2 -2
  72. package/src/TopicFilter.res +1 -25
  73. package/src/TopicFilter.res.mjs +0 -74
  74. package/src/UserContext.res +62 -23
  75. package/src/UserContext.res.mjs +26 -6
  76. package/src/Writing.res +60 -21
  77. package/src/Writing.res.mjs +27 -9
  78. package/src/bindings/NodeJs.res +5 -0
  79. package/src/bindings/Viem.res +0 -5
  80. package/src/sources/EventRouter.res +0 -21
  81. package/src/sources/EventRouter.res.mjs +0 -12
  82. package/src/sources/Evm.res +4 -1
  83. package/src/sources/Evm.res.mjs +1 -1
  84. package/src/sources/EvmChain.res +2 -27
  85. package/src/sources/EvmChain.res.mjs +2 -23
  86. package/src/sources/EvmRpcClient.res +58 -23
  87. package/src/sources/EvmRpcClient.res.mjs +11 -5
  88. package/src/sources/Fuel.res +3 -1
  89. package/src/sources/Fuel.res.mjs +1 -1
  90. package/src/sources/HyperSync.res +9 -38
  91. package/src/sources/HyperSync.res.mjs +16 -28
  92. package/src/sources/HyperSync.resi +2 -2
  93. package/src/sources/HyperSyncClient.res +88 -11
  94. package/src/sources/HyperSyncClient.res.mjs +39 -6
  95. package/src/sources/HyperSyncSource.res +18 -210
  96. package/src/sources/HyperSyncSource.res.mjs +9 -137
  97. package/src/sources/Rpc.res +0 -32
  98. package/src/sources/Rpc.res.mjs +1 -46
  99. package/src/sources/RpcSource.res +129 -533
  100. package/src/sources/RpcSource.res.mjs +161 -379
  101. package/src/sources/SimulateSource.res +37 -19
  102. package/src/sources/SimulateSource.res.mjs +27 -10
  103. package/src/sources/SourceManager.res +4 -14
  104. package/src/sources/SourceManager.res.mjs +3 -9
  105. package/src/sources/SourceManager.resi +0 -2
  106. package/src/sources/SvmHyperSyncSource.res +13 -3
  107. package/src/sources/SvmHyperSyncSource.res.mjs +1 -1
@@ -3,38 +3,17 @@
3
3
  import * as Utils from "./Utils.res.mjs";
4
4
  import * as Logging from "./Logging.res.mjs";
5
5
  import * as ChainMap from "./ChainMap.res.mjs";
6
+ import * as EnvioGlobal from "./EnvioGlobal.res.mjs";
6
7
  import * as EventRouter from "./sources/EventRouter.res.mjs";
7
8
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
8
9
  import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
9
10
  import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
10
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";
11
13
  import * as EventConfigBuilder from "./EventConfigBuilder.res.mjs";
14
+ import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
12
15
 
13
- let version = Utils.EnvioPackage.value.version;
14
-
15
- let existing = globalThis.__envioRegistry;
16
-
17
- let registry;
18
-
19
- if (existing == null) {
20
- let fresh_eventRegistrations = {};
21
- let fresh_activeRegistration = {
22
- contents: undefined
23
- };
24
- let fresh_preRegistered = [];
25
- let fresh = {
26
- version: version,
27
- eventRegistrations: fresh_eventRegistrations,
28
- activeRegistration: fresh_activeRegistration,
29
- preRegistered: fresh_preRegistered
30
- };
31
- globalThis.__envioRegistry = fresh;
32
- registry = fresh;
33
- } else {
34
- 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.`);
35
- }
36
-
37
- let eventRegistrations = registry.eventRegistrations;
16
+ let eventRegistrations = EnvioGlobal.value.eventRegistrations;
38
17
 
39
18
  function getKey(contractName, eventName) {
40
19
  return contractName + "." + eventName;
@@ -57,12 +36,10 @@ function set(contractName, eventName, registration) {
57
36
  eventRegistrations[getKey(contractName, eventName)] = registration;
58
37
  }
59
38
 
60
- let activeRegistration = registry.activeRegistration;
61
-
62
- let preRegistered = registry.preRegistered;
39
+ let preRegistered = EnvioGlobal.value.preRegistered;
63
40
 
64
41
  function withRegistration(fn) {
65
- let r = activeRegistration.contents;
42
+ let r = EnvioGlobal.value.activeRegistration;
66
43
  if (r !== undefined) {
67
44
  if (r.finished) {
68
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.");
@@ -75,15 +52,13 @@ function withRegistration(fn) {
75
52
  }
76
53
  }
77
54
 
78
- function startRegistration(ecosystem) {
55
+ function startRegistration(config) {
79
56
  let r = {
80
- ecosystem: ecosystem,
81
- registrations: {
82
- onBlockByChainId: {}
83
- },
57
+ config: config,
58
+ registrationsByChainId: {},
84
59
  finished: false
85
60
  };
86
- activeRegistration.contents = r;
61
+ EnvioGlobal.value.activeRegistration = Primitive_option.some(r);
87
62
  while (preRegistered.length !== 0) {
88
63
  let fn = preRegistered.pop();
89
64
  if (fn !== undefined) {
@@ -92,17 +67,27 @@ function startRegistration(ecosystem) {
92
67
  };
93
68
  }
94
69
 
95
- function buildOnEventRegistration(config, chainId, eventConfig, startBlock) {
96
- let contractName = eventConfig.contractName;
97
- let eventName = eventConfig.name;
98
- let t = get(contractName, eventName);
99
- let isWildcard = Stdlib_Option.getOr(Stdlib_Option.flatMap(t.eventOptions, v => v.wildcard), false);
100
- let handler = t.handler;
101
- let contractRegister = t.contractRegister;
70
+ function getPendingChainRegistrations(r, chainId) {
71
+ let key = chainId.toString();
72
+ let pending = r.registrationsByChainId[key];
73
+ if (pending !== undefined) {
74
+ return pending;
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;
84
+ }
85
+
86
+ function buildOnEventRegistrationWith(config, chainId, eventConfig, isWildcard, handler, contractRegister, where, startBlock) {
102
87
  let match = config.ecosystem.name;
103
88
  switch (match) {
104
89
  case "evm" :
105
- return EventConfigBuilder.buildEvmOnEventRegistration(eventConfig, isWildcard, handler, contractRegister, Stdlib_Option.flatMap(t.eventOptions, v => v.where), chainId, config.ecosystem.onEventBlockFilterSchema, startBlock);
90
+ return EventConfigBuilder.buildEvmOnEventRegistration(eventConfig, isWildcard, handler, contractRegister, where, chainId, config.ecosystem.onEventBlockFilterSchema, startBlock);
106
91
  case "fuel" :
107
92
  return EventConfigBuilder.buildFuelOnEventRegistration(eventConfig, isWildcard, handler, contractRegister, startBlock);
108
93
  case "svm" :
@@ -110,113 +95,9 @@ function buildOnEventRegistration(config, chainId, eventConfig, startBlock) {
110
95
  }
111
96
  }
112
97
 
113
- function buildOnEventRegistrations(chainConfig, config, notRegisteredEventsByContract) {
114
- let eventRouter = EventRouter.empty();
115
- let onEventRegistrations = [];
116
- chainConfig.contracts.forEach(contract => {
117
- let contractName = contract.name;
118
- contract.events.forEach(eventConfig => {
119
- let eventName = eventConfig.name;
120
- let onEventRegistration = buildOnEventRegistration(config, chainConfig.id, eventConfig, contract.startBlock);
121
- EventRouter.addOrThrow(eventRouter, eventConfig.id, undefined, contractName, onEventRegistration.isWildcard, eventName, ChainMap.Chain.makeUnsafe(chainConfig.id));
122
- let shouldBeIncluded;
123
- if (config.enableRawEvents) {
124
- shouldBeIncluded = true;
125
- } else {
126
- let isRegistered = Stdlib_Option.isSome(onEventRegistration.contractRegister) || Stdlib_Option.isSome(onEventRegistration.handler);
127
- if (!isRegistered) {
128
- let set = notRegisteredEventsByContract[contractName];
129
- let eventNames;
130
- if (set !== undefined) {
131
- eventNames = Primitive_option.valFromOption(set);
132
- } else {
133
- let set$1 = new Set();
134
- notRegisteredEventsByContract[contractName] = set$1;
135
- eventNames = set$1;
136
- }
137
- eventNames.add(eventName);
138
- }
139
- shouldBeIncluded = isRegistered;
140
- }
141
- let shouldSkip;
142
- try {
143
- let getEventFiltersOrThrow = onEventRegistration.getEventFiltersOrThrow;
144
- if (getEventFiltersOrThrow) {
145
- let match = getEventFiltersOrThrow(ChainMap.Chain.makeUnsafe(chainConfig.id));
146
- shouldSkip = match.TAG === "Static" ? match._0.length === 0 : false;
147
- } else {
148
- shouldSkip = false;
149
- }
150
- } catch (exn) {
151
- shouldSkip = false;
152
- }
153
- if (shouldBeIncluded && !shouldSkip) {
154
- onEventRegistrations.push(onEventRegistration);
155
- return;
156
- }
157
- });
158
- });
159
- return onEventRegistrations;
160
- }
161
-
162
- function finishRegistration(config) {
163
- let r = activeRegistration.contents;
164
- if (r === undefined) {
165
- return Stdlib_JsError.throwWithMessage("The indexer has not started registering handlers, so can't finish it.");
166
- }
167
- r.finished = true;
168
- let notRegisteredEventsByContract = {};
169
- let registrationsByChainId = {};
170
- ChainMap.values(config.chainMap).forEach(chainConfig => {
171
- let key = chainConfig.id.toString();
172
- registrationsByChainId[key] = {
173
- onEventRegistrations: buildOnEventRegistrations(chainConfig, config, notRegisteredEventsByContract),
174
- onBlockRegistrations: Stdlib_Option.getOr(r.registrations.onBlockByChainId[key], [])
175
- };
176
- });
177
- let notRegisteredEntries = Object.entries(notRegisteredEventsByContract);
178
- if (Utils.$$Array.notEmpty(notRegisteredEntries)) {
179
- let groups = notRegisteredEntries.map(param => param[0] + ` (` + Array.from(param[1]).join(", ") + `)`).join(", ");
180
- Logging.childInfo(Logging.getLogger(), `Events without a handler, skipped for indexing: ` + groups);
181
- }
182
- return registrationsByChainId;
183
- }
184
-
185
- function isPendingRegistration() {
186
- let r = activeRegistration.contents;
187
- if (r !== undefined) {
188
- return !r.finished;
189
- } else {
190
- return false;
191
- }
192
- }
193
-
194
- function throwIfFinishedRegistration(methodName) {
195
- let match = activeRegistration.contents;
196
- if (match === undefined) {
197
- return;
198
- }
199
- let match$1 = match.finished;
200
- if (match$1) {
201
- 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.`);
202
- }
203
- }
204
-
205
- function registerOnBlock(name, chainId, interval, startBlock, endBlock, handler) {
206
- withRegistration(registration => {
207
- let onBlockByChainId = registration.registrations.onBlockByChainId;
208
- let key = chainId.toString();
209
- let index = Stdlib_Option.mapOr(onBlockByChainId[key], 0, configs => configs.length);
210
- Utils.Dict.push(onBlockByChainId, key, {
211
- index: index,
212
- name: name,
213
- chainId: chainId,
214
- startBlock: startBlock,
215
- endBlock: endBlock,
216
- interval: interval,
217
- handler: handler
218
- });
219
- });
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);
220
101
  }
221
102
 
222
103
  function getHandler(contractName, eventName) {
@@ -227,10 +108,6 @@ function getContractRegister(contractName, eventName) {
227
108
  return get(contractName, eventName).contractRegister;
228
109
  }
229
110
 
230
- function getOnEventWhere(contractName, eventName) {
231
- return Stdlib_Option.flatMap(get(contractName, eventName).eventOptions, value => value.where);
232
- }
233
-
234
111
  function isWildcard(contractName, eventName) {
235
112
  return Stdlib_Option.getOr(Stdlib_Option.flatMap(get(contractName, eventName).eventOptions, value => value.wildcard), false);
236
113
  }
@@ -255,22 +132,8 @@ function raiseDuplicateRegistration(contractName, eventName, msg, logger) {
255
132
 
256
133
  function eventOptionsMatch(existing, incoming) {
257
134
  if (existing !== undefined) {
258
- if (incoming !== undefined && existing.wildcard === incoming.wildcard) {
259
- let a = existing.where;
260
- let b = incoming.where;
261
- if (a !== undefined) {
262
- if (b !== undefined) {
263
- if (typeof a === "function" || typeof b === "function") {
264
- return a === b;
265
- } else {
266
- return Primitive_object.equal(a, b);
267
- }
268
- } else {
269
- return false;
270
- }
271
- } else {
272
- return b === undefined;
273
- }
135
+ if (incoming !== undefined) {
136
+ return existing.wildcard === incoming.wildcard;
274
137
  } else {
275
138
  return false;
276
139
  }
@@ -279,6 +142,31 @@ function eventOptionsMatch(existing, incoming) {
279
142
  }
280
143
  }
281
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
+
282
170
  function setEventOptions(contractName, eventName, eventOptions, loggerOpt) {
283
171
  let logger = loggerOpt !== undefined ? loggerOpt : Logging.getLogger();
284
172
  if (eventOptions === undefined) {
@@ -303,64 +191,243 @@ function setEventOptions(contractName, eventName, eventOptions, loggerOpt) {
303
191
 
304
192
  function setHandler(contractName, eventName, handler, eventOptions, loggerOpt) {
305
193
  let logger = loggerOpt !== undefined ? loggerOpt : Logging.getLogger();
306
- withRegistration(_registration => {
194
+ withRegistration(registration => {
307
195
  let t = get(contractName, eventName);
196
+ let incomingEventOptions = Stdlib_Option.map(eventOptions, v => v);
308
197
  let prevHandler = t.handler;
309
198
  if (prevHandler !== undefined) {
310
- let incomingEventOptions = Stdlib_Option.map(eventOptions, v => v);
311
- if (!eventOptionsMatch(t.eventOptions, incomingEventOptions)) {
312
- 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);
313
211
  }
314
- let composedHandler = async args => {
315
- await prevHandler(args);
316
- return await handler(args);
317
- };
318
- return set(contractName, eventName, {
319
- handler: composedHandler,
320
- contractRegister: t.contractRegister,
321
- 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
322
219
  });
323
220
  }
324
- setEventOptions(contractName, eventName, eventOptions, logger);
325
- let t$1 = get(contractName, eventName);
326
- set(contractName, eventName, {
327
- handler: handler,
328
- contractRegister: t$1.contractRegister,
329
- eventOptions: t$1.eventOptions
330
- });
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);
331
222
  });
332
223
  }
333
224
 
334
225
  function setContractRegister(contractName, eventName, contractRegister, eventOptions, loggerOpt) {
335
226
  let logger = loggerOpt !== undefined ? loggerOpt : Logging.getLogger();
336
- withRegistration(_registration => {
227
+ withRegistration(registration => {
337
228
  let t = get(contractName, eventName);
229
+ let incomingEventOptions = Stdlib_Option.map(eventOptions, v => v);
338
230
  let prevContractRegister = t.contractRegister;
339
231
  if (prevContractRegister !== undefined) {
340
- let incomingEventOptions = Stdlib_Option.map(eventOptions, v => v);
341
- if (!eventOptionsMatch(t.eventOptions, incomingEventOptions)) {
342
- 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);
343
244
  }
344
- let composedContractRegister = async args => {
345
- await prevContractRegister(args);
346
- return await contractRegister(args);
347
- };
348
- return set(contractName, eventName, {
349
- handler: t.handler,
350
- contractRegister: composedContractRegister,
351
- 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
352
252
  });
353
253
  }
354
- setEventOptions(contractName, eventName, eventOptions, logger);
355
- let t$1 = get(contractName, eventName);
356
- set(contractName, eventName, {
357
- handler: t$1.handler,
358
- contractRegister: contractRegister,
359
- 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
360
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
+ }
361
347
  });
362
348
  }
363
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
+ return;
393
+ }
394
+ let newrecord = {...registration$1};
395
+ onEventRegistrations.push((newrecord.index = onEventRegistrations.length, newrecord));
396
+ });
397
+ });
398
+ registrationsByChainId[key] = {
399
+ onEventRegistrations: onEventRegistrations,
400
+ onBlockRegistrations: pending !== undefined ? pending.onBlockRegistrations : []
401
+ };
402
+ });
403
+ let notRegisteredEntries = Object.entries(notRegisteredEventsByContract);
404
+ if (Utils.$$Array.notEmpty(notRegisteredEntries)) {
405
+ let groups = notRegisteredEntries.map(param => param[0] + ` (` + Array.from(param[1]).join(", ") + `)`).join(", ");
406
+ Logging.childInfo(Logging.getLogger(), `Events without a handler, skipped for indexing: ` + groups);
407
+ }
408
+ return registrationsByChainId;
409
+ }
410
+
411
+ function isPendingRegistration() {
412
+ let r = EnvioGlobal.value.activeRegistration;
413
+ if (r !== undefined) {
414
+ return !r.finished;
415
+ } else {
416
+ return false;
417
+ }
418
+ }
419
+
420
+ function throwIfFinishedRegistration(methodName) {
421
+ let match = EnvioGlobal.value.activeRegistration;
422
+ if (match === undefined) {
423
+ return;
424
+ }
425
+ let match$1 = match.finished;
426
+ if (match$1) {
427
+ 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.`);
428
+ }
429
+ }
430
+
364
431
  export {
365
432
  startRegistration,
366
433
  isPendingRegistration,
@@ -371,9 +438,10 @@ export {
371
438
  setContractRegister,
372
439
  getHandler,
373
440
  getContractRegister,
374
- getOnEventWhere,
375
441
  isWildcard,
376
442
  hasRegistration,
443
+ blockRangeSchema,
444
+ defaultBlockRange,
377
445
  registerOnBlock,
378
446
  }
379
- /* existing Not a pure module */
447
+ /* blockRangeSchema Not a pure module */
@@ -4,7 +4,7 @@ type chainRegistrations = {
4
4
  }
5
5
  type registrationsByChainId = dict<chainRegistrations>
6
6
 
7
- let startRegistration: (~ecosystem: Ecosystem.t) => unit
7
+ let startRegistration: (~config: Config.t) => unit
8
8
  let isPendingRegistration: unit => bool
9
9
  let finishRegistration: (~config: Config.t) => registrationsByChainId
10
10
  let throwIfFinishedRegistration: (~methodName: string) => unit
@@ -35,15 +35,20 @@ let getContractRegister: (
35
35
  ~contractName: string,
36
36
  ~eventName: string,
37
37
  ) => option<Internal.contractRegister>
38
- let getOnEventWhere: (~contractName: string, ~eventName: string) => option<JSON.t>
39
38
  let isWildcard: (~contractName: string, ~eventName: string) => bool
40
39
  let hasRegistration: (~contractName: string, ~eventName: string) => bool
41
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
+
42
49
  let registerOnBlock: (
43
50
  ~name: string,
44
- ~chainId: int,
45
- ~interval: int,
46
- ~startBlock: option<int>,
47
- ~endBlock: option<int>,
51
+ ~where: unknown,
48
52
  ~handler: Internal.onBlockArgs => promise<unit>,
53
+ ~getChainsObject: Config.t => dict<unknown>,
49
54
  ) => unit