envio 3.0.0-alpha.1 → 3.0.0-alpha.2

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.
@@ -0,0 +1,273 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as EnvSafe from "rescript-envsafe/src/EnvSafe.res.mjs";
4
+ import * as Logging from "./Logging.res.mjs";
5
+ import * as Postgres from "./bindings/Postgres.res.mjs";
6
+ import * as Caml_option from "rescript/lib/es6/caml_option.js";
7
+ import * as HyperSyncClient from "./sources/HyperSyncClient.res.mjs";
8
+ import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
9
+
10
+ import 'dotenv/config'
11
+ ;
12
+
13
+ var envSafe = EnvSafe.make(undefined);
14
+
15
+ function getLogLevelConfig(name, $$default) {
16
+ return EnvSafe.get(envSafe, name, S$RescriptSchema.$$enum([
17
+ "trace",
18
+ "debug",
19
+ "info",
20
+ "warn",
21
+ "error",
22
+ "fatal",
23
+ "udebug",
24
+ "uinfo",
25
+ "uwarn",
26
+ "uerror"
27
+ ]), undefined, $$default, undefined, undefined);
28
+ }
29
+
30
+ var updateSyncTimeOnRestart = EnvSafe.get(envSafe, "UPDATE_SYNC_TIME_ON_RESTART", S$RescriptSchema.bool, undefined, true, undefined, undefined);
31
+
32
+ var batchSize = EnvSafe.get(envSafe, "MAX_BATCH_SIZE", S$RescriptSchema.option(S$RescriptSchema.$$int), undefined, undefined, undefined, undefined);
33
+
34
+ var targetBufferSize = EnvSafe.get(envSafe, "ENVIO_INDEXING_MAX_BUFFER_SIZE", S$RescriptSchema.option(S$RescriptSchema.$$int), undefined, undefined, undefined, undefined);
35
+
36
+ var maxAddrInPartition = EnvSafe.get(envSafe, "MAX_PARTITION_SIZE", S$RescriptSchema.$$int, undefined, 5000, undefined, undefined);
37
+
38
+ var maxPartitionConcurrency = EnvSafe.get(envSafe, "ENVIO_MAX_PARTITION_CONCURRENCY", S$RescriptSchema.$$int, undefined, 10, undefined, undefined);
39
+
40
+ var indexingBlockLag = EnvSafe.get(envSafe, "ENVIO_INDEXING_BLOCK_LAG", S$RescriptSchema.option(S$RescriptSchema.$$int), undefined, undefined, undefined, undefined);
41
+
42
+ var serverPort = EnvSafe.get(envSafe, "ENVIO_INDEXER_PORT", S$RescriptSchema.port(S$RescriptSchema.$$int, undefined), undefined, EnvSafe.get(envSafe, "METRICS_PORT", S$RescriptSchema.port(S$RescriptSchema.$$int, undefined), undefined, 9898, undefined, undefined), undefined, undefined);
43
+
44
+ var tuiOffEnvVar = EnvSafe.get(envSafe, "TUI_OFF", S$RescriptSchema.bool, undefined, false, undefined, undefined);
45
+
46
+ var logFilePath = EnvSafe.get(envSafe, "LOG_FILE", S$RescriptSchema.string, undefined, "logs/envio.log", undefined, undefined);
47
+
48
+ var userLogLevel = getLogLevelConfig("LOG_LEVEL", "info");
49
+
50
+ var defaultFileLogLevel = getLogLevelConfig("FILE_LOG_LEVEL", "trace");
51
+
52
+ var prodEnvioAppUrl = "https://envio.dev";
53
+
54
+ var envioAppUrl = EnvSafe.get(envSafe, "ENVIO_APP", S$RescriptSchema.string, undefined, prodEnvioAppUrl, undefined, undefined);
55
+
56
+ var envioApiToken = EnvSafe.get(envSafe, "ENVIO_API_TOKEN", S$RescriptSchema.option(S$RescriptSchema.string), undefined, undefined, undefined, undefined);
57
+
58
+ var hyperSyncClientTimeoutMillis = EnvSafe.get(envSafe, "ENVIO_HYPERSYNC_CLIENT_TIMEOUT_MILLIS", S$RescriptSchema.$$int, undefined, 120000, undefined, undefined);
59
+
60
+ var hyperSyncClientMaxRetries = EnvSafe.get(envSafe, "ENVIO_HYPERSYNC_CLIENT_MAX_RETRIES", S$RescriptSchema.$$int, undefined, 0, undefined, undefined);
61
+
62
+ var hypersyncClientSerializationFormat = EnvSafe.get(envSafe, "ENVIO_HYPERSYNC_CLIENT_SERIALIZATION_FORMAT", HyperSyncClient.serializationFormatSchema, undefined, "CapnProto", undefined, undefined);
63
+
64
+ var hypersyncClientEnableQueryCaching = EnvSafe.get(envSafe, "ENVIO_HYPERSYNC_CLIENT_ENABLE_QUERY_CACHING", S$RescriptSchema.bool, undefined, true, undefined, undefined);
65
+
66
+ var schema = S$RescriptSchema.$$enum([
67
+ true,
68
+ false,
69
+ "json-file",
70
+ "prometheus"
71
+ ]);
72
+
73
+ var $$default = false;
74
+
75
+ function shouldSaveJsonFile(self) {
76
+ if (typeof self !== "boolean") {
77
+ if (self === "json-file") {
78
+ return true;
79
+ } else {
80
+ return false;
81
+ }
82
+ } else if (self) {
83
+ return true;
84
+ } else {
85
+ return false;
86
+ }
87
+ }
88
+
89
+ function shouldSavePrometheus(param) {
90
+ return true;
91
+ }
92
+
93
+ function shouldSaveData(self) {
94
+ return true;
95
+ }
96
+
97
+ var SaveDataStrategy = {
98
+ schema: schema,
99
+ $$default: $$default,
100
+ shouldSaveJsonFile: shouldSaveJsonFile,
101
+ shouldSavePrometheus: shouldSavePrometheus,
102
+ shouldSaveData: shouldSaveData
103
+ };
104
+
105
+ var saveDataStrategy = EnvSafe.get(envSafe, "ENVIO_SAVE_BENCHMARK_DATA", schema, undefined, Caml_option.some($$default), undefined, undefined);
106
+
107
+ var shouldSaveData$1 = shouldSaveData(saveDataStrategy);
108
+
109
+ var shouldSaveStdDev = shouldSaveJsonFile(saveDataStrategy);
110
+
111
+ var Benchmark = {
112
+ SaveDataStrategy: SaveDataStrategy,
113
+ saveDataStrategy: saveDataStrategy,
114
+ shouldSaveData: shouldSaveData$1,
115
+ shouldSaveStdDev: shouldSaveStdDev
116
+ };
117
+
118
+ var logStrategy = EnvSafe.get(envSafe, "LOG_STRATEGY", S$RescriptSchema.$$enum([
119
+ "ecs-file",
120
+ "ecs-console",
121
+ "ecs-console-multistream",
122
+ "file-only",
123
+ "console-raw",
124
+ "console-pretty",
125
+ "both-prettyconsole"
126
+ ]), undefined, "console-pretty", undefined, undefined);
127
+
128
+ Logging.setLogger(Logging.makeLogger(logStrategy, logFilePath, defaultFileLogLevel, userLogLevel));
129
+
130
+ var host = EnvSafe.get(envSafe, "ENVIO_PG_HOST", S$RescriptSchema.string, undefined, undefined, "localhost", undefined);
131
+
132
+ var port = EnvSafe.get(envSafe, "ENVIO_PG_PORT", S$RescriptSchema.port(S$RescriptSchema.$$int, undefined), undefined, undefined, 5433, undefined);
133
+
134
+ var user = EnvSafe.get(envSafe, "ENVIO_PG_USER", S$RescriptSchema.string, undefined, undefined, "postgres", undefined);
135
+
136
+ var password = EnvSafe.get(envSafe, "ENVIO_PG_PASSWORD", S$RescriptSchema.string, undefined, EnvSafe.get(envSafe, "ENVIO_POSTGRES_PASSWORD", S$RescriptSchema.string, undefined, "testing", undefined, undefined), undefined, undefined);
137
+
138
+ var database = EnvSafe.get(envSafe, "ENVIO_PG_DATABASE", S$RescriptSchema.string, undefined, undefined, "envio-dev", undefined);
139
+
140
+ var publicSchema = EnvSafe.get(envSafe, "ENVIO_PG_PUBLIC_SCHEMA", S$RescriptSchema.string, undefined, "public", undefined, undefined);
141
+
142
+ var ssl = EnvSafe.get(envSafe, "ENVIO_PG_SSL_MODE", Postgres.sslOptionsSchema, undefined, undefined, false, undefined);
143
+
144
+ var Db = {
145
+ host: host,
146
+ port: port,
147
+ user: user,
148
+ password: password,
149
+ database: database,
150
+ publicSchema: publicSchema,
151
+ ssl: ssl
152
+ };
153
+
154
+ var host$1 = EnvSafe.get(envSafe, "ENVIO_CLICKHOUSE_SINK_HOST", S$RescriptSchema.option(S$RescriptSchema.string), undefined, undefined, undefined, undefined);
155
+
156
+ var database$1 = EnvSafe.get(envSafe, "ENVIO_CLICKHOUSE_SINK_DATABASE", S$RescriptSchema.option(S$RescriptSchema.string), undefined, undefined, undefined, undefined);
157
+
158
+ var username = host$1 !== undefined ? EnvSafe.get(envSafe, "ENVIO_CLICKHOUSE_SINK_USERNAME", S$RescriptSchema.string, undefined, undefined, undefined, undefined) : "";
159
+
160
+ var password$1 = host$1 !== undefined ? EnvSafe.get(envSafe, "ENVIO_CLICKHOUSE_SINK_PASSWORD", S$RescriptSchema.string, undefined, undefined, undefined, undefined) : "";
161
+
162
+ var ClickHouseSink = {
163
+ host: host$1,
164
+ database: database$1,
165
+ username: username,
166
+ password: password$1
167
+ };
168
+
169
+ var enabled = EnvSafe.get(envSafe, "ENVIO_HASURA", S$RescriptSchema.bool, undefined, true, undefined, undefined);
170
+
171
+ var s = EnvSafe.get(envSafe, "ENVIO_HASURA_RESPONSE_LIMIT", S$RescriptSchema.option(S$RescriptSchema.$$int), undefined, undefined, undefined, undefined);
172
+
173
+ var responseLimit = s !== undefined ? s : EnvSafe.get(envSafe, "HASURA_RESPONSE_LIMIT", S$RescriptSchema.option(S$RescriptSchema.$$int), undefined, undefined, undefined, undefined);
174
+
175
+ var graphqlEndpoint = EnvSafe.get(envSafe, "HASURA_GRAPHQL_ENDPOINT", S$RescriptSchema.string, undefined, undefined, "http://localhost:8080/v1/metadata", undefined);
176
+
177
+ var url = graphqlEndpoint.slice(0, -"/v1/metadata".length | 0);
178
+
179
+ var role = EnvSafe.get(envSafe, "HASURA_GRAPHQL_ROLE", S$RescriptSchema.string, undefined, undefined, "admin", undefined);
180
+
181
+ var secret = EnvSafe.get(envSafe, "HASURA_GRAPHQL_ADMIN_SECRET", S$RescriptSchema.string, undefined, undefined, "testing", undefined);
182
+
183
+ var aggregateEntities = EnvSafe.get(envSafe, "ENVIO_HASURA_PUBLIC_AGGREGATE", S$RescriptSchema.union([
184
+ S$RescriptSchema.array(S$RescriptSchema.string),
185
+ S$RescriptSchema.transform(S$RescriptSchema.string, (function (s) {
186
+ return {
187
+ p: (function (string) {
188
+ var entities = string.split("&");
189
+ var len = entities.length;
190
+ if (len !== 1 && len !== 0) {
191
+ return entities;
192
+ } else {
193
+ return s.fail("Provide an array of entities in the JSON format.", undefined);
194
+ }
195
+ })
196
+ };
197
+ }))
198
+ ]), undefined, [], undefined, undefined);
199
+
200
+ var Hasura = {
201
+ enabled: enabled,
202
+ responseLimit: responseLimit,
203
+ graphqlEndpoint: graphqlEndpoint,
204
+ url: url,
205
+ role: role,
206
+ secret: secret,
207
+ aggregateEntities: aggregateEntities
208
+ };
209
+
210
+ var initialBlockInterval = EnvSafe.get(envSafe, "ENVIO_RPC_INITIAL_BLOCK_INTERVAL", S$RescriptSchema.option(S$RescriptSchema.$$int), undefined, undefined, undefined, undefined);
211
+
212
+ var backoffMultiplicative = EnvSafe.get(envSafe, "ENVIO_RPC_BACKOFF_MULTIPLICATIVE", S$RescriptSchema.option(S$RescriptSchema.$$float), undefined, undefined, undefined, undefined);
213
+
214
+ var accelerationAdditive = EnvSafe.get(envSafe, "ENVIO_RPC_ACCELERATION_ADDITIVE", S$RescriptSchema.option(S$RescriptSchema.$$int), undefined, undefined, undefined, undefined);
215
+
216
+ var intervalCeiling = EnvSafe.get(envSafe, "ENVIO_RPC_INTERVAL_CEILING", S$RescriptSchema.option(S$RescriptSchema.$$int), undefined, undefined, undefined, undefined);
217
+
218
+ var SyncConfig = {
219
+ initialBlockInterval: initialBlockInterval,
220
+ backoffMultiplicative: backoffMultiplicative,
221
+ accelerationAdditive: accelerationAdditive,
222
+ intervalCeiling: intervalCeiling
223
+ };
224
+
225
+ var Configurable = {
226
+ SyncConfig: SyncConfig
227
+ };
228
+
229
+ var chainMetadataIntervalMillis = EnvSafe.get(envSafe, "ENVIO_THROTTLE_CHAIN_METADATA_INTERVAL_MILLIS", S$RescriptSchema.$$int, undefined, undefined, 500, undefined);
230
+
231
+ var pruneStaleDataIntervalMillis = EnvSafe.get(envSafe, "ENVIO_THROTTLE_PRUNE_STALE_DATA_INTERVAL_MILLIS", S$RescriptSchema.$$int, undefined, undefined, 30000, undefined);
232
+
233
+ var liveMetricsBenchmarkIntervalMillis = EnvSafe.get(envSafe, "ENVIO_THROTTLE_LIVE_METRICS_BENCHMARK_INTERVAL_MILLIS", S$RescriptSchema.$$int, undefined, undefined, 1000, undefined);
234
+
235
+ var jsonFileBenchmarkIntervalMillis = EnvSafe.get(envSafe, "ENVIO_THROTTLE_JSON_FILE_BENCHMARK_INTERVAL_MILLIS", S$RescriptSchema.$$int, undefined, undefined, 500, undefined);
236
+
237
+ var ThrottleWrites = {
238
+ chainMetadataIntervalMillis: chainMetadataIntervalMillis,
239
+ pruneStaleDataIntervalMillis: pruneStaleDataIntervalMillis,
240
+ liveMetricsBenchmarkIntervalMillis: liveMetricsBenchmarkIntervalMillis,
241
+ jsonFileBenchmarkIntervalMillis: jsonFileBenchmarkIntervalMillis
242
+ };
243
+
244
+ EnvSafe.close(envSafe);
245
+
246
+ export {
247
+ updateSyncTimeOnRestart ,
248
+ batchSize ,
249
+ targetBufferSize ,
250
+ maxAddrInPartition ,
251
+ maxPartitionConcurrency ,
252
+ indexingBlockLag ,
253
+ serverPort ,
254
+ tuiOffEnvVar ,
255
+ logFilePath ,
256
+ userLogLevel ,
257
+ defaultFileLogLevel ,
258
+ prodEnvioAppUrl ,
259
+ envioAppUrl ,
260
+ envioApiToken ,
261
+ hyperSyncClientTimeoutMillis ,
262
+ hyperSyncClientMaxRetries ,
263
+ hypersyncClientSerializationFormat ,
264
+ hypersyncClientEnableQueryCaching ,
265
+ Benchmark ,
266
+ logStrategy ,
267
+ Db ,
268
+ ClickHouseSink ,
269
+ Hasura ,
270
+ Configurable ,
271
+ ThrottleWrites ,
272
+ }
273
+ /* Not a pure module */
@@ -4,9 +4,8 @@ type registrations = {
4
4
  }
