envio 3.3.2 → 3.4.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 (60) hide show
  1. package/package.json +6 -6
  2. package/src/Api.res +1 -8
  3. package/src/Api.res.mjs +1 -5
  4. package/src/ChainState.res +6 -1
  5. package/src/ChainState.res.mjs +4 -3
  6. package/src/Config.res +33 -4
  7. package/src/Config.res.mjs +34 -5
  8. package/src/Core.res +30 -19
  9. package/src/Core.res.mjs +5 -5
  10. package/src/EnvioGlobal.res +0 -2
  11. package/src/EnvioGlobal.res.mjs +0 -1
  12. package/src/ExitOnCaughtUp.res +6 -2
  13. package/src/ExitOnCaughtUp.res.mjs +4 -0
  14. package/src/FetchState.res +3 -3
  15. package/src/HandlerRegister.res +357 -434
  16. package/src/HandlerRegister.res.mjs +202 -242
  17. package/src/HandlerRegister.resi +7 -15
  18. package/src/IndexerState.res +10 -0
  19. package/src/IndexerState.res.mjs +9 -3
  20. package/src/IndexerState.resi +3 -0
  21. package/src/Internal.res +10 -1
  22. package/src/Main.res.mjs +4 -4
  23. package/src/PgStorage.res +16 -1
  24. package/src/PgStorage.res.mjs +9 -1
  25. package/src/SimulateItems.res +61 -40
  26. package/src/SimulateItems.res.mjs +37 -21
  27. package/src/TestIndexer.res +446 -453
  28. package/src/TestIndexer.res.mjs +320 -343
  29. package/src/bindings/ClickHouse.res +68 -2
  30. package/src/bindings/ClickHouse.res.mjs +47 -2
  31. package/src/sources/EvmChain.res +1 -1
  32. package/src/sources/EvmChain.res.mjs +2 -2
  33. package/src/sources/FuelHyperSync.res +74 -0
  34. package/src/sources/FuelHyperSync.res.mjs +80 -0
  35. package/src/sources/FuelHyperSync.resi +22 -0
  36. package/src/sources/FuelHyperSyncClient.res +120 -0
  37. package/src/sources/FuelHyperSyncClient.res.mjs +71 -0
  38. package/src/sources/FuelHyperSyncSource.res +257 -0
  39. package/src/sources/FuelHyperSyncSource.res.mjs +252 -0
  40. package/src/sources/HyperSyncClient.res +2 -2
  41. package/src/sources/HyperSyncClient.res.mjs +1 -1
  42. package/src/sources/SvmHyperSyncClient.res +139 -102
  43. package/src/sources/SvmHyperSyncClient.res.mjs +45 -5
  44. package/src/sources/SvmHyperSyncSource.res +60 -440
  45. package/src/sources/SvmHyperSyncSource.res.mjs +42 -363
  46. package/src/TestIndexerProxyStorage.res +0 -196
  47. package/src/TestIndexerProxyStorage.res.mjs +0 -121
  48. package/src/TestIndexerWorker.res +0 -4
  49. package/src/TestIndexerWorker.res.mjs +0 -7
  50. package/src/sources/EventRouter.res +0 -165
  51. package/src/sources/EventRouter.res.mjs +0 -153
  52. package/src/sources/HyperFuel.res +0 -179
  53. package/src/sources/HyperFuel.res.mjs +0 -146
  54. package/src/sources/HyperFuel.resi +0 -36
  55. package/src/sources/HyperFuelClient.res +0 -127
  56. package/src/sources/HyperFuelClient.res.mjs +0 -20
  57. package/src/sources/HyperFuelSource.res +0 -502
  58. package/src/sources/HyperFuelSource.res.mjs +0 -481
  59. /package/src/sources/{HyperSyncSource.res → EvmHyperSyncSource.res} +0 -0
  60. /package/src/sources/{HyperSyncSource.res.mjs → EvmHyperSyncSource.res.mjs} +0 -0
@@ -1,7 +1,6 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
3
  import * as Source from "./Source.res.mjs";
4
- import * as EventRouter from "./EventRouter.res.mjs";
5
4
  import * as Performance from "../bindings/Performance.res.mjs";
6
5
  import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
