envio 3.3.0-alpha.9 → 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 (94) 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 +134 -55
  13. package/src/ChainState.res.mjs +78 -36
  14. package/src/ChainState.resi +14 -2
  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 +115 -34
  20. package/src/CrossChainState.res.mjs +37 -14
  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/EventConfigBuilder.res +21 -46
  27. package/src/EventConfigBuilder.res.mjs +18 -25
  28. package/src/EventProcessing.res +8 -5
  29. package/src/EventProcessing.res.mjs +2 -1
  30. package/src/FetchState.res +814 -467
  31. package/src/FetchState.res.mjs +541 -369
  32. package/src/HandlerRegister.res +3 -1
  33. package/src/HandlerRegister.res.mjs +3 -2
  34. package/src/InMemoryStore.res +14 -26
  35. package/src/InMemoryStore.res.mjs +6 -19
  36. package/src/IndexerState.res +15 -39
  37. package/src/IndexerState.res.mjs +18 -29
  38. package/src/IndexerState.resi +2 -10
  39. package/src/Internal.res +98 -14
  40. package/src/Internal.res.mjs +96 -2
  41. package/src/LoadLayer.res +44 -24
  42. package/src/LoadLayer.res.mjs +43 -20
  43. package/src/LoadLayer.resi +1 -0
  44. package/src/LogSelection.res +0 -62
  45. package/src/LogSelection.res.mjs +0 -74
  46. package/src/Metrics.res +1 -1
  47. package/src/Metrics.res.mjs +1 -1
  48. package/src/Persistence.res +12 -3
  49. package/src/PgStorage.res +155 -82
  50. package/src/PgStorage.res.mjs +130 -77
  51. package/src/Prometheus.res +20 -10
  52. package/src/Prometheus.res.mjs +22 -10
  53. package/src/PruneStaleHistory.res +146 -35
  54. package/src/PruneStaleHistory.res.mjs +114 -20
  55. package/src/RawEvent.res +2 -2
  56. package/src/Rollback.res +32 -13
  57. package/src/Rollback.res.mjs +24 -11
  58. package/src/SimulateDeadInputTracker.res +1 -1
  59. package/src/SimulateItems.res +38 -6
  60. package/src/SimulateItems.res.mjs +28 -9
  61. package/src/TestIndexer.res +2 -2
  62. package/src/TestIndexer.res.mjs +2 -2
  63. package/src/TopicFilter.res +1 -25
  64. package/src/TopicFilter.res.mjs +0 -74
  65. package/src/UserContext.res +62 -23
  66. package/src/UserContext.res.mjs +26 -6
  67. package/src/Writing.res +60 -21
  68. package/src/Writing.res.mjs +27 -9
  69. package/src/bindings/NodeJs.res +5 -0
  70. package/src/bindings/Viem.res +0 -5
  71. package/src/sources/EventRouter.res +0 -21
  72. package/src/sources/EventRouter.res.mjs +0 -12
  73. package/src/sources/EvmChain.res +2 -27
  74. package/src/sources/EvmChain.res.mjs +2 -23
  75. package/src/sources/EvmRpcClient.res +58 -23
  76. package/src/sources/EvmRpcClient.res.mjs +11 -5
  77. package/src/sources/HyperSync.res +9 -38
  78. package/src/sources/HyperSync.res.mjs +16 -28
  79. package/src/sources/HyperSync.resi +2 -2
  80. package/src/sources/HyperSyncClient.res +88 -11
  81. package/src/sources/HyperSyncClient.res.mjs +39 -6
  82. package/src/sources/HyperSyncSource.res +18 -199
  83. package/src/sources/HyperSyncSource.res.mjs +9 -128
  84. package/src/sources/Rpc.res +0 -32
  85. package/src/sources/Rpc.res.mjs +1 -46
  86. package/src/sources/RpcSource.res +129 -522
  87. package/src/sources/RpcSource.res.mjs +161 -366
  88. package/src/sources/SimulateSource.res +37 -19
  89. package/src/sources/SimulateSource.res.mjs +27 -10
  90. package/src/sources/SourceManager.res +3 -7
  91. package/src/sources/SourceManager.res.mjs +2 -7
  92. package/src/sources/SourceManager.resi +0 -2
  93. package/src/sources/SvmHyperSyncSource.res +13 -3
  94. package/src/sources/SvmHyperSyncSource.res.mjs +1 -1
package/src/Envio.res.mjs CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  import * as Address from "./Address.res.mjs";
4
4
  import * as Process from "process";
5
- import * as Internal from "./Internal.res.mjs";
6
5
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
6
+ import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
7
7
  import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
8
8
 
9
9
  function durationToMs(duration) {
@@ -18,41 +18,36 @@ function durationToMs(duration) {
18
18
  }
19
19
  }
20
20
 
