From c1a5b0d7024acb9d4fcdc9a0f633cc0fc0ae599b Mon Sep 17 00:00:00 2001 From: Dmitry Zakharov Date: Thu, 19 Feb 2026 13:23:30 +0400 Subject: [PATCH] Fix handler registration for old test framework ran with vitest --- adr/why-vitest.md | 50 -------- adr/why-workers-for-test-indexer.md | 46 -------- .../cli/npm/envio/src/ChainFetcher.res | 4 +- codegenerator/cli/npm/envio/src/Ctx.res | 2 +- .../cli/npm/envio/src/EventRegister.gen.ts | 6 - .../cli/npm/envio/src/HandlerLoader.res | 4 +- ...{EventRegister.res => HandlerRegister.res} | 111 +++++++++++------- ...ventRegister.resi => HandlerRegister.resi} | 20 ++-- .../src/hbs_templating/codegen_templates.rs | 66 ++++------- ...de_generates_correct_types_and_values.snap | 2 +- ...s__test__indexer_code_multiple_chains.snap | 2 +- .../dynamic/codegen/src/Indexer.res.hbs | 13 +- .../codegen/src/TestHelpers_MockDb.res.hbs | 4 +- scenarios/test_codegen/pnpm-lock.yaml | 2 +- 14 files changed, 116 insertions(+), 216 deletions(-) delete mode 100644 adr/why-vitest.md delete mode 100644 adr/why-workers-for-test-indexer.md delete mode 100644 codegenerator/cli/npm/envio/src/EventRegister.gen.ts rename codegenerator/cli/npm/envio/src/{EventRegister.res => HandlerRegister.res} (68%) rename codegenerator/cli/npm/envio/src/{EventRegister.resi => HandlerRegister.resi} (59%) diff --git a/adr/why-vitest.md b/adr/why-vitest.md deleted file mode 100644 index 7dd04c1ac9..0000000000 --- a/adr/why-vitest.md +++ /dev/null @@ -1,50 +0,0 @@ -# Why Vitest for User-Facing Indexer Tests - -## Status - -Accepted - -## Context - -Previously used Mocha and Chai for user-facing indexer tests. This approach had several problems: - -- Complex configuration required for TypeScript with TSX -- Difficult to expose to users since we don't control their environment -- Snapshot testing support would make configuration even more complex -- Not flexible enough for a user-controlled setup -- Requires users to install 5 dependencies instead of 1 - -Main drivers for change: - -1. Upgrade to ESM modules -2. Updated TypeScript setup made Mocha/Chai very difficult to configure -3. New createTestIndexer framework (end-to-end testing) relies heavily on snapshot testing - configuring this per-user with Mocha/Chai would be very complicated - -## Alternatives Considered - -- **Node.js built-in test runner**: Same configuration complexity issues as Mocha/Chai. Also, will require a change when potentially supporting Bun as an alternative runtime. -- **Ava.js**: Good testing framework, but requires complex setup for TypeScript + ESM -- **Jest**: Not considered at all - bad ESM support, essentially deprecated for modern projects. Vitest is its successor and does things much better - -## Decision - -Chose Vitest because: - -- **Zero configuration for users**: Just install and run `vitest run` -- **Most popular testing framework** in modern JS/web development, well-supported -- **Uses Vite under the hood**: We may adopt Vite for indexer compilation in the future -- **Flexible test file discovery**: Tests can live next to handlers (e.g., `handler.test.ts` in `src/`) without extra config -- **Powerful runtime API**: Potentially can vendor Vitest in the future and expose it behind `envio test` - -## Consequences - -### Positive - -- Users can run tests without any configuration -- Test files can be colocated with handlers in `src/` directory -- Excellent snapshot testing support out of the box -- Future path to vendor and customize the test runner - -### Negative - -- Watch mode (`vitest --watch`) doesn't work well - it tries to auto-detect affected tests via imports, but handlers don't directly import test files, so handler changes don't trigger test reruns. Not critical; solution may exist but not yet investigated diff --git a/adr/why-workers-for-test-indexer.md b/adr/why-workers-for-test-indexer.md deleted file mode 100644 index 5e77e9bcff..0000000000 --- a/adr/why-workers-for-test-indexer.md +++ /dev/null @@ -1,46 +0,0 @@ -# Why Workers for Test Indexer - -## Status - -Accepted - -## Context - -The test indexer (`createTestIndexer`) needs to provide isolation between handler module invocations. Several challenges drove this decision: - -- Users may use global variables in their handler modules -- Each `indexer.process()` call should simulate a clean indexer state, as if the indexer had restarted -- Global singleton modules (Prometheus client, logger) are not designed for multiple isolated runs within a single process - -Without isolation, state from one test run could leak into another, causing flaky tests and behavior that doesn't match production. - -## Alternatives Considered - -- **Refactor all global singletons**: Would require significant changes to Prometheus client, logger, and other modules to support reset/isolation. High effort with risk of introducing bugs in production code paths. -- **ESM cache invalidation**: Reset module cache using `?nonce=x` query params on imports. More brittle and problematic for parallel tests - handler registration is a global singleton that would conflict with top-level await, and indexer state couldn't be split between concurrent runs. -- **Process-level isolation**: Spawn new processes instead of workers. Higher overhead and more complex IPC. - -## Decision - -Use Node.js worker threads for each `indexer.process()` call. The worker runs the handler code in complete isolation: - -- Handler modules are freshly imported in each worker -- Global variables start fresh every time -- Singleton modules get new instances automatically - -The main thread maintains the storage state and communicates with workers via message passing (`TestIndexerProxyStorage`). - -## Consequences - -### Positive - -- Complete module isolation between test runs without any production code changes -- Each `process()` call simulates a clean indexer state after restart -- Enables running multiple test indexers in parallel (each has its own workers) -- Postpones refactoring of global singleton modules to a later time - -### Negative - -- Potential performance overhead from constantly creating new workers -- Workers are used for isolation, not optimization - this is an intentional trade-off -- IPC serialization overhead for storage operations between worker and main thread diff --git a/codegenerator/cli/npm/envio/src/ChainFetcher.res b/codegenerator/cli/npm/envio/src/ChainFetcher.res index 48fc2fbde8..cb7f8c457c 100644 --- a/codegenerator/cli/npm/envio/src/ChainFetcher.res +++ b/codegenerator/cli/npm/envio/src/ChainFetcher.res @@ -30,7 +30,7 @@ let make = ( ~firstEventBlock=None, ~progressBlockNumber, ~config: Config.t, - ~registrations: EventRegister.registrations, + ~registrations: HandlerRegister.registrations, ~targetBufferSize, ~logger, ~timestampCaughtUpToHeadOrEndblock, @@ -148,7 +148,7 @@ let make = ( registrations.onBlockByChainId->Utils.Dict.dangerouslyGetNonOption(chainConfig.id->Int.toString) switch onBlockConfigs { | Some(onBlockConfigs) => - // TODO: Move it to the EventRegister module + // TODO: Move it to the HandlerRegister module // so the error is thrown with better stack trace onBlockConfigs->Array.forEach(onBlockConfig => { if onBlockConfig.startBlock->Option.getWithDefault(startBlock) < startBlock { diff --git a/codegenerator/cli/npm/envio/src/Ctx.res b/codegenerator/cli/npm/envio/src/Ctx.res index 674c19ef68..c1298643cf 100644 --- a/codegenerator/cli/npm/envio/src/Ctx.res +++ b/codegenerator/cli/npm/envio/src/Ctx.res @@ -1,5 +1,5 @@ type t = { - registrations: EventRegister.registrations, + registrations: HandlerRegister.registrations, config: Config.t, persistence: Persistence.t, } \ No newline at end of file diff --git a/codegenerator/cli/npm/envio/src/EventRegister.gen.ts b/codegenerator/cli/npm/envio/src/EventRegister.gen.ts deleted file mode 100644 index bc0bca9315..0000000000 --- a/codegenerator/cli/npm/envio/src/EventRegister.gen.ts +++ /dev/null @@ -1,6 +0,0 @@ -/* TypeScript file generated from EventRegister.resi by genType. */ - -/* eslint-disable */ -/* tslint:disable */ - -export abstract class t { protected opaque!: any }; /* simulate opaque types */ diff --git a/codegenerator/cli/npm/envio/src/HandlerLoader.res b/codegenerator/cli/npm/envio/src/HandlerLoader.res index 0954de764b..8b3a9fbb79 100644 --- a/codegenerator/cli/npm/envio/src/HandlerLoader.res +++ b/codegenerator/cli/npm/envio/src/HandlerLoader.res @@ -72,7 +72,7 @@ let autoLoadFromSrcHandlers = async (~handlers: string) => { // Register all handlers - must be called BEFORE creating the final config // so that event registrations are captured in the config let registerAllHandlers = async (~config: Config.t) => { - EventRegister.startRegistration(~ecosystem=config.ecosystem, ~multichain=config.multichain) + HandlerRegister.startRegistration(~ecosystem=config.ecosystem, ~multichain=config.multichain) // Auto-load all .js files from src/handlers directory await autoLoadFromSrcHandlers(~handlers=config.handlers) @@ -85,5 +85,5 @@ let registerAllHandlers = async (~config: Config.t) => { }) ->Promise.all - EventRegister.finishRegistration() + HandlerRegister.finishRegistration() } diff --git a/codegenerator/cli/npm/envio/src/EventRegister.res b/codegenerator/cli/npm/envio/src/HandlerRegister.res similarity index 68% rename from codegenerator/cli/npm/envio/src/EventRegister.res rename to codegenerator/cli/npm/envio/src/HandlerRegister.res index 52f9b47600..da73759ce9 100644 --- a/codegenerator/cli/npm/envio/src/EventRegister.res +++ b/codegenerator/cli/npm/envio/src/HandlerRegister.res @@ -1,6 +1,32 @@ +type eventRegistration = { + handler: option, + contractRegister: option, + eventOptions: option>, +} + +let empty = { + handler: None, + contractRegister: None, + eventOptions: None, +} + +let eventRegistrations: Js.Dict.t = Js.Dict.empty() + +let getKey = (~contractName, ~eventName) => contractName ++ "." ++ eventName + +let get = (~contractName, ~eventName) => { + switch eventRegistrations->Utils.Dict.dangerouslyGetNonOption(getKey(~contractName, ~eventName)) { + | Some(existing) => existing + | None => empty + } +} + +let set = (~contractName, ~eventName, registration) => { + eventRegistrations->Js.Dict.set(getKey(~contractName, ~eventName), registration) +} + type registrations = { onBlockByChainId: dict>, - mutable hasEvents: bool, } type activeRegistration = { @@ -41,7 +67,6 @@ let startRegistration = (~ecosystem, ~multichain) => { multichain, registrations: { onBlockByChainId: Js.Dict.empty(), - hasEvents: false, }, finished: false, } @@ -141,51 +166,44 @@ let onBlock = (rawOptions: unknown, handler: Internal.onBlockArgs => promise, - mutable contractRegister: option, - mutable eventOptions: option>, -} - -let getHandler = (t: t) => t.handler - -let getContractRegister = (t: t) => t.contractRegister +let getHandler = (~contractName, ~eventName) => + get(~contractName, ~eventName).handler -let getEventFilters = (t: t) => t.eventOptions->Belt.Option.flatMap(value => value.eventFilters) +let getContractRegister = (~contractName, ~eventName) => + get(~contractName, ~eventName).contractRegister -let isWildcard = (t: t) => - t.eventOptions->Belt.Option.flatMap(value => value.wildcard)->Belt.Option.getWithDefault(false) +let getEventFilters = (~contractName, ~eventName) => + get(~contractName, ~eventName).eventOptions + ->Belt.Option.flatMap(value => value.eventFilters) -let hasRegistration = ({handler, contractRegister}) => - handler->Belt.Option.isSome || contractRegister->Belt.Option.isSome +let isWildcard = (~contractName, ~eventName) => + get(~contractName, ~eventName).eventOptions + ->Belt.Option.flatMap(value => value.wildcard) + ->Belt.Option.getWithDefault(false) -let make = (~contractName, ~eventName) => { - contractName, - eventName, - handler: None, - contractRegister: None, - eventOptions: None, +let hasRegistration = (~contractName, ~eventName) => { + let r = get(~contractName, ~eventName) + r.handler->Belt.Option.isSome || r.contractRegister->Belt.Option.isSome } type eventNamespace = {contractName: string, eventName: string} exception DuplicateEventRegistration(eventNamespace) -let setEventOptions = (t: t, ~eventOptions, ~logger=Logging.getLogger()) => { +let setEventOptions = (~contractName, ~eventName, ~eventOptions, ~logger=Logging.getLogger()) => { switch eventOptions { | Some(value) => let value = value->(Utils.magic: Internal.eventOptions<'eventFilters> => Internal.eventOptions) + let t = get(~contractName, ~eventName) switch t.eventOptions { - | None => t.eventOptions = Some(value) + | None => set(~contractName, ~eventName, {...t, eventOptions: Some(value)}) | Some(existingValue) => if ( existingValue.wildcard !== value.wildcard || // TODO: Can improve the check by using deepEqual existingValue.eventFilters !== value.eventFilters ) { - let eventNamespace = {contractName: t.contractName, eventName: t.eventName} + let eventNamespace = {contractName, eventName} DuplicateEventRegistration(eventNamespace)->ErrorHandling.mkLogAndRaise( ~logger=Logging.createChildFrom(~logger, ~params=eventNamespace), ~msg="Duplicate eventOptions in handlers not allowed", @@ -196,46 +214,49 @@ let setEventOptions = (t: t, ~eventOptions, ~logger=Logging.getLogger()) => { } } -let setHandler = (t: t, handler, ~eventOptions, ~logger=Logging.getLogger()) => { - withRegistration(registration => { - registration.registrations.hasEvents = true +let setHandler = (~contractName, ~eventName, handler, ~eventOptions, ~logger=Logging.getLogger()) => { + withRegistration(_registration => { + let t = get(~contractName, ~eventName) switch t.handler { | None => - t.handler = - handler - ->(Utils.magic: Internal.genericHandler<'args> => Internal.handler) - ->Some + set(~contractName, ~eventName, { + ...t, + handler: handler + ->(Utils.magic: Internal.genericHandler<'args> => Internal.handler) + ->Some, + }) | Some(_) => - let eventNamespace = {contractName: t.contractName, eventName: t.eventName} + let eventNamespace = {contractName, eventName} DuplicateEventRegistration(eventNamespace)->ErrorHandling.mkLogAndRaise( ~logger=Logging.createChildFrom(~logger, ~params=eventNamespace), ~msg="Duplicate registration of event handlers not allowed", ) } - t->setEventOptions(~eventOptions, ~logger) + setEventOptions(~contractName, ~eventName, ~eventOptions, ~logger) }) } -let setContractRegister = (t: t, contractRegister, ~eventOptions, ~logger=Logging.getLogger()) => { - withRegistration(registration => { - registration.registrations.hasEvents = true +let setContractRegister = (~contractName, ~eventName, contractRegister, ~eventOptions, ~logger=Logging.getLogger()) => { + withRegistration(_registration => { + let t = get(~contractName, ~eventName) switch t.contractRegister { | None => - t.contractRegister = Some( - contractRegister->( + set(~contractName, ~eventName, { + ...t, + contractRegister: contractRegister->( Utils.magic: Internal.genericContractRegister< Internal.genericContractRegisterArgs<'event, 'context>, > => Internal.contractRegister - ), - ) + )->Some, + }) | Some(_) => - let eventNamespace = {contractName: t.contractName, eventName: t.eventName} + let eventNamespace = {contractName, eventName} DuplicateEventRegistration(eventNamespace)->ErrorHandling.mkLogAndRaise( ~logger=Logging.createChildFrom(~logger, ~params=eventNamespace), ~msg="Duplicate contractRegister handlers not allowed", ) } - t->setEventOptions(~eventOptions, ~logger) + setEventOptions(~contractName, ~eventName, ~eventOptions, ~logger) }) } diff --git a/codegenerator/cli/npm/envio/src/EventRegister.resi b/codegenerator/cli/npm/envio/src/HandlerRegister.resi similarity index 59% rename from codegenerator/cli/npm/envio/src/EventRegister.resi rename to codegenerator/cli/npm/envio/src/HandlerRegister.resi index 2cc2869dc8..72dd52bb84 100644 --- a/codegenerator/cli/npm/envio/src/EventRegister.resi +++ b/codegenerator/cli/npm/envio/src/HandlerRegister.resi @@ -1,31 +1,29 @@ type registrations = { onBlockByChainId: dict>, - mutable hasEvents: bool, } let startRegistration: (~ecosystem: Ecosystem.t, ~multichain: Config.multichain) => unit let isPendingRegistration: unit => bool let finishRegistration: unit => registrations -@genType -type t -let make: (~contractName: string, ~eventName: string) => t let setHandler: ( - t, + ~contractName: string, + ~eventName: string, Internal.genericHandler>, ~eventOptions: option>, ~logger: Pino.t=?, ) => unit let setContractRegister: ( - t, + ~contractName: string, + ~eventName: string, Internal.genericContractRegister>, ~eventOptions: option>, ~logger: Pino.t=?, ) => unit -let getHandler: t => option -let getContractRegister: t => option -let getEventFilters: t => option -let isWildcard: t => bool -let hasRegistration: t => bool +let getHandler: (~contractName: string, ~eventName: string) => option +let getContractRegister: (~contractName: string, ~eventName: string) => option +let getEventFilters: (~contractName: string, ~eventName: string) => option +let isWildcard: (~contractName: string, ~eventName: string) => bool +let hasRegistration: (~contractName: string, ~eventName: string) => bool let onBlock: (unknown, Internal.onBlockArgs => promise) => unit diff --git a/codegenerator/cli/src/hbs_templating/codegen_templates.rs b/codegenerator/cli/src/hbs_templating/codegen_templates.rs index 37e0e2c539..202a96126c 100644 --- a/codegenerator/cli/src/hbs_templating/codegen_templates.rs +++ b/codegenerator/cli/src/hbs_templating/codegen_templates.rs @@ -584,9 +584,9 @@ decode: FuelSDK.Receipt.getLogDataDecoder(~abi, ~logId=sighash), let base_event_config_code = r#"id, name, contractName, -isWildcard: (handlerRegister->EventRegister.isWildcard), -handler: handlerRegister->EventRegister.getHandler, -contractRegister: handlerRegister->EventRegister.getContractRegister, +isWildcard: HandlerRegister.isWildcard(~contractName, ~eventName=name), +handler: HandlerRegister.getHandler(~contractName, ~eventName=name), +contractRegister: HandlerRegister.getContractRegister(~contractName, ~eventName=name), paramsRawEventSchema: paramsRawEventSchema->(Utils.magic: S.t => S.t),"#.to_string(); let non_event_mod_code = match fuel_event_kind_code { @@ -597,7 +597,7 @@ let {{getEventFiltersOrThrow, filterByAddresses}} = {parse_event_filters_code} {{ getEventFiltersOrThrow, filterByAddresses, - dependsOnAddresses: !(handlerRegister->EventRegister.isWildcard) || filterByAddresses, + dependsOnAddresses: !HandlerRegister.isWildcard(~contractName, ~eventName=name) || filterByAddresses, blockSchema: blockSchema->(Utils.magic: S.t => S.t), transactionSchema: transactionSchema->(Utils.magic: S.t => S.t), convertHyperSyncEventArgs: {convert_hyper_sync_event_args_code}, @@ -610,7 +610,7 @@ let {{getEventFiltersOrThrow, filterByAddresses}} = {parse_event_filters_code} let register = (): Internal.fuelEventConfig => {{ kind: {fuel_event_kind_code}, filterByAddresses: false, -dependsOnAddresses: !(handlerRegister->EventRegister.isWildcard), +dependsOnAddresses: !HandlerRegister.isWildcard(~contractName, ~eventName=name), {base_event_config_code} }}"# ), @@ -660,11 +660,6 @@ let paramsRawEventSchema = {params_raw_event_schema} let blockSchema = {block_schema} let transactionSchema = {transaction_schema} -let handlerRegister: EventRegister.t = EventRegister.make( -~contractName, -~eventName=name, -) - @genType type eventFilter = {event_filter_type} @@ -738,8 +733,8 @@ impl EventTemplate { }); format!( - "LogSelection.parseEventFiltersOrThrow(~eventFilters=handlerRegister->EventRegister.\ - getEventFilters, ~sighash, ~params=[{params_code}]{topic_filter_calls})" + "LogSelection.parseEventFiltersOrThrow(~eventFilters=HandlerRegister.\ + getEventFilters(~contractName, ~eventName=name), ~sighash, ~params=[{params_code}]{topic_filter_calls})" ) } @@ -1422,7 +1417,7 @@ let onBlock: ( Envio.onBlockOptions, {}, ) => unit = ( -EventRegister.onBlock: (unknown, Internal.onBlockArgs => promise) => unit +HandlerRegister.onBlock: (unknown, Internal.onBlockArgs => promise) => unit )->Utils.magic"#, on_block_handler_type ); @@ -2405,31 +2400,26 @@ let paramsRawEventSchema = S.object((s): eventArgs => {{id: s.field("id", BigInt let blockSchema = Block.schema let transactionSchema = Transaction.schema -let handlerRegister: EventRegister.t = EventRegister.make( -~contractName, -~eventName=name, -) - @genType type eventFilter = {{}} @genType type eventFilters = Internal.noEventFilters let register = (): Internal.evmEventConfig => {{ -let {{getEventFiltersOrThrow, filterByAddresses}} = LogSelection.parseEventFiltersOrThrow(~eventFilters=handlerRegister->EventRegister.getEventFilters, ~sighash, ~params=[]) +let {{getEventFiltersOrThrow, filterByAddresses}} = LogSelection.parseEventFiltersOrThrow(~eventFilters=HandlerRegister.getEventFilters(~contractName, ~eventName=name), ~sighash, ~params=[]) {{ getEventFiltersOrThrow, filterByAddresses, - dependsOnAddresses: !(handlerRegister->EventRegister.isWildcard) || filterByAddresses, + dependsOnAddresses: !HandlerRegister.isWildcard(~contractName, ~eventName=name) || filterByAddresses, blockSchema: blockSchema->(Utils.magic: S.t => S.t), transactionSchema: transactionSchema->(Utils.magic: S.t => S.t), convertHyperSyncEventArgs: (decodedEvent: HyperSyncClient.Decoder.decodedEvent) => {{id: decodedEvent.body->Utils.Array.firstUnsafe->HyperSyncClient.Decoder.toUnderlying->Utils.magic, owner: decodedEvent.body->Js.Array2.unsafe_get(1)->HyperSyncClient.Decoder.toUnderlying->Utils.magic, displayName: decodedEvent.body->Js.Array2.unsafe_get(2)->HyperSyncClient.Decoder.toUnderlying->Utils.magic, imageUrl: decodedEvent.body->Js.Array2.unsafe_get(3)->HyperSyncClient.Decoder.toUnderlying->Utils.magic, }}->(Utils.magic: eventArgs => Internal.eventParams), id, name, contractName, -isWildcard: (handlerRegister->EventRegister.isWildcard), -handler: handlerRegister->EventRegister.getHandler, -contractRegister: handlerRegister->EventRegister.getContractRegister, +isWildcard: HandlerRegister.isWildcard(~contractName, ~eventName=name), +handler: HandlerRegister.getHandler(~contractName, ~eventName=name), +contractRegister: HandlerRegister.getContractRegister(~contractName, ~eventName=name), paramsRawEventSchema: paramsRawEventSchema->(Utils.magic: S.t => S.t), }} }}"# @@ -2493,31 +2483,26 @@ let paramsRawEventSchema = S.literal(%raw(`null`))->S.shape(_ => ()) let blockSchema = Block.schema let transactionSchema = Transaction.schema -let handlerRegister: EventRegister.t = EventRegister.make( -~contractName, -~eventName=name, -) - @genType type eventFilter = {} @genType type eventFilters = Internal.noEventFilters let register = (): Internal.evmEventConfig => { -let {getEventFiltersOrThrow, filterByAddresses} = LogSelection.parseEventFiltersOrThrow(~eventFilters=handlerRegister->EventRegister.getEventFilters, ~sighash, ~params=[]) +let {getEventFiltersOrThrow, filterByAddresses} = LogSelection.parseEventFiltersOrThrow(~eventFilters=HandlerRegister.getEventFilters(~contractName, ~eventName=name), ~sighash, ~params=[]) { getEventFiltersOrThrow, filterByAddresses, - dependsOnAddresses: !(handlerRegister->EventRegister.isWildcard) || filterByAddresses, + dependsOnAddresses: !HandlerRegister.isWildcard(~contractName, ~eventName=name) || filterByAddresses, blockSchema: blockSchema->(Utils.magic: S.t => S.t), transactionSchema: transactionSchema->(Utils.magic: S.t => S.t), convertHyperSyncEventArgs: _ => ()->(Utils.magic: eventArgs => Internal.eventParams), id, name, contractName, -isWildcard: (handlerRegister->EventRegister.isWildcard), -handler: handlerRegister->EventRegister.getHandler, -contractRegister: handlerRegister->EventRegister.getContractRegister, +isWildcard: HandlerRegister.isWildcard(~contractName, ~eventName=name), +handler: HandlerRegister.getHandler(~contractName, ~eventName=name), +contractRegister: HandlerRegister.getContractRegister(~contractName, ~eventName=name), paramsRawEventSchema: paramsRawEventSchema->(Utils.magic: S.t => S.t), } }"#.to_string(), @@ -2587,31 +2572,26 @@ let paramsRawEventSchema = S.literal(%raw(`null`))->S.shape(_ => ()) let blockSchema = S.object((_): block => {}) let transactionSchema = S.object((s): transaction => {from: s.field("from", S.nullable(Address.schema))}) -let handlerRegister: EventRegister.t = EventRegister.make( -~contractName, -~eventName=name, -) - @genType type eventFilter = {} @genType type eventFilters = Internal.noEventFilters let register = (): Internal.evmEventConfig => { -let {getEventFiltersOrThrow, filterByAddresses} = LogSelection.parseEventFiltersOrThrow(~eventFilters=handlerRegister->EventRegister.getEventFilters, ~sighash, ~params=[]) +let {getEventFiltersOrThrow, filterByAddresses} = LogSelection.parseEventFiltersOrThrow(~eventFilters=HandlerRegister.getEventFilters(~contractName, ~eventName=name), ~sighash, ~params=[]) { getEventFiltersOrThrow, filterByAddresses, - dependsOnAddresses: !(handlerRegister->EventRegister.isWildcard) || filterByAddresses, + dependsOnAddresses: !HandlerRegister.isWildcard(~contractName, ~eventName=name) || filterByAddresses, blockSchema: blockSchema->(Utils.magic: S.t => S.t), transactionSchema: transactionSchema->(Utils.magic: S.t => S.t), convertHyperSyncEventArgs: _ => ()->(Utils.magic: eventArgs => Internal.eventParams), id, name, contractName, -isWildcard: (handlerRegister->EventRegister.isWildcard), -handler: handlerRegister->EventRegister.getHandler, -contractRegister: handlerRegister->EventRegister.getContractRegister, +isWildcard: HandlerRegister.isWildcard(~contractName, ~eventName=name), +handler: HandlerRegister.getHandler(~contractName, ~eventName=name), +contractRegister: HandlerRegister.getContractRegister(~contractName, ~eventName=name), paramsRawEventSchema: paramsRawEventSchema->(Utils.magic: S.t => S.t), } }"#.to_string(), diff --git a/codegenerator/cli/src/hbs_templating/snapshots/envio__hbs_templating__codegen_templates__test__indexer_code_generates_correct_types_and_values.snap b/codegenerator/cli/src/hbs_templating/snapshots/envio__hbs_templating__codegen_templates__test__indexer_code_generates_correct_types_and_values.snap index b0b7deeac7..bab9ec034f 100644 --- a/codegenerator/cli/src/hbs_templating/snapshots/envio__hbs_templating__codegen_templates__test__indexer_code_generates_correct_types_and_values.snap +++ b/codegenerator/cli/src/hbs_templating/snapshots/envio__hbs_templating__codegen_templates__test__indexer_code_generates_correct_types_and_values.snap @@ -111,7 +111,7 @@ let onBlock: ( Envio.onBlockOptions, Envio.onBlockArgs => promise, ) => unit = ( -EventRegister.onBlock: (unknown, Internal.onBlockArgs => promise) => unit +HandlerRegister.onBlock: (unknown, Internal.onBlockArgs => promise) => unit )->Utils.magic type testIndexerProcessConfigChains = { diff --git a/codegenerator/cli/src/hbs_templating/snapshots/envio__hbs_templating__codegen_templates__test__indexer_code_multiple_chains.snap b/codegenerator/cli/src/hbs_templating/snapshots/envio__hbs_templating__codegen_templates__test__indexer_code_multiple_chains.snap index ec3603fb76..88b376b3e8 100644 --- a/codegenerator/cli/src/hbs_templating/snapshots/envio__hbs_templating__codegen_templates__test__indexer_code_multiple_chains.snap +++ b/codegenerator/cli/src/hbs_templating/snapshots/envio__hbs_templating__codegen_templates__test__indexer_code_multiple_chains.snap @@ -100,7 +100,7 @@ let onBlock: ( Envio.onBlockOptions, Envio.onBlockArgs => promise, ) => unit = ( -EventRegister.onBlock: (unknown, Internal.onBlockArgs => promise) => unit +HandlerRegister.onBlock: (unknown, Internal.onBlockArgs => promise) => unit )->Utils.magic type testIndexerProcessConfigChains = { diff --git a/codegenerator/cli/templates/dynamic/codegen/src/Indexer.res.hbs b/codegenerator/cli/templates/dynamic/codegen/src/Indexer.res.hbs index d067aa3b53..5a8407ca01 100644 --- a/codegenerator/cli/templates/dynamic/codegen/src/Indexer.res.hbs +++ b/codegenerator/cli/templates/dynamic/codegen/src/Indexer.res.hbs @@ -102,9 +102,8 @@ module HandlerTypes = { module type Event = { type event - - let handlerRegister: EventRegister.t - + let contractName: string + let name: string type eventFilters } @@ -131,7 +130,9 @@ module MakeRegister = (Event: Event) => { >, HandlerTypes.eventConfig, > = (contractRegister, ~eventConfig=?) => - Event.handlerRegister->EventRegister.setContractRegister( + HandlerRegister.setContractRegister( + ~contractName=Event.contractName, + ~eventName=Event.name, contractRegister, ~eventOptions=eventConfig, ) @@ -140,7 +141,9 @@ module MakeRegister = (Event: Event) => { Internal.genericHandler>, HandlerTypes.eventConfig, > = (handler, ~eventConfig=?) => { - Event.handlerRegister->EventRegister.setHandler( + HandlerRegister.setHandler( + ~contractName=Event.contractName, + ~eventName=Event.name, handler->( Utils.magic: Internal.genericHandler< Internal.genericHandlerArgs, diff --git a/codegenerator/cli/templates/dynamic/codegen/src/TestHelpers_MockDb.res.hbs b/codegenerator/cli/templates/dynamic/codegen/src/TestHelpers_MockDb.res.hbs index 9844b6f515..3a32955076 100644 --- a/codegenerator/cli/templates/dynamic/codegen/src/TestHelpers_MockDb.res.hbs +++ b/codegenerator/cli/templates/dynamic/codegen/src/TestHelpers_MockDb.res.hbs @@ -318,8 +318,8 @@ and makeProcessEvents = (mockDb: t, ~chainId=?) => async ( } else { let itemsWithContractRegister = [] - let registrations = if EventRegister.isPendingRegistration() { - EventRegister.finishRegistration() + let registrations = if HandlerRegister.isPendingRegistration() { + HandlerRegister.finishRegistration() } else { await HandlerLoader.registerAllHandlers(~config) } diff --git a/scenarios/test_codegen/pnpm-lock.yaml b/scenarios/test_codegen/pnpm-lock.yaml index 5efd71a0e5..607fc3fd6c 100644 --- a/scenarios/test_codegen/pnpm-lock.yaml +++ b/scenarios/test_codegen/pnpm-lock.yaml @@ -92,7 +92,7 @@ importers: specifier: 3.3.1 version: 3.3.1 envio: - specifier: file:/Users/dzakh/code/envio/hyperindex/codegenerator/target/debug/envio/../../../cli/npm/envio + specifier: file:/Users/dzakh/code/envio/hyperindex/scenarios/test_codegen/../../codegenerator/target/debug/envio/../../../cli/npm/envio version: file:../../codegenerator/cli/npm/envio(react-dom@19.2.3(react@19.2.0))(react@19.2.0)(typescript@5.9.3) js-sdsl: specifier: 4.4.2