envio 3.11.0 → 3.12.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.
Files changed (89) hide show
  1. package/index.d.ts +3 -0
  2. package/package.json +6 -6
  3. package/src/Batch.res +111 -78
  4. package/src/Batch.res.mjs +53 -46
  5. package/src/BatchProcessing.res +1 -11
  6. package/src/BatchProcessing.res.mjs +1 -4
  7. package/src/ChainState.res +72 -19
  8. package/src/ChainState.res.mjs +50 -12
  9. package/src/ChainState.resi +5 -0
  10. package/src/Config.res +58 -37
  11. package/src/Config.res.mjs +63 -53
  12. package/src/CrossChainState.res +49 -52
  13. package/src/CrossChainState.res.mjs +25 -23
  14. package/src/CrossChainState.resi +6 -13
  15. package/src/EffectState.res +13 -4
  16. package/src/EffectState.resi +7 -1
  17. package/src/EventProcessing.res +6 -6
  18. package/src/EventProcessing.res.mjs +6 -6
  19. package/src/FetchState.res +14 -0
  20. package/src/FetchState.res.mjs +14 -0
  21. package/src/FinalizeBackfill.res +16 -12
  22. package/src/FinalizeBackfill.res.mjs +3 -3
  23. package/src/HistoryPolicy.res +46 -0
  24. package/src/HistoryPolicy.res.mjs +50 -0
  25. package/src/InMemoryStore.res +30 -32
  26. package/src/InMemoryStore.res.mjs +33 -28
  27. package/src/IndexerState.res +66 -45
  28. package/src/IndexerState.res.mjs +57 -29
  29. package/src/IndexerState.resi +8 -13
  30. package/src/Internal.res +4 -2
  31. package/src/LoadLayer.res +11 -4
  32. package/src/LoadLayer.res.mjs +8 -5
  33. package/src/Main.res +25 -24
  34. package/src/Main.res.mjs +24 -25
  35. package/src/Metrics.res +49 -1
  36. package/src/Metrics.res.mjs +26 -3
  37. package/src/Persistence.res +55 -16
  38. package/src/Persistence.res.mjs +18 -3
  39. package/src/PgStorage.res +194 -118
  40. package/src/PgStorage.res.mjs +132 -72
  41. package/src/PruneStaleHistory.res +9 -15
  42. package/src/PruneStaleHistory.res.mjs +11 -20
  43. package/src/Rollback.res +9 -14
  44. package/src/Rollback.res.mjs +5 -3
  45. package/src/Sink.res +7 -5
  46. package/src/Sink.res.mjs +4 -4
  47. package/src/Staging.res +298 -0
  48. package/src/Staging.res.mjs +257 -0
  49. package/src/TestIndexer.res +5 -5
  50. package/src/TestIndexer.res.mjs +7 -6
  51. package/src/UserContext.res +7 -4
  52. package/src/UserContext.res.mjs +5 -2
  53. package/src/Utils.res +9 -0
  54. package/src/Utils.res.mjs +9 -0
  55. package/src/Writing.res +34 -20
  56. package/src/Writing.res.mjs +15 -20
  57. package/src/bindings/ClickHouse.res +41 -34
  58. package/src/bindings/ClickHouse.res.mjs +36 -30
  59. package/src/bindings/ClickHouseSink.res +45 -186
  60. package/src/bindings/ClickHouseSink.res.mjs +21 -174
  61. package/src/db/CheckpointSequence.res +109 -0
  62. package/src/db/CheckpointSequence.res.mjs +99 -0
  63. package/src/db/EntityHistory.res +6 -5
  64. package/src/db/EntityHistory.res.mjs +5 -5
  65. package/src/db/Frontier.res +86 -0
  66. package/src/db/Frontier.res.mjs +126 -0
  67. package/src/db/InternalTable.res +145 -27
  68. package/src/db/InternalTable.res.mjs +115 -29
  69. package/src/db/RollbackFloors.res +34 -41
  70. package/src/db/RollbackFloors.res.mjs +27 -71
  71. package/src/sources/BlockStore.res +3 -0
  72. package/src/sources/EvmHyperSyncSource.res +3 -1
  73. package/src/sources/EvmHyperSyncSource.res.mjs +2 -1
  74. package/src/sources/HyperSync.res +2 -0
  75. package/src/sources/HyperSync.res.mjs +1 -0
  76. package/src/sources/HyperSync.resi +1 -0
  77. package/src/sources/HyperSyncClient.res +3 -0
  78. package/src/sources/RequestStat.res +8 -1
  79. package/src/sources/Source.res +4 -3
  80. package/src/sources/SourceManager.res +30 -10
  81. package/src/sources/SourceManager.res.mjs +24 -7
  82. package/src/sources/SourceManager.resi +2 -0
  83. package/src/tui/Tui.res +56 -143
  84. package/src/tui/Tui.res.mjs +70 -166
  85. package/src/tui/components/TuiData.res +61 -16
  86. package/src/tui/components/TuiData.res.mjs +53 -15
  87. package/svm.schema.json +0 -7
  88. package/src/db/CheckpointBounds.res +0 -53
  89. package/src/db/CheckpointBounds.res.mjs +0 -44
