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.
- package/index.d.ts +19 -0
- package/licenses/CLA.md +35 -0
- package/licenses/EULA.md +67 -0
- package/licenses/LICENSE.md +45 -0
- package/licenses/README.md +35 -0
- package/package.json +9 -8
- package/src/Batch.res.mjs +1 -1
- package/src/BatchProcessing.res +0 -7
- package/src/BatchProcessing.res.mjs +1 -8
- package/src/ChainFetching.res +30 -18
- package/src/ChainFetching.res.mjs +23 -13
- package/src/ChainState.res +205 -59
- package/src/ChainState.res.mjs +130 -27
- package/src/ChainState.resi +16 -1
- package/src/Config.res +9 -5
- package/src/Config.res.mjs +2 -2
- package/src/Core.res +20 -0
- package/src/Core.res.mjs +12 -0
- package/src/CrossChainState.res +147 -39
- package/src/CrossChainState.res.mjs +42 -10
- package/src/EffectState.res +100 -0
- package/src/EffectState.res.mjs +74 -0
- package/src/EffectState.resi +32 -0
- package/src/Envio.res +25 -7
- package/src/Envio.res.mjs +15 -19
- package/src/EnvioGlobal.res +53 -0
- package/src/EnvioGlobal.res.mjs +31 -0
- package/src/EventConfigBuilder.res +30 -56
- package/src/EventConfigBuilder.res.mjs +24 -30
- package/src/EventProcessing.res +8 -5
- package/src/EventProcessing.res.mjs +2 -1
- package/src/FetchState.res +842 -474
- package/src/FetchState.res.mjs +545 -356
- package/src/HandlerLoader.res +1 -1
- package/src/HandlerLoader.res.mjs +1 -1
- package/src/HandlerRegister.res +478 -305
- package/src/HandlerRegister.res.mjs +277 -209
- package/src/HandlerRegister.resi +11 -6
- package/src/InMemoryStore.res +14 -26
- package/src/InMemoryStore.res.mjs +6 -19
- package/src/IndexerState.res +15 -39
- package/src/IndexerState.res.mjs +18 -29
- package/src/IndexerState.resi +2 -10
- package/src/Internal.res +121 -18
- package/src/Internal.res.mjs +96 -2
- package/src/LoadLayer.res +44 -24
- package/src/LoadLayer.res.mjs +43 -20
- package/src/LoadLayer.resi +1 -0
- package/src/LogSelection.res +92 -217
- package/src/LogSelection.res.mjs +95 -184
- package/src/Main.res +29 -143
- package/src/Main.res.mjs +25 -88
- package/src/Metrics.res +1 -1
- package/src/Metrics.res.mjs +1 -1
- package/src/Persistence.res +12 -3
- package/src/PgStorage.res +155 -82
- package/src/PgStorage.res.mjs +130 -77
- package/src/Prometheus.res +20 -10
- package/src/Prometheus.res.mjs +22 -10
- package/src/PruneStaleHistory.res +146 -35
- package/src/PruneStaleHistory.res.mjs +114 -20
- package/src/RawEvent.res +2 -2
- package/src/Rollback.res +32 -13
- package/src/Rollback.res.mjs +24 -11
- package/src/RollbackCommit.res +4 -1
- package/src/RollbackCommit.res.mjs +3 -2
- package/src/SimulateDeadInputTracker.res +1 -1
- package/src/SimulateItems.res +39 -7
- package/src/SimulateItems.res.mjs +28 -9
- package/src/TestIndexer.res +2 -2
- package/src/TestIndexer.res.mjs +2 -2
- package/src/TopicFilter.res +1 -25
- package/src/TopicFilter.res.mjs +0 -74
- package/src/UserContext.res +62 -23
- package/src/UserContext.res.mjs +26 -6
- package/src/Writing.res +60 -21
- package/src/Writing.res.mjs +27 -9
- package/src/bindings/NodeJs.res +5 -0
- package/src/bindings/Viem.res +0 -5
- package/src/sources/EventRouter.res +0 -21
- package/src/sources/EventRouter.res.mjs +0 -12
- package/src/sources/Evm.res +4 -1
- package/src/sources/Evm.res.mjs +1 -1
- package/src/sources/EvmChain.res +2 -27
- package/src/sources/EvmChain.res.mjs +2 -23
- package/src/sources/EvmRpcClient.res +58 -23
- package/src/sources/EvmRpcClient.res.mjs +11 -5
- package/src/sources/Fuel.res +3 -1
- package/src/sources/Fuel.res.mjs +1 -1
- package/src/sources/HyperSync.res +9 -38
- package/src/sources/HyperSync.res.mjs +16 -28
- package/src/sources/HyperSync.resi +2 -2
- package/src/sources/HyperSyncClient.res +88 -11
- package/src/sources/HyperSyncClient.res.mjs +39 -6
- package/src/sources/HyperSyncSource.res +18 -210
- package/src/sources/HyperSyncSource.res.mjs +9 -137
- package/src/sources/Rpc.res +0 -32
- package/src/sources/Rpc.res.mjs +1 -46
- package/src/sources/RpcSource.res +129 -533
- package/src/sources/RpcSource.res.mjs +161 -379
- package/src/sources/SimulateSource.res +37 -19
- package/src/sources/SimulateSource.res.mjs +27 -10
- package/src/sources/SourceManager.res +4 -14
- package/src/sources/SourceManager.res.mjs +3 -9
- package/src/sources/SourceManager.resi +0 -2
- package/src/sources/SvmHyperSyncSource.res +13 -3
- 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
|
|
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
|
|
61
|
-
|
|
62
|
-
let preRegistered = registry.preRegistered;
|
|
39
|
+
let preRegistered = EnvioGlobal.value.preRegistered;
|
|
63
40
|
|
|
64
41
|
function withRegistration(fn) {
|
|
65
|
-
let r = activeRegistration
|
|
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(
|
|
55
|
+
function startRegistration(config) {
|
|
79
56
|
let r = {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
onBlockByChainId: {}
|
|
83
|
-
},
|
|
57
|
+
config: config,
|
|
58
|
+
registrationsByChainId: {},
|
|
84
59
|
finished: false
|
|
85
60
|
};
|
|
86
|
-
activeRegistration
|
|
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
|
|
96
|
-
let
|
|
97
|
-
let
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
let
|
|
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,
|
|
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
|
|
114
|
-
let
|
|
115
|
-
|
|
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
|
|
259
|
-
|
|
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(
|
|
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
|
-
|
|
311
|
-
|
|
312
|
-
|
|
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
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
341
|
-
|
|
342
|
-
|
|
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
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
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
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
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
|
-
/*
|
|
447
|
+
/* blockRangeSchema Not a pure module */
|
package/src/HandlerRegister.resi
CHANGED
|
@@ -4,7 +4,7 @@ type chainRegistrations = {
|
|
|
4
4
|
}
|
|
5
5
|
type registrationsByChainId = dict<chainRegistrations>
|
|
6
6
|
|
|
7
|
-
let startRegistration: (~
|
|
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
|
-
~
|
|
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
|