envio 3.0.0-alpha.3 → 3.0.0-alpha.5

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 (79) hide show
  1. package/README.md +2 -2
  2. package/evm.schema.json +0 -1
  3. package/index.d.ts +333 -2
  4. package/index.js +4 -0
  5. package/package.json +13 -6
  6. package/rescript.json +4 -1
  7. package/src/ChainFetcher.res +25 -1
  8. package/src/ChainFetcher.res.mjs +19 -1
  9. package/src/Config.res +212 -19
  10. package/src/Config.res.mjs +228 -29
  11. package/src/{Indexer.res → Ctx.res} +1 -1
  12. package/src/Ecosystem.res +2 -2
  13. package/src/Ecosystem.res.mjs +1 -1
  14. package/src/Envio.gen.ts +1 -1
  15. package/src/Envio.res +1 -1
  16. package/src/EventProcessing.res +18 -18
  17. package/src/EventProcessing.res.mjs +14 -14
  18. package/src/GlobalState.res +29 -35
  19. package/src/GlobalState.res.mjs +47 -47
  20. package/src/GlobalStateManager.res +68 -0
  21. package/src/GlobalStateManager.res.mjs +75 -0
  22. package/src/GlobalStateManager.resi +7 -0
  23. package/src/Internal.res +41 -1
  24. package/src/LogSelection.res +33 -27
  25. package/src/LogSelection.res.mjs +6 -0
  26. package/src/Main.res +342 -0
  27. package/src/Main.res.mjs +289 -0
  28. package/src/PgStorage.gen.ts +10 -0
  29. package/src/PgStorage.res +24 -2
  30. package/src/PgStorage.res.d.mts +5 -0
  31. package/src/PgStorage.res.mjs +22 -1
  32. package/src/Types.ts +1 -1
  33. package/src/UserContext.res +0 -1
  34. package/src/UserContext.res.mjs +0 -2
  35. package/src/Utils.res +28 -0
  36. package/src/Utils.res.mjs +18 -0
  37. package/src/bindings/ClickHouse.res +31 -1
  38. package/src/bindings/ClickHouse.res.mjs +27 -1
  39. package/src/bindings/Ethers.res +27 -67
  40. package/src/bindings/Ethers.res.mjs +18 -70
  41. package/src/bindings/Postgres.gen.ts +8 -0
  42. package/src/bindings/Postgres.res +3 -0
  43. package/src/bindings/Postgres.res.d.mts +5 -0
  44. package/src/bindings/RescriptMocha.res +123 -0
  45. package/src/bindings/RescriptMocha.res.mjs +18 -0
  46. package/src/bindings/Yargs.res +8 -0
  47. package/src/bindings/Yargs.res.mjs +2 -0
  48. package/src/sources/FuelSDK.res +4 -3
  49. package/src/sources/HyperSyncHeightStream.res +28 -110
  50. package/src/sources/HyperSyncHeightStream.res.mjs +30 -63
  51. package/src/sources/HyperSyncSource.res +11 -13
  52. package/src/sources/HyperSyncSource.res.mjs +20 -20
  53. package/src/sources/Rpc.res +43 -0
  54. package/src/sources/Rpc.res.mjs +31 -0
  55. package/src/sources/RpcSource.res +9 -4
  56. package/src/sources/RpcSource.res.mjs +9 -4
  57. package/src/sources/Source.res +1 -0
  58. package/src/sources/SourceManager.res +164 -81
  59. package/src/sources/SourceManager.res.mjs +146 -83
  60. package/src/sources/{Solana.res → Svm.res} +4 -4
  61. package/src/sources/{Solana.res.mjs → Svm.res.mjs} +4 -4
  62. package/src/tui/Tui.res +266 -0
  63. package/src/tui/Tui.res.mjs +342 -0
  64. package/src/tui/bindings/Ink.res +376 -0
  65. package/src/tui/bindings/Ink.res.mjs +75 -0
  66. package/src/tui/bindings/Style.res +123 -0
  67. package/src/tui/bindings/Style.res.mjs +2 -0
  68. package/src/tui/components/BufferedProgressBar.res +40 -0
  69. package/src/tui/components/BufferedProgressBar.res.mjs +57 -0
  70. package/src/tui/components/CustomHooks.res +114 -0
  71. package/src/tui/components/CustomHooks.res.mjs +162 -0
  72. package/src/tui/components/Messages.res +41 -0
  73. package/src/tui/components/Messages.res.mjs +75 -0
  74. package/src/tui/components/SyncETA.res +193 -0
  75. package/src/tui/components/SyncETA.res.mjs +269 -0
  76. package/src/tui/components/TuiData.res +46 -0
  77. package/src/tui/components/TuiData.res.mjs +29 -0
  78. package/src/bindings/Ethers.gen.ts +0 -14
  79. /package/src/{Indexer.res.mjs → Ctx.res.mjs} +0 -0
