envio 2.26.0-rc.2 → 2.27.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/evm.schema.json CHANGED
@@ -106,6 +106,13 @@
106
106
  "boolean",
107
107
  "null"
108
108
  ]
109
+ },
110
+ "preload_handlers": {
111
+ "description": "Makes handlers run twice to enable preload optimisations. Removes handlerWithLoader API, since it's not needed. (recommended, default: false)",
112
+ "type": [
113
+ "boolean",
114
+ "null"
115
+ ]
109
116
  }
110
117
  },
111
118
  "additionalProperties": false,
@@ -576,6 +583,15 @@
576
583
  "description": "A single address or a list of addresses to be indexed. This can be left as null in the case where this contracts addresses will be registered dynamically.",
577
584
  "$ref": "#/$defs/Addresses"
578
585
  },
586
+ "start_block": {
587
+ "description": "The block at which the indexer should start ingesting data for this specific contract. If not specified, uses the network start_block. Can be greater than the network start_block for more specific indexing.",
588
+ "type": [
589
+ "integer",
590
+ "null"
591
+ ],
592
+ "format": "uint64",
593
+ "minimum": 0
594
+ },
579
595
  "abi_file_path": {
580
596
  "description": "Relative path (from config) to a json abi. If this is used then each configured event should simply be referenced by its name",
581
597
  "type": [
package/fuel.schema.json CHANGED
@@ -56,6 +56,13 @@
56
56
  "boolean",
57
57
  "null"
58
58
  ]
59
+ },
60
+ "preload_handlers": {
61
+ "description": "Makes handlers run twice to enable preload optimisations. Removes handlerWithLoader API, since it's not needed. (recommended, default: false)",
62
+ "type": [
63
+ "boolean",
64
+ "null"
65
+ ]
59
66
  }
60
67
  },
61
68
  "additionalProperties": false,
@@ -217,6 +224,15 @@
217
224
  "description": "A single address or a list of addresses to be indexed. This can be left as null in the case where this contracts addresses will be registered dynamically.",
218
225
  "$ref": "#/$defs/Addresses"
219
226
  },
