envio 3.0.0-alpha.21 → 3.0.0-alpha.23

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 (220) hide show
  1. package/README.md +3 -3
  2. package/bin.mjs +2 -48
  3. package/evm.schema.json +67 -0
  4. package/fuel.schema.json +67 -0
  5. package/index.d.ts +822 -38
  6. package/index.js +5 -3
  7. package/package.json +10 -8
  8. package/rescript.json +5 -9
  9. package/src/Address.res +4 -5
  10. package/src/Address.res.mjs +9 -12
  11. package/src/Api.res +15 -0
  12. package/src/Api.res.mjs +20 -0
  13. package/src/Batch.res +32 -34
  14. package/src/Batch.res.mjs +172 -187
  15. package/src/Bin.res +89 -0
  16. package/src/Bin.res.mjs +97 -0
  17. package/src/ChainFetcher.res +33 -57
  18. package/src/ChainFetcher.res.mjs +197 -227
  19. package/src/ChainManager.res +6 -14
  20. package/src/ChainManager.res.mjs +74 -85
  21. package/src/ChainMap.res +14 -16
  22. package/src/ChainMap.res.mjs +38 -38
  23. package/src/Config.res +193 -135
  24. package/src/Config.res.mjs +566 -592
  25. package/src/Core.res +182 -0
  26. package/src/Core.res.mjs +207 -0
  27. package/src/Ecosystem.res +25 -4
  28. package/src/Ecosystem.res.mjs +12 -13
  29. package/src/Env.res +20 -13
  30. package/src/Env.res.mjs +124 -113
  31. package/src/EnvSafe.res +269 -0
  32. package/src/EnvSafe.res.mjs +296 -0
  33. package/src/EnvSafe.resi +18 -0
  34. package/src/Envio.res +37 -26
  35. package/src/Envio.res.mjs +59 -60
  36. package/src/ErrorHandling.res +2 -2
  37. package/src/ErrorHandling.res.mjs +15 -15
  38. package/src/EventConfigBuilder.res +219 -81
  39. package/src/EventConfigBuilder.res.mjs +259 -202
  40. package/src/EventProcessing.res +27 -38
  41. package/src/EventProcessing.res.mjs +165 -183
  42. package/src/EventUtils.res +11 -11
  43. package/src/EventUtils.res.mjs +21 -22
  44. package/src/EvmTypes.res +0 -1
  45. package/src/EvmTypes.res.mjs +5 -5
  46. package/src/FetchState.res +360 -256
  47. package/src/FetchState.res.mjs +958 -914
  48. package/src/GlobalState.res +365 -351
  49. package/src/GlobalState.res.mjs +958 -992
  50. package/src/GlobalStateManager.res +1 -2
  51. package/src/GlobalStateManager.res.mjs +36 -44
  52. package/src/HandlerLoader.res +107 -23
  53. package/src/HandlerLoader.res.mjs +128 -38
  54. package/src/HandlerRegister.res +127 -103
  55. package/src/HandlerRegister.res.mjs +164 -164
  56. package/src/HandlerRegister.resi +12 -4
  57. package/src/Hasura.res +35 -22
  58. package/src/Hasura.res.mjs +158 -167
  59. package/src/InMemoryStore.res +20 -27
  60. package/src/InMemoryStore.res.mjs +64 -80
  61. package/src/InMemoryTable.res +34 -39
  62. package/src/InMemoryTable.res.mjs +165 -170
  63. package/src/Internal.res +52 -33
  64. package/src/Internal.res.mjs +84 -81
  65. package/src/LazyLoader.res.mjs +55 -61
  66. package/src/LoadLayer.res +77 -78
  67. package/src/LoadLayer.res.mjs +160 -189
  68. package/src/LoadManager.res +16 -21
  69. package/src/LoadManager.res.mjs +79 -84
  70. package/src/LogSelection.res +236 -68
  71. package/src/LogSelection.res.mjs +211 -141
  72. package/src/Logging.res +13 -9
  73. package/src/Logging.res.mjs +130 -143
  74. package/src/Main.res +430 -51
  75. package/src/Main.res.mjs +530 -271
  76. package/src/Persistence.res +80 -84
  77. package/src/Persistence.res.mjs +131 -132
  78. package/src/PgStorage.res +294 -167
  79. package/src/PgStorage.res.mjs +799 -817
  80. package/src/Prometheus.res +50 -58
  81. package/src/Prometheus.res.mjs +345 -373
  82. package/src/ReorgDetection.res +22 -24
  83. package/src/ReorgDetection.res.mjs +100 -106
  84. package/src/SafeCheckpointTracking.res +7 -7
  85. package/src/SafeCheckpointTracking.res.mjs +40 -43
  86. package/src/SimulateItems.res +41 -49
  87. package/src/SimulateItems.res.mjs +257 -272
  88. package/src/Sink.res +2 -2
  89. package/src/Sink.res.mjs +22 -26
  90. package/src/TableIndices.res +1 -2
  91. package/src/TableIndices.res.mjs +42 -48
  92. package/src/TestIndexer.res +196 -189
  93. package/src/TestIndexer.res.mjs +536 -536
  94. package/src/TestIndexerProxyStorage.res +16 -16
  95. package/src/TestIndexerProxyStorage.res.mjs +99 -122
  96. package/src/TestIndexerWorker.res +4 -0
  97. package/src/TestIndexerWorker.res.mjs +7 -0
  98. package/src/Throttler.res +3 -3
  99. package/src/Throttler.res.mjs +23 -24
  100. package/src/Time.res +1 -1
  101. package/src/Time.res.mjs +18 -21
  102. package/src/TopicFilter.res +3 -3
  103. package/src/TopicFilter.res.mjs +29 -30
  104. package/src/UserContext.res +93 -54
  105. package/src/UserContext.res.mjs +197 -182
  106. package/src/Utils.res +141 -86
  107. package/src/Utils.res.mjs +334 -295
  108. package/src/bindings/BigDecimal.res +0 -2
  109. package/src/bindings/BigDecimal.res.mjs +19 -23
  110. package/src/bindings/ClickHouse.res +28 -27
  111. package/src/bindings/ClickHouse.res.mjs +243 -240
  112. package/src/bindings/DateFns.res +11 -11
  113. package/src/bindings/DateFns.res.mjs +7 -7
  114. package/src/bindings/EventSource.res.mjs +2 -2
  115. package/src/bindings/Express.res +2 -5
  116. package/src/bindings/Hrtime.res +2 -2
  117. package/src/bindings/Hrtime.res.mjs +30 -32
  118. package/src/bindings/Lodash.res.mjs +1 -1
  119. package/src/bindings/NodeJs.res +14 -9
  120. package/src/bindings/NodeJs.res.mjs +20 -20
  121. package/src/bindings/Pino.res +8 -10
  122. package/src/bindings/Pino.res.mjs +40 -43
  123. package/src/bindings/Postgres.res +7 -5
  124. package/src/bindings/Postgres.res.mjs +9 -9
  125. package/src/bindings/PromClient.res +17 -2
  126. package/src/bindings/PromClient.res.mjs +30 -7
  127. package/src/bindings/SDSL.res.mjs +2 -2
  128. package/src/bindings/Viem.res +4 -4
  129. package/src/bindings/Viem.res.mjs +20 -22
  130. package/src/bindings/Vitest.res +1 -1
  131. package/src/bindings/Vitest.res.mjs +2 -2
  132. package/src/bindings/WebSocket.res +1 -1
  133. package/src/db/EntityHistory.res +9 -3
  134. package/src/db/EntityHistory.res.mjs +84 -59
  135. package/src/db/InternalTable.res +62 -60
  136. package/src/db/InternalTable.res.mjs +271 -203
  137. package/src/db/Schema.res +1 -2
  138. package/src/db/Schema.res.mjs +28 -32
  139. package/src/db/Table.res +28 -27
  140. package/src/db/Table.res.mjs +276 -292
  141. package/src/sources/EventRouter.res +21 -16
  142. package/src/sources/EventRouter.res.mjs +55 -57
  143. package/src/sources/Evm.res +17 -1
  144. package/src/sources/Evm.res.mjs +16 -8
  145. package/src/sources/EvmChain.res +15 -17
  146. package/src/sources/EvmChain.res.mjs +40 -42
  147. package/src/sources/Fuel.res +14 -1
  148. package/src/sources/Fuel.res.mjs +16 -8
  149. package/src/sources/FuelSDK.res +1 -1
  150. package/src/sources/FuelSDK.res.mjs +6 -8
  151. package/src/sources/HyperFuel.res +8 -10
  152. package/src/sources/HyperFuel.res.mjs +113 -123
  153. package/src/sources/HyperFuelClient.res.mjs +6 -7
  154. package/src/sources/HyperFuelSource.res +19 -20
  155. package/src/sources/HyperFuelSource.res.mjs +339 -356
  156. package/src/sources/HyperSync.res +11 -13
  157. package/src/sources/HyperSync.res.mjs +206 -220
  158. package/src/sources/HyperSyncClient.res +5 -7
  159. package/src/sources/HyperSyncClient.res.mjs +70 -75
  160. package/src/sources/HyperSyncHeightStream.res +8 -9
  161. package/src/sources/HyperSyncHeightStream.res.mjs +78 -86
  162. package/src/sources/HyperSyncJsonApi.res +18 -15
  163. package/src/sources/HyperSyncJsonApi.res.mjs +201 -231
  164. package/src/sources/HyperSyncSource.res +17 -21
  165. package/src/sources/HyperSyncSource.res.mjs +268 -290
  166. package/src/sources/Rpc.res +5 -5
  167. package/src/sources/Rpc.res.mjs +168 -192
  168. package/src/sources/RpcSource.res +166 -167
  169. package/src/sources/RpcSource.res.mjs +972 -1046
  170. package/src/sources/RpcWebSocketHeightStream.res +10 -11
  171. package/src/sources/RpcWebSocketHeightStream.res.mjs +131 -145
  172. package/src/sources/SimulateSource.res +1 -1
  173. package/src/sources/SimulateSource.res.mjs +35 -38
  174. package/src/sources/Source.res +1 -1
  175. package/src/sources/Source.res.mjs +3 -3
  176. package/src/sources/SourceManager.res +39 -20
  177. package/src/sources/SourceManager.res.mjs +340 -371
  178. package/src/sources/SourceManager.resi +2 -1
  179. package/src/sources/Svm.res +12 -5
  180. package/src/sources/Svm.res.mjs +44 -41
  181. package/src/tui/Tui.res +23 -12
  182. package/src/tui/Tui.res.mjs +292 -290
  183. package/src/tui/bindings/Ink.res +2 -4
  184. package/src/tui/bindings/Ink.res.mjs +35 -41
  185. package/src/tui/components/BufferedProgressBar.res +7 -7
  186. package/src/tui/components/BufferedProgressBar.res.mjs +46 -46
  187. package/src/tui/components/CustomHooks.res +1 -2
  188. package/src/tui/components/CustomHooks.res.mjs +102 -122
  189. package/src/tui/components/Messages.res +1 -2
  190. package/src/tui/components/Messages.res.mjs +38 -42
  191. package/src/tui/components/SyncETA.res +10 -11
  192. package/src/tui/components/SyncETA.res.mjs +178 -196
  193. package/src/tui/components/TuiData.res +1 -1
  194. package/src/tui/components/TuiData.res.mjs +7 -6
  195. package/src/vendored/Rest.res +52 -66
  196. package/src/vendored/Rest.res.mjs +324 -364
  197. package/svm.schema.json +67 -0
  198. package/src/Address.gen.ts +0 -8
  199. package/src/Config.gen.ts +0 -19
  200. package/src/Envio.gen.ts +0 -55
  201. package/src/EvmTypes.gen.ts +0 -6
  202. package/src/InMemoryStore.gen.ts +0 -6
  203. package/src/Internal.gen.ts +0 -64
  204. package/src/PgStorage.gen.ts +0 -10
  205. package/src/PgStorage.res.d.mts +0 -5
  206. package/src/Types.ts +0 -56
  207. package/src/bindings/BigDecimal.gen.ts +0 -14
  208. package/src/bindings/BigDecimal.res.d.mts +0 -5
  209. package/src/bindings/BigInt.gen.ts +0 -10
  210. package/src/bindings/BigInt.res +0 -70
  211. package/src/bindings/BigInt.res.d.mts +0 -5
  212. package/src/bindings/BigInt.res.mjs +0 -154
  213. package/src/bindings/Ethers.res.d.mts +0 -5
  214. package/src/bindings/Pino.gen.ts +0 -17
  215. package/src/bindings/Postgres.gen.ts +0 -8
  216. package/src/bindings/Postgres.res.d.mts +0 -5
  217. package/src/bindings/Promise.res +0 -67
  218. package/src/bindings/Promise.res.mjs +0 -26
  219. package/src/db/InternalTable.gen.ts +0 -36
  220. package/src/sources/HyperSyncClient.gen.ts +0 -19
