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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. package/README.md +2 -2
  2. package/evm.schema.json +53 -57
  3. package/fuel.schema.json +35 -31
  4. package/index.d.ts +446 -1
  5. package/index.js +4 -0
  6. package/package.json +23 -11
  7. package/rescript.json +4 -1
  8. package/src/Batch.res.mjs +1 -1
  9. package/src/Benchmark.res +394 -0
  10. package/src/Benchmark.res.mjs +398 -0
  11. package/src/ChainFetcher.res +526 -0
  12. package/src/ChainFetcher.res.mjs +343 -0
  13. package/src/ChainManager.res +182 -0
  14. package/src/ChainManager.res.mjs +150 -0
  15. package/src/Config.res +367 -27
  16. package/src/Config.res.mjs +338 -28
  17. package/src/{Indexer.res → Ctx.res} +1 -1
  18. package/src/Ecosystem.res +25 -0
  19. package/src/Ecosystem.res.mjs +29 -0
  20. package/src/Env.res +252 -0
  21. package/src/Env.res.mjs +271 -0
  22. package/src/Envio.gen.ts +9 -1
  23. package/src/Envio.res +12 -9
  24. package/src/EventProcessing.res +476 -0
  25. package/src/EventProcessing.res.mjs +341 -0
  26. package/src/EventRegister.res +4 -15
  27. package/src/EventRegister.res.mjs +3 -9
  28. package/src/EventRegister.resi +2 -8
  29. package/src/FetchState.res +54 -29
  30. package/src/FetchState.res.mjs +62 -35
  31. package/src/GlobalState.res +1163 -0
  32. package/src/GlobalState.res.mjs +1196 -0
  33. package/src/GlobalStateManager.res +68 -0
  34. package/src/GlobalStateManager.res.mjs +75 -0
  35. package/src/GlobalStateManager.resi +7 -0
  36. package/src/HandlerLoader.res +89 -0
  37. package/src/HandlerLoader.res.mjs +79 -0
  38. package/src/Internal.gen.ts +3 -14
  39. package/src/Internal.res +45 -13
  40. package/src/LoadLayer.res +444 -0
  41. package/src/LoadLayer.res.mjs +296 -0
  42. package/src/LoadLayer.resi +32 -0
  43. package/src/LogSelection.res +33 -27
  44. package/src/LogSelection.res.mjs +6 -0
  45. package/src/Logging.res +11 -4
  46. package/src/Logging.res.mjs +14 -6
  47. package/src/Main.res +351 -0
  48. package/src/Main.res.mjs +312 -0
  49. package/src/Persistence.res +1 -2
  50. package/src/PgStorage.gen.ts +10 -0
  51. package/src/PgStorage.res +28 -34
  52. package/src/PgStorage.res.d.mts +5 -0
  53. package/src/PgStorage.res.mjs +27 -27
  54. package/src/Prometheus.res +8 -8
  55. package/src/Prometheus.res.mjs +10 -10
  56. package/src/ReorgDetection.res +6 -10
  57. package/src/ReorgDetection.res.mjs +6 -6
  58. package/src/TestIndexer.res +536 -0
  59. package/src/TestIndexer.res.mjs +412 -0
  60. package/src/TestIndexerProxyStorage.res +210 -0
  61. package/src/TestIndexerProxyStorage.res.mjs +157 -0
  62. package/src/Types.ts +1 -1
  63. package/src/UserContext.res +355 -0
  64. package/src/UserContext.res.mjs +236 -0
  65. package/src/Utils.res +28 -0
  66. package/src/Utils.res.mjs +18 -0
  67. package/src/bindings/ClickHouse.res +31 -1
  68. package/src/bindings/ClickHouse.res.mjs +27 -1
  69. package/src/bindings/DateFns.res +71 -0
  70. package/src/bindings/DateFns.res.mjs +22 -0
  71. package/src/bindings/Ethers.res +27 -67
  72. package/src/bindings/Ethers.res.mjs +18 -70
  73. package/src/bindings/EventSource.res +13 -0
  74. package/src/bindings/EventSource.res.mjs +2 -0
  75. package/src/bindings/NodeJs.res +44 -3
  76. package/src/bindings/NodeJs.res.mjs +11 -3
  77. package/src/bindings/Pino.res +21 -7
  78. package/src/bindings/Pino.res.mjs +11 -5
  79. package/src/bindings/Postgres.gen.ts +8 -0
  80. package/src/bindings/Postgres.res +3 -0
  81. package/src/bindings/Postgres.res.d.mts +5 -0
  82. package/src/bindings/RescriptMocha.res +123 -0
  83. package/src/bindings/RescriptMocha.res.mjs +18 -0
  84. package/src/bindings/Vitest.res +134 -0
  85. package/src/bindings/Vitest.res.mjs +9 -0
  86. package/src/bindings/Yargs.res +8 -0
  87. package/src/bindings/Yargs.res.mjs +2 -0
  88. package/src/db/InternalTable.res +2 -0
  89. package/src/db/InternalTable.res.mjs +1 -1
  90. package/src/sources/Evm.res +87 -0
  91. package/src/sources/Evm.res.mjs +105 -0
  92. package/src/sources/EvmChain.res +90 -0
  93. package/src/sources/EvmChain.res.mjs +57 -0
  94. package/src/sources/Fuel.res +19 -34
  95. package/src/sources/Fuel.res.mjs +34 -16
  96. package/src/sources/FuelSDK.res +38 -0
  97. package/src/sources/FuelSDK.res.mjs +29 -0
  98. package/src/sources/HyperFuel.res +2 -2
  99. package/src/sources/HyperFuel.resi +1 -1
  100. package/src/sources/HyperFuelClient.res +2 -2
  101. package/src/sources/HyperFuelSource.res +8 -8
  102. package/src/sources/HyperFuelSource.res.mjs +5 -5
  103. package/src/sources/HyperSyncHeightStream.res +97 -0
  104. package/src/sources/HyperSyncHeightStream.res.mjs +94 -0
  105. package/src/sources/HyperSyncSource.res +64 -172
  106. package/src/sources/HyperSyncSource.res.mjs +73 -155
  107. package/src/sources/Rpc.res +43 -0
  108. package/src/sources/Rpc.res.mjs +31 -0
  109. package/src/sources/RpcSource.res +32 -130
  110. package/src/sources/RpcSource.res.mjs +47 -121
  111. package/src/sources/Source.res +3 -2
  112. package/src/sources/SourceManager.res +183 -108
  113. package/src/sources/SourceManager.res.mjs +162 -99
  114. package/src/sources/SourceManager.resi +4 -5
  115. package/src/sources/Svm.res +59 -0
  116. package/src/sources/Svm.res.mjs +79 -0
  117. package/src/tui/Tui.res +266 -0
  118. package/src/tui/Tui.res.mjs +342 -0
  119. package/src/tui/bindings/Ink.res +376 -0
  120. package/src/tui/bindings/Ink.res.mjs +75 -0
  121. package/src/tui/bindings/Style.res +123 -0
  122. package/src/tui/bindings/Style.res.mjs +2 -0
  123. package/src/tui/components/BufferedProgressBar.res +40 -0
  124. package/src/tui/components/BufferedProgressBar.res.mjs +57 -0
  125. package/src/tui/components/CustomHooks.res +122 -0
  126. package/src/tui/components/CustomHooks.res.mjs +179 -0
  127. package/src/tui/components/Messages.res +41 -0
  128. package/src/tui/components/Messages.res.mjs +75 -0
  129. package/src/tui/components/SyncETA.res +193 -0
  130. package/src/tui/components/SyncETA.res.mjs +269 -0
  131. package/src/tui/components/TuiData.res +46 -0
  132. package/src/tui/components/TuiData.res.mjs +29 -0
  133. package/src/Platform.res +0 -140
  134. package/src/Platform.res.mjs +0 -170
  135. package/src/bindings/Ethers.gen.ts +0 -14
  136. /package/src/{Indexer.res.mjs → Ctx.res.mjs} +0 -0