21
+ let effectNameRe = /^[A-Za-z0-9_-][A-Za-z0-9_.-]*$/;
22
+
21
23
  function createEffect(options, handler) {
24
+ if (!effectNameRe.test(options.name)) {
25
+ Stdlib_JsError.throwWithMessage(`Invalid effect name "` + options.name + `". Effect names may contain letters, numbers, underscores, hyphens and dots (but must not start with a dot or contain a path separator), because the name is used as the cache table name and cache file path.`);
26
+ }
22
27
  let outputSchema = S$RescriptSchema.schema(param => options.output);
23
28
  let itemSchema = S$RescriptSchema.schema(s => ({
24
29
  id: s.m(S$RescriptSchema.string),
25
30
  output: s.m(outputSchema)
26
31
  }));
27
32
  let match = options.cache;
28
- let match$1 = options.rateLimit;
33
+ let match$1 = options.crossChain;
34
+ let match$2 = options.rateLimit;
29
35
  let tmp;
30
- if (match$1 === false) {
31
- tmp = undefined;
32
- } else {
33
- let calls = match$1.calls;
34
- tmp = {
35
- callsPerDuration: calls,
36
- durationMs: durationToMs(match$1.per),
37
- availableCalls: calls,
38
- windowStartTime: Date.now(),
39
- queueCount: 0,
40
- nextWindowPromise: undefined
41
- };
42
- }
36
+ tmp = match$2 === false ? undefined : ({
37
+ callsPerDuration: match$2.calls,
38
+ durationMs: durationToMs(match$2.per)
39
+ });
43
40
  return {
44
41
  name: options.name,
45
42
  handler: handler,
46
43
  storageMeta: {
47
44
  itemSchema: itemSchema,
48
- outputSchema: outputSchema,
49
- table: Internal.makeCacheTable(options.name)
45
+ outputSchema: outputSchema
50
46
  },
51
47
  defaultShouldCache: match !== undefined ? match : false,
48
+ crossChain: match$1 !== undefined ? match$1 : true,
52
49
  output: outputSchema,
53
50
  input: S$RescriptSchema.schema(param => options.input),
54
- activeCallsCount: 0,
55
- prevCallStartTimerRef: null,
56
51
  rateLimit: tmp
57
52
  };
58
53
  }
