envio 3.5.0 → 3.5.1-svm-alpha.2

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 (59) hide show
  1. package/evm.schema.json +7 -0
  2. package/fuel.schema.json +7 -0
  3. package/index.d.ts +33 -10
  4. package/package.json +6 -6
  5. package/src/ChainFetching.res +11 -21
  6. package/src/ChainFetching.res.mjs +12 -20
  7. package/src/ChainState.res +41 -4
  8. package/src/ChainState.res.mjs +39 -5
  9. package/src/ChainState.resi +10 -1
  10. package/src/Config.res +62 -3
  11. package/src/Config.res.mjs +49 -13
  12. package/src/EffectState.res +2 -2
  13. package/src/EffectState.res.mjs +2 -2
  14. package/src/EntityTables.res +32 -0
  15. package/src/EntityTables.res.mjs +44 -0
  16. package/src/Envio.res +7 -7
  17. package/src/Envio.res.mjs +5 -6
  18. package/src/FetchState.res +38 -75
  19. package/src/FetchState.res.mjs +20 -62
  20. package/src/Hasura.res +37 -3
  21. package/src/Hasura.res.mjs +23 -5
  22. package/src/InMemoryStore.res +95 -43
  23. package/src/InMemoryStore.res.mjs +69 -38
  24. package/src/IndexerState.res +30 -24
  25. package/src/IndexerState.res.mjs +20 -35
  26. package/src/IndexerState.resi +8 -6
  27. package/src/Internal.res +29 -18
  28. package/src/Internal.res.mjs +27 -10
  29. package/src/LoadLayer.res +39 -8
  30. package/src/LoadLayer.res.mjs +36 -9
  31. package/src/LoadLayer.resi +2 -0
  32. package/src/Persistence.res +12 -1
  33. package/src/PgStorage.res +183 -37
  34. package/src/PgStorage.res.mjs +149 -34
  35. package/src/PruneStaleHistory.res +1 -0
  36. package/src/PruneStaleHistory.res.mjs +2 -1
  37. package/src/Sink.res +3 -3
  38. package/src/Sink.res.mjs +2 -2
  39. package/src/TestIndexer.res +128 -17
  40. package/src/TestIndexer.res.mjs +75 -9
  41. package/src/UserContext.res +19 -4
  42. package/src/UserContext.res.mjs +15 -9
  43. package/src/Writing.res +8 -16
  44. package/src/Writing.res.mjs +10 -10
  45. package/src/bindings/ClickHouse.res +40 -4
  46. package/src/bindings/ClickHouse.res.mjs +37 -5
  47. package/src/bindings/Vitest.res +0 -3
  48. package/src/bindings/Vitest.res.mjs +2 -12
  49. package/src/db/EntityHistory.res +64 -21
  50. package/src/db/EntityHistory.res.mjs +43 -22
  51. package/src/db/InternalTable.res.mjs +31 -31
  52. package/src/db/Table.res +24 -1
  53. package/src/db/Table.res.mjs +26 -4
  54. package/src/sources/AddressStore.res +77 -26
  55. package/src/sources/AddressStore.res.mjs +21 -10
  56. package/src/sources/SvmHyperSyncClient.res +8 -7
  57. package/src/sources/SvmHyperSyncSource.res +38 -1
  58. package/src/sources/SvmHyperSyncSource.res.mjs +24 -0
  59. package/svm.schema.json +17 -4
package/src/Config.res CHANGED
@@ -59,11 +59,26 @@ type sourceSync = {
59
59
  pollingInterval: int,
60
60
  }
61
61
 
62
+ // How a backend spells column names, mirroring `column_name_format` in
63
+ // config.yaml. Only the internal columns the runtime appends need it — user
64
+ // field names arrive pre-resolved from the CLI.
65
+ type columnNameFormat = | @as("original") Original | @as("snake_case") SnakeCase
66
+
62
67
  type storage = {
63
68
  postgres: bool,
64
69
  clickhouse: bool,
70
+ postgresColumnNameFormat: columnNameFormat,
71
+ clickhouseColumnNameFormat: columnNameFormat,
65
72
  }
