envio 3.0.0-alpha.4 → 3.0.0-alpha.5

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 (55) hide show
  1. package/index.d.ts +329 -0
  2. package/index.js +3 -0
  3. package/package.json +13 -6
  4. package/rescript.json +4 -1
  5. package/src/ChainFetcher.res +25 -1
  6. package/src/ChainFetcher.res.mjs +19 -1
  7. package/src/Config.res +211 -18
  8. package/src/Config.res.mjs +226 -27
  9. package/src/{Indexer.res → Ctx.res} +1 -1
  10. package/src/EventProcessing.res +18 -18
  11. package/src/EventProcessing.res.mjs +14 -14
  12. package/src/GlobalState.res +29 -35
  13. package/src/GlobalState.res.mjs +47 -47
  14. package/src/GlobalStateManager.res +68 -0
  15. package/src/GlobalStateManager.res.mjs +75 -0
  16. package/src/GlobalStateManager.resi +7 -0
  17. package/src/Internal.res +0 -1
  18. package/src/LogSelection.res +33 -27
  19. package/src/LogSelection.res.mjs +6 -0
  20. package/src/Main.res +342 -0
  21. package/src/Main.res.mjs +289 -0
  22. package/src/PgStorage.gen.ts +10 -0
  23. package/src/PgStorage.res +24 -2
  24. package/src/PgStorage.res.d.mts +5 -0
  25. package/src/PgStorage.res.mjs +22 -1
  26. package/src/UserContext.res +0 -1
  27. package/src/UserContext.res.mjs +0 -2
  28. package/src/Utils.res +13 -0
  29. package/src/bindings/Ethers.res +0 -4
  30. package/src/bindings/Ethers.res.mjs +0 -5
  31. package/src/bindings/Postgres.gen.ts +8 -0
  32. package/src/bindings/Postgres.res +3 -0
  33. package/src/bindings/Postgres.res.d.mts +5 -0
  34. package/src/bindings/RescriptMocha.res +123 -0
  35. package/src/bindings/RescriptMocha.res.mjs +18 -0
  36. package/src/bindings/Yargs.res +8 -0
  37. package/src/bindings/Yargs.res.mjs +2 -0
  38. package/src/sources/FuelSDK.res +4 -3
  39. package/src/tui/Tui.res +266 -0
  40. package/src/tui/Tui.res.mjs +342 -0
  41. package/src/tui/bindings/Ink.res +376 -0
  42. package/src/tui/bindings/Ink.res.mjs +75 -0
  43. package/src/tui/bindings/Style.res +123 -0
  44. package/src/tui/bindings/Style.res.mjs +2 -0
  45. package/src/tui/components/BufferedProgressBar.res +40 -0
  46. package/src/tui/components/BufferedProgressBar.res.mjs +57 -0
  47. package/src/tui/components/CustomHooks.res +114 -0
  48. package/src/tui/components/CustomHooks.res.mjs +162 -0
  49. package/src/tui/components/Messages.res +41 -0
  50. package/src/tui/components/Messages.res.mjs +75 -0
  51. package/src/tui/components/SyncETA.res +193 -0
  52. package/src/tui/components/SyncETA.res.mjs +269 -0
  53. package/src/tui/components/TuiData.res +46 -0
  54. package/src/tui/components/TuiData.res.mjs +29 -0
  55. /package/src/{Indexer.res.mjs → Ctx.res.mjs} +0 -0
