envio 3.3.2 → 3.5.0-alpha.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 (61) hide show
  1. package/package.json +6 -6
  2. package/src/Api.res +1 -8
  3. package/src/Api.res.mjs +1 -5
  4. package/src/Bin.res +2 -2
  5. package/src/ChainState.res +6 -1
  6. package/src/ChainState.res.mjs +4 -3
  7. package/src/Config.res +38 -5
  8. package/src/Config.res.mjs +35 -6
  9. package/src/Core.res +65 -20
  10. package/src/Core.res.mjs +36 -6
  11. package/src/EnvioGlobal.res +0 -2
  12. package/src/EnvioGlobal.res.mjs +0 -1
  13. package/src/ExitOnCaughtUp.res +6 -2
  14. package/src/ExitOnCaughtUp.res.mjs +4 -0
  15. package/src/FetchState.res +3 -3
  16. package/src/HandlerRegister.res +357 -434
  17. package/src/HandlerRegister.res.mjs +202 -242
  18. package/src/HandlerRegister.resi +7 -15
  19. package/src/IndexerState.res +10 -0
  20. package/src/IndexerState.res.mjs +9 -3
  21. package/src/IndexerState.resi +3 -0
  22. package/src/Internal.res +10 -1
  23. package/src/Main.res.mjs +4 -4
  24. package/src/PgStorage.res +16 -1
  25. package/src/PgStorage.res.mjs +9 -1
  26. package/src/SimulateItems.res +61 -40
  27. package/src/SimulateItems.res.mjs +37 -21
  28. package/src/TestIndexer.res +453 -454
  29. package/src/TestIndexer.res.mjs +321 -344
  30. package/src/bindings/ClickHouse.res +68 -2
  31. package/src/bindings/ClickHouse.res.mjs +47 -2
  32. package/src/sources/EvmChain.res +1 -1
  33. package/src/sources/EvmChain.res.mjs +2 -2
  34. package/src/sources/FuelHyperSync.res +74 -0
  35. package/src/sources/FuelHyperSync.res.mjs +80 -0
  36. package/src/sources/FuelHyperSync.resi +22 -0
  37. package/src/sources/FuelHyperSyncClient.res +120 -0
  38. package/src/sources/FuelHyperSyncClient.res.mjs +71 -0
  39. package/src/sources/FuelHyperSyncSource.res +257 -0
  40. package/src/sources/FuelHyperSyncSource.res.mjs +252 -0
  41. package/src/sources/HyperSyncClient.res +2 -2
  42. package/src/sources/HyperSyncClient.res.mjs +1 -1
  43. package/src/sources/SvmHyperSyncClient.res +139 -102
  44. package/src/sources/SvmHyperSyncClient.res.mjs +45 -5
  45. package/src/sources/SvmHyperSyncSource.res +60 -440
  46. package/src/sources/SvmHyperSyncSource.res.mjs +42 -363
  47. package/src/TestIndexerProxyStorage.res +0 -196
  48. package/src/TestIndexerProxyStorage.res.mjs +0 -121
  49. package/src/TestIndexerWorker.res +0 -4
  50. package/src/TestIndexerWorker.res.mjs +0 -7
  51. package/src/sources/EventRouter.res +0 -165
  52. package/src/sources/EventRouter.res.mjs +0 -153
  53. package/src/sources/HyperFuel.res +0 -179
  54. package/src/sources/HyperFuel.res.mjs +0 -146
  55. package/src/sources/HyperFuel.resi +0 -36
  56. package/src/sources/HyperFuelClient.res +0 -127
  57. package/src/sources/HyperFuelClient.res.mjs +0 -20
  58. package/src/sources/HyperFuelSource.res +0 -502
  59. package/src/sources/HyperFuelSource.res.mjs +0 -481
  60. /package/src/sources/{HyperSyncSource.res → EvmHyperSyncSource.res} +0 -0
  61. /package/src/sources/{HyperSyncSource.res.mjs → EvmHyperSyncSource.res.mjs} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "envio",
3
- "version": "3.3.2",
3
+ "version": "3.5.0-alpha.0",
4
4
  "type": "module",
5
5
  "description": "A latency and sync speed optimized, developer friendly blockchain data indexer.",
