envio 3.13.0 → 3.14.0-subgraph

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 (111) hide show
  1. package/bin.mjs +10 -1
  2. package/index.d.ts +11 -0
  3. package/package.json +8 -20
  4. package/rescript.json +1 -4
  5. package/src/Config.res +78 -100
  6. package/src/Config.res.mjs +55 -64
  7. package/src/Core.res +67 -6
  8. package/src/Core.res.mjs +58 -4
  9. package/src/EventConfigBuilder.res +4 -10
  10. package/src/EventConfigBuilder.res.mjs +1 -3
  11. package/src/EventProcessing.res +6 -6
  12. package/src/EventProcessing.res.mjs +8 -6
  13. package/src/ExitOnCaughtUp.res +5 -1
  14. package/src/ExitOnCaughtUp.res.mjs +8 -3
  15. package/src/HandlerLoader.res +98 -36
  16. package/src/HandlerLoader.res.mjs +89 -24
  17. package/src/HandlerTypeCheck.mjs +14 -0
  18. package/src/HandlerTypeCheckWorker.mjs +68 -0
  19. package/src/Internal.res +1 -1
  20. package/src/LoadLayer.res +39 -7
  21. package/src/LoadLayer.res.mjs +65 -38
  22. package/src/LoadLayer.resi +28 -0
  23. package/src/Main.res +17 -12
  24. package/src/Main.res.mjs +9 -3
  25. package/src/NodeVersion.mjs +13 -0
  26. package/src/Persistence.res +79 -38
  27. package/src/Persistence.res.mjs +41 -10
  28. package/src/PgStorage.res +86 -39
  29. package/src/PgStorage.res.mjs +83 -32
  30. package/src/ResumePlan.res +172 -0
  31. package/src/ResumePlan.res.mjs +122 -0
  32. package/src/Supervisor.res +8 -8
  33. package/src/Supervisor.res.mjs +6 -1
  34. package/src/SyncWrites.res +86 -0
  35. package/src/SyncWrites.res.mjs +85 -0
  36. package/src/TestIndexer.res +14 -4
  37. package/src/TestIndexer.res.mjs +3 -2
  38. package/src/TsModuleHooks.mjs +121 -0
  39. package/src/UserContext.res +377 -62
  40. package/src/UserContext.res.mjs +297 -39
  41. package/src/Utils.res +0 -8
  42. package/src/Worker.res +8 -0
  43. package/src/Worker.res.mjs +11 -0
  44. package/src/bindings/NodeJs.res +8 -7
  45. package/src/bindings/NodeJs.res.mjs +0 -3
  46. package/src/bindings/Pino.res +2 -2
  47. package/src/db/InternalTable.res +52 -2
  48. package/src/db/InternalTable.res.mjs +32 -3
  49. package/src/db/Table.res +10 -0
  50. package/src/db/Table.res.mjs +22 -11
  51. package/src/sources/FuelHyperSync.res +2 -0
  52. package/src/sources/FuelHyperSync.res.mjs +1 -0
  53. package/src/sources/FuelHyperSync.resi +1 -0
  54. package/src/sources/FuelHyperSyncClient.res +25 -8
  55. package/src/sources/FuelHyperSyncClient.res.mjs +8 -2
  56. package/src/sources/FuelHyperSyncSource.res +24 -22
  57. package/src/sources/FuelHyperSyncSource.res.mjs +18 -13
  58. package/src/subgraph/abi-types.ts +63 -0
  59. package/src/subgraph/assemblyscript.ts +85 -0
  60. package/src/subgraph/blocks.ts +183 -0
  61. package/src/subgraph/calls.ts +149 -0
  62. package/src/subgraph/conformance.ts +83 -0
  63. package/src/subgraph/errors.ts +96 -0
  64. package/src/subgraph/graph-cli-worker.mjs +26 -0
  65. package/src/subgraph/graph-cli.ts +190 -0
  66. package/src/subgraph/graph-ts-enums.ts +28 -0
  67. package/src/subgraph/graph-ts-types/VERSION +2 -0
  68. package/src/subgraph/graph-ts-types/chain/arweave.d.ts +70 -0
  69. package/src/subgraph/graph-ts-types/chain/cosmos.d.ts +327 -0
  70. package/src/subgraph/graph-ts-types/chain/ethereum.d.ts +233 -0
  71. package/src/subgraph/graph-ts-types/chain/near.d.ts +253 -0
  72. package/src/subgraph/graph-ts-types/chain/starknet.d.ts +32 -0
  73. package/src/subgraph/graph-ts-types/common/collections.d.ts +136 -0
  74. package/src/subgraph/graph-ts-types/common/conversion.d.ts +11 -0
  75. package/src/subgraph/graph-ts-types/common/datasource.d.ts +30 -0
  76. package/src/subgraph/graph-ts-types/common/eager-offset.d.ts +0 -0
  77. package/src/subgraph/graph-ts-types/common/json.d.ts +17 -0
  78. package/src/subgraph/graph-ts-types/common/numbers.d.ts +120 -0
  79. package/src/subgraph/graph-ts-types/common/value.d.ts +120 -0
  80. package/src/subgraph/graph-ts-types/common/yaml.d.ts +90 -0
  81. package/src/subgraph/graph-ts-types/global/global.d.ts +194 -0
  82. package/src/subgraph/graph-ts-types/helper-functions.d.ts +22 -0
  83. package/src/subgraph/graph-ts-types/index.d.ts +102 -0
  84. package/src/subgraph/graph-ts.ts +2285 -0
  85. package/src/subgraph/hosts.ts +158 -0
  86. package/src/subgraph/rpc.ts +65 -0
  87. package/src/subgraph/runtime.ts +595 -0
  88. package/src/subgraph/scope.ts +68 -0
  89. package/src/tui/InitApi.res +85 -0
  90. package/src/tui/{components/CustomHooks.res.mjs → InitApi.res.mjs} +11 -64
  91. package/src/tui/Tui.res +142 -249
  92. package/src/tui/Tui.res.mjs +123 -332
  93. package/src/Js.shim.ts +0 -11
  94. package/src/bindings/DateFns.res +0 -74
  95. package/src/bindings/DateFns.res.mjs +0 -22
  96. package/src/sources/FuelSDK.res +0 -38
  97. package/src/sources/FuelSDK.res.mjs +0 -27
  98. package/src/sources/vendored-fuel-abi-coder.js +0 -1792
  99. package/src/tui/bindings/Ink.res +0 -369
  100. package/src/tui/bindings/Ink.res.mjs +0 -66
  101. package/src/tui/bindings/Style.res +0 -123
  102. package/src/tui/bindings/Style.res.mjs +0 -2
  103. package/src/tui/components/BufferedProgressBar.res +0 -40
  104. package/src/tui/components/BufferedProgressBar.res.mjs +0 -57
  105. package/src/tui/components/CustomHooks.res +0 -122
  106. package/src/tui/components/Messages.res +0 -40
  107. package/src/tui/components/Messages.res.mjs +0 -71
  108. package/src/tui/components/SyncETA.res +0 -179
  109. package/src/tui/components/SyncETA.res.mjs +0 -249
  110. package/src/tui/components/TuiData.res +0 -98
  111. package/src/tui/components/TuiData.res.mjs +0 -73
