envio 3.0.0-alpha.21 → 3.0.0-alpha.22

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 (219) hide show
  1. package/bin.mjs +2 -48
  2. package/evm.schema.json +67 -0
  3. package/fuel.schema.json +67 -0
  4. package/index.d.ts +822 -38
  5. package/index.js +5 -3
  6. package/package.json +10 -8
  7. package/rescript.json +5 -9
  8. package/src/Address.res +4 -5
  9. package/src/Address.res.mjs +9 -12
  10. package/src/Api.res +15 -0
  11. package/src/Api.res.mjs +20 -0
  12. package/src/Batch.res +32 -34
  13. package/src/Batch.res.mjs +172 -187
  14. package/src/Bin.res +89 -0
  15. package/src/Bin.res.mjs +97 -0
  16. package/src/ChainFetcher.res +33 -57
  17. package/src/ChainFetcher.res.mjs +197 -227
  18. package/src/ChainManager.res +6 -14
  19. package/src/ChainManager.res.mjs +74 -85
  20. package/src/ChainMap.res +14 -16
  21. package/src/ChainMap.res.mjs +38 -38
  22. package/src/Config.res +193 -135
  23. package/src/Config.res.mjs +566 -592
  24. package/src/Core.res +182 -0
  25. package/src/Core.res.mjs +207 -0
  26. package/src/Ecosystem.res +25 -4
  27. package/src/Ecosystem.res.mjs +12 -13
  28. package/src/Env.res +20 -13
  29. package/src/Env.res.mjs +124 -113
  30. package/src/EnvSafe.res +269 -0
  31. package/src/EnvSafe.res.mjs +296 -0
  32. package/src/EnvSafe.resi +18 -0
  33. package/src/Envio.res +37 -26
  34. package/src/Envio.res.mjs +59 -60
  35. package/src/ErrorHandling.res +2 -2
  36. package/src/ErrorHandling.res.mjs +15 -15
  37. package/src/EventConfigBuilder.res +219 -81
  38. package/src/EventConfigBuilder.res.mjs +259 -202
  39. package/src/EventProcessing.res +27 -38
  40. package/src/EventProcessing.res.mjs +165 -183
  41. package/src/EventUtils.res +11 -11
  42. package/src/EventUtils.res.mjs +21 -22
  43. package/src/EvmTypes.res +0 -1
  44. package/src/EvmTypes.res.mjs +5 -5
  45. package/src/FetchState.res +360 -256
  46. package/src/FetchState.res.mjs +958 -914
  47. package/src/GlobalState.res +365 -351
  48. package/src/GlobalState.res.mjs +958 -992
  49. package/src/GlobalStateManager.res +1 -2
  50. package/src/GlobalStateManager.res.mjs +36 -44
  51. package/src/HandlerLoader.res +107 -23
  52. package/src/HandlerLoader.res.mjs +128 -38
  53. package/src/HandlerRegister.res +127 -103
  54. package/src/HandlerRegister.res.mjs +164 -164
  55. package/src/HandlerRegister.resi +12 -4
  56. package/src/Hasura.res +35 -22
  57. package/src/Hasura.res.mjs +158 -167
  58. package/src/InMemoryStore.res +20 -27
  59. package/src/InMemoryStore.res.mjs +64 -80
  60. package/src/InMemoryTable.res +34 -39
  61. package/src/InMemoryTable.res.mjs +165 -170
  62. package/src/Internal.res +52 -33
  63. package/src/Internal.res.mjs +84 -81
  64. package/src/LazyLoader.res.mjs +55 -61
  65. package/src/LoadLayer.res +77 -78
  66. package/src/LoadLayer.res.mjs +160 -189
  67. package/src/LoadManager.res +16 -21
  68. package/src/LoadManager.res.mjs +79 -84
  69. package/src/LogSelection.res +236 -68
  70. package/src/LogSelection.res.mjs +211 -141
  71. package/src/Logging.res +13 -9
  72. package/src/Logging.res.mjs +130 -143
  73. package/src/Main.res +428 -51
  74. package/src/Main.res.mjs +528 -271
  75. package/src/Persistence.res +77 -84
  76. package/src/Persistence.res.mjs +131 -132
  77. package/src/PgStorage.res +291 -167
  78. package/src/PgStorage.res.mjs +797 -817
  79. package/src/Prometheus.res +50 -58
  80. package/src/Prometheus.res.mjs +345 -373
  81. package/src/ReorgDetection.res +22 -24
  82. package/src/ReorgDetection.res.mjs +100 -106
  83. package/src/SafeCheckpointTracking.res +7 -7
  84. package/src/SafeCheckpointTracking.res.mjs +40 -43
  85. package/src/SimulateItems.res +41 -49
  86. package/src/SimulateItems.res.mjs +257 -272
  87. package/src/Sink.res +2 -2
  88. package/src/Sink.res.mjs +22 -26
  89. package/src/TableIndices.res +1 -2
  90. package/src/TableIndices.res.mjs +42 -48
  91. package/src/TestIndexer.res +196 -189
  92. package/src/TestIndexer.res.mjs +536 -536
  93. package/src/TestIndexerProxyStorage.res +15 -16
  94. package/src/TestIndexerProxyStorage.res.mjs +98 -122
  95. package/src/TestIndexerWorker.res +4 -0
  96. package/src/TestIndexerWorker.res.mjs +7 -0
  97. package/src/Throttler.res +3 -3
  98. package/src/Throttler.res.mjs +23 -24
  99. package/src/Time.res +1 -1
  100. package/src/Time.res.mjs +18 -21
  101. package/src/TopicFilter.res +3 -3
  102. package/src/TopicFilter.res.mjs +29 -30
  103. package/src/UserContext.res +93 -54
  104. package/src/UserContext.res.mjs +197 -182
  105. package/src/Utils.res +141 -86
  106. package/src/Utils.res.mjs +334 -295
  107. package/src/bindings/BigDecimal.res +0 -2
  108. package/src/bindings/BigDecimal.res.mjs +19 -23
  109. package/src/bindings/ClickHouse.res +28 -27
  110. package/src/bindings/ClickHouse.res.mjs +243 -240
  111. package/src/bindings/DateFns.res +11 -11
  112. package/src/bindings/DateFns.res.mjs +7 -7
  113. package/src/bindings/EventSource.res.mjs +2 -2
  114. package/src/bindings/Express.res +2 -5
  115. package/src/bindings/Hrtime.res +2 -2
  116. package/src/bindings/Hrtime.res.mjs +30 -32
  117. package/src/bindings/Lodash.res.mjs +1 -1
  118. package/src/bindings/NodeJs.res +14 -9
  119. package/src/bindings/NodeJs.res.mjs +20 -20
  120. package/src/bindings/Pino.res +8 -10
  121. package/src/bindings/Pino.res.mjs +40 -43
  122. package/src/bindings/Postgres.res +2 -5
  123. package/src/bindings/Postgres.res.mjs +9 -9
  124. package/src/bindings/PromClient.res +17 -2
  125. package/src/bindings/PromClient.res.mjs +30 -7
  126. package/src/bindings/SDSL.res.mjs +2 -2
  127. package/src/bindings/Viem.res +4 -4
  128. package/src/bindings/Viem.res.mjs +20 -22
  129. package/src/bindings/Vitest.res +1 -1
  130. package/src/bindings/Vitest.res.mjs +2 -2
  131. package/src/bindings/WebSocket.res +1 -1
  132. package/src/db/EntityHistory.res +9 -3
  133. package/src/db/EntityHistory.res.mjs +84 -59
  134. package/src/db/InternalTable.res +62 -60
  135. package/src/db/InternalTable.res.mjs +271 -203
  136. package/src/db/Schema.res +1 -2
  137. package/src/db/Schema.res.mjs +28 -32
  138. package/src/db/Table.res +28 -27
  139. package/src/db/Table.res.mjs +276 -292
  140. package/src/sources/EventRouter.res +21 -16
  141. package/src/sources/EventRouter.res.mjs +55 -57
  142. package/src/sources/Evm.res +17 -1
  143. package/src/sources/Evm.res.mjs +16 -8
  144. package/src/sources/EvmChain.res +15 -17
  145. package/src/sources/EvmChain.res.mjs +40 -42
  146. package/src/sources/Fuel.res +14 -1
  147. package/src/sources/Fuel.res.mjs +16 -8
  148. package/src/sources/FuelSDK.res +1 -1
  149. package/src/sources/FuelSDK.res.mjs +6 -8
  150. package/src/sources/HyperFuel.res +8 -10
  151. package/src/sources/HyperFuel.res.mjs +113 -123
  152. package/src/sources/HyperFuelClient.res.mjs +6 -7
  153. package/src/sources/HyperFuelSource.res +19 -20
  154. package/src/sources/HyperFuelSource.res.mjs +339 -356
  155. package/src/sources/HyperSync.res +11 -13
  156. package/src/sources/HyperSync.res.mjs +206 -220
  157. package/src/sources/HyperSyncClient.res +5 -7
  158. package/src/sources/HyperSyncClient.res.mjs +70 -75
  159. package/src/sources/HyperSyncHeightStream.res +8 -9
  160. package/src/sources/HyperSyncHeightStream.res.mjs +78 -86
  161. package/src/sources/HyperSyncJsonApi.res +18 -15
  162. package/src/sources/HyperSyncJsonApi.res.mjs +201 -231
  163. package/src/sources/HyperSyncSource.res +17 -21
  164. package/src/sources/HyperSyncSource.res.mjs +268 -290
  165. package/src/sources/Rpc.res +5 -5
  166. package/src/sources/Rpc.res.mjs +168 -192
  167. package/src/sources/RpcSource.res +166 -167
  168. package/src/sources/RpcSource.res.mjs +972 -1046
  169. package/src/sources/RpcWebSocketHeightStream.res +10 -11
  170. package/src/sources/RpcWebSocketHeightStream.res.mjs +131 -145
  171. package/src/sources/SimulateSource.res +1 -1
  172. package/src/sources/SimulateSource.res.mjs +35 -38
  173. package/src/sources/Source.res +1 -1
  174. package/src/sources/Source.res.mjs +3 -3
  175. package/src/sources/SourceManager.res +39 -20
  176. package/src/sources/SourceManager.res.mjs +340 -371
  177. package/src/sources/SourceManager.resi +2 -1
  178. package/src/sources/Svm.res +12 -5
  179. package/src/sources/Svm.res.mjs +44 -41
  180. package/src/tui/Tui.res +23 -12
  181. package/src/tui/Tui.res.mjs +292 -290
  182. package/src/tui/bindings/Ink.res +2 -4
  183. package/src/tui/bindings/Ink.res.mjs +35 -41
  184. package/src/tui/components/BufferedProgressBar.res +7 -7
  185. package/src/tui/components/BufferedProgressBar.res.mjs +46 -46
  186. package/src/tui/components/CustomHooks.res +1 -2
  187. package/src/tui/components/CustomHooks.res.mjs +102 -122
  188. package/src/tui/components/Messages.res +1 -2
  189. package/src/tui/components/Messages.res.mjs +38 -42
  190. package/src/tui/components/SyncETA.res +10 -11
  191. package/src/tui/components/SyncETA.res.mjs +178 -196
  192. package/src/tui/components/TuiData.res +1 -1
  193. package/src/tui/components/TuiData.res.mjs +7 -6
  194. package/src/vendored/Rest.res +52 -66
  195. package/src/vendored/Rest.res.mjs +324 -364
  196. package/svm.schema.json +67 -0
  197. package/src/Address.gen.ts +0 -8
  198. package/src/Config.gen.ts +0 -19
  199. package/src/Envio.gen.ts +0 -55
  200. package/src/EvmTypes.gen.ts +0 -6
  201. package/src/InMemoryStore.gen.ts +0 -6
  202. package/src/Internal.gen.ts +0 -64
  203. package/src/PgStorage.gen.ts +0 -10
  204. package/src/PgStorage.res.d.mts +0 -5
  205. package/src/Types.ts +0 -56
  206. package/src/bindings/BigDecimal.gen.ts +0 -14
  207. package/src/bindings/BigDecimal.res.d.mts +0 -5
  208. package/src/bindings/BigInt.gen.ts +0 -10
  209. package/src/bindings/BigInt.res +0 -70
  210. package/src/bindings/BigInt.res.d.mts +0 -5
  211. package/src/bindings/BigInt.res.mjs +0 -154
  212. package/src/bindings/Ethers.res.d.mts +0 -5
  213. package/src/bindings/Pino.gen.ts +0 -17
  214. package/src/bindings/Postgres.gen.ts +0 -8
  215. package/src/bindings/Postgres.res.d.mts +0 -5
  216. package/src/bindings/Promise.res +0 -67
  217. package/src/bindings/Promise.res.mjs +0 -26
  218. package/src/db/InternalTable.gen.ts +0 -36
  219. package/src/sources/HyperSyncClient.gen.ts +0 -19