package/index.d.ts CHANGED
@@ -111,6 +111,9 @@ export declare namespace S {
111
111
  export type Schema<Output, Input = unknown> = Sury.Schema<Output, Input>;
112
112
  export const string: typeof Sury.string;
113
113
  export const address: Sury.Schema<Address, Address>;
114
+ // export const evmChainId: Sury.Schema<EvmChainId, EvmChainId>;
115
+ // export const fuelChainId: Sury.Schema<FuelChainId, FuelChainId>;
116
+ // export const svmChainId: Sury.Schema<SvmChainId, SvmChainId>;
114
117
  export const jsonString: typeof Sury.jsonString;
115
118
  export const boolean: typeof Sury.boolean;
116
119
  export const int32: typeof Sury.int32;
@@ -140,3 +143,329 @@ export declare namespace S {
140
143
  export const assertOrThrow: typeof Sury.assertOrThrow;
141
144
  export const parseOrThrow: typeof Sury.parseOrThrow;
142
145
  }
146
+
147
+ // ============== Indexer Config (Module Augmentation) ==============
148
+
149
+ /**
150
+ * Configuration interface for the indexer.
151
+ * This interface is augmented by generated/envio.d.ts with project-specific config using typeof config.
152
+ *
153
+ * @example
154
+ * // In generated/envio.d.ts:
155
+ * declare module "envio" {
156
+ * interface Global {
157
+ * config: typeof config;
158
+ * }
159
+ * }
160
+ */
161
+ export interface Global {}
162
+
163
+ /**
164
+ * Shape of the indexer configuration.
165
+ * Used as a constraint for IndexerFromConfig to allow usage without codegen.
166
+ */
167
+ export type IndexerConfig = {
168
+ /** The indexer name. */
169
+ name: string;
170
+ /** The indexer description. */
171
+ description?: string;
172
+ /** Path to handlers directory for auto-loading (default: "src/handlers"). */
173
+ handlers?: string;
174
+ /** Multichain mode: ordered or unordered (default: "unordered"). */
175
+ multichain?: "ordered" | "unordered";
176
+ /** Target batch size for event processing (default: 5000). */
177
+ fullBatchSize?: number;
178
+ /** Whether to rollback on chain reorg (default: true). */
179
+ rollbackOnReorg?: boolean;
180
+ /** Whether to save full entity history (default: false). */
181
+ saveFullHistory?: boolean;
182
+ /** Whether raw events are enabled (default: false). */
183
+ rawEvents?: boolean;
184
+ /** EVM ecosystem configuration. */
185
+ evm?: {
186
+ /** Chain configurations keyed by chain name. */
187
+ chains: Record<string, EvmChainConfig>;
188
+ /** Contract configurations keyed by contract name. */
189
+ contracts?: Record<string, EvmContractConfig>;
190
+ /** Address format (default: "checksum"). */
191
+ addressFormat?: "lowercase" | "checksum";
192
+ /** Event decoder (default: "hypersync"). */
193
+ eventDecoder?: "hypersync" | "viem";
194
+ };
195
+ /** Fuel ecosystem configuration. */
196
+ fuel?: {
197
+ /** Chain configurations keyed by chain name. */
198
+ chains: Record<string, FuelChainConfig>;
199
+ /** Contract configurations keyed by contract name. */
200
+ contracts?: Record<string, FuelContractConfig>;
201
+ };
202
+ /** SVM ecosystem configuration. */
203
+ svm?: {
204
+ /** Chain configurations keyed by chain name. */
205
+ chains: Record<string, SvmChainConfig>;
206
+ };
207
+ };
208
+
209
+ // ============== Contract Types ==============
210
+
211
+ /** EVM contract configuration. */
212
+ type EvmContractConfig = {
213
+ /** The contract ABI. */
214
+ readonly abi: unknown;
215
+ };
216
+
217
+ /** Fuel contract configuration. */
218
+ type FuelContractConfig = {
219
+ /** The contract ABI. */
220
+ readonly abi: unknown;
221
+ };
222
+
223
+ // ============== EVM Types ==============
224
+
225
+ /** EVM chain configuration (for IndexerConfig). */
226
+ type EvmChainConfig<Id extends number = number> = {
227
+ /** The chain ID. */
228
+ readonly id: Id;
229
+ /** The block number indexing starts from. */
230
+ readonly startBlock: number;
231
+ /** The block number indexing stops at (if configured). */
232
+ readonly endBlock?: number;
233
+ /** Number of blocks to keep for reorg handling (default: 200). */
234
+ readonly maxReorgDepth?: number;
235
+ };
236
+
237
+ /** EVM chain value (for runtime Indexer). */
238
+ type EvmChain<
239
+ Id extends number = number,
240
+ ContractName extends string = never
241
+ > = {
242
+ /** The chain ID. */
243
+ readonly id: Id;
244
+ /** The chain name. */
245
+ readonly name: string;
246
+ /** The block number indexing starts from. */
247
+ readonly startBlock: number;
248
+ /** The block number indexing stops at (if configured). */
249
+ readonly endBlock: number | undefined;
250
+ /** Whether the chain has completed initial sync and is processing live events. */
251
+ readonly isLive: boolean;
252
+ } & {
253
+ readonly [K in ContractName]: EvmContract<K>;
254
+ };
255
+
256
+ /** EVM contract (for runtime Indexer). */
257
+ type EvmContract<Name extends string = string> = {
258
+ /** The contract name. */
259
+ readonly name: Name;
260
+ /** The contract ABI. */
261
+ readonly abi: readonly unknown[];
262
+ /** The contract addresses. */
263
+ readonly addresses: readonly Address[];
264
+ };
265
+
266
+ /** Fuel contract (for runtime Indexer). */
267
+ type FuelContract<Name extends string = string> = {
268
+ /** The contract name. */
269
+ readonly name: Name;
270
+ /** The contract ABI. */
271
+ readonly abi: unknown;
272
+ /** The contract addresses. */
273
+ readonly addresses: readonly Address[];
274
+ };
275
+
276
+ // ============== Fuel Types ==============
277
+
278
+ /** Fuel chain configuration (for IndexerConfig). */
279
+ type FuelChainConfig<Id extends number = number> = {
280
+ /** The chain ID. */
281
+ readonly id: Id;
282
+ /** The block number indexing starts from. */
283
+ readonly startBlock: number;
284
+ /** The block number indexing stops at (if configured). */
285
+ readonly endBlock?: number;
286
+ /** Number of blocks to keep for reorg handling (default: 200). */
287
+ readonly maxReorgDepth?: number;
288
+ };
289
+
290
+ /** Fuel chain value (for runtime Indexer). */
291
+ type FuelChain<
292
+ Id extends number = number,
293
+ ContractName extends string = never
294
+ > = {
295
+ /** The chain ID. */
296
+ readonly id: Id;
297
+ /** The chain name. */
298
+ readonly name: string;
299
+ /** The block number indexing starts from. */
300
+ readonly startBlock: number;
301
+ /** The block number indexing stops at (if configured). */
302
+ readonly endBlock: number | undefined;
303
+ /** Whether the chain has completed initial sync and is processing live events. */
304
+ readonly isLive: boolean;
305
+ } & {
306
+ readonly [K in ContractName]: FuelContract<K>;
307
+ };
308
+
309
+ // ============== SVM (Solana) Types ==============
310
+
311
+ /** SVM chain configuration (for IndexerConfig). */
312
+ type SvmChainConfig<Id extends number = number> = {
313
+ /** The chain ID. */
314
+ readonly id: Id;
315
+ /** The block number indexing starts from. */
316
+ readonly startBlock: number;
317
+ /** The block number indexing stops at (if configured). */
318
+ readonly endBlock?: number;
319
+ /** Number of blocks to keep for reorg handling (default: 200). */
320
+ readonly maxReorgDepth?: number;
321
+ };
322
+
323
+ /** SVM chain value (for runtime Indexer). */
324
+ type SvmChain<Id extends number = number> = {
325
+ /** The chain ID. */
326
+ readonly id: Id;
327
+ /** The chain name. */
328
+ readonly name: string;
329
+ /** The block number indexing starts from. */
330
+ readonly startBlock: number;
331
+ /** The block number indexing stops at (if configured). */
332
+ readonly endBlock: number | undefined;
333
+ /** Whether the chain has completed initial sync and is processing live events. */
334
+ readonly isLive: boolean;
335
+ };
336
+
337
+ // ============== Indexer Type ==============
338
+
339
+ // Helper: Check if ecosystem is configured in a given config
340
+ type HasEvm<Config> = "evm" extends keyof Config ? true : false;
341
+ type HasFuel<Config> = "fuel" extends keyof Config ? true : false;
342
+ type HasSvm<Config> = "svm" extends keyof Config ? true : false;
343
+
344
+ // Count ecosystems using tuple length
345
+ type BoolToNum<B extends boolean> = B extends true ? 1 : 0;
346
+ type EcosystemTuple<Config> = [
347
+ ...([BoolToNum<HasEvm<Config>>] extends [1] ? [1] : []),
348
+ ...([BoolToNum<HasFuel<Config>>] extends [1] ? [1] : []),
349
+ ...([BoolToNum<HasSvm<Config>>] extends [1] ? [1] : [])
350
+ ];
351
+ type EcosystemCount<Config> = EcosystemTuple<Config>["length"];
352
+
353
+ // EVM ecosystem type
354
+ type EvmEcosystem<Config extends IndexerConfig /*= GlobalIndexerConfig*/> =
355
+ "evm" extends keyof Config
356
+ ? Config["evm"] extends {
357
+ chains: infer Chains;
358
+ contracts?: Record<infer ContractName, any>;
359
+ }
360
+ ? Chains extends Record<string, { id: number }>
361
+ ? {
362
+ /** Array of all EVM chain IDs. */
363
+ readonly chainIds: readonly Chains[keyof Chains]["id"][];
364
+ /** Per-chain configuration keyed by chain name or ID. */
365
+ readonly chains: {
366
+ readonly [K in Chains[keyof Chains]["id"]]: EvmChain<
367
+ K,
368
+ ContractName extends string ? ContractName : never
369
+ >;
370
+ } & {
371
+ readonly [K in keyof Chains]: EvmChain<
372
+ Chains[K]["id"],
373
+ ContractName extends string ? ContractName : never
374
+ >;
375
+ };
376
+ }
377
+ : never
378
+ : never
379
+ : never;
380
+
381
+ // Fuel ecosystem type
382
+ type FuelEcosystem<Config extends IndexerConfig /*= GlobalIndexerConfig*/> =
383
+ "fuel" extends keyof Config
384
+ ? Config["fuel"] extends {
385
+ chains: infer Chains;
386
+ contracts?: Record<infer ContractName, any>;
387
+ }
388
+ ? Chains extends Record<string, { id: number }>
389
+ ? {
390
+ /** Array of all Fuel chain IDs. */
391
+ readonly chainIds: readonly Chains[keyof Chains]["id"][];
392
+ /** Per-chain configuration keyed by chain name or ID. */
393
+ readonly chains: {
394
+ readonly [K in Chains[keyof Chains]["id"]]: FuelChain<
395
+ K,
396
+ ContractName extends string ? ContractName : never
397
+ >;
398
+ } & {
399
+ readonly [K in keyof Chains]: FuelChain<
400
+ Chains[K]["id"],
401
+ ContractName extends string ? ContractName : never
402
+ >;
403
+ };
404
+ }
405
+ : never
406
+ : never
407
+ : never;
408
+
409
+ // SVM ecosystem type
410
+ type SvmEcosystem<Config extends IndexerConfig /*= GlobalIndexerConfig*/> =
411
+ "svm" extends keyof Config
412
+ ? Config["svm"] extends { chains: infer Chains }
413
+ ? Chains extends Record<string, { id: number }>
414
+ ? {
415
+ /** Array of all SVM chain IDs. */
416
+ readonly chainIds: readonly Chains[keyof Chains]["id"][];
417
+ /** Per-chain configuration keyed by chain name or ID. */
418
+ readonly chains: {
419
+ readonly [K in Chains[keyof Chains]["id"]]: SvmChain<K>;
420
+ } & {
421
+ readonly [K in keyof Chains]: SvmChain<Chains[K]["id"]>;
422
+ };
423
+ }
424
+ : never
425
+ : never
426
+ : never;
427
+
428
+ // Single ecosystem chains (flattened at root level)
429
+ type SingleEcosystemChains<Config extends IndexerConfig> =
430
+ HasEvm<Config> extends true
431
+ ? EvmEcosystem<Config>
432
+ : HasFuel<Config> extends true
433
+ ? FuelEcosystem<Config>
434
+ : HasSvm<Config> extends true
435
+ ? SvmEcosystem<Config>
436
+ : {};
437
+
438
+ // Multi-ecosystem chains (namespaced by ecosystem)
439
+ type MultiEcosystemChains<Config extends IndexerConfig> =
440
+ (HasEvm<Config> extends true
441
+ ? {
442
+ /** EVM ecosystem configuration. */
443
+ readonly evm: EvmEcosystem<Config>;
444
+ }
445
+ : {}) &
446
+ (HasFuel<Config> extends true
447
+ ? {
448
+ /** Fuel ecosystem configuration. */
449
+ readonly fuel: FuelEcosystem<Config>;
450
+ }
451
+ : {}) &
452
+ (HasSvm<Config> extends true
453
+ ? {
454
+ /** SVM ecosystem configuration. */
455
+ readonly svm: SvmEcosystem<Config>;
456
+ }
457
+ : {});
458
+
459
+ /**
460
+ * Indexer type resolved from config, adapting chain properties based on configured ecosystems.
461
+ * - Single ecosystem: chains are at the root level.
462
+ * - Multiple ecosystems: chains are namespaced by ecosystem (evm, fuel, svm).
463
+ */
464
+ export type IndexerFromConfig<Config extends IndexerConfig> = {
465
+ /** The indexer name from config.yaml. */
466
+ readonly name: Config["name"];
467
+ /** The indexer description from config.yaml. */
468
+ readonly description: string | undefined;
469
+ } & (EcosystemCount<Config> extends 1
470
+ ? SingleEcosystemChains<Config>
471
+ : MultiEcosystemChains<Config>);
package/index.js CHANGED
@@ -13,6 +13,9 @@ export * from "./src/Envio.res.mjs";
13
13
  export const S = {
14
14
  string: Sury.string,
15
15
  address: Sury.string,
16
+ evmChainId: Sury.number,
17
+ fuelChainId: Sury.number,
18
+ svmChainId: Sury.number,
16
19
  jsonString: Sury.jsonString,
17
20
  boolean: Sury.boolean,
18
21
  int32: Sury.int32,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "envio",
3
- "version": "v3.0.0-alpha.4",
3
+ "version": "v3.0.0-alpha.5",
4
4
  "type": "module",
5
5
  "description": "A latency and sync speed optimized, developer friendly blockchain data indexer.",
6
6
  "bin": "./bin.js",
@@ -29,10 +29,10 @@
29
29
  "node": ">=22.0.0"
30
30
  },
31
31
  "optionalDependencies": {
32
- "envio-linux-x64": "v3.0.0-alpha.4",
33
- "envio-linux-arm64": "v3.0.0-alpha.4",
34
- "envio-darwin-x64": "v3.0.0-alpha.4",
35
- "envio-darwin-arm64": "v3.0.0-alpha.4"
32
+ "envio-linux-x64": "v3.0.0-alpha.5",
33
+ "envio-linux-arm64": "v3.0.0-alpha.5",
34
+ "envio-darwin-x64": "v3.0.0-alpha.5",
35
+ "envio-darwin-arm64": "v3.0.0-alpha.5"
36
36
  },
37
37
  "dependencies": {
38
38
  "@clickhouse/client": "1.12.1",
@@ -49,7 +49,14 @@
49
49
  "viem": "2.21.0",
50
50
  "rescript-envsafe": "5.0.0",
51
51
  "dotenv": "16.4.5",
52
- "date-fns": "3.3.1"
52
+ "date-fns": "3.3.1",
53
+ "@rescript/react": "0.14.0",
54
+ "ink": "6.5.1",
55
+ "ink-big-text": "2.0.0",
56
+ "ink-spinner": "5.0.0",
57
+ "express": "4.19.2",
58
+ "yargs": "17.7.2",
59
+ "postgres": "3.4.1"
53
60
  },
54
61
  "files": [
55
62
  "bin.js",
package/rescript.json CHANGED
@@ -19,6 +19,9 @@
19
19
  "generatedFileExtension": ".gen.ts",
20
20
  "moduleResolution": "node16"
21
21
  },
22
- "bs-dependencies": ["rescript-schema", "rescript-envsafe"],
22
+ "jsx": {
23
+ "version": 4
24
+ },
25
+ "bs-dependencies": ["rescript-schema", "@rescript/react", "rescript-envsafe"],
23
26
  "bsc-flags": ["-open RescriptSchema"]
24
27
  }