package/bin.mjs CHANGED
@@ -1,3 +1,12 @@
1
1
  #!/usr/bin/env node
2
- import { run } from "./src/Bin.res.mjs";
2
+ import { unsupportedNodeMessage } from "./src/NodeVersion.mjs";
3
+
4
+ // Checked before the rest loads, which an older Node may not even parse.
5
+ const unsupported = unsupportedNodeMessage();
6
+ if (unsupported !== undefined) {
7
+ console.error(unsupported);
8
+ process.exit(1);
9
+ }
10
+
11
+ const { run } = await import("./src/Bin.res.mjs");
3
12
  await run(process.argv.slice(2));
package/index.d.ts CHANGED
@@ -12,6 +12,17 @@ declare const bigintSchema: Sury.Schema<bigint>;
12
12
  /** Ethereum address — a 20-byte hex string prefixed with `0x`. */
13
13
  export type Address = `0x${string}`;
14
14
 
15
+ /** A value a `Json` entity field can hold. A `bigint` isn't JSON — store its
16
+ * decimal string with `.toString()`. Shadows the global `JSON` interface only
17
+ * where imported; the `JSON` object itself is unaffected. */
18
+ export type JSON =
19
+ | string
20
+ | number
21
+ | boolean
22
+ | null
23
+ | readonly JSON[]
24
+ | { readonly [key: string]: JSON };
25
+
15
26
  /** Structured logger bound to an event or handler context. Messages are
16
27
  * displayed in the console and the Envio Hosted Service. */
17
28
  export type Logger = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "envio",
3
- "version": "3.13.0",
3
+ "version": "3.14.0-subgraph",
4
4
  "type": "module",
5
5
  "description": "A latency and sync speed optimized, developer friendly blockchain data indexer.",
6
6
  "bin": "./bin.mjs",
@@ -27,7 +27,7 @@
27
27
  "dapp"
