envio 3.10.0-subgraph → 3.11.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 (76) hide show
  1. package/evm.schema.json +21 -4
  2. package/fuel.schema.json +21 -4
  3. package/index.d.ts +1 -1
  4. package/package.json +6 -6
  5. package/src/ChainState.res +9 -73
  6. package/src/ChainState.res.mjs +6 -58
  7. package/src/Config.res +73 -27
  8. package/src/Config.res.mjs +71 -21
  9. package/src/Core.res +0 -15
  10. package/src/Core.res.mjs +0 -11
  11. package/src/EventConfigBuilder.res +14 -10
  12. package/src/EventConfigBuilder.res.mjs +6 -4
  13. package/src/EventProcessing.res +6 -6
  14. package/src/EventProcessing.res.mjs +6 -8
  15. package/src/HandlerLoader.res +8 -20
  16. package/src/HandlerLoader.res.mjs +2 -11
  17. package/src/HandlerRegister.res +12 -11
  18. package/src/HandlerRegister.res.mjs +6 -5
  19. package/src/Internal.res +20 -4
  20. package/src/Internal.res.mjs +9 -0
  21. package/src/Main.res +8 -1
  22. package/src/Main.res.mjs +3 -3
  23. package/src/Persistence.res +11 -1
  24. package/src/Persistence.res.mjs +6 -2
  25. package/src/PgStorage.res +1 -1
  26. package/src/PgStorage.res.mjs +1 -1
  27. package/src/SimulateItems.res +13 -6
  28. package/src/SimulateItems.res.mjs +7 -6
  29. package/src/TestIndexer.res +6 -5
  30. package/src/TestIndexer.res.mjs +5 -4
  31. package/src/UserContext.res +51 -358
  32. package/src/UserContext.res.mjs +35 -271
  33. package/src/db/InternalTable.res +1 -1
  34. package/src/db/InternalTable.res.mjs +2 -1
  35. package/src/sources/ChainSources.res +72 -0
  36. package/src/sources/ChainSources.res.mjs +55 -0
  37. package/src/sources/EvmHyperSyncSource.res +10 -22
  38. package/src/sources/EvmHyperSyncSource.res.mjs +9 -41
  39. package/src/sources/FuelHyperSyncSource.res +10 -18
  40. package/src/sources/FuelHyperSyncSource.res.mjs +8 -38
  41. package/src/sources/HyperSync.res +31 -0
  42. package/src/sources/HyperSync.res.mjs +31 -0
  43. package/src/sources/HyperSync.resi +16 -0
  44. package/src/sources/StartBlockResolver.res +173 -0
  45. package/src/sources/StartBlockResolver.res.mjs +134 -0
  46. package/src/sources/Svm.res +0 -51
  47. package/src/sources/Svm.res.mjs +0 -46
  48. package/src/sources/SvmHyperSyncSource.res +20 -9
  49. package/src/sources/SvmHyperSyncSource.res.mjs +34 -12
  50. package/svm.schema.json +78 -63
  51. package/src/subgraph/blocks.ts +0 -176
  52. package/src/subgraph/calls.ts +0 -217
  53. package/src/subgraph/conformance.ts +0 -102
  54. package/src/subgraph/division.ts +0 -133
  55. package/src/subgraph/errors.ts +0 -90
  56. package/src/subgraph/graph-ts-types/VERSION +0 -2
  57. package/src/subgraph/graph-ts-types/chain/arweave.d.ts +0 -70
  58. package/src/subgraph/graph-ts-types/chain/cosmos.d.ts +0 -327
  59. package/src/subgraph/graph-ts-types/chain/ethereum.d.ts +0 -233
  60. package/src/subgraph/graph-ts-types/chain/near.d.ts +0 -253
  61. package/src/subgraph/graph-ts-types/chain/starknet.d.ts +0 -32
  62. package/src/subgraph/graph-ts-types/common/collections.d.ts +0 -136
  63. package/src/subgraph/graph-ts-types/common/conversion.d.ts +0 -11
  64. package/src/subgraph/graph-ts-types/common/datasource.d.ts +0 -30
  65. package/src/subgraph/graph-ts-types/common/eager-offset.d.ts +0 -0
  66. package/src/subgraph/graph-ts-types/common/json.d.ts +0 -17
  67. package/src/subgraph/graph-ts-types/common/numbers.d.ts +0 -120
  68. package/src/subgraph/graph-ts-types/common/value.d.ts +0 -120
  69. package/src/subgraph/graph-ts-types/common/yaml.d.ts +0 -90
  70. package/src/subgraph/graph-ts-types/global/global.d.ts +0 -194
  71. package/src/subgraph/graph-ts-types/helper-functions.d.ts +0 -22
  72. package/src/subgraph/graph-ts-types/index.d.ts +0 -102
  73. package/src/subgraph/graph-ts.ts +0 -1948
  74. package/src/subgraph/hosts.ts +0 -148
  75. package/src/subgraph/runtime.ts +0 -863
  76. package/src/subgraph/scope.ts +0 -66
