envio 3.0.0-alpha.0 → 3.0.0-alpha.10

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 (136) hide show
  1. package/README.md +2 -2
  2. package/evm.schema.json +53 -57
  3. package/fuel.schema.json +35 -31
  4. package/index.d.ts +446 -1
  5. package/index.js +4 -0
  6. package/package.json +23 -11
  7. package/rescript.json +4 -1
  8. package/src/Batch.res.mjs +1 -1
  9. package/src/Benchmark.res +394 -0
  10. package/src/Benchmark.res.mjs +398 -0
  11. package/src/ChainFetcher.res +526 -0
  12. package/src/ChainFetcher.res.mjs +343 -0
  13. package/src/ChainManager.res +182 -0
  14. package/src/ChainManager.res.mjs +150 -0
  15. package/src/Config.res +367 -27
  16. package/src/Config.res.mjs +338 -28
  17. package/src/{Indexer.res → Ctx.res} +1 -1
  18. package/src/Ecosystem.res +25 -0
  19. package/src/Ecosystem.res.mjs +29 -0
  20. package/src/Env.res +252 -0
  21. package/src/Env.res.mjs +271 -0
  22. package/src/Envio.gen.ts +9 -1
  23. package/src/Envio.res +12 -9
  24. package/src/EventProcessing.res +476 -0
  25. package/src/EventProcessing.res.mjs +341 -0
  26. package/src/EventRegister.res +4 -15
  27. package/src/EventRegister.res.mjs +3 -9
  28. package/src/EventRegister.resi +2 -8
  29. package/src/FetchState.res +54 -29
  30. package/src/FetchState.res.mjs +62 -35
  31. package/src/GlobalState.res +1163 -0
  32. package/src/GlobalState.res.mjs +1196 -0
  33. package/src/GlobalStateManager.res +68 -0
  34. package/src/GlobalStateManager.res.mjs +75 -0
  35. package/src/GlobalStateManager.resi +7 -0
  36. package/src/HandlerLoader.res +89 -0
  37. package/src/HandlerLoader.res.mjs +79 -0
  38. package/src/Internal.gen.ts +3 -14
  39. package/src/Internal.res +45 -13
  40. package/src/LoadLayer.res +444 -0
  41. package/src/LoadLayer.res.mjs +296 -0
  42. package/src/LoadLayer.resi +32 -0
  43. package/src/LogSelection.res +33 -27
  44. package/src/LogSelection.res.mjs +6 -0
  45. package/src/Logging.res +11 -4
  46. package/src/Logging.res.mjs +14 -6
  47. package/src/Main.res +351 -0
  48. package/src/Main.res.mjs +312 -0
  49. package/src/Persistence.res +1 -2
  50. package/src/PgStorage.gen.ts +10 -0
  51. package/src/PgStorage.res +28 -34
  52. package/src/PgStorage.res.d.mts +5 -0
  53. package/src/PgStorage.res.mjs +27 -27
  54. package/src/Prometheus.res +8 -8
  55. package/src/Prometheus.res.mjs +10 -10
  56. package/src/ReorgDetection.res +6 -10
  57. package/src/ReorgDetection.res.mjs +6 -6
  58. package/src/TestIndexer.res +536 -0
  59. package/src/TestIndexer.res.mjs +412 -0
  60. package/src/TestIndexerProxyStorage.res +210 -0
  61. package/src/TestIndexerProxyStorage.res.mjs +157 -0
  62. package/src/Types.ts +1 -1
  63. package/src/UserContext.res +355 -0
  64. package/src/UserContext.res.mjs +236 -0
  65. package/src/Utils.res +28 -0
  66. package/src/Utils.res.mjs +18 -0
  67. package/src/bindings/ClickHouse.res +31 -1
  68. package/src/bindings/ClickHouse.res.mjs +27 -1
  69. package/src/bindings/DateFns.res +71 -0
  70. package/src/bindings/DateFns.res.mjs +22 -0
  71. package/src/bindings/Ethers.res +27 -67
  72. package/src/bindings/Ethers.res.mjs +18 -70
  73. package/src/bindings/EventSource.res +13 -0
  74. package/src/bindings/EventSource.res.mjs +2 -0
  75. package/src/bindings/NodeJs.res +44 -3
  76. package/src/bindings/NodeJs.res.mjs +11 -3
  77. package/src/bindings/Pino.res +21 -7
  78. package/src/bindings/Pino.res.mjs +11 -5
  79. package/src/bindings/Postgres.gen.ts +8 -0
  80. package/src/bindings/Postgres.res +3 -0
  81. package/src/bindings/Postgres.res.d.mts +5 -0
  82. package/src/bindings/RescriptMocha.res +123 -0
  83. package/src/bindings/RescriptMocha.res.mjs +18 -0
  84. package/src/bindings/Vitest.res +134 -0
  85. package/src/bindings/Vitest.res.mjs +9 -0
  86. package/src/bindings/Yargs.res +8 -0
  87. package/src/bindings/Yargs.res.mjs +2 -0
  88. package/src/db/InternalTable.res +2 -0
  89. package/src/db/InternalTable.res.mjs +1 -1
  90. package/src/sources/Evm.res +87 -0
  91. package/src/sources/Evm.res.mjs +105 -0
  92. package/src/sources/EvmChain.res +90 -0
  93. package/src/sources/EvmChain.res.mjs +57 -0
  94. package/src/sources/Fuel.res +19 -34
  95. package/src/sources/Fuel.res.mjs +34 -16
  96. package/src/sources/FuelSDK.res +38 -0
  97. package/src/sources/FuelSDK.res.mjs +29 -0
  98. package/src/sources/HyperFuel.res +2 -2
  99. package/src/sources/HyperFuel.resi +1 -1
  100. package/src/sources/HyperFuelClient.res +2 -2
  101. package/src/sources/HyperFuelSource.res +8 -8
  102. package/src/sources/HyperFuelSource.res.mjs +5 -5
  103. package/src/sources/HyperSyncHeightStream.res +97 -0
  104. package/src/sources/HyperSyncHeightStream.res.mjs +94 -0
  105. package/src/sources/HyperSyncSource.res +64 -172
  106. package/src/sources/HyperSyncSource.res.mjs +73 -155
  107. package/src/sources/Rpc.res +43 -0
  108. package/src/sources/Rpc.res.mjs +31 -0
  109. package/src/sources/RpcSource.res +32 -130
  110. package/src/sources/RpcSource.res.mjs +47 -121
  111. package/src/sources/Source.res +3 -2
  112. package/src/sources/SourceManager.res +183 -108
  113. package/src/sources/SourceManager.res.mjs +162 -99
  114. package/src/sources/SourceManager.resi +4 -5
  115. package/src/sources/Svm.res +59 -0
  116. package/src/sources/Svm.res.mjs +79 -0
  117. package/src/tui/Tui.res +266 -0
  118. package/src/tui/Tui.res.mjs +342 -0
  119. package/src/tui/bindings/Ink.res +376 -0
  120. package/src/tui/bindings/Ink.res.mjs +75 -0
  121. package/src/tui/bindings/Style.res +123 -0
  122. package/src/tui/bindings/Style.res.mjs +2 -0
  123. package/src/tui/components/BufferedProgressBar.res +40 -0
  124. package/src/tui/components/BufferedProgressBar.res.mjs +57 -0
  125. package/src/tui/components/CustomHooks.res +122 -0
  126. package/src/tui/components/CustomHooks.res.mjs +179 -0
  127. package/src/tui/components/Messages.res +41 -0
  128. package/src/tui/components/Messages.res.mjs +75 -0
  129. package/src/tui/components/SyncETA.res +193 -0
  130. package/src/tui/components/SyncETA.res.mjs +269 -0
  131. package/src/tui/components/TuiData.res +46 -0
  132. package/src/tui/components/TuiData.res.mjs +29 -0
  133. package/src/Platform.res +0 -140
  134. package/src/Platform.res.mjs +0 -170
  135. package/src/bindings/Ethers.gen.ts +0 -14
  136. /package/src/{Indexer.res.mjs → Ctx.res.mjs} +0 -0