@@ -1,20 +1,19 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
3
  import * as Viem from "viem";
4
- import * as $$BigInt from "./bindings/BigInt.res.mjs";
5
- import * as Caml_option from "rescript/lib/es6/caml_option.js";
4
+ import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
6
5
 
7
6
  function toTwosComplement(num, bytesLen) {
8
- var maxValue = $$BigInt.Bitwise.shift_left(1n, BigInt((bytesLen << 3)));
9
- var mask = $$BigInt.sub(maxValue, 1n);
10
- return $$BigInt.Bitwise.logand($$BigInt.add(num, maxValue), mask);
7
+ let maxValue = (1n << BigInt((bytesLen << 3)));
8
+ let mask = maxValue - 1n;
9
+ return num + maxValue & mask;
11
10
  }
12
11
 
13
12
  function fromSignedBigInt(val) {
14
- var val$1 = val >= 0n ? val : toTwosComplement(val, 32);
13
+ let val$1 = val >= 0n ? val : toTwosComplement(val, 32);
15
14
  return Viem.numberToHex(val$1, {
16
- size: 32
17
- });
15
+ size: 32
16
+ });
18
17
  }
19
18
 
20
19
  function keccak256(prim) {
@@ -22,7 +21,7 @@ function keccak256(prim) {
22
21
  }
23
22
 
24
23
  function bytesToHex(prim0, prim1) {
25
- return Viem.bytesToHex(prim0, prim1 !== undefined ? Caml_option.valFromOption(prim1) : undefined);
24
+ return Viem.bytesToHex(prim0, prim1 !== undefined ? Primitive_option.valFromOption(prim1) : undefined);
26
25
  }
27
26
 
28
27
  function concat(prim) {
@@ -35,8 +34,8 @@ function castToHexUnsafe(val) {
35
34
 
36
35
  function fromBigInt(val) {
37
36
  return Viem.numberToHex(val, {
38
- size: 32
39
- });
37
+ size: 32
38
+ });
40
39
  }
41
40
 
42
41
  function fromDynamicString(val) {
@@ -45,8 +44,8 @@ function fromDynamicString(val) {
45
44
 
46
45
  function fromString(val) {
47
46
  return Viem.stringToHex(val, {
48
- size: 32
49
- });
47
+ size: 32
48
+ });
50
49
  }
51
50
 
52
51
  function fromAddress(addr) {
@@ -59,29 +58,29 @@ function fromDynamicBytes(bytes) {
59
58
 
60
59
  function fromBytes(bytes) {
61
60
  return Viem.bytesToHex(bytes, {
62
- size: 32
63
- });
61
+ size: 32
62
+ });
64
63
  }
65
64
 
66
65
  function fromBool(b) {
67
66
  return Viem.boolToHex(b, {
68
- size: 32
69
- });
67
+ size: 32
68
+ });
70
69
  }