28
28
  ],
29
29
  "engines": {
30
- "node": ">=22.0.0"
30
+ "node": ">=22.15.0"
31
31
  },
32
32
  "files": [
33
33
  "bin.mjs",
@@ -42,11 +42,6 @@
42
42
  ],
43
43
  "dependencies": {
44
44
  "@elastic/ecs-pino-format": "1.4.0",
45
- "@fuel-ts/crypto": "0.96.1",
46
- "@fuel-ts/errors": "0.96.1",
47
- "@fuel-ts/hasher": "0.96.1",
48
- "@fuel-ts/math": "0.96.1",
49
- "@fuel-ts/utils": "0.96.1",
50
45
  "bignumber.js": "9.3.1",
51
46
  "eventsource": "4.1.0",
52
47
  "express": "4.19.2",
@@ -56,20 +51,13 @@
56
51
  "rescript-schema": "9.5.1",
57
52
  "viem": "2.54.0",
58
53
  "dotenv": "16.4.5",
59
- "date-fns": "3.3.1",
60
- "@rescript/react": "0.14.1",
61
- "react": "19.2.5",
62
- "ink": "6.8.0",
63
- "ink-big-text": "2.0.0",
64
- "ink-spinner": "5.0.0",
65
- "postgres": "3.4.8",
66
- "tsx": "4.21.0"
54
+ "postgres": "3.4.8"
67
55
  },
68
56
  "optionalDependencies": {
69
- "envio-linux-x64": "3.13.0",
70
- "envio-linux-x64-musl": "3.13.0",
71
- "envio-linux-arm64": "3.13.0",
72
- "envio-darwin-x64": "3.13.0",
73
- "envio-darwin-arm64": "3.13.0"
57
+ "envio-linux-x64": "3.14.0-subgraph",
58
+ "envio-linux-x64-musl": "3.14.0-subgraph",
59
+ "envio-linux-arm64": "3.14.0-subgraph",
60
+ "envio-darwin-x64": "3.14.0-subgraph",
61
+ "envio-darwin-arm64": "3.14.0-subgraph"
74
62
  }
75
63
  }
package/rescript.json CHANGED
@@ -12,10 +12,7 @@
12
12
  "module": "esmodule",
13
13
  "in-source": true
14
14
  },
15
- "jsx": {
16
- "version": 4
17
- },
18
- "dependencies": ["rescript-schema", "@rescript/react"],
15
+ "dependencies": ["rescript-schema"],
19
16
  "compiler-flags": ["-open RescriptSchema"],