@@ -0,0 +1,109 @@
1
+ // How checkpoint ids are handed out. A schema with a cross-chain entity has
2
+ // rows any chain's reorg can reach, so its checkpoints have to be comparable
3
+ // across chains and come from one shared counter. Without one, no chain can
4
+ // touch another's rows, and each gets a counter of its own — which is what lets
5
+ // a rollback, a prune or a resume name one chain without saying anything about
6
+ // the others.
7
+ type t =
8
+ | SharedAcrossChains
9
+ | PerChain
10
+
11
+ let fromEntities = (entities: array<Internal.entityConfig>) =>
12
+ entities->Array.some(entityConfig => entityConfig.crossChain) ? SharedAcrossChains : PerChain
13
+
14
+ // Where a chain stands: under one shared counter that is wherever the counter
15
+ // got to, whichever chain moved it last.
16
+ let position = (sequence: t, frontier: Frontier.t, ~chainId) =>
17
+ switch sequence {
18
+ | SharedAcrossChains => frontier->Frontier.max
19
+ | PerChain => frontier->Frontier.get(chainId)
20
+ }
21
+
22
+ // The committed (or processed) id a scope's rows compare against. A chain scope
23
+ // reads its own. A cross-chain scope spans every chain: under one shared
24
+ // sequence the highest id is exactly how far the scope has got, while per-chain
25
+ // ids aren't comparable across chains, so only the lowest is an id every chain
26
+ // has passed.
27
+ let forScope = (sequence: t, frontier: Frontier.t, ~scope: Internal.chainScope) =>
28
+ switch scope {
29
+ | Chain(chainId) => frontier->Frontier.get(chainId)
30
+ | CrossChain =>
31
+ switch sequence {
32
+ | SharedAcrossChains => frontier->Frontier.max
33
+ | PerChain => frontier->Frontier.min
34
+ }
35
+ }
36
+
37
+ // The diff id a scope's rows carry after a rollback, taken from the frontier the
38
+ // rollback stamped them with. A per-chain rollback names only the chains it
39
+ // moved: a sibling it left alone has no diff row, and so no id to compare
40
+ // against.
41
+ let findForScope = (sequence: t, frontier: Frontier.t, ~scope: Internal.chainScope): option<
42
+ Internal.checkpointId,
43
+ > =>
44
+ switch scope {
45
+ | Chain(chainId) => frontier->Frontier.find(chainId)
46
+ | CrossChain => Some(sequence->forScope(frontier, ~scope))
47
+ }
48
+
49
+ // Hands out the ids of one batch, starting from where the frontier left each
50
+ // chain. Under `SharedAcrossChains` the ids come from a single run of the counter, so they
51
+ // interleave across chains in allocation order; under `PerChain` each chain
52
+ // continues its own.
53
+ type cursor = {sequence: t, frontier: Frontier.t}
54
+
55
+ let cursor = (sequence: t, ~frontier: Frontier.t) => {sequence, frontier: frontier->Frontier.copy}
56
+
57
+ let next = (cursor, ~chainId): Internal.checkpointId => {
58
+ let checkpointId = cursor.sequence->position(cursor.frontier, ~chainId)->BigInt.add(1n)
59
+ cursor.frontier->Frontier.set(chainId, checkpointId)
60
+ checkpointId
61
+ }
62
+
63
+ // The checkpoint id each chain's rows are compared against in a query,
64
+ // together with the sequence that decides how the comparison is rendered.
65
+ type checkpointBoundsByChain = {sequence: t, byChain: Frontier.t}
66
+
67
+ // The pieces a query splices in to read its bound as `checkpointId`.
68
+ type sql = {
69
+ join: string,
70
+ using: string,
71
+ usingMatch: string,
72
+ checkpointId: string,
73
+ }
74
+
75
+ // The chain ids are cast to the widest integer type rather than the column's
76
+ // own: nothing indexes the join, so the values only have to compare.
77
+ let relation = `unnest($1::${(Postgres.BigInt :> string)}[],$2::${(Postgres.BigInt :> string)}[]) AS envio_bounds(chain_id, checkpoint_id)`
78
+
79
+ let sql = (
80
+ bounds: checkpointBoundsByChain,
81
+ ~chainIdColumn: option<string>,
82
+ ~tableRef: string,
83
+ ): sql =>
84
+ switch (bounds.sequence, chainIdColumn) {
85
+ | (SharedAcrossChains, _) => {join: "", using: "", usingMatch: "", checkpointId: "$1"}
86
+ | (PerChain, Some(column)) =>
87
+ let chainMatch = `envio_bounds.chain_id = ${tableRef}."${column}"`
88
+ {
89
+ join: ` JOIN ${relation} ON ${chainMatch}`,
90
+ using: ` USING ${relation}`,
91
+ usingMatch: ` AND ${chainMatch}`,
92
+ checkpointId: "envio_bounds.checkpoint_id",
93
+ }
94
+ | (PerChain, None) =>
95
+ JsError.throwWithMessage(
96
+ "Internal error: per-chain checkpoint bounds can't bound a table with no chain-id column. Only a schema whose entities are all per-chain has them.",
97
+ )
98
+ }
99
+
100
+ // Bound in the order `sql` reads them: under one shared sequence the lowest of
101
+ // the ids as `$1` (every chain is held to it), otherwise the chains and their
102
+ // own ids as the two parallel arrays the relation unnests.
103
+ let params = (bounds: checkpointBoundsByChain): unknown =>
104
+ switch bounds.sequence {
105
+ | SharedAcrossChains =>
106
+ [bounds.byChain->Frontier.min->BigInt.toString]->(Utils.magic: array<string> => unknown)
107
+ | PerChain =>
108
+ bounds.byChain->Frontier.unnestParams->(Utils.magic: Frontier.unnestParams => unknown)
109
+ }
@@ -0,0 +1,99 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Frontier from "./Frontier.res.mjs";
4
+ import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
5
+
6
+ function fromEntities(entities) {
7
+ if (entities.some(entityConfig => entityConfig.crossChain)) {
8
+ return "SharedAcrossChains";
9
+ } else {
10
+ return "PerChain";
11
+ }
12
+ }
13
+
14
+ function position(sequence, frontier, chainId) {
15
+ if (sequence === "SharedAcrossChains") {
16
+ return Frontier.max(frontier);
17
+ } else {
18
+ return Frontier.get(frontier, chainId);
19
+ }
20
+ }
21
+
22
+ function forScope(sequence, frontier, scope) {
23
+ if (scope === "crossChain") {
24
+ if (sequence === "SharedAcrossChains") {
25
+ return Frontier.max(frontier);
26
+ } else {
27
+ return Frontier.min(frontier);
28
+ }
29
+ } else {
30
+ return Frontier.get(frontier, scope);
31
+ }
32
+ }
33
+
34
+ function findForScope(sequence, frontier, scope) {
35
+ if (scope === "crossChain") {
36
+ return forScope(sequence, frontier, scope);
37
+ } else {
38
+ return Frontier.find(frontier, scope);
39
+ }
40
+ }
41
+
42
+ function cursor(sequence, frontier) {
43
+ return {
44
+ sequence: sequence,
45
+ frontier: Frontier.copy(frontier)
46
+ };
47
+ }
48
+
49
+ function next(cursor, chainId) {
50
+ let checkpointId = position(cursor.sequence, cursor.frontier, chainId) + 1n;
51
+ Frontier.set(cursor.frontier, chainId, checkpointId);
52
+ return checkpointId;
53
+ }
54
+
55
+ let relation = `unnest($1::` + "BIGINT" + `[],$2::` + "BIGINT" + `[]) AS envio_bounds(chain_id, checkpoint_id)`;
56
+
57
+ function sql(bounds, chainIdColumn, tableRef) {
58
+ let match = bounds.sequence;
59
+ if (match === "SharedAcrossChains") {
60
+ return {
61
+ join: "",
62
+ using: "",
63
+ usingMatch: "",
64
+ checkpointId: "$1"
65
+ };
66
+ }
67
+ if (chainIdColumn === undefined) {
68
+ return Stdlib_JsError.throwWithMessage("Internal error: per-chain checkpoint bounds can't bound a table with no chain-id column. Only a schema whose entities are all per-chain has them.");
69
+ }
70
+ let chainMatch = `envio_bounds.chain_id = ` + tableRef + `."` + chainIdColumn + `"`;
71
+ return {
72
+ join: ` JOIN ` + relation + ` ON ` + chainMatch,
73
+ using: ` USING ` + relation,
74
+ usingMatch: ` AND ` + chainMatch,
75
+ checkpointId: "envio_bounds.checkpoint_id"
76
+ };
77
+ }
78
+
79
+ function params(bounds) {
80
+ let match = bounds.sequence;
81
+ if (match === "SharedAcrossChains") {
82
+ return [Frontier.min(bounds.byChain).toString()];
83
+ } else {
84
+ return Frontier.unnestParams(bounds.byChain);
85
+ }
86
+ }
87
+
88
+ export {
89
+ fromEntities,
90
+ position,
91
+ forScope,
92
+ findForScope,
93
+ cursor,
94
+ next,
95
+ relation,
96
+ sql,
97
+ params,
98
+ }
99
+ /* Frontier Not a pure module */
@@ -105,12 +105,12 @@ let makePruneStaleEntityHistoryQuery = (
105
105
  ~entityIndex,
106
106
  ~pgSchema,
107
107
  ~chainIdColumn,
108
- ~safeCheckpoints: CheckpointBounds.t,
108
+ ~safeCheckpoints: CheckpointSequence.checkpointBoundsByChain,
109
109
  ) => {
110
110
  let historyTableRef = `"${pgSchema}"."${historyTableName(~entityName, ~entityIndex)}"`
111
111
  let keyColumns = makeKeyColumns(~chainIdColumn)
112
112
  let anchorKeys = keyColumns->Array.map(column => `t.${column}`)->Array.joinUnsafe(", ")
113
- let bounds = safeCheckpoints->CheckpointBounds.sql(~chainIdColumn, ~tableRef="t")
113
+ let bounds = safeCheckpoints->CheckpointSequence.sql(~chainIdColumn, ~tableRef="t")
114
114
 
115
115
  // Whether a key still has a row above the safe checkpoint is an aggregate
116
116
  // over the same groups as the anchor, so it's computed in the one pass
@@ -151,7 +151,7 @@ let pruneStaleEntityHistory = (
151
151
  ~chainIdColumn,
152
152
  ~safeCheckpoints,
153
153
  ),
154
- safeCheckpoints->CheckpointBounds.params,
154
+ safeCheckpoints->CheckpointSequence.params,
155
155
  )
