envio 3.7.0 → 3.9.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 (79) hide show
  1. package/README.md +2 -2
  2. package/index.d.ts +399 -156
  3. package/package.json +6 -6
  4. package/src/AddressRows.res +121 -0
  5. package/src/AddressRows.res.mjs +143 -0
  6. package/src/Batch.res +2 -0
  7. package/src/Batch.res.mjs +2 -1
  8. package/src/ChainState.res +82 -68
  9. package/src/ChainState.res.mjs +81 -65
  10. package/src/ChainState.resi +14 -9
  11. package/src/Config.res +41 -91
  12. package/src/Config.res.mjs +34 -68
  13. package/src/ContractMapping.res +66 -0
  14. package/src/ContractMapping.res.mjs +73 -0
  15. package/src/Core.res +20 -0
  16. package/src/Core.res.mjs +4 -0
  17. package/src/Envio.res +54 -76
  18. package/src/EventConfigBuilder.res +157 -30
  19. package/src/EventConfigBuilder.res.mjs +118 -24
  20. package/src/FetchState.res +59 -67
  21. package/src/FetchState.res.mjs +34 -44
  22. package/src/HandlerRegister.res +20 -11
  23. package/src/HandlerRegister.res.mjs +22 -5
  24. package/src/Hasura.res +30 -22
  25. package/src/Hasura.res.mjs +11 -5
  26. package/src/InMemoryStore.res +18 -36
  27. package/src/InMemoryStore.res.mjs +12 -26
  28. package/src/IndexerState.res +21 -1
  29. package/src/IndexerState.res.mjs +9 -3
  30. package/src/IndexerState.resi +1 -0
  31. package/src/Internal.res +33 -13
  32. package/src/Internal.res.mjs +12 -16
  33. package/src/Main.res +27 -20
  34. package/src/Main.res.mjs +19 -14
  35. package/src/MemoryStorage.res +78 -73
  36. package/src/MemoryStorage.res.mjs +66 -81
  37. package/src/Metrics.res +15 -1
  38. package/src/Metrics.res.mjs +5 -1
  39. package/src/Persistence.res +34 -18
  40. package/src/Persistence.res.mjs +8 -5
  41. package/src/PgStorage.res +189 -66
  42. package/src/PgStorage.res.mjs +93 -59
  43. package/src/Rollback.res +14 -10
  44. package/src/Rollback.res.mjs +4 -2
  45. package/src/SimulateItems.res +254 -9
  46. package/src/SimulateItems.res.mjs +214 -47
  47. package/src/TestIndexer.res +119 -121
  48. package/src/TestIndexer.res.mjs +95 -100
  49. package/src/Utils.res +7 -0
  50. package/src/Utils.res.mjs +9 -2
  51. package/src/Writing.res +2 -0
  52. package/src/Writing.res.mjs +2 -1
  53. package/src/bindings/ClickHouse.res +39 -6
  54. package/src/bindings/ClickHouse.res.mjs +29 -4
  55. package/src/bindings/NodeJs.res +9 -0
  56. package/src/bindings/NodeJs.res.mjs +8 -1
  57. package/src/bindings/Postgres.res +9 -0
  58. package/src/bindings/Postgres.res.mjs +3 -0
  59. package/src/db/EntityHistory.res +12 -18
  60. package/src/db/EntityHistory.res.mjs +3 -14
  61. package/src/db/InternalTable.res +182 -65
  62. package/src/db/InternalTable.res.mjs +183 -73
  63. package/src/db/Table.res +24 -0
  64. package/src/db/Table.res.mjs +20 -1
  65. package/src/sources/AddressSet.res +0 -22
  66. package/src/sources/AddressStore.res +48 -88
  67. package/src/sources/AddressStore.res.mjs +11 -22
  68. package/src/sources/EvmHyperSyncSource.res +3 -2
  69. package/src/sources/SimulateSource.res +8 -4
  70. package/src/sources/SimulateSource.res.mjs +7 -3
  71. package/src/sources/Svm.res +34 -7
  72. package/src/sources/Svm.res.mjs +32 -4
  73. package/src/sources/SvmHyperSyncClient.res +24 -30
  74. package/src/sources/SvmHyperSyncClient.res.mjs +3 -2
  75. package/src/sources/SvmHyperSyncSource.res +88 -36
  76. package/src/sources/SvmHyperSyncSource.res.mjs +71 -39
  77. package/src/sources/TransactionStore.res +38 -0
  78. package/src/sources/TransactionStore.res.mjs +5 -0
  79. package/svm.schema.json +37 -82