@@ -1,5 +1,3 @@
1
- open Belt
2
-
3
1
  type evmChainConfig = {
4
2
  startBlock?: int,
5
3
  endBlock?: int,
@@ -36,30 +34,25 @@ type testIndexerState = {
36
34
  mutable processChanges: array<unknown>,
37
35
  }
38
36
 
39
- // Cast Internal.entity back to DynamicContractRegistry.t
40
- external castFromDcRegistry: Internal.entity => InternalTable.DynamicContractRegistry.t =
41
- "%identity"
37
+ // Cast Internal.entity back to EnvioAddresses.t
38
+ external castToEnvioAddresses: Internal.entity => InternalTable.EnvioAddresses.t = "%identity"
42
39
 
43
- // Convert DynamicContractRegistry.t to Internal.indexingContract
44
- let toIndexingContract = (
45
- dc: InternalTable.DynamicContractRegistry.t,
46
- ): Internal.indexingContract => {
47
- address: dc.contractAddress,
40
+ let toIndexingAddress = (dc: InternalTable.EnvioAddresses.t): Internal.indexingAddress => {
41
+ address: dc->Config.EnvioAddresses.getAddress,
48
42
  contractName: dc.contractName,
49
- startBlock: dc.registeringEventBlockNumber,
50
- registrationBlock: Some(dc.registeringEventBlockNumber),
43
+ registrationBlock: dc.registrationBlock,
51
44
  }
52
45
 
53
46
  let handleLoadByIds = (
54
47
  state: testIndexerState,
55
48
  ~tableName: string,
56
49
  ~ids: array<string>,
57
- ): Js.Json.t => {
58
- let entityDict = state.entities->Js.Dict.get(tableName)->Option.getWithDefault(Js.Dict.empty())
59
- let entityConfig = state.entityConfigs->Js.Dict.unsafeGet(tableName)
50
+ ): JSON.t => {
51
+ let entityDict = state.entities->Dict.get(tableName)->Option.getOr(Dict.make())
52
+ let entityConfig = state.entityConfigs->Dict.getUnsafe(tableName)
60
53
  let results = []
61
54
  ids->Array.forEach(id => {
62
- switch entityDict->Js.Dict.get(id) {
55
+ switch entityDict->Dict.get(id) {
63
56
  | Some(entity) =>
64
57
  // Serialize entity back to JSON for worker thread
65
58
  let jsonEntity = entity->S.reverseConvertToJsonOrThrow(entityConfig.schema)
@@ -67,24 +60,24 @@ let handleLoadByIds = (
67
60
  | None => ()
68
61
  }
69
62
  })
70
- results->Js.Json.array
63
+ results->JSON.Encode.array
71
64
  }
72
65
 
73
66
  let handleLoadByField = (
74
67
  state: testIndexerState,
75
68
  ~tableName: string,
76
69
  ~fieldName: string,
77
- ~fieldValue: Js.Json.t,
70
+ ~fieldValue: JSON.t,
78
71
  ~operator: Persistence.operator,
79
- ): Js.Json.t => {
80
- let entityDict = state.entities->Js.Dict.get(tableName)->Option.getWithDefault(Js.Dict.empty())
81
- let entityConfig = state.entityConfigs->Js.Dict.unsafeGet(tableName)
72
+ ): JSON.t => {
73
+ let entityDict = state.entities->Dict.get(tableName)->Option.getOr(Dict.make())
74
+ let entityConfig = state.entityConfigs->Dict.getUnsafe(tableName)
82
75
  let results = []
83
76
 
84
77
  // Get the field schema from the entity's table to properly parse the JSON field value
85
78
  let fieldSchema = switch entityConfig.table->Table.getFieldByName(fieldName) {
86
79
  | Some(Table.Field({fieldSchema})) => fieldSchema
87
- | _ => Js.Exn.raiseError(`Field ${fieldName} not found in entity ${tableName}`)
80
+ | _ => JsError.throwWithMessage(`Field ${fieldName} not found in entity ${tableName}`)
88
81
  }
89
82
 
90
83
  // Parse JSON field value to typed value using the field's schema
@@ -93,11 +86,11 @@ let handleLoadByField = (
93
86
  // Compare using TableIndices.FieldValue logic (same approach as InMemoryTable)
94
87
  // This properly handles bigint and BigDecimal comparisons
95
88
  entityDict
96
- ->Js.Dict.values
89
+ ->Dict.valuesToArray
97
90
  ->Array.forEach(entity => {
98
91
  // Cast entity to dict of field values (same approach as InMemoryTable)
99
92
  let entityAsDict = entity->(Utils.magic: Internal.entity => dict<TableIndices.FieldValue.t>)
100
- switch entityAsDict->Js.Dict.get(fieldName) {
93
+ switch entityAsDict->Dict.get(fieldName) {
101
94
  | Some(entityFieldValue) => {
102
95
  let matches = switch operator {
103
96
  | #"=" => entityFieldValue->TableIndices.FieldValue.eq(parsedFieldValue)
@@ -114,7 +107,7 @@ let handleLoadByField = (
114
107
  }
115
108
  })
116
109
 
117
- results->Js.Json.array
110
+ results->JSON.Encode.array
118
111
  }
119
112
 
120
113
  let handleWriteBatch = (
@@ -127,17 +120,17 @@ let handleWriteBatch = (
127
120
  ): unit => {
128
121
  // Group entity changes by checkpointId
129
122
  // checkpointId -> entityName -> entityChange
130
- let changesByCheckpoint: dict<dict<entityChange>> = Js.Dict.empty()
123
+ let changesByCheckpoint: dict<dict<entityChange>> = Dict.make()
131
124
 
132
125
  updatedEntities->Array.forEach(({entityName, updates}) => {
133
- let entityDict = switch state.entities->Js.Dict.get(entityName) {
126
+ let entityDict = switch state.entities->Dict.get(entityName) {
134
127
  | Some(dict) => dict
135
128
  | None =>
136
- let dict = Js.Dict.empty()
137
- state.entities->Js.Dict.set(entityName, dict)
129
+ let dict = Dict.make()
130
+ state.entities->Dict.set(entityName, dict)
138
131
  dict
139
132
  }
140
- let entityConfig = state.entityConfigs->Js.Dict.unsafeGet(entityName)
133
+ let entityConfig = state.entityConfigs->Dict.getUnsafe(entityName)
141
134
 
142
135
  updates->Array.forEach(update => {
143
136
  // Helper to process a single change (Set or Delete)
@@ -149,44 +142,44 @@ let handleWriteBatch = (
149
142
  let parsedEntity = entity->S.parseOrThrow(entityConfig.schema)
150
143
 
151
144
  // Update entities dict with parsed entity for load operations
152
- entityDict->Js.Dict.set(entityId, parsedEntity)
145
+ entityDict->Dict.set(entityId, parsedEntity)
153
146
 
154
147
  // Track change by checkpoint
155
148
  let checkpointKey = checkpointId->BigInt.toString
156
- let entityChanges = switch changesByCheckpoint->Js.Dict.get(checkpointKey) {
149
+ let entityChanges = switch changesByCheckpoint->Dict.get(checkpointKey) {
157
150
  | Some(changes) => changes
158
151
  | None =>
159
- let changes = Js.Dict.empty()
160
- changesByCheckpoint->Js.Dict.set(checkpointKey, changes)
152
+ let changes = Dict.make()
153
+ changesByCheckpoint->Dict.set(checkpointKey, changes)
161
154
  changes
162
155
  }
163
- let entityChange = switch entityChanges->Js.Dict.get(entityName) {
156
+ let entityChange = switch entityChanges->Dict.get(entityName) {
164
157
  | Some(change) => change
165
158
  | None =>
166
159
  let change = {sets: [], deleted: []}
167
- entityChanges->Js.Dict.set(entityName, change)
160
+ entityChanges->Dict.set(entityName, change)
168
161
  change
169
162
  }
170
163
  entityChange.sets->Array.push(parsedEntity->Utils.magic)->ignore
171
164
 
172
165
  | Delete({entityId, checkpointId}) =>
173
166
  // Update entities dict for load operations
174
- Js.Dict.unsafeDeleteKey(entityDict->Obj.magic, entityId)
167
+ Dict.delete(entityDict->Obj.magic, entityId)
175
168
 
176
169
  // Track change by checkpoint
177
170
  let checkpointKey = checkpointId->BigInt.toString
178
- let entityChanges = switch changesByCheckpoint->Js.Dict.get(checkpointKey) {
171
+ let entityChanges = switch changesByCheckpoint->Dict.get(checkpointKey) {
179
172
  | Some(changes) => changes
180
173
  | None =>
181
- let changes = Js.Dict.empty()
182
- changesByCheckpoint->Js.Dict.set(checkpointKey, changes)
174
+ let changes = Dict.make()
175
+ changesByCheckpoint->Dict.set(checkpointKey, changes)
183
176
  changes
184
177
  }
185
- let entityChange = switch entityChanges->Js.Dict.get(entityName) {
178
+ let entityChange = switch entityChanges->Dict.get(entityName) {
186
179
  | Some(change) => change
187
180
  | None =>
188
181
  let change = {sets: [], deleted: []}
189
- entityChanges->Js.Dict.set(entityName, change)
182
+ entityChanges->Dict.set(entityName, change)
190
183
  change
191
184
  }
192
185
  entityChange.deleted->Array.push(entityId)->ignore
@@ -206,96 +199,97 @@ let handleWriteBatch = (
206
199
  // Build combined checkpoint + entity changes objects
207
200
  for i in 0 to checkpointIds->Array.length - 1 {
208
201
  let checkpointId = checkpointIds->Array.getUnsafe(i)
209
- let change: dict<unknown> = Js.Dict.empty()
202
+ let change: dict<unknown> = Dict.make()
210
203
 
211
204
  // Update progress tracking from checkpoint data
212
- state.progressBlockByChain->Js.Dict.set(
205
+ state.progressBlockByChain->Dict.set(
213
206
  checkpointChainIds->Array.getUnsafe(i)->Int.toString,
214
207
  checkpointBlockNumbers->Array.getUnsafe(i),
215
208
  )
216
209
 
217
210
  // Add checkpoint metadata
218
- change->Js.Dict.set("block", checkpointBlockNumbers->Array.getUnsafe(i)->Utils.magic)
219
- change->Js.Dict.set("chainId", checkpointChainIds->Array.getUnsafe(i)->Utils.magic)
220
- change->Js.Dict.set(
221
- "eventsProcessed",
222
- checkpointEventsProcessed->Array.getUnsafe(i)->Utils.magic,
223
- )
211
+ change->Dict.set("block", checkpointBlockNumbers->Array.getUnsafe(i)->Utils.magic)
212
+ change->Dict.set("chainId", checkpointChainIds->Array.getUnsafe(i)->Utils.magic)
213
+ change->Dict.set("eventsProcessed", checkpointEventsProcessed->Array.getUnsafe(i)->Utils.magic)
224
214
 
225
215
  // Add entity changes for this checkpoint
226
216
  let checkpointKey = checkpointId->BigInt.toString
227
- switch changesByCheckpoint->Js.Dict.get(checkpointKey) {
217
+ switch changesByCheckpoint->Dict.get(checkpointKey) {
228
218
  | Some(entityChanges) =>
229
219
  entityChanges
230
- ->Js.Dict.entries
220
+ ->Dict.toArray
231
221
  ->Array.forEach(((entityName, {sets, deleted})) => {
232
- // Transform dynamic_contract_registry to addresses with simplified structure
233
- if entityName === InternalTable.DynamicContractRegistry.name {
234
- let entityObj: dict<unknown> = Js.Dict.empty()
222
+ // Transform envio_addresses to addresses with simplified structure
223
+ if entityName === InternalTable.EnvioAddresses.name {
224
+ let entityObj: dict<unknown> = Dict.make()
235
225
  if sets->Array.length > 0 {
236
226
  // Transform sets to simplified {address, contract} objects
237
227
  let simplifiedSets = sets->Array.map(entity => {
238
- let dc = entity->Utils.magic->castFromDcRegistry
239
- {"address": dc.contractAddress, "contract": dc.contractName}
228
+ let dc = entity->Utils.magic->castToEnvioAddresses
229
+ {"address": dc->Config.EnvioAddresses.getAddress, "contract": dc.contractName}
240
230
  })
241
- entityObj->Js.Dict.set("sets", simplifiedSets->Utils.magic)
231
+ entityObj->Dict.set(
232
+ "sets",
233
+ simplifiedSets->(
234
+ Utils.magic: array<{"address": Address.t, "contract": string}> => unknown
235
+ ),
236
+ )
242
237
  }
243
238
  // Note: deleted is not relevant for addresses since we use address string directly
244
- change->Js.Dict.set("addresses", entityObj->Utils.magic)
239
+ change->Dict.set("addresses", entityObj->(Utils.magic: dict<unknown> => unknown))
245
240
  } else {
246
- let entityObj: dict<unknown> = Js.Dict.empty()
241
+ let entityObj: dict<unknown> = Dict.make()
247
242
  if sets->Array.length > 0 {
248
- entityObj->Js.Dict.set("sets", sets->Utils.magic)
243
+ entityObj->Dict.set("sets", sets->(Utils.magic: array<unknown> => unknown))
249
244
  }
250
245
  if deleted->Array.length > 0 {
251
- entityObj->Js.Dict.set("deleted", deleted->Utils.magic)
246
+ entityObj->Dict.set("deleted", deleted->(Utils.magic: array<string> => unknown))
252
247
  }
253
- change->Js.Dict.set(entityName, entityObj->Utils.magic)
248
+ change->Dict.set(entityName, entityObj->(Utils.magic: dict<unknown> => unknown))
254
249
  }
255
250
  })
256
251
  | None => ()
257
252
  }
258
253
 
259
- state.processChanges->Array.push(change->Utils.magic)->ignore
254
+ state.processChanges
255
+ ->Array.push(change->(Utils.magic: dict<unknown> => unknown))
256
+ ->ignore
260
257
  }
261
258
  }
262
259
 
263
260
  let makeInitialState = (
264
261
  ~config: Config.t,
265
- ~processConfigChains: Js.Dict.t<chainConfig>,
266
- ~dynamicContractsByChain: dict<array<Internal.indexingContract>>,
262
+ ~processConfigChains: dict<chainConfig>,
263
+ ~indexingAddressesByChain: dict<array<Internal.indexingAddress>>,
267
264
  ): Persistence.initialState => {
268
- let chainKeys = processConfigChains->Js.Dict.keys
265
+ let chainKeys = processConfigChains->Dict.keysToArray
269
266
  let chains = chainKeys->Array.map(chainIdStr => {
270
- let chainId = chainIdStr->Int.fromString->Option.getWithDefault(0)
267
+ let chainId = chainIdStr->Int.fromString->Option.getOr(0)
271
268
  let chain = ChainMap.Chain.makeUnsafe(~chainId)
272
269
 
273
270
  if !(config.chainMap->ChainMap.has(chain)) {
274
- Js.Exn.raiseError(`Chain ${chainIdStr} is not configured in config.yaml`)
271
+ JsError.throwWithMessage(`Chain ${chainIdStr} is not configured in config.yaml`)
275
272
  }
276
273
 
277
- let processChainConfig = processConfigChains->Js.Dict.unsafeGet(chainIdStr)
278
- let dynamicContracts =
279
- dynamicContractsByChain
280
- ->Js.Dict.get(chainIdStr)
281
- ->Option.getWithDefault([])
274
+ let processChainConfig = processConfigChains->Dict.getUnsafe(chainIdStr)
275
+ let indexingAddresses = indexingAddressesByChain->Dict.get(chainIdStr)->Option.getOr([])
282
276
  {
283
277
  Persistence.id: chainId,
284
278
  startBlock: processChainConfig.startBlock,
285
279
  endBlock: processChainConfig.endBlock,
286
- sourceBlockNumber: processChainConfig.endBlock->Option.getWithDefault(0),
280
+ sourceBlockNumber: processChainConfig.endBlock->Option.getOr(0),
287
281
  maxReorgDepth: 0, // No reorg support in test indexer
288
282
  progressBlockNumber: -1,
289
283
  numEventsProcessed: 0.,
290
284
  firstEventBlockNumber: None,
291
285
  timestampCaughtUpToHeadOrEndblock: None,
292
- dynamicContracts,
286
+ indexingAddresses,
293
287
  }
294
288
  })
295
289
 
296
290
  {
297
291
  cleanRun: true,
298
- cache: Js.Dict.empty(),
292
+ cache: Dict.make(),
299
293
  chains,
300
294
  checkpointId: InternalTable.Checkpoints.initialCheckpointId,
301
295
  reorgCheckpoints: [],
@@ -305,7 +299,7 @@ let makeInitialState = (
305
299
  type rawChainConfig = {
306
300
  startBlock: option<int>,
307
301
  endBlock: option<int>,
308
- simulate: option<array<Js.Json.t>>,
302
+ simulate: option<array<JSON.t>>,
309
303
  }
310
304
 
311
305
  let rawChainConfigSchema = S.schema(s => {
@@ -321,25 +315,23 @@ let processConfigSchema = S.schema(s =>
321
315
  )
322
316
 
323
317
  let getSimulateEndBlock = (
324
- ~simulateItems: array<Js.Json.t>,
318
+ ~simulateItems: array<JSON.t>,
325
319
  ~config: Config.t,
326
320
  ~startBlock: int,
327
321
  ): int => {
328
322
  let maxBlock = ref(startBlock)
329
323
  simulateItems->Array.forEach(rawJson => {
330
- let blockJson: option<Js.Json.t> =
331
- (rawJson->(Utils.magic: Js.Json.t => {..}))["block"]
332
- ->(Utils.magic: 'a => Js.Nullable.t<Js.Json.t>)
333
- ->Js.Nullable.toOption
324
+ let blockJson: option<JSON.t> =
325
+ (rawJson->(Utils.magic: JSON.t => {..}))["block"]
326
+ ->(Utils.magic: 'a => Nullable.t<JSON.t>)
327
+ ->Nullable.toOption
334
328
  switch blockJson {
335
329
  | Some(bj) =>
336
- let blockDict = bj->(Utils.magic: Js.Json.t => Js.Dict.t<Js.Json.t>)
330
+ let blockDict = bj->(Utils.magic: JSON.t => dict<JSON.t>)
337
331
  let n: option<int> =
338
332
  blockDict
339
- ->Js.Dict.get(config.ecosystem.blockNumberName)
340
- ->Option.flatMap(v =>
341
- v->(Utils.magic: Js.Json.t => Js.Nullable.t<int>)->Js.Nullable.toOption
342
- )
333
+ ->Dict.get(config.ecosystem.blockNumberName)
334
+ ->Option.flatMap(v => v->(Utils.magic: JSON.t => Nullable.t<int>)->Nullable.toOption)
343
335
  switch n {
344
336
  | Some(v) if v > maxBlock.contents => maxBlock := v
345
337
  | _ => ()
@@ -360,11 +352,12 @@ let parseBlockRange = (
360
352
  ): chainConfig => {
361
353
  let chainId = switch chainIdStr->Int.fromString {
362
354
  | Some(id) => id
363
- | None => Js.Exn.raiseError(`Invalid chain ID "${chainIdStr}": expected a numeric chain ID`)
355
+ | None =>
356
+ JsError.throwWithMessage(`Invalid chain ID "${chainIdStr}": expected a numeric chain ID`)
364
357
  }
365
358
  let chain = ChainMap.Chain.makeUnsafe(~chainId)
366
359
  if !(config.chainMap->ChainMap.has(chain)) {
367
- Js.Exn.raiseError(`Chain ${chainIdStr} is not configured in config.yaml`)
360
+ JsError.throwWithMessage(`Chain ${chainIdStr} is not configured in config.yaml`)
368
361
  }
369
362
  let configChain = config.chainMap->ChainMap.get(chain)
370
363
 
@@ -382,7 +375,7 @@ let parseBlockRange = (
382
375
  | None if rawChainConfig.simulate->Option.isSome =>
383
376
  Some(
384
377
  getSimulateEndBlock(
385
- ~simulateItems=rawChainConfig.simulate->Option.getExn,
378
+ ~simulateItems=rawChainConfig.simulate->Option.getOrThrow,
386
379
  ~config,
387
380
  ~startBlock,
388
381
  ),
@@ -391,7 +384,7 @@ let parseBlockRange = (
391
384
  }
392
385
 
393
386
  if startBlock < configChain.startBlock {
394
- Js.Exn.raiseError(
387
+ JsError.throwWithMessage(
395
388
  `Invalid block range for chain ${chainIdStr}: startBlock (${startBlock->Int.toString}) is less than config.startBlock (${configChain.startBlock->Int.toString}). ` ++
396
389
  `Either use startBlock >= ${configChain.startBlock->Int.toString} or create a new test indexer with createTestIndexer().`,
397
390
  )
@@ -399,7 +392,7 @@ let parseBlockRange = (
399
392
 
400
393
  switch (endBlock, configChain.endBlock) {
401
394
  | (Some(eb), Some(configEndBlock)) if eb > configEndBlock =>
402
- Js.Exn.raiseError(
395
+ JsError.throwWithMessage(
403
396
  `Invalid block range for chain ${chainIdStr}: endBlock (${eb->Int.toString}) exceeds config.endBlock (${configEndBlock->Int.toString}). ` ++
404
397
  `Either use endBlock <= ${configEndBlock->Int.toString} or create a new test indexer with createTestIndexer().`,
405
398
  )
@@ -408,7 +401,7 @@ let parseBlockRange = (
408
401
 
409
402
  switch progressBlock {
410
403
  | Some(prevEndBlock) if startBlock <= prevEndBlock =>
411
- Js.Exn.raiseError(
404
+ JsError.throwWithMessage(
412
405
  `Invalid block range for chain ${chainIdStr}: startBlock (${startBlock->Int.toString}) must be greater than previously processed endBlock (${prevEndBlock->Int.toString}). ` ++
413
406
  `Either use startBlock > ${prevEndBlock->Int.toString} or create a new test indexer with createTestIndexer().`,
414
407
  )
@@ -426,13 +419,12 @@ let getEntityFromState = (
426
419
  ~methodName: string,
427
420
  ): option<Internal.entity> => {
428
421
  if state.processInProgress {
429
- Js.Exn.raiseError(
422
+ JsError.throwWithMessage(
430
423
  `Cannot call ${entityConfig.name}.${methodName}() while indexer.process() is running. ` ++ "Wait for process() to complete before accessing entities directly.",
431
424
  )
432
425
  }
433
- let entityDict =
434
- state.entities->Js.Dict.get(entityConfig.name)->Option.getWithDefault(Js.Dict.empty())
435
- entityDict->Js.Dict.get(entityId)
426
+ let entityDict = state.entities->Dict.get(entityConfig.name)->Option.getOr(Dict.make())
427
+ entityDict->Dict.get(entityId)
436
428
  }
437
429
 
438
430
  let makeEntityGet = (~state: testIndexerState, ~entityConfig: Internal.entityConfig): (
@@ -454,7 +446,7 @@ let makeEntityGetOrThrow = (~state: testIndexerState, ~entityConfig: Internal.en
454
446
  | Some(m) => m
455
447
  | None => `Entity ${entityConfig.name} with id ${entityId} not found`
456
448
  }
457
- Js.Exn.raiseError(msg)
449
+ JsError.throwWithMessage(msg)
458
450
  }
459
451
  }
460
452
  }
@@ -464,18 +456,18 @@ let makeEntitySet = (~state: testIndexerState, ~entityConfig: Internal.entityCon
464
456
  ) => {
465
457
  entity => {
466
458
  if state.processInProgress {
467
- Js.Exn.raiseError(
459
+ JsError.throwWithMessage(
468
460
  `Cannot call ${entityConfig.name}.set() while indexer.process() is running. ` ++ "Wait for process() to complete before modifying entities directly.",
469
461
  )
470
462
  }
471
- let entityDict = switch state.entities->Js.Dict.get(entityConfig.name) {
463
+ let entityDict = switch state.entities->Dict.get(entityConfig.name) {
472
464
  | Some(dict) => dict
473
465
  | None =>
474
- let dict = Js.Dict.empty()
475
- state.entities->Js.Dict.set(entityConfig.name, dict)
466
+ let dict = Dict.make()
467
+ state.entities->Dict.set(entityConfig.name, dict)
476
468
  dict
477
469
  }
478
- entityDict->Js.Dict.set(entity.id, entity)
470
+ entityDict->Dict.set(entity.id, entity)
479
471
  }
480
472
  }
481
473
 
@@ -484,13 +476,12 @@ let makeEntityGetAll = (~state: testIndexerState, ~entityConfig: Internal.entity
484
476
  ) => {
485
477
  () => {
486
478
  if state.processInProgress {
487
- Js.Exn.raiseError(
479
+ JsError.throwWithMessage(
488
480
  `Cannot call ${entityConfig.name}.getAll() while indexer.process() is running. ` ++ "Wait for process() to complete before accessing entities directly.",
489
481
  )
490
482
  }
491
- let entityDict =
492
- state.entities->Js.Dict.get(entityConfig.name)->Option.getWithDefault(Js.Dict.empty())
493
- Promise.resolve(entityDict->Js.Dict.values)
483
+ let entityDict = state.entities->Dict.get(entityConfig.name)->Option.getOr(Dict.make())
484
+ Promise.resolve(entityDict->Dict.valuesToArray)
494
485
  }
495
486
  }
496
487
 
@@ -505,36 +496,57 @@ type workerData = {
505
496
  chainId: int,
506
497
  startBlock: int,
507
498
  endBlock: option<int>,
508
- simulate: option<array<Js.Json.t>>,
499
+ simulate: option<array<JSON.t>>,
509
500
  initialState: Persistence.initialState,
510
501
  }
511
502
 
512
- let makeCreateTestIndexer = (
513
- ~config: Config.t,
514
- ~workerPath: string,
515
- ~allEntities: array<Internal.entityConfig>,
516
- ): (unit => t<'processConfig>) => {
503
+ let makeCreateTestIndexer = (~config: Config.t, ~workerPath: string): (
504
+ unit => t<'processConfig>
505
+ ) => {
517
506
  () => {
518
- let entities = Js.Dict.empty()
519
- let entityConfigs = Js.Dict.empty()
507
+ let allEntities = config.allEntities
508
+ let entities = Dict.make()
509
+ let entityConfigs = Dict.make()
520
510
  allEntities->Array.forEach(entityConfig => {
521
- entities->Js.Dict.set(entityConfig.name, Js.Dict.empty())
522
- entityConfigs->Js.Dict.set(entityConfig.name, entityConfig)
511
+ entities->Dict.set(entityConfig.name, Dict.make())
512
+ entityConfigs->Dict.set(entityConfig.name, entityConfig)
523
513
  })
514
+
515
+ // Populate config addresses into the entity dict, mirroring PgStorage.initialize
516
+ let envioAddressesDict = entities->Dict.getUnsafe(InternalTable.EnvioAddresses.name)
517
+ config.chainMap
518
+ ->ChainMap.values
519
+ ->Array.forEach(chainConfig => {
520
+ chainConfig.contracts->Array.forEach(contract => {
521
+ contract.addresses->Array.forEach(
522
+ address => {
523
+ let entity: InternalTable.EnvioAddresses.t = {
524
+ id: Config.EnvioAddresses.makeId(~chainId=chainConfig.id, ~address),
525
+ chainId: chainConfig.id,
526
+ contractName: contract.name,
527
+ registrationBlock: -1,
528
+ registrationLogIndex: -1,
529
+ }
530
+ envioAddressesDict->Dict.set(entity.id, entity->Config.EnvioAddresses.castToInternal)
531
+ },
532
+ )
533
+ })
534
+ })
535
+
524
536
  let state = {
525
537
  processInProgress: false,
526
- progressBlockByChain: Js.Dict.empty(),
538
+ progressBlockByChain: Dict.make(),
527
539
  entities,
528
540
  entityConfigs,
529
541
  processChanges: [],
530
542
  }
531
543
 
532
544
  // Build entity operations for each user entity
533
- let entityOpsDict: Js.Dict.t<entityOperations> = Js.Dict.empty()
545
+ let entityOpsDict: dict<entityOperations> = Dict.make()
534
546
  allEntities->Array.forEach(entityConfig => {
535
- // Only create ops for user entities (not internal tables like dynamic_contract_registry)
536
- if entityConfig.name !== InternalTable.DynamicContractRegistry.name {
537
- entityOpsDict->Js.Dict.set(
547
+ // Only create ops for user entities (not internal tables like envio_addresses)
548
+ if entityConfig.name !== InternalTable.EnvioAddresses.name {
549
+ entityOpsDict->Dict.set(
538
550
  entityConfig.name,
539
551
  {
540
552
  get: makeEntityGet(~state, ~entityConfig),
@@ -553,7 +565,7 @@ let makeCreateTestIndexer = (
553
565
  ->ChainMap.values
554
566
  ->Array.forEach(chainConfig => {
555
567
  let chainIdStr = chainConfig.id->Int.toString
556
- chainIds->Js.Array2.push(chainConfig.id)->ignore
568
+ chainIds->Array.push(chainConfig.id)->ignore
557
569
 
558
570
  let chainObj = Utils.Object.createNullObject()
559
571
  chainObj
@@ -582,22 +594,20 @@ let makeCreateTestIndexer = (
582
594
  enumerable: true,
583
595
  get: () => {
584
596
  if state.processInProgress {
585
- Js.Exn.raiseError(
597
+ JsError.throwWithMessage(
586
598
  `Cannot access ${contract.name}.addresses while indexer.process() is running. ` ++ "Wait for process() to complete before reading contract addresses.",
587
599
  )
588
600
  }
589
- // Start with static config addresses
590
- let addresses = contract.addresses->Array.copy
591
- // Add accumulated dynamic contract addresses
592
- switch state.entities->Js.Dict.get(InternalTable.DynamicContractRegistry.name) {
601
+ let addresses = []
602
+ switch state.entities->Dict.get(InternalTable.EnvioAddresses.name) {
593
603
  | Some(dcDict) =>
594
604
  dcDict
595
- ->Js.Dict.values
605
+ ->Dict.valuesToArray
596
606
  ->Array.forEach(
597
607
  entity => {
598
- let dc = entity->castFromDcRegistry
608
+ let dc = entity->castToEnvioAddresses
599
609
  if dc.contractName === contract.name && dc.chainId === chainConfig.id {
600
- addresses->Array.push(dc.contractAddress)->ignore
610
+ addresses->Array.push(dc->Config.EnvioAddresses.getAddress)->ignore
601
611
  }
602
612
  },
603
613
  )
@@ -632,22 +642,22 @@ let makeCreateTestIndexer = (
632
642
  })
633
643
 
634
644
  // Build the result object with process + entity operations + chain info
635
- let result: Js.Dict.t<unknown> = Js.Dict.empty()
636
- result->Js.Dict.set("chainIds", chainIds->(Utils.magic: array<int> => unknown))
637
- result->Js.Dict.set("chains", chains->(Utils.magic: {..} => unknown))
645
+ let result: dict<unknown> = Dict.make()
646
+ result->Dict.set("chainIds", chainIds->(Utils.magic: array<int> => unknown))
647
+ result->Dict.set("chains", chains->(Utils.magic: {..} => unknown))
638
648
  entityOpsDict
639
- ->Js.Dict.entries
649
+ ->Dict.toArray
640
650
  ->Array.forEach(((name, ops)) => {
641
- result->Js.Dict.set(name, ops->(Utils.magic: entityOperations => unknown))
651
+ result->Dict.set(name, ops->(Utils.magic: entityOperations => unknown))
642
652
  })
643
653
 
644
- result->Js.Dict.set(
654
+ result->Dict.set(
645
655
  "process",
646
656
  (
647
657
  processConfig => {
648
658
  // Check if already processing
649
659
  if state.processInProgress {
650
- Js.Exn.raiseError(
660
+ JsError.throwWithMessage(
651
661
  "createTestIndexer process is already running. Only one process call is allowed at a time",
652
662
  )
653
663
  }
@@ -655,40 +665,40 @@ let makeCreateTestIndexer = (
655
665
  // Parse and validate processConfig
656
666
  let parsedConfig = try processConfig->S.parseOrThrow(processConfigSchema) catch {
657
667
  | S.Raised(exn) =>
658
- Js.Exn.raiseError(
668
+ JsError.throwWithMessage(
659
669
  `Invalid processConfig: ${exn->Utils.prettifyExn->(Utils.magic: exn => string)}`,
660
670
  )
661
671
  }
662
672
  let rawChains = parsedConfig["chains"]
663
- let chainKeys = rawChains->Js.Dict.keys
673
+ let chainKeys = rawChains->Dict.keysToArray
664
674
 
665
675
  if chainKeys->Array.length === 0 {
666
- Js.Exn.raiseError("createTestIndexer requires at least one chain to be defined")
676
+ JsError.throwWithMessage("createTestIndexer requires at least one chain to be defined")
667
677
  }
668
678
 
669
679
  // Sort chain keys by chain ID for deterministic ordering
670
- let sortedChainKeys =
671
- chainKeys
672
- ->Array.copy
673
- ->Js.Array2.sortInPlaceWith((a, b) => {
674
- let aId = a->Int.fromString->Option.getWithDefault(0)
675
- let bId = b->Int.fromString->Option.getWithDefault(0)
676
- aId - bId
677
- })
680
+ let sortedChainKeys = chainKeys->Array.copy
681
+ sortedChainKeys->Array.sort((a, b) => {
682
+ let aId = a->Int.fromString->Option.getOr(0)
683
+ let bId = b->Int.fromString->Option.getOr(0)
684
+ Int.compare(aId, bId)
685
+ })
678
686
 
679
687
  // Parse and validate all chain configs upfront before starting any workers
680
688
  let chainEntries = sortedChainKeys->Array.map(chainIdStr => {
681
- let rawChainConfig = rawChains->Js.Dict.unsafeGet(chainIdStr)
689
+ let rawChainConfig = rawChains->Dict.getUnsafe(chainIdStr)
682
690
  let chainId = switch chainIdStr->Int.fromString {
683
691
  | Some(id) => id
684
692
  | None =>
685
- Js.Exn.raiseError(`Invalid chain ID "${chainIdStr}": expected a numeric chain ID`)
693
+ JsError.throwWithMessage(
694
+ `Invalid chain ID "${chainIdStr}": expected a numeric chain ID`,
695
+ )
686
696
  }
687
697
  let processChainConfig = parseBlockRange(
688
698
  ~chainIdStr,
689
699
  ~config,
690
700
  ~rawChainConfig,
691
- ~progressBlock=state.progressBlockByChain->Js.Dict.get(chainIdStr),
701
+ ~progressBlock=state.progressBlockByChain->Dict.get(chainIdStr),
692
702
  )
693
703
  (chainIdStr, chainId, rawChainConfig, processChainConfig)
694
704
  })
@@ -703,26 +713,26 @@ let makeCreateTestIndexer = (
703
713
  processChainConfig,
704
714
  )) => {
705
715
  // Build initialState from resolved block range
706
- let chains: Js.Dict.t<chainConfig> = Js.Dict.empty()
707
- chains->Js.Dict.set(chainIdStr, processChainConfig)
716
+ let chains: dict<chainConfig> = Dict.make()
717
+ chains->Dict.set(chainIdStr, processChainConfig)
708
718
 
709
719
  // Extract dynamic contracts from state.entities for each chain
710
- let dynamicContractsByChain: dict<array<Internal.indexingContract>> = Js.Dict.empty()
711
- switch state.entities->Js.Dict.get(InternalTable.DynamicContractRegistry.name) {
720
+ let indexingAddressesByChain: dict<array<Internal.indexingAddress>> = Dict.make()
721
+ switch state.entities->Dict.get(InternalTable.EnvioAddresses.name) {
712
722
  | Some(dcDict) =>
713
723
  dcDict
714
- ->Js.Dict.values
724
+ ->Dict.valuesToArray
715
725
  ->Array.forEach(entity => {
716
- let dc = entity->castFromDcRegistry
726
+ let dc = entity->castToEnvioAddresses
717
727
  let dcChainIdStr = dc.chainId->Int.toString
718
- let contracts = switch dynamicContractsByChain->Js.Dict.get(dcChainIdStr) {
728
+ let contracts = switch indexingAddressesByChain->Dict.get(dcChainIdStr) {
719
729
  | Some(arr) => arr
720
730
  | None =>
721
731
  let arr = []
722
- dynamicContractsByChain->Js.Dict.set(dcChainIdStr, arr)
732
+ indexingAddressesByChain->Dict.set(dcChainIdStr, arr)
723
733
  arr
724
734
  }
725
- contracts->Array.push(dc->toIndexingContract)->ignore
735
+ contracts->Array.push(dc->toIndexingAddress)->ignore
726
736
  })
727
737
  | None => ()
728
738
  }
@@ -730,7 +740,7 @@ let makeCreateTestIndexer = (
730
740
  let initialState = makeInitialState(
731
741
  ~config,
732
742
  ~processConfigChains=chains,
733
- ~dynamicContractsByChain,
743
+ ~indexingAddressesByChain,
734
744
  )
735
745
 
736
746
  Promise.make((resolve, reject) => {
@@ -745,13 +755,17 @@ let makeCreateTestIndexer = (
745
755
  NodeJs.WorkerThreads.makeWorker(
746
756
  workerPath,
747
757
  {
748
- workerData: workerData->(Utils.magic: workerData => Js.Json.t),
758
+ workerData: workerData->(Utils.magic: workerData => JSON.t),
759
+ // Explicitly forward parent env so handlers running in
760
+ // the worker observe the same environment as the test
761
+ // process (e.g. E2E_EXPECTED_END_BLOCK).
762
+ env: %raw(`process.env`),
749
763
  },
750
764
  )
751
765
  } catch {
752
766
  | exn =>
753
767
  reject(exn->Utils.magic)
754
- raise(exn)
768
+ throw(exn)
755
769
  }
756
770
 
757
771
  // Handle messages from worker
@@ -789,7 +803,7 @@ let makeCreateTestIndexer = (
789
803
  ~checkpointBlockNumbers,
790
804
  ~checkpointEventsProcessed,
791
805
  )
792
- Js.Json.null->respond
806
+ JSON.Encode.null->respond
793
807
  }
794
808
  })
795
809
 
@@ -831,21 +845,21 @@ let makeCreateTestIndexer = (
831
845
  )->(Utils.magic: ('a => promise<processResult>) => unknown),
832
846
  )
833
847
 
834
- result->(Utils.magic: Js.Dict.t<unknown> => t<'processConfig>)
848
+ result->(Utils.magic: dict<unknown> => t<'processConfig>)
835
849
  }
836
850
  }
837
851
 
838
- let initTestWorker = (~makeGeneratedConfig: unit => Config.t) => {
852
+ let initTestWorker = () => {
839
853
  if NodeJs.WorkerThreads.isMainThread {
840
- Js.Exn.raiseError("initTestWorker must be called from a worker thread")
854
+ JsError.throwWithMessage("initTestWorker must be called from a worker thread")
841
855
  }
842
856
 
843
- let parentPort = switch NodeJs.WorkerThreads.parentPort->Js.Nullable.toOption {
857
+ let parentPort = switch NodeJs.WorkerThreads.parentPort->Nullable.toOption {
844
858
  | Some(port) => port
845
- | None => Js.Exn.raiseError("initTestWorker: No parent port available")
859
+ | None => JsError.throwWithMessage("initTestWorker: No parent port available")
846
860
  }
847
861
 
848
- let workerData: option<workerData> = NodeJs.WorkerThreads.workerData->Js.Nullable.toOption
862
+ let workerData: option<workerData> = NodeJs.WorkerThreads.workerData->Nullable.toOption
849
863
  switch workerData {
850
864
  | Some({chainId, startBlock, endBlock, simulate, initialState}) =>
851
865
  let chainIdStr = chainId->Int.toString
@@ -854,29 +868,28 @@ let initTestWorker = (~makeGeneratedConfig: unit => Config.t) => {
854
868
  let exitAfterFirstEventBlock = endBlock->Option.isNone
855
869
 
856
870
  // Build processConfig JSON for SimulateItems.patchConfig
857
- let resolvedChainDict: Js.Dict.t<unknown> = Js.Dict.empty()
858
- resolvedChainDict->Js.Dict.set("startBlock", startBlock->(Utils.magic: int => unknown))
871
+ let resolvedChainDict: dict<unknown> = Dict.make()
872
+ resolvedChainDict->Dict.set("startBlock", startBlock->(Utils.magic: int => unknown))
859
873
  switch endBlock {
860
- | Some(eb) => resolvedChainDict->Js.Dict.set("endBlock", eb->(Utils.magic: int => unknown))
874
+ | Some(eb) => resolvedChainDict->Dict.set("endBlock", eb->(Utils.magic: int => unknown))
861
875
  | None => ()
862
876
  }
863
877
  switch simulate {
864
- | Some(s) =>
865
- resolvedChainDict->Js.Dict.set("simulate", s->(Utils.magic: array<Js.Json.t> => unknown))
878
+ | Some(s) => resolvedChainDict->Dict.set("simulate", s->(Utils.magic: array<JSON.t> => unknown))
866
879
  | None => ()
867
880
  }
868
- let resolvedChainsDict: Js.Dict.t<unknown> = Js.Dict.empty()
869
- resolvedChainsDict->Js.Dict.set(
881
+ let resolvedChainsDict: dict<unknown> = Dict.make()
882
+ resolvedChainsDict->Dict.set(
870
883
  chainIdStr,
871
- resolvedChainDict->(Utils.magic: Js.Dict.t<unknown> => unknown),
884
+ resolvedChainDict->(Utils.magic: dict<unknown> => unknown),
872
885
  )
873
886
  let processConfig =
874
- {"chains": resolvedChainsDict}->(Utils.magic: {"chains": Js.Dict.t<unknown>} => Js.Json.t)
887
+ {"chains": resolvedChainsDict}->(Utils.magic: {"chains": dict<unknown>} => JSON.t)
875
888
 
876
889
  // Create proxy storage that communicates with main thread
877
890
  let proxy = TestIndexerProxyStorage.make(~parentPort, ~initialState)
878
891
  let storage = TestIndexerProxyStorage.makeStorage(proxy)
879
- let config = makeGeneratedConfig()
892
+ let config = Config.loadWithoutRegistrations()
880
893
  let persistence = Persistence.make(
881
894
  ~userEntities=config.userEntities,
882
895
  ~allEnums=config.allEnums,
@@ -899,13 +912,7 @@ let initTestWorker = (~makeGeneratedConfig: unit => Config.t) => {
899
912
  config
900
913
  }
901
914
  }
902
- Main.start(
903
- ~makeGeneratedConfig,
904
- ~persistence,
905
- ~isTest=true,
906
- ~patchConfig,
907
- ~exitAfterFirstEventBlock,
908
- )->ignore
915
+ Main.start(~persistence, ~isTest=true, ~patchConfig, ~exitAfterFirstEventBlock)->ignore
909
916
  | None =>
910
917
  Logging.error("TestIndexerWorker: No worker data provided")
911
918
  NodeJs.process->NodeJs.exitWithCode(Failure)