156
156
 
157
157
  // If an entity doesn't have a history before the update
@@ -224,11 +224,12 @@ let rollback = (
224
224
  ~floors: RollbackFloors.t,
225
225
  ) => {
226
226
  let historyTableRef = `"${pgSchema}"."${historyTableName(~entityName, ~entityIndex)}"`
227
- let bounds = floors.floors->CheckpointBounds.sql(~chainIdColumn, ~tableRef=historyTableRef)
227
+ let bounds =
228
+ floors.checkpointBounds->CheckpointSequence.sql(~chainIdColumn, ~tableRef=historyTableRef)
228
229
  sql
229
230
  ->Postgres.preparedUnsafe(
230
231
  `DELETE FROM ${historyTableRef}${bounds.using} WHERE "${checkpointIdFieldName}" > ${bounds.checkpointId}${bounds.usingMatch};`,
231
- floors.floors->CheckpointBounds.params,
232
+ floors.checkpointBounds->CheckpointSequence.params,
232
233
  )
233
234
  ->Utils.Promise.ignoreValue
234
235
  }
@@ -3,9 +3,9 @@
3
3
  import * as Table from "./Table.res.mjs";
4
4
  import * as ChainId from "../ChainId.res.mjs";
5
5
  import * as Stdlib_BigInt from "@rescript/runtime/lib/es6/Stdlib_BigInt.js";