@@ -82,7 +82,29 @@ let make = (
82
82
  isRegistered
83
83
  }
84
84
 
85
- if shouldBeIncluded {
85
+ // Check if event has Static([]) filters (from eventFilters: false)
86
+ // If so, skip it entirely - it should never be fetched
87
+ let shouldSkip = try {
88
+ let getEventFiltersOrThrow = (
89
+ eventConfig->(Utils.magic: Internal.eventConfig => Internal.evmEventConfig)
90
+ ).getEventFiltersOrThrow
91
+
92
+ // Check for non-evm chains
93
+ if getEventFiltersOrThrow->Utils.magic {
94
+ switch getEventFiltersOrThrow(ChainMap.Chain.makeUnsafe(~chainId=chainConfig.id)) {
95
+ | Static([]) => true
96
+ | _ => false
97
+ }
98
+ } else {
99
+ false
100
+ }
101
+ } catch {
102
+ // Can throw when filter is invalid
103
+ // Don't skip an event in this case. Let it throw in a better place - source code
104
+ | _ => false
105
+ }
106
+
107
+ if shouldBeIncluded && !shouldSkip {
86
108
  eventConfigs->Array.push(eventConfig)
87
109
  }
88
110
  })
@@ -457,3 +479,5 @@ let getLastKnownValidBlock = async (
457
479
  }
