envio 3.7.0 → 3.9.0-resolvers.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 (118) hide show
  1. package/README.md +2 -2
  2. package/evm.schema.json +7 -0
  3. package/fuel.schema.json +7 -0
  4. package/index.d.ts +674 -161
  5. package/index.js +10 -0
  6. package/package.json +6 -7
  7. package/src/AddressRows.res +121 -0
  8. package/src/AddressRows.res.mjs +143 -0
  9. package/src/Batch.res +11 -0
  10. package/src/Batch.res.mjs +2 -1
  11. package/src/Bin.res +47 -0
  12. package/src/Bin.res.mjs +34 -1
  13. package/src/ChainState.res +108 -98
  14. package/src/ChainState.res.mjs +86 -67
  15. package/src/ChainState.resi +28 -15
  16. package/src/Config.res +61 -131
  17. package/src/Config.res.mjs +47 -79
  18. package/src/ContractMapping.res +66 -0
  19. package/src/ContractMapping.res.mjs +73 -0
  20. package/src/Core.res +24 -0
  21. package/src/Core.res.mjs +4 -0
  22. package/src/Ecosystem.res +7 -2
  23. package/src/Env.res +128 -1
  24. package/src/Env.res.mjs +123 -1
  25. package/src/Envio.res +54 -76
  26. package/src/EventConfigBuilder.res +316 -46
  27. package/src/EventConfigBuilder.res.mjs +231 -28
  28. package/src/FetchState.res +59 -67
  29. package/src/FetchState.res.mjs +34 -44
  30. package/src/HandlerRegister.res +26 -15
  31. package/src/HandlerRegister.res.mjs +27 -7
  32. package/src/Hasura.res +30 -22
  33. package/src/Hasura.res.mjs +11 -5
  34. package/src/InMemoryStore.res +23 -38
  35. package/src/InMemoryStore.res.mjs +13 -27
  36. package/src/IndexerState.res +40 -3
  37. package/src/IndexerState.res.mjs +30 -4
  38. package/src/IndexerState.resi +4 -1
  39. package/src/Internal.res +49 -30
  40. package/src/Internal.res.mjs +12 -16
  41. package/src/Main.res +27 -20
  42. package/src/Main.res.mjs +19 -14
  43. package/src/Metrics.res +15 -1
  44. package/src/Metrics.res.mjs +5 -1
  45. package/src/Persistence.res +46 -21
  46. package/src/Persistence.res.mjs +8 -5
  47. package/src/PgStorage.res +238 -79
  48. package/src/PgStorage.res.mjs +115 -73
  49. package/src/PruneStaleHistory.res +1 -1
  50. package/src/PruneStaleHistory.res.mjs +1 -1
  51. package/src/Rollback.res +62 -41
  52. package/src/Rollback.res.mjs +61 -19
  53. package/src/RollbackCommit.res +7 -9
  54. package/src/RollbackCommit.res.mjs +5 -6
  55. package/src/SimulateItems.res +254 -9
  56. package/src/SimulateItems.res.mjs +214 -47
  57. package/src/Sink.res +35 -26
  58. package/src/Sink.res.mjs +20 -16
  59. package/src/TestIndexer.res +121 -123
  60. package/src/TestIndexer.res.mjs +97 -102
  61. package/src/Utils.res +38 -0
  62. package/src/Utils.res.mjs +39 -2
  63. package/src/Writing.res +4 -2
  64. package/src/Writing.res.mjs +3 -2
  65. package/src/bindings/ClickHouse.res +311 -656
  66. package/src/bindings/ClickHouse.res.mjs +294 -395
  67. package/src/bindings/ClickHouseSink.res +303 -0
  68. package/src/bindings/ClickHouseSink.res.mjs +216 -0
  69. package/src/bindings/NodeJs.res +9 -0
  70. package/src/bindings/NodeJs.res.mjs +8 -1
  71. package/src/bindings/Postgres.res +9 -0
  72. package/src/bindings/Postgres.res.mjs +3 -0
  73. package/src/db/EntityHistory.res +29 -24
  74. package/src/db/EntityHistory.res.mjs +11 -19
  75. package/src/db/InternalTable.res +258 -83
  76. package/src/db/InternalTable.res.mjs +223 -85
  77. package/src/db/RollbackScope.res +29 -0
  78. package/src/db/RollbackScope.res.mjs +31 -0
  79. package/src/db/Table.res +28 -1
  80. package/src/db/Table.res.mjs +26 -2
  81. package/src/resolvers/ResolverProcess.res +809 -0
  82. package/src/resolvers/ResolverProcess.res.mjs +667 -0
  83. package/src/resolvers/ResolverQuery.res +317 -0
  84. package/src/resolvers/ResolverQuery.res.mjs +220 -0
  85. package/src/resolvers/collisions.js +108 -0
  86. package/src/resolvers/db.js +363 -0
  87. package/src/resolvers/dispatch.js +165 -0
  88. package/src/resolvers/errors.js +30 -0
  89. package/src/resolvers/graphqlSelection.js +292 -0
  90. package/src/resolvers/hasuraAction.js +84 -0
  91. package/src/resolvers/hasuraApply.js +323 -0
  92. package/src/resolvers/hasuraMetadata.js +119 -0
  93. package/src/resolvers/index.js +95 -0
  94. package/src/resolvers/manifest.js +370 -0
  95. package/src/resolvers/server.js +270 -0
  96. package/src/sources/AddressSet.res +0 -22
  97. package/src/sources/AddressStore.res +48 -88
  98. package/src/sources/AddressStore.res.mjs +11 -22
  99. package/src/sources/Evm.res +2 -0
  100. package/src/sources/Evm.res.mjs +2 -0
  101. package/src/sources/EvmHyperSyncSource.res +3 -2
  102. package/src/sources/Fuel.res +2 -0
  103. package/src/sources/Fuel.res.mjs +2 -0
  104. package/src/sources/SimulateSource.res +8 -4
  105. package/src/sources/SimulateSource.res.mjs +7 -3
  106. package/src/sources/Svm.res +36 -7
  107. package/src/sources/Svm.res.mjs +34 -4
  108. package/src/sources/SvmHyperSyncClient.res +20 -116
  109. package/src/sources/SvmHyperSyncClient.res.mjs +5 -7
  110. package/src/sources/SvmHyperSyncSource.res +89 -37
  111. package/src/sources/SvmHyperSyncSource.res.mjs +71 -39
  112. package/src/sources/TransactionStore.res +38 -0
  113. package/src/sources/TransactionStore.res.mjs +5 -0
  114. package/src/tui/Tui.res +1 -1
  115. package/src/tui/Tui.res.mjs +1 -1
  116. package/svm.schema.json +44 -156
  117. package/src/MemoryStorage.res +0 -724
  118. package/src/MemoryStorage.res.mjs +0 -601