71
70
 
72
71
  export {
73
- toTwosComplement ,
74
- fromSignedBigInt ,
75
- keccak256 ,
76
- bytesToHex ,
77
- concat ,
78
- castToHexUnsafe ,
79
- fromBigInt ,
80
- fromDynamicString ,
81
- fromString ,
82
- fromAddress ,
83
- fromDynamicBytes ,
84
- fromBytes ,
85
- fromBool ,
72
+ toTwosComplement,
73
+ fromSignedBigInt,
74
+ keccak256,
75
+ bytesToHex,
76
+ concat,
77
+ castToHexUnsafe,
78
+ fromBigInt,
79
+ fromDynamicString,
80
+ fromString,
81
+ fromAddress,
82
+ fromDynamicBytes,
83
+ fromBytes,
84
+ fromBool,
86
85
  }
87
86
  /* viem Not a pure module */
@@ -74,53 +74,53 @@ type entityContextParams = {
74
74
  entityConfig: Internal.entityConfig,
75
75
  }
76
76
 
77
- let getWhereHandler = (params: entityContextParams, filter: Js.Dict.t<Js.Dict.t<unknown>>) => {
77
+ let getWhereHandler = (params: entityContextParams, filter: dict<dict<unknown>>) => {
78
78
  let entityConfig = params.entityConfig
79
- let filterKeys = filter->Js.Dict.keys
79
+ let filterKeys = filter->Dict.keysToArray
80
80
 
81
81
  if filterKeys->Array.length === 0 {
82
- Js.Exn.raiseError(
82
+ JsError.throwWithMessage(
83
83
  `Empty filter passed to context.${entityConfig.name}.getWhere(). Please provide a filter like { fieldName: { _eq: value } }.`,
84
84
  )
85
85
  }
86
86
  if filterKeys->Array.length > 1 {
87
- Js.Exn.raiseError(
88
- `Multiple filter fields passed to context.${entityConfig.name}.getWhere(). Currently only one filter field per call is supported. Received fields: ${filterKeys->Js.Array2.joinWith(
87
+ JsError.throwWithMessage(
88
+ `Multiple filter fields passed to context.${entityConfig.name}.getWhere(). Currently only one filter field per call is supported. Received fields: ${filterKeys->Array.joinUnsafe(
89
89
  ", ",
90
90
  )}.`,
91
91
  )
92
92
  }
93
93
 
94
- let dbFieldName = filterKeys->Js.Array2.unsafe_get(0)
95
- let operatorObj = filter->Js.Dict.unsafeGet(dbFieldName)
96
- let operatorKeys = operatorObj->Js.Dict.keys
94
+ let dbFieldName = filterKeys->Array.getUnsafe(0)
95
+ let operatorObj = filter->Dict.getUnsafe(dbFieldName)
96
+ let operatorKeys = operatorObj->Dict.keysToArray
97
97
 
98
98
  if operatorKeys->Array.length === 0 {
99
- Js.Exn.raiseError(
99
+ JsError.throwWithMessage(
100
100
  `Empty operator passed to context.${entityConfig.name}.getWhere({ ${dbFieldName}: {} }). Please provide an operator like { _eq: value }, { _gt: value }, { _lt: value }, { _gte: value }, { _lte: value }, or { _in: [values] }.`,
101
101
  )
102
102
  }
103
103
  if operatorKeys->Array.length > 1 {
104
- Js.Exn.raiseError(
105
- `Multiple operators passed to context.${entityConfig.name}.getWhere({ ${dbFieldName}: ... }). Currently only one operator per filter field is supported. Received operators: ${operatorKeys->Js.Array2.joinWith(
104
+ JsError.throwWithMessage(
105
+ `Multiple operators passed to context.${entityConfig.name}.getWhere({ ${dbFieldName}: ... }). Currently only one operator per filter field is supported. Received operators: ${operatorKeys->Array.joinUnsafe(
106
106
  ", ",
107
107
  )}.`,
108
108
  )
109
109
  }
110
110
 
111
- let operatorKey = operatorKeys->Js.Array2.unsafe_get(0)
111
+ let operatorKey = operatorKeys->Array.getUnsafe(0)
112
112
 
113
113
  let fieldSchema = switch entityConfig.table->Table.getFieldByDbName(dbFieldName) {
114
114
  | None =>
115
- Js.Exn.raiseError(
115
+ JsError.throwWithMessage(
116
116
  `Invalid field "${dbFieldName}" in context.${entityConfig.name}.getWhere(). The field doesn't exist. ${codegenHelpMessage}`,
117
117
  )
118
118
  | Some(DerivedFrom(_)) =>
119
- Js.Exn.raiseError(
119
+ JsError.throwWithMessage(
120
120
  `The field "${dbFieldName}" on entity "${entityConfig.name}" is a derived field and cannot be used in getWhere(). Use the source entity's indexed field instead.`,
121
121
  )
122
122
  | Some(Field({isIndex: false, linkedEntity: None})) =>
123
- Js.Exn.raiseError(
123
+ JsError.throwWithMessage(
124
124
  `The field "${dbFieldName}" on entity "${entityConfig.name}" does not have an index. To use it in getWhere(), add the @index directive in your schema.graphql:\n\n ${dbFieldName}: ... @index\n\nThen run 'pnpm envio codegen' to regenerate.`,
125
125
  )
126
126
  | Some(Field({fieldSchema})) => fieldSchema
@@ -129,11 +129,11 @@ let getWhereHandler = (params: entityContextParams, filter: Js.Dict.t<Js.Dict.t<
129
129
  if operatorKey === "_in" {
130
130
  let fieldValues =
131
131
  operatorObj
132
- ->Js.Dict.unsafeGet(operatorKey)
132
+ ->Dict.getUnsafe(operatorKey)
133
133
  ->(Utils.magic: unknown => array<unknown>)
134
134
 
135
135
  fieldValues
136
- ->Js.Array2.map(fieldValue =>
136
+ ->Array.map(fieldValue =>
137
137
  LoadLayer.loadByField(
138
138
  ~loadManager=params.loadManager,
139
139
  ~persistence=params.persistence,
@@ -152,7 +152,7 @@ let getWhereHandler = (params: entityContextParams, filter: Js.Dict.t<Js.Dict.t<
152
152
  } else if operatorKey === "_gte" || operatorKey === "_lte" {
153
153
  // _gte and _lte are composed from Eq + Gt/Lt
154
154
  let rangeOperator: TableIndices.Operator.t = operatorKey === "_gte" ? Gt : Lt
155
- let fieldValue = operatorObj->Js.Dict.unsafeGet(operatorKey)
155
+ let fieldValue = operatorObj->Dict.getUnsafe(operatorKey)
156
156
 
157
157
  let loadWithOperator = operator =>
158
158
  LoadLayer.loadByField(
@@ -177,12 +177,12 @@ let getWhereHandler = (params: entityContextParams, filter: Js.Dict.t<Js.Dict.t<
177
177
  | "_gt" => Gt
178
178
  | "_lt" => Lt
179
179
  | _ =>
180
- Js.Exn.raiseError(
180
+ JsError.throwWithMessage(
181
181
  `Invalid operator "${operatorKey}" in context.${entityConfig.name}.getWhere({ ${dbFieldName}: { ${operatorKey}: ... } }). Valid operators are _eq, _gt, _lt, _gte, _lte, _in.`,
182
182
  )
183
183
  }
184
184
 
185
- let fieldValue = operatorObj->Js.Dict.unsafeGet(operatorKey)
185
+ let fieldValue = operatorObj->Dict.getUnsafe(operatorKey)
186
186
 
187
187
  LoadLayer.loadByField(
188
188
  ~loadManager=params.loadManager,
@@ -236,10 +236,9 @@ let entityTraps: Utils.Proxy.traps<entityContextParams> = {
236
236
  )
237
237
  )->(Utils.magic: (string => promise<option<Internal.entity>>) => unknown)
238
238
  | "getWhere" =>
239
- (
240
- filter =>
241
- getWhereHandler(params, filter->(Utils.magic: unknown => Js.Dict.t<Js.Dict.t<unknown>>))
242
- )->(Utils.magic: (unknown => promise<array<Internal.entity>>) => unknown)
239
+ (filter => getWhereHandler(params, filter->(Utils.magic: unknown => dict<dict<unknown>>)))->(
240
+ Utils.magic: (unknown => promise<array<Internal.entity>>) => unknown
241
+ )
243
242
  | "getOrThrow" =>
244
243
  (
245
244
  (entityId, ~message=?) =>
@@ -255,7 +254,7 @@ let entityTraps: Utils.Proxy.traps<entityContextParams> = {
255
254
  switch entity {
256
255
  | Some(entity) => entity
257
256
  | None =>
258
- Js.Exn.raiseError(
257
+ JsError.throwWithMessage(
259
258
  message->Belt.Option.getWithDefault(
260
259
  `Entity '${params.entityConfig.name}' with ID '${entityId}' is expected to exist.`,
261
260
  ),
@@ -301,7 +300,8 @@ let entityTraps: Utils.Proxy.traps<entityContextParams> = {
301
300
  )
302
301
  }
303
302
  }->(Utils.magic: (string => unit) => unknown)
304
- | _ => Js.Exn.raiseError(`Invalid context.${params.entityConfig.name}.${prop} operation.`)
303
+ | _ =>
304
+ JsError.throwWithMessage(`Invalid context.${params.entityConfig.name}.${prop} operation.`)
305
305
  }
306
306
  },
307
307
  }
@@ -352,7 +352,9 @@ let handlerTraps: Utils.Proxy.traps<contextParams> = {
352
352
  ->Utils.Proxy.make(entityTraps)
353
353
  ->(Utils.magic: entityContextParams => unknown)
354
354
  | None =>
355
- Js.Exn.raiseError(`Invalid context access by '${prop}' property. ${codegenHelpMessage}`)
355
+ JsError.throwWithMessage(
356
+ `Invalid context access by '${prop}' property. ${codegenHelpMessage}`,
357
+ )
356
358
  }
357
359
  }
358
360
  },
@@ -370,6 +372,63 @@ type contractRegisterParams = {
370
372
  mutable isResolved: bool,
371
373
  }
372
374
 
375
+ // Helper to create a validated add function for contract registration.
376
+ // The isResolved check has to live inside the returned closure (not just in the
377
+ // outer proxy trap) because users can capture `const add = context.chain.X.add`
378
+ // before awaiting — a later call would otherwise bypass the resolved guard.
379
+ let makeAddFunction = (~params: contractRegisterParams, ~contractName: string): (
380
+ Address.t => unit
381
+ ) => {
382
+ (contractAddress: Address.t) => {
383
+ if params.isResolved {
384
+ Utils.Error.make(`Impossible to access context.chain after the contract register is resolved. Make sure you didn't miss an await in the handler.`)->ErrorHandling.mkLogAndRaise(
385
+ ~logger=params.item->Logging.getItemLogger,
386
+ )
387
+ }
388
+ let validatedAddress = if params.config.ecosystem.name === Evm {
389
+ // The value is passed from the user-land,
390
+ // so we need to validate and checksum/lowercase the address.
391
+ if params.config.lowercaseAddresses {
392
+ contractAddress->Address.Evm.fromAddressLowercaseOrThrow
393
+ } else {
394
+ contractAddress->Address.Evm.fromAddressOrThrow
395
+ }
396
+ } else {
397
+ // TODO: Ideally we should do the same for other ecosystems
398
+ contractAddress
399
+ }
400
+
401
+ params.onRegister(~item=params.item, ~contractAddress=validatedAddress, ~contractName)
402
+ }
403
+ }
404
+
405
+ // Chain proxy for contractRegister context: context.chain.ContractName.add(address)
406
+ let contractRegisterChainTraps: Utils.Proxy.traps<contractRegisterParams> = {
407
+ get: (~target as params, ~prop: unknown) => {
408
+ let prop = prop->(Utils.magic: unknown => string)
409
+ switch prop {
410
+ | "id" =>
411
+ let eventItem = params.item->Internal.castUnsafeEventItem
412
+ eventItem.chain->ChainMap.Chain.toChainId->(Utils.magic: int => unknown)
413
+ | _ =>
414
+ // Look up the contract name directly in config contracts across all chains.
415
+ let contractName = prop
416
+ let isValidContract =
417
+ params.config.chainMap
418
+ ->ChainMap.values
419
+ ->Array.some(chain => chain.contracts->Array.some(c => c.name === contractName))
420
+ if isValidContract {
421
+ let addFn = makeAddFunction(~params, ~contractName)
422
+ {"add": addFn}->(Utils.magic: {"add": Address.t => unit} => unknown)
423
+ } else {
424
+ JsError.throwWithMessage(
425
+ `Invalid contract name '${prop}' on context.chain. ${codegenHelpMessage}`,
426
+ )
427
+ }
428
+ }
429
+ },
430
+ }
431
+
373
432
  let contractRegisterTraps: Utils.Proxy.traps<contractRegisterParams> = {
374
433
  get: (~target as params, ~prop: unknown) => {
375
434
  let prop = prop->(Utils.magic: unknown => string)
@@ -380,34 +439,14 @@ let contractRegisterTraps: Utils.Proxy.traps<contractRegisterParams> = {
380
439
  }
381
440
  switch prop {
382
441
  | "log" => params.item->Logging.getUserLogger->(Utils.magic: Envio.logger => unknown)
442
+ | "chain" =>
443
+ params
444
+ ->Utils.Proxy.make(contractRegisterChainTraps)
445
+ ->(Utils.magic: contractRegisterParams => unknown)
383
446
  | _ =>
384
- // Use the pre-built mapping for efficient lookup
385
- switch params.config.addContractNameToContractNameMapping->Utils.Dict.dangerouslyGetNonOption(
386
- prop,
387
- ) {
388
- | Some(contractName) => {
389
- let addFunction = (contractAddress: Address.t) => {
390
- let validatedAddress = if params.config.ecosystem.name === Evm {
391
- // The value is passed from the user-land,
392
- // so we need to validate and checksum/lowercase the address.
393
- if params.config.lowercaseAddresses {
394
- contractAddress->Address.Evm.fromAddressLowercaseOrThrow
395
- } else {
396
- contractAddress->Address.Evm.fromAddressOrThrow
397
- }
398
- } else {
399
- // TODO: Ideally we should do the same for other ecosystems
400
- contractAddress
401
- }
402
-
403
- params.onRegister(~item=params.item, ~contractAddress=validatedAddress, ~contractName)
404
- }
405
-
406
- addFunction->(Utils.magic: (Address.t => unit) => unknown)
407
- }
408
- | None =>
409
- Js.Exn.raiseError(`Invalid context access by '${prop}' property. ${codegenHelpMessage}`)
410
- }
447
+ JsError.throwWithMessage(
448
+ `Invalid context access by '${prop}' property. Use context.chain.ContractName.add(address) to register contracts. ${codegenHelpMessage}`,
449
+ )
411
450
  }
412
451
  },
413
452
  }