@@ -0,0 +1,412 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Env from "./Env.res.mjs";
4
+ import * as Main from "./Main.res.mjs";
5
+ import * as Table from "./db/Table.res.mjs";
6
+ import * as Js_exn from "rescript/lib/es6/js_exn.js";
7
+ import * as Js_dict from "rescript/lib/es6/js_dict.js";
8
+ import * as Js_json from "rescript/lib/es6/js_json.js";
9
+ import * as Logging from "./Logging.res.mjs";
10
+ import * as Process from "process";
11
+ import * as Belt_Int from "rescript/lib/es6/belt_Int.js";
12
+ import * as ChainMap from "./ChainMap.res.mjs";
13
+ import * as Belt_Array from "rescript/lib/es6/belt_Array.js";
14
+ import * as Belt_Option from "rescript/lib/es6/belt_Option.js";
15
+ import * as Caml_option from "rescript/lib/es6/caml_option.js";
16
+ import * as TableIndices from "./TableIndices.res.mjs";
17
+ import * as InternalTable from "./db/InternalTable.res.mjs";
18
+ import * as Worker_threads from "worker_threads";
19
+ import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
20
+ import * as Caml_js_exceptions from "rescript/lib/es6/caml_js_exceptions.js";
21
+ import * as TestIndexerProxyStorage from "./TestIndexerProxyStorage.res.mjs";
22
+
23
+ function toIndexingContract(dc) {
24
+ return {
25
+ address: dc.contract_address,
26
+ contractName: dc.contract_name,
27
+ startBlock: dc.registering_event_block_number,
28
+ registrationBlock: dc.registering_event_block_number
29
+ };
30
+ }
31
+
32
+ function handleLoadByIds(state, tableName, ids) {
33
+ var entityDict = Belt_Option.getWithDefault(Js_dict.get(state.entities, tableName), {});
34
+ var entityConfig = state.entityConfigs[tableName];
35
+ var results = [];
36
+ Belt_Array.forEach(ids, (function (id) {
37
+ var entity = Js_dict.get(entityDict, id);
38
+ if (entity === undefined) {
39
+ return ;
40
+ }
41
+ var jsonEntity = S$RescriptSchema.reverseConvertToJsonOrThrow(entity, entityConfig.schema);
42
+ results.push(jsonEntity);
43
+ }));
44
+ return results;
45
+ }
46
+
47
+ function handleLoadByField(state, tableName, fieldName, fieldValue, operator) {
48
+ var entityDict = Belt_Option.getWithDefault(Js_dict.get(state.entities, tableName), {});
49
+ var entityConfig = state.entityConfigs[tableName];
50
+ var results = [];
51
+ var match = Table.getFieldByName(entityConfig.table, fieldName);
52
+ var fieldSchema;
53
+ var exit = 0;
54
+ if (match !== undefined && match.TAG === "Field") {
55
+ fieldSchema = match._0.fieldSchema;
56
+ } else {
57
+ exit = 1;
58
+ }
59
+ if (exit === 1) {
60
+ fieldSchema = Js_exn.raiseError("Field " + fieldName + " not found in entity " + tableName);
61
+ }
62
+ var parsedFieldValue = S$RescriptSchema.convertOrThrow(fieldValue, fieldSchema);
63
+ Belt_Array.forEach(Js_dict.values(entityDict), (function (entity) {
64
+ var entityFieldValue = Js_dict.get(entity, fieldName);
65
+ if (entityFieldValue === undefined) {
66
+ return ;
67
+ }
68
+ var entityFieldValue$1 = Caml_option.valFromOption(entityFieldValue);
69
+ var matches = operator === "=" ? TableIndices.FieldValue.eq(entityFieldValue$1, parsedFieldValue) : (
70
+ operator === ">" ? TableIndices.FieldValue.gt(entityFieldValue$1, parsedFieldValue) : TableIndices.FieldValue.lt(entityFieldValue$1, parsedFieldValue)
71
+ );
72
+ if (!matches) {
73
+ return ;
74
+ }
75
+ var jsonEntity = S$RescriptSchema.reverseConvertToJsonOrThrow(entity, entityConfig.schema);
76
+ results.push(jsonEntity);
77
+ }));
78
+ return results;
79
+ }
80
+
81
+ function handleWriteBatch(state, updatedEntities, checkpointIds, checkpointChainIds, checkpointBlockNumbers, checkpointBlockHashes, checkpointEventsProcessed) {
82
+ var changesByCheckpoint = {};
83
+ Belt_Array.forEach(updatedEntities, (function (param) {
84
+ var entityName = param.entityName;
85
+ var dict = Js_dict.get(state.entities, entityName);
86
+ var entityDict;
87
+ if (dict !== undefined) {
88
+ entityDict = dict;
89
+ } else {
90
+ var dict$1 = {};
91
+ state.entities[entityName] = dict$1;
92
+ entityDict = dict$1;
93
+ }
94
+ var entityConfig = state.entityConfigs[entityName];
95
+ Belt_Array.forEach(param.updates, (function (update) {
96
+ var processChange = function (change) {
97
+ if (change.type === "SET") {
98
+ var parsedEntity = S$RescriptSchema.parseOrThrow(change.entity, entityConfig.schema);
99
+ entityDict[change.entityId] = parsedEntity;
100
+ var checkpointKey = String(change.checkpointId);
101
+ var changes = Js_dict.get(changesByCheckpoint, checkpointKey);
102
+ var entityChanges;
103
+ if (changes !== undefined) {
104
+ entityChanges = changes;
105
+ } else {
106
+ var changes$1 = {};
107
+ changesByCheckpoint[checkpointKey] = changes$1;
108
+ entityChanges = changes$1;
109
+ }
110
+ var change$1 = Js_dict.get(entityChanges, entityName);
111
+ var entityChange;
112
+ if (change$1 !== undefined) {
113
+ entityChange = change$1;
114
+ } else {
115
+ var change_sets = [];
116
+ var change_deleted = [];
117
+ var change$2 = {
118
+ sets: change_sets,
119
+ deleted: change_deleted
120
+ };
121
+ entityChanges[entityName] = change$2;
122
+ entityChange = change$2;
123
+ }
124
+ entityChange.sets.push(parsedEntity);
125
+ return ;
126
+ }
127
+ var entityId = change.entityId;
128
+ Js_dict.unsafeDeleteKey(entityDict, entityId);
129
+ var checkpointKey$1 = String(change.checkpointId);
130
+ var changes$2 = Js_dict.get(changesByCheckpoint, checkpointKey$1);
131
+ var entityChanges$1;
132
+ if (changes$2 !== undefined) {
133
+ entityChanges$1 = changes$2;
134
+ } else {
135
+ var changes$3 = {};
136
+ changesByCheckpoint[checkpointKey$1] = changes$3;
137
+ entityChanges$1 = changes$3;
138
+ }
139
+ var change$3 = Js_dict.get(entityChanges$1, entityName);
140
+ var entityChange$1;
141
+ if (change$3 !== undefined) {
142
+ entityChange$1 = change$3;
143
+ } else {
144
+ var change_sets$1 = [];
145
+ var change_deleted$1 = [];
146
+ var change$4 = {
147
+ sets: change_sets$1,
148
+ deleted: change_deleted$1
149
+ };
150
+ entityChanges$1[entityName] = change$4;
151
+ entityChange$1 = change$4;
152
+ }
153
+ entityChange$1.deleted.push(entityId);
154
+ };
155
+ Belt_Array.forEach(update.history, processChange);
156
+ if (update.history.length === 0) {
157
+ return processChange(update.latestChange);
158
+ }
159
+
160
+ }));
161
+ }));
162
+ for(var i = 0 ,i_finish = checkpointIds.length; i < i_finish; ++i){
163
+ var checkpointId = checkpointIds[i];
164
+ var change = {};
165
+ change["block"] = checkpointBlockNumbers[i];
166
+ var hash = checkpointBlockHashes[i];
167
+ if (hash !== null) {
168
+ change["blockHash"] = hash;
169
+ }
170
+ change["chainId"] = checkpointChainIds[i];
171
+ change["eventsProcessed"] = checkpointEventsProcessed[i];
172
+ var checkpointKey = String(checkpointId);
173
+ var entityChanges = Js_dict.get(changesByCheckpoint, checkpointKey);
174
+ if (entityChanges !== undefined) {
175
+ Belt_Array.forEach(Js_dict.entries(entityChanges), (function(change){
176
+ return function (param) {
177
+ var match = param[1];
178
+ var deleted = match.deleted;
179
+ var sets = match.sets;
180
+ var entityName = param[0];
181
+ if (entityName === InternalTable.DynamicContractRegistry.name) {
182
+ var entityObj = {};
183
+ if (sets.length !== 0) {
184
+ var simplifiedSets = Belt_Array.map(sets, (function (entity) {
185
+ return {
186
+ address: entity.contract_address,
187
+ contract: entity.contract_name
188
+ };
189
+ }));
190
+ entityObj["sets"] = simplifiedSets;
191
+ }
192
+ change["addresses"] = entityObj;
193
+ return ;
194
+ }
195
+ var entityObj$1 = {};
196
+ if (sets.length !== 0) {
197
+ entityObj$1["sets"] = sets;
198
+ }
199
+ if (deleted.length !== 0) {
200
+ entityObj$1["deleted"] = deleted;
201
+ }
202
+ change[entityName] = entityObj$1;
203
+ }
204
+ }(change)));
205
+ }
206
+ state.processChanges.push(change);
207
+ }
208
+ }
209
+
210
+ function makeInitialState(config, processConfigChains, dynamicContractsByChain) {
211
+ var chainKeys = Object.keys(processConfigChains);
212
+ var chains = Belt_Array.map(chainKeys, (function (chainIdStr) {
213
+ var chainId = Belt_Option.getWithDefault(Belt_Int.fromString(chainIdStr), 0);
214
+ var chain = ChainMap.Chain.makeUnsafe(chainId);
215
+ if (!ChainMap.has(config.chainMap, chain)) {
216
+ Js_exn.raiseError("Chain " + chainIdStr + " is not configured in config.yaml");
217
+ }
218
+ var processChainConfig = processConfigChains[chainIdStr];
219
+ var dynamicContracts = Belt_Option.getWithDefault(Js_dict.get(dynamicContractsByChain, chainIdStr), []);
220
+ return {
221
+ id: chainId,
222
+ startBlock: processChainConfig.startBlock,
223
+ endBlock: processChainConfig.endBlock,
224
+ maxReorgDepth: 0,
225
+ progressBlockNumber: -1,
226
+ numEventsProcessed: 0,
227
+ firstEventBlockNumber: undefined,
228
+ timestampCaughtUpToHeadOrEndblock: undefined,
229
+ dynamicContracts: dynamicContracts,
230
+ sourceBlockNumber: processChainConfig.endBlock
231
+ };
232
+ }));
233
+ return {
234
+ cleanRun: true,
235
+ cache: {},
236
+ chains: chains,
237
+ checkpointId: InternalTable.Checkpoints.initialCheckpointId,
238
+ reorgCheckpoints: []
239
+ };
240
+ }
241
+
242
+ function validateBlockRange(chainId, configChain, processChainConfig, progressBlock) {
243
+ if (processChainConfig.startBlock < configChain.startBlock) {
244
+ Js_exn.raiseError("Invalid block range for chain " + chainId + ": startBlock (" + String(processChainConfig.startBlock) + ") is less than config.startBlock (" + String(configChain.startBlock) + "). " + ("Either use startBlock >= " + String(configChain.startBlock) + " or create a new test indexer with createTestIndexer()."));
245
+ }
246
+ var configEndBlock = configChain.endBlock;
247
+ if (configEndBlock !== undefined && processChainConfig.endBlock > configEndBlock) {
248
+ Js_exn.raiseError("Invalid block range for chain " + chainId + ": endBlock (" + String(processChainConfig.endBlock) + ") exceeds config.endBlock (" + String(configEndBlock) + "). " + ("Either use endBlock <= " + String(configEndBlock) + " or create a new test indexer with createTestIndexer()."));
249
+ }
250
+ if (progressBlock !== undefined && processChainConfig.startBlock <= progressBlock) {
251
+ return Js_exn.raiseError("Invalid block range for chain " + chainId + ": startBlock (" + String(processChainConfig.startBlock) + ") must be greater than previously processed endBlock (" + String(progressBlock) + "). " + ("Either use startBlock > " + String(progressBlock) + " or create a new test indexer with createTestIndexer()."));
252
+ }
253
+
254
+ }
255
+
256
+ function makeCreateTestIndexer(config, workerPath, allEntities) {
257
+ return function () {
258
+ var entities = {};
259
+ var entityConfigs = {};
260
+ Belt_Array.forEach(allEntities, (function (entityConfig) {
261
+ entities[entityConfig.name] = {};
262
+ entityConfigs[entityConfig.name] = entityConfig;
263
+ }));
264
+ var state = {
265
+ processInProgress: false,
266
+ progressBlockByChain: {},
267
+ entities: entities,
268
+ entityConfigs: entityConfigs,
269
+ processChanges: []
270
+ };
271
+ return {
272
+ process: (function (processConfig) {
273
+ if (state.processInProgress) {
274
+ Js_exn.raiseError("createTestIndexer process is already running. Only one process call is allowed at a time");
275
+ }
276
+ var chains = processConfig.chains;
277
+ var chainKeys = Object.keys(chains);
278
+ var n = chainKeys.length;
279
+ if (n !== 0) {
280
+ if (n !== 1) {
281
+ Js_exn.raiseError("createTestIndexer does not support processing multiple chains at once. Found " + String(n) + " chains defined");
282
+ }
283
+
284
+ } else {
285
+ Js_exn.raiseError("createTestIndexer requires exactly one chain to be defined");
286
+ }
287
+ Belt_Array.forEach(chainKeys, (function (chainIdStr) {
288
+ var chainId = Belt_Option.getWithDefault(Belt_Int.fromString(chainIdStr), 0);
289
+ var chain = ChainMap.Chain.makeUnsafe(chainId);
290
+ var configChain = ChainMap.get(config.chainMap, chain);
291
+ var processChainConfig = chains[chainIdStr];
292
+ var progressBlock = Js_dict.get(state.progressBlockByChain, chainIdStr);
293
+ validateBlockRange(chainIdStr, configChain, processChainConfig, progressBlock);
294
+ }));
295
+ state.processChanges = [];
296
+ var dynamicContractsByChain = {};
297
+ var dcDict = Js_dict.get(state.entities, InternalTable.DynamicContractRegistry.name);
298
+ if (dcDict !== undefined) {
299
+ Belt_Array.forEach(Js_dict.values(dcDict), (function (entity) {
300
+ var chainIdStr = String(entity.chain_id);
301
+ var arr = Js_dict.get(dynamicContractsByChain, chainIdStr);
302
+ var contracts;
303
+ if (arr !== undefined) {
304
+ contracts = arr;
305
+ } else {
306
+ var arr$1 = [];
307
+ dynamicContractsByChain[chainIdStr] = arr$1;
308
+ contracts = arr$1;
309
+ }
310
+ contracts.push(toIndexingContract(entity));
311
+ }));
312
+ }
313
+ var initialState = makeInitialState(config, chains, dynamicContractsByChain);
314
+ return new Promise((function (resolve, reject) {
315
+ var workerDataObj = {
316
+ processConfig: JSON.parse(Js_json.serializeExn(processConfig)),
317
+ initialState: initialState
318
+ };
319
+ var workerData = JSON.parse(Js_json.serializeExn(workerDataObj));
320
+ var worker;
321
+ try {
322
+ worker = new Worker_threads.Worker(workerPath, {
323
+ workerData: workerData
324
+ });
325
+ }
326
+ catch (raw_exn){
327
+ var exn = Caml_js_exceptions.internalToOCamlException(raw_exn);
328
+ reject(exn);
329
+ throw exn;
330
+ }
331
+ state.processInProgress = true;
332
+ worker.on("message", (function (msg) {
333
+ var respond = function (data) {
334
+ worker.postMessage({
335
+ id: msg.id,
336
+ payload: {
337
+ type: "response",
338
+ data: data
339
+ }
340
+ });
341
+ };
342
+ var match = msg.payload;
343
+ switch (match.type) {
344
+ case "loadByIds" :
345
+ return respond(handleLoadByIds(state, match.tableName, match.ids));
346
+ case "loadByField" :
347
+ return respond(handleLoadByField(state, match.tableName, match.fieldName, match.fieldValue, match.operator));
348
+ case "writeBatch" :
349
+ handleWriteBatch(state, match.updatedEntities, match.checkpointIds, match.checkpointChainIds, match.checkpointBlockNumbers, match.checkpointBlockHashes, match.checkpointEventsProcessed);
350
+ return respond(null);
351
+
352
+ }
353
+ }));
354
+ worker.on("error", (function (err) {
355
+ state.processInProgress = false;
356
+ worker.terminate();
357
+ reject(err);
358
+ }));
359
+ worker.on("exit", (function (code) {
360
+ state.processInProgress = false;
361
+ if (code !== 0) {
362
+ return reject(new Error("Worker exited with code " + String(code)));
363
+ } else {
364
+ Belt_Array.forEach(chainKeys, (function (chainIdStr) {
365
+ var processChainConfig = chains[chainIdStr];
366
+ state.progressBlockByChain[chainIdStr] = processChainConfig.endBlock;
367
+ }));
368
+ return resolve({
369
+ changes: state.processChanges
370
+ });
371
+ }
372
+ }));
373
+ }));
374
+ })
375
+ };
376
+ };
377
+ }
378
+
379
+ function initTestWorker(makeGeneratedConfig, makePersistence) {
380
+ if (Worker_threads.isMainThread) {
381
+ Js_exn.raiseError("initTestWorker must be called from a worker thread");
382
+ }
383
+ var port = Worker_threads.parentPort;
384
+ var parentPort = (port == null) ? Js_exn.raiseError("initTestWorker: No parent port available") : port;
385
+ var workerData = Worker_threads.workerData;
386
+ if (workerData == null) {
387
+ Logging.error("TestIndexerWorker: No worker data provided");
388
+ Process.exit(1);
389
+ return ;
390
+ }
391
+ var proxy = TestIndexerProxyStorage.make(parentPort, workerData.initialState);
392
+ var storage = TestIndexerProxyStorage.makeStorage(proxy);
393
+ var persistence = makePersistence(storage);
394
+ if (Env.userLogLevel !== undefined) {
395
+
396
+ } else {
397
+ Logging.setLogLevel("silent");
398
+ }
399
+ Main.start(makeGeneratedConfig, persistence, true);
400
+ }
401
+
402
+ export {
403
+ toIndexingContract ,
404
+ handleLoadByIds ,
405
+ handleLoadByField ,
406
+ handleWriteBatch ,
407
+ makeInitialState ,
408
+ validateBlockRange ,
409
+ makeCreateTestIndexer ,
410
+ initTestWorker ,
411
+ }
412
+ /* Env Not a pure module */
@@ -0,0 +1,210 @@
1
+ open Belt
2
+
3
+ // Message types for communication between worker and main thread
4
+ type requestId = int
5
+
6
+ // Serializable change with entity as JSON (for worker thread messaging)
7
+ @tag("type")
8
+ type serializableChange =
9
+ | @as("SET") Set({entityId: string, entity: Js.Json.t, checkpointId: float})
10
+ | @as("DELETE") Delete({entityId: string, checkpointId: float})
11
+
12
+ type serializableEntityUpdate = {
13
+ latestChange: serializableChange,
14
+ history: array<serializableChange>,
15
+ containsRollbackDiffChange: bool,
16
+ }
17
+
18
+ type serializableUpdatedEntity = {
19
+ entityName: string,
20
+ updates: array<serializableEntityUpdate>,
21
+ }
22
+
23
+ // Worker -> Main thread payloads
24
+ @tag("type")
25
+ type workerPayload =
26
+ | @as("loadByIds") LoadByIds({tableName: string, ids: array<string>})
27
+ | @as("loadByField")
28
+ LoadByField({
29
+ tableName: string,
30
+ fieldName: string,
31
+ fieldValue: Js.Json.t,
32
+ operator: Persistence.operator,
33
+ })
34
+ | @as("writeBatch")
35
+ WriteBatch({
36
+ updatedEntities: array<serializableUpdatedEntity>,
37
+ checkpointIds: array<float>,
38
+ checkpointChainIds: array<int>,
39
+ checkpointBlockNumbers: array<int>,
40
+ checkpointBlockHashes: array<Js.Null.t<string>>,
41
+ checkpointEventsProcessed: array<int>,
42
+ })
43
+
44
+ // Main thread -> Worker payloads
45
+ @tag("type")
46
+ type mainPayload =
47
+ | @as("response") Response({data: Js.Json.t})
48
+ | @as("error") Error({message: string})
49
+
50
+ // Message wrapper with id
51
+ type message<'payload> = {id: requestId, payload: 'payload}
52
+ type workerMessage = message<workerPayload>
53
+ type mainMessage = message<mainPayload>
54
+
55
+ // Pending request tracker
56
+ type pendingRequest = {
57
+ resolve: Js.Json.t => unit,
58
+ reject: exn => unit,
59
+ }
60
+
61
+ type t = {
62
+ parentPort: NodeJs.WorkerThreads.messagePort,
63
+ initialState: Persistence.initialState,
64
+ pendingRequests: dict<pendingRequest>,
65
+ mutable requestCounter: int,
66
+ }
67
+
68
+ let make = (~parentPort, ~initialState): t => {
69
+ let proxy = {
70
+ parentPort,
71
+ initialState,
72
+ pendingRequests: Js.Dict.empty(),
73
+ requestCounter: 0,
74
+ }
75
+
76
+ // Set up message listener for responses from main thread
77
+ parentPort->NodeJs.WorkerThreads.onPortMessage((msg: mainMessage) => {
78
+ let idStr = msg.id->Int.toString
79
+ let {resolve, reject} = switch proxy.pendingRequests->Utils.Dict.dangerouslyGetNonOption(
80
+ idStr,
81
+ ) {
82
+ | Some(pending) => pending
83
+ | None => Js.Exn.raiseError(`TestIndexer: No pending request found for id ${idStr}`)
84
+ }
85
+ Js.Dict.unsafeDeleteKey(proxy.pendingRequests->Obj.magic, idStr)
86
+
87
+ switch msg.payload {
88
+ | Response({data}) => resolve(data)
89
+ | Error({message}) => reject(Utils.Error.make(message))
90
+ }
91
+ })
92
+
93
+ proxy
94
+ }
95
+
96
+ let nextRequestId = (proxy: t): requestId => {
97
+ proxy.requestCounter = proxy.requestCounter + 1
98
+ proxy.requestCounter
99
+ }
100
+
101
+ let sendRequest = (proxy: t, ~payload: workerPayload): promise<Js.Json.t> => {
102
+ Promise.make((resolve, reject) => {
103
+ let id = proxy->nextRequestId
104
+ proxy.pendingRequests->Js.Dict.set(id->Int.toString, {resolve, reject})
105
+ proxy.parentPort->NodeJs.WorkerThreads.postMessage({id, payload})
106
+ })
107
+ }
108
+
109
+ let makeStorage = (proxy: t): Persistence.storage => {
110
+ isInitialized: async () => true,
111
+ initialize: async (~chainConfigs as _=?, ~entities as _=?, ~enums as _=?) => {
112
+ Js.Exn.raiseError(
113
+ "TestIndexer: initialize should not be called. Use resumeInitialState instead.",
114
+ )
115
+ },
116
+ resumeInitialState: async () => proxy.initialState,
117
+ loadByIdsOrThrow: async (~ids, ~table: Table.table, ~rowsSchema) => {
118
+ let response = await proxy->sendRequest(~payload=LoadByIds({tableName: table.tableName, ids}))
119
+ response->S.parseOrThrow(rowsSchema)
120
+ },
121
+ loadByFieldOrThrow: async (
122
+ ~fieldName,
123
+ ~fieldSchema,
124
+ ~fieldValue,
125
+ ~operator,
126
+ ~table: Table.table,
127
+ ~rowsSchema,
128
+ ) => {
129
+ let response = await proxy->sendRequest(
130
+ ~payload=LoadByField({
131
+ tableName: table.tableName,
132
+ fieldName,
133
+ fieldValue: fieldValue->S.reverseConvertToJsonOrThrow(fieldSchema),
134
+ operator,
135
+ }),
136
+ )
137
+ response->S.parseOrThrow(rowsSchema)
138
+ },
139
+ setOrThrow: async (~items as _, ~table as _, ~itemSchema as _) => {
140
+ // Not used anywhere, no-op
141
+ ()
142
+ },
143
+ writeBatch: async (
144
+ ~batch,
145
+ ~rawEvents as _,
146
+ ~rollbackTargetCheckpointId as _,
147
+ ~isInReorgThreshold as _,
148
+ ~config as _,
149
+ ~allEntities as _,
150
+ ~updatedEffectsCache as _,
151
+ ~updatedEntities,
152
+ ) => {
153
+ // Encode entities to JSON for serialization across worker boundary
154
+ let serializableEntities = updatedEntities->Array.map((
155
+ {entityConfig, updates}: Persistence.updatedEntity,
156
+ ) => {
157
+ let encodeChange = (change: Change.t<Internal.entity>): serializableChange => {
158
+ switch change {
159
+ | Set({entityId, entity, checkpointId}) =>
160
+ Set({
161
+ entityId,
162
+ entity: entity->S.reverseConvertToJsonOrThrow(entityConfig.schema),
163
+ checkpointId,
164
+ })
165
+ | Delete({entityId, checkpointId}) => Delete({entityId, checkpointId})
166
+ }
167
+ }
168
+ {
169
+ entityName: entityConfig.name,
170
+ updates: updates->Array.map(update => {
171
+ latestChange: encodeChange(update.latestChange),
172
+ history: update.history->Array.map(encodeChange),
173
+ containsRollbackDiffChange: update.containsRollbackDiffChange,
174
+ }),
175
+ }
176
+ })
177
+ let _ = await proxy->sendRequest(
178
+ ~payload=WriteBatch({
179
+ updatedEntities: serializableEntities,
180
+ checkpointIds: batch.checkpointIds,
181
+ checkpointChainIds: batch.checkpointChainIds,
182
+ checkpointBlockNumbers: batch.checkpointBlockNumbers,
183
+ checkpointBlockHashes: batch.checkpointBlockHashes,
184
+ checkpointEventsProcessed: batch.checkpointEventsProcessed,
185
+ }),
186
+ )
187
+ },
188
+ setEffectCacheOrThrow: async (~effect as _, ~items as _, ~initialize as _) => (),
189
+ dumpEffectCache: async () => (),
190
+ executeUnsafe: async _ => Obj.magic(),
191
+ setChainMeta: async _ => Obj.magic(),
192
+ pruneStaleCheckpoints: async (~safeCheckpointId as _) => (),
193
+ pruneStaleEntityHistory: async (~entityName as _, ~entityIndex as _, ~safeCheckpointId as _) =>
194
+ (),
195
+ getRollbackTargetCheckpoint: async (~reorgChainId as _, ~lastKnownValidBlockNumber as _) => {
196
+ Js.Exn.raiseError(
197
+ "TestIndexer: Rollback is not supported. Set rollbackOnReorg to false in config.",
198
+ )
199
+ },
200
+ getRollbackProgressDiff: async (~rollbackTargetCheckpointId as _) => {
201
+ Js.Exn.raiseError(
202
+ "TestIndexer: Rollback is not supported. Set rollbackOnReorg to false in config.",
203
+ )
204
+ },
205
+ getRollbackData: async (~entityConfig as _, ~rollbackTargetCheckpointId as _) => {
206
+ Js.Exn.raiseError(
207
+ "TestIndexer: Rollback is not supported. Set rollbackOnReorg to false in config.",
208
+ )
209
+ },
210
+ }