envio 3.0.2-svm-alpha.1 → 3.0.2-svm-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.
- package/README.md +0 -1
- package/evm.schema.json +7 -0
- package/fuel.schema.json +7 -0
- package/index.d.ts +0 -2
- package/package.json +6 -6
- package/src/Batch.res +4 -214
- package/src/Batch.res.mjs +6 -165
- package/src/ChainFetcher.res +4 -5
- package/src/ChainFetcher.res.mjs +6 -7
- package/src/ChainManager.res +3 -5
- package/src/ChainManager.res.mjs +4 -6
- package/src/Config.res +100 -32
- package/src/Config.res.mjs +102 -31
- package/src/Core.res +4 -8
- package/src/Env.res +0 -1
- package/src/Env.res.mjs +0 -2
- package/src/EventConfigBuilder.res +38 -136
- package/src/EventConfigBuilder.res.mjs +14 -79
- package/src/EventUtils.res +0 -18
- package/src/EventUtils.res.mjs +0 -18
- package/src/FetchState.res +1 -11
- package/src/FetchState.res.mjs +2 -16
- package/src/GlobalState.res +3 -8
- package/src/GlobalState.res.mjs +1 -13
- package/src/HandlerLoader.res +6 -5
- package/src/HandlerLoader.res.mjs +27 -9
- package/src/HandlerRegister.res +1 -12
- package/src/HandlerRegister.res.mjs +1 -6
- package/src/HandlerRegister.resi +1 -1
- package/src/Hasura.res +96 -32
- package/src/Hasura.res.mjs +93 -38
- package/src/Internal.res +10 -17
- package/src/Internal.res.mjs +3 -3
- package/src/Main.res +2 -6
- package/src/Main.res.mjs +24 -16
- package/src/Persistence.res +17 -2
- package/src/Persistence.res.mjs +14 -2
- package/src/PgStorage.res +5 -1
- package/src/PgStorage.res.mjs +12 -6
- package/src/SimulateItems.res.mjs +21 -3
- package/src/TestIndexer.res.mjs +23 -4
- package/src/bindings/ClickHouse.res +6 -2
- package/src/bindings/ClickHouse.res.mjs +3 -2
- package/src/bindings/Vitest.res +3 -0
- package/src/db/InternalTable.res.mjs +35 -35
- package/src/db/Table.res +9 -2
- package/src/db/Table.res.mjs +10 -7
- package/src/sources/EvmChain.res +32 -9
- package/src/sources/EvmChain.res.mjs +31 -4
- package/src/sources/HyperSyncClient.res +35 -79
- package/src/sources/HyperSyncClient.res.mjs +35 -46
- package/src/sources/HyperSyncSolanaClient.res +2 -0
- package/src/sources/HyperSyncSolanaSource.res +72 -50
- package/src/sources/HyperSyncSolanaSource.res.mjs +71 -57
- package/src/sources/HyperSyncSource.res +13 -14
- package/src/sources/HyperSyncSource.res.mjs +8 -5
- package/src/sources/RpcSource.res +11 -7
- package/src/sources/RpcSource.res.mjs +6 -5
- package/svm.schema.json +112 -29
package/src/ChainManager.res
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
type t = {
|
|
2
2
|
committedCheckpointId: bigint,
|
|
3
3
|
chainFetchers: ChainMap.t<ChainFetcher.t>,
|
|
4
|
-
multichain: Config.multichain,
|
|
5
4
|
isInReorgThreshold: bool,
|
|
6
5
|
// True once every chain has caught up to head/endBlock. Monotonic during a run.
|
|
7
6
|
isRealtime: bool,
|
|
@@ -35,6 +34,7 @@ let makeFromDbState = (
|
|
|
35
34
|
~initialState: Persistence.initialState,
|
|
36
35
|
~config: Config.t,
|
|
37
36
|
~registrations,
|
|
37
|
+
~reducedPollingInterval=?,
|
|
38
38
|
): t => {
|
|
39
39
|
let isInReorgThreshold = if initialState.cleanRun {
|
|
40
40
|
false
|
|
@@ -81,6 +81,7 @@ let makeFromDbState = (
|
|
|
81
81
|
~targetBufferSize,
|
|
82
82
|
~config,
|
|
83
83
|
~registrations,
|
|
84
|
+
~reducedPollingInterval?,
|
|
84
85
|
),
|
|
85
86
|
)
|
|
86
87
|
})
|
|
@@ -106,7 +107,6 @@ let makeFromDbState = (
|
|
|
106
107
|
|
|
107
108
|
{
|
|
108
109
|
committedCheckpointId: initialState.checkpointId,
|
|
109
|
-
multichain: config.multichain,
|
|
110
110
|
chainFetchers,
|
|
111
111
|
isInReorgThreshold,
|
|
112
112
|
isRealtime,
|
|
@@ -128,11 +128,10 @@ let setChainFetcher = (chainManager: t, chainFetcher: ChainFetcher.t) => {
|
|
|
128
128
|
}
|
|
129
129
|
|
|
130
130
|
let nextItemIsNone = (chainManager: t): bool => {
|
|
131
|
-
!Batch.
|
|
131
|
+
!Batch.hasReadyItem(
|
|
132
132
|
chainManager.chainFetchers->ChainMap.map(cf => {
|
|
133
133
|
cf.fetchState
|
|
134
134
|
}),
|
|
135
|
-
~multichain=chainManager.multichain,
|
|
136
135
|
)
|
|
137
136
|
}
|
|
138
137
|
|
|
@@ -152,7 +151,6 @@ let createBatch = (chainManager: t, ~batchSizeTarget: int, ~isRollback: bool): B
|
|
|
152
151
|
reorgDetection: cf.reorgDetection,
|
|
153
152
|
chainConfig: cf.chainConfig,
|
|
154
153
|
}),
|
|
155
|
-
~multichain=chainManager.multichain,
|
|
156
154
|
~batchSizeTarget,
|
|
157
155
|
)
|
|
158
156
|
}
|
package/src/ChainManager.res.mjs
CHANGED
|
@@ -38,7 +38,7 @@ function calculateTargetBufferSize(activeChainsCount) {
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
function makeFromDbState(initialState, config, registrations) {
|
|
41
|
+
function makeFromDbState(initialState, config, registrations, reducedPollingInterval) {
|
|
42
42
|
let isInReorgThreshold = initialState.cleanRun ? false : initialState.chains.some(chain => isProgressInReorgThreshold(chain.progressBlockNumber, chain.sourceBlockNumber, chain.maxReorgDepth));
|
|
43
43
|
let targetBufferSize = calculateTargetBufferSize(initialState.chains.length);
|
|
44
44
|
Prometheus.ProcessingMaxBatchSize.set(config.batchSize);
|
|
@@ -54,7 +54,7 @@ function makeFromDbState(initialState, config, registrations) {
|
|
|
54
54
|
let chainConfig = ChainMap.get(config.chainMap, chain);
|
|
55
55
|
return [
|
|
56
56
|
chain,
|
|
57
|
-
ChainFetcher.makeFromDbState(chainConfig, resumedChainState, initialState.reorgCheckpoints, isInReorgThreshold, isRealtime, config, registrations, targetBufferSize)
|
|
57
|
+
ChainFetcher.makeFromDbState(chainConfig, resumedChainState, initialState.reorgCheckpoints, isInReorgThreshold, isRealtime, config, registrations, targetBufferSize, reducedPollingInterval)
|
|
58
58
|
];
|
|
59
59
|
});
|
|
60
60
|
let chainFetchers = ChainMap.fromArrayUnsafe(chainFetchersArr);
|
|
@@ -79,7 +79,6 @@ function makeFromDbState(initialState, config, registrations) {
|
|
|
79
79
|
return {
|
|
80
80
|
committedCheckpointId: initialState.checkpointId,
|
|
81
81
|
chainFetchers: chainFetchers,
|
|
82
|
-
multichain: config.multichain,
|
|
83
82
|
isInReorgThreshold: isInReorgThreshold,
|
|
84
83
|
isRealtime: isRealtime
|
|
85
84
|
};
|
|
@@ -93,14 +92,13 @@ function setChainFetcher(chainManager, chainFetcher) {
|
|
|
93
92
|
return {
|
|
94
93
|
committedCheckpointId: chainManager.committedCheckpointId,
|
|
95
94
|
chainFetchers: ChainMap.set(chainManager.chainFetchers, ChainMap.Chain.makeUnsafe(chainFetcher.chainConfig.id), chainFetcher),
|
|
96
|
-
multichain: chainManager.multichain,
|
|
97
95
|
isInReorgThreshold: chainManager.isInReorgThreshold,
|
|
98
96
|
isRealtime: chainManager.isRealtime
|
|
99
97
|
};
|
|
100
98
|
}
|
|
101
99
|
|
|
102
100
|
function nextItemIsNone(chainManager) {
|
|
103
|
-
return !Batch.
|
|
101
|
+
return !Batch.hasReadyItem(ChainMap.map(chainManager.chainFetchers, cf => cf.fetchState));
|
|
104
102
|
}
|
|
105
103
|
|
|
106
104
|
function createBatch(chainManager, batchSizeTarget, isRollback) {
|
|
@@ -113,7 +111,7 @@ function createBatch(chainManager, batchSizeTarget, isRollback) {
|
|
|
113
111
|
sourceBlockNumber: cf.fetchState.knownHeight,
|
|
114
112
|
totalEventsProcessed: cf.numEventsProcessed,
|
|
115
113
|
chainConfig: cf.chainConfig
|
|
116
|
-
})),
|
|
114
|
+
})), batchSizeTarget);
|
|
117
115
|
}
|
|
118
116
|
|
|
119
117
|
function isProgressAtHead(chainManager) {
|
package/src/Config.res
CHANGED
|
@@ -15,8 +15,6 @@ type contract = {
|
|
|
15
15
|
addresses: array<Address.t>,
|
|
16
16
|
events: array<Internal.eventConfig>,
|
|
17
17
|
startBlock: option<int>,
|
|
18
|
-
// EVM-specific: event sighashes for HyperSync queries
|
|
19
|
-
eventSignatures: array<string>,
|
|
20
18
|
}
|
|
21
19
|
|
|
22
20
|
// Sources are instantiated lazily in ChainFetcher from this config.
|
|
@@ -56,10 +54,6 @@ type sourceSync = {
|
|
|
56
54
|
pollingInterval: int,
|
|
57
55
|
}
|
|
58
56
|
|
|
59
|
-
type multichain = Internal.multichain =
|
|
60
|
-
| @as("ordered") Ordered
|
|
61
|
-
| @as("unordered") Unordered
|
|
62
|
-
|
|
63
57
|
type storage = {
|
|
64
58
|
postgres: bool,
|
|
65
59
|
clickhouse: bool,
|
|
@@ -78,7 +72,6 @@ type t = {
|
|
|
78
72
|
shouldRollbackOnReorg: bool,
|
|
79
73
|
shouldSaveFullHistory: bool,
|
|
80
74
|
storage: storage,
|
|
81
|
-
multichain: multichain,
|
|
82
75
|
chainMap: ChainMap.t<chain>,
|
|
83
76
|
defaultChain: option<chain>,
|
|
84
77
|
ecosystem: Ecosystem.t,
|
|
@@ -207,6 +200,7 @@ let svmEventDescriptorSchema = S.schema(s =>
|
|
|
207
200
|
"discriminatorByteLen": s.matches(S.int),
|
|
208
201
|
"includeTransaction": s.matches(S.bool),
|
|
209
202
|
"includeLogs": s.matches(S.bool),
|
|
203
|
+
"includeTokenBalances": s.matches(S.bool),
|
|
210
204
|
"accountFilters": s.matches(
|
|
211
205
|
S.option(
|
|
212
206
|
S.array(
|
|
@@ -235,10 +229,9 @@ let svmAbiSchema = S.schema(s =>
|
|
|
235
229
|
|
|
236
230
|
let contractEventItemSchema = S.schema(s =>
|
|
237
231
|
{
|
|
238
|
-
"event": s.matches(S.string),
|
|
239
232
|
"name": s.matches(S.string),
|
|
240
233
|
"sighash": s.matches(S.string),
|
|
241
|
-
"params": s.matches(S.option(S.array(EventConfigBuilder.
|
|
234
|
+
"params": s.matches(S.option(S.array(EventConfigBuilder.paramMetaSchema))),
|
|
242
235
|
"kind": s.matches(S.option(S.string)),
|
|
243
236
|
"blockFields": s.matches(S.option(S.array(Internal.evmBlockFieldSchema))),
|
|
244
237
|
"transactionFields": s.matches(S.option(S.array(Internal.evmTransactionFieldSchema))),
|
|
@@ -280,8 +273,6 @@ let publicConfigEvmSchema = S.schema(s =>
|
|
|
280
273
|
}
|
|
281
274
|
)
|
|
282
275
|
|
|
283
|
-
let multichainSchema = S.enum([Ordered, Unordered])
|
|
284
|
-
|
|
285
276
|
let compositeIndexFieldSchema = S.schema(s =>
|
|
286
277
|
{
|
|
287
278
|
"fieldName": s.matches(S.string),
|
|
@@ -294,6 +285,7 @@ let derivedFieldSchema = S.schema(s =>
|
|
|
294
285
|
"fieldName": s.matches(S.string),
|
|
295
286
|
"derivedFromEntity": s.matches(S.string),
|
|
296
287
|
"derivedFromField": s.matches(S.string),
|
|
288
|
+
"description": s.matches(S.option(S.string)),
|
|
297
289
|
}
|
|
298
290
|
)
|
|
299
291
|
|
|
@@ -309,6 +301,7 @@ let propertySchema = S.schema(s =>
|
|
|
309
301
|
"entity": s.matches(S.option(S.string)),
|
|
310
302
|
"precision": s.matches(S.option(S.int)),
|
|
311
303
|
"scale": s.matches(S.option(S.int)),
|
|
304
|
+
"description": s.matches(S.option(S.string)),
|
|
312
305
|
}
|
|
313
306
|
)
|
|
314
307
|
|
|
@@ -326,6 +319,7 @@ let entityJsonSchema = S.schema(s =>
|
|
|
326
319
|
"properties": s.matches(S.array(propertySchema)),
|
|
327
320
|
"derivedFields": s.matches(S.option(S.array(derivedFieldSchema))),
|
|
328
321
|
"compositeIndices": s.matches(S.option(S.array(S.array(compositeIndexFieldSchema)))),
|
|
322
|
+
"description": s.matches(S.option(S.string)),
|
|
329
323
|
}
|
|
330
324
|
)
|
|
331
325
|
|
|
@@ -418,6 +412,7 @@ let parseEntitiesFromJson = (
|
|
|
418
412
|
~isArray,
|
|
419
413
|
~isIndex,
|
|
420
414
|
~linkedEntity=?prop["linkedEntity"],
|
|
415
|
+
~description=?prop["description"],
|
|
421
416
|
)
|
|
422
417
|
})
|
|
423
418
|
|
|
@@ -429,6 +424,7 @@ let parseEntitiesFromJson = (
|
|
|
429
424
|
df["fieldName"],
|
|
430
425
|
~derivedFromEntity=df["derivedFromEntity"],
|
|
431
426
|
~derivedFromField=df["derivedFromField"],
|
|
427
|
+
~description=?df["description"],
|
|
432
428
|
)
|
|
433
429
|
)
|
|
434
430
|
|
|
@@ -448,6 +444,7 @@ let parseEntitiesFromJson = (
|
|
|
448
444
|
entityName,
|
|
449
445
|
~fields=Array.concat(fields, derivedFields),
|
|
450
446
|
~compositeIndices,
|
|
447
|
+
~description=?entityJson["description"],
|
|
451
448
|
)
|
|
452
449
|
|
|
453
450
|
// Build schema dynamically from properties
|
|
@@ -509,7 +506,6 @@ let publicConfigSchema = S.schema(s =>
|
|
|
509
506
|
"description": s.matches(S.option(S.string)),
|
|
510
507
|
"handlers": s.matches(S.option(S.string)),
|
|
511
508
|
"isDev": s.matches(S.option(S.bool)),
|
|
512
|
-
"multichain": s.matches(S.option(multichainSchema)),
|
|
513
509
|
"fullBatchSize": s.matches(S.option(S.int)),
|
|
514
510
|
"rollbackOnReorg": s.matches(S.option(S.bool)),
|
|
515
511
|
"saveFullHistory": s.matches(S.option(S.bool)),
|
|
@@ -592,7 +588,6 @@ let fromPublic = (publicConfigJson: JSON.t) => {
|
|
|
592
588
|
| None => (Utils.Set.fromArray(EventConfigBuilder.alwaysIncludedBlockFields), Utils.Set.make())
|
|
593
589
|
}
|
|
594
590
|
|
|
595
|
-
// Build contract data lookup: ABI, event signatures, event configs (keyed by capitalized name)
|
|
596
591
|
let contractDataByName: dict<{
|
|
597
592
|
"abi": EvmTypes.Abi.t,
|
|
598
593
|
"eventSignatures": array<string>,
|
|
@@ -607,7 +602,7 @@ let fromPublic = (publicConfigJson: JSON.t) => {
|
|
|
607
602
|
let capitalizedName = contractName->Utils.String.capitalize
|
|
608
603
|
let abi = contractConfig["abi"]->(Utils.magic: JSON.t => EvmTypes.Abi.t)
|
|
609
604
|
let eventSignatures = switch contractConfig["events"] {
|
|
610
|
-
| Some(events) => events->Array.map(eventItem => eventItem["
|
|
605
|
+
| Some(events) => events->Array.map(eventItem => eventItem["sighash"])
|
|
611
606
|
| None => []
|
|
612
607
|
}
|
|
613
608
|
let widened =
|
|
@@ -696,7 +691,7 @@ let fromPublic = (publicConfigJson: JSON.t) => {
|
|
|
696
691
|
"includeLogs": bool,
|
|
697
692
|
"includeTokenBalances": bool,
|
|
698
693
|
"accountFilters": option<
|
|
699
|
-
array<{"position": int, "values": array<string>}
|
|
694
|
+
array<array<{"position": int, "values": array<string>}>>,
|
|
700
695
|
>,
|
|
701
696
|
"isInner": option<bool>,
|
|
702
697
|
"accounts": option<array<string>>,
|
|
@@ -712,10 +707,12 @@ let fromPublic = (publicConfigJson: JSON.t) => {
|
|
|
712
707
|
)
|
|
713
708
|
}
|
|
714
709
|
let accountFilters =
|
|
715
|
-
(svm["accountFilters"]->Option.getOr([]))->Array.map(
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
710
|
+
(svm["accountFilters"]->Option.getOr([]))->Array.map(group =>
|
|
711
|
+
group->Array.map(af => {
|
|
712
|
+
Internal.position: af["position"],
|
|
713
|
+
values: af["values"]->SvmTypes.Pubkey.fromStringsUnsafe,
|
|
714
|
+
})
|
|
715
|
+
)
|
|
719
716
|
(EventConfigBuilder.buildSvmInstructionEventConfig(
|
|
720
717
|
~contractName,
|
|
721
718
|
~instructionName=eventName,
|
|
@@ -824,7 +821,6 @@ let fromPublic = (publicConfigJson: JSON.t) => {
|
|
|
824
821
|
addresses,
|
|
825
822
|
events,
|
|
826
823
|
startBlock,
|
|
827
|
-
eventSignatures: contractData["eventSignatures"],
|
|
828
824
|
}
|
|
829
825
|
})
|
|
830
826
|
|
|
@@ -963,7 +959,6 @@ let fromPublic = (publicConfigJson: JSON.t) => {
|
|
|
963
959
|
shouldRollbackOnReorg: publicConfig["rollbackOnReorg"]->Option.getOr(true),
|
|
964
960
|
shouldSaveFullHistory: publicConfig["saveFullHistory"]->Option.getOr(false),
|
|
965
961
|
storage: globalStorage,
|
|
966
|
-
multichain: publicConfig["multichain"]->Option.getOr(Unordered),
|
|
967
962
|
chainMap,
|
|
968
963
|
defaultChain: chains->Array.get(0),
|
|
969
964
|
enableRawEvents: publicConfig["rawEvents"]->Option.getOr(false),
|
|
@@ -1094,11 +1089,18 @@ let rec canonicalJson = (json: JSON.t): JSON.t =>
|
|
|
1094
1089
|
}
|
|
1095
1090
|
|
|
1096
1091
|
// Returns dotted leaf paths (`a.b[i].c`) where `stored` differs from
|
|
1097
|
-
// `current
|
|
1092
|
+
// `current`, restricted to the highest-priority top-level tier with any
|
|
1093
|
+
// diff. Tiers in order: version → name → storage → ecosystem
|
|
1094
|
+
// (evm/fuel/svm) → entities → other top-level keys. The first tier
|
|
1095
|
+
// containing a diff is the only one rendered; lower tiers are silenced
|
|
1096
|
+
// so a single noisy section doesn't bury the actionable change.
|
|
1098
1097
|
let diffPaths = (~stored: JSON.t, ~current: JSON.t): array<string> => {
|
|
1098
|
+
let canonEq = (a: JSON.t, b: JSON.t) =>
|
|
1099
|
+
JSON.stringify(canonicalJson(a)) === JSON.stringify(canonicalJson(b))
|
|
1100
|
+
|
|
1099
1101
|
let acc = []
|
|
1100
1102
|
let rec go = (s: JSON.t, c: JSON.t, prefix: string) => {
|
|
1101
|
-
if
|
|
1103
|
+
if canonEq(s, c) {
|
|
1102
1104
|
()
|
|
1103
1105
|
} else {
|
|
1104
1106
|
switch (s, c) {
|
|
@@ -1124,25 +1126,91 @@ let diffPaths = (~stored: JSON.t, ~current: JSON.t): array<string> => {
|
|
|
1124
1126
|
| (Some(sv), Some(cv)) => go(sv, cv, p)
|
|
1125
1127
|
}
|
|
1126
1128
|
}
|
|
1127
|
-
| _ =>
|
|
1128
|
-
// Type mismatch or scalar diff
|
|
1129
|
-
acc->Array.push(prefix === "" ? "<root>" : prefix)->ignore
|
|
1129
|
+
| _ => acc->Array.push(prefix === "" ? "<root>" : prefix)->ignore
|
|
1130
1130
|
}
|
|
1131
1131
|
}
|
|
1132
1132
|
}
|
|
1133
|
-
|
|
1133
|
+
|
|
1134
|
+
let getTopKey = (j: JSON.t, k: string) =>
|
|
1135
|
+
switch j {
|
|
1136
|
+
| Object(d) => d->Dict.get(k)
|
|
1137
|
+
| _ => None
|
|
1138
|
+
}
|
|
1139
|
+
let topKeyDiffers = (k: string) =>
|
|
1140
|
+
switch (getTopKey(stored, k), getTopKey(current, k)) {
|
|
1141
|
+
| (None, None) => false
|
|
1142
|
+
| (None, _) | (_, None) => true
|
|
1143
|
+
| (Some(s), Some(c)) => !canonEq(s, c)
|
|
1144
|
+
}
|
|
1145
|
+
let runTier = (keys: array<string>) =>
|
|
1146
|
+
keys->Array.forEach(k =>
|
|
1147
|
+
switch (getTopKey(stored, k), getTopKey(current, k)) {
|
|
1148
|
+
| (None, None) => ()
|
|
1149
|
+
| (None, _) | (_, None) => acc->Array.push(k)->ignore
|
|
1150
|
+
| (Some(s), Some(c)) => go(s, c, k)
|
|
1151
|
+
}
|
|
1152
|
+
)
|
|
1153
|
+
|
|
1154
|
+
switch (stored, current) {
|
|
1155
|
+
| (Object(sObj), Object(cObj)) =>
|
|
1156
|
+
let tiers = [["version"], ["name"], ["storage"], ["evm", "fuel", "svm"], ["entities"]]
|
|
1157
|
+
let firstHit = tiers->Array.reduce(None, (acc, tier) =>
|
|
1158
|
+
switch acc {
|
|
1159
|
+
| Some(_) => acc
|
|
1160
|
+
| None =>
|
|
1161
|
+
switch tier->Array.filter(topKeyDiffers) {
|
|
1162
|
+
| [] => None
|
|
1163
|
+
| hits => Some(hits)
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
)
|
|
1167
|
+
switch firstHit {
|
|
1168
|
+
| Some(hits) => runTier(hits)
|
|
1169
|
+
| None =>
|
|
1170
|
+
let knownSet = Utils.Set.fromArray(tiers->Belt.Array.concatMany)
|
|
1171
|
+
let extras =
|
|
1172
|
+
Utils.Set.fromArray(Array.concat(sObj->Dict.keysToArray, cObj->Dict.keysToArray))
|
|
1173
|
+
->Utils.Set.toArray
|
|
1174
|
+
->Array.filter(k => !(knownSet->Utils.Set.has(k)))
|
|
1175
|
+
->Array.toSorted(String.compare)
|
|
1176
|
+
->Array.filter(topKeyDiffers)
|
|
1177
|
+
runTier(extras)
|
|
1178
|
+
}
|
|
1179
|
+
| _ => go(stored, current, "")
|
|
1180
|
+
}
|
|
1134
1181
|
acc
|
|
1135
1182
|
}
|
|
1136
1183
|
|
|
1137
1184
|
// Throws an `incompatible config` error listing each path in `changedPaths`,
|
|
1138
|
-
// plus the
|
|
1139
|
-
// (
|
|
1140
|
-
//
|
|
1141
|
-
|
|
1185
|
+
// plus the remediation options. `~resetCommand` is rendered as-is for
|
|
1186
|
+
// option 2 (the wipe-and-redo). `~runCommand` controls option 3 (parallel
|
|
1187
|
+
// indexer recipe): when `None`, option 3 is omitted — the migrate flow
|
|
1188
|
+
// uses this because running a second indexer doesn't apply.
|
|
1189
|
+
// `~hasClickhouse` adds the extra env line so users running both
|
|
1190
|
+
// Postgres and Clickhouse get a complete override.
|
|
1191
|
+
let throwIfIncompatible = (
|
|
1192
|
+
changedPaths: array<string>,
|
|
1193
|
+
~resetCommand: string,
|
|
1194
|
+
~runCommand: option<string>,
|
|
1195
|
+
~hasClickhouse: bool,
|
|
1196
|
+
) => {
|
|
1142
1197
|
if changedPaths->Array.length > 0 {
|
|
1143
1198
|
let bullets = changedPaths->Array.map(p => ` - ${p}`)->Array.joinUnsafe("\n")
|
|
1199
|
+
let option1 = "Revert the changes above"
|
|
1200
|
+
let padTo = (s, col) => s ++ " "->String.repeat(Math.Int.max(col - String.length(s), 1))
|
|
1201
|
+
let col = Math.Int.max(String.length(option1), String.length(resetCommand)) + 2
|
|
1202
|
+
let option3 = switch runCommand {
|
|
1203
|
+
| None => ""
|
|
1204
|
+
| Some(cmd) =>
|
|
1205
|
+
let clickhouseLine = hasClickhouse ? " ENVIO_CLICKHOUSE_DATABASE=<new_db> \\\n" : ""
|
|
1206
|
+
`\n 3. Run a second indexer alongside this one — keep both datasets:\n ENVIO_PG_SCHEMA=<new_schema> \\\n${clickhouseLine} ENVIO_INDEXER_PORT=<new_port> \\\n ${cmd}`
|
|
1207
|
+
}
|
|
1144
1208
|
JsError.throwWithMessage(
|
|
1145
|
-
`The following config changes are incompatible with the existing indexer data:\n\n${bullets}\n\nPick one:\n
|
|
1209
|
+
`The following config changes are incompatible with the existing indexer data:\n\n${bullets}\n\nPick one:\n 1. ${option1->padTo(
|
|
1210
|
+
col,
|
|
1211
|
+
)}# resume indexing where it left off\n 2. ${resetCommand->padTo(
|
|
1212
|
+
col,
|
|
1213
|
+
)}# delete all indexed data and start over${option3}`,
|
|
1146
1214
|
)
|
|
1147
1215
|
}
|
|
1148
1216
|
}
|
package/src/Config.res.mjs
CHANGED
|
@@ -44,12 +44,12 @@ let schema = S$RescriptSchema.schema(s => ({
|
|
|
44
44
|
let rowsSchema = S$RescriptSchema.array(schema);
|
|
45
45
|
|
|
46
46
|
let table = Table.mkTable(name, undefined, [
|
|
47
|
-
Table.mkField("id", "String", S$RescriptSchema.string, undefined, undefined, undefined, true, undefined, undefined),
|
|
48
|
-
Table.mkField("chain_id", "Int32", S$RescriptSchema.int, undefined, undefined, undefined, undefined, undefined, undefined),
|
|
49
|
-
Table.mkField("registration_block", "Int32", S$RescriptSchema.int, undefined, undefined, undefined, undefined, undefined, undefined),
|
|
50
|
-
Table.mkField("registration_log_index", "Int32", S$RescriptSchema.int, undefined, undefined, undefined, undefined, undefined, undefined),
|
|
51
|
-
Table.mkField("contract_name", "String", S$RescriptSchema.string, undefined, undefined, undefined, undefined, undefined, undefined)
|
|
52
|
-
]);
|
|
47
|
+
Table.mkField("id", "String", S$RescriptSchema.string, undefined, undefined, undefined, true, undefined, undefined, undefined),
|
|
48
|
+
Table.mkField("chain_id", "Int32", S$RescriptSchema.int, undefined, undefined, undefined, undefined, undefined, undefined, undefined),
|
|
49
|
+
Table.mkField("registration_block", "Int32", S$RescriptSchema.int, undefined, undefined, undefined, undefined, undefined, undefined, undefined),
|
|
50
|
+
Table.mkField("registration_log_index", "Int32", S$RescriptSchema.int, undefined, undefined, undefined, undefined, undefined, undefined, undefined),
|
|
51
|
+
Table.mkField("contract_name", "String", S$RescriptSchema.string, undefined, undefined, undefined, undefined, undefined, undefined, undefined)
|
|
52
|
+
], undefined);
|
|
53
53
|
|
|
54
54
|
let entityConfig_storage = {
|
|
55
55
|
postgres: true,
|
|
@@ -118,6 +118,7 @@ let svmEventDescriptorSchema = S$RescriptSchema.schema(s => ({
|
|
|
118
118
|
discriminatorByteLen: s.m(S$RescriptSchema.int),
|
|
119
119
|
includeTransaction: s.m(S$RescriptSchema.bool),
|
|
120
120
|
includeLogs: s.m(S$RescriptSchema.bool),
|
|
121
|
+
includeTokenBalances: s.m(S$RescriptSchema.bool),
|
|
121
122
|
accountFilters: s.m(S$RescriptSchema.option(S$RescriptSchema.array(S$RescriptSchema.schema(s => ({
|
|
122
123
|
position: s.m(S$RescriptSchema.int),
|
|
123
124
|
values: s.m(S$RescriptSchema.array(S$RescriptSchema.string))
|
|
@@ -134,10 +135,9 @@ let svmAbiSchema = S$RescriptSchema.schema(s => ({
|
|
|
134
135
|
}));
|
|
135
136
|
|
|
136
137
|
let contractEventItemSchema = S$RescriptSchema.schema(s => ({
|
|
137
|
-
event: s.m(S$RescriptSchema.string),
|
|
138
138
|
name: s.m(S$RescriptSchema.string),
|
|
139
139
|
sighash: s.m(S$RescriptSchema.string),
|
|
140
|
-
params: s.m(S$RescriptSchema.option(S$RescriptSchema.array(EventConfigBuilder.
|
|
140
|
+
params: s.m(S$RescriptSchema.option(S$RescriptSchema.array(EventConfigBuilder.paramMetaSchema))),
|
|
141
141
|
kind: s.m(S$RescriptSchema.option(S$RescriptSchema.string)),
|
|
142
142
|
blockFields: s.m(S$RescriptSchema.option(S$RescriptSchema.array(Internal.evmBlockFieldSchema))),
|
|
143
143
|
transactionFields: s.m(S$RescriptSchema.option(S$RescriptSchema.array(Internal.evmTransactionFieldSchema))),
|
|
@@ -168,11 +168,6 @@ let publicConfigEvmSchema = S$RescriptSchema.schema(s => ({
|
|
|
168
168
|
globalTransactionFields: s.m(S$RescriptSchema.option(S$RescriptSchema.array(Internal.evmTransactionFieldSchema)))
|
|
169
169
|
}));
|
|
170
170
|
|
|
171
|
-
let multichainSchema = S$RescriptSchema.$$enum([
|
|
172
|
-
"ordered",
|
|
173
|
-
"unordered"
|
|
174
|
-
]);
|
|
175
|
-
|
|
176
171
|
let compositeIndexFieldSchema = S$RescriptSchema.schema(s => ({
|
|
177
172
|
fieldName: s.m(S$RescriptSchema.string),
|
|
178
173
|
direction: s.m(S$RescriptSchema.string)
|
|
@@ -181,7 +176,8 @@ let compositeIndexFieldSchema = S$RescriptSchema.schema(s => ({
|
|
|
181
176
|
let derivedFieldSchema = S$RescriptSchema.schema(s => ({
|
|
182
177
|
fieldName: s.m(S$RescriptSchema.string),
|
|
183
178
|
derivedFromEntity: s.m(S$RescriptSchema.string),
|
|
184
|
-
derivedFromField: s.m(S$RescriptSchema.string)
|
|
179
|
+
derivedFromField: s.m(S$RescriptSchema.string),
|
|
180
|
+
description: s.m(S$RescriptSchema.option(S$RescriptSchema.string))
|
|
185
181
|
}));
|
|
186
182
|
|
|
187
183
|
let propertySchema = S$RescriptSchema.schema(s => ({
|
|
@@ -194,7 +190,8 @@ let propertySchema = S$RescriptSchema.schema(s => ({
|
|
|
194
190
|
enum: s.m(S$RescriptSchema.option(S$RescriptSchema.string)),
|
|
195
191
|
entity: s.m(S$RescriptSchema.option(S$RescriptSchema.string)),
|
|
196
192
|
precision: s.m(S$RescriptSchema.option(S$RescriptSchema.int)),
|
|
197
|
-
scale: s.m(S$RescriptSchema.option(S$RescriptSchema.int))
|
|
193
|
+
scale: s.m(S$RescriptSchema.option(S$RescriptSchema.int)),
|
|
194
|
+
description: s.m(S$RescriptSchema.option(S$RescriptSchema.string))
|
|
198
195
|
}));
|
|
199
196
|
|
|
200
197
|
let entityStorageSchema = S$RescriptSchema.schema(s => ({
|
|
@@ -207,7 +204,8 @@ let entityJsonSchema = S$RescriptSchema.schema(s => ({
|
|
|
207
204
|
storage: s.m(S$RescriptSchema.option(entityStorageSchema)),
|
|
208
205
|
properties: s.m(S$RescriptSchema.array(propertySchema)),
|
|
209
206
|
derivedFields: s.m(S$RescriptSchema.option(S$RescriptSchema.array(derivedFieldSchema))),
|
|
210
|
-
compositeIndices: s.m(S$RescriptSchema.option(S$RescriptSchema.array(S$RescriptSchema.array(compositeIndexFieldSchema))))
|
|
207
|
+
compositeIndices: s.m(S$RescriptSchema.option(S$RescriptSchema.array(S$RescriptSchema.array(compositeIndexFieldSchema)))),
|
|
208
|
+
description: s.m(S$RescriptSchema.option(S$RescriptSchema.string))
|
|
211
209
|
}));
|
|
212
210
|
|
|
213
211
|
function getFieldTypeAndSchema(prop, enumConfigsByName) {
|
|
@@ -325,14 +323,14 @@ function parseEntitiesFromJson(entitiesJson, enumConfigsByName, globalStorage) {
|
|
|
325
323
|
let entityName = entityJson.name;
|
|
326
324
|
let fields = entityJson.properties.map(prop => {
|
|
327
325
|
let match = getFieldTypeAndSchema(prop, enumConfigsByName);
|
|
328
|
-
return Table.mkField(prop.name, match[0], match[1], undefined, match[3], match[2], prop.name === "id", match[4], prop.linkedEntity);
|
|
326
|
+
return Table.mkField(prop.name, match[0], match[1], undefined, match[3], match[2], prop.name === "id", match[4], prop.linkedEntity, prop.description);
|
|
329
327
|
});
|
|
330
|
-
let derivedFields = Stdlib_Option.getOr(entityJson.derivedFields, []).map(df => Table.mkDerivedFromField(df.fieldName, df.derivedFromEntity, df.derivedFromField));
|
|
328
|
+
let derivedFields = Stdlib_Option.getOr(entityJson.derivedFields, []).map(df => Table.mkDerivedFromField(df.fieldName, df.derivedFromEntity, df.derivedFromField, df.description));
|
|
331
329
|
let compositeIndices = Stdlib_Option.getOr(entityJson.compositeIndices, []).map(ci => ci.map(f => ({
|
|
332
330
|
fieldName: f.fieldName,
|
|
333
331
|
direction: f.direction === "Asc" ? "Asc" : "Desc"
|
|
334
332
|
})));
|
|
335
|
-
let table = Table.mkTable(entityName, compositeIndices, fields.concat(derivedFields));
|
|
333
|
+
let table = Table.mkTable(entityName, compositeIndices, fields.concat(derivedFields), entityJson.description);
|
|
336
334
|
let schema = S$RescriptSchema.schema(s => {
|
|
337
335
|
let dict = {};
|
|
338
336
|
entityJson.properties.forEach(prop => {
|
|
@@ -378,7 +376,6 @@ let publicConfigSchema = S$RescriptSchema.schema(s => ({
|
|
|
378
376
|
description: s.m(S$RescriptSchema.option(S$RescriptSchema.string)),
|
|
379
377
|
handlers: s.m(S$RescriptSchema.option(S$RescriptSchema.string)),
|
|
380
378
|
isDev: s.m(S$RescriptSchema.option(S$RescriptSchema.bool)),
|
|
381
|
-
multichain: s.m(S$RescriptSchema.option(multichainSchema)),
|
|
382
379
|
fullBatchSize: s.m(S$RescriptSchema.option(S$RescriptSchema.int)),
|
|
383
380
|
rollbackOnReorg: s.m(S$RescriptSchema.option(S$RescriptSchema.bool)),
|
|
384
381
|
saveFullHistory: s.m(S$RescriptSchema.option(S$RescriptSchema.bool)),
|
|
@@ -478,7 +475,7 @@ function fromPublic(publicConfigJson) {
|
|
|
478
475
|
let capitalizedName = Utils.$$String.capitalize(param[0]);
|
|
479
476
|
let abi = contractConfig.abi;
|
|
480
477
|
let events = contractConfig.events;
|
|
481
|
-
let eventSignatures = events !== undefined ? events.map(eventItem => eventItem.
|
|
478
|
+
let eventSignatures = events !== undefined ? events.map(eventItem => eventItem.sighash) : [];
|
|
482
479
|
contractDataByName[capitalizedName] = {
|
|
483
480
|
abi: abi,
|
|
484
481
|
eventSignatures: eventSignatures,
|
|
@@ -511,10 +508,10 @@ function fromPublic(publicConfigJson) {
|
|
|
511
508
|
) : addresses[0];
|
|
512
509
|
let s = eventItem.svm;
|
|
513
510
|
let svm = s !== undefined ? Primitive_option.valFromOption(s) : Stdlib_JsError.throwWithMessage(`SVM instruction ` + contractName + `.` + eventName + ` is missing the "svm" descriptor in internal config`);
|
|
514
|
-
let accountFilters = Stdlib_Option.getOr(svm.accountFilters, []).map(af => ({
|
|
511
|
+
let accountFilters = Stdlib_Option.getOr(svm.accountFilters, []).map(group => group.map(af => ({
|
|
515
512
|
position: af.position,
|
|
516
513
|
values: af.values
|
|
517
|
-
}));
|
|
514
|
+
})));
|
|
518
515
|
return EventConfigBuilder.buildSvmInstructionEventConfig(contractName, eventName, programId, svm.discriminator, svm.discriminatorByteLen, svm.includeTransaction, svm.includeLogs, svm.includeTokenBalances, accountFilters, svm.isInner, false, undefined, undefined, Stdlib_Option.getOr(svm.accounts, []), Stdlib_Option.getOr(svm.args, null), svmDefinedTypes, startBlock);
|
|
519
516
|
}
|
|
520
517
|
});
|
|
@@ -562,8 +559,7 @@ function fromPublic(publicConfigJson) {
|
|
|
562
559
|
abi: contractData.abi,
|
|
563
560
|
addresses: addresses,
|
|
564
561
|
events: events,
|
|
565
|
-
startBlock: startBlock
|
|
566
|
-
eventSignatures: contractData.eventSignatures
|
|
562
|
+
startBlock: startBlock
|
|
567
563
|
};
|
|
568
564
|
});
|
|
569
565
|
let sourceConfig;
|
|
@@ -672,7 +668,6 @@ function fromPublic(publicConfigJson) {
|
|
|
672
668
|
shouldRollbackOnReorg: Stdlib_Option.getOr(publicConfig.rollbackOnReorg, true),
|
|
673
669
|
shouldSaveFullHistory: Stdlib_Option.getOr(publicConfig.saveFullHistory, false),
|
|
674
670
|
storage: globalStorage,
|
|
675
|
-
multichain: Stdlib_Option.getOr(publicConfig.multichain, "unordered"),
|
|
676
671
|
chainMap: chainMap,
|
|
677
672
|
defaultChain: chains[0],
|
|
678
673
|
ecosystem: ecosystem,
|
|
@@ -818,9 +813,10 @@ function canonicalJson(json) {
|
|
|
818
813
|
}
|
|
819
814
|
|
|
820
815
|
function diffPaths(stored, current) {
|
|
816
|
+
let canonEq = (a, b) => JSON.stringify(canonicalJson(a)) === JSON.stringify(canonicalJson(b));
|
|
821
817
|
let acc = [];
|
|
822
818
|
let go = (s, c, prefix) => {
|
|
823
|
-
if (
|
|
819
|
+
if (canonEq(s, c)) {
|
|
824
820
|
return;
|
|
825
821
|
}
|
|
826
822
|
if (Array.isArray(s)) {
|
|
@@ -868,16 +864,92 @@ function diffPaths(stored, current) {
|
|
|
868
864
|
}
|
|
869
865
|
acc.push(prefix === "" ? "<root>" : prefix);
|
|
870
866
|
};
|
|
871
|
-
|
|
867
|
+
let getTopKey = (j, k) => {
|
|
868
|
+
if (typeof j === "object" && j !== null && !Array.isArray(j)) {
|
|
869
|
+
return j[k];
|
|
870
|
+
}
|
|
871
|
+
};
|
|
872
|
+
let topKeyDiffers = k => {
|
|
873
|
+
let match = getTopKey(stored, k);
|
|
874
|
+
let match$1 = getTopKey(current, k);
|
|
875
|
+
if (match !== undefined) {
|
|
876
|
+
if (match$1 !== undefined) {
|
|
877
|
+
return !canonEq(match, match$1);
|
|
878
|
+
} else {
|
|
879
|
+
return true;
|
|
880
|
+
}
|
|
881
|
+
} else {
|
|
882
|
+
return match$1 !== undefined;
|
|
883
|
+
}
|
|
884
|
+
};
|
|
885
|
+
let runTier = keys => {
|
|
886
|
+
keys.forEach(k => {
|
|
887
|
+
let match = getTopKey(stored, k);
|
|
888
|
+
let match$1 = getTopKey(current, k);
|
|
889
|
+
if (match !== undefined) {
|
|
890
|
+
if (match$1 !== undefined) {
|
|
891
|
+
return go(match, match$1, k);
|
|
892
|
+
} else {
|
|
893
|
+
acc.push(k);
|
|
894
|
+
return;
|
|
895
|
+
}
|
|
896
|
+
} else if (match$1 !== undefined) {
|
|
897
|
+
acc.push(k);
|
|
898
|
+
return;
|
|
899
|
+
} else {
|
|
900
|
+
return;
|
|
901
|
+
}
|
|
902
|
+
});
|
|
903
|
+
};
|
|
904
|
+
if (typeof stored === "object" && stored !== null && !Array.isArray(stored) && typeof current === "object" && current !== null && !Array.isArray(current)) {
|
|
905
|
+
let tiers = [
|
|
906
|
+
["version"],
|
|
907
|
+
["name"],
|
|
908
|
+
["storage"],
|
|
909
|
+
[
|
|
910
|
+
"evm",
|
|
911
|
+
"fuel",
|
|
912
|
+
"svm"
|
|
913
|
+
],
|
|
914
|
+
["entities"]
|
|
915
|
+
];
|
|
916
|
+
let firstHit = Stdlib_Array.reduce(tiers, undefined, (acc, tier) => {
|
|
917
|
+
if (acc !== undefined) {
|
|
918
|
+
return acc;
|
|
919
|
+
}
|
|
920
|
+
let hits = tier.filter(topKeyDiffers);
|
|
921
|
+
if (hits.length !== 0) {
|
|
922
|
+
return hits;
|
|
923
|
+
}
|
|
924
|
+
});
|
|
925
|
+
if (firstHit !== undefined) {
|
|
926
|
+
runTier(firstHit);
|
|
927
|
+
} else {
|
|
928
|
+
let knownSet = new Set(Belt_Array.concatMany(tiers));
|
|
929
|
+
runTier(Array.from(new Set(Object.keys(stored).concat(Object.keys(current)))).filter(k => !knownSet.has(k)).toSorted(Primitive_string.compare).filter(topKeyDiffers));
|
|
930
|
+
}
|
|
931
|
+
} else {
|
|
932
|
+
go(stored, current, "");
|
|
933
|
+
}
|
|
872
934
|
return acc;
|
|
873
935
|
}
|
|
874
936
|
|
|
875
|
-
function throwIfIncompatible(changedPaths, resetCommand) {
|
|
937
|
+
function throwIfIncompatible(changedPaths, resetCommand, runCommand, hasClickhouse) {
|
|
876
938
|
if (changedPaths.length === 0) {
|
|
877
939
|
return;
|
|
878
940
|
}
|
|
879
941
|
let bullets = changedPaths.map(p => ` - ` + p).join("\n");
|
|
880
|
-
|
|
942
|
+
let option1 = "Revert the changes above";
|
|
943
|
+
let padTo = (s, col) => s + " ".repeat(Math.max(col - s.length | 0, 1));
|
|
944
|
+
let col = Math.max(option1.length, resetCommand.length) + 2 | 0;
|
|
945
|
+
let option3;
|
|
946
|
+
if (runCommand !== undefined) {
|
|
947
|
+
let clickhouseLine = hasClickhouse ? " ENVIO_CLICKHOUSE_DATABASE=<new_db> \\\n" : "";
|
|
948
|
+
option3 = `\n 3. Run a second indexer alongside this one — keep both datasets:\n ENVIO_PG_SCHEMA=<new_schema> \\\n` + clickhouseLine + ` ENVIO_INDEXER_PORT=<new_port> \\\n ` + runCommand;
|
|
949
|
+
} else {
|
|
950
|
+
option3 = "";
|
|
951
|
+
}
|
|
952
|
+
Stdlib_JsError.throwWithMessage(`The following config changes are incompatible with the existing indexer data:\n\n` + bullets + `\n\nPick one:\n 1. ` + padTo(option1, col) + `# resume indexing where it left off\n 2. ` + padTo(resetCommand, col) + `# delete all indexed data and start over` + option3);
|
|
881
953
|
}
|
|
882
954
|
|
|
883
955
|
function loadWithoutRegistrations() {
|
|
@@ -906,7 +978,6 @@ export {
|
|
|
906
978
|
contractConfigSchema,
|
|
907
979
|
publicConfigEcosystemSchema,
|
|
908
980
|
publicConfigEvmSchema,
|
|
909
|
-
multichainSchema,
|
|
910
981
|
compositeIndexFieldSchema,
|
|
911
982
|
derivedFieldSchema,
|
|
912
983
|
propertySchema,
|
package/src/Core.res
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
// Resolution order:
|
|
2
|
-
// 1. Production: require("envio-{os}-{arch}")
|
|
3
|
-
// 2. Dev build: find repo
|
|
2
|
+
// 1. Production: require("envio-{os}-{arch}") - platform-specific npm package
|
|
3
|
+
// 2. Dev build: find repo -> cargo build --lib -> load from target/debug/
|
|
4
4
|
|
|
5
5
|
// NAPI encodes Rust `Option<T>` as `null | T` (never `undefined`), so the
|
|
6
6
|
// tighter `Null.t` captures the exact boundary shape.
|
|
7
|
-
//
|
|
8
|
-
// Opaque carriers for the NAPI class constructors. Static factories
|
|
9
|
-
// (`newWithAgent`, `fromConfig`, `fromSignatures`) hang off these via `@send`
|
|
10
|
-
// in `HyperSyncClient.res` / `HyperSyncSolanaClient.res`.
|
|
11
7
|
type hypersyncClientCtor
|
|
12
8
|
type hypersyncSolanaClientCtor
|
|
13
9
|
type decoderCtor
|
|
@@ -147,8 +143,8 @@ let loadAddon = () => {
|
|
|
147
143
|
}
|
|
148
144
|
|
|
149
145
|
// Only swallow MODULE_NOT_FOUND (the optional package isn't installed on
|
|
150
|
-
// this host). Any other failure
|
|
151
|
-
// error
|
|
146
|
+
// this host). Any other failure - corrupt .node, ABI mismatch, dlopen
|
|
147
|
+
// error - is a real load failure and must surface.
|
|
152
148
|
let rec tryRequire = i =>
|
|
153
149
|
switch candidates[i] {
|
|
154
150
|
| None => None
|