@@ -102,6 +97,7 @@ let TestHelpers = {
102
97
 
103
98
  export {
104
99
  durationToMs,
100
+ effectNameRe,
105
101
  createEffect,
106
102
  isNonInteractive,
107
103
  TestHelpers,
@@ -236,58 +236,30 @@ let buildSimulateParamsSchema = (params: array<paramMeta>): S.t<Internal.eventPa
236
236
 
237
237
  // ============== Build topic filter getters ==============
238
238
 
239
- let getTopicEncoder = (abiType: string): (unknown => EvmTypes.Hex.t) => {
240
- // Handle array/tuple types - these get keccak256'd
241
- if abiType->String.endsWith("]") || abiType->String.startsWith("(") {
242
- TopicFilter.castToHexUnsafe->(Utils.magic: ('a => EvmTypes.Hex.t) => unknown => EvmTypes.Hex.t)
243
- } else {
244
- switch abiType {
245
- | "address" =>
246
- // Lowercase before encoding so mixed-case (checksummed) user input
247
- // still matches the lowercase hex topics returned by sources.
248
-
249
- (
250
- (value: string) =>
251
- value->String.toLowerCase->Address.unsafeFromString->TopicFilter.fromAddress
252
- )->(Utils.magic: (string => EvmTypes.Hex.t) => unknown => EvmTypes.Hex.t)
253
-
254
- | "bool" =>
255
- TopicFilter.fromBool->(Utils.magic: (bool => EvmTypes.Hex.t) => unknown => EvmTypes.Hex.t)
256
- | "string" =>
257
- TopicFilter.fromDynamicString->(
258
- Utils.magic: (string => EvmTypes.Hex.t) => unknown => EvmTypes.Hex.t
259
- )
260
-
261
- | "bytes" =>
262
- TopicFilter.fromDynamicBytes->(
263
- Utils.magic: (string => EvmTypes.Hex.t) => unknown => EvmTypes.Hex.t
264
- )
265
-
266
- | t if t->String.startsWith("uint") =>
267
- TopicFilter.fromBigInt->(Utils.magic: (bigint => EvmTypes.Hex.t) => unknown => EvmTypes.Hex.t)
268
- | t if t->String.startsWith("int") =>
269
- TopicFilter.fromSignedBigInt->(
270
- Utils.magic: (bigint => EvmTypes.Hex.t) => unknown => EvmTypes.Hex.t
271
- )
272
-
273
- | t if t->String.startsWith("bytes") =>
274
- TopicFilter.castToHexUnsafe->(
275
- Utils.magic: ('a => EvmTypes.Hex.t) => unknown => EvmTypes.Hex.t
276
- )
277
-
278
- | other => JsError.throwWithMessage(`Unsupported topic filter ABI type: ${other}`)
279
- }
280
- }
281
- }
239
+ let getTopicEncoder = (abiType: string): (unknown => EvmTypes.Hex.t) => value =>
240
+ Core.getAddon().encodeIndexedTopic(~abiType, ~value)
282
241
 
283
242
  let buildTopicGetter = (p: paramMeta) => {
284
243
  let encoder = getTopicEncoder(p.abiType)
244
+ let isTuple = p.abiType->String.startsWith("(")
285
245
  (eventFilter: dict<JSON.t>) =>
286
246
  eventFilter
287
247
  ->Utils.Dict.dangerouslyGetNonOption(p.name)
288
- ->Option.mapOr([], topicFilters =>
289
- topicFilters->(Utils.magic: JSON.t => unknown)->normalizeOrThrow->Array.map(encoder)
290
- )
248
+ ->Option.mapOr([], topicFilters => {
249
+ let raw = topicFilters->(Utils.magic: JSON.t => unknown)
250
+ // A tuple filter value is itself an array, so a directly-passed tuple is
251
+ // indistinguishable from an OR-list by shape alone. A single tuple is
252
+ // the common case, so try it first; when the value doesn't ABI-encode as
253
+ // one tuple it must be an OR-list of tuples.
254
+ if isTuple {
255
+ switch encoder(raw) {
256
+ | encoded => [encoded]
257
+ | exception _ => raw->normalizeOrThrow->Array.map(encoder)
258
+ }
259
+ } else {
260
+ raw->normalizeOrThrow->Array.map(encoder)
261
+ }
262
+ })
291
263
  }
292
264
 
293
265
  // ============== Field selection ==============
@@ -452,6 +424,7 @@ let buildEvmOnEventRegistration = (
452
424
  }
453
425
 
454
426
  {
427
+ index: -1,
455
428
  eventConfig: (eventConfig :> Internal.eventConfig),
456
429
  isWildcard,
457
430
  handler,
@@ -536,6 +509,7 @@ let buildSvmOnEventRegistration = (
536
509
  ~contractRegister: option<Internal.contractRegister>,
537
510
  ~startBlock: option<int>=?,
538
511
  ): Internal.svmOnEventRegistration => {
512
+ index: -1,
539
513
  eventConfig: (eventConfig :> Internal.eventConfig),
540
514
  handler,
541
515
  contractRegister,
@@ -613,6 +587,7 @@ let buildFuelOnEventRegistration = (
613
587
  ~contractRegister: option<Internal.contractRegister>,
614
588
  ~startBlock: option<int>=?,
615
589
  ): Internal.fuelOnEventRegistration => {
590
+ index: -1,
616
591
  eventConfig: (eventConfig :> Internal.eventConfig),
617
592
  handler,
618
593
  contractRegister,
@@ -2,11 +2,11 @@
2
2
 
3
3
  import * as Evm from "./sources/Evm.res.mjs";
4
4
  import * as Svm from "./sources/Svm.res.mjs";
5
+ import * as Core from "./Core.res.mjs";
5
6
  import * as Utils from "./Utils.res.mjs";
6
7
  import * as Address from "./Address.res.mjs";
7
8
  import * as FuelSDK from "./sources/FuelSDK.res.mjs";
8
9
  import * as Internal from "./Internal.res.mjs";
9
- import * as TopicFilter from "./TopicFilter.res.mjs";
10
10
  import * as LogSelection from "./LogSelection.res.mjs";
11
11
  import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
12
12
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
@@ -208,34 +208,24 @@ function buildSimulateParamsSchema(params) {
208
208
  }
209
209
 
210
210
  function getTopicEncoder(abiType) {
211
- if (abiType.endsWith("]") || abiType.startsWith("(")) {
212
- return TopicFilter.castToHexUnsafe;
213
- }
214
- switch (abiType) {
215
- case "address" :
216
- return value => TopicFilter.fromAddress(value.toLowerCase());
217
- case "bool" :
218
- return TopicFilter.fromBool;
219
- case "bytes" :
220
- return TopicFilter.fromDynamicBytes;
221
- case "string" :
222
- return TopicFilter.fromDynamicString;
223
- default:
224
- if (abiType.startsWith("uint")) {
225
- return TopicFilter.fromBigInt;
226
- } else if (abiType.startsWith("int")) {
227
- return TopicFilter.fromSignedBigInt;
228
- } else if (abiType.startsWith("bytes")) {
229
- return TopicFilter.castToHexUnsafe;
230
- } else {
231
- return Stdlib_JsError.throwWithMessage(`Unsupported topic filter ABI type: ` + abiType);
232
- }
233
- }
211
+ return value => Core.getAddon().encodeIndexedTopic(abiType, value);
234
212
  }
235
213
 
236
214
  function buildTopicGetter(p) {
237
215
  let encoder = getTopicEncoder(p.abiType);
238
- return eventFilter => Stdlib_Option.mapOr(eventFilter[p.name], [], topicFilters => normalizeOrThrow(topicFilters).map(encoder));
216
+ let isTuple = p.abiType.startsWith("(");
217
+ return eventFilter => Stdlib_Option.mapOr(eventFilter[p.name], [], topicFilters => {
218
+ if (!isTuple) {
219
+ return normalizeOrThrow(topicFilters).map(encoder);
220
+ }
221
+ let encoded;
222
+ try {
223
+ encoded = encoder(topicFilters);
224
+ } catch (exn) {
225
+ return normalizeOrThrow(topicFilters).map(encoder);
226
+ }
227
+ return [encoded];
228
+ });
239
229
  }
240
230
 
241
231
  let alwaysIncludedBlockFields = [
@@ -317,6 +307,7 @@ function buildEvmOnEventRegistration(eventConfig, isWildcard, handler, contractR
317
307
  let sb = resolvedWhere.startBlock;
318
308
  let resolvedStartBlock = sb !== undefined ? sb : startBlock;
319
309
  return {
310
+ index: -1,
320
311
  eventConfig: eventConfig,
321
312
  handler: handler,
322
313
  contractRegister: contractRegister,
@@ -369,6 +360,7 @@ function buildSvmInstructionEventConfig(contractName, instructionName, programId
369
360
 
370
361
  function buildSvmOnEventRegistration(eventConfig, isWildcard, handler, contractRegister, startBlock) {
371
362
  return {
363
+ index: -1,
372
364
  eventConfig: eventConfig,
373
365
  handler: handler,
374
366
  contractRegister: contractRegister,
@@ -438,6 +430,7 @@ function buildFuelEventConfig(contractName, eventName, kind, sighash, rawAbi) {
438
430
 
439
431
  function buildFuelOnEventRegistration(eventConfig, isWildcard, handler, contractRegister, startBlock) {
440
432
  return {
433
+ index: -1,
441
434
  eventConfig: eventConfig,
442
435
  handler: handler,
443
436
  contractRegister: contractRegister,
@@ -73,9 +73,10 @@ let runEventHandlerOrThrow = async (
73
73
  )
74
74
  }
75
75
  let handlerDuration = timeBeforeHandler->Performance.secondsSince
76
+ let eventConfig = eventItem.onEventRegistration.eventConfig
76
77
  Prometheus.ProcessingHandler.increment(
77
- ~contract=eventItem.onEventRegistration.eventConfig.contractName,
78
- ~event=eventItem.onEventRegistration.eventConfig.name,
78
+ ~contract=eventConfig.contractName,
79
+ ~event=eventConfig.name,
79
80
  ~duration=handlerDuration,
80
81
  )
81
82
  }
@@ -121,8 +122,8 @@ let runHandlerOrThrow = async (
121
122
  }),
122
123
  )
123
124
  }
124
- | Event({onEventRegistration}) =>
125
- switch onEventRegistration.handler {
125
+ | Event(_) =>
126
+ switch (item->Internal.castUnsafeEventItem).onEventRegistration.handler {
126
127
  | Some(handler) =>
127
128
  await item->runEventHandlerOrThrow(
128
129
  ~handler,
@@ -161,7 +162,9 @@ let preloadBatchOrThrow = async (
161
162
  for idx in 0 to checkpointEventsProcessed - 1 {
162
163
  let item = batch.items->Array.getUnsafe(itemIdx.contents + idx)
163
164
  switch item {
164
- | Event({onEventRegistration: {handler, eventConfig: {contractName, name: eventName}}}) =>
165
+ | Event(_) =>
166
+ let {handler, eventConfig: {contractName, name: eventName}} =
167
+ (item->Internal.castUnsafeEventItem).onEventRegistration
165
168
  switch handler {
166
169
  | None => ()
167
170
  | Some(handler) =>
@@ -65,7 +65,8 @@ async function runEventHandlerOrThrow(item, checkpointId, handler, indexerState,
65
65
  };
66
66
  }
67
67
  let handlerDuration = Performance.secondsSince(timeBeforeHandler);
68
- return Prometheus.ProcessingHandler.increment(item.onEventRegistration.eventConfig.contractName, item.onEventRegistration.eventConfig.name, handlerDuration);
68
+ let eventConfig = item.onEventRegistration.eventConfig;
69
+ return Prometheus.ProcessingHandler.increment(eventConfig.contractName, eventConfig.name, handlerDuration);
69
70
  }
70
71
 
71
72
  async function runHandlerOrThrow(item, checkpointId, indexerState, loadManager, persistence, config, chains) {