New Testing Framework#887
Conversation
📝 WalkthroughWalkthroughAdds a TestIndexer feature including in-memory proxy storage, a worker-thread test worker, public TestIndexer types/typings, createTestIndexer factory exported from generated packages, Node.js worker_threads bindings, and widespread refactor of Rescript-specific type names to a generalized type_schema API. Changes
Sequence Diagram(s)sequenceDiagram
participant Consumer as Test Consumer
participant Factory as createTestIndexer()
participant Main as Main thread / Proxy
participant Worker as TestIndexer Worker
participant Store as In-memory Store
Consumer->>Factory: call createTestIndexer()
Factory->>Consumer: returns TestIndexer.handle.process
Consumer->>Main: call process(processConfig)
Main->>Main: validate exactly one chain, check processInProgress
alt already running
Main->>Consumer: throw "process already in progress"
else proceed
Main->>Worker: spawn Worker (workerData: initialState, processConfig)
Worker->>Main: RPC LoadByIds / LoadByField requests
Main->>Store: perform loadByIds/loadByField/writeBatch on in-memory store
Store-->>Main: return data (JSON)
Worker->>Main: send WriteBatch / checkpoints
Main->>Consumer: return { checkpoints: [...], changes: {...} }
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
scenarios/test_codegen/test/EventHandler_test.ts (1)
15-15: Consider consolidating imports from "generated".The
createTestIndexerimport is on a separate line from the existing "generated" imports (lines 3-12). For consistency and cleaner code, consider merging it into the existing import block.♻️ Suggested consolidation
import { TestHelpers, indexer, type User, type Indexer, type EvmChainId, type EvmChainName, type FuelChainId, type SvmChainId, + createTestIndexer, } from "generated"; import { type Address } from "envio"; import { expectType, type TypeEqual } from "ts-expect"; -import { createTestIndexer } from "generated";codegenerator/cli/npm/envio/src/Main.res (1)
358-368: Type parameter should be constrained when implementing actual logic.The
'processConfigtype parameter is free and unconstrained in the current scaffolding. When this mock is replaced with actual implementation, consider constraining it totestIndexerChainConfig(or the appropriate config shape) to ensure type safety at call sites. Currently, the unconstrained type parameter could require explicit type annotations for callers, though this scaffolding phase uses a mock that ignores the parameter entirely.Replace the mock implementation with actual indexer chain processing logic once the API is further developed.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
codegenerator/cli/src/hbs_templating/snapshots/envio__hbs_templating__codegen_templates__test__indexer_code_generates_correct_types_and_values.snapis excluded by!**/*.snapcodegenerator/cli/src/hbs_templating/snapshots/envio__hbs_templating__codegen_templates__test__indexer_code_multiple_chains.snapis excluded by!**/*.snap
📒 Files selected for processing (8)
codegenerator/cli/npm/envio/index.d.tscodegenerator/cli/npm/envio/src/Main.rescodegenerator/cli/src/hbs_templating/codegen_templates.rscodegenerator/cli/templates/dynamic/codegen/index.d.ts.hbscodegenerator/cli/templates/dynamic/codegen/index.js.hbscodegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbsscenarios/erc20_multichain_factory/test/Handler_Test.resscenarios/test_codegen/test/EventHandler_test.ts
🧰 Additional context used
📓 Path-based instructions (3)
codegenerator/cli/templates/dynamic/**/*.hbs
📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)
Templates in Handlebars format (.hbs) live under
codegenerator/cli/templates/dynamic/
Files:
codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbscodegenerator/cli/templates/dynamic/codegen/index.js.hbscodegenerator/cli/templates/dynamic/codegen/index.d.ts.hbs
**/*.{res,resi}
📄 CodeRabbit inference engine (.cursor/rules/rescript.mdc)
**/*.{res,resi}: Always use ReScript 11 documentation
Never suggest ReasonML syntax
Never use[| item |]to create an array. Use[ item ]instead
Must always use=for setting value to a field. Use:=only for ref values created usingreffunction
Use records when working with structured data, and objects to conveniently pass payload data between functions
Never use %raw to access object fields if you know the type
Files:
codegenerator/cli/npm/envio/src/Main.resscenarios/erc20_multichain_factory/test/Handler_Test.res
**/*.res
📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)
Prefer reading ReScript
.resmodules directly; ignore compiled.jsartifacts
Files:
codegenerator/cli/npm/envio/src/Main.resscenarios/erc20_multichain_factory/test/Handler_Test.res
🧠 Learnings (19)
📓 Common learnings
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.245Z
Learning: AFTER EVERY SINGLE CODE CHANGE, you MUST test the indexer with `TUI_OFF=true pnpm dev` to catch runtime errors early, as TypeScript compilation only catches syntax and type errors while runtime errors (database issues, missing entities, logic errors) only appear when running the indexer
Learnt from: nikbhintade
Repo: enviodev/hyperindex PR: 822
File: codegenerator/cli/templates/static/multichain_indexer_template/typescript/src/EventHandlers.ts:10-18
Timestamp: 2025-11-19T05:36:33.975Z
Learning: The multichain_indexer_template in codegenerator/cli/templates/static/ is designed to demonstrate multichain indexing features. It intentionally uses minimal event parameters (e.g., only capturing the `pool` address from Uniswap V3 PoolCreated events) to keep the focus on multichain functionality rather than comprehensive event indexing.
📚 Learning: 2025-12-04T12:12:49.547Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-12-04T12:12:49.547Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.{ts,js} : In Envio HyperIndex, use `entity_id` fields (e.g., `token_id: string`) instead of direct object references for entity relationships
Applied to files:
codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbscodegenerator/cli/npm/envio/index.d.tscodegenerator/cli/templates/dynamic/codegen/index.js.hbscodegenerator/cli/templates/dynamic/codegen/index.d.ts.hbs
📚 Learning: 2025-12-04T12:13:23.246Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.246Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : Import entity types from `generated/src/db/Entities.gen` for type annotations (e.g., `Pair_t`, `Token_t`), NOT from `generated` which exports contract handlers. Use the correct entity type imports to prevent TypeScript errors like 'refers to a value, but is being used as a type'
Applied to files:
codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbsscenarios/test_codegen/test/EventHandler_test.tscodegenerator/cli/templates/dynamic/codegen/index.d.ts.hbs
📚 Learning: 2025-12-04T12:12:49.547Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-12-04T12:12:49.547Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.{ts,js} : Import and use the Effect API (`S`, `createEffect`) from 'envio' package for external calls in HyperIndex handlers
Applied to files:
codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbsscenarios/test_codegen/test/EventHandler_test.tscodegenerator/cli/templates/dynamic/codegen/index.js.hbscodegenerator/cli/templates/dynamic/codegen/index.d.ts.hbs
📚 Learning: 2025-12-04T12:12:49.547Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-12-04T12:12:49.547Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : Use `string | undefined` for optional string fields in Envio types, not `string | null`, as generated types are strict about null vs undefined
Applied to files:
codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs
📚 Learning: 2025-12-04T12:12:49.547Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-12-04T12:12:49.547Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.{ts,js} : When updating existing entities in HyperIndex handlers, always use the spread operator for immutability since returned objects are read-only
Applied to files:
codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbscodegenerator/cli/templates/dynamic/codegen/index.js.hbscodegenerator/cli/templates/dynamic/codegen/index.d.ts.hbs
📚 Learning: 2025-12-04T12:13:23.246Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.246Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : Always verify entity type field names match exactly with the generated entity types. For example, use `token0_id` not `token0`, and `transaction_id` not `transaction`. Run `pnpm tsc --noEmit` to catch type mismatches
Applied to files:
codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs
📚 Learning: 2025-12-04T12:13:23.245Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.245Z
Learning: AFTER EVERY SINGLE CODE CHANGE, you MUST test the indexer with `TUI_OFF=true pnpm dev` to catch runtime errors early, as TypeScript compilation only catches syntax and type errors while runtime errors (database issues, missing entities, logic errors) only appear when running the indexer
Applied to files:
codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbsscenarios/test_codegen/test/EventHandler_test.tscodegenerator/cli/npm/envio/index.d.tscodegenerator/cli/templates/dynamic/codegen/index.js.hbscodegenerator/cli/npm/envio/src/Main.resscenarios/erc20_multichain_factory/test/Handler_Test.rescodegenerator/cli/templates/dynamic/codegen/index.d.ts.hbs
📚 Learning: 2025-11-19T05:36:33.975Z
Learnt from: nikbhintade
Repo: enviodev/hyperindex PR: 822
File: codegenerator/cli/templates/static/multichain_indexer_template/typescript/src/EventHandlers.ts:10-18
Timestamp: 2025-11-19T05:36:33.975Z
Learning: The multichain_indexer_template in codegenerator/cli/templates/static/ is designed to demonstrate multichain indexing features. It intentionally uses minimal event parameters (e.g., only capturing the `pool` address from Uniswap V3 PoolCreated events) to keep the focus on multichain functionality rather than comprehensive event indexing.
Applied to files:
codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbscodegenerator/cli/src/hbs_templating/codegen_templates.rscodegenerator/cli/npm/envio/index.d.tscodegenerator/cli/templates/dynamic/codegen/index.js.hbscodegenerator/cli/templates/dynamic/codegen/index.d.ts.hbs
📚 Learning: 2025-12-04T12:13:23.246Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.246Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/EventHandlers.ts : For Step 1 - Clear all boilerplate code from EventHandlers.ts and replace with empty handlers containing TODO comments referencing the original subgraph implementation
Applied to files:
scenarios/test_codegen/test/EventHandler_test.ts
📚 Learning: 2026-01-05T11:20:07.222Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/navigation.mdc:0-0
Timestamp: 2026-01-05T11:20:07.222Z
Learning: Config parsing flows: `human_config.rs` → `system_config.rs` → `hbs_templating/codegen_templates.rs`
Applied to files:
codegenerator/cli/src/hbs_templating/codegen_templates.rs
📚 Learning: 2025-12-04T12:13:23.246Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.246Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/src/**/*.ts : For Step 3 - Refactor file structure to mirror the original subgraph EXACTLY using the same filenames, create separate handler files by contract (e.g., contract1.ts, contract2.ts) instead of a single EventHandlers.ts file, and move handlers from EventHandlers.ts to contract-specific files
Applied to files:
codegenerator/cli/templates/dynamic/codegen/index.js.hbscodegenerator/cli/templates/dynamic/codegen/index.d.ts.hbs
📚 Learning: 2025-12-04T12:12:49.547Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-12-04T12:12:49.547Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.{ts,js} : Use `context.effect` to make external calls in HyperIndex handlers and prevent double execution during preload optimization
Applied to files:
codegenerator/cli/templates/dynamic/codegen/index.js.hbscodegenerator/cli/templates/dynamic/codegen/index.d.ts.hbs
📚 Learning: 2026-01-05T11:20:07.222Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/navigation.mdc:0-0
Timestamp: 2026-01-05T11:20:07.222Z
Learning: Applies to **/*.{test,spec}.{ts,tsx,js,jsx,res} : Prefer Public module API for testing
Applied to files:
codegenerator/cli/templates/dynamic/codegen/index.js.hbs
📚 Learning: 2025-12-04T12:13:23.246Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.246Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : MAINTAIN BigDecimal precision from the original subgraph. Use BigDecimal and BigInt types for financial calculations, never simplify to JavaScript number type which loses precision. Always use BigDecimal constants (ZERO_BD, ONE_BD) and BigInt constants (ZERO_BI, ONE_BI)
Applied to files:
codegenerator/cli/templates/dynamic/codegen/index.js.hbs
📚 Learning: 2025-12-04T12:12:49.547Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-12-04T12:12:49.547Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.{ts,js} : ALWAYS normalize amounts when adding tokens with different decimal places in HyperIndex handlers, creating helper functions to convert to standard decimals (e.g., 18 decimals)
Applied to files:
codegenerator/cli/templates/dynamic/codegen/index.d.ts.hbs
📚 Learning: 2025-12-04T12:12:49.547Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-12-04T12:12:49.547Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.{ts,js} : Use `!context.isPreload` check to prevent logic from running during preload in HyperIndex handlers
Applied to files:
codegenerator/cli/templates/dynamic/codegen/index.d.ts.hbs
📚 Learning: 2025-12-04T12:13:23.246Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.246Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : For Step 6 - Final Migration Verification: Go through each handler and helper function systematically, comparing the logic line-by-line to the original subgraph implementation. Iterate multiple times until logic is completely correct, as first pass often misses subtle differences
Applied to files:
codegenerator/cli/templates/dynamic/codegen/index.d.ts.hbs
📚 Learning: 2025-12-04T12:13:23.246Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.246Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/src/**/*.ts : For Step 4 - Implement contract registration for factory events using `contractRegister` above the handler to track dynamically created contracts: `Factory.EventName.contractRegister(({ event, context }) => { context.addContractName(event.params.contractAddress); });`
Applied to files:
codegenerator/cli/templates/dynamic/codegen/index.d.ts.hbs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build_and_test
🔇 Additional comments (11)
codegenerator/cli/src/hbs_templating/codegen_templates.rs (1)
1421-1447: Test indexer scaffolding looks well-integrated.The generated ReScript types and factory function align with the public API surface. A few observations:
- The
testIndexerProcessConfigChainsuses optional fields (?) which correctly matchesPartial<Record<...>>in the TypeScript types.- The factory delegates to
Main.makeCreateTestIndexerwith the config, maintaining consistency with the runtime implementation.One consideration: the generated chain field names use
chain{id}format (e.g.,chain1,chain137), but the tests inEventHandler_test.tspass chain IDs directly as keys (1,100, etc.). The@as("{id}")annotation should handle this mapping correctly.scenarios/test_codegen/test/EventHandler_test.ts (1)
638-654: Test case validates the basic API contract.The test correctly validates that
createTestIndexerreturns an indexer with aprocessmethod that resolves to the expected structure. The empty result assertion aligns with the mock implementation inMain.res.codegenerator/cli/templates/dynamic/codegen/index.d.ts.hbs (1)
10-12: Public API surface correctly exposes the test indexer.The template properly imports
TestIndexerfrom the types module and exports thecreateTestIndexerfactory with the correct return type.codegenerator/cli/templates/dynamic/codegen/index.js.hbs (1)
7-7: Export correctly added to the public module surface.The
createTestIndexeris properly exported from the ReScript-compiled module alongside the existing exports.codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs (1)
87-98: TestIndexer type definition follows established patterns.The conditional type correctly extracts the config from
Globaland delegates toTestIndexerFromConfig<Config>, consistent with how theIndexertype is defined. The fallback message provides helpful guidance when codegen hasn't been run.codegenerator/cli/npm/envio/index.d.ts (4)
476-481: Clear type definition for chain configuration.The
TestIndexerChainConfigtype is straightforward with requiredstartBlockandendBlockfields. Good documentation with JSDoc comments.
483-489: Progress type usesunknownfor flexibility.Using
unknown[]forcheckpointsandunknown[]for change arrays provides flexibility but trades off type safety. Consider adding more specific types in a future iteration once the structure is finalized.
491-511: Chain ID extraction assumes single ecosystem.The
TestIndexerChainIdshelper type uses a cascading conditional that only extracts chain IDs from the first matching ecosystem (EVM → Fuel → SVM). This aligns with the current architecture where indexers typically target a single ecosystem, matching the pattern inSingleEcosystemChains.
513-528: Well-designed public API types.The
TestIndexerProcessConfigusingPartial<Record<...>>allows tests to specify only a subset of configured chains, which is practical for targeted testing. TheTestIndexerFromConfigprovides a clean interface with a singleprocessmethod.scenarios/erc20_multichain_factory/test/Handler_Test.res (1)
5-27: No changes needed. The test correctly useschain1for chain ID 1.Chain ID 1 is configured in the scenario, and the generated types map chain IDs to field names using the pattern
chain{id}(e.g.,@as("1") chain1?: Main.testIndexerChainConfig). The test code will compile correctly without type mismatch.codegenerator/cli/npm/envio/src/Main.res (1)
346-356: Type definitions look good.The Test Indexer API type definitions are well-structured:
testIndexerChainConfigappropriately captures block rangetestIndexerProgresscorrectly usesdictandarraytypes for checkpoints and changestestIndexerproperly defines a generic record with a process method
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In @codegenerator/cli/npm/envio/src/Main.res:
- Around line 375-376: The code is using Utils.magic twice to extract `chains`
from `processConfig`, bypassing type safety; define a concrete type
`processConfig` with a `chains: Js.Dict.t<testIndexerChainConfig>` field, update
the `testIndexer` type/signature so its `process` parameter uses this
`processConfig` type (e.g., `process: processConfig =>
promise<testIndexerProgress>`), and replace the double `Utils.magic` extraction
with a typed access to `processConfig.chains` so you no longer need any
`Utils.magic` casts.
🧹 Nitpick comments (2)
codegenerator/cli/npm/envio/src/Main.res (2)
362-365: Consider removing the unused config parameter.The
_configparameter is currently unused in the mock implementation. If it's not needed for the factory signature, consider removing it to reduce clutter. If it's reserved for future implementation, the current approach is acceptable.
390-398: Consider adding error handling for future-proofing.The current mock implementation safely resets
processInProgressin the success path. If this is later converted to a real async implementation that can fail, ensure the flag is also reset in error cases (e.g., usingPromise.catchor try/finally pattern). For the current mock implementation, this is acceptable.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
codegenerator/cli/npm/envio/src/Main.resscenarios/test_codegen/test/EventHandler_test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- scenarios/test_codegen/test/EventHandler_test.ts
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{res,resi}
📄 CodeRabbit inference engine (.cursor/rules/rescript.mdc)
**/*.{res,resi}: Always use ReScript 11 documentation
Never suggest ReasonML syntax
Never use[| item |]to create an array. Use[ item ]instead
Must always use=for setting value to a field. Use:=only for ref values created usingreffunction
Use records when working with structured data, and objects to conveniently pass payload data between functions
Never use %raw to access object fields if you know the type
Files:
codegenerator/cli/npm/envio/src/Main.res
**/*.res
📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)
Prefer reading ReScript
.resmodules directly; ignore compiled.jsartifacts
Files:
codegenerator/cli/npm/envio/src/Main.res
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.245Z
Learning: AFTER EVERY SINGLE CODE CHANGE, you MUST test the indexer with `TUI_OFF=true pnpm dev` to catch runtime errors early, as TypeScript compilation only catches syntax and type errors while runtime errors (database issues, missing entities, logic errors) only appear when running the indexer
📚 Learning: 2025-12-04T12:13:23.245Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.245Z
Learning: AFTER EVERY SINGLE CODE CHANGE, you MUST test the indexer with `TUI_OFF=true pnpm dev` to catch runtime errors early, as TypeScript compilation only catches syntax and type errors while runtime errors (database issues, missing entities, logic errors) only appear when running the indexer
Applied to files:
codegenerator/cli/npm/envio/src/Main.res
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build_and_test
🔇 Additional comments (2)
codegenerator/cli/npm/envio/src/Main.res (2)
344-360: LGTM! Clean type definitions.The type definitions for the Test Indexer API are well-structured and appropriate for the mock implementation.
344-401: The suggested test location is incorrect.scenarios/test_codegenis a separate example indexer project that would not test this CLI code. No specific tests exist for this new Test Indexer API in the Main.res codebase, and the guidance to test inscenarios/test_codegenwould not verify this implementation.If unit tests are needed for
makeCreateTestIndexer, they should be added to the appropriate test suite withincodegenerator/cli/npm/enviowith other Main.res tests, not run against a separate example indexer project.Likely an incorrect or invalid review comment.
| let chains: Js.Dict.t<testIndexerChainConfig> = | ||
| (processConfig->Utils.magic)["chains"]->Utils.magic |
There was a problem hiding this comment.
Unsafe type casting bypasses type safety.
Using Utils.magic twice to extract and cast the chains field from processConfig completely bypasses ReScript's type system. This can lead to runtime errors if the structure doesn't match expectations.
Instead of using a generic 'processConfig type parameter with magic casts, define a proper type for the process config:
type processConfig = {
chains: Js.Dict.t<testIndexerChainConfig>
}
// Then update the testIndexer type to use the concrete type
type testIndexer = {process: processConfig => promise<testIndexerProgress>}This aligns with the coding guideline principle: "Never use %raw to access object fields if you know the type" (similar principle applies to magic).
🔧 Proposed fix
Add a proper type definition before the testIndexer type:
+type testIndexerProcessConfig = {
+ chains: Js.Dict.t<testIndexerChainConfig>,
+}
+
-type testIndexer<'processConfig> = {process: 'processConfig => promise<testIndexerProgress>}
+type testIndexer = {process: testIndexerProcessConfig => promise<testIndexerProgress>}Then update the factory signature and implementation:
-let makeCreateTestIndexer = (~config as _config: Config.t): (unit => testIndexer<'processConfig>) => {
+let makeCreateTestIndexer = (~config as _config: Config.t): (unit => testIndexer) => {
() => {
let state = {processInProgress: false}
{
process: processConfig => {
// ... validation code ...
- let chains: Js.Dict.t<testIndexerChainConfig> =
- (processConfig->Utils.magic)["chains"]->Utils.magic
+ let chains = processConfig.chains
let chainKeys = chains->Js.Dict.keys🤖 Prompt for AI Agents
In @codegenerator/cli/npm/envio/src/Main.res around lines 375 - 376, The code is
using Utils.magic twice to extract `chains` from `processConfig`, bypassing type
safety; define a concrete type `processConfig` with a `chains:
Js.Dict.t<testIndexerChainConfig>` field, update the `testIndexer`
type/signature so its `process` parameter uses this `processConfig` type (e.g.,
`process: processConfig => promise<testIndexerProgress>`), and replace the
double `Utils.magic` extraction with a typed access to `processConfig.chains` so
you no longer need any `Utils.magic` casts.
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In @codegenerator/cli/npm/envio/src/bindings/NodeJs.res:
- Line 103: The onMessage external binding exposes a polymorphic type parameter
'a for the message callback which bypasses serialization/type-safety (same issue
as postMessage/workerData); change the callback signature in onMessage to accept
a concrete serializable type (e.g., Js.Json.t or a specific DTO type) instead of
'a, update the @as("message") param accordingly, and document that callers must
decode/encode messages to/from JSON to ensure safe serialization across worker
boundaries.
- Around line 89-94: The polymorphic type 'a used in workerData, postMessage and
onMessage allows non-serializable values and can cause DataCloneError at
runtime; change those polymorphic types to Js.Json.t (i.e., update external
workerData: Js.Nullable.t<'a> -> Js.Nullable.t<Js.Json.t>, postMessage:
(messagePort, 'a) => unit -> (messagePort, Js.Json.t) => unit, and the onMessage
handler signature likewise) so the bindings only accept structured-clone-able
JSON values, and update any related helper functions or docs to reflect the
Js.Json.t contract.
In @codegenerator/cli/npm/envio/src/Main.res:
- Around line 375-386: The code is unsafely casting processConfig->Utils.magic
to Js.Dict.t<testIndexerChainConfig> via Utils.magic; replace the magic casts
with a typed access and runtime validation: change the function signature or the
surrounding type for processConfig so it includes a chains:
Js.Dict.t<testIndexerChainConfig> field (or extract chains via a safe accessor
that returns option), remove Utils.magic usages, then validate the extracted
value (e.g., pattern-match Some(dict) vs None or use Js.Json decoding) before
computing chainKeys and running createTestIndexer logic to ensure you never
assume the shape at runtime.
🧹 Nitpick comments (3)
codegenerator/cli/npm/envio/src/Main.res (2)
388-397: Consider adding error handling for robustness.The
processInProgressflag is reset inthenResolve(line 395), which only handles the success case. For the current mock implementation this is acceptable, but when implementing real functionality, consider using afinallyblock orcatchhandler to ensure the flag is reset even if an error occurs.♻️ Suggested pattern for future implementation
- Promise.resolve({ - checkpoints: [], - changes: Js.Dict.empty(), - })->Promise.thenResolve(result => { - state.processInProgress = false - result - }) + Promise.resolve({ + checkpoints: [], + changes: Js.Dict.empty(), + }) + ->Promise.then(result => { + state.processInProgress = false + Promise.resolve(result) + }) + ->Promise.catch(error => { + state.processInProgress = false + Promise.reject(error) + })Or use a try/finally pattern when adding real async work.
360-361: Mock implementation: config parameter unused.The
_configparameter is intentionally unused (indicated by the underscore prefix), which is appropriate for this mock implementation. When you're ready to implement the actual test indexer functionality, the config will likely be needed for chain configuration, contract setup, and event processing.Would you like me to help implement the actual test indexer logic that uses the config to process events, or should this remain a stub for now?
codegenerator/cli/npm/envio/src/bindings/NodeJs.res (1)
98-98: TheworkerOptionstype is currently unused in the codebase.The
workerOptionstype only includes theworkerDatafield. While Node.jsWorkerOptionsdoes support additional fields (eval,execArgv,stdin,stdout,stderr,resourceLimits, etc.), there are no usages ofmakeWorkerorworkerOptionsin the codebase. The current minimal binding appears intentional. Expand this type only when those options are actually needed.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
codegenerator/cli/npm/envio/src/Main.rescodegenerator/cli/npm/envio/src/bindings/NodeJs.res
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{res,resi}
📄 CodeRabbit inference engine (.cursor/rules/rescript.mdc)
**/*.{res,resi}: Always use ReScript 11 documentation
Never suggest ReasonML syntax
Never use[| item |]to create an array. Use[ item ]instead
Must always use=for setting value to a field. Use:=only for ref values created usingreffunction
Use records when working with structured data, and objects to conveniently pass payload data between functions
Never use %raw to access object fields if you know the type
Files:
codegenerator/cli/npm/envio/src/bindings/NodeJs.rescodegenerator/cli/npm/envio/src/Main.res
**/*.res
📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)
Prefer reading ReScript
.resmodules directly; ignore compiled.jsartifacts
Files:
codegenerator/cli/npm/envio/src/bindings/NodeJs.rescodegenerator/cli/npm/envio/src/Main.res
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.245Z
Learning: AFTER EVERY SINGLE CODE CHANGE, you MUST test the indexer with `TUI_OFF=true pnpm dev` to catch runtime errors early, as TypeScript compilation only catches syntax and type errors while runtime errors (database issues, missing entities, logic errors) only appear when running the indexer
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/navigation.mdc:0-0
Timestamp: 2026-01-05T11:20:07.222Z
Learning: Verify tests pass by running compiler `pnpm rescript` and tests `pnpm mocha`
📚 Learning: 2025-12-04T12:13:23.245Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.245Z
Learning: AFTER EVERY SINGLE CODE CHANGE, you MUST test the indexer with `TUI_OFF=true pnpm dev` to catch runtime errors early, as TypeScript compilation only catches syntax and type errors while runtime errors (database issues, missing entities, logic errors) only appear when running the indexer
Applied to files:
codegenerator/cli/npm/envio/src/Main.res
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build_and_test
🔇 Additional comments (3)
codegenerator/cli/npm/envio/src/Main.res (3)
346-354: LGTM! Clean type definitions.The type definitions follow ReScript 11 conventions correctly and provide a clear API surface for the test indexer.
356-358: LGTM! Appropriate type definitions for the API.The generic
testIndexertype and mutable state tracking are well-designed for handling concurrent access control.
368-372: LGTM! Effective concurrency guard.The check prevents overlapping process calls with a clear error message.
| @module("worker_threads") external workerData: Js.Nullable.t<'a> = "workerData" | ||
|
|
||
| // MessagePort for communication with parent | ||
| type messagePort | ||
| @module("worker_threads") external parentPort: Js.Nullable.t<messagePort> = "parentPort" | ||
| @send external postMessage: (messagePort, 'a) => unit = "postMessage" |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
Node.js worker_threads workerData postMessage serialization requirements structured clone
💡 Result:
Short answer: workerData and postMessage in worker_threads use the HTML structured clone algorithm — values must be structured-cloneable (primitives, plain objects/arrays, Map/Set, Date, RegExp (with some caveats), TypedArrays/ArrayBuffer, SharedArrayBuffer, MessagePort, etc.). Functions, DOM nodes and other non‑cloneable things will throw (DataCloneError). You can also transfer ownership of transferable objects (e.g. ArrayBuffer, MessagePort) via the second argument to postMessage. See Node.js docs and the Structured Clone spec/MDN for full lists and details. [1][2]
References
- Node.js worker_threads (workerData / postMessage & transfer support). [1]
- MDN: The structured clone algorithm (supported/unsupported types and caveats). [2]
🏁 Script executed:
cat -n codegenerator/cli/npm/envio/src/bindings/NodeJs.res | sed -n '84,107p'Repository: enviodev/hyperindex
Length of output: 1243
Type safety concern: polymorphic types do not enforce serializability constraint.
The polymorphic type 'a used in workerData (line 89), postMessage (line 94), and onMessage (line 103) does not enforce that data must be structured-cloneable. Node.js worker_threads uses the structured clone algorithm, which only supports certain data types (primitives, objects, arrays, Map/Set, Date, RegExp, TypedArrays, SharedArrayBuffer, MessagePort, etc.). Non-serializable data (functions, symbols, DOM nodes, etc.) will cause runtime errors (DataCloneError).
This is inconsistent with workerOptions.workerData (line 98), which correctly uses Js.Json.t to provide stronger compile-time safety. Consider using Js.Json.t for all bindings or documenting this serializability constraint clearly for developers.
🤖 Prompt for AI Agents
In @codegenerator/cli/npm/envio/src/bindings/NodeJs.res around lines 89 - 94,
The polymorphic type 'a used in workerData, postMessage and onMessage allows
non-serializable values and can cause DataCloneError at runtime; change those
polymorphic types to Js.Json.t (i.e., update external workerData:
Js.Nullable.t<'a> -> Js.Nullable.t<Js.Json.t>, postMessage: (messagePort, 'a) =>
unit -> (messagePort, Js.Json.t) => unit, and the onMessage handler signature
likewise) so the bindings only accept structured-clone-able JSON values, and
update any related helper functions or docs to reflect the Js.Json.t contract.
| @new @module("worker_threads") | ||
| external makeWorker: (string, workerOptions) => worker = "Worker" | ||
|
|
||
| @send external onMessage: (worker, @as("message") _, 'a => unit) => unit = "on" |
There was a problem hiding this comment.
Note: Same type safety concern as postMessage.
The onMessage callback uses polymorphic type 'a for the message parameter, which has the same serialization concerns mentioned in the earlier comment about postMessage and workerData.
🤖 Prompt for AI Agents
In @codegenerator/cli/npm/envio/src/bindings/NodeJs.res at line 103, The
onMessage external binding exposes a polymorphic type parameter 'a for the
message callback which bypasses serialization/type-safety (same issue as
postMessage/workerData); change the callback signature in onMessage to accept a
concrete serializable type (e.g., Js.Json.t or a specific DTO type) instead of
'a, update the @as("message") param accordingly, and document that callers must
decode/encode messages to/from JSON to ensure safe serialization across worker
boundaries.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (3)
codegenerator/cli/src/type_schema.rs (2)
19-66: Guard against cycles inTypeDeclMulti::to_rescript_schemaThe dependency-based sorting loop will never terminate if there is a cycle between type declarations, since
sorted.len()will stop increasing but thewhilecondition remains true. Even if current inputs are acyclic, this is a brittle failure mode.Consider detecting lack of progress in an iteration and either:
- returning an error with the offending types, or
- falling back to a stable order with a warning.
This keeps generation robust against accidental cyclic declarations.
290-323: TypeScript type strings: handle non-identifier field names and expand tests
TypeExpr::to_ts_type_stringcurrently emits object types like{ dashed-field: boolean }, which is invalid TS whenfield.name(oras_name) contains characters that require quoting (dashes, spaces, etc.).RecordField::to_valid_rescript_namedoesn’t sanitize such characters, so this is reachable for schemas with those field names.To avoid generating invalid TS:
- Detect when
field_nameis not a valid identifier and emit a quoted key instead:
- e.g.
{ "dashed-field": boolean }or{ ['dashed-field']: boolean }.And to pin behavior, add TS-string tests that cover:
- A
RecordFieldwhereas_nameis set (reserved word or renamed field).- A field name with characters like
-that force quoting.Example adjustment
- let field_name = field - .as_name - .as_ref() - .map_or(field.name.as_str(), |name| name.as_str()); - format!("{}: {}", field_name, field.type_ident.to_ts_type_string()) + let field_name = field + .as_name + .as_ref() + .map_or(field.name.as_str(), |name| name.as_str()); + let needs_quotes = !field_name + .chars() + .next() + .is_some_and(|c| c == '_' || c.is_alphabetic()) + || !field_name + .chars() + .all(|c| c == '_' || c.is_alphanumeric()); + let rendered_name = if needs_quotes { + format!("\"{field_name}\"") + } else { + field_name.to_string() + }; + format!( + "{}: {}", + rendered_name, + field.type_ident.to_ts_type_string() + )Also, these TS string helpers are now part of the codegen surface; after regenerating an indexer that exercises them, please run
TUI_OFF=true pnpm devto catch any runtime/typing regressions. Based on learnings, this is expected after schema/type changes.Also applies to: 347-373, 794-804, 1168-1277
codegenerator/cli/src/config_parsing/event_parsing.rs (1)
3-4: Eth ABI → TypeIdent mapping looks correct (name can be modernized later)The updated
abi_to_rescript_typecorrectly buildsTypeIdenttrees (BigInt/Bool/Address/String/Array/Tuple) and the tests cover arrays, fixed arrays, tuples, and default values, so behavior matches prior expectations.At some point you might want to rename
abi_to_rescript_typeto something likeabi_to_type_identto reflect the generalizedTypeIdentabstraction, but that’s purely cosmetic and can be deferred.Also applies to: 110-151, 193-251
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
codegenerator/cli/src/config_parsing/entity_parsing.rscodegenerator/cli/src/config_parsing/event_parsing.rscodegenerator/cli/src/config_parsing/system_config.rscodegenerator/cli/src/fuel/abi.rscodegenerator/cli/src/hbs_templating/codegen_templates.rscodegenerator/cli/src/hbs_templating/contract_import_templates.rscodegenerator/cli/src/lib.rscodegenerator/cli/src/type_schema.rs
🧰 Additional context used
🧠 Learnings (16)
📓 Common learnings
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.245Z
Learning: AFTER EVERY SINGLE CODE CHANGE, you MUST test the indexer with `TUI_OFF=true pnpm dev` to catch runtime errors early, as TypeScript compilation only catches syntax and type errors while runtime errors (database issues, missing entities, logic errors) only appear when running the indexer
Learnt from: nikbhintade
Repo: enviodev/hyperindex PR: 822
File: codegenerator/cli/templates/static/multichain_indexer_template/typescript/src/EventHandlers.ts:10-18
Timestamp: 2025-11-19T05:36:33.975Z
Learning: The multichain_indexer_template in codegenerator/cli/templates/static/ is designed to demonstrate multichain indexing features. It intentionally uses minimal event parameters (e.g., only capturing the `pool` address from Uniswap V3 PoolCreated events) to keep the focus on multichain functionality rather than comprehensive event indexing.
📚 Learning: 2025-12-04T12:12:49.547Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-12-04T12:12:49.547Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.{ts,js} : In Envio HyperIndex, use `entity_id` fields (e.g., `token_id: string`) instead of direct object references for entity relationships
Applied to files:
codegenerator/cli/src/hbs_templating/contract_import_templates.rscodegenerator/cli/src/config_parsing/system_config.rscodegenerator/cli/src/config_parsing/entity_parsing.rscodegenerator/cli/src/hbs_templating/codegen_templates.rs
📚 Learning: 2025-12-04T12:13:23.246Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.246Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : Import entity types from `generated/src/db/Entities.gen` for type annotations (e.g., `Pair_t`, `Token_t`), NOT from `generated` which exports contract handlers. Use the correct entity type imports to prevent TypeScript errors like 'refers to a value, but is being used as a type'
Applied to files:
codegenerator/cli/src/hbs_templating/contract_import_templates.rscodegenerator/cli/src/config_parsing/event_parsing.rscodegenerator/cli/src/config_parsing/entity_parsing.rscodegenerator/cli/src/hbs_templating/codegen_templates.rs
📚 Learning: 2026-01-05T11:20:07.222Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/navigation.mdc:0-0
Timestamp: 2026-01-05T11:20:07.222Z
Learning: Applies to codegenerator/cli/templates/static/**/*.res : Static ReScript template files live under `codegenerator/cli/templates/static/` and are copied verbatim
Applied to files:
codegenerator/cli/src/hbs_templating/contract_import_templates.rscodegenerator/cli/src/lib.rs
📚 Learning: 2025-12-04T12:13:23.246Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.246Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : Always verify entity type field names match exactly with the generated entity types. For example, use `token0_id` not `token0`, and `transaction_id` not `transaction`. Run `pnpm tsc --noEmit` to catch type mismatches
Applied to files:
codegenerator/cli/src/hbs_templating/contract_import_templates.rscodegenerator/cli/src/config_parsing/entity_parsing.rscodegenerator/cli/src/hbs_templating/codegen_templates.rs
📚 Learning: 2025-12-04T12:13:23.246Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.246Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/src/**/*.ts : For Step 3 - Refactor file structure to mirror the original subgraph EXACTLY using the same filenames, create separate handler files by contract (e.g., contract1.ts, contract2.ts) instead of a single EventHandlers.ts file, and move handlers from EventHandlers.ts to contract-specific files
Applied to files:
codegenerator/cli/src/hbs_templating/contract_import_templates.rs
📚 Learning: 2025-11-25T12:40:26.435Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/rescript.mdc:0-0
Timestamp: 2025-11-25T12:40:26.435Z
Learning: Applies to **/*.{res,resi} : Always use ReScript 11 documentation
Applied to files:
codegenerator/cli/src/fuel/abi.rscodegenerator/cli/src/lib.rs
📚 Learning: 2025-12-04T12:13:23.246Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.246Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/schema.graphql : For Step 2 - Migrate GraphQL schema from TheGraph format to Envio format: remove `entity` decorators, convert `Bytes!` to `String!`, convert `ID!` to `ID!` (keep as is), and ensure ALL entity arrays have `derivedFrom(field: "fieldName")` directives to prevent 'EE211: Arrays of entities is unsupported' error
Applied to files:
codegenerator/cli/src/config_parsing/entity_parsing.rscodegenerator/cli/src/hbs_templating/codegen_templates.rscodegenerator/cli/src/type_schema.rs
📚 Learning: 2025-12-04T12:12:49.547Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-12-04T12:12:49.547Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.graphql : Use `entity_id` fields for relationships in GraphQL schemas (e.g., `user_id: String!`) instead of direct entity references or entity arrays
Applied to files:
codegenerator/cli/src/config_parsing/entity_parsing.rscodegenerator/cli/src/hbs_templating/codegen_templates.rs
📚 Learning: 2025-12-04T12:13:23.246Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.246Z
Learning: Applies to codegenerator/cli/templates/static/shared/{**/*.ts,**/schema.graphql} : Ensure database schema compatibility: verify that the types you're setting in code match the schema entity property types exactly. Compare with schema.graphql - for example, `Int!` in schema requires `number` in code, `BigInt!` requires `BigInt`, `BigDecimal!` requires `BigDecimal`
Applied to files:
codegenerator/cli/src/config_parsing/entity_parsing.rscodegenerator/cli/src/hbs_templating/codegen_templates.rs
📚 Learning: 2025-12-04T12:12:49.547Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-12-04T12:12:49.547Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.graphql : Do not add the entity decorator to GraphQL schema types in HyperIndex
Applied to files:
codegenerator/cli/src/config_parsing/entity_parsing.rscodegenerator/cli/src/hbs_templating/codegen_templates.rs
📚 Learning: 2025-12-04T12:12:49.547Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-12-04T12:12:49.547Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.{ts,js} : When updating existing entities in HyperIndex handlers, always use the spread operator for immutability since returned objects are read-only
Applied to files:
codegenerator/cli/src/hbs_templating/codegen_templates.rs
📚 Learning: 2025-12-04T12:13:23.246Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.246Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : When accessing entity fields that represent relationships, use the `_id` suffix convention. For example, use `token0_id` not `token0` when storing relationships in entity types
Applied to files:
codegenerator/cli/src/hbs_templating/codegen_templates.rs
📚 Learning: 2025-11-19T05:36:33.975Z
Learnt from: nikbhintade
Repo: enviodev/hyperindex PR: 822
File: codegenerator/cli/templates/static/multichain_indexer_template/typescript/src/EventHandlers.ts:10-18
Timestamp: 2025-11-19T05:36:33.975Z
Learning: The multichain_indexer_template in codegenerator/cli/templates/static/ is designed to demonstrate multichain indexing features. It intentionally uses minimal event parameters (e.g., only capturing the `pool` address from Uniswap V3 PoolCreated events) to keep the focus on multichain functionality rather than comprehensive event indexing.
Applied to files:
codegenerator/cli/src/hbs_templating/codegen_templates.rs
📚 Learning: 2026-01-05T11:20:07.222Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/navigation.mdc:0-0
Timestamp: 2026-01-05T11:20:07.222Z
Learning: Applies to **/*.res : Prefer reading ReScript `.res` modules directly; ignore compiled `.js` artifacts
Applied to files:
codegenerator/cli/src/lib.rs
📚 Learning: 2025-11-25T12:40:26.435Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/rescript.mdc:0-0
Timestamp: 2025-11-25T12:40:26.435Z
Learning: Applies to **/*.{res,resi} : Use records when working with structured data, and objects to conveniently pass payload data between functions
Applied to files:
codegenerator/cli/src/type_schema.rs
🧬 Code graph analysis (6)
codegenerator/cli/src/hbs_templating/contract_import_templates.rs (1)
codegenerator/cli/src/type_schema.rs (1)
to_valid_rescript_name(348-364)
codegenerator/cli/src/fuel/abi.rs (1)
codegenerator/cli/src/type_schema.rs (5)
new(20-26)new(113-121)new(366-373)new(398-401)constructors(311-320)
codegenerator/cli/src/config_parsing/event_parsing.rs (1)
codegenerator/cli/src/type_schema.rs (4)
new(20-26)new(113-121)new(366-373)new(398-401)
codegenerator/cli/src/config_parsing/entity_parsing.rs (1)
codegenerator/cli/src/type_schema.rs (4)
new(20-26)new(113-121)new(366-373)new(398-401)
codegenerator/cli/src/hbs_templating/codegen_templates.rs (1)
codegenerator/cli/src/type_schema.rs (5)
to_valid_rescript_name(348-364)to_rescript_schema(28-66)to_rescript_schema(158-181)to_rescript_schema(240-288)to_rescript_schema(551-608)
codegenerator/cli/src/type_schema.rs (2)
codegenerator/cli/src/fuel/abi.rs (1)
vec(348-351)codegenerator/cli/src/config_parsing/event_parsing.rs (1)
params(73-83)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build_and_test
🔇 Additional comments (11)
codegenerator/cli/src/lib.rs (1)
13-13: Module wiring fortype_schemalooks correctDeclaring
mod type_schema;here cleanly exposes the new internal module to the rest of the crate without altering the public surface. No issues spotted.codegenerator/cli/src/hbs_templating/contract_import_templates.rs (1)
190-200: Centralizing ReScript param name normalization is a good moveUsing
RecordField::to_valid_rescript_name(&js_name)here reuses the same reserved-word and identifier normalization as the rest of the type system, so event param names and entity field names stay aligned across generators. No functional issues spotted in this refactor.Also applies to: 465-481
codegenerator/cli/src/config_parsing/system_config.rs (1)
22-24: TypeIdent migration in field selection appears consistentThe switch from
RescriptTypeIdenttoTypeIdentforFuelEventKind::LogData,SelectedField.data_type, and the Block/Transaction field mappings preserves the existing semantics:
- Fuel defaults (
FieldSelection::fuel) still mapid/height/timetoString/Int.- EVM block/transaction fields use the expected
Int/BigInt/Address/String/array/optioncombinations, including theHyperSyncClient.ResponseTypes.*applications.Nothing problematic stands out in the new TypeIdent-based wiring.
Also applies to: 1277-1717
codegenerator/cli/src/fuel/abi.rs (1)
6-8: Fuel ABI → type_schema integration is coherentThe refactor cleanly moves Fuel decoding onto the new
type_schemasurface:
FuelType.type_decl: TypeDeclandFuelLog.data_type: TypeIdentline up withto_type_decl_multireturning aTypeDeclMulti.unified_type_application_to_type_identcorrectly distinguishes named type applications from generic parameters and recursively buildsTypeIdent::TypeApplication/GenericParamgraphs.- Structs/enums/tuples/arrays are mapped into
TypeExpr::{Record, Variant}andTypeIdent::Tuple/Arrayas expected.Behavior is equivalent to the previous Rescript-specific types, just on the new abstractions.
Also applies to: 79-116, 144-193, 216-324, 338-355, 472-481
codegenerator/cli/src/config_parsing/entity_parsing.rs (2)
823-849: GraphQL → TypeIdent mapping for scalars, nullability, and lists is consistent and well-testedThe new
UserDefinedFieldType::to_rescript_type/FieldType::to_rescript_typepipeline correctly encodes:
- Nullable scalars as
TypeIdent::Option(<scalar>)(e.g."Int"→option<int>).- Non-null scalars as the bare type (e.g.
"Int!"→int).- Non-null lists of non-null scalars as
Array<scalar>(e.g."[Int!]!"→array<int>).- Nullable lists as
Option<Array<inner>>, producing shapes likeoption<array<option<int>>>for[Int].The tests around
gql_type_to_rescript_type_*andgql_type_to_rescript_type_entity/enumexercise these paths and confirm the expected string forms, so the migration toTypeIdentpreserves behavior.Field::get_postgres_fieldalso correctly usesSchemaMode::ForDbwhen emittingres_schema_code.Also applies to: 1063-1085, 1672-1730, 1894-1914
1434-1452:GqlScalar→TypeIdentmapping looks correct across built-ins, Big types, and enums*The new
GqlScalar::to_rescript_typeimplementation maps:
- Built-ins (
ID,String,Int,Float,Boolean,Bytes,Json,Timestamp) onto the correspondingTypeIdentprimitives.BigInt/BigDecimaltoTypeIdent::BigInt/BigDecimal.- Custom scalars to:
TypeIdent::IDfor entity references.TypeIdent::SchemaEnum(name.to_capitalized_options())for enums.This aligns with how entity and enum fields are rendered elsewhere (and matches expectations in tests like
gql_type_to_rescript_type_entityandgql_type_to_rescript_type_enum). No mismatches spotted.codegenerator/cli/src/hbs_templating/codegen_templates.rs (5)
29-29: LGTM! Clean refactoring of type imports.The migration from
Rescript*types to generalType*types is consistent with the usage throughout the file and aligns with the broader refactoring effort described in the AI summary.
76-165: LGTM! Type system migration is consistent and complete.The changes from
RescriptTypeIdenttoTypeIdent,RescriptRecordFieldtoRecordField, andRescriptTypeExprtoTypeExprare applied consistently throughout entity and record type template generation. The use ofSchemaMode::ForDb(line 165) is appropriate for database schema generation.
402-610: LGTM! Event template generation correctly uses the new type system.The use of
RecordField::to_valid_rescript_namefor parameter name validation,TypeIdentfor type comparisons, andTypeExprfor building event argument types is consistent throughout. The schema generation withSchemaMode::ForDbis appropriate for event parameter schemas.
1934-1949: LGTM! Test helper constants and functions updated correctly.The test constants (
RESCRIPT_BIG_INT_TYPE,RESCRIPT_ADDRESS_TYPE,RESCRIPT_STRING_TYPE) are updated to useTypeIdent, and theEventParamTypeTemplate::newhelper function correctly uses the new type system.
1419-1445: LGTM! Test indexer scaffolding is well-structured.The new test indexer code generates appropriate types and a factory function. The optional chain configuration fields and the use of
Main.makeCreateTestIndexerwith the config are well-designed. All referenced types (Main.testIndexerChainConfig,Main.testIndexer,Main.makeCreateTestIndexer) and config (Generated.configWithoutRegistrations) are properly defined in the codebase.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
codegenerator/cli/npm/envio/index.d.ts (1)
487-492: Consider more specific types for better type safety.The
unknown[]types forcheckpointsandchangesvalues reduce type safety. Consider defining more specific types if the structure is known (e.g., checkpoint shape, entity change shape), or at least documenting the expected structure in JSDoc comments to help consumers understand what to expect.💡 Potential type refinement example
+/** A checkpoint representing a processed block. */ +export type TestIndexerCheckpoint = { + chainId: number; + blockNumber: number; + // ... other checkpoint fields +}; + +/** An entity change captured during processing. */ +export type TestIndexerEntityChange = { + id: string; + operation: 'create' | 'update' | 'delete'; + // ... other change fields +}; + /** Progress returned after processing blocks with the test indexer. */ export type TestIndexerProgress = { /** Array of checkpoints processed. */ - checkpoints: unknown[]; + checkpoints: TestIndexerCheckpoint[]; /** Entity changes keyed by entity name. */ - changes: Record<string, unknown[]>; + changes: Record<string, TestIndexerEntityChange[]>; };
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
codegenerator/cli/npm/envio/index.d.tscodegenerator/cli/templates/dynamic/codegen/src/Types.res.hbscodegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs
💤 Files with no reviewable changes (1)
- codegenerator/cli/templates/dynamic/codegen/src/Types.res.hbs
🚧 Files skipped from review as they are similar to previous changes (1)
- codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs
🧰 Additional context used
🧠 Learnings (14)
📓 Common learnings
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.245Z
Learning: AFTER EVERY SINGLE CODE CHANGE, you MUST test the indexer with `TUI_OFF=true pnpm dev` to catch runtime errors early, as TypeScript compilation only catches syntax and type errors while runtime errors (database issues, missing entities, logic errors) only appear when running the indexer
📚 Learning: 2025-12-04T12:12:49.547Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-12-04T12:12:49.547Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.{ts,js} : In Envio HyperIndex, use `entity_id` fields (e.g., `token_id: string`) instead of direct object references for entity relationships
Applied to files:
codegenerator/cli/npm/envio/index.d.ts
📚 Learning: 2025-12-04T12:12:49.547Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-12-04T12:12:49.547Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.{ts,js} : When updating existing entities in HyperIndex handlers, always use the spread operator for immutability since returned objects are read-only
Applied to files:
codegenerator/cli/npm/envio/index.d.ts
📚 Learning: 2025-12-04T12:13:23.246Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.246Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : Import entity types from `generated/src/db/Entities.gen` for type annotations (e.g., `Pair_t`, `Token_t`), NOT from `generated` which exports contract handlers. Use the correct entity type imports to prevent TypeScript errors like 'refers to a value, but is being used as a type'
Applied to files:
codegenerator/cli/npm/envio/index.d.ts
📚 Learning: 2025-12-04T12:13:23.246Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.246Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : Always verify entity type field names match exactly with the generated entity types. For example, use `token0_id` not `token0`, and `transaction_id` not `transaction`. Run `pnpm tsc --noEmit` to catch type mismatches
Applied to files:
codegenerator/cli/npm/envio/index.d.ts
📚 Learning: 2026-01-05T11:20:07.222Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/navigation.mdc:0-0
Timestamp: 2026-01-05T11:20:07.222Z
Learning: Applies to **/*.{test,spec}.{ts,tsx,js,jsx,res} : Prefer Public module API for testing
Applied to files:
codegenerator/cli/npm/envio/index.d.ts
📚 Learning: 2025-12-04T12:12:49.547Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-12-04T12:12:49.547Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.{ts,js} : ALWAYS normalize amounts when adding tokens with different decimal places in HyperIndex handlers, creating helper functions to convert to standard decimals (e.g., 18 decimals)
Applied to files:
codegenerator/cli/npm/envio/index.d.ts
📚 Learning: 2025-12-04T12:12:49.547Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-12-04T12:12:49.547Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.{ts,js} : Import and use the Effect API (`S`, `createEffect`) from 'envio' package for external calls in HyperIndex handlers
Applied to files:
codegenerator/cli/npm/envio/index.d.ts
📚 Learning: 2025-12-04T12:13:23.246Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.246Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/src/**/*.ts : For Step 3 - Refactor file structure to mirror the original subgraph EXACTLY using the same filenames, create separate handler files by contract (e.g., contract1.ts, contract2.ts) instead of a single EventHandlers.ts file, and move handlers from EventHandlers.ts to contract-specific files
Applied to files:
codegenerator/cli/npm/envio/index.d.ts
📚 Learning: 2025-12-04T12:12:49.547Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-12-04T12:12:49.547Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : Use `string | undefined` for optional string fields in Envio types, not `string | null`, as generated types are strict about null vs undefined
Applied to files:
codegenerator/cli/npm/envio/index.d.ts
📚 Learning: 2025-12-04T12:13:23.245Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.245Z
Learning: AFTER EVERY SINGLE CODE CHANGE, you MUST test the indexer with `TUI_OFF=true pnpm dev` to catch runtime errors early, as TypeScript compilation only catches syntax and type errors while runtime errors (database issues, missing entities, logic errors) only appear when running the indexer
Applied to files:
codegenerator/cli/npm/envio/index.d.ts
📚 Learning: 2025-12-04T12:13:23.246Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.246Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/{src/handlers,src/**}/*.ts : ALL external calls (RPC calls, API calls, blockchain state fetching) MUST use the Effect API with `context.effect()` to enable preload optimization and parallelization. Create Effect API functions in `src/effects/` folder for better organization
Applied to files:
codegenerator/cli/npm/envio/index.d.ts
📚 Learning: 2025-12-04T12:13:23.246Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.246Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/src/effects/**/*.ts : When making external RPC calls, use viem with createPublicClient and batching for efficiency. Define Effect functions with proper schemas using the S module from 'envio': S.object(), S.string, S.number, etc.
Applied to files:
codegenerator/cli/npm/envio/index.d.ts
📚 Learning: 2025-11-19T05:36:33.975Z
Learnt from: nikbhintade
Repo: enviodev/hyperindex PR: 822
File: codegenerator/cli/templates/static/multichain_indexer_template/typescript/src/EventHandlers.ts:10-18
Timestamp: 2025-11-19T05:36:33.975Z
Learning: The multichain_indexer_template in codegenerator/cli/templates/static/ is designed to demonstrate multichain indexing features. It intentionally uses minimal event parameters (e.g., only capturing the `pool` address from Uniswap V3 PoolCreated events) to keep the focus on multichain functionality rather than comprehensive event indexing.
Applied to files:
codegenerator/cli/npm/envio/index.d.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build_and_test
🔇 Additional comments (4)
codegenerator/cli/npm/envio/index.d.ts (4)
18-19: LGTM! Standard TypeScript utility pattern.The
Prettifyutility type is correctly implemented and will help improve IDE type hints for complex intersection types.
479-484: LGTM! Clean configuration type.The
TestIndexerChainConfigtype is well-defined with clear start and end block boundaries for testing scenarios.
476-531: Well-structured test indexer type system.The test indexer types integrate cleanly with the existing
IndexerConfiginfrastructure and follow established patterns. The conditional type logic for extracting chain IDs correctly handles all three ecosystems (EVM, Fuel, SVM).
517-520: No changes needed—runtime validation is already in place.The type definition using
Partial<Record<...>>allows type-level flexibility, but the implementation validates that exactly one chain must be configured. Empty chains or multiple chains will throw errors with clear messages: "createTestIndexer requires exactly one chain to be defined" and "createTestIndexer does not support processing multiple chains at once."Likely an incorrect or invalid review comment.
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Fix all issues with AI agents
In @codegenerator/cli/npm/envio/src/TestIndexer.res:
- Around line 63-67: The current match using operator with direct comparisons of
Js.Json.t (variables matches, operator, entityFieldValue, fieldValue) can yield
wrong results for objects/arrays or non-numeric values; implement a helper
(e.g., compareValues) that decodes Js.Json.t to primitives then compares: first
try decodeString on both and apply "="/">"/"<" as string compare, else try
decodeNumber on both and apply numeric compare, otherwise fall back to strict
equality only for identical JSON primitives or return false; replace the
existing switch that sets matches with a call to this compareValues helper so
field matching behaves deterministically for strings and numbers.
- Around line 232-244: The onExit handler currently calls
reject(Js.Exn.raiseError(...)) which throws synchronously and prevents the
promise rejection from running; change the handler in
NodeJs.WorkerThreads.onExit (the code block using state.processInProgress and
reject/resolve) to create and pass an Error-like value to reject (e.g.,
construct an Error with the message "Worker exited with code X") instead of
calling Js.Exn.raiseError so the reject callback actually receives the error
object.
- Around line 193-199: In the catch block around NodeJs.WorkerThreads.makeWorker
where you call reject(exn->Utils.magic), remove the subsequent raise(exn) (or
otherwise return/stop after calling reject) so the exception isn't re-thrown
synchronously; ensure the catch only rejects the promise with the error (using
reject) and does not propagate the exception by calling raise, referencing the
worker creation code that uses workerPath, workerData, and reject.
In @codegenerator/cli/npm/envio/src/TestIndexerProxyStorage.res:
- Around line 62-65: The match on msg.payload currently calls
Js.Exn.raiseError(message) inside reject which throws immediately; replace that
call so reject receives an Error/exception object instead of throwing — e.g., in
the Error({message}) branch call reject(Js.Exn.error(message)) or reject(new
Error(message)) rather than reject(Js.Exn.raiseError(message)) so the promise
rejection happens correctly.
🧹 Nitpick comments (1)
codegenerator/cli/npm/envio/src/TestIndexer.res (1)
119-127: Consider explicit error for invalid chain ID strings.Line 121 silently defaults to
0whenInt.fromStringfails. This could mask configuration errors where an invalid chain ID string is provided.♻️ Proposed fix for explicit error handling
let chains = chainKeys->Array.map(chainIdStr => { - let chainId = chainIdStr->Int.fromString->Option.getWithDefault(0) + let chainId = switch chainIdStr->Int.fromString { + | Some(id) => id + | None => Js.Exn.raiseError(`Invalid chain ID: ${chainIdStr}. Expected an integer.`) + } let chain = ChainMap.Chain.makeUnsafe(~chainId)
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
codegenerator/cli/src/hbs_templating/snapshots/envio__hbs_templating__codegen_templates__test__indexer_code_generates_correct_types_and_values.snapis excluded by!**/*.snapcodegenerator/cli/src/hbs_templating/snapshots/envio__hbs_templating__codegen_templates__test__indexer_code_multiple_chains.snapis excluded by!**/*.snap
📒 Files selected for processing (7)
codegenerator/cli/npm/envio/src/Main.rescodegenerator/cli/npm/envio/src/TestIndexer.rescodegenerator/cli/npm/envio/src/TestIndexerProxyStorage.rescodegenerator/cli/npm/envio/src/bindings/NodeJs.rescodegenerator/cli/src/hbs_templating/codegen_templates.rscodegenerator/cli/templates/static/codegen/src/TestIndexerWorker.resscenarios/test_codegen/src/handlers/EventHandlers.res
🚧 Files skipped from review as they are similar to previous changes (1)
- codegenerator/cli/npm/envio/src/bindings/NodeJs.res
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{res,resi}
📄 CodeRabbit inference engine (.cursor/rules/rescript.mdc)
**/*.{res,resi}: Always use ReScript 11 documentation
Never suggest ReasonML syntax
Never use[| item |]to create an array. Use[ item ]instead
Must always use=for setting value to a field. Use:=only for ref values created usingreffunction
Use records when working with structured data, and objects to conveniently pass payload data between functions
Never use %raw to access object fields if you know the type
Files:
codegenerator/cli/npm/envio/src/Main.resscenarios/test_codegen/src/handlers/EventHandlers.rescodegenerator/cli/npm/envio/src/TestIndexer.rescodegenerator/cli/templates/static/codegen/src/TestIndexerWorker.rescodegenerator/cli/npm/envio/src/TestIndexerProxyStorage.res
**/*.res
📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)
Prefer reading ReScript
.resmodules directly; ignore compiled.jsartifacts
Files:
codegenerator/cli/npm/envio/src/Main.resscenarios/test_codegen/src/handlers/EventHandlers.rescodegenerator/cli/npm/envio/src/TestIndexer.rescodegenerator/cli/templates/static/codegen/src/TestIndexerWorker.rescodegenerator/cli/npm/envio/src/TestIndexerProxyStorage.res
codegenerator/cli/templates/static/**/*.res
📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)
Static ReScript template files live under
codegenerator/cli/templates/static/and are copied verbatim
Files:
codegenerator/cli/templates/static/codegen/src/TestIndexerWorker.res
🧠 Learnings (15)
📓 Common learnings
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.245Z
Learning: AFTER EVERY SINGLE CODE CHANGE, you MUST test the indexer with `TUI_OFF=true pnpm dev` to catch runtime errors early, as TypeScript compilation only catches syntax and type errors while runtime errors (database issues, missing entities, logic errors) only appear when running the indexer
📚 Learning: 2025-12-04T12:13:23.246Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.246Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : For Step 6 - Final Migration Verification: Go through each handler and helper function systematically, comparing the logic line-by-line to the original subgraph implementation. Iterate multiple times until logic is completely correct, as first pass often misses subtle differences
Applied to files:
codegenerator/cli/npm/envio/src/Main.res
📚 Learning: 2026-01-05T11:20:07.222Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/navigation.mdc:0-0
Timestamp: 2026-01-05T11:20:07.222Z
Learning: Entry module for generated runtime is `Index.res` which starts HTTP server, loads `Config.res`, calls `RegisterHandlers.res`, spins up `GlobalStateManager.res`
Applied to files:
codegenerator/cli/npm/envio/src/Main.res
📚 Learning: 2025-12-04T12:12:49.547Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-12-04T12:12:49.547Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.{ts,js} : In Envio HyperIndex, use `entity_id` fields (e.g., `token_id: string`) instead of direct object references for entity relationships
Applied to files:
scenarios/test_codegen/src/handlers/EventHandlers.rescodegenerator/cli/src/hbs_templating/codegen_templates.rs
📚 Learning: 2025-12-04T12:13:23.246Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.246Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/schema.graphql : For Step 2 - Migrate GraphQL schema from TheGraph format to Envio format: remove `entity` decorators, convert `Bytes!` to `String!`, convert `ID!` to `ID!` (keep as is), and ensure ALL entity arrays have `derivedFrom(field: "fieldName")` directives to prevent 'EE211: Arrays of entities is unsupported' error
Applied to files:
codegenerator/cli/src/hbs_templating/codegen_templates.rs
📚 Learning: 2025-12-04T12:13:23.246Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.246Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : Import entity types from `generated/src/db/Entities.gen` for type annotations (e.g., `Pair_t`, `Token_t`), NOT from `generated` which exports contract handlers. Use the correct entity type imports to prevent TypeScript errors like 'refers to a value, but is being used as a type'
Applied to files:
codegenerator/cli/src/hbs_templating/codegen_templates.rs
📚 Learning: 2025-12-04T12:13:23.246Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.246Z
Learning: Applies to codegenerator/cli/templates/static/shared/{**/*.ts,**/schema.graphql} : Ensure database schema compatibility: verify that the types you're setting in code match the schema entity property types exactly. Compare with schema.graphql - for example, `Int!` in schema requires `number` in code, `BigInt!` requires `BigInt`, `BigDecimal!` requires `BigDecimal`
Applied to files:
codegenerator/cli/src/hbs_templating/codegen_templates.rs
📚 Learning: 2025-12-04T12:12:49.547Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-12-04T12:12:49.547Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.graphql : Use `entity_id` fields for relationships in GraphQL schemas (e.g., `user_id: String!`) instead of direct entity references or entity arrays
Applied to files:
codegenerator/cli/src/hbs_templating/codegen_templates.rs
📚 Learning: 2025-12-04T12:13:23.246Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.246Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : Always verify entity type field names match exactly with the generated entity types. For example, use `token0_id` not `token0`, and `transaction_id` not `transaction`. Run `pnpm tsc --noEmit` to catch type mismatches
Applied to files:
codegenerator/cli/src/hbs_templating/codegen_templates.rs
📚 Learning: 2025-12-04T12:13:23.246Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.246Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : When accessing entity fields that represent relationships, use the `_id` suffix convention. For example, use `token0_id` not `token0` when storing relationships in entity types
Applied to files:
codegenerator/cli/src/hbs_templating/codegen_templates.rs
📚 Learning: 2025-12-04T12:12:49.547Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-12-04T12:12:49.547Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.graphql : Do not add the entity decorator to GraphQL schema types in HyperIndex
Applied to files:
codegenerator/cli/src/hbs_templating/codegen_templates.rs
📚 Learning: 2025-12-04T12:12:49.547Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-12-04T12:12:49.547Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.{ts,js} : When updating existing entities in HyperIndex handlers, always use the spread operator for immutability since returned objects are read-only
Applied to files:
codegenerator/cli/src/hbs_templating/codegen_templates.rs
📚 Learning: 2025-12-04T12:12:49.547Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-12-04T12:12:49.547Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.graphql : Avoid schema fields like dailyVolume or other time-series fields that aggregate over time in HyperIndex schemas, as these are typically inaccurate
Applied to files:
codegenerator/cli/src/hbs_templating/codegen_templates.rs
📚 Learning: 2025-11-19T05:36:33.975Z
Learnt from: nikbhintade
Repo: enviodev/hyperindex PR: 822
File: codegenerator/cli/templates/static/multichain_indexer_template/typescript/src/EventHandlers.ts:10-18
Timestamp: 2025-11-19T05:36:33.975Z
Learning: The multichain_indexer_template in codegenerator/cli/templates/static/ is designed to demonstrate multichain indexing features. It intentionally uses minimal event parameters (e.g., only capturing the `pool` address from Uniswap V3 PoolCreated events) to keep the focus on multichain functionality rather than comprehensive event indexing.
Applied to files:
codegenerator/cli/src/hbs_templating/codegen_templates.rscodegenerator/cli/templates/static/codegen/src/TestIndexerWorker.res
📚 Learning: 2025-12-04T12:13:23.245Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.245Z
Learning: AFTER EVERY SINGLE CODE CHANGE, you MUST test the indexer with `TUI_OFF=true pnpm dev` to catch runtime errors early, as TypeScript compilation only catches syntax and type errors while runtime errors (database issues, missing entities, logic errors) only appear when running the indexer
Applied to files:
codegenerator/cli/npm/envio/src/TestIndexer.rescodegenerator/cli/templates/static/codegen/src/TestIndexerWorker.res
🧬 Code graph analysis (1)
codegenerator/cli/src/hbs_templating/codegen_templates.rs (1)
codegenerator/cli/src/type_schema.rs (5)
to_valid_rescript_name(348-364)to_rescript_schema(28-66)to_rescript_schema(158-181)to_rescript_schema(240-288)to_rescript_schema(551-608)
🔇 Additional comments (10)
codegenerator/cli/templates/static/codegen/src/TestIndexerWorker.res (1)
1-13: LGTM! Clean worker entry point.The worker initialization correctly wires all dependencies (handlers, config, persistence) using a factory pattern that enables storage injection for the test indexer. The labeled arguments make the API clear and self-documenting.
codegenerator/cli/src/hbs_templating/codegen_templates.rs (3)
1415-1443: Test indexer code generation looks correct.The test indexer scaffolding properly generates:
- Chain configuration types with optional chain fields
- Worker path construction using Node.js path utilities for ESM compatibility
- Factory function wiring config, worker path, and entity configs
The use of
NodeJs.Path.joinandNodeJs.Url.fileURLToPathensures correct path resolution in ESM modules.
30-30: Type import updated correctly.The import now uses the generalized
TypeIdent,TypeExpr,RecordField, andSchemaModetypes fromtype_schema, replacing the previous Rescript-specific type names.
692-705: No issues found with Fuel ABI type declaration generation.The
to_type_decl_multi()method andto_rescript_schema(&SchemaMode::ForDb)are correctly implemented and well-tested. The error handling with.context()appropriately wraps the Result type, and comprehensive unit tests intype_schema.rsvalidate schema generation across all supported types (primitives, BigInt, BigDecimal, Address, Arrays, Tuples, Unions, and Objects). The code integration at lines 692-705 is correct.scenarios/test_codegen/src/handlers/EventHandlers.res (1)
28-35: LGTM! Entity type annotation updated correctly.The change from
Types.gravatartoEntities.Gravatar.tfollows the proper convention for entity type references. ThegravatarObjectnow correctly includes all required fields (imageUrl,updatesCount,size) matching the entity schema.codegenerator/cli/npm/envio/src/Main.res (2)
245-258: LGTM! Test mode integration properly implemented.The
~isTestparameter correctly:
- Disables TUI in test mode
- Sets
isDevelopmentModetofalseduring tests to prevent exposing debug endpoints- Gates server startup to avoid port conflicts during testing
This clean separation allows the test indexer to reuse the main processing logic without side effects.
271-323: Server startup correctly gated by test mode.When
isTestis true, the HTTP server is not started, which:
- Avoids port binding conflicts when running multiple tests
- Reduces test overhead
- Prevents accidental exposure of debug endpoints during testing
The
getStatecallback and chain data construction are only evaluated when the server is actually needed.codegenerator/cli/npm/envio/src/TestIndexerProxyStorage.res (2)
84-117: LGTM! Storage proxy methods correctly delegate to worker.The
loadByIdsOrThrowandloadByFieldOrThrowmethods properly:
- Send typed RPC requests via
sendRequest- Parse responses using the provided schemas
- Handle the async nature of worker communication
The
setOrThrowno-op is acceptable since it's documented as unused.
138-152: Clear error messages for unsupported rollback operations.The rollback-related methods provide explicit error messages directing users to disable
rollbackOnReorgin config. This is appropriate since the in-memory test storage doesn't support rollback semantics.codegenerator/cli/npm/envio/src/TestIndexer.res (1)
256-283: LGTM! Worker initialization with proper error handling.The
initTestWorkerfunction correctly:
- Validates it's running in a worker thread
- Retrieves
parentPortandworkerDatawith proper null checks- Creates the proxy storage and persistence layer
- Calls
Main.startwith~isTest=trueto skip server startup- Handles missing worker data by logging and exiting with failure code
| let matches = switch operator { | ||
| | #"=" => entityFieldValue == fieldValue | ||
| | #">" => entityFieldValue > fieldValue | ||
| | #"<" => entityFieldValue < fieldValue | ||
| } |
There was a problem hiding this comment.
Verify JSON comparison semantics for field matching.
The comparison operators (==, >, <) on Js.Json.t values may not behave as expected for complex types. JSON objects compared with == use reference equality in JavaScript, and > / < operators on non-numeric JSON values may produce unexpected results.
Consider parsing field values to their expected types before comparison, or documenting that only primitive field types (strings, numbers) are supported for field queries.
💡 Suggested approach
For reliable comparisons, consider converting to primitive types:
let compareValues = (a: Js.Json.t, b: Js.Json.t, operator: Persistence.operator): bool => {
// For strings
switch (a->Js.Json.decodeString, b->Js.Json.decodeString) {
| (Some(aStr), Some(bStr)) =>
switch operator {
| #"=" => aStr == bStr
| #">" => aStr > bStr
| #"<" => aStr < bStr
}
// For numbers
| _ =>
switch (a->Js.Json.decodeNumber, b->Js.Json.decodeNumber) {
| (Some(aNum), Some(bNum)) =>
switch operator {
| #"=" => aNum == bNum
| #">" => aNum > bNum
| #"<" => aNum < bNum
}
| _ => a == b // Fallback for other types
}
}
}🤖 Prompt for AI Agents
In @codegenerator/cli/npm/envio/src/TestIndexer.res around lines 63 - 67, The
current match using operator with direct comparisons of Js.Json.t (variables
matches, operator, entityFieldValue, fieldValue) can yield wrong results for
objects/arrays or non-numeric values; implement a helper (e.g., compareValues)
that decodes Js.Json.t to primitives then compares: first try decodeString on
both and apply "="/">"/"<" as string compare, else try decodeNumber on both and
apply numeric compare, otherwise fall back to strict equality only for identical
JSON primitives or return false; replace the existing switch that sets matches
with a call to this compareValues helper so field matching behaves
deterministically for strings and numbers.
| let worker = try { | ||
| NodeJs.WorkerThreads.makeWorker(workerPath, {workerData: workerData}) | ||
| } catch { | ||
| | exn => | ||
| reject(exn->Utils.magic) | ||
| raise(exn) | ||
| } |
There was a problem hiding this comment.
Redundant raise after reject in catch block.
When the worker creation fails, both reject(exn) and raise(exn) are called. The raise will propagate the exception synchronously, potentially bypassing the promise rejection flow and causing unhandled exceptions.
🐛 Proposed fix
let worker = try {
NodeJs.WorkerThreads.makeWorker(workerPath, {workerData: workerData})
} catch {
| exn =>
reject(exn->Utils.magic)
- raise(exn)
+ // Return early - the promise will be rejected
+ // Use a sentinel that won't be used since we rejected
+ Obj.magic()
}Or restructure to avoid the issue:
- let worker = try {
- NodeJs.WorkerThreads.makeWorker(workerPath, {workerData: workerData})
- } catch {
- | exn =>
- reject(exn->Utils.magic)
- raise(exn)
- }
+ let workerResult = try {
+ Ok(NodeJs.WorkerThreads.makeWorker(workerPath, {workerData: workerData}))
+ } catch {
+ | exn => Error(exn)
+ }
+
+ switch workerResult {
+ | Error(exn) => reject(exn->Utils.magic)
+ | Ok(worker) =>
+ // ... rest of the worker setup
+ }Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In @codegenerator/cli/npm/envio/src/TestIndexer.res around lines 193 - 199, In
the catch block around NodeJs.WorkerThreads.makeWorker where you call
reject(exn->Utils.magic), remove the subsequent raise(exn) (or otherwise
return/stop after calling reject) so the exception isn't re-thrown
synchronously; ensure the catch only rejects the promise with the error (using
reject) and does not propagate the exception by calling raise, referencing the
worker creation code that uses workerPath, workerData, and reject.
| worker->NodeJs.WorkerThreads.onExit(code => { | ||
| state.processInProgress = false | ||
| if code !== 0 { | ||
| reject(Js.Exn.raiseError(`Worker exited with code ${code->Int.toString}`)) | ||
| } else { | ||
| // Worker exited successfully (SuccessExit was dispatched in GlobalState) | ||
| let changes = store->extractChanges | ||
| resolve({ | ||
| checkpoints: [], | ||
| changes, | ||
| }) | ||
| } | ||
| }) |
There was a problem hiding this comment.
Bug: Js.Exn.raiseError in onExit throws instead of rejecting.
Same issue as in TestIndexerProxyStorage.res - Js.Exn.raiseError throws synchronously, so the reject callback is never invoked.
🐛 Proposed fix
worker->NodeJs.WorkerThreads.onExit(code => {
state.processInProgress = false
if code !== 0 {
- reject(Js.Exn.raiseError(`Worker exited with code ${code->Int.toString}`))
+ let exn: exn = %raw(`new Error("Worker exited with code " + code)`)
+ reject(exn)
} else {
// Worker exited successfully (SuccessExit was dispatched in GlobalState)
let changes = store->extractChanges
resolve({
checkpoints: [],
changes,
})
}
})📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| worker->NodeJs.WorkerThreads.onExit(code => { | |
| state.processInProgress = false | |
| if code !== 0 { | |
| reject(Js.Exn.raiseError(`Worker exited with code ${code->Int.toString}`)) | |
| } else { | |
| // Worker exited successfully (SuccessExit was dispatched in GlobalState) | |
| let changes = store->extractChanges | |
| resolve({ | |
| checkpoints: [], | |
| changes, | |
| }) | |
| } | |
| }) | |
| worker->NodeJs.WorkerThreads.onExit(code => { | |
| state.processInProgress = false | |
| if code !== 0 { | |
| reject(Js.Exn.error(`Worker exited with code ${code->Int.toString}`)) | |
| } else { | |
| // Worker exited successfully (SuccessExit was dispatched in GlobalState) | |
| let changes = store->extractChanges | |
| resolve({ | |
| checkpoints: [], | |
| changes, | |
| }) | |
| } | |
| }) |
🤖 Prompt for AI Agents
In @codegenerator/cli/npm/envio/src/TestIndexer.res around lines 232 - 244, The
onExit handler currently calls reject(Js.Exn.raiseError(...)) which throws
synchronously and prevents the promise rejection from running; change the
handler in NodeJs.WorkerThreads.onExit (the code block using
state.processInProgress and reject/resolve) to create and pass an Error-like
value to reject (e.g., construct an Error with the message "Worker exited with
code X") instead of calling Js.Exn.raiseError so the reject callback actually
receives the error object.
| switch msg.payload { | ||
| | Response({data}) => resolve(data) | ||
| | Error({message}) => reject(Js.Exn.raiseError(message)) | ||
| } |
There was a problem hiding this comment.
Bug: Js.Exn.raiseError throws immediately, preventing reject from being called.
Js.Exn.raiseError(message) will throw synchronously, so the reject callback is never invoked. This means error handling in the promise chain won't work correctly.
🐛 Proposed fix
switch msg.payload {
| Response({data}) => resolve(data)
- | Error({message}) => reject(Js.Exn.raiseError(message))
+ | Error({message}) => reject(Js.Exn.anyToExnInternal({"message": message}->Obj.magic))
}Alternatively, create the exception without throwing:
switch msg.payload {
| Response({data}) => resolve(data)
- | Error({message}) => reject(Js.Exn.raiseError(message))
+ | Error({message}) => {
+ let exn: exn = %raw(`new Error(message)`)
+ reject(exn)
+ }
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| switch msg.payload { | |
| | Response({data}) => resolve(data) | |
| | Error({message}) => reject(Js.Exn.raiseError(message)) | |
| } | |
| switch msg.payload { | |
| | Response({data}) => resolve(data) | |
| | Error({message}) => reject(Js.Exn.error(message)) | |
| } |
🤖 Prompt for AI Agents
In @codegenerator/cli/npm/envio/src/TestIndexerProxyStorage.res around lines 62
- 65, The match on msg.payload currently calls Js.Exn.raiseError(message) inside
reject which throws immediately; replace that call so reject receives an
Error/exception object instead of throwing — e.g., in the Error({message})
branch call reject(Js.Exn.error(message)) or reject(new Error(message)) rather
than reject(Js.Exn.raiseError(message)) so the promise rejection happens
correctly.
|
Closed in favor of #889 |
Related to: #802
Summary by CodeRabbit
New Features
Public API
Tests
✏️ Tip: You can customize this high-level summary in your review settings.