@@ -16,6 +16,7 @@ import * as BigDecimal from "./bindings/BigDecimal.res.mjs";
16
16
  import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
17
17
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
18
18
  import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
19
+ import * as ContractMapping from "./ContractMapping.res.mjs";
19
20
  import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
20
21
  import * as Primitive_string from "@rescript/runtime/lib/es6/Primitive_string.js";
21
22
  import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
@@ -32,57 +33,6 @@ function chainIdColumnName(format) {
32
33
  }
33
34
  }
34
35
 
35
- let name = "envio_addresses";
36
-
37
- function makeId(chainId, address) {
38
- return ChainId.toString(chainId) + "-" + address;
39
- }
40
-
41
- function getAddress(entity) {
42
- let sepIdx = entity.id.indexOf("-");
43
- return entity.id.slice(sepIdx + 1 | 0, entity.id.length);
44
- }
45
-
46
- let schema = S$RescriptSchema.schema(s => ({
47
- id: s.m(S$RescriptSchema.string),
48
- chain_id: s.m(ChainId.schema),
49
- registration_block: s.m(S$RescriptSchema.int),
50
- registration_log_index: s.m(S$RescriptSchema.int),
51
- contract_name: s.m(S$RescriptSchema.string)
52
- }));
53
-
54
- let table = Table.mkTable(name, 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)
60
- ], undefined);
61
-
62
- let entityConfig_storage = {
63
- postgres: true,
64
- clickhouse: false
65
- };
66
-
67
- let entityConfig = {
68
- name: name,
69
- index: -1,
70
- schema: schema,
71
- table: table,
72
- storage: entityConfig_storage,
73
- crossChain: true
74
- };
75
-
76
- let EnvioAddresses = {
77
- name: name,
78
- index: -1,
79
- makeId: makeId,
80
- getAddress: getAddress,
81
- schema: schema,
82
- table: table,
83
- entityConfig: entityConfig
84
- };
85
-
86
36
  let rpcSourceForSchema = S$RescriptSchema.$$enum([
87
37
  "sync",
88
38
  "fallback",
@@ -124,9 +74,6 @@ let publicConfigChainSchema = S$RescriptSchema.schema(s => ({
124
74
  let svmEventDescriptorSchema = S$RescriptSchema.schema(s => ({
125
75
  discriminator: s.m(S$RescriptSchema.option(S$RescriptSchema.string)),
126
76
  discriminatorByteLen: s.m(S$RescriptSchema.int),
127
- transactionFields: s.m(S$RescriptSchema.array(Internal.svmTransactionFieldSchema)),
128
- blockFields: s.m(S$RescriptSchema.option(S$RescriptSchema.array(Internal.svmBlockFieldSchema))),
129
- includeLogs: s.m(S$RescriptSchema.bool),
130
77
  accountFilters: s.m(S$RescriptSchema.option(S$RescriptSchema.array(S$RescriptSchema.array(S$RescriptSchema.schema(s => ({
131
78
  position: s.m(S$RescriptSchema.int),
132
79
  values: s.m(S$RescriptSchema.array(S$RescriptSchema.string))
@@ -204,10 +151,18 @@ let propertySchema = S$RescriptSchema.schema(s => ({
204
151
  description: s.m(S$RescriptSchema.option(S$RescriptSchema.string))
205
152
  }));
206
153
 
154
+ let clickhouseSkippingIndexSchema = S$RescriptSchema.object(s => ({
155
+ name: s.f("name", S$RescriptSchema.string),
156
+ expr: s.f("expr", S$RescriptSchema.string),
157
+ type: s.f("type", S$RescriptSchema.string),
158
+ granularity: s.f("granularity", S$RescriptSchema.option(S$RescriptSchema.int))
159
+ }));
160
+
207
161
  let clickhouseTableOptionsSchema = S$RescriptSchema.object(s => ({
208
162
  partitionBy: s.f("partitionBy", S$RescriptSchema.option(S$RescriptSchema.string)),
209
163
  orderBy: s.f("orderBy", S$RescriptSchema.option(S$RescriptSchema.array(S$RescriptSchema.string))),
210
- ttl: s.f("ttl", S$RescriptSchema.option(S$RescriptSchema.string))
164
+ ttl: s.f("ttl", S$RescriptSchema.option(S$RescriptSchema.string)),
165
+ skippingIndexes: s.f("skippingIndexes", S$RescriptSchema.option(S$RescriptSchema.array(clickhouseSkippingIndexSchema)))
211
166
  }));
212
167
 
213
168
  let entityClickhouseStorageJsonSchema = S$RescriptSchema.union([
@@ -230,6 +185,7 @@ let entityJsonSchema = S$RescriptSchema.schema(s => ({
230
185
  name: s.m(S$RescriptSchema.string),
231
186
  crossChain: s.m(S$RescriptSchema.option(S$RescriptSchema.bool)),
232
187
  storage: s.m(S$RescriptSchema.option(entityStorageSchema)),
188
+ internal: s.m(S$RescriptSchema.option(S$RescriptSchema.bool)),
233
189
  properties: s.m(S$RescriptSchema.array(propertySchema)),
234
190
  derivedFields: s.m(S$RescriptSchema.option(S$RescriptSchema.array(derivedFieldSchema))),
235
191
  compositeIndices: s.m(S$RescriptSchema.option(S$RescriptSchema.array(S$RescriptSchema.array(compositeIndexFieldSchema)))),
@@ -400,7 +356,8 @@ function parseEntitiesFromJson(entitiesJson, enumConfigsByName, globalStorage, d
400
356
  schema: schema,
401
357
  table: table,
402
358
  storage: storage,
403
- crossChain: crossChain
359
+ crossChain: crossChain,
360
+ internal: Stdlib_Option.getOr(entityJson.internal, false)
404
361
  };
405
362
  });
406
363
  }
@@ -436,6 +393,16 @@ let publicConfigSchema = S$RescriptSchema.schema(s => ({
436
393
  entities: s.m(S$RescriptSchema.option(S$RescriptSchema.array(entityJsonSchema)))
437
394
  }));
438
395
 
396
+ function contractMappingOf(chainConfigs) {
397
+ let names = [];
398
+ chainConfigs.forEach(chain => {
399
+ chain.contracts.forEach(contract => {
400
+ names.push(contract.name);
401
+ });
402
+ });
403
+ return ContractMapping.make(names);
404
+ }
405
+
439
406
  function fromPublic(publicConfigJson) {
440
407
  let publicConfig;
441
408
  try {
@@ -564,7 +531,7 @@ function fromPublic(publicConfigJson) {
564
531
  position: af.position,
565
532
  values: af.values
566
533
  })));
567
- return EventConfigBuilder.buildSvmInstructionEventConfig(contractName, eventName, programId, svm.discriminator, svm.discriminatorByteLen, svm.includeLogs, svm.transactionFields, svm.blockFields, accountFilters, svm.isInner, Stdlib_Option.getOr(svm.accounts, []), Stdlib_Option.getOr(svm.args, null), svmDefinedTypes);
534
+ return EventConfigBuilder.buildSvmInstructionEventConfig(contractName, eventName, programId, svm.discriminator, svm.discriminatorByteLen, accountFilters, svm.isInner, Stdlib_Option.getOr(svm.accounts, []), Stdlib_Option.getOr(svm.args, null), svmDefinedTypes);
568
535
  }
569
536
  });
570
537
  } else {
@@ -614,16 +581,14 @@ function fromPublic(publicConfigJson) {
614
581
  startBlock: startBlock
615
582
  };
616
583
  });
617
- let contractNameByAddress = {};
584
+ let seen = new Set();
618
585
  contracts.forEach(contract => {
619
586
  contract.addresses.forEach(address => {
620
- let existingContractName = contractNameByAddress[address];
621
- if (existingContractName !== undefined) {
622
- return Stdlib_JsError.throwWithMessage(existingContractName === contract.name ? `Address ` + address + ` is listed multiple times for the contract ` + contract.name + ` on chain ` + ChainId.toString(chainId) + `. Please remove the duplicate from your config.` : `Address ` + address + ` on chain ` + ChainId.toString(chainId) + ` is configured for multiple contracts: ` + existingContractName + ` and ` + contract.name + `. Indexing the same address with multiple contract definitions is not supported. Please define the events on a single contract definition instead.`);
623
- } else {
624
- contractNameByAddress[address] = contract.name;
625
- return;
587
+ let key = contract.name + "-" + address;
588
+ if (seen.has(key)) {
589
+ Stdlib_JsError.throwWithMessage(`Address ` + address + ` is listed multiple times for the contract ` + contract.name + ` on chain ` + ChainId.toString(chainId) + `. Please remove the duplicate from your config.`);
626
590
  }
591
+ seen.add(key);
627
592
  });
628
593
  });
629
594
  let sourceConfig;
@@ -696,6 +661,7 @@ function fromPublic(publicConfigJson) {
696
661
  return {
697
662
  name: chainName,
698
663
  id: chainId,
664
+ ecosystem: ecosystemName,
699
665
  startBlock: publicChainConfig.startBlock,
700
666
  endBlock: publicChainConfig.endBlock,
701
667
  maxReorgDepth: tmp,
@@ -725,7 +691,6 @@ function fromPublic(publicConfigJson) {
725
691
  };
726
692
  let defaultCrossChain = Stdlib_Option.getOr(publicConfig.defaultCrossChain, true);
727
693
  let userEntities = parseEntitiesFromJson(Stdlib_Option.getOr(publicConfig.entities, []), enumConfigsByName, globalStorage, defaultCrossChain);
728
- let allEntities = userEntities.concat([entityConfig]);
729
694
  let userEntitiesByName = Object.fromEntries(userEntities.map(entityConfig => [
730
695
  Utils.$$String.capitalize(entityConfig.name),
731
696
  entityConfig
@@ -745,6 +710,7 @@ function fromPublic(publicConfigJson) {
745
710
  storage: globalStorage,
746
711
  chainIdMode: Stdlib_Option.getOr(publicConfig.chainIdMode, "int32"),
747
712
  chainMap: chainMap,
713
+ contractMapping: contractMappingOf(chains),
748
714
  defaultChain: chains[0],
749
715
  ecosystem: ecosystem,
750
716
  enableRawEvents: Stdlib_Option.getOr(publicConfig.rawEvents, false),
@@ -756,7 +722,6 @@ function fromPublic(publicConfigJson) {
756
722
  isDev: Stdlib_Option.getOr(publicConfig.isDev, false),
757
723
  userEntitiesByName: userEntitiesByName,
758
724
  userEntities: userEntities,
759
- allEntities: allEntities,
760
725
  allEnums: allEnums
761
726
  };
762
727
  }
@@ -1083,7 +1048,6 @@ function getPgUserEntities(config) {
1083
1048
  export {
1084
1049
  chainIdFieldName,
1085
1050
  chainIdColumnName,
1086
- EnvioAddresses,
1087
1051
  rpcSourceForSchema,
1088
1052
  rpcConfigSchema,
1089
1053
  chainContractSchema,
@@ -1097,6 +1061,7 @@ export {
1097
1061
  compositeIndexFieldSchema,
1098
1062
  derivedFieldSchema,
1099
1063
  propertySchema,
1064
+ clickhouseSkippingIndexSchema,
1100
1065
  clickhouseTableOptionsSchema,
1101
1066
  entityClickhouseStorageJsonSchema,
1102
1067
  entityStorageSchema,
@@ -1108,6 +1073,7 @@ export {
1108
1073
  columnNameFormatSchema,
1109
1074
  publicConfigStorageSchema,
1110
1075
  publicConfigSchema,
1076
+ contractMappingOf,
1111
1077
  fromPublic,
1112
1078
  normalizeUserAddress,
1113
1079
  normalizeSimulateAddress,
@@ -1124,4 +1090,4 @@ export {
1124
1090
  load,
1125
1091
  getPgUserEntities,
1126
1092
  }
1127
- /* schema Not a pure module */
1093
+ /* rpcSourceForSchema Not a pure module */
@@ -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
@@ -47,6 +47,22 @@ type addon = {
47
47
  addressStore: addressStoreCtor,
48
48
  @as("MockHyperSyncServer")
49
49
  mockHyperSyncServer: mockHyperSyncServerCtor,
50
+ encodeAddresses: (~ecosystem: string, ~addresses: array<Address.t>) => array<NodeJs.Buffer.t>,
51
+ renderAddresses: (
52
+ ~ecosystem: string,
53
+ ~shouldChecksum: bool,
54
+ ~bytes: NodeJs.Buffer.t,
55
+ ~lengths: array<int>,
56
+ ) => array<Address.t>,
57
+ renderContractAddresses: (
58
+ ~ecosystem: string,
59
+ ~shouldChecksum: bool,
60
+ ~bytes: NodeJs.Buffer.t,
61
+ ~lengths: array<int>,
62
+ ~contractIds: array<int>,
63
+ ~contractId: int,
64
+ ) => array<Address.t>,
65
+ canonicalContractNames: array<string> => array<string>,
50
66
  // Ordered transaction-field names exposed for the field-code contract test
51
67
  // (the ReScript `transactionFields` arrays must match the Rust ordinals).
52
68
  evmTransactionFieldNames: unit => array<string>,
@@ -84,6 +100,10 @@ let loadDevAddon: ({..}, string) => addon = %raw(`function(req, envioDir) {
84
100
  var path = Nodepath;
85
101
  var fs = Nodefs;
86
102
 
103
+ // Vitest test.env points workers at the addon globalSetup already built.
104
+ var preBuilt = process.env.ENVIO_DEV_ADDON;
105
+ if (preBuilt && fs.existsSync(preBuilt)) return req(preBuilt);
106
+
87
107
  var repoRoot = null;
88
108
  var dir = path.resolve(envioDir);
89
109
  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/Envio.res CHANGED
@@ -20,58 +20,48 @@ type svmOnSlotArgs<'context> = {
20
20
  context: 'context,
21
21
  }
22
22
 
23
- /** Borsh-decoded instruction view. Present whenever a `ProgramSchema` was
24
- attached to the program (bundled schema, Anchor IDL, or hand-written YAML
25
- `accounts`/`args`). Absent (`None`) when no schema applied or the
26
- discriminator didn't match any registered instruction. */
27
- type svmInstructionParams = {
28
- /** Schema-declared instruction name (matches the codegen module suffix). */
29
- name: string,
30
- /** Borsh-decoded args. `JSON.Object({})` for no-arg instructions
31
- (e.g. `VerifyCollection`). POC types this as raw `JSON.t`; cast at the
32
- handler with `(json :> MyArgsType)` until typed codegen lands. */
33
- args: JSON.t,
34
- /** Named accounts in schema order. Keys are exactly the schema-declared
35
- names; values are base58 pubkey strings. */
36
- accounts: dict<string>,
37
- /** Accounts beyond the schema's named list (Anchor `remaining_accounts`,
38
- IDL drift). `[]` when counts match. */
39
- extraAccounts: array<string>,
23
+ type svmLamports = {
24
+ pre: bigint,
25
+ post: bigint,
40
26
  }
41
27
 
42
- type svmTokenBalance = {
43
- account?: SvmTypes.Pubkey.t,
44
- mint?: SvmTypes.Pubkey.t,
45
- /** Owner at the end of the transaction, falling back to the owner on entry
46
- when the account was closed during it. Pre and post owners differ only when
47
- a `SetAuthority(AccountOwner)` runs mid-transaction. */
48
- owner?: SvmTypes.Pubkey.t,
49
- /** Mint decimals, for scaling the raw amounts below. */
50
- decimals?: int,
51
- /** Raw amount in base units before the transaction. Absent when the token
52
- account was created during it. */
28
+ type svmAccountToken = {
29
+ mint: SvmTypes.Pubkey.t,
30
+ owner: SvmTypes.Pubkey.t,
31
+ decimals: int,
53
32
  preAmount?: bigint,
54
- /** Raw amount in base units after the transaction. Absent when the token
55
- account was closed during it. */
56
33
  postAmount?: bigint,
57
34
  }
58
35
 
36
+ type svmAccountActivity = {
37
+ address: SvmTypes.Pubkey.t,
38
+ transactionAccountIndex?: int,
39
+ isSigner?: bool,
40
+ isWritable?: bool,
41
+ lamports?: svmLamports,
42
+ token?: svmAccountToken,
43
+ }
44
+
45
+ type svmInstructionAccount = {
46
+ address: SvmTypes.Pubkey.t,
47
+ accountName: string,
48
+ instructionAccountIndex: int,
49
+ activity?: svmAccountActivity,
50
+ }
51
+
59
52
  type svmTransaction = {
60
53
  transactionIndex?: int,
61
- /** The transaction's identifying signature (`allSignatures[0]`). */
62
- signature: string,
54
+ signature?: string,
63
55
  feePayer?: SvmTypes.Pubkey.t,
64
56
  success?: bool,
65
57
  err?: string,
66
58
  fee?: bigint,
67
59
  computeUnitsConsumed?: bigint,
68
- accountKeys: array<SvmTypes.Pubkey.t>,
60
+ accountKeys?: array<SvmTypes.Pubkey.t>,
69
61
  recentBlockhash?: string,
70
62
  version?: string,
71
- /** Every signature on the transaction, in message order; the first is
72
- `signature`. Longer than one element only for a multi-signer transaction. */
73
- allSignatures: array<string>,
74
- tokenBalances?: array<svmTokenBalance>,
63
+ allSignatures?: array<string>,
64
+ accountActivities?: array<svmAccountActivity>,
75
65
  }
76
66
 
77
67
  type svmLog = {
@@ -79,57 +69,29 @@ type svmLog = {
79
69
  message: string,
80
70
  }
81
71
 
82
- /** Block context for a matched instruction. `slot`/`hash` are always present;
83
- `time` can still be absent — HyperSync/Solana may not report a block time for
84
- every slot. Every other field is opt-in via `field_selection.block_fields`,
85
- materialised from the per-chain block store at batch prep. */
86
- type svmInstructionBlock = {
87
- /** Slot this instruction's block was matched in. */
72
+ type svmBlock = {
88
73
  slot: int,
89
- /** Unix block time (seconds). */
90
74
  time?: int,
91
- hash: string,
92
- /** Block height (distinct from slot). Absent when not selected via
93
- `field_selection.block_fields`. */
75
+ hash?: string,
94
76
  height?: int,
95
77
  parentSlot?: int,
96
78
  parentHash?: string,
97
79
  }
98
80
 
99
- /** The per-instruction payload handlers receive as their `instruction`
100
- argument. Carries the matched instruction's own fields plus the
101
- program/instruction names, parent transaction, scoped logs, and block. */
102
81
  type svmInstruction = {
103
- /** Program name as declared under `programs[].name` in `config.yaml`. */
104
82
  programName: string,
105
- /** Instruction name as declared under `instructions[].name` in
106
- `config.yaml`. */
107
83
  instructionName: string,
108
- programId: SvmTypes.Pubkey.t,
109
- /** Raw instruction bytes as `0x`-prefixed hex. */
110
- data: string,
111
- accounts: array<SvmTypes.Pubkey.t>,
112
- /** Path through the call tree: `[outerIndex]` for top-level instructions,
113
- appended child indices for inner CPI calls. */
114
- instructionAddress: array<int>,
115
- isInner: bool,
116
- /** Discriminator prefixes pre-extracted by HyperSync. Each is `Some` only
117
- when the underlying instruction is at least that long. */
118
- d1?: string,
119
- d2?: string,
120
- d4?: string,
121
- d8?: string,
122
- /** Borsh-decoded params view. See [[svmInstructionParams]]. */
123
- params?: svmInstructionParams,
124
- /** Parent transaction. Carries only the fields selected via
125
- `field_selection.transaction_fields`; absent when none are selected. */
84
+ discriminator: string,
85
+ programId?: SvmTypes.Pubkey.t,
86
+ data?: string,
87
+ path?: array<int>,
88
+ isInner?: bool,
89
+ args?: JSON.t,
90
+ accounts?: dict<svmInstructionAccount>,
91
+ accountArguments?: array<SvmTypes.Pubkey.t>,
126
92
  transaction?: svmTransaction,
127
- /** Program log entries scoped to this instruction. Absent when the
128
- per-instruction `include_logs` flag is `false`. */
129
93
  logs?: array<svmLog>,
130
- // Omitted on construction; materialised onto the payload at batch prep,
131
- // before a handler ever reads it.
132
- block?: svmInstructionBlock,
94
+ block?: svmBlock,
133
95
  }
134
96
 
135
97
  /** Arguments passed to handlers registered via `indexer.onInstruction`. */
@@ -315,6 +277,22 @@ type fuelSimulateItem = {
315
277
  transaction?: fuelTransactionInput,
316
278
  }
317
279
 
280
+ type svmSimulateItem = {
281
+ program: string,
282
+ instruction: string,
283
+ slot?: int,
284
+ path?: array<int>,
285
+ programId?: string,
286
+ data?: string,
287
+ isInner?: bool,
288
+ args?: JSON.t,
289
+ accounts?: dict<{address: string}>,
290
+ accountArguments?: array<string>,
291
+ logs?: array<{kind?: string, message?: string}>,
292
+ block?: svmBlock,
293
+ transaction?: unknown,
294
+ }
295
+
318
296
  // Detects contexts where a full-screen TUI is counter-productive: piped/redirected
319
297
  // stdout, CI, and coding agents. `CLAUDECODE` is set by Claude Code; `CI` is the
320
298
  // de-facto convention across CI providers; `TERM=dumb` is set by editors/tools