@@ -0,0 +1,66 @@
1
+ // The contract name <-> id mapping every stored address row references: a
2
+ // name's position in `names` is the id `envio_contracts` holds and
3
+ // `envio_addresses.contract_id` points at. Ids must mean the same thing on
4
+ // every chain and across restarts, so a mapping is built once — from the whole
5
+ // config, never from a filtered subset — and read everywhere else.
6
+ type t = {
7
+ // Id order. Index i is the name of contract id i.
8
+ names: array<string>,
9
+ idByName: dict<int>,
10
+ }
11
+
12
+ let indexNames = (names: array<string>): t => {
13
+ let idByName = Dict.make()
14
+ names->Array.forEachWithIndex((name, id) => idByName->Dict.set(name, id))
15
+ {names, idByName}
16
+ }
17
+
18
+ // Ids are 0-based positions in a smallint column, so 32768 contracts fit.
19
+ let maxContracts = 32768
20
+
21
+ // Names in any order; the codec puts them in byte order so the ids never depend
22
+ // on the order contracts happen to be declared in.
23
+ let make = (~names: array<string>): t => {
24
+ let canonical = Core.getAddon().canonicalContractNames(names)
25
+ if canonical->Array.length > maxContracts {
26
+ JsError.throwWithMessage(
27
+ `The indexer declares ${canonical
28
+ ->Array.length
29
+ ->Int.toString} contracts, more than the ${maxContracts->Int.toString} a smallint contract id can hold.`,
30
+ )
31
+ }
32
+ indexNames(canonical)
33
+ }
34
+
35
+ // What a storage holds before it has been initialized: no contract has an id
36
+ // yet, so every lookup fails rather than resolving against a stale mapping.
37
+ let empty = indexNames([])
38
+
39
+ // A mapping read back from storage. Taken verbatim: the stored order *is* the
40
+ // id order the stored rows were written against, so re-canonicalizing it would
41
+ // paper over a mapping that no longer matches those rows.
42
+ let fromStoredNames = indexNames
43
+
44
+ let names = (mapping: t) => mapping.names
45
+
46
+ let idOfOrThrow = (mapping: t, name, ~context="") =>
47
+ switch mapping.idByName->Utils.Dict.dangerouslyGetNonOption(name) {
48
+ | Some(id) => id
49
+ | None =>
50
+ JsError.throwWithMessage(
51
+ `Contract "${name}"${context} is missing from the indexer's contract list.`,
52
+ )
53
+ }
54
+
55
+ let nameOfOrThrow = (mapping: t, id) =>
56
+ switch mapping.names->Array.get(id) {
57
+ | Some(name) => name
58
+ | None =>
59
+ JsError.throwWithMessage(
60
+ `Contract id ${id->Int.toString} is outside the indexer's contract list.`,
61
+ )
62
+ }
63
+
64
+ let isEqual = (a: t, b: t) =>
65
+ a.names->Array.length === b.names->Array.length &&
66
+ a.names->Array.everyWithIndex((name, idx) => b.names->Array.getUnsafe(idx) === name)
@@ -0,0 +1,73 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Core from "./Core.res.mjs";
4
+ import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
5
+
6
+ function indexNames(names) {
7
+ let idByName = {};
8
+ names.forEach((name, id) => {
9
+ idByName[name] = id;
10
+ });
11
+ return {
12
+ names: names,
13
+ idByName: idByName
14
+ };
15
+ }
16
+
17
+ function make(names) {
18
+ let canonical = Core.getAddon().canonicalContractNames(names);
19
+ if (canonical.length > 32768) {
20
+ Stdlib_JsError.throwWithMessage(`The indexer declares ` + canonical.length.toString() + ` contracts, more than the ` + (32768).toString() + ` a smallint contract id can hold.`);
21
+ }
22
+ return indexNames(canonical);
23
+ }
24
+
25
+ let empty = indexNames([]);
26
+
27
+ function names(mapping) {
28
+ return mapping.names;
29
+ }
30
+
31
+ function idOfOrThrow(mapping, name, contextOpt) {
32
+ let context = contextOpt !== undefined ? contextOpt : "";
33
+ let id = mapping.idByName[name];
34
+ if (id !== undefined) {
35
+ return id;
36
+ } else {
37
+ return Stdlib_JsError.throwWithMessage(`Contract "` + name + `"` + context + ` is missing from the indexer's contract list.`);
38
+ }
39
+ }
40
+
41
+ function nameOfOrThrow(mapping, id) {
42
+ let name = mapping.names[id];
43
+ if (name !== undefined) {
44
+ return name;
45
+ } else {
46
+ return Stdlib_JsError.throwWithMessage(`Contract id ` + id.toString() + ` is outside the indexer's contract list.`);
47
+ }
48
+ }
49
+
50
+ function isEqual(a, b) {
51
+ if (a.names.length === b.names.length) {
52
+ return a.names.every((name, idx) => b.names[idx] === name);
53
+ } else {
54
+ return false;
55
+ }
56
+ }
57
+
58
+ let maxContracts = 32768;
59
+
60
+ let fromStoredNames = indexNames;
61
+
62
+ export {
63
+ indexNames,
64
+ maxContracts,
65
+ make,
66
+ empty,
67
+ fromStoredNames,
68
+ names,
69
+ idOfOrThrow,
70
+ nameOfOrThrow,
71
+ isEqual,
72
+ }
73
+ /* empty Not a pure module */
package/src/Core.res CHANGED
@@ -10,6 +10,7 @@ type svmHyperSyncClientCtor
10
10
  type fuelHyperSyncClientCtor