5
5
 
6
6
  type activeRegistration = {
7
- platform: Platform.t,
7
+ ecosystem: Ecosystem.t,
8
8
  multichain: Config.multichain,
9
- preloadHandlers: bool,
10
9
  registrations: registrations,
11
10
  mutable finished: bool,
12
11
  }
@@ -36,11 +35,10 @@ let withRegistration = (fn: activeRegistration => unit) => {
36
35
  }
37
36
  }
38
37
 
39
- let startRegistration = (~platform, ~multichain, ~preloadHandlers) => {
38
+ let startRegistration = (~ecosystem, ~multichain) => {
40
39
  let r = {
41
- platform,
40
+ ecosystem,
42
41
  multichain,
43
- preloadHandlers,
44
42
  registrations: {
45
43
  onBlockByChainId: Js.Dict.empty(),
46
44
  hasEvents: false,
@@ -92,16 +90,7 @@ let onBlock = (rawOptions: unknown, handler: Internal.onBlockArgs => promise<uni
92
90
  | Unordered => ()
93
91
  | Ordered =>
94
92
  Js.Exn.raiseError(
95
- "Block Handlers are not supported for ordered multichain mode. Please reach out to the Envio team if you need this feature or enable unordered multichain mode with `unordered_multichain_mode: true` in your config.",
96
- )
97
- }
98
- // So we encourage users to upgrade to preload optimization
99
- // otherwise block handlers will be extremely slow
100
- switch registration.preloadHandlers {
101
- | true => ()
102
- | false =>
103
- Js.Exn.raiseError(
104
- "Block Handlers require the Preload Optimization feature. Enable it by setting the `preload_handlers` option to `true` in your config.",
93
+ "Block Handlers are not supported for ordered multichain mode. Please reach out to the Envio team if you need this feature. Or enable unordered multichain mode by removing `multichain: ordered` from the config.yaml file.",
105
94
  )
106
95
  }
107
96
 
@@ -27,11 +27,10 @@ function withRegistration(fn) {
27
27
  }
28
28
  }
29
29
 
30
- function startRegistration(platform, multichain, preloadHandlers) {
30
+ function startRegistration(ecosystem, multichain) {
31
31
  var r = {
32
- platform: platform,
32
+ ecosystem: ecosystem,
33
33
  multichain: multichain,
34
- preloadHandlers: preloadHandlers,
35
34
  registrations: {
36
35
  onBlockByChainId: {},
37
36
  hasEvents: false
@@ -81,12 +80,7 @@ function onBlock(rawOptions, handler) {
81
80
  withRegistration(function (registration) {
82
81
  var match = registration.multichain;
83
82
  if (match === "ordered") {
84
- Js_exn.raiseError("Block Handlers are not supported for ordered multichain mode. Please reach out to the Envio team if you need this feature or enable unordered multichain mode with `unordered_multichain_mode: true` in your config.");
85
- }
86
- if (registration.preloadHandlers) {
87
-
88
- } else {
89
- Js_exn.raiseError("Block Handlers require the Preload Optimization feature. Enable it by setting the `preload_handlers` option to `true` in your config.");
83
+ Js_exn.raiseError("Block Handlers are not supported for ordered multichain mode. Please reach out to the Envio team if you need this feature. Or enable unordered multichain mode by removing `multichain: ordered` from the config.yaml file.");
90
84
  }
91
85
  var options = S$RescriptSchema.parseOrThrow(rawOptions, onBlockOptionsSchema);
92
86
  var chainId = options.chain;
@@ -3,11 +3,7 @@ type registrations = {
3
3
  mutable hasEvents: bool,
4
4
  }
5
5
 
6
- let startRegistration: (
7
- ~platform: Platform.t,
8
- ~multichain: Config.multichain,
9
- ~preloadHandlers: bool,
10
- ) => unit
6
+ let startRegistration: (~ecosystem: Ecosystem.t, ~multichain: Config.multichain) => unit
11
7
  let isPendingRegistration: unit => bool
12
8
  let finishRegistration: unit => registrations
13
9
 
@@ -15,9 +11,7 @@ type t
15
11
  let make: (~contractName: string, ~eventName: string) => t
16
12
  let setHandler: (
17
13
  t,
18
- Internal.genericHandler<
19
- Internal.genericHandlerArgs<'event, Internal.handlerContext, 'loaderReturn>,
20
- >,
14
+ Internal.genericHandler<Internal.genericHandlerArgs<'event, Internal.handlerContext>>,
21
15
  ~eventOptions: option<Internal.eventOptions<'eventFilters>>,
22
16
  ~logger: Pino.t=?,
23
17
  ) => unit
@@ -26,11 +26,7 @@ export type genericContractRegisterArgs<event,context> = { readonly event: event
26
26
 
27
27
  export type genericContractRegister<args> = $$genericContractRegister<args>;
28
28
 
29
- export type genericHandlerArgs<event,context,loaderReturn> = {
30
- readonly event: event;
31
- readonly context: context;
32
- readonly loaderReturn: loaderReturn
33
- };
29
+ export type genericHandlerArgs<event,context> = { readonly event: event; readonly context: context };
34
30
 
35
31
  export type genericHandler<args> = (_1:args) => Promise<void>;
36
32
 
@@ -46,17 +42,10 @@ export type genericHandlerWithLoader<loader,handler,eventFilters> = {
46
42
  readonly loader: loader;
47
43
  readonly handler: handler;
48
44
  readonly wildcard?: boolean;
49
- readonly eventFilters?: eventFilters;
50
- /** @deprecated The option is removed starting from v2.19 since we made the default mode even faster than pre-registration. */
51
- readonly preRegisterDynamicContracts?: boolean
45
+ readonly eventFilters?: eventFilters
52
46
  };
53
47
 
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
- };
48
+ export type eventOptions<eventFilters> = { readonly wildcard?: boolean; readonly eventFilters?: eventFilters };
60
49
 
61
50
  export type fuelSupplyParams = { readonly subId: string; readonly amount: bigint };
62
51
 
package/src/Internal.res CHANGED
@@ -37,10 +37,9 @@ type contractRegisterArgs = genericContractRegisterArgs<event, contractRegisterC
37
37
  type contractRegister = genericContractRegister<contractRegisterArgs>
38
38
 
39
39
  @genType
40
- type genericHandlerArgs<'event, 'context, 'loaderReturn> = {
40
+ type genericHandlerArgs<'event, 'context> = {
41
41
  event: 'event,
42
42
  context: 'context,
43
- loaderReturn: 'loaderReturn,
44
43
  }
45
44
  @genType
46
45
  type genericHandler<'args> = 'args => promise<unit>
@@ -81,10 +80,6 @@ type genericHandlerWithLoader<'loader, 'handler, 'eventFilters> = {
81
80
  handler: 'handler,
82
81
  wildcard?: bool,
83
82
  eventFilters?: 'eventFilters,
84
- /**
85
- @deprecated The option is removed starting from v2.19 since we made the default mode even faster than pre-registration.
86
- */
87
- preRegisterDynamicContracts?: bool,
88
83
  }
89
84
 
90
85
  // This is private so it's not manually constructed internally
@@ -170,7 +165,7 @@ type eventItem = private {
170
165
  event: event,
171
166
  }
172
167
 
173
- // Opaque type to support both EVM and Fuel platforms
168
+ // Opaque type to support both EVM and other ecosystems
174
169
  type blockEvent
175
170
 
176
171
  type onBlockArgs = {
@@ -225,10 +220,6 @@ external setItemDcs: (item, dcs) => unit = "dcs"
225
220
  type eventOptions<'eventFilters> = {
226
221
  wildcard?: bool,
227
222
  eventFilters?: 'eventFilters,
228
- /**
229
- @deprecated The option is removed starting from v2.19 since we made the default mode even faster than pre-registration.
230
- */
231
- preRegisterDynamicContracts?: bool,
232
223
  }
233
224
 
234
225
  @genType
@@ -0,0 +1,13 @@
1
+ type t
2
+
3
+ type options = {headers?: Js.Dict.t<string>}
4
+
5
+ @module("eventsource") @new
6
+ external create: (~url: string, ~options: options=?) => t = "EventSource"
7
+
8
+ @set external onopen: (t, unit => unit) => unit = "onopen"
9
+ @set external onerror: (t, Js.Exn.t => unit) => unit = "onerror"
10
+
11
+ type event = {data: string}
12
+ @send external addEventListener: (t, string, event => unit) => unit = "addEventListener"
13
+ @send external close: t => unit = "close"
@@ -0,0 +1,2 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+ /* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */
@@ -0,0 +1,179 @@
1
+ /*
2
+ Pure js implementation of the HyperSync height stream.
3
+ */
4
+
5
+ type t = {
6
+ heightRef: ref<int>,
7
+ errorRef: ref<option<string>>,
8
+ timeoutIdRef: ref<Js.Global.timeoutId>,
9
+ eventsourceRef: ref<option<EventSource.t>>,
10
+ }
11
+
12
+ let make = (~hyperSyncUrl, ~apiToken) => {
13
+ /**
14
+ On every successful ping or height event, clear the timeout and set a new one.
15
+
16
+ if the timeout lapses, close and reconnect the EventSource.
17
+ */
18
+ let rec updateTimeoutId = (
19
+ ~eventsourceRef: ref<option<EventSource.t>>,
20
+ ~timeoutIdRef: ref<Js.Global.timeoutId>,
21
+ ~hyperSyncUrl,
22
+ ~apiToken,
23
+ ~heightRef: ref<int>,
24
+ ~errorRef: ref<option<string>>,
25
+ ) => {
26
+ timeoutIdRef.contents->Js.Global.clearTimeout
27
+
28
+ // Should receive a ping at least every 5s, so 15s is a safe margin
29
+ // for staleness to restart the EventSource connection
30
+ let staleTimeMillis = 15_000
31
+ let newTimeoutId = Js.Global.setTimeout(() => {
32
+ Logging.trace({
33
+ "msg": "Timeout fired for height stream",
34
+ "url": hyperSyncUrl,
35
+ "staleTimeMillis": staleTimeMillis,
36
+ })
37
+ refreshEventSource(
38
+ ~eventsourceRef,
39
+ ~hyperSyncUrl,
40
+ ~apiToken,
41
+ ~heightRef,
42
+ ~errorRef,
43
+ ~timeoutIdRef,
44
+ )
45
+ }, staleTimeMillis)
46
+
47
+ timeoutIdRef := newTimeoutId
48
+ }
49
+ and /**
50
+ Instantiate a new EventSource and set it to the shared refs.
51
+ Add the necessary event listeners, handle errors
52
+ and update the timeout.
53
+ */
54
+ refreshEventSource = (
55
+ ~eventsourceRef: ref<option<EventSource.t>>,
56
+ ~hyperSyncUrl,
57
+ ~apiToken,
58
+ ~heightRef: ref<int>,
59
+ ~errorRef: ref<option<string>>,
60
+ ~timeoutIdRef: ref<Js.Global.timeoutId>,
61
+ ) => {
62
+ // Close the old EventSource if it exists (on a new connection after timeout)
63
+ switch eventsourceRef.contents {
64
+ | Some(es) => es->EventSource.close
65
+ | None => ()
66
+ }
67
+
68
+ let userAgent = `hyperindex/${Utils.EnvioPackage.value.version}`
69
+ let es = EventSource.create(
70
+ ~url=`${hyperSyncUrl}/height/sse`,
71
+ ~options={
72
+ headers: Js.Dict.fromArray([
73
+ ("Authorization", `Bearer ${apiToken}`),
74
+ ("User-Agent", userAgent),
75
+ ]),
76
+ },
77
+ )
78
+
79
+ // Set the new EventSource to the shared ref
80
+ eventsourceRef := Some(es)
81
+ // Update the timeout in case connection goes stale
82
+ updateTimeoutId(~eventsourceRef, ~timeoutIdRef, ~hyperSyncUrl, ~apiToken, ~heightRef, ~errorRef)
83
+
84
+ es->EventSource.onopen(_ => {
85
+ Logging.trace({"msg": "SSE connection opened for height stream", "url": hyperSyncUrl})
86
+ })
87
+
88
+ es->EventSource.onerror(error => {
89
+ Logging.trace({
90
+ "msg": "EventSource error",
91
+ "error": error->Js.Exn.message,
92
+ })
93
+ // On errors, set the error ref
94
+ // so that getHeight can raise an error
95
+ errorRef :=
96
+ Some(error->Js.Exn.message->Belt.Option.getWithDefault("Unexpected no error.message"))
97
+ })
98
+
99
+ es->EventSource.addEventListener("ping", _event => {
100
+ // ping lets us know from the server that the connection is still alive
101
+ // and that the height hasn't updated for 5seconds
102
+ // update the timeout on each successful ping received
103
+ updateTimeoutId(
104
+ ~eventsourceRef,
105
+ ~timeoutIdRef,
106
+ ~hyperSyncUrl,
107
+ ~apiToken,
108
+ ~heightRef,
109
+ ~errorRef,
110
+ )
111
+ // reset the error ref, since we had a successful ping
112
+ errorRef := None
113
+ })
114
+
115
+ es->EventSource.addEventListener("height", event => {
116
+ switch event.data->Belt.Int.fromString {
117
+ | Some(height) =>
118
+ // On a successful height event, update the timeout
119
+ // and reset the error ref
120
+ updateTimeoutId(
121
+ ~eventsourceRef,
122
+ ~timeoutIdRef,
123
+ ~hyperSyncUrl,
124
+ ~apiToken,
125
+ ~heightRef,
126
+ ~errorRef,
127
+ )
128
+ errorRef := None
129
+ // Set the actual height ref
130
+ heightRef := height
131
+ | None =>
132
+ Logging.trace({"msg": "Height was not a number in event.data", "data": event.data})
133
+ errorRef := Some("Height was not a number in event.data")
134
+ }
135
+ })
136
+ }
137
+
138
+ // Refs used between the functions
139
+
140
+ let heightRef = ref(0)
141
+ let errorRef = ref(None)
142
+ let eventsourceRef = ref(None)
143
+ // Timeout doesn't do anything for initalization
144
+ let timeoutIdRef = ref(Js.Global.setTimeout(() => (), 0))
145
+ refreshEventSource(
146
+ ~eventsourceRef,
147
+ ~hyperSyncUrl,
148
+ ~apiToken,
149
+ ~heightRef,
150
+ ~errorRef,
151
+ ~timeoutIdRef,
152
+ )
153
+
154
+ {
155
+ heightRef,
156
+ errorRef,
157
+ timeoutIdRef,
158
+ eventsourceRef,
159
+ }
160
+ }
161
+
162
+ let getHeight = async (t: t) => {
163
+ while t.heightRef.contents == 0 && t.errorRef.contents == None {
164
+ // Poll internally until height is over 0
165
+ await Utils.delay(200)
166
+ }
167
+ switch t.errorRef.contents {
168
+ | None => t.heightRef.contents
169
+ | Some(error) => Js.Exn.raiseError(error)
170
+ }
171
+ }
172
+
173
+ let close = t => {
174
+ t.timeoutIdRef.contents->Js.Global.clearTimeout
175
+ switch t.eventsourceRef.contents {
176
+ | Some(es) => es->EventSource.close
177
+ | None => ()
178
+ }
179
+ }