envio 3.3.1 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +6 -6
- package/src/Api.res +1 -8
- package/src/Api.res.mjs +1 -5
- package/src/ChainState.res +6 -1
- package/src/ChainState.res.mjs +4 -3
- package/src/Config.res +33 -4
- package/src/Config.res.mjs +34 -5
- package/src/Core.res +30 -19
- package/src/Core.res.mjs +5 -5
- package/src/EnvioGlobal.res +0 -2
- package/src/EnvioGlobal.res.mjs +0 -1
- package/src/ExitOnCaughtUp.res +6 -2
- package/src/ExitOnCaughtUp.res.mjs +4 -0
- package/src/FetchState.res +3 -3
- package/src/HandlerRegister.res +357 -434
- package/src/HandlerRegister.res.mjs +202 -242
- package/src/HandlerRegister.resi +7 -15
- package/src/IndexerState.res +10 -0
- package/src/IndexerState.res.mjs +9 -3
- package/src/IndexerState.resi +3 -0
- package/src/Internal.res +10 -1
- package/src/Main.res.mjs +4 -4
- package/src/PgStorage.res +52 -26
- package/src/PgStorage.res.mjs +32 -23
- package/src/SimulateItems.res +61 -40
- package/src/SimulateItems.res.mjs +37 -21
- package/src/TestIndexer.res +446 -453
- package/src/TestIndexer.res.mjs +320 -343
- package/src/bindings/ClickHouse.res +68 -2
- package/src/bindings/ClickHouse.res.mjs +47 -2
- package/src/sources/EvmChain.res +1 -1
- package/src/sources/EvmChain.res.mjs +2 -2
- package/src/sources/FuelHyperSync.res +74 -0
- package/src/sources/FuelHyperSync.res.mjs +80 -0
- package/src/sources/FuelHyperSync.resi +22 -0
- package/src/sources/FuelHyperSyncClient.res +120 -0
- package/src/sources/FuelHyperSyncClient.res.mjs +71 -0
- package/src/sources/FuelHyperSyncSource.res +257 -0
- package/src/sources/FuelHyperSyncSource.res.mjs +252 -0
- package/src/sources/HyperSyncClient.res +2 -2
- package/src/sources/HyperSyncClient.res.mjs +1 -1
- package/src/sources/SvmHyperSyncClient.res +139 -102
- package/src/sources/SvmHyperSyncClient.res.mjs +45 -5
- package/src/sources/SvmHyperSyncSource.res +60 -440
- package/src/sources/SvmHyperSyncSource.res.mjs +42 -363
- package/src/TestIndexerProxyStorage.res +0 -196
- package/src/TestIndexerProxyStorage.res.mjs +0 -121
- package/src/TestIndexerWorker.res +0 -4
- package/src/TestIndexerWorker.res.mjs +0 -7
- package/src/sources/EventRouter.res +0 -165
- package/src/sources/EventRouter.res.mjs +0 -153
- package/src/sources/HyperFuel.res +0 -179
- package/src/sources/HyperFuel.res.mjs +0 -146
- package/src/sources/HyperFuel.resi +0 -36
- package/src/sources/HyperFuelClient.res +0 -127
- package/src/sources/HyperFuelClient.res.mjs +0 -20
- package/src/sources/HyperFuelSource.res +0 -502
- package/src/sources/HyperFuelSource.res.mjs +0 -481
- /package/src/sources/{HyperSyncSource.res → EvmHyperSyncSource.res} +0 -0
- /package/src/sources/{HyperSyncSource.res.mjs → EvmHyperSyncSource.res.mjs} +0 -0
|
@@ -353,6 +353,72 @@ let makeCreateHistoryTableQuery = (
|
|
|
353
353
|
}
|
|
354
354
|
})
|
|
355
355
|
|
|
356
|
+
let (partitionBy, orderBy, ttl) = switch entityConfig.storage.clickhouseOptions {
|
|
357
|
+
| Some(options) => (options.partitionBy, options.orderBy, options.ttl)
|
|
358
|
+
| None => (None, None, None)
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Schema field name -> ClickHouse column name, so @storage(clickhouse: {...})
|
|
362
|
+
// options can reference fields the way they're written in the schema and get
|
|
363
|
+
// renames (`column_name_format: snake_case`) and linked-entity `_id` suffixes
|
|
364
|
+
// resolved here.
|
|
365
|
+
let columnByFieldName = Dict.make()
|
|
366
|
+
entityConfig.table.fields->Array.forEach(field =>
|
|
367
|
+
switch field {
|
|
368
|
+
| Field(f) => columnByFieldName->Dict.set(f.fieldName, f->Table.getClickHouseDbFieldName)
|
|
369
|
+
| DerivedFrom(_) => ()
|
|
370
|
+
}
|
|
371
|
+
)
|
|
372
|
+
|
|
373
|
+
let orderByColumns = switch orderBy {
|
|
374
|
+
| Some(fieldNames) =>
|
|
375
|
+
// envio_checkpoint_id stays appended so the sorting key keeps a
|
|
376
|
+
// deterministic tie-break and the view's checkpoint dedup gets a clean
|
|
377
|
+
// ascending run per prefix. id is dropped: ClickHouse entities are
|
|
378
|
+
// read-only, so nothing looks history rows up by id.
|
|
379
|
+
let userColumns =
|
|
380
|
+
fieldNames
|
|
381
|
+
->Array.map(fieldName =>
|
|
382
|
+
switch columnByFieldName->Dict.get(fieldName) {
|
|
383
|
+
| Some(column) => `\`${column}\``
|
|
384
|
+
| None =>
|
|
385
|
+
// Validated at codegen, so a miss means the schema and the
|
|
386
|
+
// persisted config diverged.
|
|
387
|
+
JsError.throwWithMessage(
|
|
388
|
+
`ClickHouse orderBy field "${fieldName}" is not defined on entity "${entityConfig.name}"`,
|
|
389
|
+
)
|
|
390
|
+
}
|
|
391
|
+
)
|
|
392
|
+
->Array.joinUnsafe(", ")
|
|
393
|
+
`${userColumns}, ${EntityHistory.checkpointIdFieldName}`
|
|
394
|
+
| None => `${Table.idFieldName}, ${EntityHistory.checkpointIdFieldName}`
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// partitionBy/ttl are raw ClickHouse expressions. Rewrite any bare identifier
|
|
398
|
+
// that names an entity field to that field's ClickHouse column, leaving
|
|
399
|
+
// functions, keywords, numbers, string literals and already-backticked
|
|
400
|
+
// identifiers untouched (a quoted token never matches a bare field name).
|
|
401
|
+
let resolveExpressionColumns = expression =>
|
|
402
|
+
expression->String.replaceRegExpBy0Unsafe(/'[^']*'|`[^`]*`|[A-Za-z_][A-Za-z0-9_]*/g, (
|
|
403
|
+
~match,
|
|
404
|
+
~offset as _,
|
|
405
|
+
~input as _,
|
|
406
|
+
) =>
|
|
407
|
+
switch columnByFieldName->Dict.get(match) {
|
|
408
|
+
| Some(column) => `\`${column}\``
|
|
409
|
+
| None => match
|
|
410
|
+
}
|
|
411
|
+
)
|
|
412
|
+
|
|
413
|
+
let partitionByClause = switch partitionBy {
|
|
414
|
+
| Some(expression) => `\nPARTITION BY ${expression->resolveExpressionColumns}`
|
|
415
|
+
| None => ""
|
|
416
|
+
}
|
|
417
|
+
let ttlClause = switch ttl {
|
|
418
|
+
| Some(expression) => `\nTTL ${expression->resolveExpressionColumns}`
|
|
419
|
+
| None => ""
|
|
420
|
+
}
|
|
421
|
+
|
|
356
422
|
`CREATE TABLE IF NOT EXISTS ${database}.\`${EntityHistory.historyTableName(
|
|
357
423
|
~entityName=entityConfig.name,
|
|
358
424
|
~entityIndex=entityConfig.index,
|
|
@@ -369,8 +435,8 @@ let makeCreateHistoryTableQuery = (
|
|
|
369
435
|
~isArray=false,
|
|
370
436
|
)}
|
|
371
437
|
)
|
|
372
|
-
ENGINE = ${tableEngine}
|
|
373
|
-
ORDER BY (${
|
|
438
|
+
ENGINE = ${tableEngine}${partitionByClause}
|
|
439
|
+
ORDER BY (${orderByColumns})${ttlClause}`
|
|
374
440
|
}
|
|
375
441
|
|
|
376
442
|
// Generate CREATE TABLE query for checkpoints
|
|
@@ -260,6 +260,51 @@ function makeCreateHistoryTableQuery(entityConfig, database, replicatedOpt, onCl
|
|
|
260
260
|
let clickHouseType = getClickHouseFieldType(field$1.fieldType, field$1.isNullable, field$1.isArray);
|
|
261
261
|
return `\`` + fieldName + `\` ` + clickHouseType;
|
|
262
262
|
});
|
|
263
|
+
let options = entityConfig.storage.clickhouseOptions;
|
|
264
|
+
let match = options !== undefined ? [
|
|
265
|
+
options.partitionBy,
|
|
266
|
+
options.orderBy,
|
|
267
|
+
options.ttl
|
|
268
|
+
] : [
|
|
269
|
+
undefined,
|
|
270
|
+
undefined,
|
|
271
|
+
undefined
|
|
272
|
+
];
|
|
273
|
+
let ttl = match[2];
|
|
274
|
+
let orderBy = match[1];
|
|
275
|
+
let partitionBy = match[0];
|
|
276
|
+
let columnByFieldName = {};
|
|
277
|
+
entityConfig.table.fields.forEach(field => {
|
|
278
|
+
if (field.TAG !== "Field") {
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
let f = field._0;
|
|
282
|
+
columnByFieldName[f.fieldName] = Table.getClickHouseDbFieldName(f);
|
|
283
|
+
});
|
|
284
|
+
let orderByColumns;
|
|
285
|
+
if (orderBy !== undefined) {
|
|
286
|
+
let userColumns = orderBy.map(fieldName => {
|
|
287
|
+
let column = columnByFieldName[fieldName];
|
|
288
|
+
if (column !== undefined) {
|
|
289
|
+
return `\`` + column + `\``;
|
|
290
|
+
} else {
|
|
291
|
+
return Stdlib_JsError.throwWithMessage(`ClickHouse orderBy field "` + fieldName + `" is not defined on entity "` + entityConfig.name + `"`);
|
|
292
|
+
}
|
|
293
|
+
}).join(", ");
|
|
294
|
+
orderByColumns = userColumns + `, ` + EntityHistory.checkpointIdFieldName;
|
|
295
|
+
} else {
|
|
296
|
+
orderByColumns = Table.idFieldName + `, ` + EntityHistory.checkpointIdFieldName;
|
|
297
|
+
}
|
|
298
|
+
let resolveExpressionColumns = expression => expression.replace(/'[^']*'|`[^`]*`|[A-Za-z_][A-Za-z0-9_]*/g, (match, param, param$1) => {
|
|
299
|
+
let column = columnByFieldName[match];
|
|
300
|
+
if (column !== undefined) {
|
|
301
|
+
return `\`` + column + `\``;
|
|
302
|
+
} else {
|
|
303
|
+
return match;
|
|
304
|
+
}
|
|
305
|
+
});
|
|
306
|
+
let partitionByClause = partitionBy !== undefined ? `\nPARTITION BY ` + resolveExpressionColumns(partitionBy) : "";
|
|
307
|
+
let ttlClause = ttl !== undefined ? `\nTTL ` + resolveExpressionColumns(ttl) : "";
|
|
263
308
|
return `CREATE TABLE IF NOT EXISTS ` + database + `.\`` + EntityHistory.historyTableName(entityConfig.name, entityConfig.index) + `\`` + (
|
|
264
309
|
onCluster ? ` ON CLUSTER '{cluster}'` : ""
|
|
265
310
|
) + ` (
|
|
@@ -270,8 +315,8 @@ function makeCreateHistoryTableQuery(entityConfig, database, replicatedOpt, onCl
|
|
|
270
315
|
config: EntityHistory.RowAction.config
|
|
271
316
|
}, false, false) + `
|
|
272
317
|
)
|
|
273
|
-
ENGINE = ` + tableEngine + `
|
|
274
|
-
ORDER BY (` +
|
|
318
|
+
ENGINE = ` + tableEngine + partitionByClause + `
|
|
319
|
+
ORDER BY (` + orderByColumns + `)` + ttlClause;
|
|
275
320
|
}
|
|
276
321
|
|
|
277
322
|
function makeCreateCheckpointsTableQuery(database, replicatedOpt, onClusterOpt) {
|
package/src/sources/EvmChain.res
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import * as Env from "../Env.res.mjs";
|
|
4
4
|
import * as RpcSource from "./RpcSource.res.mjs";
|
|
5
5
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
6
|
-
import * as
|
|
6
|
+
import * as EvmHyperSyncSource from "./EvmHyperSyncSource.res.mjs";
|
|
7
7
|
|
|
8
8
|
function getSyncConfig(param) {
|
|
9
9
|
let queryTimeoutMillis = Stdlib_Option.getOr(param.queryTimeoutMillis, 20000);
|
|
@@ -20,7 +20,7 @@ function getSyncConfig(param) {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
function makeSources(chain, onEventRegistrations, hyperSync, rpcs, lowercaseAddresses) {
|
|
23
|
-
let sources = hyperSync !== undefined ? [
|
|
23
|
+
let sources = hyperSync !== undefined ? [EvmHyperSyncSource.make({
|
|
24
24
|
chain: chain,
|
|
25
25
|
endpointUrl: hyperSync,
|
|
26
26
|
onEventRegistrations: onEventRegistrations,
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
type logsQueryPage = {
|
|
2
|
+
items: array<FuelHyperSyncClient.EventItems.item>,
|
|
3
|
+
// Blocks referenced by `items`, one per height.
|
|
4
|
+
blocks: array<FuelHyperSyncClient.EventItems.block>,
|
|
5
|
+
nextBlock: int,
|
|
6
|
+
archiveHeight: int,
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
module GetLogs = {
|
|
10
|
+
type error =
|
|
11
|
+
| UnexpectedMissingParams({missingParams: array<string>})
|
|
12
|
+
| WrongInstance
|
|
13
|
+
|
|
14
|
+
exception Error(error)
|
|
15
|
+
|
|
16
|
+
// Rust encodes structured failures as a JSON payload in the napi error's
|
|
17
|
+
// message: `{"kind":"MissingFields","fields":["receipt.txId", ...]}`.
|
|
18
|
+
// JSON.parse + shape check is the recovery protocol — no string-grepping
|
|
19
|
+
// on anyhow's Debug format.
|
|
20
|
+
let extractMissingParams = (exn: exn): option<array<string>> => {
|
|
21
|
+
let message = switch exn {
|
|
22
|
+
| JsExn(jsExn) => jsExn->JsExn.message
|
|
23
|
+
| _ => None
|
|
24
|
+
}
|
|
25
|
+
switch message {
|
|
26
|
+
| None => None
|
|
27
|
+
| Some(msg) =>
|
|
28
|
+
switch msg->JSON.parseOrThrow->JSON.Decode.object {
|
|
29
|
+
| exception _ => None
|
|
30
|
+
| None => None
|
|
31
|
+
| Some(obj) =>
|
|
32
|
+
switch (obj->Dict.get("kind"), obj->Dict.get("fields")) {
|
|
33
|
+
| (Some(String("MissingFields")), Some(Array(fields))) =>
|
|
34
|
+
Some(fields->Array.filterMap(JSON.Decode.string))
|
|
35
|
+
| _ => None
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
let query = async (
|
|
42
|
+
~client: FuelHyperSyncClient.t,
|
|
43
|
+
~fromBlock,
|
|
44
|
+
~toBlock,
|
|
45
|
+
~registrationIndexes,
|
|
46
|
+
~addressesByContractName,
|
|
47
|
+
): logsQueryPage => {
|
|
48
|
+
let query: FuelHyperSyncClient.EventItems.query = {
|
|
49
|
+
fromBlock,
|
|
50
|
+
toBlock,
|
|
51
|
+
registrationIndexes,
|
|
52
|
+
addressesByContractName,
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
let res = switch await client->FuelHyperSyncClient.getEventItems(query) {
|
|
56
|
+
| res => res
|
|
57
|
+
| exception exn =>
|
|
58
|
+
switch exn->extractMissingParams {
|
|
59
|
+
| Some(missingParams) => throw(Error(UnexpectedMissingParams({missingParams: missingParams})))
|
|
60
|
+
| None => throw(exn)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if res.nextBlock <= fromBlock {
|
|
64
|
+
// Might happen when /height response was from another instance of HyperFuel
|
|
65
|
+
throw(Error(WrongInstance))
|
|
66
|
+
}
|
|
67
|
+
{
|
|
68
|
+
items: res.items,
|
|
69
|
+
blocks: res.blocks,
|
|
70
|
+
nextBlock: res.nextBlock,
|
|
71
|
+
archiveHeight: res.archiveHeight->Option.getOr(0), // TODO: FIXME: Shouldn't have a default here
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Stdlib_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
|
|
4
|
+
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
5
|
+
import * as Stdlib_JsExn from "@rescript/runtime/lib/es6/Stdlib_JsExn.js";
|
|
6
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
7
|
+
import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
|
|
8
|
+
|
|
9
|
+
let $$Error = /* @__PURE__ */Primitive_exceptions.create("FuelHyperSync.GetLogs.Error");
|
|
10
|
+
|
|
11
|
+
function extractMissingParams(exn) {
|
|
12
|
+
let message = exn.RE_EXN_ID === "JsExn" ? Stdlib_JsExn.message(exn._1) : undefined;
|
|
13
|
+
if (message === undefined) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
let obj;
|
|
17
|
+
try {
|
|
18
|
+
obj = Stdlib_JSON.Decode.object(JSON.parse(message));
|
|
19
|
+
} catch (exn$1) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
if (obj === undefined) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
let match = obj["kind"];
|
|
26
|
+
let match$1 = obj["fields"];
|
|
27
|
+
if (match === "MissingFields" && Array.isArray(match$1)) {
|
|
28
|
+
return Stdlib_Array.filterMap(match$1, Stdlib_JSON.Decode.string);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function query(client, fromBlock, toBlock, registrationIndexes, addressesByContractName) {
|
|
33
|
+
let query$1 = {
|
|
34
|
+
fromBlock: fromBlock,
|
|
35
|
+
toBlock: toBlock,
|
|
36
|
+
registrationIndexes: registrationIndexes,
|
|
37
|
+
addressesByContractName: addressesByContractName
|
|
38
|
+
};
|
|
39
|
+
let res;
|
|
40
|
+
try {
|
|
41
|
+
res = await client.getEventItems(query$1);
|
|
42
|
+
} catch (raw_exn) {
|
|
43
|
+
let exn = Primitive_exceptions.internalToException(raw_exn);
|
|
44
|
+
let missingParams = extractMissingParams(exn);
|
|
45
|
+
if (missingParams !== undefined) {
|
|
46
|
+
throw {
|
|
47
|
+
RE_EXN_ID: $$Error,
|
|
48
|
+
_1: {
|
|
49
|
+
TAG: "UnexpectedMissingParams",
|
|
50
|
+
missingParams: missingParams
|
|
51
|
+
},
|
|
52
|
+
Error: new Error()
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
throw exn;
|
|
56
|
+
}
|
|
57
|
+
if (res.nextBlock <= fromBlock) {
|
|
58
|
+
throw {
|
|
59
|
+
RE_EXN_ID: $$Error,
|
|
60
|
+
_1: "WrongInstance",
|
|
61
|
+
Error: new Error()
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
items: res.items,
|
|
66
|
+
blocks: res.blocks,
|
|
67
|
+
nextBlock: res.nextBlock,
|
|
68
|
+
archiveHeight: Stdlib_Option.getOr(res.archiveHeight, 0)
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
let GetLogs = {
|
|
73
|
+
$$Error: $$Error,
|
|
74
|
+
query: query
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export {
|
|
78
|
+
GetLogs,
|
|
79
|
+
}
|
|
80
|
+
/* Stdlib_JsExn Not a pure module */
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
type logsQueryPage = {
|
|
2
|
+
items: array<FuelHyperSyncClient.EventItems.item>,
|
|
3
|
+
blocks: array<FuelHyperSyncClient.EventItems.block>,
|
|
4
|
+
nextBlock: int,
|
|
5
|
+
archiveHeight: int,
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
module GetLogs: {
|
|
9
|
+
type error =
|
|
10
|
+
| UnexpectedMissingParams({missingParams: array<string>})
|
|
11
|
+
| WrongInstance
|
|
12
|
+
|
|
13
|
+
exception Error(error)
|
|
14
|
+
|
|
15
|
+
let query: (
|
|
16
|
+
~client: FuelHyperSyncClient.t,
|
|
17
|
+
~fromBlock: int,
|
|
18
|
+
~toBlock: option<int>,
|
|
19
|
+
~registrationIndexes: array<int>,
|
|
20
|
+
~addressesByContractName: dict<array<Address.t>>,
|
|
21
|
+
) => promise<logsQueryPage>
|
|
22
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
type t
|
|
2
|
+
|
|
3
|
+
type cfg = {
|
|
4
|
+
url: string,
|
|
5
|
+
apiToken: string,
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
module Registration = {
|
|
9
|
+
type kind =
|
|
10
|
+
| @as("LogData") LogData
|
|
11
|
+
| @as("Mint") Mint
|
|
12
|
+
| @as("Burn") Burn
|
|
13
|
+
| @as("Transfer") Transfer
|
|
14
|
+
| @as("Call") Call
|
|
15
|
+
|
|
16
|
+
// The full per-(event, chain) registration passed to the Rust client at
|
|
17
|
+
// construction: routing identity plus the receipt-selection state queries
|
|
18
|
+
// are built from.
|
|
19
|
+
type input = {
|
|
20
|
+
// Chain-scoped sequential registration index, echoed back on routed items.
|
|
21
|
+
index: int,
|
|
22
|
+
eventName: string,
|
|
23
|
+
contractName: string,
|
|
24
|
+
isWildcard: bool,
|
|
25
|
+
kind: kind,
|
|
26
|
+
// The LogData `rb` value as a decimal string; absent for other kinds.
|
|
27
|
+
logId?: string,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
let fromOnEventRegistrations = (
|
|
31
|
+
onEventRegistrations: array<Internal.fuelOnEventRegistration>,
|
|
32
|
+
): array<input> =>
|
|
33
|
+
onEventRegistrations->Array.map(reg => {
|
|
34
|
+
let eventConfig =
|
|
35
|
+
reg.eventConfig->(Utils.magic: Internal.eventConfig => Internal.fuelEventConfig)
|
|
36
|
+
let (kind, logId) = switch eventConfig.kind {
|
|
37
|
+
| LogData({logId}) => (LogData, Some(logId))
|
|
38
|
+
| Mint => (Mint, None)
|
|
39
|
+
| Burn => (Burn, None)
|
|
40
|
+
| Transfer => (Transfer, None)
|
|
41
|
+
| Call => (Call, None)
|
|
42
|
+
}
|
|
43
|
+
{
|
|
44
|
+
index: reg.index,
|
|
45
|
+
eventName: eventConfig.name,
|
|
46
|
+
contractName: eventConfig.contractName,
|
|
47
|
+
isWildcard: reg.isWildcard,
|
|
48
|
+
kind,
|
|
49
|
+
?logId,
|
|
50
|
+
}
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
module EventItems = {
|
|
55
|
+
// The whole per-query input: block range, the partition's registration
|
|
56
|
+
// selection (by index), and its current addresses. Receipt selections,
|
|
57
|
+
// field selection, and routing are derived on the Rust side.
|
|
58
|
+
type query = {
|
|
59
|
+
fromBlock: int,
|
|
60
|
+
// Inclusive; None queries to the end of available data.
|
|
61
|
+
toBlock: option<int>,
|
|
62
|
+
registrationIndexes: array<int>,
|
|
63
|
+
addressesByContractName: dict<array<Address.t>>,
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// One routed receipt with its kind-specific columns flattened: LogData
|
|
67
|
+
// carries `data` (decoded here in JS), Mint/Burn carry `val`/`subId`,
|
|
68
|
+
// Transfer/TransferOut/Call carry `amount`/`assetId`/`to` (TransferOut's
|
|
69
|
+
// wallet recipient normalised into `to`).
|
|
70
|
+
type item = {
|
|
71
|
+
onEventRegistrationIndex: int,
|
|
72
|
+
receiptIndex: int,
|
|
73
|
+
txId: string,
|
|
74
|
+
blockHeight: int,
|
|
75
|
+
srcAddress: Address.t,
|
|
76
|
+
data?: string,
|
|
77
|
+
subId?: string,
|
|
78
|
+
val?: bigint,
|
|
79
|
+
amount?: bigint,
|
|
80
|
+
assetId?: string,
|
|
81
|
+
to?: string,
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
type block = {
|
|
85
|
+
id: string,
|
|
86
|
+
height: int,
|
|
87
|
+
time: int,
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
type response = {
|
|
91
|
+
archiveHeight: option<int>,
|
|
92
|
+
nextBlock: int,
|
|
93
|
+
// One block per height; items reference them by `blockHeight`.
|
|
94
|
+
blocks: array<block>,
|
|
95
|
+
items: array<item>,
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
@send
|
|
100
|
+
external classNew: (
|
|
101
|
+
Core.fuelHyperSyncClientCtor,
|
|
102
|
+
cfg,
|
|
103
|
+
~userAgent: string,
|
|
104
|
+
array<Registration.input>,
|
|
105
|
+
) => t = "new"
|
|
106
|
+
|
|
107
|
+
let make = (cfg: cfg, ~eventRegistrations) => {
|
|
108
|
+
let envioVersion = Utils.EnvioPackage.value.version
|
|
109
|
+
Core.getAddon().fuelHyperSyncClient->classNew(
|
|
110
|
+
cfg,
|
|
111
|
+
~userAgent=`hyperindex/${envioVersion}`,
|
|
112
|
+
eventRegistrations,
|
|
113
|
+
)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
@send
|
|
117
|
+
external getEventItems: (t, EventItems.query) => promise<EventItems.response> = "getEventItems"
|
|
118
|
+
|
|
119
|
+
@send
|
|
120
|
+
external getHeight: t => promise<int> = "getHeight"
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Core from "../Core.res.mjs";
|
|
4
|
+
import * as Utils from "../Utils.res.mjs";
|
|
5
|
+
|
|
6
|
+
function fromOnEventRegistrations(onEventRegistrations) {
|
|
7
|
+
return onEventRegistrations.map(reg => {
|
|
8
|
+
let eventConfig = reg.eventConfig;
|
|
9
|
+
let match = eventConfig.kind;
|
|
10
|
+
let match$1;
|
|
11
|
+
if (typeof match !== "object") {
|
|
12
|
+
switch (match) {
|
|
13
|
+
case "Mint" :
|
|
14
|
+
match$1 = [
|
|
15
|
+
"Mint",
|
|
16
|
+
undefined
|
|
17
|
+
];
|
|
18
|
+
break;
|
|
19
|
+
case "Burn" :
|
|
20
|
+
match$1 = [
|
|
21
|
+
"Burn",
|
|
22
|
+
undefined
|
|
23
|
+
];
|
|
24
|
+
break;
|
|
25
|
+
case "Transfer" :
|
|
26
|
+
match$1 = [
|
|
27
|
+
"Transfer",
|
|
28
|
+
undefined
|
|
29
|
+
];
|
|
30
|
+
break;
|
|
31
|
+
case "Call" :
|
|
32
|
+
match$1 = [
|
|
33
|
+
"Call",
|
|
34
|
+
undefined
|
|
35
|
+
];
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
} else {
|
|
39
|
+
match$1 = [
|
|
40
|
+
"LogData",
|
|
41
|
+
match.logId
|
|
42
|
+
];
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
index: reg.index,
|
|
46
|
+
eventName: eventConfig.name,
|
|
47
|
+
contractName: eventConfig.contractName,
|
|
48
|
+
isWildcard: reg.isWildcard,
|
|
49
|
+
kind: match$1[0],
|
|
50
|
+
logId: match$1[1]
|
|
51
|
+
};
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
let Registration = {
|
|
56
|
+
fromOnEventRegistrations: fromOnEventRegistrations
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
let EventItems = {};
|
|
60
|
+
|
|
61
|
+
function make(cfg, eventRegistrations) {
|
|
62
|
+
let envioVersion = Utils.EnvioPackage.value.version;
|
|
63
|
+
return Core.getAddon().FuelHyperSyncClient.new(cfg, `hyperindex/` + envioVersion, eventRegistrations);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export {
|
|
67
|
+
Registration,
|
|
68
|
+
EventItems,
|
|
69
|
+
make,
|
|
70
|
+
}
|
|
71
|
+
/* Core Not a pure module */
|