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,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
  }