package/src/Main.res ADDED
@@ -0,0 +1,342 @@
1
+ open Belt
2
+
3
+ type chainData = {
4
+ chainId: float,
5
+ poweredByHyperSync: bool,
6
+ firstEventBlockNumber: option<int>,
7
+ latestProcessedBlock: option<int>,
8
+ timestampCaughtUpToHeadOrEndblock: option<Js.Date.t>,
9
+ numEventsProcessed: int,
10
+ latestFetchedBlockNumber: int,
11
+ // Need this for API backwards compatibility
12
+ @as("currentBlockHeight")
13
+ knownHeight: int,
14
+ numBatchesFetched: int,
15
+ endBlock: option<int>,
16
+ numAddresses: int,
17
+ }
18
+ @tag("status")
19
+ type state =
20
+ | @as("disabled") Disabled({})
21
+ | @as("initializing") Initializing({})
22
+ | @as("active")
23
+ Active({
24
+ envioVersion: string,
25
+ chains: array<chainData>,
26
+ indexerStartTime: Js.Date.t,
27
+ isPreRegisteringDynamicContracts: bool,
28
+ isUnorderedMultichainMode: bool,
29
+ rollbackOnReorg: bool,
30
+ })
31
+
32
+ let chainDataSchema = S.schema((s): chainData => {
33
+ chainId: s.matches(S.float),
34
+ poweredByHyperSync: s.matches(S.bool),
35
+ firstEventBlockNumber: s.matches(S.option(S.int)),
36
+ latestProcessedBlock: s.matches(S.option(S.int)),
37
+ timestampCaughtUpToHeadOrEndblock: s.matches(S.option(S.datetime(S.string))),
38
+ numEventsProcessed: s.matches(S.int),
39
+ latestFetchedBlockNumber: s.matches(S.int),
40
+ knownHeight: s.matches(S.int),
41
+ numBatchesFetched: s.matches(S.int),
42
+ endBlock: s.matches(S.option(S.int)),
43
+ numAddresses: s.matches(S.int),
44
+ })
45
+ let stateSchema = S.union([
46
+ S.literal(Disabled({})),
47
+ S.literal(Initializing({})),
48
+ S.schema(s => Active({
49
+ envioVersion: s.matches(S.string),
50
+ chains: s.matches(S.array(chainDataSchema)),
51
+ indexerStartTime: s.matches(S.datetime(S.string)),
52
+ // Keep the field, since Dev Console expects it to be present
53
+ isPreRegisteringDynamicContracts: false,
54
+ isUnorderedMultichainMode: s.matches(S.bool),
55
+ rollbackOnReorg: s.matches(S.bool),
56
+ })),
57
+ ])
58
+
59
+ let globalGsManagerRef: ref<option<GlobalStateManager.t>> = ref(None)
60
+
61
+ let getGlobalIndexer = (~config: Config.t): 'indexer => {
62
+ let indexer = Utils.Object.createNullObject()
63
+
64
+ indexer
65
+ ->Utils.Object.definePropertyWithValue("name", {enumerable: true, value: config.name})
66
+ ->Utils.Object.definePropertyWithValue(
67
+ "description",
68
+ {enumerable: true, value: config.description},
69
+ )
70
+ ->ignore
71
+
72
+ let chainIds = []
73
+
74
+ // Build chains object with chain ID as string key
75
+ let chains = Utils.Object.createNullObject()
76
+ config.chainMap
77
+ ->ChainMap.values
78
+ ->Array.forEach(chainConfig => {
79
+ let chainIdStr = chainConfig.id->Int.toString
80
+
81
+ chainIds->Js.Array2.push(chainConfig.id)->ignore
82
+
83
+ let chainObj = Utils.Object.createNullObject()
84
+ chainObj
85
+ ->Utils.Object.definePropertyWithValue("id", {enumerable: true, value: chainConfig.id})
86
+ ->Utils.Object.definePropertyWithValue(
87
+ "startBlock",
88
+ {enumerable: true, value: chainConfig.startBlock},
89
+ )
90
+ ->Utils.Object.definePropertyWithValue(
91
+ "endBlock",
92
+ {enumerable: true, value: chainConfig.endBlock},
93
+ )
94
+ ->Utils.Object.definePropertyWithValue("name", {enumerable: true, value: chainConfig.name})
95
+ ->Utils.Object.defineProperty(
96
+ "isLive",
97
+ {
98
+ enumerable: true,
99
+ get: () => {
100
+ switch globalGsManagerRef.contents {
101
+ | None => false
102
+ | Some(gsManager) =>
103
+ let state = gsManager->GlobalStateManager.getState
104
+ let chain = ChainMap.Chain.makeUnsafe(~chainId=chainConfig.id)
105
+ let chainFetcher = state.chainManager.chainFetchers->ChainMap.get(chain)
106
+ chainFetcher->ChainFetcher.isLive
107
+ }
108
+ },
109
+ },
110
+ )
111
+ ->ignore
112
+
113
+ // Add contracts to chain object
114
+ chainConfig.contracts->Array.forEach(contract => {
115
+ let contractObj = Utils.Object.createNullObject()
116
+ contractObj
117
+ ->Utils.Object.definePropertyWithValue("name", {enumerable: true, value: contract.name})
118
+ ->Utils.Object.definePropertyWithValue("abi", {enumerable: true, value: contract.abi})
119
+ ->Utils.Object.defineProperty(
120
+ "addresses",
121
+ {
122
+ enumerable: true,
123
+ get: () => {
124
+ switch globalGsManagerRef.contents {
125
+ | None => contract.addresses
126
+ | Some(gsManager) => {
127
+ let state = gsManager->GlobalStateManager.getState
128
+ let chain = ChainMap.Chain.makeUnsafe(~chainId=chainConfig.id)
129
+ let chainFetcher = state.chainManager.chainFetchers->ChainMap.get(chain)
130
+ let indexingContracts = chainFetcher.fetchState.indexingContracts
131
+
132
+ // Collect all addresses for this contract name from indexingContracts
133
+ let addresses = []
134
+ let values = indexingContracts->Js.Dict.values
135
+ for idx in 0 to values->Array.length - 1 {
136
+ let indexingContract = values->Js.Array2.unsafe_get(idx)
137
+ if indexingContract.contractName === contract.name {
138
+ addresses->Array.push(indexingContract.address)->ignore
139
+ }
140
+ }
141
+ addresses
142
+ }
143
+ }
144
+ },
145
+ },
146
+ )
147
+ ->ignore
148
+
149
+ chainObj
150
+ ->Utils.Object.definePropertyWithValue(contract.name, {enumerable: true, value: contractObj})
151
+ ->ignore
152
+ })
153
+
154
+ // Primary key is chain ID as string
155
+ chains
156
+ ->Utils.Object.definePropertyWithValue(chainIdStr, {enumerable: true, value: chainObj})
157
+ ->ignore
158
+
159
+ // If chain has a name different from ID, add non-enumerable alias
160
+ if chainConfig.name !== chainIdStr {
161
+ chains
162
+ ->Utils.Object.definePropertyWithValue(chainConfig.name, {enumerable: false, value: chainObj})
163
+ ->ignore
164
+ }
165
+ })
166
+ indexer
167
+ ->Utils.Object.definePropertyWithValue("chainIds", {enumerable: true, value: chainIds})
168
+ ->ignore
169
+ indexer->Utils.Object.definePropertyWithValue("chains", {enumerable: true, value: chains})->ignore
170
+
171
+ indexer->Utils.magic
172
+ }
173
+
174
+ let startServer = (~getState, ~ctx: Ctx.t, ~isDevelopmentMode: bool) => {
175
+ open Express
176
+
177
+ let app = make()
178
+
179
+ let consoleCorsMiddleware = (req, res, next) => {
180
+ switch req.headers->Js.Dict.get("origin") {
181
+ | Some(origin) if origin === Env.prodEnvioAppUrl || origin === Env.envioAppUrl =>
182
+ res->setHeader("Access-Control-Allow-Origin", origin)
183
+ | _ => ()
184
+ }
185
+
186
+ res->setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
187
+ res->setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept")
188
+
189
+ if req.method === Rest.Options {
190
+ res->sendStatus(200)
191
+ } else {
192
+ next()
193
+ }
194
+ }
195
+ app->useFor("/console", consoleCorsMiddleware)
196
+ app->useFor("/metrics", consoleCorsMiddleware)
197
+
198
+ app->get("/healthz", (_req, res) => {
199
+ // this is the machine readable port used in kubernetes to check the health of this service.
200
+ // aditional health information could be added in the future (info about errors, back-offs, etc).
201
+ res->sendStatus(200)
202
+ })
203
+
204
+ app->get("/console/state", (_req, res) => {
205
+ let state = if isDevelopmentMode {
206
+ getState()
207
+ } else {
208
+ Disabled({})
209
+ }
210
+
211
+ res->json(state->S.reverseConvertToJsonOrThrow(stateSchema))
212
+ })
213
+
214
+ app->post("/console/syncCache", (_req, res) => {
215
+ if isDevelopmentMode {
216
+ (ctx.persistence->Persistence.getInitializedStorageOrThrow).dumpEffectCache()
217
+ ->Promise.thenResolve(_ => res->json(Boolean(true)))
218
+ ->Promise.done
219
+ } else {
220
+ res->json(Boolean(false))
221
+ }
222
+ })
223
+
224
+ PromClient.collectDefaultMetrics()
225
+
226
+ app->get("/metrics", (_req, res) => {
227
+ res->set("Content-Type", PromClient.defaultRegister->PromClient.getContentType)
228
+ let _ =
229
+ PromClient.defaultRegister
230
+ ->PromClient.metrics
231
+ ->Promise.thenResolve(metrics => res->endWithData(metrics))
232
+ })
233
+
234
+ let _ = app->listen(Env.serverPort)
235
+ }
236
+
237
+ type args = {@as("tui-off") tuiOff?: bool}
238
+
239
+ type process
240
+ @val external process: process = "process"
241
+ @get external argv: process => 'a = "argv"
242
+
243
+ type mainArgs = Yargs.parsedArgs<args>
244
+
245
+ let start = async (
246
+ ~registerAllHandlers: unit => promise<EventRegister.registrations>,
247
+ ~makeGeneratedConfig: unit => Config.t,
248
+ ~persistence: Persistence.t,
249
+ ) => {
250
+ let mainArgs: mainArgs = process->argv->Yargs.hideBin->Yargs.yargs->Yargs.argv
251
+ let shouldUseTui = !(mainArgs.tuiOff->Belt.Option.getWithDefault(Env.tuiOffEnvVar))
252
+ // The most simple check to verify whether we are running in development mode
253
+ // and prevent exposing the console to public, when creating a real deployment.
254
+ let isDevelopmentMode = Env.Db.password === "testing"
255
+
256
+ let registrations = await registerAllHandlers()
257
+ let config = makeGeneratedConfig()
258
+ let ctx = {
259
+ Ctx.registrations,
260
+ config,
261
+ persistence,
262
+ }
263
+
264
+ let envioVersion = Utils.EnvioPackage.value.version
265
+ Prometheus.Info.set(~version=envioVersion)
266
+ Prometheus.RollbackEnabled.set(~enabled=ctx.config.shouldRollbackOnReorg)
267
+
268
+ startServer(~ctx, ~isDevelopmentMode, ~getState=() =>
269
+ switch globalGsManagerRef.contents {
270
+ | None => Initializing({})
271
+ | Some(gsManager) => {
272
+ let state = gsManager->GlobalStateManager.getState
273
+ let chains =
274
+ state.chainManager.chainFetchers
275
+ ->ChainMap.values
276
+ ->Array.map(cf => {
277
+ let {fetchState} = cf
278
+ let latestFetchedBlockNumber = Pervasives.max(
279
+ FetchState.bufferBlockNumber(fetchState),
280
+ 0,
281
+ )
282
+ let knownHeight =
283
+ cf->ChainFetcher.hasProcessedToEndblock
284
+ ? cf.fetchState.endBlock->Option.getWithDefault(cf.fetchState.knownHeight)
285
+ : cf.fetchState.knownHeight
286
+
287
+ {
288
+ chainId: cf.chainConfig.id->Js.Int.toFloat,
289
+ poweredByHyperSync: (
290
+ cf.sourceManager->SourceManager.getActiveSource
291
+ ).poweredByHyperSync,
292
+ latestFetchedBlockNumber,
293
+ knownHeight,
294
+ numBatchesFetched: cf.numBatchesFetched,
295
+ endBlock: cf.fetchState.endBlock,
296
+ firstEventBlockNumber: cf.firstEventBlockNumber,
297
+ latestProcessedBlock: cf.committedProgressBlockNumber === -1
298
+ ? None
299
+ : Some(cf.committedProgressBlockNumber),
300
+ timestampCaughtUpToHeadOrEndblock: cf.timestampCaughtUpToHeadOrEndblock,
301
+ numEventsProcessed: cf.numEventsProcessed,
302
+ numAddresses: cf.fetchState->FetchState.numAddresses,
303
+ }
304
+ })
305
+ Active({
306
+ envioVersion,
307
+ chains,
308
+ indexerStartTime: state.indexerStartTime,
309
+ isPreRegisteringDynamicContracts: false,
310
+ rollbackOnReorg: ctx.config.shouldRollbackOnReorg,
311
+ isUnorderedMultichainMode: switch ctx.config.multichain {
312
+ | Unordered => true
313
+ | Ordered => false
314
+ },
315
+ })
316
+ }
317
+ }
318
+ )
319
+
320
+ await ctx.persistence->Persistence.init(~chainConfigs=ctx.config.chainMap->ChainMap.values)
321
+
322
+ let chainManager = await ChainManager.makeFromDbState(
323
+ ~initialState=ctx.persistence->Persistence.getInitializedState,
324
+ ~config=ctx.config,
325
+ ~registrations=ctx.registrations,
326
+ ~persistence=ctx.persistence,
327
+ )
328
+ let globalState = GlobalState.make(~ctx, ~chainManager, ~isDevelopmentMode, ~shouldUseTui)
329
+ let gsManager = globalState->GlobalStateManager.make
330
+ if shouldUseTui {
331
+ let _rerender = Tui.start(~getState=() => gsManager->GlobalStateManager.getState)
332
+ }
333
+ globalGsManagerRef := Some(gsManager)
334
+ gsManager->GlobalStateManager.dispatchTask(NextQuery(CheckAllChains))
335
+ /*
336
+ NOTE:
337
+ This `ProcessEventBatch` dispatch shouldn't be necessary but we are adding for safety, it should immediately return doing
338
+ nothing since there is no events on the queues.
339
+ */
340
+
341
+ gsManager->GlobalStateManager.dispatchTask(ProcessEventBatch)
342
+ }
@@ -0,0 +1,289 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Env from "./Env.res.mjs";
4
+ import * as Tui from "./tui/Tui.res.mjs";
5
+ import * as Caml from "rescript/lib/es6/caml.js";
6
+ import * as Utils from "./Utils.res.mjs";
7
+ import * as Js_dict from "rescript/lib/es6/js_dict.js";
8
+ import Express from "express";
9
+ import * as ChainMap from "./ChainMap.res.mjs";
10
+ import * as Belt_Array from "rescript/lib/es6/belt_Array.js";
11
+ import * as FetchState from "./FetchState.res.mjs";
12
+ import * as Prometheus from "./Prometheus.res.mjs";
13
+ import * as Belt_Option from "rescript/lib/es6/belt_Option.js";
14
+ import * as Caml_option from "rescript/lib/es6/caml_option.js";
15
+ import * as GlobalState from "./GlobalState.res.mjs";
16
+ import * as Persistence from "./Persistence.res.mjs";
17
+ import * as PromClient from "prom-client";
18
+ import Yargs from "yargs/yargs";
19
+ import * as ChainFetcher from "./ChainFetcher.res.mjs";
20
+ import * as ChainManager from "./ChainManager.res.mjs";
21
+ import * as SourceManager from "./sources/SourceManager.res.mjs";
22
+ import * as Helpers from "yargs/helpers";
23
+ import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
24
+ import * as GlobalStateManager from "./GlobalStateManager.res.mjs";
25
+
26
+ var chainDataSchema = S$RescriptSchema.schema(function (s) {
27
+ return {
28
+ chainId: s.m(S$RescriptSchema.$$float),
29
+ poweredByHyperSync: s.m(S$RescriptSchema.bool),
30
+ firstEventBlockNumber: s.m(S$RescriptSchema.option(S$RescriptSchema.$$int)),
31
+ latestProcessedBlock: s.m(S$RescriptSchema.option(S$RescriptSchema.$$int)),
32
+ timestampCaughtUpToHeadOrEndblock: s.m(S$RescriptSchema.option(S$RescriptSchema.datetime(S$RescriptSchema.string, undefined))),
33
+ numEventsProcessed: s.m(S$RescriptSchema.$$int),
34
+ latestFetchedBlockNumber: s.m(S$RescriptSchema.$$int),
35
+ currentBlockHeight: s.m(S$RescriptSchema.$$int),
36
+ numBatchesFetched: s.m(S$RescriptSchema.$$int),
37
+ endBlock: s.m(S$RescriptSchema.option(S$RescriptSchema.$$int)),
38
+ numAddresses: s.m(S$RescriptSchema.$$int)
39
+ };
40
+ });
41
+
42
+ var stateSchema = S$RescriptSchema.union([
43
+ S$RescriptSchema.literal({
44
+ status: "disabled"
45
+ }),
46
+ S$RescriptSchema.literal({
47
+ status: "initializing"
48
+ }),
49
+ S$RescriptSchema.schema(function (s) {
50
+ return {
51
+ status: "active",
52
+ envioVersion: s.m(S$RescriptSchema.string),
53
+ chains: s.m(S$RescriptSchema.array(chainDataSchema)),
54
+ indexerStartTime: s.m(S$RescriptSchema.datetime(S$RescriptSchema.string, undefined)),
55
+ isPreRegisteringDynamicContracts: false,
56
+ isUnorderedMultichainMode: s.m(S$RescriptSchema.bool),
57
+ rollbackOnReorg: s.m(S$RescriptSchema.bool)
58
+ };
59
+ })
60
+ ]);
61
+
62
+ var globalGsManagerRef = {
63
+ contents: undefined
64
+ };
65
+
66
+ function getGlobalIndexer(config) {
67
+ var indexer = Object.create(null);
68
+ Object.defineProperty(Object.defineProperty(indexer, "name", {
69
+ enumerable: true,
70
+ value: config.name
71
+ }), "description", {
72
+ enumerable: true,
73
+ value: config.description
74
+ });
75
+ var chainIds = [];
76
+ var chains = Object.create(null);
77
+ Belt_Array.forEach(ChainMap.values(config.chainMap), (function (chainConfig) {
78
+ var chainIdStr = String(chainConfig.id);
79
+ chainIds.push(chainConfig.id);
80
+ var chainObj = Object.create(null);
81
+ Object.defineProperty(Object.defineProperty(Object.defineProperty(Object.defineProperty(Object.defineProperty(chainObj, "id", {
82
+ enumerable: true,
83
+ value: chainConfig.id
84
+ }), "startBlock", {
85
+ enumerable: true,
86
+ value: chainConfig.startBlock
87
+ }), "endBlock", {
88
+ enumerable: true,
89
+ value: chainConfig.endBlock
90
+ }), "name", {
91
+ enumerable: true,
92
+ value: chainConfig.name
93
+ }), "isLive", {
94
+ enumerable: true,
95
+ get: (function () {
96
+ var gsManager = globalGsManagerRef.contents;
97
+ if (gsManager === undefined) {
98
+ return false;
99
+ }
100
+ var state = GlobalStateManager.getState(Caml_option.valFromOption(gsManager));
101
+ var chain = ChainMap.Chain.makeUnsafe(chainConfig.id);
102
+ var chainFetcher = ChainMap.get(state.chainManager.chainFetchers, chain);
103
+ return ChainFetcher.isLive(chainFetcher);
104
+ })
105
+ });
106
+ Belt_Array.forEach(chainConfig.contracts, (function (contract) {
107
+ var contractObj = Object.create(null);
108
+ Object.defineProperty(Object.defineProperty(Object.defineProperty(contractObj, "name", {
109
+ enumerable: true,
110
+ value: contract.name
111
+ }), "abi", {
112
+ enumerable: true,
113
+ value: contract.abi
114
+ }), "addresses", {
115
+ enumerable: true,
116
+ get: (function () {
117
+ var gsManager = globalGsManagerRef.contents;
118
+ if (gsManager === undefined) {
119
+ return contract.addresses;
120
+ }
121
+ var state = GlobalStateManager.getState(Caml_option.valFromOption(gsManager));
122
+ var chain = ChainMap.Chain.makeUnsafe(chainConfig.id);
123
+ var chainFetcher = ChainMap.get(state.chainManager.chainFetchers, chain);
124
+ var indexingContracts = chainFetcher.fetchState.indexingContracts;
125
+ var addresses = [];
126
+ var values = Js_dict.values(indexingContracts);
127
+ for(var idx = 0 ,idx_finish = values.length; idx < idx_finish; ++idx){
128
+ var indexingContract = values[idx];
129
+ if (indexingContract.contractName === contract.name) {
130
+ addresses.push(indexingContract.address);
131
+ }
132
+
133
+ }
134
+ return addresses;
135
+ })
136
+ });
137
+ Object.defineProperty(chainObj, contract.name, {
138
+ enumerable: true,
139
+ value: contractObj
140
+ });
141
+ }));
142
+ Object.defineProperty(chains, chainIdStr, {
143
+ enumerable: true,
144
+ value: chainObj
145
+ });
146
+ if (chainConfig.name !== chainIdStr) {
147
+ Object.defineProperty(chains, chainConfig.name, {
148
+ enumerable: false,
149
+ value: chainObj
150
+ });
151
+ return ;
152
+ }
153
+
154
+ }));
155
+ Object.defineProperty(indexer, "chainIds", {
156
+ enumerable: true,
157
+ value: chainIds
158
+ });
159
+ Object.defineProperty(indexer, "chains", {
160
+ enumerable: true,
161
+ value: chains
162
+ });
163
+ return indexer;
164
+ }
165
+
166
+ function startServer(getState, ctx, isDevelopmentMode) {
167
+ var app = Express();
168
+ var consoleCorsMiddleware = function (req, res, next) {
169
+ var origin = Js_dict.get(req.headers, "origin");
170
+ if (origin !== undefined && (origin === Env.prodEnvioAppUrl || origin === Env.envioAppUrl)) {
171
+ res.setHeader("Access-Control-Allow-Origin", origin);
172
+ }
173
+ res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
174
+ res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
175
+ if (req.method === "OPTIONS") {
176
+ res.sendStatus(200);
177
+ return ;
178
+ } else {
179
+ return next();
180
+ }
181
+ };
182
+ app.use("/console", consoleCorsMiddleware);
183
+ app.use("/metrics", consoleCorsMiddleware);
184
+ app.get("/healthz", (function (_req, res) {
185
+ res.sendStatus(200);
186
+ }));
187
+ app.get("/console/state", (function (_req, res) {
188
+ var state = isDevelopmentMode ? getState() : ({
189
+ status: "disabled"
190
+ });
191
+ res.json(S$RescriptSchema.reverseConvertToJsonOrThrow(state, stateSchema));
192
+ }));
193
+ app.post("/console/syncCache", (function (_req, res) {
194
+ if (isDevelopmentMode) {
195
+ Persistence.getInitializedStorageOrThrow(ctx.persistence).dumpEffectCache().then(function () {
196
+ res.json(true);
197
+ });
198
+ } else {
199
+ res.json(false);
200
+ }
201
+ }));
202
+ PromClient.collectDefaultMetrics();
203
+ app.get("/metrics", (function (_req, res) {
204
+ res.set("Content-Type", PromClient.register.contentType);
205
+ PromClient.register.metrics().then(function (metrics) {
206
+ return res.end(metrics);
207
+ });
208
+ }));
209
+ app.listen(Env.serverPort);
210
+ }
211
+
212
+ async function start(registerAllHandlers, makeGeneratedConfig, persistence) {
213
+ var mainArgs = Yargs(Helpers.hideBin(process.argv)).argv;
214
+ var shouldUseTui = !Belt_Option.getWithDefault(mainArgs["tui-off"], Env.tuiOffEnvVar);
215
+ var isDevelopmentMode = Env.Db.password === "testing";
216
+ var registrations = await registerAllHandlers();
217
+ var config = makeGeneratedConfig();
218
+ var ctx = {
219
+ registrations: registrations,
220
+ config: config,
221
+ persistence: persistence
222
+ };
223
+ var envioVersion = Utils.EnvioPackage.value.version;
224
+ Prometheus.Info.set(envioVersion);
225
+ Prometheus.RollbackEnabled.set(config.shouldRollbackOnReorg);
226
+ startServer((function () {
227
+ var gsManager = globalGsManagerRef.contents;
228
+ if (gsManager === undefined) {
229
+ return {
230
+ status: "initializing"
231
+ };
232
+ }
233
+ var state = GlobalStateManager.getState(Caml_option.valFromOption(gsManager));
234
+ var chains = Belt_Array.map(ChainMap.values(state.chainManager.chainFetchers), (function (cf) {
235
+ var latestFetchedBlockNumber = Caml.int_max(FetchState.bufferBlockNumber(cf.fetchState), 0);
236
+ var knownHeight = ChainFetcher.hasProcessedToEndblock(cf) ? Belt_Option.getWithDefault(cf.fetchState.endBlock, cf.fetchState.knownHeight) : cf.fetchState.knownHeight;
237
+ return {
238
+ chainId: cf.chainConfig.id,
239
+ poweredByHyperSync: SourceManager.getActiveSource(cf.sourceManager).poweredByHyperSync,
240
+ firstEventBlockNumber: cf.firstEventBlockNumber,
241
+ latestProcessedBlock: cf.committedProgressBlockNumber === -1 ? undefined : cf.committedProgressBlockNumber,
242
+ timestampCaughtUpToHeadOrEndblock: cf.timestampCaughtUpToHeadOrEndblock,
243
+ numEventsProcessed: cf.numEventsProcessed,
244
+ latestFetchedBlockNumber: latestFetchedBlockNumber,
245
+ currentBlockHeight: knownHeight,
246
+ numBatchesFetched: cf.numBatchesFetched,
247
+ endBlock: cf.fetchState.endBlock,
248
+ numAddresses: FetchState.numAddresses(cf.fetchState)
249
+ };
250
+ }));
251
+ var match = config.multichain;
252
+ var tmp;
253
+ tmp = match === "ordered" ? false : true;
254
+ return {
255
+ status: "active",
256
+ envioVersion: envioVersion,
257
+ chains: chains,
258
+ indexerStartTime: state.indexerStartTime,
259
+ isPreRegisteringDynamicContracts: false,
260
+ isUnorderedMultichainMode: tmp,
261
+ rollbackOnReorg: config.shouldRollbackOnReorg
262
+ };
263
+ }), ctx, isDevelopmentMode);
264
+ await Persistence.init(persistence, ChainMap.values(config.chainMap), undefined);
265
+ var chainManager = await ChainManager.makeFromDbState(Persistence.getInitializedState(persistence), config, registrations, persistence);
266
+ var globalState = GlobalState.make(ctx, chainManager, isDevelopmentMode, shouldUseTui);
267
+ var gsManager = GlobalStateManager.make(globalState, undefined);
268
+ if (shouldUseTui) {
269
+ Tui.start(function () {
270
+ return GlobalStateManager.getState(gsManager);
271
+ });
272
+ }
273
+ globalGsManagerRef.contents = Caml_option.some(gsManager);
274
+ GlobalStateManager.dispatchTask(gsManager, {
275
+ TAG: "NextQuery",
276
+ _0: "CheckAllChains"
277
+ });
278
+ return GlobalStateManager.dispatchTask(gsManager, "ProcessEventBatch");
279
+ }
280
+
281
+ export {
282
+ chainDataSchema ,
283
+ stateSchema ,
284
+ globalGsManagerRef ,
285
+ getGlobalIndexer ,
286
+ startServer ,
287
+ start ,
288
+ }
289
+ /* chainDataSchema Not a pure module */
@@ -0,0 +1,10 @@
1
+ /* TypeScript file generated from PgStorage.res by genType. */
2
+
3
+ /* eslint-disable */
4
+ /* tslint:disable */
5
+
6
+ import * as PgStorageJS from './PgStorage.res.mjs';
7
+
8
+ import type {sql as Postgres_sql} from '../src/bindings/Postgres.gen.js';
9
+
10
+ export const makeClient: () => Postgres_sql = PgStorageJS.makeClient as any;
package/src/PgStorage.res CHANGED
@@ -1,5 +1,28 @@
1
1
  let getCacheRowCountFnName = "get_cache_row_count"