7
6
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
@@ -9,139 +8,9 @@ import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js
9
8
  import * as SvmHyperSyncClient from "./SvmHyperSyncClient.res.mjs";
10
9
  import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
11
10
 
12
- function buildInstructionSelections(eventConfigs) {
13
- return eventConfigs.flatMap(cfg => {
14
- let programIdString = cfg.programId;
15
- if (programIdString === "") {
16
- return [];
17
- }
18
- let match = cfg.discriminator;
19
- let match$1 = cfg.discriminatorByteLen;
20
- let match$2;
21
- if (match !== undefined) {
22
- switch (match$1) {
23
- case 1 :
24
- match$2 = [
25
- [match],
26
- undefined,
27
- undefined,
28
- undefined
29
- ];
30
- break;
31
- case 2 :
32
- match$2 = [
33
- undefined,
34
- [match],
35
- undefined,
36
- undefined
37
- ];
38
- break;
39
- case 4 :
40
- match$2 = [
41
- undefined,
42
- undefined,
43
- [match],
44
- undefined
45
- ];
46
- break;
47
- case 8 :
48
- match$2 = [
49
- undefined,
50
- undefined,
51
- undefined,
52
- [match]
53
- ];
54
- break;
55
- default:
56
- match$2 = [
57
- undefined,
58
- undefined,
59
- undefined,
60
- undefined
61
- ];
62
- }
63
- } else {
64
- match$2 = [
65
- undefined,
66
- undefined,
67
- undefined,
68
- undefined
69
- ];
70
- }
71
- let d8 = match$2[3];
72
- let d4 = match$2[2];
73
- let d2 = match$2[1];
74
- let d1 = match$2[0];
75
- let gs = cfg.accountFilters;
76
- let groups = gs.length !== 0 ? gs : [[]];
77
- return groups.map(group => {
78
- let pick = position => Stdlib_Array.filterMap(group, f => {
79
- if (f.position === position) {
80
- return f.values;
81
- }
82
- })[0];
83
- return {
84
- programId: [programIdString],
85
- d1: d1,
86
- d2: d2,
87
- d4: d4,
88
- d8: d8,
89
- a0: pick(0),
90
- a1: pick(1),
91
- a2: pick(2),
92
- a3: pick(3),
93
- a4: pick(4),
94
- a5: pick(5),
95
- isInner: cfg.isInner
96
- };
97
- });
98
- });
99
- }
100
-
101
- function synthLogIndex(instr) {
102
- let tx = instr.transactionIndex;
103
- let addrSum = Stdlib_Array.reduce(instr.instructionAddress, 0, (acc, n) => ((acc << 10) + n | 0) + 1 | 0);
104
- return (tx << 16) + addrSum | 0;
105
- }
106
-
107
- function serializeInstructionAddress(addr) {
108
- return addr.map(n => n.toString()).join(",");
109
- }
110
-
111
- function buildProgramSchemas(eventConfigs) {
112
- let descriptorsByProgram = {};
113
- eventConfigs.forEach(ec => {
114
- let programIdString = ec.programId;
115
- if (programIdString === "") {
116
- return;
117
- }
118
- let hasSchema = ec.accounts.length !== 0 || ec.args !== null;
119
- let discriminator = Stdlib_Option.getOr(ec.discriminator, "");
120
- if (!(hasSchema && discriminator !== "")) {
121
- return;
122
- }
123
- let other = ec.definedTypes;
124
- let definedTypes;
125
- definedTypes = other === null ? ({}) : other;
126
- let existing = descriptorsByProgram[programIdString];
127
- let descriptor = existing !== undefined ? Primitive_option.valFromOption(existing) : ({
128
- programId: programIdString,
129
- definedTypes: definedTypes,
130
- instructions: []
131
- });
132
- let instruction = {
133
- name: ec.name,
134
- discriminator: discriminator,
135
- accounts: ec.accounts,
136
- args: ec.args
137
- };
138
- descriptorsByProgram[programIdString] = {
139
- programId: descriptor.programId,
140
- definedTypes: descriptor.definedTypes,
141
- instructions: descriptor.instructions.concat([instruction])
142
- };
143
- });
144
- return Object.values(descriptorsByProgram).map(descriptor => JSON.stringify(descriptor));
11
+ function synthLogIndex(transactionIndex, instructionAddress) {
12
+ let addrSum = Stdlib_Array.reduce(instructionAddress, 0, (acc, n) => ((acc << 10) + n | 0) + 1 | 0);
13
+ return (transactionIndex << 16) + addrSum | 0;
145
14
  }
146
15
 
147
16
  function parseDecoded(d) {
@@ -165,200 +34,45 @@ function parseDecoded(d) {
165
34
  };
166
35
  }
167
36
 
168
- function toSvmInstruction(instr, programName, instructionName, logs) {
37
+ function toSvmInstruction(item, programName, instructionName) {
169
38
  return {
170
39
  programName: programName,
171
40
  instructionName: instructionName,
172
- programId: instr.programId,
173
- data: instr.data,
174
- accounts: instr.accounts,
175
- instructionAddress: instr.instructionAddress,
176
- isInner: instr.isInner,
177
- d1: instr.d1,
178
- d2: instr.d2,
179
- d4: instr.d4,
180
- d8: instr.d8,
181
- params: Stdlib_Option.map(instr.decoded, parseDecoded),
182
- logs: logs
41
+ programId: item.programId,
42
+ data: item.data,
43
+ accounts: item.accounts,
44
+ instructionAddress: item.instructionAddress,
45
+ isInner: item.isInner,
46
+ d1: item.d1,
47
+ d2: item.d2,
48
+ d4: item.d4,
49
+ d8: item.d8,
50
+ params: Stdlib_Option.map(item.decoded, parseDecoded),
51
+ logs: Stdlib_Option.map(item.logs, logs => logs.map(log => ({
52
+ kind: log.kind,
53
+ message: log.message
54
+ })))
183
55
  };
184
56
  }
185
57
 
186
- function probeRouter(router, programId, instr, byteLengthsDesc, contractAddress, contractNameByAddress) {
187
- let probe = dN => {
188
- let tag = EventRouter.getSvmEventId(programId, dN);
189
- return EventRouter.get(router, tag, contractAddress, contractNameByAddress);
190
- };
191
- let result = Stdlib_Array.reduce(byteLengthsDesc, undefined, (acc, len) => {
192
- if (acc !== undefined) {
193
- return acc;
194
- }
195
- let candidate;
196
- switch (len) {
197
- case 1 :
198
- candidate = instr.d1;
199
- break;
200
- case 2 :
201
- candidate = instr.d2;
202
- break;
203
- case 4 :
204
- candidate = instr.d4;
205
- break;
206
- case 8 :
207
- candidate = instr.d8;
208
- break;
209
- default:
210
- candidate = undefined;
211
- }
212
- if (candidate !== undefined) {
213
- return probe(candidate);
214
- }
215
- });
216
- if (result !== undefined) {
217
- return result;
218
- } else {
219
- return probe(undefined);
220
- }
221
- }
222
-
223
- function toQueryTxField(field) {
224
- switch (field) {
225
- case "signatures" :
226
- return "signatures";
227
- case "feePayer" :
228
- return "fee_payer";
229
- case "success" :
230
- return "success";
231
- case "err" :
232
- return "err";
233
- case "fee" :
234
- return "fee";
235
- case "computeUnitsConsumed" :
236
- return "compute_units_consumed";
237
- case "accountKeys" :
238
- return "account_keys";
239
- case "recentBlockhash" :
240
- return "recent_blockhash";
241
- case "version" :
242
- return "version";
243
- case "transactionIndex" :
244
- case "tokenBalances" :
245
- return;
246
- }
247
- }
248
-
249
- function toQueryBlockField(field) {
250
- switch (field) {
251
- case "height" :
252
- return "block_height";
253
- case "parentSlot" :
254
- return "parent_slot";
255
- case "parentHash" :
256
- return "parent_blockhash";
257
- default:
258
- return;
259
- }
260
- }
261
-
262
58
  function make(param) {
263
59
  let onEventRegistrations = param.onEventRegistrations;
264
60
  let chain = param.chain;
265
- let eventConfigs = onEventRegistrations.map(reg => reg.eventConfig);
266
- let programSchemas = buildProgramSchemas(eventConfigs);
267
- let client = SvmHyperSyncClient.make(param.endpointUrl, param.apiToken, param.clientTimeoutMillis, undefined, undefined, undefined, programSchemas.length !== 0 ? programSchemas : undefined);
268
- let match = EventRouter.fromSvmEventConfigsOrThrow(onEventRegistrations, chain);
269
- let eventRouter = match[0];
270
- let orderingByProgram = {};
271
- match[1].forEach(o => {
272
- orderingByProgram[o.programId] = o.byteLengthsDesc;
273
- });
274
- let needsLogs = eventConfigs.some(cfg => cfg.includeLogs);
275
- let selectedTxFields = new Set();
276
- eventConfigs.forEach(cfg => {
277
- cfg.selectedTransactionFields.forEach(field => {
278
- selectedTxFields.add(field);
279
- });
280
- });
281
- let needsTokenBalances = selectedTxFields.has("tokenBalances");
282
- let fields = [
283
- "slot",
284
- "transaction_index"
285
- ];
286
- Array.from(selectedTxFields).forEach(field => {
287
- let queryField = toQueryTxField(field);
288
- if (queryField !== undefined) {
289
- fields.push(queryField);
290
- return;
291
- }
292
- });
293
- let needsTransactions = Array.from(selectedTxFields).some(field => {
294
- switch (field) {
295
- case "transactionIndex" :
296
- case "tokenBalances" :
297
- return false;
298
- default:
299
- return true;
300
- }
301
- });
302
- let fields$1 = [
303
- "slot",
304
- "blockhash",
305
- "block_time"
306
- ];
307
- let selected = new Set();
308
- eventConfigs.forEach(cfg => {
309
- cfg.selectedBlockFields.forEach(field => {
310
- selected.add(field);
311
- });
312
- });
313
- selected.forEach(field => {
314
- let queryField = toQueryBlockField(field);
315
- if (queryField !== undefined) {
316
- fields$1.push(queryField);
317
- return;
318
- }
319
- });
320
- let getItemsOrThrow = async (fromBlock, toBlock, param, contractNameByAddress, knownHeight, param$1, param$2, itemsTarget, retry, logger) => {
61
+ let client = SvmHyperSyncClient.make(param.endpointUrl, param.apiToken, param.clientTimeoutMillis, undefined, undefined, undefined, SvmHyperSyncClient.Registration.fromOnEventRegistrations(onEventRegistrations));
62
+ let getItemsOrThrow = async (fromBlock, toBlock, addressesByContractName, param, knownHeight, param$1, selection, itemsTarget, retry, param$2) => {
321
63
  let totalTimeRef = Performance.now();
322
64
  let pageFetchRef = Performance.now();
323
- let instructionSelections = buildInstructionSelections(eventConfigs);
324
- let fields_block = fields$1;
325
- let fields_transaction = needsTransactions ? fields : undefined;
326
- let fields_log = needsLogs ? [
327
- "slot",
328
- "transaction_index",
329
- "instruction_address",
330
- "kind",
331
- "message"
332
- ] : undefined;
333
- let fields_tokenBalance = needsTokenBalances ? [
334
- "slot",
335
- "transaction_index",
336
- "account",
337
- "mint",
338
- "owner",
339
- "pre_amount",
340
- "post_amount"
341
- ] : undefined;
342
- let fields$2 = {
343
- block: fields_block,
344
- transaction: fields_transaction,
345
- log: fields_log,
346
- tokenBalance: fields_tokenBalance
347
- };
348
- let query_toSlot = Stdlib_Option.map(toBlock, toBlock => toBlock + 1 | 0);
349
- let query_instructions = instructionSelections;
350
- let query_fields = fields$2;
351
- let query_maxNumInstructions = itemsTarget;
65
+ let query_registrationIndexes = selection.onEventRegistrations.map(reg => reg.index);
352
66
  let query = {
353
67
  fromSlot: fromBlock,
354
- toSlot: query_toSlot,
355
- instructions: query_instructions,
356
- fields: query_fields,
357
- maxNumInstructions: query_maxNumInstructions
68
+ toSlot: toBlock,
69
+ maxNumInstructions: itemsTarget,
70
+ registrationIndexes: query_registrationIndexes,
71
+ addressesByContractName: addressesByContractName
358
72
  };
359
73
  let match;
360
74
  try {
361
- match = await client.get(query);
75
+ match = await client.getEventItems(query);
362
76
  } catch (raw_exn) {
363
77
  let exn = Primitive_exceptions.internalToException(raw_exn);
364
78
  throw {
@@ -384,60 +98,31 @@ function make(param) {
384
98
  }];
385
99
  let parsingRef = Performance.now();
386
100
  let blockTimeBySlot = {};
387
- resp.data.blocks.forEach(b => {
101
+ resp.blocks.forEach(b => {
388
102
  let t = b.blockTime;
389
103
  if (t !== undefined) {
390
104
  blockTimeBySlot[b.slot.toString()] = t;
391
105
  return;
392
106
  }
393
107
  });
394
- let logsByKey = {};
395
- resp.data.logs.forEach(log => {
396
- let match = log.transactionIndex;
397
- let match$1 = log.instructionAddress;
398
- if (match === undefined) {
399
- return;
400
- }
401
- if (match$1 === undefined) {
402
- return;
403
- }
404
- let key = log.slot.toString() + ":" + match.toString() + ":" + serializeInstructionAddress(match$1);
405
- let existing = logsByKey[key];
406
- if (existing !== undefined) {
407
- existing.push(log);
408
- } else {
409
- logsByKey[key] = [log];
410
- }
411
- });
412
- let parsedQueueItems = [];
413
- resp.data.instructions.forEach(instr => {
414
- let programId = instr.programId;
415
- let byteLengths = Stdlib_Option.getOr(orderingByProgram[instr.programId], []);
416
- let contractAddress = instr.programId;
417
- let maybeConfig = probeRouter(eventRouter, programId, instr, byteLengths, contractAddress, contractNameByAddress);
418
- if (maybeConfig !== undefined && instr.isCommitted) {
419
- let eventConfig = maybeConfig.eventConfig;
420
- let logKey = instr.slot.toString() + ":" + instr.transactionIndex.toString() + ":" + serializeInstructionAddress(instr.instructionAddress);
421
- let maybeLogs = Stdlib_Option.map(logsByKey[logKey], logs => logs.map(log => ({
422
- kind: Stdlib_Option.getOr(log.kind, ""),
423
- message: Stdlib_Option.getOr(log.message, "")
424
- })));
425
- let payload = toSvmInstruction(instr, eventConfig.contractName, eventConfig.name, eventConfig.includeLogs ? maybeLogs : undefined);
426
- parsedQueueItems.push({
427
- kind: 0,
428
- onEventRegistration: maybeConfig,
429
- chain: chain,
430
- blockNumber: instr.slot,
431
- logIndex: synthLogIndex(instr),
432
- transactionIndex: instr.transactionIndex,
433
- payload: payload
434
- });
435
- }
108
+ let parsedQueueItems = resp.items.map(item => {
109
+ let onEventRegistration = onEventRegistrations[item.onEventRegistrationIndex];
110
+ let eventConfig = onEventRegistration.eventConfig;
111
+ let payload = toSvmInstruction(item, eventConfig.contractName, eventConfig.name);
112
+ return {
113
+ kind: 0,
114
+ onEventRegistration: onEventRegistration,
115
+ chain: chain,
116
+ blockNumber: item.slot,
117
+ logIndex: synthLogIndex(item.transactionIndex, item.instructionAddress),
118
+ transactionIndex: item.transactionIndex,
119
+ payload: payload
120
+ };
436
121
  });
437
122
  let parsingTimeElapsed = Performance.secondsSince(parsingRef);
438
123
  let highestSlot = resp.nextSlot - 1 | 0;
439
124
  let latestBlockTime = Stdlib_Option.getOr(blockTimeBySlot[highestSlot.toString()], 0);
440
- let blockHashes = resp.data.blocks.map(b => ({
125
+ let blockHashes = resp.blocks.map(b => ({
441
126
  blockHash: b.blockhash,
442
127
  blockNumber: b.slot
443
128
  }));
@@ -578,15 +263,9 @@ function make(param) {
578
263
  }
579
264
 
580
265
  export {
581
- buildInstructionSelections,
582
266
  synthLogIndex,
583
- serializeInstructionAddress,
584
- buildProgramSchemas,
585
267
  parseDecoded,
586
268
  toSvmInstruction,
587
- probeRouter,
588
- toQueryTxField,
589
- toQueryBlockField,
590
269
  make,
591
270
  }
592
- /* EventRouter Not a pure module */
271
+ /* SvmHyperSyncClient Not a pure module */
@@ -1,196 +0,0 @@
1
- // Message types for communication between worker and main thread
2
- type requestId = int
3
-
4
- // Serializable change with entity as JSON (for worker thread messaging)
5
- @tag("type")
6
- type serializableChange =
7
- | @as("SET") Set({entityId: string, entity: JSON.t, checkpointId: bigint})
8
- | @as("DELETE") Delete({entityId: string, checkpointId: bigint})
9
-
10
- type serializableUpdatedEntity = {
11
- entityName: string,
12
- changes: array<serializableChange>,
13
- }
14
-
15
- // Worker -> Main thread payloads
16
- @tag("type")
17
- type workerPayload =
18
- | @as("load")
19
- Load({
20
- tableName: string,
21
- // Leaf field values are JSON-serialized with the table's field schemas
22
- filter: EntityFilter.t,
23
- })
24
- | @as("writeBatch")
25
- WriteBatch({
26
- updatedEntities: array<serializableUpdatedEntity>,
27
- checkpointIds: array<bigint>,
28
- checkpointChainIds: array<int>,
29
- checkpointBlockNumbers: array<int>,
30
- checkpointBlockHashes: array<Null.t<string>>,
31
- checkpointEventsProcessed: array<int>,
32
- })
33
-
34
- // Main thread -> Worker payloads
35
- @tag("type")
36
- type mainPayload =
37
- | @as("response") Response({data: JSON.t})
38
- | @as("error") Error({message: string})
39
-
40
- // Message wrapper with id
41
- type message<'payload> = {id: requestId, payload: 'payload}
42
- type workerMessage = message<workerPayload>
43
- type mainMessage = message<mainPayload>
44
-
45
- // Pending request tracker
46
- type pendingRequest = {
47
- resolve: JSON.t => unit,
48
- reject: exn => unit,
49
- }
50
-
51
- type t = {
52
- parentPort: NodeJs.WorkerThreads.messagePort,
53
- initialState: Persistence.initialState,
54
- pendingRequests: dict<pendingRequest>,
55
- mutable requestCounter: int,
56
- }
57
-
58
- let make = (~parentPort, ~initialState): t => {
59
- let proxy = {
60
- parentPort,
61
- initialState,
62
- pendingRequests: Dict.make(),
63
- requestCounter: 0,
64
- }
65
-
66
- // Set up message listener for responses from main thread
67
- parentPort->NodeJs.WorkerThreads.onPortMessage((msg: mainMessage) => {
68
- let idStr = msg.id->Int.toString
69
- let {resolve, reject} = switch proxy.pendingRequests->Utils.Dict.dangerouslyGetNonOption(
70
- idStr,
71
- ) {
72
- | Some(pending) => pending
73
- | None => JsError.throwWithMessage(`TestIndexer: No pending request found for id ${idStr}`)
74
- }
75
- Dict.delete(proxy.pendingRequests->Obj.magic, idStr)
76
-
77
- switch msg.payload {
78
- | Response({data}) => resolve(data)
79
- | Error({message}) => reject(Utils.Error.make(message))
80
- }
81
- })
82
-
83
- proxy
84
- }
85
-
86
- let nextRequestId = (proxy: t): requestId => {
87
- proxy.requestCounter = proxy.requestCounter + 1
88
- proxy.requestCounter
89
- }
90
-
91
- let sendRequest = (proxy: t, ~payload: workerPayload): promise<JSON.t> => {
92
- Promise.make((resolve, reject) => {
93
- let id = proxy->nextRequestId
94
- proxy.pendingRequests->Dict.set(id->Int.toString, {resolve, reject})
95
- proxy.parentPort->NodeJs.WorkerThreads.postMessage({id, payload})
96
- })
97
- }
98
-
99
- let makeStorage = (proxy: t): Persistence.storage => {
100
- name: "test-proxy",
101
- isInitialized: async () => true,
102
- initialize: async (~chainConfigs as _=?, ~entities as _=?, ~enums as _=?, ~envioInfo as _) => {
103
- JsError.throwWithMessage(
104
- "TestIndexer: initialize should not be called. Use resumeInitialState instead.",
105
- )
106
- },
107
- resumeInitialState: async () => proxy.initialState,
108
- loadOrThrow: async (~filter, ~table: Table.table) => {
109
- let serializeLeafOrThrow = (~fieldName, ~fieldValue: unknown, ~isArray) => {
110
- let queryField = switch table->Table.queryFields->Dict.get(fieldName) {
111
- | Some(queryField) => queryField
112
- | None =>
113
- JsError.throwWithMessage(
114
- `TestIndexer: The table "${table.tableName}" doesn't have the field "${fieldName}"`,
115
- )
116
- }
117
- fieldValue
118
- ->S.reverseConvertToJsonOrThrow(
119
- isArray ? queryField.arrayFieldSchema : queryField.fieldSchema,
120
- )
121
- ->(Utils.magic: JSON.t => unknown)
122
- }
123
- let response = await proxy->sendRequest(
124
- ~payload=Load({
125
- tableName: table.tableName,
126
- // Field values must be JSON-safe to survive the worker thread boundary
127
- filter: filter->EntityFilter.mapValues(~mapValue=serializeLeafOrThrow),
128
- }),
129
- )
130
- response->S.parseOrThrow(table->Table.rowsSchema)
131
- },
132
- writeBatch: async (
133
- ~batch,
134
- ~rollback as _,
135
- ~isInReorgThreshold as _,
136
- ~config as _,
137
- ~allEntities as _,
138
- ~updatedEffectsCache as _,
139
- ~updatedEntities,
140
- ~chainMetaData as _,
141
- ~onWrite as _,
142
- ) => {
143
- // Encode entities to JSON for serialization across worker boundary
144
- let serializableEntities = updatedEntities->Array.map((
145
- {entityConfig, changes}: Persistence.updatedEntity,
146
- ) => {
147
- let encodeChange = (change: Change.t<Internal.entity>): serializableChange => {
148
- switch change {
149
- | Set({entityId, entity, checkpointId}) =>
150
- Set({
151
- entityId,
152
- entity: entity->S.reverseConvertToJsonOrThrow(entityConfig.schema),
153
- checkpointId,
154
- })
155
- | Delete({entityId, checkpointId}) => Delete({entityId, checkpointId})
156
- }
157
- }
158
- {
159
- entityName: entityConfig.name,
160
- changes: changes->Array.map(encodeChange),
161
- }
162
- })
163
- let _ = await proxy->sendRequest(
164
- ~payload=WriteBatch({
165
- updatedEntities: serializableEntities,
166
- checkpointIds: batch.checkpointIds,
167
- checkpointChainIds: batch.checkpointChainIds,
168
- checkpointBlockNumbers: batch.checkpointBlockNumbers,
169
- checkpointBlockHashes: batch.checkpointBlockHashes,
170
- checkpointEventsProcessed: batch.checkpointEventsProcessed,
171
- }),
172
- )
173
- },
174
- dumpEffectCache: async () => (),
175
- reset: async () => (),
176
- setChainMeta: async _ => Obj.magic(),
177
- pruneStaleCheckpoints: async (~safeCheckpointId as _) => (),
178
- pruneStaleEntityHistory: async (~entityName as _, ~entityIndex as _, ~safeCheckpointId as _) =>
179
- (),
180
- getRollbackTargetCheckpoint: async (~reorgChainId as _, ~lastKnownValidBlockNumber as _) => {
181
- JsError.throwWithMessage(
182
- "TestIndexer: Rollback is not supported. Set rollbackOnReorg to false in config.",
183
- )
184
- },
185
- getRollbackProgressDiff: async (~rollbackTargetCheckpointId as _) => {
186
- JsError.throwWithMessage(
187
- "TestIndexer: Rollback is not supported. Set rollbackOnReorg to false in config.",
188
- )
189
- },
190
- getRollbackData: async (~entityConfig as _, ~rollbackTargetCheckpointId as _) => {
191
- JsError.throwWithMessage(
192
- "TestIndexer: Rollback is not supported. Set rollbackOnReorg to false in config.",
193
- )
194
- },
195
- close: async () => (),
196
- }