@@ -1,7 +1,6 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
3
  import * as Utils from "./Utils.res.mjs";
4
- import * as ChainId from "./ChainId.res.mjs";
5
4
  import * as Logging from "./Logging.res.mjs";
6
5
  import * as Internal from "./Internal.res.mjs";
7
6
  import * as Ecosystem from "./Ecosystem.res.mjs";
@@ -13,70 +12,8 @@ import * as InMemoryStore from "./InMemoryStore.res.mjs";
13
12
  import * as InMemoryTable from "./InMemoryTable.res.mjs";
14
13
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
15
14
  import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
16
- import * as Stdlib_Promise from "@rescript/runtime/lib/es6/Stdlib_Promise.js";
17
15
  import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
18
16
  import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
19
- import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
20
-
21
- let Suspend = /* @__PURE__ */Primitive_exceptions.create("UserContext.Suspend");
22
-
23
- function isSuspend(exn) {
24
- return exn.RE_EXN_ID === Suspend;
25
- }
26
-
27
- function makeSyncState() {
28
- return {
29
- status: "Active",
30
- pending: undefined,
31
- memo: undefined
32
- };
33
- }
34
-
35
- function getPending(sync) {
36
- let pending = sync.pending;
37
- if (pending !== undefined) {
38
- return pending;
39
- }
40
- let pending$1 = [];
41
- sync.pending = pending$1;
42
- return pending$1;
43
- }
44
-
45
- function getMemo(sync) {
46
- let memo = sync.memo;
47
- if (memo !== undefined) {
48
- return memo;
49
- }
50
- let memo$1 = {};
51
- sync.memo = memo$1;
52
- return memo$1;
53
- }
54
-
55
- function checkStatusOrThrow(params, access) {
56
- let exn = params.sync.status;
57
- if (typeof exn !== "object") {
58
- if (exn === "Active") {
59
- return;
60
- } else {
61
- return ErrorHandling.mkLogAndRaise(Ecosystem.getItemLogger(params.item, params.config.ecosystem), undefined, new Error(`Impossible to access ` + access + ` after the handler is resolved. Make sure you didn't miss an await in the handler.`));
62
- }
63
- }
64
- throw exn._0;
65
- }
66
-
67
- function scheduleAndSuspend(params, promise) {
68
- getPending(params.sync).push(promise);
69
- params.sync.status = {
70
- TAG: "Aborted",
71
- _0: {
72
- RE_EXN_ID: Suspend
73
- }
74
- };
75
- throw {
76
- RE_EXN_ID: Suspend,
77
- Error: new Error()
78
- };
79
- }
80
17
 
81
18
  let paramsByThis = new WeakMap();
82
19
 