2
2
 
3
+ // Only needed for some old tests
4
+ // Remove @genType in the future
5
+ @genType
6
+ let makeClient = () => {
7
+ Postgres.makeSql(
8
+ ~config={
9
+ host: Env.Db.host,
10
+ port: Env.Db.port,
11
+ username: Env.Db.user,
12
+ password: Env.Db.password,
13
+ database: Env.Db.database,
14
+ ssl: Env.Db.ssl,
15
+ // TODO: think how we want to pipe these logs to pino.
16
+ onnotice: ?(
17
+ Env.userLogLevel == #warn || Env.userLogLevel == #error ? None : Some(_str => ())
18
+ ),
19
+ transform: {undefined: Null},
20
+ max: 2,
21
+ // debug: (~connection, ~query, ~params as _, ~types as _) => Js.log2(connection, query),
22
+ },
23
+ )
24
+ }
25
+
3
26
  let makeCreateIndexQuery = (~tableName, ~indexFields, ~pgSchema) => {
4
27
  let indexName = tableName ++ "_" ++ indexFields->Js.Array2.joinWith("_")
5
28
  let index = indexFields->Belt.Array.map(idx => `"${idx}"`)->Js.Array2.joinWith(", ")
@@ -1056,8 +1079,7 @@ let make = (
1056
1079
  }
1057
1080
 
1058
1081
  let cacheDirPath = NodeJs.Path.resolve([
1059
- // Right outside of the generated directory
1060
- "..",
1082
+ // Right at the project root
1061
1083
  ".envio",
1062
1084
  "cache",
1063
1085
  ])
@@ -0,0 +1,5 @@
1
+ // This is to prevent tsc --noEmit from failing
2
+ // when importing code from .res.mjs files in genType .ts files
3
+ // After we upgrade GenType and it starts to include ts-ignore,
4
+ // the line can be removed.
5
+ export const makeClient: any;