6
6
  "bin": "./bin.mjs",
@@ -69,10 +69,10 @@
69
69
  "tsx": "4.21.0"
70
70
  },
71
71
  "optionalDependencies": {
72
- "envio-linux-x64": "3.3.2",
73
- "envio-linux-x64-musl": "3.3.2",
74
- "envio-linux-arm64": "3.3.2",
75
- "envio-darwin-x64": "3.3.2",
76
- "envio-darwin-arm64": "3.3.2"
72
+ "envio-linux-x64": "3.5.0-alpha.0",
73
+ "envio-linux-x64-musl": "3.5.0-alpha.0",
74
+ "envio-linux-arm64": "3.5.0-alpha.0",
75
+ "envio-darwin-x64": "3.5.0-alpha.0",
76
+ "envio-darwin-arm64": "3.5.0-alpha.0"
77
77
  }
78
78
  }
package/src/Api.res CHANGED
@@ -4,12 +4,5 @@
4
4
  let indexer: unknown = Main.getGlobalIndexer()
5
5
 
6
6
  let createTestIndexer: unit => unknown = () => {
7
- let workerPath =
8
- NodeJs.Path.join(
9
- NodeJs.Path.getDirname(NodeJs.ImportMeta.importMeta),
10
- "TestIndexerWorker.res.mjs",
11
- )->NodeJs.Path.toString
12
- TestIndexer.makeCreateTestIndexer(~config=Config.load(), ~workerPath)()->(
13
- Utils.magic: TestIndexer.t<'a> => unknown
14
- )
7
+ TestIndexer.createTestIndexer()->(Utils.magic: TestIndexer.t<'a> => unknown)
15
8
  }
package/src/Api.res.mjs CHANGED
@@ -1,16 +1,12 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
3
  import * as Main from "./Main.res.mjs";
4
- import * as Path from "path";
5
- import * as Config from "./Config.res.mjs";
6
- import * as NodeJs from "./bindings/NodeJs.res.mjs";
7
4
  import * as TestIndexer from "./TestIndexer.res.mjs";
8
5
 
9
6
  let indexer = Main.getGlobalIndexer();
10
7
 
11
8
  function createTestIndexer() {
12
- let workerPath = Path.join(NodeJs.Path.getDirname(import.meta), "TestIndexerWorker.res.mjs");
13
- return TestIndexer.makeCreateTestIndexer(Config.load(), workerPath)();
9
+ return TestIndexer.createTestIndexer();
14
10
  }
15
11
 
16
12
  export {
package/src/Bin.res CHANGED
@@ -52,8 +52,8 @@ let applyEnv = (env: dict<JSON.t>) =>
52
52
  let run = async args => {
53
53
  try {
54
54
  switch (await Core.runCli(args))->Null.toOption {
55
- // Rust-only command (codegen / init / stop / docker / metrics / help /
56
- // version / scripts) — nothing for JS to do, exit cleanly.
55
+ // Rust-only command (codegen / init / serve / stop / docker / metrics /
56
+ // help / version / scripts) — nothing for JS to do, exit cleanly.
57
57
  | None => ()
58
58
  | Some(json) =>
59
59
  switch decodeCommand(json->JSON.parseOrThrow) {
@@ -224,7 +224,12 @@ let makeInternal = (
224
224
  ~lowercaseAddresses,
225
225
  )
226
226
  | Config.FuelSourceConfig({hypersync}) => [
227
- HyperFuelSource.make({chain, endpointUrl: hypersync, apiToken: Env.envioApiToken}),
227
+ FuelHyperSyncSource.make({
228
+ chain,
229
+ endpointUrl: hypersync,
230
+ apiToken: Env.envioApiToken,
231
+ onEventRegistrations,
232
+ }),
228
233
  ]
229
234
  | Config.SvmSourceConfig({hypersync, rpc}) =>
230
235
  switch (hypersync, rpc) {
@@ -17,12 +17,12 @@ import * as SourceManager from "./sources/SourceManager.res.mjs";
17
17
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
18
18
  import * as ReorgDetection from "./ReorgDetection.res.mjs";
19
19
  import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
20
- import * as HyperFuelSource from "./sources/HyperFuelSource.res.mjs";
21
20
  import * as Primitive_float from "@rescript/runtime/lib/es6/Primitive_float.js";
22
21
  import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
23
22
  import * as TransactionStore from "./sources/TransactionStore.res.mjs";
24
23
  import * as IndexingAddresses from "./IndexingAddresses.res.mjs";
25
24
  import * as SvmHyperSyncSource from "./sources/SvmHyperSyncSource.res.mjs";
25
+ import * as FuelHyperSyncSource from "./sources/FuelHyperSyncSource.res.mjs";
26
26
  import * as SafeCheckpointTracking from "./SafeCheckpointTracking.res.mjs";
27
27
 
28
28
  function configAddresses(chainConfig) {
@@ -132,10 +132,11 @@ function makeInternal(chainConfig, indexingAddresses, startBlock, endBlock, firs
132
132
  sources$1 = EvmChain.makeSources(chain, onEventRegistrations, sources.hypersync, evmRpcs, lowercaseAddresses);
133
133
  break;
134
134
  case "FuelSourceConfig" :
135
- sources$1 = [HyperFuelSource.make({
135
+ sources$1 = [FuelHyperSyncSource.make({
136
136
  chain: chain,
137
137
  endpointUrl: sources.hypersync,
138
- apiToken: Env.envioApiToken
138
+ apiToken: Env.envioApiToken,
139
+ onEventRegistrations: onEventRegistrations
139
140
  })];
140
141
  break;
141
142
  case "SvmSourceConfig" :
package/src/Config.res CHANGED
@@ -314,10 +314,27 @@ let propertySchema = S.schema(s =>
314
314
  }
315
315
  )
316
316
 
317
+ let clickhouseTableOptionsSchema: S.t<Internal.clickhouseTableOptions> = S.object(s => {
318
+ Internal.partitionBy: ?s.field("partitionBy", S.option(S.string)),
319
+ orderBy: ?s.field("orderBy", S.option(S.array(S.string))),
320
+ ttl: ?s.field("ttl", S.option(S.string)),
321
+ })
322
+
323
+ // The entity's `clickhouse` storage arg mirrors the @storage directive:
324
+ // either a boolean or a table options object (which implies enabled).
325
+ type entityClickhouseStorageJson =
326
+ | Enabled(bool)
327
+ | TableOptions(Internal.clickhouseTableOptions)
328
+
329
+ let entityClickhouseStorageJsonSchema = S.union([
330
+ S.bool->S.shape(enabled => Enabled(enabled)),
331
+ clickhouseTableOptionsSchema->S.shape(options => TableOptions(options)),
332
+ ])
333
+
317
334
  let entityStorageSchema = S.schema(s =>
318
335
  {
319
336
  "postgres": s.matches(S.option(S.bool)),
320
- "clickhouse": s.matches(S.option(S.bool)),
337
+ "clickhouse": s.matches(S.option(entityClickhouseStorageJsonSchema)),
321
338
  }
322
339
  )
323
340
 
@@ -483,9 +500,21 @@ let parseEntitiesFromJson = (
483
500
  // config didn't enable, and that at least one backend stays true
484
501
  // for an annotated entity — so `getOr(false)` is safe here.
485
502
  let storage: Internal.entityStorage = switch entityJson["storage"] {
486
- | Some(s) => {
487
- postgres: s["postgres"]->Option.getOr(false),
488
- clickhouse: s["clickhouse"]->Option.getOr(false),
503
+ | Some(s) =>
504
+ switch s["clickhouse"] {
505
+ | Some(TableOptions(options)) => {
506
+ postgres: s["postgres"]->Option.getOr(false),
507
+ clickhouse: true,
508
+ clickhouseOptions: options,
509
+ }
510
+ | Some(Enabled(clickhouse)) => {
511
+ postgres: s["postgres"]->Option.getOr(false),
512
+ clickhouse,
513
+ }
514
+ | None => {
515
+ postgres: s["postgres"]->Option.getOr(false),
516
+ clickhouse: false,
517
+ }
489
518
  }
490
519
  | None => {
491
520
  postgres: globalStorage.postgres,
@@ -966,10 +995,14 @@ let fromPublic = (publicConfigJson: JSON.t) => {
966
995
 
967
996
  let allEntities = userEntities->Array.concat([EnvioAddresses.entityConfig])
968
997
 
998
+ // Keyed by the capitalized entity name to match the handler-context
999
+ // accessor (`context.Pool_snapshots`) the generated types expose, while
1000
+ // entityConfig.name stays the original schema name used for the physical
1001
+ // Postgres/ClickHouse tables.
969
1002
  let userEntitiesByName =
970
1003
  userEntities
971
1004
  ->Array.map(entityConfig => {
972
- (entityConfig.name, entityConfig)
1005
+ (entityConfig.name->Utils.String.capitalize, entityConfig)
973
1006
  })
974
1007
  ->Dict.fromArray
975
1008
 
@@ -192,9 +192,26 @@ let propertySchema = S$RescriptSchema.schema(s => ({
192
192
  description: s.m(S$RescriptSchema.option(S$RescriptSchema.string))
193
193
  }));
194
194
 
195
+ let clickhouseTableOptionsSchema = S$RescriptSchema.object(s => ({
196
+ partitionBy: s.f("partitionBy", S$RescriptSchema.option(S$RescriptSchema.string)),
197
+ orderBy: s.f("orderBy", S$RescriptSchema.option(S$RescriptSchema.array(S$RescriptSchema.string))),
198
+ ttl: s.f("ttl", S$RescriptSchema.option(S$RescriptSchema.string))
199
+ }));
200
+
201
+ let entityClickhouseStorageJsonSchema = S$RescriptSchema.union([
202
+ S$RescriptSchema.shape(S$RescriptSchema.bool, enabled => ({
203
+ TAG: "Enabled",
204
+ _0: enabled
205
+ })),
206
+ S$RescriptSchema.shape(clickhouseTableOptionsSchema, options => ({
207
+ TAG: "TableOptions",
208
+ _0: options
209
+ }))
210
+ ]);
211
+
195
212
  let entityStorageSchema = S$RescriptSchema.schema(s => ({
196
213
  postgres: s.m(S$RescriptSchema.option(S$RescriptSchema.bool)),
197
- clickhouse: s.m(S$RescriptSchema.option(S$RescriptSchema.bool))
214
+ clickhouse: s.m(S$RescriptSchema.option(entityClickhouseStorageJsonSchema))
198
215
  }));
199
216
 
200
217
  let entityJsonSchema = S$RescriptSchema.schema(s => ({
@@ -349,10 +366,20 @@ function parseEntitiesFromJson(entitiesJson, enumConfigsByName, globalStorage) {
349
366
  let storage;
350
367
  if (s !== undefined) {
351
368
  let s$1 = Primitive_option.valFromOption(s);
352
- storage = {
353
- postgres: Stdlib_Option.getOr(s$1.postgres, false),
354
- clickhouse: Stdlib_Option.getOr(s$1.clickhouse, false)
355
- };
369
+ let match = s$1.clickhouse;
370
+ storage = match !== undefined ? (
371
+ match.TAG === "Enabled" ? ({
372
+ postgres: Stdlib_Option.getOr(s$1.postgres, false),
373
+ clickhouse: match._0
374
+ }) : ({
375
+ postgres: Stdlib_Option.getOr(s$1.postgres, false),
376
+ clickhouse: true,
377
+ clickhouseOptions: match._0
378
+ })
379
+ ) : ({
380
+ postgres: Stdlib_Option.getOr(s$1.postgres, false),
381
+ clickhouse: false
382
+ });
356
383
  } else {
357
384
  storage = {
358
385
  postgres: globalStorage.postgres,
@@ -677,7 +704,7 @@ function fromPublic(publicConfigJson) {
677
704
  let userEntities = parseEntitiesFromJson(Stdlib_Option.getOr(publicConfig.entities, []), enumConfigsByName, globalStorage);
678
705
  let allEntities = userEntities.concat([entityConfig]);
679
706
  let userEntitiesByName = Object.fromEntries(userEntities.map(entityConfig => [
680
- entityConfig.name,
707
+ Utils.$$String.capitalize(entityConfig.name),
681
708
  entityConfig
682
709
  ]));
683
710
  let contractHandlers = publicContractsConfig !== undefined ? Object.entries(publicContractsConfig).map(param => ({
@@ -1042,6 +1069,8 @@ export {
1042
1069
  compositeIndexFieldSchema,
1043
1070
  derivedFieldSchema,
1044
1071
  propertySchema,
1072
+ clickhouseTableOptionsSchema,
1073
+ entityClickhouseStorageJsonSchema,
1045
1074
  entityStorageSchema,
1046
1075
  entityJsonSchema,
1047
1076
  getFieldTypeAndSchema,
package/src/Core.res CHANGED
@@ -4,32 +4,38 @@
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
- type evmHypersyncClientCtor
7
+ type evmHyperSyncClientCtor
8
8
  type evmRpcClientCtor
9
- type svmHypersyncClientCtor
10
- type hyperfuelClientCtor
9
+ type svmHyperSyncClientCtor
10
+ type fuelHyperSyncClientCtor
11
11
  type transactionStoreCtor
12
12
  type blockStoreCtor
13
- type parseConfigYamlOptions = {
13
+ type fromUserApiOptions = {
14
14
  schema?: string,
15
15
  env?: dict<string>,
16
16
  files?: dict<string>,
17
- isRescript?: bool,
17
+ withIndexerTypes?: bool,
18
+ }
19
+
20
+ type fromUserApiResult = {
21
+ config: string,
22
+ indexerTypes: Null.t<string>,
18
23
  }
19
24
 
20
25
  type addon = {
21
26
  getConfigJson: (~configPath: Null.t<string>, ~directory: Null.t<string>) => string,
22
27
  encodeIndexedTopic: (~abiType: string, ~value: unknown) => EvmTypes.Hex.t,
23
- parseConfigYaml: (string, parseConfigYamlOptions) => string,
28
+ fromUserApi: (string, fromUserApiOptions) => fromUserApiResult,
24
29
  runCli: (~args: array<string>, ~envioPackageDir: Null.t<string>) => promise<Null.t<string>>,
25
- @as("EvmHypersyncClient")
26
- evmHypersyncClient: evmHypersyncClientCtor,
30
+ requestShutdown: unit => unit,
31
+ @as("EvmHyperSyncClient")
32
+ evmHyperSyncClient: evmHyperSyncClientCtor,
27
33
  @as("EvmRpcClient")
28
34
  evmRpcClient: evmRpcClientCtor,
29
- @as("SvmHypersyncClient")
30
- svmHypersyncClient: svmHypersyncClientCtor,
31
- @as("HyperfuelClient")
32
- hyperfuelClient: hyperfuelClientCtor,
35
+ @as("SvmHyperSyncClient")
36
+ svmHyperSyncClient: svmHyperSyncClientCtor,
37
+ @as("FuelHyperSyncClient")
38
+ fuelHyperSyncClient: fuelHyperSyncClientCtor,
33
39
  @as("TransactionStore")
34
40
  transactionStore: transactionStoreCtor,
35
41
  @as("BlockStore")
@@ -207,17 +213,56 @@ let getConfigJson = (~configPath=?, ~directory=?) => {
207
213
 
208
214
  // Pure config entry point: no cwd, config file, schema file, .env, or process env lookup.
209
215
  // A supplied schema is authoritative; omitted or blank schema text means an empty schema.
210
- let parseConfigYaml = (~schema=?, ~env=?, ~files=?, ~isRescript=false, yaml) => {
216
+ // With `withIndexerTypes`, the single parse also returns the generated
217
+ // `.envio/types.d.ts`, so callers can type-check handlers against the config's
218
+ // `indexer` surface without re-parsing.
219
+ let fromUserApi = (~schema=?, ~env=?, ~files=?, ~withIndexerTypes=false, yaml) => {
211
220
  let addon = getAddon()
212
- addon.parseConfigYaml(yaml, {
213
- ?schema,
214
- ?env,
215
- ?files,
216
- isRescript,
217
- })
221
+ addon.fromUserApi(
222
+ yaml,
223
+ {
224
+ ?schema,
225
+ ?env,
226
+ ?files,
227
+ withIndexerTypes,
228
+ },
229
+ )
218
230
  }
219
231
 
232
+ let runWithShutdownSignals = %raw(`function(run, requestShutdown) {
233
+ var onShutdown = function() { requestShutdown(); };
234
+ process.once("SIGINT", onShutdown);
235
+ process.once("SIGTERM", onShutdown);
236
+ return run().finally(function() {
237
+ process.off("SIGINT", onShutdown);
238
+ process.off("SIGTERM", onShutdown);
239
+ });
240
+ }`)
241
+
242
+ // True only when the parsed subcommand is `serve`. The subcommand is the
243
+ // first positional arg; global value-taking flags (`-d`/`--directory`/
244
+ // `--config`) consume the token after them, and other leading flags are
245
+ // skipped — so an unrelated arg value that happens to equal "serve" (e.g.
246
+ // `envio init --name serve`) does not trigger the serve-only shutdown wiring.
247
+ let isServeCommand: array<string> => bool = %raw(`function(args) {
248
+ var valueFlags = { "-d": true, "--directory": true, "--config": true };
249
+ for (var i = 0; i < args.length; i++) {
250
+ var a = args[i];
251
+ if (a[0] === "-") {
252
+ if (a.indexOf("=") === -1 && valueFlags[a]) { i++; }
253
+ continue;
254
+ }
255
+ return a === "serve";
256
+ }
257
+ return false;
258
+ }`)
259
+
220
260
  let runCli = args => {
221
261
  let addon = getAddon()
222
- addon.runCli(~args, ~envioPackageDir=Null.make(envioPackageDir))
262
+ let invoke = () => addon.runCli(~args, ~envioPackageDir=Null.make(envioPackageDir))
263
+ if isServeCommand(args) {
264
+ runWithShutdownSignals(invoke, () => addon.requestShutdown())
265
+ } else {
266
+ invoke()
267
+ }
223
268
  }
package/src/Core.res.mjs CHANGED
@@ -180,20 +180,48 @@ function getConfigJson(configPath, directory) {
180
180
  return addon.getConfigJson(Stdlib_Null.fromOption(configPath), Stdlib_Null.fromOption(directory));
181
181
  }
182
182
 
183
- function parseConfigYaml(schema, env, files, isRescriptOpt, yaml) {
184
- let isRescript = isRescriptOpt !== undefined ? isRescriptOpt : false;
183
+ function fromUserApi(schema, env, files, withIndexerTypesOpt, yaml) {
184
+ let withIndexerTypes = withIndexerTypesOpt !== undefined ? withIndexerTypesOpt : false;
185
185
  let addon = getAddon();
186
- return addon.parseConfigYaml(yaml, {
186
+ return addon.fromUserApi(yaml, {
187
187
  schema: schema,
188
188
  env: env,
189
189
  files: files,
190
- isRescript: isRescript
190
+ withIndexerTypes: withIndexerTypes
191
191
  });
192
192
  }
193
193
 
194
+ let runWithShutdownSignals = (function(run, requestShutdown) {
195
+ var onShutdown = function() { requestShutdown(); };
196
+ process.once("SIGINT", onShutdown);
197
+ process.once("SIGTERM", onShutdown);
198
+ return run().finally(function() {
199
+ process.off("SIGINT", onShutdown);
200
+ process.off("SIGTERM", onShutdown);
201
+ });
202
+ });
203
+
204
+ let isServeCommand = (function(args) {
205
+ var valueFlags = { "-d": true, "--directory": true, "--config": true };
206
+ for (var i = 0; i < args.length; i++) {
207
+ var a = args[i];
208
+ if (a[0] === "-") {
209
+ if (a.indexOf("=") === -1 && valueFlags[a]) { i++; }
210
+ continue;
211
+ }
212
+ return a === "serve";
213
+ }
214
+ return false;
215
+ });
216
+
194
217
  function runCli(args) {
195
218
  let addon = getAddon();
196
- return addon.runCli(args, envioPackageDir);
219
+ let invoke = () => addon.runCli(args, envioPackageDir);
220
+ if (isServeCommand(args)) {
221
+ return runWithShutdownSignals(invoke, () => addon.requestShutdown());
222
+ } else {
223
+ return addon.runCli(args, envioPackageDir);
224
+ }
197
225
  }
198
226
 
199
227
  export {
@@ -207,7 +235,9 @@ export {
207
235
  addonRef,
208
236
  getAddon,
209
237
  getConfigJson,
210
- parseConfigYaml,
238
+ fromUserApi,
239
+ runWithShutdownSignals,
240
+ isServeCommand,
211
241
  runCli,
212
242
  }
213
243
  /* envioPackageDir Not a pure module */
@@ -15,7 +15,6 @@
15
15
  // deduplication hint instead of silently mixing shapes across builds.
16
16
  type t = {
17
17
  version: string,
18
- eventRegistrations: dict<unknown>,
19
18
  mutable activeRegistration: option<unknown>,
20
19
  preRegistered: array<unknown>,
21
20
  rollbackCommitCallbacks: array<unknown>,
@@ -40,7 +39,6 @@ let value: t = {
40
39
  | None =>
41
40
  let fresh = {
42
41
  version,
43
- eventRegistrations: Dict.make(),
44
42
  activeRegistration: None,
45
43
  preRegistered: [],
46
44
  rollbackCommitCallbacks: [],
@@ -12,7 +12,6 @@ let value;
12
12
  if (existing == null) {
13
13
  let fresh = {
14
14
  version: version,
15
- eventRegistrations: {},
16
15
  activeRegistration: undefined,
17
16
  preRegistered: [],
18
17
  rollbackCommitCallbacks: [],
@@ -10,8 +10,12 @@ let run = async (state: IndexerState.t) => {
10
10
  ->IndexerState.simulateDeadInputTracker
11
11
  ->Option.flatMap(SimulateDeadInputTracker.failureMessage) {
12
12
  | None =>
13
- Logging.info("Exiting with success")
14
- NodeJs.process->NodeJs.exitWithCode(Success)
13
+ switch state->IndexerState.onExit {
14
+ | Some(onExit) => onExit()
15
+ | None =>
16
+ Logging.info("Exiting with success")
17
+ NodeJs.process->NodeJs.exitWithCode(Success)
18
+ }
15
19
  | Some(message) => state->IndexerState.errorExit(ErrorHandling.make(Utils.Error.make(message)))
16
20
  }
17
21
  }
@@ -18,6 +18,10 @@ async function run(state) {
18
18
  let message = Stdlib_Option.flatMap(IndexerState.simulateDeadInputTracker(state), SimulateDeadInputTracker.failureMessage);
19
19
  if (message !== undefined) {
20
20
  return IndexerState.errorExit(state, ErrorHandling.make(new Error(message), undefined, undefined));
21
+ }
22
+ let onExit = IndexerState.onExit(state);
23
+ if (onExit !== undefined) {
24
+ return onExit();
21
25
  } else {
22
26
  Logging.info("Exiting with success");
23
27
  Process.exit(0);
@@ -1006,8 +1006,8 @@ OptimizedPartitions.t => {
1006
1006
 
1007
1007
  // Addresses with different start blocks within range share a partition;
1008
1008
  // events before each address's effectiveStartBlock are dropped on the
1009
- // client side (EventRouter for the srcAddress, the event's
1010
- // clientAddressFilter for address-valued params).
1009
+ // client side (the event's clientAddressFilter for address-valued
1010
+ // params).
1011
1011
  if shouldJoinCurrentStartBlock {
1012
1012
  addressesRef :=
1013
1013
  addressesRef.contents->Array.concat(byStartBlock->Dict.getUnsafe(nextStartBlockKey))
@@ -1411,7 +1411,7 @@ let registerDynamicContracts = (
1411
1411
  // Drop events an address-param filter rejects. A merged partition may
1412
1412
  // over-fetch a wildcard event whose indexed address param references an
1413
1413
  // address registered after the log's block; `clientAddressFilter` is the
1414
- // param-level analogue of EventRouter's srcAddress effectiveStartBlock check.
1414
+ // param-level analogue of the srcAddress effectiveStartBlock check.
1415
1415
  let filterByClientAddress = (
1416
1416
  items: array<Internal.item>,
1417
1417
  ~indexingAddresses: IndexingAddresses.t,