6
- import * as CheckpointBounds from "./CheckpointBounds.res.mjs";
7
6
  import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
8
7
  import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
8
+ import * as CheckpointSequence from "./CheckpointSequence.res.mjs";
9
9
 
10
10
  let variants = [
11
11
  "SET",
@@ -90,7 +90,7 @@ function makePruneStaleEntityHistoryQuery(entityName, entityIndex, pgSchema, cha
90
90
  let historyTableRef = `"` + pgSchema + `"."` + historyTableName(entityName, entityIndex) + `"`;
91
91
  let keyColumns = makeKeyColumns(chainIdColumn);
92
92
  let anchorKeys = keyColumns.map(column => `t.` + column).join(", ");
93
- let bounds = CheckpointBounds.sql(safeCheckpoints, chainIdColumn, "t");
93
+ let bounds = CheckpointSequence.sql(safeCheckpoints, chainIdColumn, "t");
94
94
  return `WITH anchors AS (
95
95
  SELECT ` + anchorKeys + `,
96
96
  MAX(t.` + checkpointIdFieldName + `) FILTER (WHERE t.` + checkpointIdFieldName + ` <= ` + bounds.checkpointId + `) AS keep_checkpoint_id,
@@ -107,7 +107,7 @@ WHERE ` + makeKeyMatch(chainIdColumn, "d", "a") + `
107
107
  }
108
108
 
109
109
  function pruneStaleEntityHistory(sql, entityName, entityIndex, pgSchema, chainIdColumn, safeCheckpoints) {
110
- return sql.unsafe(makePruneStaleEntityHistoryQuery(entityName, entityIndex, pgSchema, chainIdColumn, safeCheckpoints), CheckpointBounds.params(safeCheckpoints), {prepare: true});
110
+ return sql.unsafe(makePruneStaleEntityHistoryQuery(entityName, entityIndex, pgSchema, chainIdColumn, safeCheckpoints), CheckpointSequence.params(safeCheckpoints), {prepare: true});
111
111
  }
112
112
 
113
113
  function makeBackfillHistoryQuery(pgSchema, entityName, entityIndex, idPgType, chainIdColumn, chainId) {
@@ -137,8 +137,8 @@ function backfillHistory(sql, pgSchema, table, entityIndex, chainId, ids) {
137
137
 
138
138
  function rollback(sql, pgSchema, entityName, entityIndex, chainIdColumn, floors) {
139
139
  let historyTableRef = `"` + pgSchema + `"."` + historyTableName(entityName, entityIndex) + `"`;
140
- let bounds = CheckpointBounds.sql(floors.floors, chainIdColumn, historyTableRef);
141
- return sql.unsafe(`DELETE FROM ` + historyTableRef + bounds.using + ` WHERE "` + checkpointIdFieldName + `" > ` + bounds.checkpointId + bounds.usingMatch + `;`, CheckpointBounds.params(floors.floors), {prepare: true});
140
+ let bounds = CheckpointSequence.sql(floors.checkpointBounds, chainIdColumn, historyTableRef);
141
+ return sql.unsafe(`DELETE FROM ` + historyTableRef + bounds.using + ` WHERE "` + checkpointIdFieldName + `" > ` + bounds.checkpointId + bounds.usingMatch + `;`, CheckpointSequence.params(floors.checkpointBounds), {prepare: true});
142
142
  }
143
143
 
144
144
  let checkpointIdFieldType = "UInt64";
@@ -0,0 +1,86 @@
1
+ // Where each chain stands in its checkpoint sequence.
2
+ type t = dict<Internal.checkpointId>
3
+
4
+ let empty = (): t => Dict.make()
5
+
6
+ let fromEntries = (entries: array<(ChainId.t, Internal.checkpointId)>): t => {
7
+ let frontier = Dict.make()
8
+ entries->Array.forEach(((chainId, checkpointId)) =>
9
+ frontier->ChainId.Dict.set(chainId, checkpointId)
10
+ )
11
+ frontier
12
+ }
13
+
14
+ let copy = (frontier: t): t => frontier->Dict.copy
15
+
16
+ // A chain the frontier doesn't name has committed nothing yet, which is what
17
+ // the initial checkpoint id means.
18
+ let get = (frontier: t, chainId): Internal.checkpointId =>
19
+ switch frontier->ChainId.Dict.dangerouslyGetNonOption(chainId) {
20
+ | Some(checkpointId) => checkpointId
21
+ | None => Internal.initialCheckpointId
22
+ }
23
+
24
+ // Whether the frontier names the chain at all, as opposed to `get`'s reading of
25
+ // an absent chain as the initial id. A rollback frontier names only the chains
26
+ // it moved, and "no id" is not the same answer as "id zero" there.
27
+ let find = (frontier: t, chainId): option<Internal.checkpointId> =>
28
+ frontier->ChainId.Dict.dangerouslyGetNonOption(chainId)
29
+
30
+ let set = (frontier: t, chainId, checkpointId) => frontier->ChainId.Dict.set(chainId, checkpointId)
31
+
32
+ let entries = (frontier: t): array<(ChainId.t, Internal.checkpointId)> =>
33
+ frontier
34
+ ->Dict.toArray
35
+ ->Array.map(((key, checkpointId)) => (key->ChainId.normalizeOrThrow, checkpointId))
36
+
37
+ let chainIds = (frontier: t): array<ChainId.t> =>
38
+ frontier->Dict.keysToArray->Array.map(ChainId.normalizeOrThrow)
39
+
40
+ // The two parallel arrays an `unnest($1, $2) AS ...(chain_id, checkpoint_id)`
41
+ // relation reads positionally.
42
+ type unnestParams = (array<ChainId.t>, array<string>)
43
+
44
+ let unnestParams = (frontier: t): unnestParams => {
45
+ let chainIds = []
46
+ let checkpointIds = []
47
+ frontier->Utils.Dict.forEachWithKey((checkpointId, key) => {
48
+ chainIds->Array.push(key->ChainId.normalizeOrThrow)
49
+ checkpointIds->Array.push(checkpointId->BigInt.toString)
50
+ })
51
+ (chainIds, checkpointIds)
52
+ }
53
+
54
+ %%private(
55
+ let fold = (frontier: t, pick) =>
56
+ frontier
57
+ ->Dict.valuesToArray
58
+ ->Array.reduce(None, (acc, checkpointId) =>
59
+ switch acc {
60
+ | None => Some(checkpointId)
61
+ | Some(picked) => Some(pick(picked, checkpointId))
62
+ }
63
+ )
64
+ )
65
+
66
+ // A frontier naming no chain has committed nothing anywhere.
67
+ let max = (frontier: t) =>
68
+ frontier->fold(Pervasives.max)->Option.getOr(Internal.initialCheckpointId)
69
+ let min = (frontier: t) =>
70
+ frontier->fold(Pervasives.min)->Option.getOr(Internal.initialCheckpointId)
71
+
72
+ let mergeMin = (a: t, b: t): t => Utils.Dict.mergeWith(a, b, Pervasives.min)
73
+ let mergeMax = (a: t, b: t): t => Utils.Dict.mergeWith(a, b, Pervasives.max)
74
+
75
+ let equals = (a: t, b: t) => {
76
+ let same = (a: t, b: t) =>
77
+ a
78
+ ->Dict.toArray
79
+ ->Array.every(((key, checkpointId)) =>
80
+ switch b->Utils.Dict.dangerouslyGetNonOption(key) {
81
+ | Some(other) => other == checkpointId
82
+ | None => checkpointId == Internal.initialCheckpointId
83
+ }
84
+ )
85
+ same(a, b) && same(b, a)
86
+ }
@@ -0,0 +1,126 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Utils from "../Utils.res.mjs";
4
+ import * as ChainId from "../ChainId.res.mjs";
5
+ import * as Internal from "../Internal.res.mjs";
6
+ import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
7
+ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
8
+ import * as Primitive_bigint from "@rescript/runtime/lib/es6/Primitive_bigint.js";
9
+
10
+ function empty() {
11
+ return {};
12
+ }
13
+
14
+ function fromEntries(entries) {
15
+ let frontier = {};
16
+ entries.forEach(param => {
17
+ frontier[param[0]] = param[1];
18
+ });
19
+ return frontier;
20
+ }
21
+
22
+ function copy(frontier) {
23
+ return Object.assign({}, frontier);
24
+ }
25
+
26
+ function get(frontier, chainId) {
27
+ let checkpointId = frontier[chainId];
28
+ if (checkpointId !== undefined) {
29
+ return checkpointId;
30
+ } else {
31
+ return Internal.initialCheckpointId;
32
+ }
33
+ }
34
+
35
+ function find(frontier, chainId) {
36
+ return frontier[chainId];
37
+ }
38
+
39
+ function set(frontier, chainId, checkpointId) {
40
+ frontier[chainId] = checkpointId;
41
+ }
42
+
43
+ function entries(frontier) {
44
+ return Object.entries(frontier).map(param => [
45
+ ChainId.normalizeOrThrow(param[0]),
46
+ param[1]
47
+ ]);
48
+ }
49
+
50
+ function chainIds(frontier) {
51
+ return Object.keys(frontier).map(ChainId.normalizeOrThrow);
52
+ }
53
+
54
+ function unnestParams(frontier) {
55
+ let chainIds = [];
56
+ let checkpointIds = [];
57
+ Utils.Dict.forEachWithKey(frontier, (checkpointId, key) => {
58
+ chainIds.push(ChainId.normalizeOrThrow(key));
59
+ checkpointIds.push(checkpointId.toString());
60
+ });
61
+ return [
62
+ chainIds,
63
+ checkpointIds
64
+ ];
65
+ }
66
+
67
+ function fold(frontier, pick) {
68
+ return Stdlib_Array.reduce(Object.values(frontier), undefined, (acc, checkpointId) => {
69
+ if (acc !== undefined) {
70
+ return pick(acc, checkpointId);
71
+ } else {
72
+ return checkpointId;
73
+ }
74
+ });
75
+ }
76
+
77
+ function max(frontier) {
78
+ return Stdlib_Option.getOr(fold(frontier, Primitive_bigint.max), Internal.initialCheckpointId);
79
+ }
80
+
81
+ function min(frontier) {
82
+ return Stdlib_Option.getOr(fold(frontier, Primitive_bigint.min), Internal.initialCheckpointId);
83
+ }
84
+
85
+ function mergeMin(a, b) {
86
+ return Utils.Dict.mergeWith(a, b, Primitive_bigint.min);
87
+ }
88
+
89
+ function mergeMax(a, b) {
90
+ return Utils.Dict.mergeWith(a, b, Primitive_bigint.max);
91
+ }
92
+
93
+ function equals(a, b) {
94
+ let same = (a, b) => Object.entries(a).every(param => {
95
+ let checkpointId = param[1];
96
+ let other = b[param[0]];
97
+ if (other !== undefined) {
98
+ return other === checkpointId;
99
+ } else {
100
+ return checkpointId === Internal.initialCheckpointId;
101
+ }
102
+ });
103
+ if (same(a, b)) {
104
+ return same(b, a);
105
+ } else {
106
+ return false;
107
+ }
108
+ }
109
+
110
+ export {
111
+ empty,
112
+ fromEntries,
113
+ copy,
114
+ get,
115
+ find,
116
+ set,
117
+ entries,
118
+ chainIds,
119
+ unnestParams,
120
+ max,
121
+ min,
122
+ mergeMin,
123
+ mergeMax,
124
+ equals,
125
+ }
126
+ /* Utils Not a pure module */