envio 2.32.2 → 2.32.6
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/package.json +12 -11
- package/src/Utils.res +9 -0
- package/src/Utils.res.js +18 -0
- package/src/bindings/EventSource.res +13 -0
- package/src/bindings/EventSource.res.js +2 -0
- package/src/sources/HyperSyncClient.res +75 -18
- package/src/sources/HyperSyncClient.res.js +22 -6
- package/src/sources/HyperSyncHeightStream.res +179 -0
- package/src/sources/HyperSyncHeightStream.res.js +126 -0
- package/src/sources/HyperSyncSource.res +19 -9
- package/src/sources/HyperSyncSource.res.js +21 -17
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "envio",
|
|
3
|
-
"version": "v2.32.
|
|
3
|
+
"version": "v2.32.6",
|
|
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,22 +25,23 @@
|
|
|
25
25
|
},
|
|
26
26
|
"homepage": "https://envio.dev",
|
|
27
27
|
"optionalDependencies": {
|
|
28
|
-
"envio-linux-x64": "v2.32.
|
|
29
|
-
"envio-linux-arm64": "v2.32.
|
|
30
|
-
"envio-darwin-x64": "v2.32.
|
|
31
|
-
"envio-darwin-arm64": "v2.32.
|
|
28
|
+
"envio-linux-x64": "v2.32.6",
|
|
29
|
+
"envio-linux-arm64": "v2.32.6",
|
|
30
|
+
"envio-darwin-x64": "v2.32.6",
|
|
31
|
+
"envio-darwin-arm64": "v2.32.6"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@
|
|
34
|
+
"@elastic/ecs-pino-format": "1.4.0",
|
|
35
|
+
"@envio-dev/hypersync-client": "0.7.0-hyperindex-v2-compatible",
|
|
35
36
|
"@envio-dev/hyperfuel-client": "1.2.2",
|
|
36
|
-
"rescript": "11.1.3",
|
|
37
|
-
"rescript-schema": "9.3.0",
|
|
38
|
-
"viem": "2.21.0",
|
|
39
37
|
"bignumber.js": "9.1.2",
|
|
38
|
+
"eventsource": "4.1.0",
|
|
40
39
|
"pino": "8.16.1",
|
|
41
40
|
"pino-pretty": "10.2.3",
|
|
42
|
-
"
|
|
43
|
-
"
|
|
41
|
+
"prom-client": "15.0.0",
|
|
42
|
+
"rescript": "11.1.3",
|
|
43
|
+
"rescript-schema": "9.3.0",
|
|
44
|
+
"viem": "2.21.0"
|
|
44
45
|
},
|
|
45
46
|
"files": [
|
|
46
47
|
"bin.js",
|
package/src/Utils.res
CHANGED
|
@@ -653,3 +653,12 @@ let prettifyExn = exn => {
|
|
|
653
653
|
| exn => exn
|
|
654
654
|
}
|
|
655
655
|
}
|
|
656
|
+
|
|
657
|
+
module EnvioPackage = {
|
|
658
|
+
type t = {version: string}
|
|
659
|
+
|
|
660
|
+
%%private(let getPackageJson = (): t => %raw(`require("../package.json")`))
|
|
661
|
+
let json: t = try getPackageJson() catch {
|
|
662
|
+
| _ => Js.Exn.raiseError("Failed to get package.json in envio package")
|
|
663
|
+
}
|
|
664
|
+
}
|
package/src/Utils.res.js
CHANGED
|
@@ -580,6 +580,23 @@ function prettifyExn(exn) {
|
|
|
580
580
|
}
|
|
581
581
|
}
|
|
582
582
|
|
|
583
|
+
function getPackageJson() {
|
|
584
|
+
return (require("../package.json"));
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
var json;
|
|
588
|
+
|
|
589
|
+
try {
|
|
590
|
+
json = getPackageJson();
|
|
591
|
+
}
|
|
592
|
+
catch (exn){
|
|
593
|
+
json = Js_exn.raiseError("Failed to get package.json in envio package");
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
var EnvioPackage = {
|
|
597
|
+
json: json
|
|
598
|
+
};
|
|
599
|
+
|
|
583
600
|
exports.delay = delay;
|
|
584
601
|
exports.$$Object = $$Object;
|
|
585
602
|
exports.$$Error = $$Error;
|
|
@@ -600,4 +617,5 @@ exports.$$Map = $$Map;
|
|
|
600
617
|
exports.$$Proxy = $$Proxy;
|
|
601
618
|
exports.Hash = Hash;
|
|
602
619
|
exports.prettifyExn = prettifyExn;
|
|
620
|
+
exports.EnvioPackage = EnvioPackage;
|
|
603
621
|
/* variantTag Not a pure module */
|
|
@@ -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"
|
|
@@ -1,12 +1,33 @@
|
|
|
1
|
+
/** Determines query serialization format for HTTP requests. */
|
|
2
|
+
type serializationFormat =
|
|
3
|
+
// Use JSON serialization (default)
|
|
4
|
+
| Json
|
|
5
|
+
// Use Cap'n Proto binary serialization
|
|
6
|
+
| CapnProto
|
|
7
|
+
|
|
8
|
+
let serializationFormatSchema = S.enum([Json, CapnProto])
|
|
9
|
+
|
|
1
10
|
type cfg = {
|
|
2
|
-
|
|
3
|
-
|
|
11
|
+
/** HyperSync server URL. */
|
|
12
|
+
url: string,
|
|
13
|
+
/** HyperSync server api token. */
|
|
14
|
+
apiToken: string,
|
|
15
|
+
/** Milliseconds to wait for a response before timing out. Default: 30000. */
|
|
4
16
|
httpReqTimeoutMillis?: int,
|
|
17
|
+
/** Number of retries to attempt before returning error. Default: 12. */
|
|
5
18
|
maxNumRetries?: int,
|
|
19
|
+
/** Milliseconds that would be used for retry backoff increasing. Default: 500. */
|
|
6
20
|
retryBackoffMs?: int,
|
|
21
|
+
/** Initial wait time for request backoff. Default: 200. */
|
|
7
22
|
retryBaseMs?: int,
|
|
23
|
+
/** Ceiling time for request backoff. Default: 5000. */
|
|
8
24
|
retryCeilingMs?: int,
|
|
25
|
+
/** Enable checksum addresses in responses. */
|
|
9
26
|
enableChecksumAddresses?: bool,
|
|
27
|
+
/** Query serialization format to use for HTTP requests. Default: Json. */
|
|
28
|
+
serializationFormat?: serializationFormat,
|
|
29
|
+
/** Whether to use query caching when using CapnProto serialization format. */
|
|
30
|
+
enableQueryCaching?: bool,
|
|
10
31
|
}
|
|
11
32
|
|
|
12
33
|
module QueryTypes = {
|
|
@@ -111,7 +132,7 @@ module QueryTypes = {
|
|
|
111
132
|
| TraceAddress
|
|
112
133
|
| TransactionHash
|
|
113
134
|
| TransactionPosition
|
|
114
|
-
|
|
|
135
|
+
| Type
|
|
115
136
|
| Error
|
|
116
137
|
|
|
117
138
|
type fieldSelection = {
|
|
@@ -133,7 +154,7 @@ module QueryTypes = {
|
|
|
133
154
|
topic3,
|
|
134
155
|
)
|
|
135
156
|
|
|
136
|
-
type
|
|
157
|
+
type logFilter = {
|
|
137
158
|
/**
|
|
138
159
|
* Address of the contract, any logs that has any of these addresses will be returned.
|
|
139
160
|
* Empty means match all.
|
|
@@ -148,7 +169,7 @@ module QueryTypes = {
|
|
|
148
169
|
|
|
149
170
|
let makeLogSelection = (~address, ~topics) => {address, topics}
|
|
150
171
|
|
|
151
|
-
type
|
|
172
|
+
type transactionFilter = {
|
|
152
173
|
/**
|
|
153
174
|
* Address the transaction should originate from. If transaction.from matches any of these, the transaction
|
|
154
175
|
* will be returned. Keep in mind that this has an and relationship with to filter, so each transaction should
|
|
@@ -167,7 +188,8 @@ module QueryTypes = {
|
|
|
167
188
|
/** If tx.status matches this it will be returned. */
|
|
168
189
|
status?: int,
|
|
169
190
|
/** If transaction.type matches any of these values, the transaction will be returned */
|
|
170
|
-
|
|
191
|
+
@as("type")
|
|
192
|
+
type_?: array<int>,
|
|
171
193
|
contractAddress?: array<Address.t>,
|
|
172
194
|
}
|
|
173
195
|
|
|
@@ -177,7 +199,8 @@ module QueryTypes = {
|
|
|
177
199
|
address?: array<Address.t>,
|
|
178
200
|
callType?: array<string>,
|
|
179
201
|
rewardType?: array<string>,
|
|
180
|
-
|
|
202
|
+
@as("type")
|
|
203
|
+
type_?: array<string>,
|
|
181
204
|
sighash?: array<string>,
|
|
182
205
|
}
|
|
183
206
|
|
|
@@ -214,12 +237,12 @@ module QueryTypes = {
|
|
|
214
237
|
* List of log selections, these have an or relationship between them, so the query will return logs
|
|
215
238
|
* that match any of these selections.
|
|
216
239
|
*/
|
|
217
|
-
logs?: array<
|
|
240
|
+
logs?: array<logFilter>,
|
|
218
241
|
/**
|
|
219
242
|
* List of transaction selections, the query will return transactions that match any of these selections and
|
|
220
243
|
* it will return transactions that are related to the returned logs.
|
|
221
244
|
*/
|
|
222
|
-
transactions?: array<
|
|
245
|
+
transactions?: array<transactionFilter>,
|
|
223
246
|
/**
|
|
224
247
|
* List of trace selections, the query will return traces that match any of these selections and
|
|
225
248
|
* it will re turn traces that are related to the returned logs.
|
|
@@ -436,6 +459,22 @@ type streamConfig
|
|
|
436
459
|
type queryResponse
|
|
437
460
|
type queryResponseStream
|
|
438
461
|
type eventStream
|
|
462
|
+
|
|
463
|
+
@tag("type")
|
|
464
|
+
type heightStreamEvent =
|
|
465
|
+
| Height({height: int})
|
|
466
|
+
| Connected
|
|
467
|
+
| Reconnecting({delayMillis: int, errorMsg: string})
|
|
468
|
+
|
|
469
|
+
module HeightStream = {
|
|
470
|
+
type t = {
|
|
471
|
+
/** Close the height stream */
|
|
472
|
+
close: unit => promise<unit>,
|
|
473
|
+
/** Receive the next height stream event from the stream */
|
|
474
|
+
recv: unit => promise<heightStreamEvent>,
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
439
478
|
type t = {
|
|
440
479
|
getHeight: unit => promise<int>,
|
|
441
480
|
collect: (~query: query, ~config: streamConfig) => promise<queryResponse>,
|
|
@@ -445,23 +484,41 @@ type t = {
|
|
|
445
484
|
getEvents: (~query: query) => promise<eventResponse>,
|
|
446
485
|
stream: (~query: query, ~config: streamConfig) => promise<queryResponseStream>,
|
|
447
486
|
streamEvents: (~query: query, ~config: streamConfig) => promise<eventStream>,
|
|
487
|
+
streamHeight: unit => promise<HeightStream.t>,
|
|
448
488
|
}
|
|
449
489
|
|
|
450
|
-
@module("@envio-dev/hypersync-client") @scope("HypersyncClient")
|
|
490
|
+
@module("@envio-dev/hypersync-client") @scope("HypersyncClient")
|
|
491
|
+
external makeWithAgent: (cfg, ~userAgent: string) => t = "newWithAgent"
|
|
492
|
+
|
|
451
493
|
let make = (
|
|
452
494
|
~url,
|
|
453
495
|
~apiToken,
|
|
454
496
|
~httpReqTimeoutMillis,
|
|
455
497
|
~maxNumRetries,
|
|
456
498
|
~enableChecksumAddresses=true,
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
499
|
+
~serializationFormat=?,
|
|
500
|
+
~enableQueryCaching=?,
|
|
501
|
+
~retryBaseMs=?,
|
|
502
|
+
~retryBackoffMs=?,
|
|
503
|
+
~retryCeilingMs=?,
|
|
504
|
+
) => {
|
|
505
|
+
let envioVersion = Utils.EnvioPackage.json.version
|
|
506
|
+
makeWithAgent(
|
|
507
|
+
{
|
|
508
|
+
url,
|
|
509
|
+
enableChecksumAddresses,
|
|
510
|
+
apiToken,
|
|
511
|
+
httpReqTimeoutMillis,
|
|
512
|
+
maxNumRetries,
|
|
513
|
+
?serializationFormat,
|
|
514
|
+
?enableQueryCaching,
|
|
515
|
+
?retryBaseMs,
|
|
516
|
+
?retryBackoffMs,
|
|
517
|
+
?retryCeilingMs,
|
|
518
|
+
},
|
|
519
|
+
~userAgent=`hyperindex/${envioVersion}`,
|
|
520
|
+
)
|
|
521
|
+
}
|
|
465
522
|
|
|
466
523
|
module Decoder = {
|
|
467
524
|
type rec decodedSolType<'a> = {val: 'a}
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
+
var Utils = require("../Utils.res.js");
|
|
4
5
|
var Address = require("../Address.res.js");
|
|
5
6
|
var Belt_Array = require("rescript/lib/js/belt_Array.js");
|
|
6
7
|
var S$RescriptSchema = require("rescript-schema/src/S.res.js");
|
|
7
8
|
var HypersyncClient = require("@envio-dev/hypersync-client");
|
|
8
9
|
|
|
10
|
+
var serializationFormatSchema = S$RescriptSchema.$$enum([
|
|
11
|
+
"Json",
|
|
12
|
+
"CapnProto"
|
|
13
|
+
]);
|
|
14
|
+
|
|
9
15
|
function makeTopicSelection(topic0Opt, topic1Opt, topic2Opt, topic3Opt) {
|
|
10
16
|
var topic0 = topic0Opt !== undefined ? topic0Opt : [];
|
|
11
17
|
var topic1 = topic1Opt !== undefined ? topic1Opt : [];
|
|
@@ -57,15 +63,23 @@ var ResponseTypes = {
|
|
|
57
63
|
authorizationListSchema: authorizationListSchema
|
|
58
64
|
};
|
|
59
65
|
|
|
60
|
-
|
|
66
|
+
var HeightStream = {};
|
|
67
|
+
|
|
68
|
+
function make(url, apiToken, httpReqTimeoutMillis, maxNumRetries, enableChecksumAddressesOpt, serializationFormat, enableQueryCaching, retryBaseMs, retryBackoffMs, retryCeilingMs) {
|
|
61
69
|
var enableChecksumAddresses = enableChecksumAddressesOpt !== undefined ? enableChecksumAddressesOpt : true;
|
|
62
|
-
|
|
70
|
+
var envioVersion = Utils.EnvioPackage.json.version;
|
|
71
|
+
return HypersyncClient.HypersyncClient.newWithAgent({
|
|
63
72
|
url: url,
|
|
64
|
-
|
|
73
|
+
apiToken: apiToken,
|
|
65
74
|
httpReqTimeoutMillis: httpReqTimeoutMillis,
|
|
66
75
|
maxNumRetries: maxNumRetries,
|
|
67
|
-
|
|
68
|
-
|
|
76
|
+
retryBackoffMs: retryBackoffMs,
|
|
77
|
+
retryBaseMs: retryBaseMs,
|
|
78
|
+
retryCeilingMs: retryCeilingMs,
|
|
79
|
+
enableChecksumAddresses: enableChecksumAddresses,
|
|
80
|
+
serializationFormat: serializationFormat,
|
|
81
|
+
enableQueryCaching: enableQueryCaching
|
|
82
|
+
}, "hyperindex/" + envioVersion);
|
|
69
83
|
}
|
|
70
84
|
|
|
71
85
|
function toUnderlying(_d) {
|
|
@@ -98,8 +112,10 @@ var Decoder = {
|
|
|
98
112
|
fromSignatures: fromSignatures
|
|
99
113
|
};
|
|
100
114
|
|
|
115
|
+
exports.serializationFormatSchema = serializationFormatSchema;
|
|
101
116
|
exports.QueryTypes = QueryTypes;
|
|
102
117
|
exports.ResponseTypes = ResponseTypes;
|
|
118
|
+
exports.HeightStream = HeightStream;
|
|
103
119
|
exports.make = make;
|
|
104
120
|
exports.Decoder = Decoder;
|
|
105
|
-
/*
|
|
121
|
+
/* serializationFormatSchema Not a pure module */
|
|
@@ -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.json.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
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var Utils = require("../Utils.res.js");
|
|
5
|
+
var Js_exn = require("rescript/lib/js/js_exn.js");
|
|
6
|
+
var Js_dict = require("rescript/lib/js/js_dict.js");
|
|
7
|
+
var Logging = require("../Logging.res.js");
|
|
8
|
+
var Belt_Int = require("rescript/lib/js/belt_Int.js");
|
|
9
|
+
var Belt_Option = require("rescript/lib/js/belt_Option.js");
|
|
10
|
+
var Caml_option = require("rescript/lib/js/caml_option.js");
|
|
11
|
+
var Eventsource = require("eventsource");
|
|
12
|
+
|
|
13
|
+
function make(hyperSyncUrl, apiToken) {
|
|
14
|
+
var updateTimeoutId = function (eventsourceRef, timeoutIdRef, hyperSyncUrl, apiToken, heightRef, errorRef) {
|
|
15
|
+
clearTimeout(timeoutIdRef.contents);
|
|
16
|
+
var newTimeoutId = setTimeout((function () {
|
|
17
|
+
Logging.trace({
|
|
18
|
+
msg: "Timeout fired for height stream",
|
|
19
|
+
url: hyperSyncUrl,
|
|
20
|
+
staleTimeMillis: 15000
|
|
21
|
+
});
|
|
22
|
+
refreshEventSource(eventsourceRef, hyperSyncUrl, apiToken, heightRef, errorRef, timeoutIdRef);
|
|
23
|
+
}), 15000);
|
|
24
|
+
timeoutIdRef.contents = newTimeoutId;
|
|
25
|
+
};
|
|
26
|
+
var refreshEventSource = function (eventsourceRef, hyperSyncUrl, apiToken, heightRef, errorRef, timeoutIdRef) {
|
|
27
|
+
var es = eventsourceRef.contents;
|
|
28
|
+
if (es !== undefined) {
|
|
29
|
+
Caml_option.valFromOption(es).close();
|
|
30
|
+
}
|
|
31
|
+
var userAgent = "hyperindex/" + Utils.EnvioPackage.json.version;
|
|
32
|
+
var es$1 = new Eventsource.EventSource(hyperSyncUrl + "/height/sse", {
|
|
33
|
+
headers: Js_dict.fromArray([
|
|
34
|
+
[
|
|
35
|
+
"Authorization",
|
|
36
|
+
"Bearer " + apiToken
|
|
37
|
+
],
|
|
38
|
+
[
|
|
39
|
+
"User-Agent",
|
|
40
|
+
userAgent
|
|
41
|
+
]
|
|
42
|
+
])
|
|
43
|
+
});
|
|
44
|
+
eventsourceRef.contents = Caml_option.some(es$1);
|
|
45
|
+
updateTimeoutId(eventsourceRef, timeoutIdRef, hyperSyncUrl, apiToken, heightRef, errorRef);
|
|
46
|
+
es$1.onopen = (function () {
|
|
47
|
+
Logging.trace({
|
|
48
|
+
msg: "SSE connection opened for height stream",
|
|
49
|
+
url: hyperSyncUrl
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
es$1.onerror = (function (error) {
|
|
53
|
+
Logging.trace({
|
|
54
|
+
msg: "EventSource error",
|
|
55
|
+
error: error.message
|
|
56
|
+
});
|
|
57
|
+
errorRef.contents = Belt_Option.getWithDefault(error.message, "Unexpected no error.message");
|
|
58
|
+
});
|
|
59
|
+
es$1.addEventListener("ping", (function (_event) {
|
|
60
|
+
updateTimeoutId(eventsourceRef, timeoutIdRef, hyperSyncUrl, apiToken, heightRef, errorRef);
|
|
61
|
+
errorRef.contents = undefined;
|
|
62
|
+
}));
|
|
63
|
+
es$1.addEventListener("height", (function ($$event) {
|
|
64
|
+
var height = Belt_Int.fromString($$event.data);
|
|
65
|
+
if (height !== undefined) {
|
|
66
|
+
updateTimeoutId(eventsourceRef, timeoutIdRef, hyperSyncUrl, apiToken, heightRef, errorRef);
|
|
67
|
+
errorRef.contents = undefined;
|
|
68
|
+
heightRef.contents = height;
|
|
69
|
+
} else {
|
|
70
|
+
Logging.trace({
|
|
71
|
+
msg: "Height was not a number in event.data",
|
|
72
|
+
data: $$event.data
|
|
73
|
+
});
|
|
74
|
+
errorRef.contents = "Height was not a number in event.data";
|
|
75
|
+
}
|
|
76
|
+
}));
|
|
77
|
+
};
|
|
78
|
+
var heightRef = {
|
|
79
|
+
contents: 0
|
|
80
|
+
};
|
|
81
|
+
var errorRef = {
|
|
82
|
+
contents: undefined
|
|
83
|
+
};
|
|
84
|
+
var eventsourceRef = {
|
|
85
|
+
contents: undefined
|
|
86
|
+
};
|
|
87
|
+
var timeoutIdRef = {
|
|
88
|
+
contents: setTimeout((function () {
|
|
89
|
+
|
|
90
|
+
}), 0)
|
|
91
|
+
};
|
|
92
|
+
refreshEventSource(eventsourceRef, hyperSyncUrl, apiToken, heightRef, errorRef, timeoutIdRef);
|
|
93
|
+
return {
|
|
94
|
+
heightRef: heightRef,
|
|
95
|
+
errorRef: errorRef,
|
|
96
|
+
timeoutIdRef: timeoutIdRef,
|
|
97
|
+
eventsourceRef: eventsourceRef
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async function getHeight(t) {
|
|
102
|
+
while(t.heightRef.contents === 0 && t.errorRef.contents === undefined) {
|
|
103
|
+
await Utils.delay(200);
|
|
104
|
+
};
|
|
105
|
+
var error = t.errorRef.contents;
|
|
106
|
+
if (error !== undefined) {
|
|
107
|
+
return Js_exn.raiseError(error);
|
|
108
|
+
} else {
|
|
109
|
+
return t.heightRef.contents;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function close(t) {
|
|
114
|
+
clearTimeout(t.timeoutIdRef.contents);
|
|
115
|
+
var es = t.eventsourceRef.contents;
|
|
116
|
+
if (es !== undefined) {
|
|
117
|
+
Caml_option.valFromOption(es).close();
|
|
118
|
+
return ;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
exports.make = make;
|
|
124
|
+
exports.getHeight = getHeight;
|
|
125
|
+
exports.close = close;
|
|
126
|
+
/* Utils Not a pure module */
|
|
@@ -155,6 +155,8 @@ type options = {
|
|
|
155
155
|
clientMaxRetries: int,
|
|
156
156
|
clientTimeoutMillis: int,
|
|
157
157
|
lowercaseAddresses: bool,
|
|
158
|
+
serializationFormat: HyperSyncClient.serializationFormat,
|
|
159
|
+
enableQueryCaching: bool,
|
|
158
160
|
}
|
|
159
161
|
|
|
160
162
|
let make = (
|
|
@@ -169,6 +171,8 @@ let make = (
|
|
|
169
171
|
clientMaxRetries,
|
|
170
172
|
clientTimeoutMillis,
|
|
171
173
|
lowercaseAddresses,
|
|
174
|
+
serializationFormat,
|
|
175
|
+
enableQueryCaching,
|
|
172
176
|
}: options,
|
|
173
177
|
): t => {
|
|
174
178
|
let name = "HyperSync"
|
|
@@ -183,6 +187,8 @@ let make = (
|
|
|
183
187
|
~maxNumRetries=clientMaxRetries,
|
|
184
188
|
~httpReqTimeoutMillis=clientTimeoutMillis,
|
|
185
189
|
~enableChecksumAddresses=!lowercaseAddresses,
|
|
190
|
+
~serializationFormat,
|
|
191
|
+
~enableQueryCaching,
|
|
186
192
|
)
|
|
187
193
|
|
|
188
194
|
let hscDecoder: ref<option<HyperSyncClient.Decoder.t>> = ref(None)
|
|
@@ -545,28 +551,32 @@ let make = (
|
|
|
545
551
|
~logger,
|
|
546
552
|
)->Promise.thenResolve(HyperSync.mapExn)
|
|
547
553
|
|
|
548
|
-
let jsonApiClient = Rest.client(endpointUrl)
|
|
549
|
-
|
|
550
554
|
let malformedTokenMessage = `Your token is malformed. For more info: https://docs.envio.dev/docs/HyperSync/api-tokens.`
|
|
551
555
|
|
|
556
|
+
let heightStream = HyperSyncHeightStream.make(~hyperSyncUrl=endpointUrl, ~apiToken)
|
|
557
|
+
|
|
552
558
|
{
|
|
553
559
|
name,
|
|
554
560
|
sourceFor: Sync,
|
|
555
561
|
chain,
|
|
556
|
-
pollingInterval:
|
|
562
|
+
pollingInterval: 32, // purely internal state polling since we now stream the height to the state
|
|
557
563
|
poweredByHyperSync: true,
|
|
558
564
|
getBlockHashes,
|
|
559
|
-
getHeightOrThrow: async () =>
|
|
560
|
-
|
|
561
|
-
|
|
|
562
|
-
|
|
565
|
+
getHeightOrThrow: async () => {
|
|
566
|
+
try await heightStream->HyperSyncHeightStream.getHeight catch {
|
|
567
|
+
| Js.Exn.Error(exn)
|
|
568
|
+
if exn
|
|
569
|
+
->Js.Exn.message
|
|
570
|
+
->Option.getWithDefault("")
|
|
571
|
+
->Js.String2.includes(malformedTokenMessage) =>
|
|
563
572
|
Logging.error(`Your ENVIO_API_TOKEN is malformed. The indexer will not be able to fetch events. Update the token and restart the indexer using 'pnpm envio start'. For more info: https://docs.envio.dev/docs/HyperSync/api-tokens`)
|
|
564
573
|
// Don't want to retry if the token is malformed
|
|
565
574
|
// So just block forever
|
|
566
575
|
let _ = await Promise.make((_, _) => ())
|
|
567
576
|
0
|
|
568
|
-
|
|
|
569
|
-
}
|
|
577
|
+
| exn => raise(exn)
|
|
578
|
+
}
|
|
579
|
+
},
|
|
570
580
|
getItemsOrThrow,
|
|
571
581
|
}
|
|
572
582
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
var Rest = require("../vendored/Rest.res.js");
|
|
5
4
|
var Viem = require("../bindings/Viem.res.js");
|
|
6
5
|
var Utils = require("../Utils.res.js");
|
|
7
6
|
var Hrtime = require("../bindings/Hrtime.res.js");
|
|
@@ -17,8 +16,8 @@ var ErrorHandling = require("../ErrorHandling.res.js");
|
|
|
17
16
|
var Caml_exceptions = require("rescript/lib/js/caml_exceptions.js");
|
|
18
17
|
var HyperSyncClient = require("./HyperSyncClient.res.js");
|
|
19
18
|
var Caml_splice_call = require("rescript/lib/js/caml_splice_call.js");
|
|
20
|
-
var HyperSyncJsonApi = require("./HyperSyncJsonApi.res.js");
|
|
21
19
|
var Caml_js_exceptions = require("rescript/lib/js/caml_js_exceptions.js");
|
|
20
|
+
var HyperSyncHeightStream = require("./HyperSyncHeightStream.res.js");
|
|
22
21
|
|
|
23
22
|
function getSelectionConfig(selection, chain) {
|
|
24
23
|
var nonOptionalBlockFieldNames = new Set();
|
|
@@ -132,7 +131,7 @@ function make(param) {
|
|
|
132
131
|
var chain = param.chain;
|
|
133
132
|
var getSelectionConfig = memoGetSelectionConfig(chain);
|
|
134
133
|
var apiToken = Belt_Option.getWithDefault(param.apiToken, "3dc856dd-b0ea-494f-b27e-017b8b6b7e07");
|
|
135
|
-
var client = HyperSyncClient.make(endpointUrl, apiToken, param.clientTimeoutMillis, param.clientMaxRetries, !lowercaseAddresses);
|
|
134
|
+
var client = HyperSyncClient.make(endpointUrl, apiToken, param.clientTimeoutMillis, param.clientMaxRetries, !lowercaseAddresses, param.serializationFormat, param.enableQueryCaching, undefined, undefined, undefined);
|
|
136
135
|
var hscDecoder = {
|
|
137
136
|
contents: undefined
|
|
138
137
|
};
|
|
@@ -385,26 +384,31 @@ function make(param) {
|
|
|
385
384
|
var getBlockHashes = function (blockNumbers, logger) {
|
|
386
385
|
return HyperSync.queryBlockDataMulti(endpointUrl, apiToken, blockNumbers, logger).then(HyperSync.mapExn);
|
|
387
386
|
};
|
|
388
|
-
var
|
|
387
|
+
var heightStream = HyperSyncHeightStream.make(endpointUrl, apiToken);
|
|
389
388
|
return {
|
|
390
389
|
name: "HyperSync",
|
|
391
390
|
sourceFor: "Sync",
|
|
392
391
|
chain: chain,
|
|
393
392
|
poweredByHyperSync: true,
|
|
394
|
-
pollingInterval:
|
|
393
|
+
pollingInterval: 32,
|
|
395
394
|
getBlockHashes: getBlockHashes,
|
|
396
395
|
getHeightOrThrow: (async function () {
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
396
|
+
try {
|
|
397
|
+
return await HyperSyncHeightStream.getHeight(heightStream);
|
|
398
|
+
}
|
|
399
|
+
catch (raw_exn){
|
|
400
|
+
var exn = Caml_js_exceptions.internalToOCamlException(raw_exn);
|
|
401
|
+
if (exn.RE_EXN_ID === Js_exn.$$Error) {
|
|
402
|
+
if (Belt_Option.getWithDefault(exn._1.message, "").includes("Your token is malformed. For more info: https://docs.envio.dev/docs/HyperSync/api-tokens.")) {
|
|
403
|
+
Logging.error("Your ENVIO_API_TOKEN is malformed. The indexer will not be able to fetch events. Update the token and restart the indexer using 'pnpm envio start'. For more info: https://docs.envio.dev/docs/HyperSync/api-tokens");
|
|
404
|
+
await new Promise((function (param, param$1) {
|
|
405
|
+
|
|
406
|
+
}));
|
|
407
|
+
return 0;
|
|
408
|
+
}
|
|
409
|
+
throw exn;
|
|
410
|
+
}
|
|
411
|
+
throw exn;
|
|
408
412
|
}
|
|
409
413
|
}),
|
|
410
414
|
getItemsOrThrow: getItemsOrThrow
|
|
@@ -414,4 +418,4 @@ function make(param) {
|
|
|
414
418
|
exports.getSelectionConfig = getSelectionConfig;
|
|
415
419
|
exports.memoGetSelectionConfig = memoGetSelectionConfig;
|
|
416
420
|
exports.make = make;
|
|
417
|
-
/*
|
|
421
|
+
/* Viem Not a pure module */
|