11
11
  type transactionStoreCtor
12
12
  type blockStoreCtor
13
+ type clickHouseSinkCtor
13
14
  type addressStoreCtor
14
15
  // Test-only: a local HyperSync server, bound by MockHyperSyncServer in envio-tests.
15
16
  type mockHyperSyncServerCtor
@@ -29,6 +30,7 @@ type fromUserApiResult = {
29
30
  type addon = {
30
31
  getConfigJson: (~configPath: Null.t<string>, ~directory: Null.t<string>) => string,
31
32
  encodeIndexedTopic: (~abiType: string, ~value: unknown) => EvmTypes.Hex.t,
33
+ isSvmPubkey: (~value: string) => bool,
32
34
  fromUserApi: (string, fromUserApiOptions) => fromUserApiResult,
33
35
  runCli: (~args: array<string>, ~envioPackageDir: Null.t<string>) => promise<Null.t<string>>,
34
36
  @as("EvmHyperSyncClient")
@@ -45,8 +47,26 @@ type addon = {
45
47
  blockStore: blockStoreCtor,
46
48
  @as("AddressStore")
47
49
  addressStore: addressStoreCtor,
50
+ @as("ClickHouseSink")
51
+ clickHouseSink: clickHouseSinkCtor,
48
52
  @as("MockHyperSyncServer")
49
53
  mockHyperSyncServer: mockHyperSyncServerCtor,
54
+ encodeAddresses: (~ecosystem: string, ~addresses: array<Address.t>) => array<NodeJs.Buffer.t>,
55
+ renderAddresses: (
56
+ ~ecosystem: string,
57
+ ~shouldChecksum: bool,
58
+ ~bytes: NodeJs.Buffer.t,
59
+ ~lengths: array<int>,
60
+ ) => array<Address.t>,
61
+ renderContractAddresses: (
62
+ ~ecosystem: string,
63
+ ~shouldChecksum: bool,
64
+ ~bytes: NodeJs.Buffer.t,
65
+ ~lengths: array<int>,
66
+ ~contractIds: array<int>,
67
+ ~contractId: int,
68
+ ) => array<Address.t>,
69
+ canonicalContractNames: array<string> => array<string>,
50
70
  // Ordered transaction-field names exposed for the field-code contract test
51
71
  // (the ReScript `transactionFields` arrays must match the Rust ordinals).
52
72
  evmTransactionFieldNames: unit => array<string>,
@@ -84,6 +104,10 @@ let loadDevAddon: ({..}, string) => addon = %raw(`function(req, envioDir) {
84
104
  var path = Nodepath;
85
105
  var fs = Nodefs;
86
106
 
107
+ // Vitest test.env points workers at the addon globalSetup already built.
108
+ var preBuilt = process.env.ENVIO_DEV_ADDON;
109
+ if (preBuilt && fs.existsSync(preBuilt)) return req(preBuilt);
110
+
87
111
  var repoRoot = null;
88
112
  var dir = path.resolve(envioDir);
89
113
  for (var i = 0; i < 10; i++) {
package/src/Core.res.mjs CHANGED
@@ -26,6 +26,10 @@ let loadDevAddon = (function(req, envioDir) {
26
26
  var path = Nodepath;
27
27
  var fs = Nodefs;
28
28
 
29
+ // Vitest test.env points workers at the addon globalSetup already built.
30
+ var preBuilt = process.env.ENVIO_DEV_ADDON;
31
+ if (preBuilt && fs.existsSync(preBuilt)) return req(preBuilt);
32
+
29
33
  var repoRoot = null;
30
34
  var dir = path.resolve(envioDir);
31
35
  for (var i = 0; i < 10; i++) {
package/src/Ecosystem.res CHANGED
@@ -10,6 +10,11 @@ type t = {
10
10
  for SVM. Centralised here so adding a new ecosystem only requires a
11
11
  new ecosystem record, not another switch in `Main.res`. */
12
12
  onBlockMethodName: string,
13
+ /** What the ecosystem calls a contract and one of its events, for
14
+ registration errors that are shared across ecosystems — "contract" /
15
+ "event" on EVM and Fuel, "program" / "instruction" on SVM. */
16
+ contractNoun: string,
17
+ eventNoun: string,
13
18
  /** Schema that unwraps the ecosystem-specific outer wrapper around the
14
19
  user's `where`-returned filter (`block.number` on EVM, `block.height`
15
20
  on Fuel, `slot` on SVM) and surfaces the raw inner `{_gte?, _lte?,
@@ -23,8 +28,8 @@ type t = {
23
28
  `option<unknown>`. Separate from `onBlockFilterSchema` because event
24
29
  block filters support only `_gte` (→ per-event `startBlock`) — `_lte`
25
30
  and `_every` are rejected by the inner `eventBlockRangeSchema` in
26
- `LogSelection.res`. SVM does not support event handlers, so its
27
- schema always surfaces `None`. */
31
+ `LogSelection.res`. SVM parses its own `where` (including the
32
+ `block.slot` chunk), so its schema always surfaces `None`. */
28
33
  onEventBlockFilterSchema: S.t<option<unknown>>,
29
34
  /** Base logger injected at construction. Used to build per-item child
30
35
  loggers (see `getItemLogger`). */
package/src/Env.res CHANGED
@@ -163,6 +163,128 @@ module ClickHouse = {
163
163
  let databaseEngine = () => read("ENVIO_CLICKHOUSE_DATABASE_ENGINE")
164
164
  }
165
165
 
166
+ // The resolver process runs on its own, so its database connection comes from
167
+ // the same ENVIO_PG_* vars the indexer's does -- point them wherever reads
168
+ // should go. Only what genuinely differs from the indexer's shape gets a var
169
+ // of its own.
170
+ //
171
+ // Read at call time rather than module load, for the same reason ClickHouse's
172
+ // are: `envio dev` injects them after this module has been evaluated.
173
+ module Resolvers = {
174
+ %%private(
175
+ let read: string => option<string> = %raw(`(k) => {
176
+ const v = process.env[k];
177
+ return v === undefined || v === "" ? undefined : v;
178
+ }`)
179
+
180
+ // `Int.fromString` is `parseInt`: it takes the leading digits and drops the
181
+ // rest, so "60s" reads as 60 and "1e3" as 1. For a duration that is a
182
+ // thousandfold error in the quiet direction -- "60s" meaning a minute
183
+ // becomes a 60ms loop -- so the parse only accepts what it can write back
184
+ // unchanged.
185
+ let parseWhole = raw => {
186
+ let trimmed = raw->String.trim
187
+ switch trimmed->Int.fromString {
188
+ | Some(value) if trimmed === value->Int.toString => Some(value)
189
+ | _ => None
190
+ }
191
+ }
192
+
193
+ let readInt = (key, ~fallback) =>
194
+ switch read(key) {
195
+ | None => fallback
196
+ | Some(raw) =>
197
+ switch raw->parseWhole {
198
+ | Some(value) if value > 0 => value
199
+ | _ =>
200
+ JsError.throwWithMessage(
201
+ `Invalid ${key} value: "${raw}". Expected a positive whole number.`,
202
+ )
203
+ }
204
+ }
205
+ )
206
+
207
+ let port = () =>
208
+ switch readInt("ENVIO_RESOLVERS_PORT", ~fallback=9900) {
209
+ | value if value <= 65535 => value
210
+ | value =>
211
+ // `readInt` only rejects zero and below, so an out-of-range port reached
212
+ // `listen` and failed there instead, naming neither the variable nor why.
213
+ JsError.throwWithMessage(
214
+ `Invalid ENVIO_RESOLVERS_PORT value: "${value->Int.toString}". A TCP port is 1 to 65535.`,
215
+ )
216
+ }
217
+
218
+ // Sized as concurrent heavy requests x per-request fan-out, not as the
219
+ // indexer's two long-lived connections: one resolver request can hold four
220
+ // at once.
221
+ let poolSize = () => readInt("ENVIO_RESOLVERS_POOL_SIZE", ~fallback=25)
222
+
223
+ let poolWaitTimeoutMs = () => readInt("ENVIO_RESOLVERS_POOL_WAIT_TIMEOUT_MS", ~fallback=10_000)
224
+
225
+ // `envio dev` sets this on the resolver process it spawns: locally the
226
+ // caller is the person who wrote the resolver, so an unexpected error's own
227
+ // message is what they need. Deployed, the caller may be the public internet
228
+ // and the message can carry a connection string.
229
+ let exposeErrors = () =>
230
+ switch read("ENVIO_RESOLVERS_EXPOSE_ERRORS") {
231
+ | None
232
+ | Some("false") => false
233
+ | Some("true") => true
234
+ | Some(other) =>
235
+ // Refused rather than read as false: a typo here silently keeps a
236
+ // resolver's own error messages off the wire, which is the opposite of
237
+ // what the person who set it wanted, and nothing would say so.
238
+ JsError.throwWithMessage(
239
+ `Invalid ENVIO_RESOLVERS_EXPOSE_ERRORS value: "${other}". Expected "true" or "false".`,
240
+ )
241
+ }
242
+
243
+ // The URL *Hasura* posts to, which is not the address this process binds:
244
+ // it is baked into every action, so Hasura has no other way to reach the
245
+ // resolvers.
246
+ let publicUrl = () => read("ENVIO_RESOLVERS_PUBLIC_URL")
247
+
248
+ // How often the metadata is re-asserted. 0 disables it, for a deployment
249
+ // where something else owns Hasura's metadata.
250
+ let metadataIntervalMs = () =>
251
+ switch read("ENVIO_RESOLVERS_METADATA_INTERVAL_MS") {
252
+ | None => 60_000
253
+ | Some(raw) =>
254
+ switch raw->parseWhole {
255
+ | Some(value) if value >= 0 => value
256
+ | _ =>
257
+ JsError.throwWithMessage(
258
+ `Invalid ENVIO_RESOLVERS_METADATA_INTERVAL_MS value: "${raw}". Expected a whole number of milliseconds, or 0 to disable.`,
259
+ )
260
+ }
261
+ }
262
+
263
+ // Required on every request to either route. Unset, the service cannot tell
264
+ // its callers apart from anything else that reaches the socket, and both
265
+ // routes take the role from the request body -- so anyone can claim `admin`.
266
+ let actionSecret = () => read("ENVIO_RESOLVERS_ACTION_SECRET")
267
+
268
+ // Read raw rather than through `Env.Hasura`, whose dev fallbacks would have
269
+ // this process apply metadata to a localhost Hasura nobody asked for. Only
270
+ // an endpoint someone set means "there is a Hasura to register with".
271
+ let hasuraEndpoint = () => read("HASURA_GRAPHQL_ENDPOINT")
272
+ let hasuraAdminSecret = () => read("HASURA_GRAPHQL_ADMIN_SECRET")
273
+
274
+ // Set where a transaction-mode pooler is the only way in. Those reject
275
+ // named prepared statements, so this gives up plan reuse.
276
+ let poolerBacked = () =>
277
+ switch read("ENVIO_RESOLVERS_POOLER_BACKED") {
278
+ | None
279
+ | Some("false") => false
280
+ | Some("true") => true
281
+ | Some(other) =>
282
+ JsError.throwWithMessage(
283
+ `Invalid ENVIO_RESOLVERS_POOLER_BACKED value: "${other}". Expected "true" or "false".`,
284
+ )
285
+ }
286
+ }
287
+
166
288
  module Hasura = {
167
289
  // Disable it on HS indexer run, since we don't have Hasura credentials anyways
168
290
  // Also, it might be useful for some users who don't care about Hasura
@@ -180,7 +302,12 @@ module Hasura = {
180
302
  ~devFallback="http://localhost:8080/v1/metadata",
181
303
  )
182
304
 
183
- let url = graphqlEndpoint->String.slice(~start=0, ~end=-("/v1/metadata"->String.length))
305
+ // Lazy on purpose. `graphqlEndpoint` is required in production, and a missing
306
+ // one arrives here as undefined -- slicing it threw a bare TypeError at import
307
+ // and killed the process before `EnvSafe.close` could say which variable was
308
+ // missing. Only the dev TUI reads this, so there is nothing to compute up
309
+ // front.
310
+ let url = () => graphqlEndpoint->String.slice(~start=0, ~end=-("/v1/metadata"->String.length))
184
311
 
185
312
  let role = envSafe->EnvSafe.get("HASURA_GRAPHQL_ROLE", S.string, ~devFallback="admin")
186
313
 
package/src/Env.res.mjs CHANGED
@@ -3,6 +3,7 @@
3
3
  import * as EnvSafe from "./EnvSafe.res.mjs";
4
4
  import * as Logging from "./Logging.res.mjs";
5
5
  import * as Postgres from "./bindings/Postgres.res.mjs";
6
+ import * as Stdlib_Int from "@rescript/runtime/lib/es6/Stdlib_Int.js";
6
7
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
7
8
  import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
8
9
  import * as HyperSyncClient from "./sources/HyperSyncClient.res.mjs";
@@ -147,6 +148,124 @@ let ClickHouse = {
147
148
  databaseEngine: databaseEngine
148
149
  };
149
150
 
151
+ let read$1 = ((k) => {
152
+ const v = process.env[k];
153
+ return v === undefined || v === "" ? undefined : v;
154
+ });
155
+
156
+ function parseWhole(raw) {
157
+ let trimmed = raw.trim();
158
+ let value = Stdlib_Int.fromString(trimmed, undefined);
159
+ if (value !== undefined && trimmed === value.toString()) {
160
+ return value;
161
+ }
162
+ }
163
+
164
+ function readInt(key, fallback) {
165
+ let raw = read$1(key);
166
+ if (raw === undefined) {
167
+ return fallback;
168
+ }
169
+ let value = parseWhole(raw);
170
+ if (value !== undefined && value > 0) {
171
+ return value;
172
+ }
173
+ return Stdlib_JsError.throwWithMessage(`Invalid ` + key + ` value: "` + raw + `". Expected a positive whole number.`);
174
+ }
175
+
176
+ function port$1() {
177
+ let value = readInt("ENVIO_RESOLVERS_PORT", 9900);
178
+ if (value <= 65535) {
179
+ return value;
180
+ } else {
181
+ return Stdlib_JsError.throwWithMessage(`Invalid ENVIO_RESOLVERS_PORT value: "` + value.toString() + `". A TCP port is 1 to 65535.`);
182
+ }
183
+ }
184
+
185
+ function poolSize() {
186
+ return readInt("ENVIO_RESOLVERS_POOL_SIZE", 25);
187
+ }
188
+
189
+ function poolWaitTimeoutMs() {
190
+ return readInt("ENVIO_RESOLVERS_POOL_WAIT_TIMEOUT_MS", 10000);
191
+ }
192
+
193
+ function exposeErrors() {
194
+ let other = read$1("ENVIO_RESOLVERS_EXPOSE_ERRORS");
195
+ if (other === undefined) {
196
+ return false;
197
+ }
198
+ switch (other) {
199
+ case "false" :
200
+ return false;
201
+ case "true" :
202
+ return true;
203
+ default:
204
+ return Stdlib_JsError.throwWithMessage(`Invalid ENVIO_RESOLVERS_EXPOSE_ERRORS value: "` + other + `". Expected "true" or "false".`);
205
+ }
206
+ }
207
+
208
+ function publicUrl() {
209
+ return read$1("ENVIO_RESOLVERS_PUBLIC_URL");
210
+ }
211
+
212
+ function metadataIntervalMs() {
213
+ let raw = read$1("ENVIO_RESOLVERS_METADATA_INTERVAL_MS");
214
+ if (raw === undefined) {
215
+ return 60000;
216
+ }
217
+ let value = parseWhole(raw);
218
+ if (value !== undefined) {
219
+ if (value >= 0) {
220
+ return value;
221
+ } else {
222
+ return Stdlib_JsError.throwWithMessage(`Invalid ENVIO_RESOLVERS_METADATA_INTERVAL_MS value: "` + raw + `". Expected a whole number of milliseconds, or 0 to disable.`);
223
+ }
224
+ } else {
225
+ return Stdlib_JsError.throwWithMessage(`Invalid ENVIO_RESOLVERS_METADATA_INTERVAL_MS value: "` + raw + `". Expected a whole number of milliseconds, or 0 to disable.`);
226
+ }
227
+ }
228
+
229
+ function actionSecret() {
230
+ return read$1("ENVIO_RESOLVERS_ACTION_SECRET");
231
+ }
232
+
233
+ function hasuraEndpoint() {
234
+ return read$1("HASURA_GRAPHQL_ENDPOINT");
235
+ }
236
+
237
+ function hasuraAdminSecret() {
238
+ return read$1("HASURA_GRAPHQL_ADMIN_SECRET");
239
+ }
240
+
241
+ function poolerBacked() {
242
+ let other = read$1("ENVIO_RESOLVERS_POOLER_BACKED");
243
+ if (other === undefined) {
244
+ return false;
245
+ }
246
+ switch (other) {
247
+ case "false" :
248
+ return false;
249
+ case "true" :
250
+ return true;
251
+ default:
252
+ return Stdlib_JsError.throwWithMessage(`Invalid ENVIO_RESOLVERS_POOLER_BACKED value: "` + other + `". Expected "true" or "false".`);
253
+ }
254
+ }
255
+
256
+ let Resolvers = {
257
+ port: port$1,
258
+ poolSize: poolSize,
259
+ poolWaitTimeoutMs: poolWaitTimeoutMs,
260
+ exposeErrors: exposeErrors,
261
+ publicUrl: publicUrl,
262
+ metadataIntervalMs: metadataIntervalMs,
263
+ actionSecret: actionSecret,
264
+ hasuraEndpoint: hasuraEndpoint,
265
+ hasuraAdminSecret: hasuraAdminSecret,
266
+ poolerBacked: poolerBacked
267
+ };
268
+
150
269
  let enabled = EnvSafe.get(envSafe, "ENVIO_HASURA", S$RescriptSchema.bool, undefined, true, undefined, undefined);
151
270
 
152
271
  let s = EnvSafe.get(envSafe, "ENVIO_HASURA_RESPONSE_LIMIT", S$RescriptSchema.option(S$RescriptSchema.int), undefined, undefined, undefined, undefined);
@@ -155,7 +274,9 @@ let responseLimit = s !== undefined ? s : EnvSafe.get(envSafe, "HASURA_RESPONSE_
155
274
 
156
275
  let graphqlEndpoint = EnvSafe.get(envSafe, "HASURA_GRAPHQL_ENDPOINT", S$RescriptSchema.string, undefined, undefined, "http://localhost:8080/v1/metadata", undefined);
157
276
 
158
- let url = graphqlEndpoint.slice(0, -"/v1/metadata".length | 0);
277
+ function url() {
278
+ return graphqlEndpoint.slice(0, -"/v1/metadata".length | 0);
279
+ }
159
280
 
160
281
  let role = EnvSafe.get(envSafe, "HASURA_GRAPHQL_ROLE", S$RescriptSchema.string, undefined, undefined, "admin", undefined);
161
282
 
@@ -240,6 +361,7 @@ export {
240
361
  logStrategy,
241
362
  Db,
242
363
  ClickHouse,
364
+ Resolvers,
243
365
  Hasura,
244
366
  Configurable,
245
367
  ThrottleWrites,