package/src/Main.res ADDED
@@ -0,0 +1,351 @@
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
+ ~makeGeneratedConfig: unit => Config.t,
247
+ ~persistence: Persistence.t,
248
+ ~isTest=false,
249
+ ) => {
250
+ let mainArgs: mainArgs = process->argv->Yargs.hideBin->Yargs.yargs->Yargs.argv
251
+ let shouldUseTui = !isTest && !(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
+ // Note: isTest overrides isDevelopmentMode to ensure proper process exit in test mode.
255
+ let isDevelopmentMode = !isTest && Env.Db.password === "testing"
256
+
257
+ // Register all handlers first, then get the config with registrations
258
+ let configWithoutRegistrations = makeGeneratedConfig()
259
+ let registrations = await HandlerLoader.registerAllHandlers(~config=configWithoutRegistrations)
260
+ let config = makeGeneratedConfig()
261
+ let config = if isTest {
262
+ {...config, shouldRollbackOnReorg: false}
263
+ } else {
264
+ config
265
+ }
266
+ let ctx = {
267
+ Ctx.registrations,
268
+ config,
269
+ persistence,
270
+ }
271
+
272
+ let envioVersion = Utils.EnvioPackage.value.version
273
+ Prometheus.Info.set(~version=envioVersion)
274
+ Prometheus.RollbackEnabled.set(~enabled=ctx.config.shouldRollbackOnReorg)
275
+
276
+ if !isTest {
277
+ startServer(~ctx, ~isDevelopmentMode, ~getState=() =>
278
+ switch globalGsManagerRef.contents {
279
+ | None => Initializing({})
280
+ | Some(gsManager) => {
281
+ let state = gsManager->GlobalStateManager.getState
282
+ let chains =
283
+ state.chainManager.chainFetchers
284
+ ->ChainMap.values
285
+ ->Array.map(cf => {
286
+ let {fetchState} = cf
287
+ let latestFetchedBlockNumber = Pervasives.max(
288
+ FetchState.bufferBlockNumber(fetchState),
289
+ 0,
290
+ )
291
+ let knownHeight =
292
+ cf->ChainFetcher.hasProcessedToEndblock
293
+ ? cf.fetchState.endBlock->Option.getWithDefault(cf.fetchState.knownHeight)
294
+ : cf.fetchState.knownHeight
295
+
296
+ {
297
+ chainId: cf.chainConfig.id->Js.Int.toFloat,
298
+ poweredByHyperSync: (
299
+ cf.sourceManager->SourceManager.getActiveSource
300
+ ).poweredByHyperSync,
301
+ latestFetchedBlockNumber,
302
+ knownHeight,
303
+ numBatchesFetched: cf.numBatchesFetched,
304
+ endBlock: cf.fetchState.endBlock,
305
+ firstEventBlockNumber: cf.firstEventBlockNumber,
306
+ latestProcessedBlock: cf.committedProgressBlockNumber === -1
307
+ ? None
308
+ : Some(cf.committedProgressBlockNumber),
309
+ timestampCaughtUpToHeadOrEndblock: cf.timestampCaughtUpToHeadOrEndblock,
310
+ numEventsProcessed: cf.numEventsProcessed,
311
+ numAddresses: cf.fetchState->FetchState.numAddresses,
312
+ }
313
+ })
314
+ Active({
315
+ envioVersion,
316
+ chains,
317
+ indexerStartTime: state.indexerStartTime,
318
+ isPreRegisteringDynamicContracts: false,
319
+ rollbackOnReorg: ctx.config.shouldRollbackOnReorg,
320
+ isUnorderedMultichainMode: switch ctx.config.multichain {
321
+ | Unordered => true
322
+ | Ordered => false
323
+ },
324
+ })
325
+ }
326
+ }
327
+ )
328
+ }
329
+
330
+ await ctx.persistence->Persistence.init(~chainConfigs=ctx.config.chainMap->ChainMap.values)
331
+
332
+ let chainManager = await ChainManager.makeFromDbState(
333
+ ~initialState=ctx.persistence->Persistence.getInitializedState,
334
+ ~config=ctx.config,
335
+ ~registrations=ctx.registrations,
336
+ )
337
+ let globalState = GlobalState.make(~ctx, ~chainManager, ~isDevelopmentMode, ~shouldUseTui)
338
+ let gsManager = globalState->GlobalStateManager.make
339
+ if shouldUseTui {
340
+ let _rerender = Tui.start(~getState=() => gsManager->GlobalStateManager.getState)
341
+ }
342
+ globalGsManagerRef := Some(gsManager)
343
+ gsManager->GlobalStateManager.dispatchTask(NextQuery(CheckAllChains))
344
+ /*
345
+ NOTE:
346
+ This `ProcessEventBatch` dispatch shouldn't be necessary but we are adding for safety, it should immediately return doing
347
+ nothing since there is no events on the queues.
348
+ */
349
+
350
+ gsManager->GlobalStateManager.dispatchTask(ProcessEventBatch)
351
+ }
@@ -0,0 +1,312 @@
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 HandlerLoader from "./HandlerLoader.res.mjs";
22
+ import * as SourceManager from "./sources/SourceManager.res.mjs";
23
+ import * as Helpers from "yargs/helpers";
24
+ import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
25
+ import * as GlobalStateManager from "./GlobalStateManager.res.mjs";
26
+
27
+ var chainDataSchema = S$RescriptSchema.schema(function (s) {
28
+ return {
29
+ chainId: s.m(S$RescriptSchema.$$float),
30
+ poweredByHyperSync: s.m(S$RescriptSchema.bool),
31
+ firstEventBlockNumber: s.m(S$RescriptSchema.option(S$RescriptSchema.$$int)),
32
+ latestProcessedBlock: s.m(S$RescriptSchema.option(S$RescriptSchema.$$int)),
33
+ timestampCaughtUpToHeadOrEndblock: s.m(S$RescriptSchema.option(S$RescriptSchema.datetime(S$RescriptSchema.string, undefined))),
34
+ numEventsProcessed: s.m(S$RescriptSchema.$$int),
35
+ latestFetchedBlockNumber: s.m(S$RescriptSchema.$$int),
36
+ currentBlockHeight: s.m(S$RescriptSchema.$$int),
37
+ numBatchesFetched: s.m(S$RescriptSchema.$$int),
38
+ endBlock: s.m(S$RescriptSchema.option(S$RescriptSchema.$$int)),
39
+ numAddresses: s.m(S$RescriptSchema.$$int)
40
+ };
41
+ });
42
+
43
+ var stateSchema = S$RescriptSchema.union([
44
+ S$RescriptSchema.literal({
45
+ status: "disabled"
46
+ }),
47
+ S$RescriptSchema.literal({
48
+ status: "initializing"
49
+ }),
50
+ S$RescriptSchema.schema(function (s) {
51
+ return {
52
+ status: "active",
53
+ envioVersion: s.m(S$RescriptSchema.string),
54
+ chains: s.m(S$RescriptSchema.array(chainDataSchema)),
55
+ indexerStartTime: s.m(S$RescriptSchema.datetime(S$RescriptSchema.string, undefined)),
56
+ isPreRegisteringDynamicContracts: false,
57
+ isUnorderedMultichainMode: s.m(S$RescriptSchema.bool),
58
+ rollbackOnReorg: s.m(S$RescriptSchema.bool)
59
+ };
60
+ })
61
+ ]);
62
+
63
+ var globalGsManagerRef = {
64
+ contents: undefined
65
+ };
66
+
67
+ function getGlobalIndexer(config) {
68
+ var indexer = Object.create(null);
69
+ Object.defineProperty(Object.defineProperty(indexer, "name", {
70
+ enumerable: true,
71
+ value: config.name
72
+ }), "description", {
73
+ enumerable: true,
74
+ value: config.description
75
+ });
76
+ var chainIds = [];
77
+ var chains = Object.create(null);
78
+ Belt_Array.forEach(ChainMap.values(config.chainMap), (function (chainConfig) {
79
+ var chainIdStr = String(chainConfig.id);
80
+ chainIds.push(chainConfig.id);
81
+ var chainObj = Object.create(null);
82
+ Object.defineProperty(Object.defineProperty(Object.defineProperty(Object.defineProperty(Object.defineProperty(chainObj, "id", {
83
+ enumerable: true,
84
+ value: chainConfig.id
85
+ }), "startBlock", {
86
+ enumerable: true,
87
+ value: chainConfig.startBlock
88
+ }), "endBlock", {
89
+ enumerable: true,
90
+ value: chainConfig.endBlock
91
+ }), "name", {
92
+ enumerable: true,
93
+ value: chainConfig.name
94
+ }), "isLive", {
95
+ enumerable: true,
96
+ get: (function () {
97
+ var gsManager = globalGsManagerRef.contents;
98
+ if (gsManager === undefined) {
99
+ return false;
100
+ }
101
+ var state = GlobalStateManager.getState(Caml_option.valFromOption(gsManager));
102
+ var chain = ChainMap.Chain.makeUnsafe(chainConfig.id);
103
+ var chainFetcher = ChainMap.get(state.chainManager.chainFetchers, chain);
104
+ return ChainFetcher.isLive(chainFetcher);
105
+ })
106
+ });
107
+ Belt_Array.forEach(chainConfig.contracts, (function (contract) {
108
+ var contractObj = Object.create(null);
109
+ Object.defineProperty(Object.defineProperty(Object.defineProperty(contractObj, "name", {
110
+ enumerable: true,
111
+ value: contract.name
112
+ }), "abi", {
113
+ enumerable: true,
114
+ value: contract.abi
115
+ }), "addresses", {
116
+ enumerable: true,
117
+ get: (function () {
118
+ var gsManager = globalGsManagerRef.contents;
119
+ if (gsManager === undefined) {
120
+ return contract.addresses;
121
+ }
122
+ var state = GlobalStateManager.getState(Caml_option.valFromOption(gsManager));
123
+ var chain = ChainMap.Chain.makeUnsafe(chainConfig.id);
124
+ var chainFetcher = ChainMap.get(state.chainManager.chainFetchers, chain);
125
+ var indexingContracts = chainFetcher.fetchState.indexingContracts;
126
+ var addresses = [];
127
+ var values = Js_dict.values(indexingContracts);
128
+ for(var idx = 0 ,idx_finish = values.length; idx < idx_finish; ++idx){
129
+ var indexingContract = values[idx];
130
+ if (indexingContract.contractName === contract.name) {
131
+ addresses.push(indexingContract.address);
132
+ }
133
+
134
+ }
135
+ return addresses;
136
+ })
137
+ });
138
+ Object.defineProperty(chainObj, contract.name, {
139
+ enumerable: true,
140
+ value: contractObj
141
+ });
142
+ }));
143
+ Object.defineProperty(chains, chainIdStr, {
144
+ enumerable: true,
145
+ value: chainObj
146
+ });
147
+ if (chainConfig.name !== chainIdStr) {
148
+ Object.defineProperty(chains, chainConfig.name, {
149
+ enumerable: false,
150
+ value: chainObj
151
+ });
152
+ return ;
153
+ }
154
+
155
+ }));
156
+ Object.defineProperty(indexer, "chainIds", {
157
+ enumerable: true,
158
+ value: chainIds
159
+ });
160
+ Object.defineProperty(indexer, "chains", {
161
+ enumerable: true,
162
+ value: chains
163
+ });
164
+ return indexer;
165
+ }
166
+
167
+ function startServer(getState, ctx, isDevelopmentMode) {
168
+ var app = Express();
169
+ var consoleCorsMiddleware = function (req, res, next) {
170
+ var origin = Js_dict.get(req.headers, "origin");
171
+ if (origin !== undefined && (origin === Env.prodEnvioAppUrl || origin === Env.envioAppUrl)) {
172
+ res.setHeader("Access-Control-Allow-Origin", origin);
173
+ }
174
+ res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
175
+ res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
176
+ if (req.method === "OPTIONS") {
177
+ res.sendStatus(200);
178
+ return ;
179
+ } else {
180
+ return next();
181
+ }
182
+ };
183
+ app.use("/console", consoleCorsMiddleware);
184
+ app.use("/metrics", consoleCorsMiddleware);
185
+ app.get("/healthz", (function (_req, res) {
186
+ res.sendStatus(200);
187
+ }));
188
+ app.get("/console/state", (function (_req, res) {
189
+ var state = isDevelopmentMode ? getState() : ({
190
+ status: "disabled"
191
+ });
192
+ res.json(S$RescriptSchema.reverseConvertToJsonOrThrow(state, stateSchema));
193
+ }));
194
+ app.post("/console/syncCache", (function (_req, res) {
195
+ if (isDevelopmentMode) {
196
+ Persistence.getInitializedStorageOrThrow(ctx.persistence).dumpEffectCache().then(function () {
197
+ res.json(true);
198
+ });
199
+ } else {
200
+ res.json(false);
201
+ }
202
+ }));
203
+ PromClient.collectDefaultMetrics();
204
+ app.get("/metrics", (function (_req, res) {
205
+ res.set("Content-Type", PromClient.register.contentType);
206
+ PromClient.register.metrics().then(function (metrics) {
207
+ return res.end(metrics);
208
+ });
209
+ }));
210
+ app.listen(Env.serverPort);
211
+ }
212
+
213
+ async function start(makeGeneratedConfig, persistence, isTestOpt) {
214
+ var isTest = isTestOpt !== undefined ? isTestOpt : false;
215
+ var mainArgs = Yargs(Helpers.hideBin(process.argv)).argv;
216
+ var shouldUseTui = !isTest && !Belt_Option.getWithDefault(mainArgs["tui-off"], Env.tuiOffEnvVar);
217
+ var isDevelopmentMode = !isTest && Env.Db.password === "testing";
218
+ var configWithoutRegistrations = makeGeneratedConfig();
219
+ var registrations = await HandlerLoader.registerAllHandlers(configWithoutRegistrations);
220
+ var config = makeGeneratedConfig();
221
+ var config$1 = isTest ? ({
222
+ name: config.name,
223
+ description: config.description,
224
+ handlers: config.handlers,
225
+ contractHandlers: config.contractHandlers,
226
+ shouldRollbackOnReorg: false,
227
+ shouldSaveFullHistory: config.shouldSaveFullHistory,
228
+ multichain: config.multichain,
229
+ chainMap: config.chainMap,
230
+ defaultChain: config.defaultChain,
231
+ ecosystem: config.ecosystem,
232
+ enableRawEvents: config.enableRawEvents,
233
+ maxAddrInPartition: config.maxAddrInPartition,
234
+ batchSize: config.batchSize,
235
+ lowercaseAddresses: config.lowercaseAddresses,
236
+ addContractNameToContractNameMapping: config.addContractNameToContractNameMapping,
237
+ userEntitiesByName: config.userEntitiesByName
238
+ }) : config;
239
+ var ctx = {
240
+ registrations: registrations,
241
+ config: config$1,
242
+ persistence: persistence
243
+ };
244
+ var envioVersion = Utils.EnvioPackage.value.version;
245
+ Prometheus.Info.set(envioVersion);
246
+ Prometheus.RollbackEnabled.set(config$1.shouldRollbackOnReorg);
247
+ if (!isTest) {
248
+ startServer((function () {
249
+ var gsManager = globalGsManagerRef.contents;
250
+ if (gsManager === undefined) {
251
+ return {
252
+ status: "initializing"
253
+ };
254
+ }
255
+ var state = GlobalStateManager.getState(Caml_option.valFromOption(gsManager));
256
+ var chains = Belt_Array.map(ChainMap.values(state.chainManager.chainFetchers), (function (cf) {
257
+ var latestFetchedBlockNumber = Caml.int_max(FetchState.bufferBlockNumber(cf.fetchState), 0);
258
+ var knownHeight = ChainFetcher.hasProcessedToEndblock(cf) ? Belt_Option.getWithDefault(cf.fetchState.endBlock, cf.fetchState.knownHeight) : cf.fetchState.knownHeight;
259
+ return {
260
+ chainId: cf.chainConfig.id,
261
+ poweredByHyperSync: SourceManager.getActiveSource(cf.sourceManager).poweredByHyperSync,
262
+ firstEventBlockNumber: cf.firstEventBlockNumber,
263
+ latestProcessedBlock: cf.committedProgressBlockNumber === -1 ? undefined : cf.committedProgressBlockNumber,
264
+ timestampCaughtUpToHeadOrEndblock: cf.timestampCaughtUpToHeadOrEndblock,
265
+ numEventsProcessed: cf.numEventsProcessed,
266
+ latestFetchedBlockNumber: latestFetchedBlockNumber,
267
+ currentBlockHeight: knownHeight,
268
+ numBatchesFetched: cf.numBatchesFetched,
269
+ endBlock: cf.fetchState.endBlock,
270
+ numAddresses: FetchState.numAddresses(cf.fetchState)
271
+ };
272
+ }));
273
+ var match = config$1.multichain;
274
+ var tmp;
275
+ tmp = match === "ordered" ? false : true;
276
+ return {
277
+ status: "active",
278
+ envioVersion: envioVersion,
279
+ chains: chains,
280
+ indexerStartTime: state.indexerStartTime,
281
+ isPreRegisteringDynamicContracts: false,
282
+ isUnorderedMultichainMode: tmp,
283
+ rollbackOnReorg: config$1.shouldRollbackOnReorg
284
+ };
285
+ }), ctx, isDevelopmentMode);
286
+ }
287
+ await Persistence.init(persistence, ChainMap.values(config$1.chainMap), undefined);
288
+ var chainManager = await ChainManager.makeFromDbState(Persistence.getInitializedState(persistence), config$1, registrations);
289
+ var globalState = GlobalState.make(ctx, chainManager, isDevelopmentMode, shouldUseTui);
290
+ var gsManager = GlobalStateManager.make(globalState, undefined);
291
+ if (shouldUseTui) {
292
+ Tui.start(function () {
293
+ return GlobalStateManager.getState(gsManager);
294
+ });
295
+ }
296
+ globalGsManagerRef.contents = Caml_option.some(gsManager);
297
+ GlobalStateManager.dispatchTask(gsManager, {
298
+ TAG: "NextQuery",
299
+ _0: "CheckAllChains"
300
+ });
301
+ return GlobalStateManager.dispatchTask(gsManager, "ProcessEventBatch");
302
+ }
303
+
304
+ export {
305
+ chainDataSchema ,
306
+ stateSchema ,
307
+ globalGsManagerRef ,
308
+ getGlobalIndexer ,
309
+ startServer ,
310
+ start ,
311
+ }
312
+ /* chainDataSchema Not a pure module */
@@ -23,6 +23,7 @@ type initialChainState = {
23
23
  firstEventBlockNumber: option<int>,
24
24
  timestampCaughtUpToHeadOrEndblock: option<Js.Date.t>,
25
25
  dynamicContracts: array<Internal.indexingContract>,
26
+ sourceBlockNumber: int,
26
27
  }
27
28
 
28
29
  type initialState = {
@@ -90,8 +91,6 @@ type storage = {
90
91
  dumpEffectCache: unit => promise<unit>,
91
92
  // Execute raw SQL query
92
93
  executeUnsafe: string => promise<unknown>,
93
- // Check if entity history has rows
94
- hasEntityHistoryRows: unit => promise<bool>,
95
94
  // Update chain metadata
96
95
  setChainMeta: dict<InternalTable.Chains.metaFields> => promise<unknown>,
97
96
  // Prune old checkpoints
@@ -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;