458
480
 
459
481
  let isActivelyIndexing = (chainFetcher: t) => chainFetcher.fetchState->FetchState.isActivelyIndexing
482
+
483
+ let isLive = (chainFetcher: t) => chainFetcher.timestampCaughtUpToHeadOrEndblock !== None
@@ -41,7 +41,20 @@ function make(chainConfig, dynamicContracts, startBlock, endBlock, firstEventBlo
41
41
  }
42
42
  shouldBeIncluded = isRegistered;
43
43
  }
44
- if (shouldBeIncluded) {
44
+ var shouldSkip;
45
+ try {
46
+ var getEventFiltersOrThrow = eventConfig.getEventFiltersOrThrow;
47
+ if (getEventFiltersOrThrow) {
48
+ var match = getEventFiltersOrThrow(ChainMap.Chain.makeUnsafe(chainConfig.id));
49
+ shouldSkip = match.TAG === "Static" ? match._0.length === 0 : false;
50
+ } else {
51
+ shouldSkip = false;
52
+ }
53
+ }
54
+ catch (exn){
55
+ shouldSkip = false;
56
+ }
57
+ if (shouldBeIncluded && !shouldSkip) {
45
58
  eventConfigs.push(eventConfig);
46
59
  return ;
47
60
  }
@@ -265,6 +278,10 @@ function isActivelyIndexing(chainFetcher) {
265
278
  return FetchState.isActivelyIndexing(chainFetcher.fetchState);
266
279
  }
267
280
 
281
+ function isLive(chainFetcher) {
282
+ return chainFetcher.timestampCaughtUpToHeadOrEndblock !== undefined;
283
+ }
284
+
268
285
  export {
269
286
  make ,
270
287
  makeFromConfig ,
@@ -277,5 +294,6 @@ export {
277
294
  getHighestBlockBelowThreshold ,
278
295
  getLastKnownValidBlock ,
279
296
  isActivelyIndexing ,
297
+ isLive ,
280
298
  }
281
299
  /* Env Not a pure module */