20
17
  "warnings": {
21
18
  "error": "+a"
package/src/Config.res CHANGED
@@ -136,6 +136,9 @@ type t = {
136
136
  reorgThresholdReadyTolerance: int,
137
137
  lowercaseAddresses: bool,
138
138
  isDev: bool,
139
+ // The operator's `-d` / `--config` flags, repeated in every command printed
140
+ // for them to run next. Empty when they gave neither.
141
+ projectFlags: string,
139
142
  // An `envio start --chain` process: drives a subset of the schema's chains
140
143
  // while sibling processes drive the rest, so it only touches what its own
141
144
  // chains own — their partitions' indexes, their `ready_at`, their resume.
@@ -147,6 +150,10 @@ type t = {
147
150
  // the schema alone: a cross-chain entity has rows any chain's reorg can
148
151
  // reach, so its checkpoints have to be comparable across chains.
149
152
  checkpointSequence: CheckpointSequence.t,
153
+ envioInfo: JSON.t,
154
+ // Set only in subgraph mode: the translated manifest, which is what makes
155
+ // the subgraph runtime take over handler registration.
156
+ subgraph: option<JSON.t>,
150
157
  }
151
158
 
152
159
  type rpcSourceFor = | @as("sync") Sync | @as("fallback") Fallback | @as("realtime") Realtime
@@ -595,6 +602,7 @@ let publicConfigSchema = S.schema(s =>
595
602
  "handlers": s.matches(S.option(S.string)),
596
603
  "isDev": s.matches(S.option(S.bool)),
597
604
  "isolatedChains": s.matches(S.option(S.array(ChainId.schema))),
605
+ "projectFlags": s.matches(S.option(S.string)),
598
606
  "fullBatchSize": s.matches(S.option(S.int)),
599
607
  "rollbackOnReorg": s.matches(S.option(S.bool)),
600
608
  "saveFullHistory": s.matches(S.option(S.bool)),
@@ -607,6 +615,7 @@ let publicConfigSchema = S.schema(s =>
607
615
  "svm": s.matches(S.option(publicConfigEcosystemSchema)),
608
616
  "enums": s.matches(S.option(S.dict(S.array(S.string)))),
609
617
  "entities": s.matches(S.option(S.array(entityJsonSchema))),
618
+ "subgraph": s.matches(S.option(S.json(~validate=false))),
610
619
  }
611
620
  )
612
621
 
@@ -666,6 +675,45 @@ let isolate = (config: t, ~chainIds: array<ChainId.t>) => {
666
675
  }
667
676
  }
668
677
 
678
+ // What the command decided rather than the project's files: `envio dev` vs
679
+ // `envio start`, which chains this process drives, and how it found the
680
+ // project.
681
+ let commandFields = ["isDev", "isolatedChains", "projectFlags"]
682
+
683
+ let withProjectFlags = (command, ~config: t) =>
684
+ switch config.projectFlags {
685
+ | "" => command
686
+ | flags => `${command} ${flags}`
687
+ }
688
+
689
+ let ecosystemFields = ["evm", "fuel", "svm"]
690
+
691
+ // What `envio_info` records: the public config without the command's fields
692
+ // or its chains. A chain is recorded by its own `envio_chains` row and its
693
+ // config's `envio_addresses` rows instead, so adding one never rewrites this
694
+ // record. The rest of a chain's config — its sources, its block lag, a
695
+ // contract's start block — is read from config.yaml on every start.
696
+ let toEnvioInfo = (publicConfigJson: JSON.t): JSON.t => {
697
+ let envioInfo = publicConfigJson->JSON.stringify->JSON.parseOrThrow
698
+ switch envioInfo {
699
+ | Object(obj) => {
700
+ commandFields->Array.forEach(field => obj->Utils.Dict.deleteInPlace(field))
701
+ // The subgraph blob is how the runtime finds mappings. None of it
702
+ // describes stored data — that's already in `evm` / `entities` — so a
703
+ // specVersion bump or a mapping-path edit must not force a reset.
704
+ obj->Utils.Dict.deleteInPlace("subgraph")
705
+ ecosystemFields->Array.forEach(ecosystem =>
706
+ switch obj->Dict.get(ecosystem) {
707
+ | Some(Object(ecosystemDict)) => ecosystemDict->Utils.Dict.deleteInPlace("chains")
708
+ | _ => ()
709
+ }
710
+ )
711
+ }
712
+ | _ => ()
713
+ }
714
+ envioInfo
715
+ }
716
+
669
717
  let fromPublic = (publicConfigJson: JSON.t) => {
670
718
  let maxAddrInPartition = Env.maxAddrInPartition
671
719
  // Parse public config
@@ -1136,11 +1184,14 @@ let fromPublic = (publicConfigJson: JSON.t) => {
1136
1184
  reorgThresholdReadyTolerance: 100,
1137
1185
  lowercaseAddresses,
1138
1186
  isDev: publicConfig["isDev"]->Option.getOr(false),
1187
+ projectFlags: publicConfig["projectFlags"]->Option.getOr(""),
1139
1188
  isolated: false,
1140
1189
  userEntitiesByName,
1141
1190
  userEntities,
1142
1191
  allEnums,
1143
1192
  checkpointSequence: CheckpointSequence.fromEntities(userEntities),
1193
+ envioInfo: publicConfigJson->toEnvioInfo,
1194
+ subgraph: publicConfig["subgraph"],
1144
1195
  }
1145
1196
 
1146
1197
  switch publicConfig["isolatedChains"] {
@@ -1255,49 +1306,6 @@ let getPublicConfigJson = () =>
1255
1306
  | None => Core.getConfigJson()->JSON.parseOrThrow
1256
1307
  }
1257
1308
 
1258
- // Drops source URLs from each chain so RPC/hypersync edits don't trigger
1259
- // the resume-time compat check (and don't end up in `envio_info`). Also
1260
- // drops `isDev`, which toggles between `envio dev` and `envio start` and
1261
- // has no bearing on schema/indexing compatibility.
1262
- let stripSensitiveData = (json: JSON.t): JSON.t => {
1263
- let cloned = json->JSON.stringify->JSON.parseOrThrow
1264
- let stripChains = (ecosystem: option<JSON.t>) =>
1265
- switch ecosystem {
1266
- | Some(Object(ecosystemDict)) =>
1267
- switch ecosystemDict->Dict.get("chains") {
1268
- | Some(Object(chains)) =>
1269
- chains
1270
- ->Dict.valuesToArray
1271
- ->Array.forEach(chainJson =>
1272
- switch chainJson {
1273
- | Object(chain) => {
1274
- chain->Utils.Dict.deleteInPlace("rpcs")
1275
- chain->Utils.Dict.deleteInPlace("hypersync")
1276
- }
1277
- | _ => ()
1278
- }
1279
- )
1280
- | _ => ()
1281
- }
1282
- | _ => ()
1283
- }
1284
- switch cloned {
1285
- | Object(obj) => {
1286
- obj->Utils.Dict.deleteInPlace("isDev")
1287
- obj->Utils.Dict.deleteInPlace("isolatedChains")
1288
- stripChains(obj->Dict.get("evm"))
1289
- stripChains(obj->Dict.get("fuel"))
1290
- stripChains(obj->Dict.get("svm"))
1291
- }
1292
- | _ => ()
1293
- }
1294
- cloned
1295
- }
1296
-
1297
- // What the storage layer records as the config this schema was built from,
1298
- // and checks a resuming run against.
1299
- let envioInfo = () => getPublicConfigJson()->stripSensitiveData
1300
-
1301
1309
  // Postgres jsonb doesn't preserve key order, so canonicalize with sorted
1302
1310
  // keys before string-comparing.
1303
1311
  let rec canonicalJson = (json: JSON.t): JSON.t =>
@@ -1317,9 +1325,10 @@ let rec canonicalJson = (json: JSON.t): JSON.t =>
1317
1325
  // Returns dotted leaf paths (`a.b[i].c`) where `stored` differs from
1318
1326
  // `current`, restricted to the highest-priority top-level tier with any
1319
1327
  // diff. Tiers in order: version → name → storage → ecosystem
1320
- // (evm/fuel/svm) → entities → other top-level keys. The first tier
1321
- // containing a diff is the only one rendered; lower tiers are silenced
1322
- // so a single noisy section doesn't bury the actionable change.
1328
+ // (evm/fuel/svm, and the chains a resume puts beside them) → entities →
1329
+ // other top-level keys. The first tier containing a diff is the only one
1330
+ // rendered; lower tiers are silenced so a single noisy section doesn't bury
1331
+ // the actionable change.
1323
1332
  let diffPaths = (~stored: JSON.t, ~current: JSON.t): array<string> => {
1324
1333
  let canonEq = (a: JSON.t, b: JSON.t) =>
1325
1334
  JSON.stringify(canonicalJson(a)) === JSON.stringify(canonicalJson(b))
@@ -1387,7 +1396,7 @@ let diffPaths = (~stored: JSON.t, ~current: JSON.t): array<string> => {
1387
1396
  ["chainIdMode"],
1388
1397
  ["name"],
1389
1398
  ["storage"],
1390
- ["evm", "fuel", "svm"],
1399
+ ["evm", "fuel", "svm", "chains"],
1391
1400
  ["entities"],
1392
1401
  ]
1393
1402
  let firstHit = tiers->Array.reduce(None, (acc, tier) =>
@@ -1417,65 +1426,34 @@ let diffPaths = (~stored: JSON.t, ~current: JSON.t): array<string> => {
1417
1426
  acc
1418
1427
  }
1419
1428
 
1420
- // Throws an `incompatible config` error listing each path in `changedPaths`,
1421
- // plus the remediation options. `~resetCommand` is rendered as-is for
1422
- // option 2 (the wipe-and-redo). `~runCommand` controls option 3 (parallel
1423
- // indexer recipe): when `None`, option 3 is omitted — the migrate flow
1424
- // uses this because running a second indexer doesn't apply.
1425
- // `~hasClickhouse` adds the extra env line so users running both
1426
- // Postgres and Clickhouse get a complete override.
1427
- let throwIfIncompatible = (
1429
+ // The `incompatible config` error listing each path in `changedPaths`, plus
1430
+ // the remediation options. `~resetCommand` is rendered as-is for option 2
1431
+ // (the wipe-and-redo). `~runCommand` controls option 3 (parallel indexer
1432
+ // recipe): when `None`, option 3 is omitted — the migrate flow uses this
1433
+ // because running a second indexer doesn't apply. `~hasClickhouse` adds the
1434
+ // extra env line so users running both Postgres and Clickhouse get a complete
1435
+ // override.
1436
+ let incompatibleMessage = (
1428
1437
  changedPaths: array<string>,
1429
1438
  ~resetCommand: string,
1430
1439
  ~runCommand: option<string>,
1431
1440
  ~hasClickhouse: bool,
1432
1441
  ) => {
1433
- if changedPaths->Array.length > 0 {
1434
- let bullets = changedPaths->Array.map(p => ` - ${p}`)->Array.joinUnsafe("\n")
1435
- let option1 = "Revert the changes above"
1436
- let padTo = (s, col) => s ++ " "->String.repeat(Math.Int.max(col - String.length(s), 1))
1437
- let col = Math.Int.max(String.length(option1), String.length(resetCommand)) + 2
1438
- let option3 = switch runCommand {
1439
- | None => ""
1440
- | Some(cmd) =>
1441
- let clickhouseLine = hasClickhouse ? " ENVIO_CLICKHOUSE_DATABASE=<new_db> \\\n" : ""
1442
- `\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}`
1443
- }
1444
- JsError.throwWithMessage(
1445
- `The following config changes are incompatible with the existing indexer data:\n\n${bullets}\n\nPick one:\n 1. ${option1->padTo(
1446
- col,
1447
- )}# resume indexing where it left off\n 2. ${resetCommand->padTo(
1448
- col,
1449
- )}# delete all indexed data and start over${option3}`,
1450
- )
1451
- }
1452
- }
1453
-
1454
- let throwIfResumeIncompatible = (
1455
- ~storedEnvioInfo: option<JSON.t>,
1456
- ~storedContractMapping: ContractMapping.t,
1457
- ~envioInfo: JSON.t,
1458
- ~contractMapping: ContractMapping.t,
1459
- ~resetCommand: string,
1460
- ~runCommand: option<string>,
1461
- ) => {
1462
- let changedPaths = switch storedEnvioInfo {
1463
- | None => ["storage was initialized by an older envio version"]
1464
- | Some(stored) => diffPaths(~stored, ~current=envioInfo)
1465
- }
1466
- let changedPaths =
1467
- storedContractMapping->ContractMapping.isEqual(contractMapping)
1468
- ? changedPaths
1469
- : changedPaths->Array.concat(["contracts"])
1470
- let hasClickhouse = switch envioInfo {
1471
- | Object(d) =>
1472
- switch d->Dict.get("storage") {
1473
- | Some(Object(s)) => s->Dict.get("clickhouse") == Some(Boolean(true))
1474
- | _ => false
1475
- }
1476
- | _ => false
1442
+ let bullets = changedPaths->Array.map(p => ` - ${p}`)->Array.joinUnsafe("\n")
1443
+ let option1 = "Revert the changes above"
1444
+ let padTo = (s, col) => s ++ " "->String.repeat(Math.Int.max(col - String.length(s), 1))
1445
+ let col = Math.Int.max(String.length(option1), String.length(resetCommand)) + 2
1446
+ let option3 = switch runCommand {
1447
+ | None => ""
1448
+ | Some(cmd) =>
1449
+ let clickhouseLine = hasClickhouse ? " ENVIO_CLICKHOUSE_DATABASE=<new_db> \\\n" : ""
1450
+ `\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}`
1477
1451
  }
1478
- throwIfIncompatible(changedPaths, ~resetCommand, ~runCommand, ~hasClickhouse)
1452
+ `The following config changes are incompatible with the existing indexer data:\n\n${bullets}\n\nPick one:\n 1. ${option1->padTo(
1453
+ col,
1454
+ )}# resume indexing where it left off\n 2. ${resetCommand->padTo(
1455
+ col,
1456
+ )}# delete all indexed data and start over${option3}`
1479
1457
  }
1480
1458
 
1481
1459
  // The returned value is a pure function of the JSON: it holds only event
@@ -18,7 +18,6 @@ import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
18
18
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
19
19
  import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
20
20
  import * as ContractMapping from "./ContractMapping.res.mjs";
21
- import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
22
21
  import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
23
22
  import * as Primitive_string from "@rescript/runtime/lib/es6/Primitive_string.js";
24
23
  import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
@@ -439,6 +438,7 @@ let publicConfigSchema = S$RescriptSchema.schema(s => ({
439
438
  handlers: s.m(S$RescriptSchema.option(S$RescriptSchema.string)),
440
439
  isDev: s.m(S$RescriptSchema.option(S$RescriptSchema.bool)),
441
440
  isolatedChains: s.m(S$RescriptSchema.option(S$RescriptSchema.array(ChainId.schema))),
441
+ projectFlags: s.m(S$RescriptSchema.option(S$RescriptSchema.string)),
442
442
  fullBatchSize: s.m(S$RescriptSchema.option(S$RescriptSchema.int)),
443
443
  rollbackOnReorg: s.m(S$RescriptSchema.option(S$RescriptSchema.bool)),
444
444
  saveFullHistory: s.m(S$RescriptSchema.option(S$RescriptSchema.bool)),
@@ -450,7 +450,8 @@ let publicConfigSchema = S$RescriptSchema.schema(s => ({
450
450
  fuel: s.m(S$RescriptSchema.option(publicConfigEcosystemSchema)),
451
451
  svm: s.m(S$RescriptSchema.option(publicConfigEcosystemSchema)),
452
452
  enums: s.m(S$RescriptSchema.option(S$RescriptSchema.dict(S$RescriptSchema.array(S$RescriptSchema.string)))),
453
- entities: s.m(S$RescriptSchema.option(S$RescriptSchema.array(entityJsonSchema)))
453
+ entities: s.m(S$RescriptSchema.option(S$RescriptSchema.array(entityJsonSchema))),
454
+ subgraph: s.m(S$RescriptSchema.option(S$RescriptSchema.json(false)))
454
455
  }));
455
456
 
456
457
  function contractMappingOf(chainConfigs) {
@@ -495,6 +496,42 @@ function isolate(config, chainIds) {
495
496
  return newrecord;
496
497
  }
497
498
 
499
+ let commandFields = [
500
+ "isDev",
501
+ "isolatedChains",
502
+ "projectFlags"
503
+ ];
504
+
505
+ function withProjectFlags(command, config) {
506
+ let flags = config.projectFlags;
507
+ if (flags === "") {
508
+ return command;
509
+ } else {
510
+ return command + ` ` + flags;
511
+ }
512
+ }
513
+
514
+ let ecosystemFields = [
515
+ "evm",
516
+ "fuel",
517
+ "svm"
518
+ ];
519
+
520
+ function toEnvioInfo(publicConfigJson) {
521
+ let envioInfo = JSON.parse(JSON.stringify(publicConfigJson));
522
+ if (typeof envioInfo === "object" && envioInfo !== null && !Array.isArray(envioInfo)) {
523
+ commandFields.forEach(field => Utils.Dict.deleteInPlace(envioInfo, field));
524
+ Utils.Dict.deleteInPlace(envioInfo, "subgraph");
525
+ ecosystemFields.forEach(ecosystem => {
526
+ let match = envioInfo[ecosystem];
527
+ if (typeof match === "object" && match !== null && !Array.isArray(match)) {
528
+ return Utils.Dict.deleteInPlace(match, "chains");
529
+ }
530
+ });
531
+ }
532
+ return envioInfo;
533
+ }
534
+
498
535
  function fromPublic(publicConfigJson) {
499
536
  let publicConfig;
500
537
  try {
@@ -801,7 +838,10 @@ function fromPublic(publicConfigJson) {
801
838
  let config_enableRawEvents = Stdlib_Option.getOr(publicConfig.rawEvents, false);
802
839
  let config_batchSize = Stdlib_Option.getOr(publicConfig.fullBatchSize, 5000);
803
840
  let config_isDev = Stdlib_Option.getOr(publicConfig.isDev, false);
841
+ let config_projectFlags = Stdlib_Option.getOr(publicConfig.projectFlags, "");
804
842
  let config_checkpointSequence = CheckpointSequence.fromEntities(userEntities);
843
+ let config_envioInfo = toEnvioInfo(publicConfigJson);
844
+ let config_subgraph = publicConfig.subgraph;
805
845
  let config = {
806
846
  name: config_name,
807
847
  description: config_description,
@@ -823,11 +863,14 @@ function fromPublic(publicConfigJson) {
823
863
  reorgThresholdReadyTolerance: 100,
824
864
  lowercaseAddresses: lowercaseAddresses,
825
865
  isDev: config_isDev,
866
+ projectFlags: config_projectFlags,
826
867
  isolated: false,
827
868
  userEntitiesByName: userEntitiesByName,
828
869
  userEntities: userEntities,
829
870
  allEnums: allEnums,
830
- checkpointSequence: config_checkpointSequence
871
+ checkpointSequence: config_checkpointSequence,
872
+ envioInfo: config_envioInfo,
873
+ subgraph: config_subgraph
831
874
  };
832
875
  let chainIds = publicConfig.isolatedChains;
833
876
  if (chainIds !== undefined) {
@@ -933,44 +976,6 @@ function getPublicConfigJson() {
933
976
  }
934
977
  }
935
978
 
936
- function stripSensitiveData(json) {
937
- let cloned = JSON.parse(JSON.stringify(json));
938
- let stripChains = ecosystem => {
939
- if (ecosystem === undefined) {
940
- return;
941
- }
942
- if (typeof ecosystem !== "object" || ecosystem === null || Array.isArray(ecosystem)) {
943
- return;
944
- }
945
- let match = ecosystem["chains"];
946
- if (match === undefined) {
947
- return;
948
- }
949
- if (typeof match !== "object" || match === null || Array.isArray(match)) {
950
- return;
951
- }
952
- Object.values(match).forEach(chainJson => {
953
- if (typeof chainJson !== "object" || chainJson === null || Array.isArray(chainJson)) {
954
- return;
955
- }
956
- Utils.Dict.deleteInPlace(chainJson, "rpcs");
957
- Utils.Dict.deleteInPlace(chainJson, "hypersync");
958
- });
959
- };
960
- if (typeof cloned === "object" && cloned !== null && !Array.isArray(cloned)) {
961
- Utils.Dict.deleteInPlace(cloned, "isDev");
962
- Utils.Dict.deleteInPlace(cloned, "isolatedChains");
963
- stripChains(cloned["evm"]);
964
- stripChains(cloned["fuel"]);
965
- stripChains(cloned["svm"]);
966
- }
967
- return cloned;
968
- }
969
-
970
- function envioInfo() {
971
- return stripSensitiveData(getPublicConfigJson());
972
- }
973
-
974
979
  function canonicalJson(json) {
975
980
  if (Array.isArray(json)) {
976
981
  return json.map(canonicalJson);
@@ -1088,7 +1093,8 @@ function diffPaths(stored, current) {
1088
1093
  [
1089
1094
  "evm",
1090
1095
  "fuel",
1091
- "svm"
1096
+ "svm",
1097
+ "chains"
1092
1098
  ],
1093
1099
  ["entities"]
1094
1100
  ];
@@ -1113,10 +1119,7 @@ function diffPaths(stored, current) {
1113
1119
  return acc;
1114
1120
  }
1115
1121
 
1116
- function throwIfIncompatible(changedPaths, resetCommand, runCommand, hasClickhouse) {
1117
- if (changedPaths.length === 0) {
1118
- return;
1119
- }
1122
+ function incompatibleMessage(changedPaths, resetCommand, runCommand, hasClickhouse) {
1120
1123
  let bullets = changedPaths.map(p => ` - ` + p).join("\n");
1121
1124
  let option1 = "Revert the changes above";
1122
1125
  let padTo = (s, col) => s + " ".repeat(Math.max(col - s.length | 0, 1));
@@ -1128,20 +1131,7 @@ function throwIfIncompatible(changedPaths, resetCommand, runCommand, hasClickhou
1128
1131
  } else {
1129
1132
  option3 = "";
1130
1133
  }
1131
- 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);
1132
- }
1133
-
1134
- function throwIfResumeIncompatible(storedEnvioInfo, storedContractMapping, envioInfo, contractMapping, resetCommand, runCommand) {
1135
- let changedPaths = storedEnvioInfo !== undefined ? diffPaths(storedEnvioInfo, envioInfo) : ["storage was initialized by an older envio version"];
1136
- let changedPaths$1 = ContractMapping.isEqual(storedContractMapping, contractMapping) ? changedPaths : changedPaths.concat(["contracts"]);
1137
- let hasClickhouse;
1138
- if (typeof envioInfo === "object" && envioInfo !== null && !Array.isArray(envioInfo)) {
1139
- let match = envioInfo["storage"];
1140
- hasClickhouse = typeof match === "object" && match !== null && !Array.isArray(match) ? Primitive_object.equal(match["clickhouse"], true) : false;
1141
- } else {
1142
- hasClickhouse = false;
1143
- }
1144
- throwIfIncompatible(changedPaths$1, resetCommand, runCommand, hasClickhouse);
1134
+ return `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;
1145
1135
  }
1146
1136
 
1147
1137
  function load() {
@@ -1195,6 +1185,10 @@ export {
1195
1185
  getChain,
1196
1186
  isPerChain,
1197
1187
  isolate,
1188
+ commandFields,
1189
+ withProjectFlags,
1190
+ ecosystemFields,
1191
+ toEnvioInfo,
1198
1192
  fromPublic,
1199
1193
  normalizeUserAddress,
1200
1194
  normalizeSimulateAddress,
@@ -1202,12 +1196,9 @@ export {
1202
1196
  prime,
1203
1197
  withCommandFields,
1204
1198
  getPublicConfigJson,
1205
- stripSensitiveData,
1206
- envioInfo,
1207
1199
  canonicalJson,
1208
1200
  diffPaths,
1209
- throwIfIncompatible,
1210
- throwIfResumeIncompatible,
1201
+ incompatibleMessage,
1211
1202
  load,
1212
1203
  getPgUserEntities,
1213
1204
  }