227
+ "start_block": {
228
+ "description": "The block at which the indexer should start ingesting data for this specific contract. If not specified, uses the network start_block. Can be greater than the network start_block for more specific indexing.",
229
+ "type": [
230
+ "integer",
231
+ "null"
232
+ ],
233
+ "format": "uint64",
234
+ "minimum": 0
235
+ },
220
236
  "abi_file_path": {
221
237
  "description": "Relative path (from config) to a json abi.",
222
238
  "type": "string"
package/index.d.ts CHANGED
@@ -95,6 +95,7 @@ export function experimental_createEffect<
95
95
  // Important! Should match the index.js file
96
96
  export declare namespace S {
97
97
  export type Output<T> = Sury.Output<T>;
98
+ export type Infer<T> = Sury.Output<T>;
98
99
  export type Input<T> = Sury.Input<T>;
99
100
  export type Schema<Output, Input = unknown> = Sury.Schema<Output, Input>;
100
101
  export const string: typeof Sury.string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "envio",
3
- "version": "v2.26.0-rc.2",
3
+ "version": "v2.27.0",
4
4
  "description": "A latency and sync speed optimized, developer friendly blockchain data indexer.",
5
5
  "bin": "./bin.js",
6
6
  "main": "./index.js",
@@ -25,10 +25,10 @@
25
25
  },
26
26
  "homepage": "https://envio.dev",
27
27
  "optionalDependencies": {
28
- "envio-linux-x64": "v2.26.0-rc.2",
29
- "envio-linux-arm64": "v2.26.0-rc.2",
30
- "envio-darwin-x64": "v2.26.0-rc.2",
31
- "envio-darwin-arm64": "v2.26.0-rc.2"
28
+ "envio-linux-x64": "v2.27.0",
29
+ "envio-linux-arm64": "v2.27.0",
30
+ "envio-darwin-x64": "v2.27.0",
31
+ "envio-darwin-arm64": "v2.27.0"
32
32
  },
33
33
  "dependencies": {
34
34
  "@envio-dev/hypersync-client": "0.6.5",
@@ -0,0 +1,92 @@
1
+ type t = {
2
+ contractName: string,
3
+ eventName: string,
4
+ mutable handler: option<Internal.handler>,
5
+ mutable contractRegister: option<Internal.contractRegister>,
6
+ mutable eventOptions: option<Internal.eventOptions<Js.Json.t>>,
7
+ }
8
+
9
+ let getHandler = (t: t) => t.handler
10
+
11
+ let getContractRegister = (t: t) => t.contractRegister
12
+
13
+ let getEventFilters = (t: t) => t.eventOptions->Belt.Option.flatMap(value => value.eventFilters)
14
+
15
+ let isWildcard = (t: t) =>
16
+ t.eventOptions->Belt.Option.flatMap(value => value.wildcard)->Belt.Option.getWithDefault(false)
17
+
18
+ let hasRegistration = ({handler, contractRegister}) =>
19
+ handler->Belt.Option.isSome || contractRegister->Belt.Option.isSome
20
+
21
+ let make = (~contractName, ~eventName) => {
22
+ contractName,
23
+ eventName,
24
+ handler: None,
25
+ contractRegister: None,
26
+ eventOptions: None,
27
+ }
28
+
29
+ type eventNamespace = {contractName: string, eventName: string}
30
+ exception DuplicateEventRegistration(eventNamespace)
31
+
32
+ let setEventOptions = (t: t, ~eventOptions, ~logger=Logging.getLogger()) => {
33
+ switch eventOptions {
34
+ | Some(value) =>
35
+ let value =
36
+ value->(Utils.magic: Internal.eventOptions<'eventFilters> => Internal.eventOptions<Js.Json.t>)
37
+ switch t.eventOptions {
38
+ | None => t.eventOptions = Some(value)
39
+ | Some(existingValue) =>
40
+ if (
41
+ existingValue.wildcard !== value.wildcard ||
42
+ // TODO: Can improve the check by using deepEqual
43
+ existingValue.eventFilters !== value.eventFilters
44
+ ) {
45
+ let eventNamespace = {contractName: t.contractName, eventName: t.eventName}
46
+ DuplicateEventRegistration(eventNamespace)->ErrorHandling.mkLogAndRaise(
47
+ ~logger=Logging.createChildFrom(~logger, ~params=eventNamespace),
48
+ ~msg="Duplicate eventOptions in handlers not allowed",
49
+ )
50
+ }
51
+ }
52
+ | None => ()
53
+ }
54
+ }
55
+
56
+ let setHandler = (t: t, handler, ~eventOptions, ~logger=Logging.getLogger()) => {
57
+ switch t.handler {
58
+ | None =>
59
+ t.handler =
60
+ handler
61
+ ->(Utils.magic: Internal.genericHandler<'args> => Internal.handler)
62
+ ->Some
63
+ | Some(_) =>
64
+ let eventNamespace = {contractName: t.contractName, eventName: t.eventName}
65
+ DuplicateEventRegistration(eventNamespace)->ErrorHandling.mkLogAndRaise(
66
+ ~logger=Logging.createChildFrom(~logger, ~params=eventNamespace),
67
+ ~msg="Duplicate registration of event handlers not allowed",
68
+ )
69
+ }
70
+
71
+ t->setEventOptions(~eventOptions, ~logger)
72
+ }
73
+
74
+ let setContractRegister = (t: t, contractRegister, ~eventOptions, ~logger=Logging.getLogger()) => {
75
+ switch t.contractRegister {
76
+ | None =>
77
+ t.contractRegister = Some(
78
+ contractRegister->(
79
+ Utils.magic: Internal.genericContractRegister<
80
+ Internal.genericContractRegisterArgs<'event, 'context>,
81
+ > => Internal.contractRegister
82
+ ),
83
+ )
84
+ | Some(_) =>
85
+ let eventNamespace = {contractName: t.contractName, eventName: t.eventName}
86
+ DuplicateEventRegistration(eventNamespace)->ErrorHandling.mkLogAndRaise(
87
+ ~logger=Logging.createChildFrom(~logger, ~params=eventNamespace),
88
+ ~msg="Duplicate contractRegister handlers not allowed",
89
+ )
90
+ }
91
+ t->setEventOptions(~eventOptions, ~logger)
92
+ }
@@ -0,0 +1,124 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+ 'use strict';
3
+
4
+ var Logging = require("./Logging.res.js");
5
+ var Belt_Option = require("rescript/lib/js/belt_Option.js");
6
+ var ErrorHandling = require("./ErrorHandling.res.js");
7
+ var Caml_exceptions = require("rescript/lib/js/caml_exceptions.js");
8
+
9
+ function getHandler(t) {
10
+ return t.handler;
11
+ }
12
+
13
+ function getContractRegister(t) {
14
+ return t.contractRegister;
15
+ }
16
+
17
+ function getEventFilters(t) {
18
+ return Belt_Option.flatMap(t.eventOptions, (function (value) {
19
+ return value.eventFilters;
20
+ }));
21
+ }
22
+
23
+ function isWildcard(t) {
24
+ return Belt_Option.getWithDefault(Belt_Option.flatMap(t.eventOptions, (function (value) {
25
+ return value.wildcard;
26
+ })), false);
27
+ }
28
+
29
+ function hasRegistration(param) {
30
+ var handler = param.handler;
31
+ var contractRegister = param.contractRegister;
32
+ if (Belt_Option.isSome(handler)) {
33
+ return true;
34
+ } else {
35
+ return Belt_Option.isSome(contractRegister);
36
+ }
37
+ }
38
+
39
+ function make(contractName, eventName) {
40
+ return {
41
+ contractName: contractName,
42
+ eventName: eventName,
43
+ handler: undefined,
44
+ contractRegister: undefined,
45
+ eventOptions: undefined
46
+ };
47
+ }
48
+
49
+ var DuplicateEventRegistration = /* @__PURE__ */Caml_exceptions.create("EventRegister.DuplicateEventRegistration");
50
+
51
+ function setEventOptions(t, eventOptions, loggerOpt) {
52
+ var logger = loggerOpt !== undefined ? loggerOpt : Logging.getLogger();
53
+ if (eventOptions === undefined) {
54
+ return ;
55
+ }
56
+ var existingValue = t.eventOptions;
57
+ if (existingValue === undefined) {
58
+ t.eventOptions = eventOptions;
59
+ return ;
60
+ }
61
+ if (!(existingValue.wildcard !== eventOptions.wildcard || existingValue.eventFilters !== eventOptions.eventFilters)) {
62
+ return ;
63
+ }
64
+ var eventNamespace_contractName = t.contractName;
65
+ var eventNamespace_eventName = t.eventName;
66
+ var eventNamespace = {
67
+ contractName: eventNamespace_contractName,
68
+ eventName: eventNamespace_eventName
69
+ };
70
+ ErrorHandling.mkLogAndRaise(Logging.createChildFrom(logger, eventNamespace), "Duplicate eventOptions in handlers not allowed", {
71
+ RE_EXN_ID: DuplicateEventRegistration,
72
+ _1: eventNamespace
73
+ });
74
+ }
75
+
76
+ function setHandler(t, handler, eventOptions, loggerOpt) {
77
+ var logger = loggerOpt !== undefined ? loggerOpt : Logging.getLogger();
78
+ var match = t.handler;
79
+ if (match !== undefined) {
80
+ var eventNamespace_contractName = t.contractName;
81
+ var eventNamespace_eventName = t.eventName;
82
+ var eventNamespace = {
83
+ contractName: eventNamespace_contractName,
84
+ eventName: eventNamespace_eventName
85
+ };
86
+ ErrorHandling.mkLogAndRaise(Logging.createChildFrom(logger, eventNamespace), "Duplicate registration of event handlers not allowed", {
87
+ RE_EXN_ID: DuplicateEventRegistration,
88
+ _1: eventNamespace
89
+ });
90
+ } else {
91
+ t.handler = handler;
92
+ }
93
+ setEventOptions(t, eventOptions, logger);
94
+ }
95
+
96
+ function setContractRegister(t, contractRegister, eventOptions, loggerOpt) {
97
+ var logger = loggerOpt !== undefined ? loggerOpt : Logging.getLogger();
98
+ var match = t.contractRegister;
99
+ if (match !== undefined) {
100
+ var eventNamespace_contractName = t.contractName;
101
+ var eventNamespace_eventName = t.eventName;
102
+ var eventNamespace = {
103
+ contractName: eventNamespace_contractName,
104
+ eventName: eventNamespace_eventName
105
+ };
106
+ ErrorHandling.mkLogAndRaise(Logging.createChildFrom(logger, eventNamespace), "Duplicate contractRegister handlers not allowed", {
107
+ RE_EXN_ID: DuplicateEventRegistration,
108
+ _1: eventNamespace
109
+ });
110
+ } else {
111
+ t.contractRegister = contractRegister;
112
+ }
113
+ setEventOptions(t, eventOptions, logger);
114
+ }
115
+
116
+ exports.make = make;
117
+ exports.setHandler = setHandler;
118
+ exports.setContractRegister = setContractRegister;
119
+ exports.getHandler = getHandler;
120
+ exports.getContractRegister = getContractRegister;
121
+ exports.getEventFilters = getEventFilters;
122
+ exports.isWildcard = isWildcard;
123
+ exports.hasRegistration = hasRegistration;
124
+ /* Logging Not a pure module */
@@ -0,0 +1,21 @@
1
+ type t
2
+ let make: (~contractName: string, ~eventName: string) => t
3
+ let setHandler: (
4
+ t,
5
+ Internal.genericHandler<
6
+ Internal.genericHandlerArgs<'event, Internal.handlerContext, 'loaderReturn>,
7
+ >,
8
+ ~eventOptions: option<Internal.eventOptions<'eventFilters>>,
9
+ ~logger: Pino.t=?,
10
+ ) => unit
11
+ let setContractRegister: (
12
+ t,
13
+ Internal.genericContractRegister<Internal.genericContractRegisterArgs<'event, 'context>>,
14
+ ~eventOptions: option<Internal.eventOptions<'eventFilters>>,
15
+ ~logger: Pino.t=?,
16
+ ) => unit
17
+ let getHandler: t => option<Internal.handler>
18
+ let getContractRegister: t => option<Internal.contractRegister>
19
+ let getEventFilters: t => option<Js.Json.t>
20
+ let isWildcard: t => bool
21
+ let hasRegistration: t => bool
@@ -966,8 +966,7 @@ let make = (
966
966
  ~startBlock,
967
967
  ~endBlock,
968
968
  ~eventConfigs: array<Internal.eventConfig>,
969
- ~staticContracts: dict<array<Address.t>>,
970
- ~dynamicContracts: array<indexingContract>,
969
+ ~contracts: array<indexingContract>,
971
970
  ~maxAddrInPartition,
972
971
  ~chainId,
973
972
  ~blockLag=?,
@@ -1041,49 +1040,21 @@ let make = (
1041
1040
 
1042
1041
  let pendingNormalPartition = ref(makePendingNormalPartition())
1043
1042
 
1044
- let registerAddress = (contractName, address, ~dc: option<indexingContract>=?) => {
1045
- let pendingPartition = pendingNormalPartition.contents
1046
- switch pendingPartition.addressesByContractName->Utils.Dict.dangerouslyGetNonOption(
1047
- contractName,
1048
- ) {
1049
- | Some(addresses) => addresses->Array.push(address)
1050
- | None => pendingPartition.addressesByContractName->Js.Dict.set(contractName, [address])
1051
- }
1052
- indexingContracts->Js.Dict.set(
1053
- address->Address.toString,
1054
- switch dc {
1055
- | Some(dc) => dc
1056
- | None => {
1057
- address,
1058
- contractName,
1059
- startBlock,
1060
- register: Config,
1061
- }
1062
- },
1063
- )
1064
- if (
1065
- pendingPartition.addressesByContractName->addressesByContractNameCount ===
1066
- maxAddrInPartition
1067
- ) {
1068
- partitions->Array.push(pendingPartition)
1069
- pendingNormalPartition := makePendingNormalPartition()
1070
- }
1071
- }
1072
-
1073
- staticContracts
1074
- ->Js.Dict.entries
1075
- ->Array.forEach(((contractName, addresses)) => {
1076
- if contractNamesWithNormalEvents->Utils.Set.has(contractName) {
1077
- addresses->Array.forEach(a => {
1078
- registerAddress(contractName, a)
1079
- })
1080
- }
1081
- })
1082
-
1083
- dynamicContracts->Array.forEach(dc => {
1084
- let contractName = dc.contractName
1043
+ contracts->Array.forEach(contract => {
1044
+ let contractName = contract.contractName
1085
1045
  if contractNamesWithNormalEvents->Utils.Set.has(contractName) {
1086
- registerAddress(contractName, dc.address, ~dc)
1046
+ let pendingPartition = pendingNormalPartition.contents
1047
+ pendingPartition.addressesByContractName->Utils.Dict.push(contractName, contract.address)
1048
+ indexingContracts->Js.Dict.set(contract.address->Address.toString, contract)
1049
+ if (
1050
+ pendingPartition.addressesByContractName->addressesByContractNameCount ===
1051
+ maxAddrInPartition
1052
+ ) {
1053
+ // FIXME: should split into separate partitions
1054
+ // depending on the start block
1055
+ partitions->Array.push(pendingPartition)
1056
+ pendingNormalPartition := makePendingNormalPartition()
1057
+ }
1087
1058
  }
1088
1059
  })
1089
1060
 
@@ -698,7 +698,7 @@ function getEarliestEvent(param) {
698
698
  }
699
699
  }
700
700
 
701
- function make(startBlock, endBlock, eventConfigs, staticContracts, dynamicContracts, maxAddrInPartition, chainId, blockLag) {
701
+ function make(startBlock, endBlock, eventConfigs, contracts, maxAddrInPartition, chainId, blockLag) {
702
702
  var latestFetchedBlock_blockNumber = startBlock - 1 | 0;
703
703
  var latestFetchedBlock = {
704
704
  blockNumber: latestFetchedBlock_blockNumber,
@@ -761,40 +761,18 @@ function make(startBlock, endBlock, eventConfigs, staticContracts, dynamicContra
761
761
  var pendingNormalPartition = {
762
762
  contents: makePendingNormalPartition()
763
763
  };
764
- var registerAddress = function (contractName, address, dc) {
765
- var pendingPartition = pendingNormalPartition.contents;
766
- var addresses = pendingPartition.addressesByContractName[contractName];
767
- if (addresses !== undefined) {
768
- addresses.push(address);
769
- } else {
770
- pendingPartition.addressesByContractName[contractName] = [address];
771
- }
772
- indexingContracts[address] = dc !== undefined ? dc : ({
773
- address: address,
774
- contractName: contractName,
775
- startBlock: startBlock,
776
- register: "Config"
777
- });
778
- if (addressesByContractNameCount(pendingPartition.addressesByContractName) === maxAddrInPartition) {
779
- partitions.push(pendingPartition);
780
- pendingNormalPartition.contents = makePendingNormalPartition();
781
- return ;
782
- }
783
-
784
- };
785
- Belt_Array.forEach(Js_dict.entries(staticContracts), (function (param) {
786
- var contractName = param[0];
787
- if (contractNamesWithNormalEvents.has(contractName)) {
788
- return Belt_Array.forEach(param[1], (function (a) {
789
- registerAddress(contractName, a, undefined);
790
- }));
764
+ Belt_Array.forEach(contracts, (function (contract) {
765
+ var contractName = contract.contractName;
766
+ if (!contractNamesWithNormalEvents.has(contractName)) {
767
+ return ;
791
768
  }
792
-
793
- }));
794
- Belt_Array.forEach(dynamicContracts, (function (dc) {
795
- var contractName = dc.contractName;
796
- if (contractNamesWithNormalEvents.has(contractName)) {
797
- return registerAddress(contractName, dc.address, dc);
769
+ var pendingPartition = pendingNormalPartition.contents;
770
+ Utils.Dict.push(pendingPartition.addressesByContractName, contractName, contract.address);
771
+ indexingContracts[contract.address] = contract;
772
+ if (addressesByContractNameCount(pendingPartition.addressesByContractName) === maxAddrInPartition) {
773
+ partitions.push(pendingPartition);
774
+ pendingNormalPartition.contents = makePendingNormalPartition();
775
+ return ;
798
776
  }
799
777
 
800
778
  }));
@@ -34,6 +34,14 @@ export type genericHandlerArgs<event,context,loaderReturn> = {
34
34
 
35
35
  export type genericHandler<args> = (_1:args) => Promise<void>;
36
36
 
37
+ export type entityHandlerContext<entity> = {
38
+ readonly get: (_1:string) => Promise<(undefined | entity)>;
39
+ readonly getOrThrow: (_1:string, message:(undefined | string)) => Promise<entity>;
40
+ readonly getOrCreate: (_1:entity) => Promise<entity>;
41
+ readonly set: (_1:entity) => void;
42
+ readonly deleteUnsafe: (_1:string) => void
43
+ };
44
+
37
45
  export type genericHandlerWithLoader<loader,handler,eventFilters> = {
38
46
  readonly loader: loader;
39
47
  readonly handler: handler;
@@ -43,6 +51,13 @@ export type genericHandlerWithLoader<loader,handler,eventFilters> = {
43
51
  readonly preRegisterDynamicContracts?: boolean
44
52
  };
45
53
 
54
+ export type eventOptions<eventFilters> = {
55
+ readonly wildcard?: boolean;
56
+ readonly eventFilters?: eventFilters;
57
+ /** @deprecated The option is removed starting from v2.19 since we made the default mode even faster than pre-registration. */
58
+ readonly preRegisterDynamicContracts?: boolean
59
+ };
60
+
46
61
  export type fuelSupplyParams = { readonly subId: string; readonly amount: bigint };
47
62
 
48
63
  export type fuelTransferParams = {
package/src/Internal.res CHANGED
@@ -16,8 +16,6 @@ type event = genericEvent<eventParams, eventBlock, eventTransaction>
16
16
 
17
17
  external fromGenericEvent: genericEvent<'a, 'b, 'c> => event = "%identity"
18
18
 
19
- type loaderReturn
20
-
21
19
  @genType
22
20
  type genericLoaderArgs<'event, 'context> = {
23
21
  event: 'event,
@@ -26,10 +24,6 @@ type genericLoaderArgs<'event, 'context> = {
26
24
  @genType
27
25
  type genericLoader<'args, 'loaderReturn> = 'args => promise<'loaderReturn>
28
26
 
29
- type loaderContext
30
- type loaderArgs = genericLoaderArgs<event, loaderContext>
31
- type loader = genericLoader<loaderArgs, loaderReturn>
32
-
33
27
  @genType
34
28
  type genericContractRegisterArgs<'event, 'context> = {
35
29
  event: 'event,
@@ -51,8 +45,21 @@ type genericHandlerArgs<'event, 'context, 'loaderReturn> = {
51
45
  @genType
52
46
  type genericHandler<'args> = 'args => promise<unit>
53
47
 
54
- type handlerContext
55
- type handlerArgs = genericHandlerArgs<event, handlerContext, loaderReturn>
48
+ @genType
49
+ type entityHandlerContext<'entity> = {
50
+ get: string => promise<option<'entity>>,
51
+ getOrThrow: (string, ~message: string=?) => promise<'entity>,
52
+ getOrCreate: 'entity => promise<'entity>,
53
+ set: 'entity => unit,
54
+ deleteUnsafe: string => unit,
55
+ }
56
+
57
+ type loaderReturn
58
+ type handlerContext = private {isPreload: bool}
59
+ type handlerArgs = {
60
+ event: event,
61
+ context: handlerContext,
62
+ }
56
63
  type handler = genericHandler<handlerArgs>
57
64
 
58
65
  @genType
@@ -81,7 +88,6 @@ type eventConfig = private {
81
88
  // Usually always false for wildcard events
82
89
  // But might be true for wildcard event with dynamic event filter by addresses
83
90
  dependsOnAddresses: bool,
84
- loader: option<loader>,
85
91
  handler: option<handler>,
86
92
  contractRegister: option<contractRegister>,
87
93
  paramsRawEventSchema: S.schema<eventParams>,
@@ -138,6 +144,16 @@ type eventItem = {
138
144
  mutable loggerCache?: Pino.t,
139
145
  }
140
146
 
147
+ @genType
148
+ type eventOptions<'eventFilters> = {
149
+ wildcard?: bool,
150
+ eventFilters?: 'eventFilters,
151
+ /**
152
+ @deprecated The option is removed starting from v2.19 since we made the default mode even faster than pre-registration.
153
+ */
154
+ preRegisterDynamicContracts?: bool,
155
+ }
156
+
141
157
  @genType
142
158
  type fuelSupplyParams = {
143
159
  subId: string,
@@ -214,7 +230,7 @@ let makeCacheTable = (~effectName) => {
214
230
  cacheTablePrefix ++ effectName,
215
231
  ~fields=[
216
232
  Table.mkField("id", Text, ~fieldSchema=S.string, ~isPrimaryKey=true),
217
- Table.mkField("output", JsonB, ~fieldSchema=S.json(~validate=false)),
233
+ Table.mkField("output", JsonB, ~fieldSchema=S.json(~validate=false), ~isNullable=true),
218
234
  ],
219
235
  ~compositeIndices=[],
220
236
  )
@@ -40,7 +40,7 @@ var cacheTablePrefix = "envio_effect_";
40
40
  function makeCacheTable(effectName) {
41
41
  return Table.mkTable(cacheTablePrefix + effectName, [], [
42
42
  Table.mkField("id", "TEXT", S$RescriptSchema.string, undefined, undefined, undefined, true, undefined, undefined),
43
- Table.mkField("output", "JSONB", S$RescriptSchema.json(false), undefined, undefined, undefined, undefined, undefined, undefined)
43
+ Table.mkField("output", "JSONB", S$RescriptSchema.json(false), undefined, undefined, true, undefined, undefined, undefined)
44
44
  ]);
45
45
  }
46
46
 
package/src/Logging.res CHANGED
@@ -155,6 +155,7 @@ let getEventLogger = (eventItem: Internal.eventItem) => {
155
155
  "chainId": eventItem.chain->ChainMap.Chain.toChainId,
156
156
  "block": eventItem.blockNumber,
157
157
  "logIndex": eventItem.logIndex,
158
+ "address": eventItem.event.srcAddress,
158
159
  }->createChildParams,
159
160
  )
160
161
  eventItem.loggerCache = Some(l)
@@ -187,7 +187,8 @@ function getEventLogger(eventItem) {
187
187
  eventName: eventItem.eventConfig.name,
188
188
  chainId: eventItem.chain,
189
189
  block: eventItem.blockNumber,
190
- logIndex: eventItem.logIndex
190
+ logIndex: eventItem.logIndex,
191
+ address: eventItem.event.srcAddress
191
192
  }));
192
193
  eventItem.loggerCache = l$1;
193
194
  return l$1;
@@ -53,7 +53,11 @@ type storage = {
53
53
  ~items: array<Internal.effectCacheItem>,
54
54
  ~initialize: bool,
55
55
  ) => promise<unit>,
56
+ // This is to download cache from the database to .envio/cache
56
57
  dumpEffectCache: unit => promise<unit>,
58
+ // This is not good, but the function does two things:
59
+ // - Gets info about existing cache tables
60
+ // - if withUpload is true, it also populates the cache from .envio/cache to the database
57
61
  restoreEffectCache: (~withUpload: bool) => promise<array<effectCacheRecord>>,
58
62
  }
59
63
 
package/src/PgStorage.res CHANGED
@@ -1,3 +1,5 @@
1
+ let getCacheRowCountFnName = "get_cache_row_count"
2
+
1
3
  let makeCreateIndexQuery = (~tableName, ~indexFields, ~pgSchema) => {
2
4
  let indexName = tableName ++ "_" ++ indexFields->Js.Array2.joinWith("_")
3
5
  let index = indexFields->Belt.Array.map(idx => `"${idx}"`)->Js.Array2.joinWith(", ")
@@ -133,15 +135,15 @@ GRANT ALL ON SCHEMA "${pgSchema}" TO public;`,
133
135
  functionsQuery :=
134
136
  functionsQuery.contents ++
135
137
  "\n" ++
136
- `CREATE OR REPLACE FUNCTION get_cache_row_count(table_name text)
137
- RETURNS integer AS $$
138
- DECLARE
139
- result integer;
140
- BEGIN
141
- EXECUTE format('SELECT COUNT(*) FROM "${pgSchema}".%I', table_name) INTO result;
142
- RETURN result;
143
- END;
144
- $$ LANGUAGE plpgsql;`
138
+ `CREATE OR REPLACE FUNCTION ${getCacheRowCountFnName}(table_name text)
139
+ RETURNS integer AS $$
140
+ DECLARE
141
+ result integer;
142
+ BEGIN
143
+ EXECUTE format('SELECT COUNT(*) FROM "${pgSchema}".%I', table_name) INTO result;
144
+ RETURN result;
145
+ END;
146
+ $$ LANGUAGE plpgsql;`
145
147
 
146
148
  [query.contents]->Js.Array2.concat(
147
149
  functionsQuery.contents !== "" ? [functionsQuery.contents] : [],
@@ -445,7 +447,7 @@ type schemaCacheTableInfo = {
445
447
  let makeSchemaCacheTableInfoQuery = (~pgSchema) => {
446
448
  `SELECT
447
449
  t.table_name,
448
- get_cache_row_count(t.table_name) as count
450
+ ${getCacheRowCountFnName}(t.table_name) as count
449
451
  FROM information_schema.tables t
450
452
  WHERE t.table_schema = '${pgSchema}'
451
453
  AND t.table_name LIKE '${Internal.cacheTablePrefix}%';`
@@ -577,6 +579,7 @@ let make = (
577
579
  queries->Js.Array2.map(query => sql->Postgres.unsafe(query))
578
580
  })
579
581
 
582
+ // Integration with other tools like Hasura
580
583
  switch onInitialize {
581
584
  | Some(onInitialize) => await onInitialize()
582
585
  | None => ()
@@ -694,6 +697,7 @@ let make = (
694
697
 
695
698
  if initialize {
696
699
  let _ = await sql->Postgres.unsafe(makeCreateTableQuery(table, ~pgSchema))
700
+ // Integration with other tools like Hasura
697
701
  switch onNewTables {
698
702
  | Some(onNewTables) => await onNewTables(~tableNames=[table.tableName])
699
703
  | None => ()
@@ -828,6 +832,7 @@ let make = (
828
832
  await sql->Postgres.unsafe(makeSchemaCacheTableInfoQuery(~pgSchema))
829
833
 
830
834
  if withUpload && cacheTableInfo->Utils.Array.notEmpty {
835
+ // Integration with other tools like Hasura
831
836
  switch onNewTables {
832
837
  | Some(onNewTables) =>
833
838
  await onNewTables(
@@ -21,6 +21,8 @@ var Caml_exceptions = require("rescript/lib/js/caml_exceptions.js");
21
21
  var S$RescriptSchema = require("rescript-schema/src/S.res.js");
22
22
  var Caml_js_exceptions = require("rescript/lib/js/caml_js_exceptions.js");
23
23
 
24
+ var getCacheRowCountFnName = "get_cache_row_count";
25
+
24
26
  function makeCreateIndexQuery(tableName, indexFields, pgSchema) {
25
27
  var indexName = tableName + "_" + indexFields.join("_");
26
28
  var index = Belt_Array.map(indexFields, (function (idx) {
@@ -111,7 +113,7 @@ function makeInitializeTransaction(pgSchema, pgUser, generalTablesOpt, entitiesO
111
113
  query.contents = query.contents + "\n" + makeCreateIndexQuery(derivedFromField.derivedFromEntity, [indexField], pgSchema);
112
114
  });
113
115
  });
114
- functionsQuery.contents = functionsQuery.contents + "\n" + ("CREATE OR REPLACE FUNCTION get_cache_row_count(table_name text) \n RETURNS integer AS $$\n DECLARE\n result integer;\n BEGIN\n EXECUTE format('SELECT COUNT(*) FROM \"" + pgSchema + "\".%I', table_name) INTO result;\n RETURN result;\n END;\n $$ LANGUAGE plpgsql;");
116
+ functionsQuery.contents = functionsQuery.contents + "\n" + ("CREATE OR REPLACE FUNCTION " + getCacheRowCountFnName + "(table_name text) \nRETURNS integer AS $$\nDECLARE\n result integer;\nBEGIN\n EXECUTE format('SELECT COUNT(*) FROM \"" + pgSchema + "\".%I', table_name) INTO result;\n RETURN result;\nEND;\n$$ LANGUAGE plpgsql;");
115
117
  return [query.contents].concat(functionsQuery.contents !== "" ? [functionsQuery.contents] : []);
116
118
  }
117
119
 
@@ -299,7 +301,7 @@ function makeSchemaTableNamesQuery(pgSchema) {
299
301
  var cacheTablePrefixLength = Internal.cacheTablePrefix.length;
300
302
 
301
303
  function makeSchemaCacheTableInfoQuery(pgSchema) {
302
- return "SELECT \n t.table_name,\n get_cache_row_count(t.table_name) as count\n FROM information_schema.tables t\n WHERE t.table_schema = '" + pgSchema + "' \n AND t.table_name LIKE '" + Internal.cacheTablePrefix + "%';";
304
+ return "SELECT \n t.table_name,\n " + getCacheRowCountFnName + "(t.table_name) as count\n FROM information_schema.tables t\n WHERE t.table_schema = '" + pgSchema + "' \n AND t.table_name LIKE '" + Internal.cacheTablePrefix + "%';";
303
305
  }
304
306
 
305
307
  var psqlExecState = {
@@ -613,6 +615,7 @@ function make(sql, pgHost, pgSchema, pgPort, pgUser, pgDatabase, pgPassword, onI
613
615
 
614
616
  var maxItemsPerQuery = 500;
615
617
 
618
+ exports.getCacheRowCountFnName = getCacheRowCountFnName;
616
619
  exports.makeCreateIndexQuery = makeCreateIndexQuery;
617
620
  exports.makeCreateTableIndicesQuery = makeCreateTableIndicesQuery;
618
621
  exports.makeCreateTableQuery = makeCreateTableQuery;
package/src/Utils.res CHANGED
@@ -516,6 +516,12 @@ module Proxy = {
516
516
  }
517
517
 
518
518
  module Hash = {
519
+ let fail = name => {
520
+ Js.Exn.raiseError(
521
+ `Failed to get hash for ${name}. If you're using a custom Sury schema make it based on the string type with a decoder: const myTypeSchema = S.transform(S.string, undefined, (yourType) => yourType.toString())`,
522
+ )
523
+ }
524
+
519
525
  // Hash to JSON string. No specific reason for this,
520
526
  // just to stick to at least some sort of spec.
521
527
  // After Sury v11 is out we'll be able to do it with schema
@@ -546,13 +552,16 @@ module Hash = {
546
552
  if constructor === %raw(`Object`) {
547
553
  let hash = ref("{")
548
554
  let keys = any->Js.Dict.keys->Js.Array2.sortInPlace
555
+ let isFirst = ref(true)
549
556
  for i in 0 to keys->Js.Array2.length - 1 {
550
557
  let key = keys->Js.Array2.unsafe_get(i)
551
558
  let value = any->Js.Dict.unsafeGet(key)
552
- if i !== 0 {
553
- hash := hash.contents ++ ","
554
- }
555
559
  if value !== %raw(`undefined`) {
560
+ if isFirst.contents {
561
+ isFirst := false
562
+ } else {
563
+ hash := hash.contents ++ ","
564
+ }
556
565
  // Ideally should escape and wrap the key in double quotes
557
566
  // but since we don't need to decode the hash,
558
567
  // it's fine to keep it super simple
@@ -563,13 +572,13 @@ module Hash = {
563
572
  } else if constructor["name"] === "BigNumber" {
564
573
  `"${(any->magic)["toString"]()}"`
565
574
  } else {
566
- Js.Exn.raiseError(`Don't know how to serialize ${(constructor->magic)["name"]}`)
575
+ fail((constructor->magic)["name"])
567
576
  }
568
577
  }
569
578
  | "symbol"
570
579
  | "function" =>
571
580
  (any->magic)["toString"]()
572
- | typeof => Js.Exn.raiseError(`Don't know how to serialize ${typeof}`)
581
+ | typeof => fail(typeof)
573
582
  }
574
583
  }
575
584
  }
package/src/Utils.res.js CHANGED
@@ -452,6 +452,10 @@ var $$Map = {};
452
452
 
453
453
  var $$Proxy = {};
454
454
 
455
+ function fail(name) {
456
+ return Js_exn.raiseError("Failed to get hash for " + name + ". If you're using a custom Sury schema make it based on the string type with a decoder: const myTypeSchema = S.transform(S.string, undefined, (yourType) => yourType.toString())");
457
+ }
458
+
455
459
  function makeOrThrow(any) {
456
460
  var $$typeof = typeof any;
457
461
  switch ($$typeof) {
@@ -484,18 +488,21 @@ function makeOrThrow(any) {
484
488
  if (constructor.name === "BigNumber") {
485
489
  return "\"" + any.toString() + "\"";
486
490
  } else {
487
- return Js_exn.raiseError("Don't know how to serialize " + constructor.name);
491
+ return fail(constructor.name);
488
492
  }
489
493
  }
490
494
  var hash$1 = "{";
491
495
  var keys = Object.keys(any).sort();
496
+ var isFirst = true;
492
497
  for(var i$1 = 0 ,i_finish$1 = keys.length; i$1 < i_finish$1; ++i$1){
493
498
  var key = keys[i$1];
494
499
  var value = any[key];
495
- if (i$1 !== 0) {
496
- hash$1 = hash$1 + ",";
497
- }
498
500
  if (value !== undefined) {
501
+ if (isFirst) {
502
+ isFirst = false;
503
+ } else {
504
+ hash$1 = hash$1 + ",";
505
+ }
499
506
  hash$1 = hash$1 + ("\"" + key + "\":" + makeOrThrow(any[key]));
500
507
  }
501
508
 
@@ -509,11 +516,12 @@ function makeOrThrow(any) {
509
516
  case "undefined" :
510
517
  return "null";
511
518
  default:
512
- return Js_exn.raiseError("Don't know how to serialize " + $$typeof);
519
+ return fail($$typeof);
513
520
  }
514
521
  }
515
522
 
516
523
  var Hash = {
524
+ fail: fail,
517
525
  makeOrThrow: makeOrThrow
518
526
  };
519
527
 
@@ -4,6 +4,37 @@ type t
4
4
  type exitCode = | @as(0) Success | @as(1) Failure
5
5
  @send external exitWithCode: (t, exitCode) => unit = "exit"
6
6
 
7
+ module Util = {
8
+ @unboxed
9
+ type depth = Int(int) | @as(null) Null
10
+ @unboxed
11
+ type compact = Bool(bool) | Int(int)
12
+ @unboxed
13
+ type sorted = Bool(bool) | Fn((string, string) => int)
14
+ @unboxed
15
+ type getters = | @as(true) True | @as(false) False | @as("get") Get | @as("set") Set
16
+
17
+ @unbox
18
+ type inspectOptions = {
19
+ showHidden?: bool,
20
+ depth?: depth,
21
+ colors?: bool,
22
+ customInspect?: bool,
23
+ showProxy?: bool,
24
+ maxArrayLength?: int,
25
+ maxStringLength?: int,
26
+ breakLength?: int,
27
+ @as("compact") compact?: compact,
28
+ sorted?: sorted,
29
+ getters?: string,
30
+ numericSeparator?: bool,
31
+ }
32
+
33
+ @module("util") external inspect: ('a, inspectOptions) => string = "inspect"
34
+
35
+ let inspectObj = a => inspect(a, {showHidden: false, depth: Null, colors: true})
36
+ }
37
+
7
38
  module Process = {
8
39
  type t = {env: Js.Dict.t<string>}
9
40
  @module external process: t = "process"
@@ -1,6 +1,19 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
  'use strict';
3
3
 
4
+ var Util = require("util");
5
+
6
+ function inspectObj(a) {
7
+ return Util.inspect(a, {
8
+ showHidden: false,
9
+ depth: null,
10
+ colors: true
11
+ });
12
+ }
13
+
14
+ var Util$1 = {
15
+ inspectObj: inspectObj
16
+ };
4
17
 
5
18
  var Process = {};
6
19
 
@@ -14,8 +27,9 @@ var Fs = {
14
27
  Promises: Promises
15
28
  };
16
29
 
30
+ exports.Util = Util$1;
17
31
  exports.Process = Process;
18
32
  exports.ChildProcess = ChildProcess;
19
33
  exports.Path = Path;
20
34
  exports.Fs = Fs;
21
- /* No side effect */
35
+ /* util Not a pure module */
@@ -53,6 +53,8 @@ external race: array<t<'a>> => t<'a> = "race"
53
53
 
54
54
  external done: promise<'a> => unit = "%ignore"
55
55
 
56
+ external ignoreValue: promise<'a> => promise<unit> = "%identity"
57
+
56
58
  external unsafe_async: 'a => promise<'a> = "%identity"
57
59
  external unsafe_await: promise<'a> => 'a = "?await"
58
60