66
73
 
74
+ let chainIdFieldName = "chainId"
75
+
76
+ let chainIdColumnName = format =>
77
+ switch format {
78
+ | Original => chainIdFieldName
79
+ | SnakeCase => "chain_id"
80
+ }
81
+
67
82
  type contractHandler = {
68
83
  name: string,
69
84
  handler: option<string>,
@@ -76,6 +91,10 @@ type t = {
76
91
  contractHandlers: array<contractHandler>,
77
92
  shouldRollbackOnReorg: bool,
78
93
  shouldSaveFullHistory: bool,
94
+ // False when `disable_default_cross_chain: true` in config.yaml. Entities
95
+ // carry their own resolved `crossChain`; this only decides the default for
96
+ // effects that don't state one.
97
+ defaultCrossChain: bool,
79
98
  storage: storage,
80
99
  // Widest scalar the internal chain-id columns need, resolved by the CLI from
81
100
  // the maximum active chain id. Older configs predate the field, and every id
@@ -114,7 +133,8 @@ module EnvioAddresses = {
114
133
  id: string,
115
134
  @as("chain_id") chainId: ChainId.t,
116
135
  @as("registration_block") registrationBlock: int,
117
- // -1 when the address was registered from a block handler (no log index)
136
+ // Vestigial: always written as -1 and never read back. The column stays so
137
+ // an existing schema doesn't need a migration.
118
138
  @as("registration_log_index") registrationLogIndex: int,
119
139
  @as("contract_name") contractName: string,
120
140
  }
@@ -160,6 +180,9 @@ module EnvioAddresses = {
160
180
  // always required to have Postgres enabled (Storage::resolve forbids
161
181
  // a Postgres-disabled global), so this is safe regardless of mode.
162
182
  storage: {postgres: true, clickhouse: false},
183
+ // The table already keys rows by chain through the composite `id`, so the
184
+ // per-chain mode must not append a second chain-id column to it.
185
+ crossChain: true,
163
186
  }->Internal.fromGenericEntityConfig
164
187
  }
165
188
 
@@ -352,6 +375,7 @@ let entityStorageSchema = S.schema(s =>
352
375
  let entityJsonSchema = S.schema(s =>
353
376
  {
354
377
  "name": s.matches(S.string),
378
+ "crossChain": s.matches(S.option(S.bool)),
355
379
  "storage": s.matches(S.option(entityStorageSchema)),
356
380
  "properties": s.matches(S.array(propertySchema)),
357
381
  "derivedFields": s.matches(S.option(S.array(derivedFieldSchema))),
@@ -423,13 +447,30 @@ let parseEnumsFromJson = (enumsJson: dict<array<string>>): array<Table.enumConfi
423
447
  )
424
448
  }
425
449
 
450
+ // The chain-id column appended to a per-chain entity's table. It completes the
451
+ // primary key so the same id can exist independently on every chain, and it's
452
+ // spelled per backend because the two can be configured with different
453
+ // `column_name_format`s.
454
+ let makeChainIdField = (~globalStorage: storage) =>
455
+ Table.mkField(
456
+ chainIdFieldName,
457
+ ChainId,
458
+ ~fieldSchema=ChainId.schema,
459
+ ~isPrimaryKey=true,
460
+ ~isChainId=true,
461
+ ~postgresDbName=globalStorage.postgresColumnNameFormat->chainIdColumnName,
462
+ ~clickhouseDbName=globalStorage.clickhouseColumnNameFormat->chainIdColumnName,
463
+ )
464
+
426
465
  let parseEntitiesFromJson = (
427
466
  entitiesJson: array<'entityJson>,
428
467
  ~enumConfigsByName: dict<Table.enumConfig<Table.enum>>,
429
468
  ~globalStorage: storage,
469
+ ~defaultCrossChain: bool,
430
470
  ): array<Internal.entityConfig> => {
431
471
  entitiesJson->Array.mapWithIndex((entityJson, index) => {
432
472
  let entityName = entityJson["name"]
473
+ let crossChain = entityJson["crossChain"]->Option.getOr(defaultCrossChain)
433
474
 
434
475
  let fields: array<Table.fieldOrDerived> = entityJson["properties"]->Array.map(prop => {
435
476
  let (fieldType, fieldSchema, isNullable, isArray, isIndex) = getFieldTypeAndSchema(
@@ -477,7 +518,10 @@ let parseEntitiesFromJson = (
477
518
 
478
519
  let table = Table.mkTable(
479
520
  entityName,
480
- ~fields=Array.concat(fields, derivedFields),
521
+ ~fields=Array.concatMany(
522
+ fields,
523
+ [crossChain ? [] : [makeChainIdField(~globalStorage)], derivedFields],
524
+ ),
481
525
  ~compositeIndexes,
482
526
  ~description=?entityJson["description"],
483
527
  )
@@ -535,14 +579,19 @@ let parseEntitiesFromJson = (
535
579
  schema: schema->(Utils.magic: S.t<dict<unknown>> => S.t<Internal.entity>),
536
580
  table,
537
581
  storage,
582
+ crossChain,
538
583
  }->Internal.fromGenericEntityConfig
539
584
  })
540
585
  }
541
586
 
587
+ let columnNameFormatSchema = S.enum([Original, SnakeCase])
588
+
542
589
  let publicConfigStorageSchema = S.schema(s =>
543
590
  {
544
591
  "postgres": s.matches(S.bool),
545
592
  "clickhouse": s.matches(S.option(S.bool)),
593
+ "postgresColumnNameFormat": s.matches(S.option(columnNameFormatSchema)),
594
+ "clickhouseColumnNameFormat": s.matches(S.option(columnNameFormatSchema)),
546
595
  }
547
596
  )
548
597
 
@@ -557,6 +606,7 @@ let publicConfigSchema = S.schema(s =>
557
606
  "saveFullHistory": s.matches(S.option(S.bool)),
558
607
  "rawEvents": s.matches(S.option(S.bool)),
559
608
  "chainIdMode": s.matches(S.option(ChainId.modeSchema)),
609
+ "defaultCrossChain": s.matches(S.option(S.bool)),
560
610
  "storage": s.matches(publicConfigStorageSchema),
561
611
  "evm": s.matches(S.option(publicConfigEvmSchema)),
562
612
  "fuel": s.matches(S.option(publicConfigEcosystemSchema)),
@@ -994,12 +1044,20 @@ let fromPublic = (publicConfigJson: JSON.t) => {
994
1044
  let globalStorage: storage = {
995
1045
  postgres: publicConfig["storage"]["postgres"],
996
1046
  clickhouse: publicConfig["storage"]["clickhouse"]->Option.getOr(false),
1047
+ postgresColumnNameFormat: publicConfig["storage"]["postgresColumnNameFormat"]->Option.getOr(
1048
+ Original,
1049
+ ),
1050
+ clickhouseColumnNameFormat: publicConfig["storage"]["clickhouseColumnNameFormat"]->Option.getOr(
1051
+ Original,
1052
+ ),
997
1053
  }
998
1054
 
1055
+ let defaultCrossChain = publicConfig["defaultCrossChain"]->Option.getOr(true)
1056
+
999
1057
  let userEntities =
1000
1058
  publicConfig["entities"]
1001
1059
  ->Option.getOr([])
1002
- ->parseEntitiesFromJson(~enumConfigsByName, ~globalStorage)
1060
+ ->parseEntitiesFromJson(~enumConfigsByName, ~globalStorage, ~defaultCrossChain)
1003
1061
 
1004
1062
  let allEntities = userEntities->Array.concat([EnvioAddresses.entityConfig])
1005
1063
 
@@ -1035,6 +1093,7 @@ let fromPublic = (publicConfigJson: JSON.t) => {
1035
1093
  contractHandlers,
1036
1094
  shouldRollbackOnReorg: publicConfig["rollbackOnReorg"]->Option.getOr(true),
1037
1095
  shouldSaveFullHistory: publicConfig["saveFullHistory"]->Option.getOr(false),
1096
+ defaultCrossChain,
1038
1097
  storage: globalStorage,
1039
1098
  chainIdMode: publicConfig["chainIdMode"]->Option.getOr(Int32),
1040
1099
  chainMap,
@@ -22,6 +22,16 @@ import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
22
22
  import * as EventConfigBuilder from "./EventConfigBuilder.res.mjs";
23
23
  import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
24
24
 
25
+ let chainIdFieldName = "chainId";
26
+
27
+ function chainIdColumnName(format) {
28
+ if (format === "original") {
29
+ return chainIdFieldName;
30
+ } else {
31
+ return "chain_id";
32
+ }
33
+ }
34
+
25
35
  let name = "envio_addresses";
26
36
 
27
37
  function makeId(chainId, address) {
@@ -42,11 +52,11 @@ let schema = S$RescriptSchema.schema(s => ({
42
52
  }));
43
53
 
44
54
  let table = Table.mkTable(name, undefined, [
45
- Table.mkField("id", "String", S$RescriptSchema.string, undefined, undefined, undefined, true, undefined, undefined, undefined, undefined, undefined),
46
- Table.mkField("chain_id", "ChainId", ChainId.schema, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined),
47
- Table.mkField("registration_block", "Int32", S$RescriptSchema.int, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined),
48
- Table.mkField("registration_log_index", "Int32", S$RescriptSchema.int, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined),
49
- Table.mkField("contract_name", "String", S$RescriptSchema.string, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined)
55
+ Table.mkField("id", "String", S$RescriptSchema.string, undefined, undefined, undefined, true, undefined, undefined, undefined, undefined, undefined, undefined),
56
+ Table.mkField("chain_id", "ChainId", ChainId.schema, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined),
57
+ Table.mkField("registration_block", "Int32", S$RescriptSchema.int, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined),
58
+ Table.mkField("registration_log_index", "Int32", S$RescriptSchema.int, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined),
59
+ Table.mkField("contract_name", "String", S$RescriptSchema.string, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined)
50
60
  ], undefined);
51
61
 
52
62
  let entityConfig_storage = {
@@ -59,7 +69,8 @@ let entityConfig = {
59
69
  index: -1,
60
70
  schema: schema,
61
71
  table: table,
62
- storage: entityConfig_storage
72
+ storage: entityConfig_storage,
73
+ crossChain: true
63
74
  };
64
75
 
65
76
  let EnvioAddresses = {
@@ -217,6 +228,7 @@ let entityStorageSchema = S$RescriptSchema.schema(s => ({
217
228
 
218
229
  let entityJsonSchema = S$RescriptSchema.schema(s => ({
219
230
  name: s.m(S$RescriptSchema.string),
231
+ crossChain: s.m(S$RescriptSchema.option(S$RescriptSchema.bool)),
220
232
  storage: s.m(S$RescriptSchema.option(entityStorageSchema)),
221
233
  properties: s.m(S$RescriptSchema.array(propertySchema)),
222
234
  derivedFields: s.m(S$RescriptSchema.option(S$RescriptSchema.array(derivedFieldSchema))),
@@ -324,19 +336,24 @@ function parseEnumsFromJson(enumsJson) {
324
336
  return Object.entries(enumsJson).map(param => Table.makeEnumConfig(param[0], param[1]));
325
337
  }
326
338
 
327
- function parseEntitiesFromJson(entitiesJson, enumConfigsByName, globalStorage) {
339
+ function makeChainIdField(globalStorage) {
340
+ return Table.mkField(chainIdFieldName, "ChainId", ChainId.schema, undefined, undefined, undefined, true, undefined, true, undefined, undefined, chainIdColumnName(globalStorage.postgresColumnNameFormat), chainIdColumnName(globalStorage.clickhouseColumnNameFormat));
341
+ }
342
+
343
+ function parseEntitiesFromJson(entitiesJson, enumConfigsByName, globalStorage, defaultCrossChain) {
328
344
  return entitiesJson.map((entityJson, index) => {
329
345
  let entityName = entityJson.name;
346
+ let crossChain = Stdlib_Option.getOr(entityJson.crossChain, defaultCrossChain);
330
347
  let fields = entityJson.properties.map(prop => {
331
348
  let match = getFieldTypeAndSchema(prop, enumConfigsByName);
332
- return Table.mkField(prop.name, match[0], match[1], undefined, match[3], match[2], prop.name === "id", match[4], prop.linkedEntity, prop.description, prop.postgresDbName, prop.clickhouseDbName);
349
+ return Table.mkField(prop.name, match[0], match[1], undefined, match[3], match[2], prop.name === "id", match[4], undefined, prop.linkedEntity, prop.description, prop.postgresDbName, prop.clickhouseDbName);
333
350
  });
334
351
  let derivedFields = Stdlib_Option.getOr(entityJson.derivedFields, []).map(df => Table.mkDerivedFromField(df.fieldName, df.derivedFromEntity, df.derivedFromField, df.description));
335
352
  let compositeIndexes = Stdlib_Option.getOr(entityJson.compositeIndices, []).map(ci => ci.map(f => ({
336
353
  fieldName: f.fieldName,
337
354
  direction: f.direction === "Asc" ? "Asc" : "Desc"
338
355
  })));
339
- let table = Table.mkTable(entityName, compositeIndexes, fields.concat(derivedFields), entityJson.description);
356
+ let table = Table.mkTable(entityName, compositeIndexes, fields.concat(crossChain ? [] : [makeChainIdField(globalStorage)], derivedFields), entityJson.description);
340
357
  let getApiFieldName = prop => {
341
358
  let match = prop.linkedEntity;
342
359
  if (match !== undefined) {
@@ -382,14 +399,22 @@ function parseEntitiesFromJson(entitiesJson, enumConfigsByName, globalStorage) {
382
399
  index: index,
383
400
  schema: schema,
384
401
  table: table,
385
- storage: storage
402
+ storage: storage,
403
+ crossChain: crossChain
386
404
  };
387
405
  });
388
406
  }
389
407
 
408
+ let columnNameFormatSchema = S$RescriptSchema.$$enum([
409
+ "original",
410
+ "snake_case"
411
+ ]);
412
+
390
413
  let publicConfigStorageSchema = S$RescriptSchema.schema(s => ({
391
414
  postgres: s.m(S$RescriptSchema.bool),
392
- clickhouse: s.m(S$RescriptSchema.option(S$RescriptSchema.bool))
415
+ clickhouse: s.m(S$RescriptSchema.option(S$RescriptSchema.bool)),
416
+ postgresColumnNameFormat: s.m(S$RescriptSchema.option(columnNameFormatSchema)),
417
+ clickhouseColumnNameFormat: s.m(S$RescriptSchema.option(columnNameFormatSchema))
393
418
  }));
394
419
 
395
420
  let publicConfigSchema = S$RescriptSchema.schema(s => ({
@@ -402,6 +427,7 @@ let publicConfigSchema = S$RescriptSchema.schema(s => ({
402
427
  saveFullHistory: s.m(S$RescriptSchema.option(S$RescriptSchema.bool)),
403
428
  rawEvents: s.m(S$RescriptSchema.option(S$RescriptSchema.bool)),
404
429
  chainIdMode: s.m(S$RescriptSchema.option(ChainId.modeSchema)),
430
+ defaultCrossChain: s.m(S$RescriptSchema.option(S$RescriptSchema.bool)),
405
431
  storage: s.m(publicConfigStorageSchema),
406
432
  evm: s.m(S$RescriptSchema.option(publicConfigEvmSchema)),
407
433
  fuel: s.m(S$RescriptSchema.option(publicConfigEcosystemSchema)),
@@ -689,11 +715,16 @@ function fromPublic(publicConfigJson) {
689
715
  ]));
690
716
  let globalStorage_postgres = publicConfig.storage.postgres;
691
717
  let globalStorage_clickhouse = Stdlib_Option.getOr(publicConfig.storage.clickhouse, false);
718
+ let globalStorage_postgresColumnNameFormat = Stdlib_Option.getOr(publicConfig.storage.postgresColumnNameFormat, "original");
719
+ let globalStorage_clickhouseColumnNameFormat = Stdlib_Option.getOr(publicConfig.storage.clickhouseColumnNameFormat, "original");
692
720
  let globalStorage = {
693
721
  postgres: globalStorage_postgres,
694
- clickhouse: globalStorage_clickhouse
722
+ clickhouse: globalStorage_clickhouse,
723
+ postgresColumnNameFormat: globalStorage_postgresColumnNameFormat,
724
+ clickhouseColumnNameFormat: globalStorage_clickhouseColumnNameFormat
695
725
  };
696
- let userEntities = parseEntitiesFromJson(Stdlib_Option.getOr(publicConfig.entities, []), enumConfigsByName, globalStorage);
726
+ let defaultCrossChain = Stdlib_Option.getOr(publicConfig.defaultCrossChain, true);
727
+ let userEntities = parseEntitiesFromJson(Stdlib_Option.getOr(publicConfig.entities, []), enumConfigsByName, globalStorage, defaultCrossChain);
697
728
  let allEntities = userEntities.concat([entityConfig]);
698
729
  let userEntitiesByName = Object.fromEntries(userEntities.map(entityConfig => [
699
730
  Utils.$$String.capitalize(entityConfig.name),
@@ -710,6 +741,7 @@ function fromPublic(publicConfigJson) {
710
741
  contractHandlers: contractHandlers,
711
742
  shouldRollbackOnReorg: Stdlib_Option.getOr(publicConfig.rollbackOnReorg, true),
712
743
  shouldSaveFullHistory: Stdlib_Option.getOr(publicConfig.saveFullHistory, false),
744
+ defaultCrossChain: defaultCrossChain,
713
745
  storage: globalStorage,
714
746
  chainIdMode: Stdlib_Option.getOr(publicConfig.chainIdMode, "int32"),
715
747
  chainMap: chainMap,
@@ -1049,6 +1081,8 @@ function getPgUserEntities(config) {
1049
1081
  }
1050
1082
 
1051
1083
  export {
1084
+ chainIdFieldName,
1085
+ chainIdColumnName,
1052
1086
  EnvioAddresses,
1053
1087
  rpcSourceForSchema,
1054
1088
  rpcConfigSchema,
@@ -1069,7 +1103,9 @@ export {
1069
1103
  entityJsonSchema,
1070
1104
  getFieldTypeAndSchema,
1071
1105
  parseEnumsFromJson,
1106
+ makeChainIdField,
1072
1107
  parseEntitiesFromJson,
1108
+ columnNameFormatSchema,
1073
1109
  publicConfigStorageSchema,
1074
1110
  publicConfigSchema,
1075
1111
  fromPublic,
@@ -131,7 +131,7 @@ let commitCacheCount = (inMemTable: effectCacheInMemTable, ~count) => {
131
131
 
132
132
  let statsToMetrics = (stats: effectStats): Metrics.effectMetrics => {
133
133
  Metrics.effect: stats.effectName,
134
- scope: stats.scope->Internal.EffectCache.scopeToString,
134
+ scope: stats.scope->Internal.chainScopeToString,
135
135
  callSeconds: stats.callSeconds,
136
136
  callSecondsTotal: stats.callSecondsTotal,
137
137
  callCount: stats.callCount,
@@ -152,7 +152,7 @@ let toMetrics = (self: t): array<Metrics.effectMetrics> => {
152
152
  metrics
153
153
  ->Array.push({
154
154
  Metrics.effect: effectName,
155
- scope: scope->Internal.EffectCache.scopeToString,
155
+ scope: scope->Internal.chainScopeToString,
156
156
  callSeconds: 0.,
157
157
  callSecondsTotal: 0.,
158
158
  callCount: 0.,
@@ -68,7 +68,7 @@ function toMetrics(self) {
68
68
  let stats = t.stats;
69
69
  return {
70
70
  effect: stats.effectName,
71
- scope: Internal.EffectCache.scopeToString(stats.scope),
71
+ scope: Internal.chainScopeToString(stats.scope),
72
72
  callSeconds: stats.callSeconds,
73
73
  callSecondsTotal: stats.callSecondsTotal,
74
74
  callCount: stats.callCount,
@@ -82,7 +82,7 @@ function toMetrics(self) {
82
82
  Utils.Dict.forEach(self.unregisteredCacheCounts, param => {
83
83
  metrics.push({
84
84
  effect: param.effectName,
85
- scope: Internal.EffectCache.scopeToString(param.scope),
85
+ scope: Internal.chainScopeToString(param.scope),
86
86
  callSeconds: 0,
87
87
  callSecondsTotal: 0,
88
88
  callCount: 0,
@@ -0,0 +1,32 @@
1
+ // One in-memory table per entity, for a single chain scope. The indexer holds
2
+ // the cross-chain partition; each ChainState holds the per-chain one.
3
+
4
+ type t = dict<InMemoryTable.Entity.t>
5
+
6
+ exception UndefinedEntity({entityName: string})
7
+
8
+ let make = (entities: array<Internal.entityConfig>): t => {
9
+ let init = Dict.make()
10
+ entities->Array.forEach(entityConfig => {
11
+ init->Dict.set((entityConfig.name :> string), InMemoryTable.Entity.make())
12
+ })
13
+ init
14
+ }
15
+
16
+ let get = (self: t, ~entityName: string) => {
17
+ switch self->Utils.Dict.dangerouslyGetNonOption(entityName) {
18
+ | Some(table) => table
19
+ | None =>
20
+ UndefinedEntity({entityName: entityName})->ErrorHandling.mkLogAndRaise(
21
+ ~msg="Unexpected, entity InMemoryTable is undefined",
22
+ )
23
+ }
24
+ }
25
+
26
+ // Entities whose rows are shared by every chain, so their tables live on the
27
+ // indexer rather than on a ChainState.
28
+ let crossChain = (entities: array<Internal.entityConfig>) =>
29
+ entities->Array.filter((entityConfig: Internal.entityConfig) => entityConfig.crossChain)
30
+
31
+ let perChain = (entities: array<Internal.entityConfig>) =>
32
+ entities->Array.filter((entityConfig: Internal.entityConfig) => !entityConfig.crossChain)
@@ -0,0 +1,44 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as ErrorHandling from "./ErrorHandling.res.mjs";
4
+ import * as InMemoryTable from "./InMemoryTable.res.mjs";
5
+ import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
6
+
7
+ let UndefinedEntity = /* @__PURE__ */Primitive_exceptions.create("EntityTables.UndefinedEntity");
8
+
9
+ function make(entities) {
10
+ let init = {};
11
+ entities.forEach(entityConfig => {
12
+ init[entityConfig.name] = InMemoryTable.Entity.make();
13
+ });
14
+ return init;
15
+ }
16
+
17
+ function get(self, entityName) {
18
+ let table = self[entityName];
19
+ if (table !== undefined) {
20
+ return table;
21
+ } else {
22
+ return ErrorHandling.mkLogAndRaise(undefined, "Unexpected, entity InMemoryTable is undefined", {
23
+ RE_EXN_ID: UndefinedEntity,
24
+ entityName: entityName
25
+ });
26
+ }
27
+ }
28
+
29
+ function crossChain(entities) {
30
+ return entities.filter(entityConfig => entityConfig.crossChain);
31
+ }
32
+
33
+ function perChain(entities) {
34
+ return entities.filter(entityConfig => !entityConfig.crossChain);
35
+ }
36
+
37
+ export {
38
+ UndefinedEntity,
39
+ make,
40
+ get,
41
+ crossChain,
42
+ perChain,
43
+ }
44
+ /* ErrorHandling Not a pure module */
package/src/Envio.res CHANGED
@@ -186,7 +186,8 @@ and effectOptions<'input, 'output> = {
186
186
  rateLimit: rateLimit,
187
187
  /** Whether the effect should be cached. */
188
188
  cache?: bool,
189
- /** Whether the effect's cache is shared across all chains. Defaults to `true`.
189
+ /** Whether the effect's cache is shared across all chains. Defaults to `true`,
190
+ or to `false` when config.yaml sets `disable_default_cross_chain: true`.
190
191
  Set to `false` to isolate the cache (and rate limiting) per chain and enable
191
192
  `context.chain.id` inside the handler. */
192
193
  crossChain?: bool,
@@ -196,8 +197,8 @@ and effectContext = {
196
197
  log: logger,
197
198
  effect: 'input 'output. (effect<'input, 'output>, 'input) => promise<'output>,
198
199
  mutable cache: bool,
199
- /** The chain the effect was called on. Only available on effects created with
200
- `crossChain: false`; accessing it on a cross-chain effect throws. */
200
+ /** The chain the effect was called on. Only available on chain-scoped
201
+ effects; accessing it on a cross-chain effect throws. */
201
202
  chain: effectChain,
202
203
  }
203
204
  and effectArgs<'input> = {
@@ -259,10 +260,9 @@ let createEffect = (
259
260
  | Some(true) => true
260
261
  | _ => false
261
262
  },
262
- crossChain: switch options.crossChain {
263
- | Some(false) => false
264
- | _ => true
265
- },
263
+ // Left unresolved: the config's `defaultCrossChain` fills it in when the
264
+ // effect didn't state one, and the config isn't available here.
265
+ crossChain: options.crossChain,
266
266
  rateLimit: switch options.rateLimit {
267
267
  | Disable => None
268
268
  | Enable({calls, per}) =>
package/src/Envio.res.mjs CHANGED
@@ -30,12 +30,11 @@ function createEffect(options, handler) {
30
30
  output: s.m(outputSchema)
31
31
  }));
32
32
  let match = options.cache;
33
- let match$1 = options.crossChain;
34
- let match$2 = options.rateLimit;
33
+ let match$1 = options.rateLimit;
35
34
  let tmp;
36
- tmp = match$2 === false ? undefined : ({
37
- callsPerDuration: match$2.calls,
38
- durationMs: durationToMs(match$2.per)
35
+ tmp = match$1 === false ? undefined : ({
36
+ callsPerDuration: match$1.calls,
37
+ durationMs: durationToMs(match$1.per)
39
38
  });
40
39
  return {
41
40
  name: options.name,
@@ -45,7 +44,7 @@ function createEffect(options, handler) {
45
44
  outputSchema: outputSchema
46
45
  },
47
46
  defaultShouldCache: match !== undefined ? match : false,
48
- crossChain: match$1 !== undefined ? match$1 : true,
47
+ crossChain: options.crossChain,
49
48
  output: outputSchema,
50
49
  input: S$RescriptSchema.schema(param => options.input),
51
50
  rateLimit: tmp