@@ -110,69 +47,28 @@ var EffectContext = function(params, chainId, effectName, defaultShouldCache, ca
110
47
  EffectContext.prototype = effectContextPrototype;
111
48
  ;
112
49
 
113
- function prepareEffectCall(params, effect, input, caller) {
114
- let isCrossChain = effect => Stdlib_Option.getOr(effect.crossChain, params.config.defaultCrossChain);
115
- let scope = isCrossChain(effect) ? "crossChain" : Internal.getItemChainId(params.item);
116
- if (caller !== undefined && isCrossChain(caller) && !isCrossChain(effect)) {
117
- Stdlib_JsError.throwWithMessage(`The cross-chain effect "` + caller.name + `" cannot call the chain-scoped effect "` + effect.name + `", because a cross-chain effect isn't tied to a single chain. Make "` + effect.name + `" cross-chain (\`crossChain: true\`), or make "` + caller.name + `" chain-scoped (\`crossChain: false\`).`);
118
- }
119
- let tmp;
120
- tmp = scope === "crossChain" ? undefined : Primitive_option.some(scope);
121
- let effectContext = new EffectContext(params, tmp, effect.name, effect.defaultShouldCache, (nested, nestedInput) => callEffectAsync(params, nested, nestedInput, effect));
122
- let effectArgs_cacheKey = Utils.Hash.makeOrThrow(S$RescriptSchema.reverseConvertOrThrow(input, effect.input));
123
- let effectArgs_checkpointId = params.checkpointId;
124
- let effectArgs = {
125
- input: input,
126
- context: effectContext,
127
- cacheKey: effectArgs_cacheKey,
128
- checkpointId: effectArgs_checkpointId
129
- };
130
- return [
131
- scope,
132
- effectArgs
133
- ];
134
- }
135
-
136
- function callEffectAsync(params, effect, input, caller) {
137
- let match = prepareEffectCall(params, effect, input, caller);
138
- return LoadLayer.loadEffect(params.loadManager, params.persistence, effect, match[1], match[0], params.indexerState, params.isPreload, params.item, params.config.ecosystem);
139
- }
140
-
141
50
  function initEffect(params) {
142
- return (effect, input) => {
143
- checkStatusOrThrow(params, "context.effect");
144
- return callEffectAsync(params, effect, input, undefined);
145
- };
146
- }
147
-
148
- function effectMemoKey(effect, scope, cacheKey) {
149
- if (scope === "crossChain") {
150
- return effect.name + `.` + cacheKey;
151
- } else {
152
- return effect.name + `.` + ChainId.toString(scope) + `.` + cacheKey;
153
- }
154
- }
155
-
156
- function initEffectSync(params) {
157
- return (effect, input) => {
158
- checkStatusOrThrow(params, "context.effectSync");
159
- let match = prepareEffectCall(params, effect, input, undefined);
160
- let effectArgs = match[1];
161
- let scope = match[0];
162
- let memo = getMemo(params.sync);
163
- let memoKey = effectMemoKey(effect, scope, effectArgs.cacheKey);
164
- let output = memo[memoKey];
165
- if (output !== undefined) {
166
- return Primitive_option.valFromOption(output);
167
- }
168
- let inMemTable = InMemoryStore.getEffectInMemTable(params.indexerState, effect, scope);
169
- if (!InMemoryStore.hasEffectOutput(inMemTable, effectArgs.cacheKey)) {
170
- return scheduleAndSuspend(params, LoadLayer.loadEffect(params.loadManager, params.persistence, effect, effectArgs, scope, params.indexerState, params.isPreload, params.item, params.config.ecosystem));
51
+ let handlerChainId = Internal.getItemChainId(params.item);
52
+ let isCrossChain = effect => Stdlib_Option.getOr(effect.crossChain, params.config.defaultCrossChain);
53
+ let makeCaller = caller => ((effect, input) => {
54
+ let scope = isCrossChain(effect) ? "crossChain" : handlerChainId;
55
+ if (caller !== undefined && isCrossChain(caller) && !isCrossChain(effect)) {
56
+ Stdlib_JsError.throwWithMessage(`The cross-chain effect "` + caller.name + `" cannot call the chain-scoped effect "` + effect.name + `", because a cross-chain effect isn't tied to a single chain. Make "` + effect.name + `" cross-chain (\`crossChain: true\`), or make "` + caller.name + `" chain-scoped (\`crossChain: false\`).`);
171
57
  }
172
- let output$1 = InMemoryStore.getEffectOutputUnsafe(inMemTable, effectArgs.cacheKey);
173
- memo[memoKey] = output$1;
174
- return output$1;
175
- };
58
+ let tmp;
59
+ tmp = scope === "crossChain" ? undefined : Primitive_option.some(scope);
60
+ let effectContext = new EffectContext(params, tmp, effect.name, effect.defaultShouldCache, makeCaller(effect));
61
+ let effectArgs_cacheKey = Utils.Hash.makeOrThrow(S$RescriptSchema.reverseConvertOrThrow(input, effect.input));
62
+ let effectArgs_checkpointId = params.checkpointId;
63
+ let effectArgs = {
64
+ input: input,
65
+ context: effectContext,
66
+ cacheKey: effectArgs_cacheKey,
67
+ checkpointId: effectArgs_checkpointId
68
+ };
69
+ return LoadLayer.loadEffect(params.loadManager, params.persistence, effect, effectArgs, scope, params.indexerState, params.isPreload, params.item, params.config.ecosystem);
70
+ });
71
+ return makeCaller(undefined);
176
72
  }
177
73
 
178
74
  function entityScope(params) {
@@ -201,83 +97,24 @@ function throwClickHouseReadOnly(entityConfig, op) {
201
97
  return Stdlib_JsError.throwWithMessage(`context.` + entityConfig.name + `.` + op + `() is unavailable: ClickHouse storage is currently write-only. Follow Envio releases to be notified when ClickHouse supports both reads and writes from handlers.`);
202
98
  }
203
99
 
204
- function getSyncHandler(params, entityId) {
205
- let inMemTable = InMemoryStore.getInMemTable(params.indexerState, params.entityConfig, entityScope(params));
206
- if (entityId in inMemTable.latestEntityChangeById) {
207
- return InMemoryTable.Entity.getUnsafe(inMemTable)(entityId);
208
- } else {
209
- return scheduleAndSuspend(params, LoadLayer.loadById(params.loadManager, params.persistence, params.entityConfig, entityScope(params), params.indexerState, params.isPreload, params.item, params.config.ecosystem, entityId));
210
- }
211
- }
212
-
213
- function getWhereSyncHandler(params, filter) {
214
- let entityConfig = params.entityConfig;
215
- let inMemTable = InMemoryStore.getInMemTable(params.indexerState, entityConfig, entityScope(params));
216
- let hasIndex = InMemoryTable.Entity.hasIndex(inMemTable);
217
- let getOnIndex = InMemoryTable.Entity.getUnsafeOnIndex(inMemTable);
218
- let filters = EntityFilter.parseGetWhereOrThrow(filter, entityConfig.name, entityConfig.table);
219
- let missing = [];
220
- let entities = [];
221
- filters.forEach(filter => {
222
- let filterKey = EntityFilter.toString(filter);
223
- if (hasIndex(filterKey)) {
224
- entities.push(...getOnIndex(filterKey));
225
- } else {
226
- missing.push(LoadLayer.loadByFilter(params.loadManager, params.persistence, entityConfig, entityScope(params), params.indexerState, params.isPreload, params.item, params.config.ecosystem, filter));
227
- }
228
- });
229
- if (Utils.$$Array.notEmpty(missing)) {
230
- let pending = getPending(params.sync);
231
- missing.forEach(promise => {
232
- pending.push(promise);
233
- });
234
- params.sync.status = {
235
- TAG: "Aborted",
236
- _0: {
237
- RE_EXN_ID: Suspend
238
- }
239
- };
240
- throw {
241
- RE_EXN_ID: Suspend,
242
- Error: new Error()
243
- };
244
- }
245
- return entities;
246
- }
247
-
248
- function getInBlockSyncHandler(params, entityId) {
249
- let inMemTable = InMemoryStore.getInMemTable(params.indexerState, params.entityConfig, entityScope(params));
250
- let change = inMemTable.latestEntityChangeById[entityId];
251
- if (change !== undefined && change.checkpointId === params.checkpointId) {
252
- return InMemoryTable.Entity.mapChangeToEntity(change);
253
- }
254
- }
255
-
256
100
  let entityTraps_get = (params, prop) => {
257
- checkStatusOrThrow(params, `context.` + params.entityConfig.name + `.` + prop);
258
101
  let isClickHouseOnly = !params.entityConfig.storage.postgres;
259
- let set = params.isPreload ? noopSet : entity => {
260
- checkStatusOrThrow(params, `context.` + params.entityConfig.name + `.set`);
261
- InMemoryTable.Entity.set(InMemoryStore.getInMemTable(params.indexerState, params.entityConfig, entityScope(params)), IndexerState.committedCheckpointId(params.indexerState), {
262
- type: "SET",
263
- entityId: entity.id,
264
- entity: entity,
265
- checkpointId: params.checkpointId
266
- });
267
- };
102
+ let set = params.isPreload ? noopSet : entity => InMemoryTable.Entity.set(InMemoryStore.getInMemTable(params.indexerState, params.entityConfig, entityScope(params)), IndexerState.committedCheckpointId(params.indexerState), {
103
+ type: "SET",
104
+ entityId: entity.id,
105
+ entity: entity,
106
+ checkpointId: params.checkpointId
107
+ });
268
108
  switch (prop) {
269
109
  case "deleteUnsafe" :
270
110
  if (params.isPreload) {
271
111
  return noopDeleteUnsafe;
272
112
  } else {
273
- return entityId => {
274
- checkStatusOrThrow(params, `context.` + params.entityConfig.name + `.deleteUnsafe`);
275
- InMemoryTable.Entity.set(InMemoryStore.getInMemTable(params.indexerState, params.entityConfig, entityScope(params)), IndexerState.committedCheckpointId(params.indexerState), {
276
- type: "DELETE",
277
- entityId: entityId,
278
- checkpointId: params.checkpointId
279
- });
280
- };
113
+ return entityId => InMemoryTable.Entity.set(InMemoryStore.getInMemTable(params.indexerState, params.entityConfig, entityScope(params)), IndexerState.committedCheckpointId(params.indexerState), {
114
+ type: "DELETE",
115
+ entityId: entityId,
116
+ checkpointId: params.checkpointId
117
+ });
281
118
  }
282
119
  case "get" :
283
120
  if (isClickHouseOnly) {
@@ -285,8 +122,6 @@ let entityTraps_get = (params, prop) => {
285
122
  } else {
286
123
  return entityId => LoadLayer.loadById(params.loadManager, params.persistence, params.entityConfig, entityScope(params), params.indexerState, params.isPreload, params.item, params.config.ecosystem, entityId);
287
124
  }
288
- case "getInBlockSync" :
289
- return entityId => getInBlockSyncHandler(params, entityId);
290
125
  case "getOrCreate" :
291
126
  if (isClickHouseOnly) {
292
127
  return _entity => throwClickHouseReadOnly(params.entityConfig, "getOrCreate");
@@ -312,16 +147,12 @@ let entityTraps_get = (params, prop) => {
312
147
  }
313
148
  });
314
149
  }
315
- case "getSync" :
316
- return entityId => getSyncHandler(params, entityId);
317
150
  case "getWhere" :
318
151
  if (isClickHouseOnly) {
319
152
  return _filter => throwClickHouseReadOnly(params.entityConfig, "getWhere");
320
153
  } else {
321
154
  return filter => getWhereHandler(params, filter);
322
155
  }
323
- case "getWhereSync" :
324
- return filter => getWhereSyncHandler(params, filter);
325
156
  case "set" :
326
157
  return set;
327
158
  default:
@@ -333,63 +164,16 @@ let entityTraps = {
333
164
  get: entityTraps_get
334
165
  };
335
166
 
336
- async function runSyncRound(params, fn, round) {
337
- if (round > 10000) {
338
- Stdlib_JsError.throwWithMessage(`The handler suspended on a synchronous read too many times: gave up after ` + (10000).toString() + ` rounds. This usually means the code isn't deterministic across reruns.`);
339
- }
340
- params.sync.status = "Active";
341
- params.sync.pending = undefined;
342
- let suspended;
343
- try {
344
- fn();
345
- suspended = false;
346
- } catch (raw_exn) {
347
- let exn = Primitive_exceptions.internalToException(raw_exn);
348
- if (exn.RE_EXN_ID === Suspend) {
349
- suspended = true;
350
- } else {
351
- let pending = params.sync.pending;
352
- if (pending !== undefined) {
353
- params.sync.pending = undefined;
354
- pending.forEach(promise => {
355
- Utils.$$Promise.silentCatch(promise);
356
- });
357
- }
358
- throw exn;
359
- }
360
- }
361
- let pending$1 = params.sync.pending;
362
- if (pending$1 === undefined) {
363
- return;
364
- }
365
- params.sync.pending = undefined;
366
- if (suspended) {
367
- let errors = [];
368
- await Promise.all(pending$1.map(promise => Stdlib_Promise.$$catch(promise, exn => {
369
- errors.push(exn);
370
- return Promise.resolve();
371
- })));
372
- let exn$1 = errors[0];
373
- if (exn$1 !== undefined) {
374
- throw exn$1;
375
- }
376
- return await runSyncRound(params, fn, round + 1 | 0);
377
- }
378
- pending$1.forEach(promise => {
379
- Utils.$$Promise.silentCatch(promise);
380
- });
381
- }
382
-
383
167
  let handlerTraps_get = (params, prop) => {
384
- checkStatusOrThrow(params, `context.` + prop);
168
+ if (params.isResolved) {
169
+ ErrorHandling.mkLogAndRaise(Ecosystem.getItemLogger(params.item, params.config.ecosystem), undefined, new Error(`Impossible to access context.` + prop + ` after the handler is resolved. Make sure you didn't miss an await in the handler.`));
170
+ }
385
171
  switch (prop) {
386
172
  case "chain" :
387
173
  let chainId = Internal.getItemChainId(params.item);
388
174
  return params.chains[chainId];
389
175
  case "effect" :
390
176
  return initEffect(params);
391
- case "effectSync" :
392
- return initEffectSync(params);
393
177
  case "isPreload" :
394
178
  return params.isPreload;
395
179
  case "log" :
@@ -398,8 +182,6 @@ let handlerTraps_get = (params, prop) => {
398
182
  } else {
399
183
  return Ecosystem.getItemUserLogger(params.item, params.config.ecosystem);
400
184
  }
401
- case "runSync" :
402
- return fn => runSyncRound(params, fn, 1);
403
185
  default:
404
186
  let entityConfig = params.config.userEntitiesByName[prop];
405
187
  if (entityConfig !== undefined) {
@@ -412,7 +194,7 @@ let handlerTraps_get = (params, prop) => {
412
194
  isPreload: params.isPreload,
413
195
  chains: params.chains,
414
196
  config: params.config,
415
- sync: params.sync,
197
+ isResolved: params.isResolved,
416
198
  entityConfig: entityConfig
417
199
  }, entityTraps);
418
200
  } else {
@@ -429,34 +211,16 @@ function getHandlerContext(params) {
429
211
  return new Proxy(params, handlerTraps);
430
212
  }
431
213
 
432
- let maxSyncRounds = 10000;
433
-
434
214
  export {
435
- Suspend,
436
- isSuspend,
437
- makeSyncState,
438
- getPending,
439
- getMemo,
440
- checkStatusOrThrow,
441
- scheduleAndSuspend,
442
215
  paramsByThis,
443
216
  effectContextPrototype,
444
- prepareEffectCall,
445
- callEffectAsync,
446
217
  initEffect,
447
- effectMemoKey,
448
- initEffectSync,
449
218
  entityScope,
450
219
  getWhereHandler,
451
220
  noopSet,
452
221
  noopDeleteUnsafe,
453
222
  throwClickHouseReadOnly,
454
- getSyncHandler,
455
- getWhereSyncHandler,
456
- getInBlockSyncHandler,
457
223
  entityTraps,
458
- maxSyncRounds,
459
- runSyncRound,
460
224
  handlerTraps,
461
225
  getHandlerContext,
462
226
  }
@@ -272,7 +272,7 @@ module Chains = {
272
272
  {
273
273
  id: chainConfig.id,
274
274
  ecosystem: (chainConfig.ecosystem: Ecosystem.name :> string),
275
- startBlock: chainConfig.startBlock,
275
+ startBlock: chainConfig->Config.startBlockOrThrow,
276
276
  endBlock: chainConfig.endBlock->Null.fromOption,
277
277
  maxReorgDepth: chainConfig.maxReorgDepth,
278
278
  blockHeight: 0,
@@ -2,6 +2,7 @@
2
2
 
3
3
  import * as Table from "./Table.res.mjs";
4
4
  import * as Utils from "../Utils.res.mjs";
5
+ import * as Config from "../Config.res.mjs";
5
6
  import * as Address from "../Address.res.mjs";
6
7
  import * as ChainId from "../ChainId.res.mjs";
7
8
  import * as Postgres from "../bindings/Postgres.res.mjs";
@@ -181,7 +182,7 @@ function initialFromConfig(chainConfig) {
181
182
  return {
182
183
  id: chainConfig.id,
183
184
  ecosystem: chainConfig.ecosystem,
184
- start_block: chainConfig.startBlock,
185
+ start_block: Config.startBlockOrThrow(chainConfig),
185
186
  end_block: Stdlib_Null.fromOption(chainConfig.endBlock),
186
187
  max_reorg_depth: chainConfig.maxReorgDepth,
187
188
  source_block: 0,
@@ -0,0 +1,72 @@
1
+ // Sits below `ChainState`/`Persistence` in the module graph so that
2
+ // `StartBlockResolver` (called from `Persistence.init`) can build a chain's
3
+ // sources without a dependency cycle.
4
+ let make = (
5
+ ~chainConfig: Config.chain,
6
+ ~onEventRegistrations: array<Internal.onEventRegistration>,
7
+ ~addressStore: AddressStore.t,
8
+ ~lowercaseAddresses: bool,
9
+ ): array<Source.t> => {
10
+ let chainId = chainConfig.id
11
+ switch chainConfig.sourceConfig {
12
+ | Config.EvmSourceConfig({hypersync, rpcs}) =>
13
+ let evmRpcs: array<EvmChain.rpc> = rpcs->Array.map((rpc): EvmChain.rpc => {
14
+ let syncConfig = rpc.syncConfig
15
+ let ws = rpc.ws
16
+ let headers = rpc.headers
17
+ {
18
+ url: rpc.url,
19
+ sourceFor: rpc.sourceFor,
20
+ ?syncConfig,
21
+ ?ws,
22
+ ?headers,
23
+ }
24
+ })
25
+ EvmChain.makeSources(
26
+ ~chainId,
27
+ ~onEventRegistrations=onEventRegistrations->(
28
+ Utils.magic: array<Internal.onEventRegistration> => array<Internal.evmOnEventRegistration>
29
+ ),
30
+ ~hyperSync=hypersync,
31
+ ~rpcs=evmRpcs,
32
+ ~lowercaseAddresses,
33
+ ~addressStore,
34
+ )
35
+ | Config.FuelSourceConfig({hypersync}) => [
36
+ FuelHyperSyncSource.make({
37
+ chainId,
38
+ endpointUrl: hypersync,
39
+ apiToken: Env.envioApiToken,
40
+ onEventRegistrations,
41
+ addressStore,
42
+ }),
43
+ ]
44
+ | Config.SvmSourceConfig({hypersync}) => [
45
+ SvmHyperSyncSource.make({
46
+ chainId,
47
+ endpointUrl: hypersync,
48
+ apiToken: Env.envioApiToken,
49
+ onEventRegistrations: onEventRegistrations->(
50
+ Utils.magic: array<Internal.onEventRegistration> => array<
51
+ Internal.svmOnEventRegistration,
52
+ >
53
+ ),
54
+ clientTimeoutMillis: Env.hyperSyncClientTimeoutMillis,
55
+ addressStore,
56
+ }),
57
+ ]
58
+ | Config.SimulateSourceConfig({items, endBlock, ?transactionStore, ?blockStore}) => [
59
+ SimulateSource.make(
60
+ ~items,
61
+ ~endBlock,
62
+ ~chainId,
63
+ ~addressStore,
64
+ ~ecosystem=chainConfig.ecosystem,
65
+ ~transactionStore,
66
+ ~blockStore,
67
+ ),
68
+ ]
69
+ // For tests: use ready-to-use sources directly
70
+ | Config.CustomSources(sources) => sources
71
+ }
72
+ }
@@ -0,0 +1,55 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Env from "../Env.res.mjs";
4
+ import * as EvmChain from "./EvmChain.res.mjs";
5
+ import * as SimulateSource from "./SimulateSource.res.mjs";
6
+ import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
7
+ import * as SvmHyperSyncSource from "./SvmHyperSyncSource.res.mjs";
8
+ import * as FuelHyperSyncSource from "./FuelHyperSyncSource.res.mjs";
9
+
10
+ function make(chainConfig, onEventRegistrations, addressStore, lowercaseAddresses) {
11
+ let chainId = chainConfig.id;
12
+ let sources = chainConfig.sourceConfig;
13
+ switch (sources.TAG) {
14
+ case "EvmSourceConfig" :
15
+ let evmRpcs = sources.rpcs.map(rpc => {
16
+ let syncConfig = rpc.syncConfig;
17
+ let ws = rpc.ws;
18
+ let headers = rpc.headers;
19
+ return {
20
+ url: rpc.url,
21
+ sourceFor: rpc.sourceFor,
22
+ syncConfig: syncConfig,
23
+ ws: ws,
24
+ headers: headers
25
+ };
26
+ });
27
+ return EvmChain.makeSources(chainId, onEventRegistrations, sources.hypersync, evmRpcs, lowercaseAddresses, addressStore);
28
+ case "FuelSourceConfig" :
29
+ return [FuelHyperSyncSource.make({
30
+ chainId: chainId,
31
+ endpointUrl: sources.hypersync,
32
+ apiToken: Env.envioApiToken,
33
+ onEventRegistrations: onEventRegistrations,
34
+ addressStore: addressStore
35
+ })];
36
+ case "SvmSourceConfig" :
37
+ return [SvmHyperSyncSource.make({
38
+ chainId: chainId,
39
+ endpointUrl: sources.hypersync,
40
+ apiToken: Env.envioApiToken,
41
+ onEventRegistrations: onEventRegistrations,
42
+ clientTimeoutMillis: Env.hyperSyncClientTimeoutMillis,
43
+ addressStore: addressStore
44
+ })];
45
+ case "SimulateSourceConfig" :
46
+ return [SimulateSource.make(sources.items, sources.endBlock, chainId, addressStore, chainConfig.ecosystem, Primitive_option.some(sources.transactionStore), Primitive_option.some(sources.blockStore))];
47
+ case "CustomSources" :
48
+ return sources._0;
49
+ }
50
+ }
51
+
52
+ export {
53
+ make,
54
+ }
55
+ /* Env Not a pure module */
@@ -1,11 +1,5 @@
1
1
  open Source
2
2
 
3
- // Surfaced by the HyperSync client (Rust) when HyperSync rejects the API
4
- // token. The corrupted-token test feeds the real server error (from the query
5
- // endpoint; the edge no longer 401s malformed tokens on /height) through this
6
- // check so it can't silently drift away from what getHeightOrThrow guards on.
7
- let isUnauthorizedError = (message: string) => message->String.includes("401 Unauthorized")
8
-
9
3
  type options = {
10
4
  chainId: ChainId.t,
11
5
  endpointUrl: string,
@@ -37,13 +31,11 @@ let make = (
37
31
  ): t => {
38
32
  let name = "HyperSync"
39
33
 
40
- let apiToken = switch apiToken {
41
- | Some(token) => token
42
- | None =>
43
- JsError.throwWithMessage(`An Envio API token is required for using HyperSync as a data-source.
44
- Set the ENVIO_API_TOKEN environment variable in your .env file.
45
- Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`)
46
- }
34
+ // Per source, so one rejected token is reported once rather than on every
35
+ // height retry for the life of the process.
36
+ let unauthorizedWarned = ref(false)
37
+
38
+ let apiToken = apiToken->HyperSync.requireApiToken
47
39
 
48
40
  let client = switch HyperSyncClient.make(
49
41
  ~url=endpointUrl,
@@ -213,15 +205,11 @@ Learn more or get a free Envio API token at: https://envio.dev/app/api-tokens`)
213
205
  let height = try {
214
206
  await client.getHeight()
215
207
  } catch {
216
- | JsExn(e) =>
217
- switch e->JsExn.message {
218
- | Some(message) if message->isUnauthorizedError =>
219
- Logging.error(`Your ENVIO_API_TOKEN was rejected by HyperSync (401 Unauthorized). The indexer will not be able to fetch events. Update the token and try again using 'envio start' or 'envio dev'. For more info: https://docs.envio.dev/docs/HyperSync/api-tokens`)
220
- // Retrying an unauthorized request can never succeed, so block forever
221
- let _ = await Promise.make((_, _) => ())
222
- 0
223
- | _ => throw(JsExn(e))
224
- }
208
+ | exn =>
209
+ exn->HyperSync.rethrowLoggingUnauthorized(
210
+ ~warned=unauthorizedWarned,
211
+ ~product="HyperSync",
212
+ )
225
213
  }
226
214
  let seconds = timerRef->Performance.secondsSince
227
215
  {height, requestStats: [{method: "getHeight", seconds}]}