Skip to content

New Testing Framework (main PR)#889

Merged
DZakh merged 33 commits into
mainfrom
dz/test-indexer-with-vitest
Jan 14, 2026
Merged

New Testing Framework (main PR)#889
DZakh merged 33 commits into
mainfrom
dz/test-indexer-with-vitest

Conversation

@DZakh

@DZakh DZakh commented Jan 9, 2026

Copy link
Copy Markdown
Member

Based on #884
And #802

Summary by CodeRabbit

  • New Features

    • Added a TestIndexer API (createTestIndexer) with worker-backed isolated test runs and a proxy-backed in-memory test store; exposed test-oriented types and per-entity public type aliases.
  • Tests

    • Switched generated tests and templates to Vitest; added Vitest bindings, configs, and test worker entrypoints/helpers.
  • Documentation

    • New ADRs describing test tooling and worker design; templates and docs now require Node.js v22+ (v24 recommended).
  • Breaking Changes

    • Removed legacy generated re-exports — update call sites to new generated type names.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitai Bot commented Jan 9, 2026

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@DZakh has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 20 minutes and 23 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 31eec0c and dbd41b8.

📒 Files selected for processing (9)
  • codegenerator/cli/npm/envio/src/TestIndexer.res
  • codegenerator/cli/templates/static/blank_template/shared/README.md
  • codegenerator/cli/templates/static/erc20_template/shared/README.md
  • codegenerator/cli/templates/static/factory_template/shared/README.md
  • codegenerator/cli/templates/static/greeter_template/typescript/README.md
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/README.md
  • codegenerator/cli/templates/static/svmblock_template/typescript/README.md
  • codegenerator/integration_tests/tests/test_indexers/wildcard-uni-factory/README.md
  • scenarios/erc20_multichain_factory/package.json
📝 Walkthrough

Walkthrough

Adds a worker-based TestIndexer harness and proxy storage bridge, migrates tests to Vitest with ReScript bindings, exposes createTestIndexer/TestIndexer in generated outputs, renames rescript-specific schema types to a unified type_schema, and updates templates, runtime Node/worker bindings, and docs.

Changes

Cohort / File(s) Summary
Type system & codegen refactor
codegenerator/cli/src/type_schema.rs, codegenerator/cli/src/lib.rs, codegenerator/cli/src/config_parsing/*, codegenerator/cli/src/hbs_templating/*, codegenerator/cli/src/fuel/abi.rs, codegenerator/cli/src/hbs_templating/codegen_templates.rs, ...
Renamed Rescript* types to Type* (TypeIdent, TypeExpr, SchemaMode, RecordField), updated codegen templates and tests to use type_schema, added internal JSON/DTS config generation and per-entity public TS aliases.
TestIndexer & worker harness
codegenerator/cli/npm/envio/src/TestIndexer.res, codegenerator/cli/npm/envio/src/TestIndexerProxyStorage.res, codegenerator/cli/templates/static/codegen/src/TestIndexerWorker.res
New TestIndexer runtime/types, in-memory entity store, per-chain ranges, worker↔main IPC protocol, createTestIndexer factory, and worker entrypoint template.
Runtime & worker bindings
codegenerator/cli/npm/envio/src/Main.res, codegenerator/cli/npm/envio/src/bindings/NodeJs.res, codegenerator/cli/npm/envio/src/bindings/Pino.res, codegenerator/cli/npm/envio/src/Benchmark.res
Added ~isTest flag to start, introduced WorkerThreads bindings (worker, parentPort, workerData, execArgv), ESM import-meta/path helpers, and added #silent log level and import-meta-based dirname.
Templates & generated API changes
codegenerator/cli/templates/dynamic/codegen/*, codegenerator/cli/templates/dynamic/codegen/internal.config.json.hbs, codegenerator/cli/templates/dynamic/codegen/index.d.ts.hbs, codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs, codegenerator/cli/templates/dynamic/codegen/src/Generated.res.hbs
Exposed createTestIndexer/TestIndexer in generated index and Types, switched internal config to JSON import, removed legacy re-exports, added per-entity TS aliases, and filtered test/spec handler files from auto-load.
Vitest migration & test updates
codegenerator/cli/npm/envio/src/bindings/Vitest.res, codegenerator/cli/templates/*, *.vitest.config.ts, various *_test.* template/test files, scenarios/*
Added Vitest bindings, migrated templates and example tests from Mocha/assert/Chai to Vitest, added vitest devDep/script changes.
Storage & persistence plumbing
codegenerator/cli/npm/envio/src/TestIndexerProxyStorage.res, codegenerator/cli/npm/envio/src/PgStorage.res, scenarios/test_codegen/test/helpers/Mock.res
Implemented proxy request/response correlation and serializable change/entity shapes, forwarded Persistence.storage methods via IPC, adjusted PgStorage onnotice handling, and added test-mode log suppression/defaults.
Scaffolding, templates & docs
.cursor/commands/testrust.md, adr/why-vitest.md, adr/why-workers-for-test-indexer.md, CONTRIBUTING.md, README templates, many codegen/static templates
Added test instructions, ADRs for Vitest and worker-thread decisions, bumped Node.js recommended version to v22+, updated package templates and package.json scripts/deps, and various small template tweaks.

Sequence Diagram(s)

sequenceDiagram
    participant Caller as Caller (test/runtime)
    participant Main as Main Thread (envio)
    participant Proxy as ProxyStorage (Main)
    participant Worker as Worker Thread
    participant Indexer as Generated Indexer (Worker)

    Caller->>Main: createTestIndexer(...).process(chains)
    Main->>Worker: spawn(workerPath, workerData={processConfig, initialState})
    Worker->>Indexer: initialize/register handlers
    Indexer->>Worker: storage request (LoadByIds / LoadByField / WriteBatch)
    Worker->>Main: postMessage(workerPayload)
    Main->>Proxy: sendRequest(payload) -> Persistence access
    Proxy-->>Main: Response/Error
    Main-->>Worker: postMessage(mainPayload)
    Worker->>Indexer: deliver response -> continue processing
    loop per-checkpoint
      Indexer->>Worker: more storage ops
      Worker->>Main: forward ops
      Main-->>Worker: responses
    end
    Indexer->>Worker: finish -> final changes
    Worker->>Main: exit with final changes
    Main->>Caller: aggregate and return result
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Suggested reviewers

  • JonoPrest

Poem

🐇 I hop through threads with a curious cheer,

Types reborn and tests now run with Vitest here.
I ferry id-tagged whispers, proxying each store,
Workers hum, main keeps state — then hand back more.
A small white rabbit nods: the harness is now sure.

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.45% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The PR title broadly refers to a testing framework implementation but does not clearly specify the primary change: introducing Vitest-based test indexer infrastructure with worker threads. Consider a more specific title like 'Add Vitest-based test indexer with worker thread isolation' or 'Implement TestIndexer harness with Vitest testing framework' to better communicate the main technical contribution.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In @codegenerator/cli/npm/envio/src/TestIndexerProxyStorage.res:
- Around line 62-65: The Error branch currently calls Js.Exn.raiseError(message)
which throws immediately instead of returning an exception to reject; change the
branch to create and pass an Error/exception object to reject (e.g., construct a
JS Error with the message or an Exn value) instead of calling Js.Exn.raiseError
— replace the line in the Error({message}) arm that references Js.Exn.raiseError
with code that builds an Error/exception object and calls reject(thatError) so
reject is actually invoked (look for the switch on msg.payload, the
Error({message}) arm, and the resolve/reject callbacks).

In @codegenerator/cli/templates/dynamic/codegen/index.d.ts.hbs:
- Around line 10-12: The declaration for createTestIndexer is incorrect: update
the signature in index.d.ts.hbs so it matches the actual ReScript export (a
zero-arg function returning the TestIndexer specialized by the
testIndexerProcessConfig type) — e.g. change export const createTestIndexer: ()
=> TestIndexer; to export const createTestIndexer: () =>
TestIndexer<testIndexerProcessConfig> (or the equivalent TypeScript
representation used in ./src/Types.ts), and ensure the testIndexerProcessConfig
type is exported from Types.ts so the generic specialization resolves; reference
the createTestIndexer, TestIndexer and testIndexerProcessConfig symbols to
locate and update the template to match
codegenerator/cli/src/hbs_templating/codegen_templates.rs expected signature.

In @codegenerator/cli/templates/static/erc20_template/typescript/config.yaml:
- Around line 11-14: Update the ERC20 contract entry's address field (under the
contracts list with name: ERC20 and start_block: 20000000) to the canonical UNI
mainnet address 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984 so the template
monitors the actual UNI token instead of Loot: Adventure Gold.
🧹 Nitpick comments (8)
codegenerator/cli/npm/envio/index.d.ts (1)

486-492: Consider using more specific types for TestIndexerProgress.

The checkpoints and changes fields use unknown[] and Record<string, unknown[]>, which provides minimal type safety. If the structure of checkpoints and entity changes is known, consider exposing more specific types to improve the developer experience when consuming test results.

codegenerator/cli/npm/envio/src/bindings/Vitest.res (1)

22-28: Clarify matcher categorization.

The toContainItem matcher (line 27) is grouped under "String matchers" comment (line 22) but it's actually an array matcher. Consider moving the comment or reorganizing for clarity.

♻️ Suggested reorganization
   // String matchers
   toContain: string => unit,
   toMatch: Js.Re.t => unit,
   toMatchString: string => unit,
+  // Array matchers
   toContainItem: 'a => unit,
   toHaveLength: int => unit,
-  // Array matchers
-  toContainItem: 'a => unit,
-  toHaveLength: int => unit,
codegenerator/cli/src/hbs_templating/codegen_templates.rs (1)

1932-1948: Consider renaming test constants for consistency.

The constants are named RESCRIPT_*_TYPE but now hold TypeIdent values rather than RescriptTypeIdent. While functionally correct, the naming could be confusing.

♻️ Optional rename suggestion
-    const RESCRIPT_BIG_INT_TYPE: TypeIdent = TypeIdent::BigInt;
-    const RESCRIPT_ADDRESS_TYPE: TypeIdent = TypeIdent::Address;
-    const RESCRIPT_STRING_TYPE: TypeIdent = TypeIdent::String;
+    const BIG_INT_TYPE: TypeIdent = TypeIdent::BigInt;
+    const ADDRESS_TYPE: TypeIdent = TypeIdent::Address;
+    const STRING_TYPE: TypeIdent = TypeIdent::String;
scenarios/erc20_multichain_factory/test/Handler_Test.res (1)

18-25: Make the changes assertion robust (prototype/representation differences).
Deep-equality on Js.Dict.empty() can be brittle if the runtime returns {} vs Object.create(null); consider asserting emptiness via keys/entries instead.

Proposed tweak
-    Assert.deepEqual(
-      result,
-      {
-        checkpoints: [],
-        changes: Js.Dict.empty(),
-      },
-      ~message="Test Indexer should return the correct result",
-    )
+    Assert.equal(result.checkpoints->Array.length, 0, ~message="expected no checkpoints")
+    Assert.equal(result.changes->Js.Dict.keys->Array.length, 0, ~message="expected no changes")
codegenerator/cli/templates/static/codegen/src/TestIndexerWorker.res (1)

1-13: Don’t skip runtime validation for this worker-thread wiring.
Please run the indexer after these template changes (per team learnings): TUI_OFF=true pnpm dev.

codegenerator/cli/src/config_parsing/event_parsing.rs (1)

3-3: Consistent migration to TypeIdent type system.

The function correctly updates all type mappings from RescriptTypeIdent to TypeIdent:

  • Primitive types (lines 112-118)
  • Recursive array handling (lines 119-133)
  • Tuple type construction (lines 134-150)

The tests verify the conversions work correctly with the new type system.

Consider renaming abi_to_rescript_type to abi_to_type_ident to better reflect that it now returns TypeIdent rather than a ReScript-specific type. This would improve code clarity as part of the broader migration away from ReScript-specific naming.

♻️ Optional rename suggestion
-pub fn abi_to_rescript_type(param: &EthereumEventParam) -> TypeIdent {
+pub fn abi_to_type_ident(param: &EthereumEventParam) -> TypeIdent {

And update all call sites accordingly.

Also applies to: 110-150

codegenerator/cli/npm/envio/src/TestIndexerProxyStorage.res (1)

132-134: Consider adding more explicit stubs for test-only methods.

The executeUnsafe and setChainMeta methods return Obj.magic() which is a potential runtime hazard if these methods are ever called during tests. Consider either:

  1. Raising an explicit error like the rollback methods do
  2. Adding a comment explaining why these are safe no-ops in test context
codegenerator/cli/npm/envio/src/TestIndexer.res (1)

188-192: Redundant JSON serialization/deserialization.

The pattern processConfig->Utils.magic->Js.Json.serializeExn->Js.Json.parseExn followed by another Js.Json.serializeExn->Js.Json.parseExn appears to be an unnecessarily convoluted way to pass data. This double serialize/parse cycle could lose precision or behave unexpectedly with certain data types.

♻️ Suggested simplification

If the goal is to ensure the data is a plain JSON object for the worker, consider:

-          let workerDataObj = {
-            "processConfig": processConfig->Utils.magic->Js.Json.serializeExn->Js.Json.parseExn,
-            "initialState": initialState->Utils.magic,
-          }
-          let workerData = workerDataObj->Js.Json.serializeExn->Js.Json.parseExn
+          let workerData = {
+            "processConfig": processConfig->Utils.magic,
+            "initialState": initialState->Utils.magic,
+          }->Utils.magic

Or if serialization is truly needed for worker data cloning, a single round-trip should suffice.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1ea763b and d43493f.

⛔ 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.snap is excluded by !**/*.snap
  • codegenerator/cli/src/hbs_templating/snapshots/envio__hbs_templating__codegen_templates__test__indexer_code_multiple_chains.snap is excluded by !**/*.snap
📒 Files selected for processing (38)
  • .cursor/commands/testrust.md
  • adr/why-vitest.md
  • codegenerator/cli/npm/envio/index.d.ts
  • codegenerator/cli/npm/envio/src/Main.res
  • codegenerator/cli/npm/envio/src/TestIndexer.res
  • codegenerator/cli/npm/envio/src/TestIndexerProxyStorage.res
  • codegenerator/cli/npm/envio/src/bindings/NodeJs.res
  • codegenerator/cli/npm/envio/src/bindings/Vitest.res
  • codegenerator/cli/src/config_parsing/entity_parsing.rs
  • codegenerator/cli/src/config_parsing/event_parsing.rs
  • codegenerator/cli/src/config_parsing/system_config.rs
  • codegenerator/cli/src/fuel/abi.rs
  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
  • codegenerator/cli/src/hbs_templating/contract_import_templates.rs
  • codegenerator/cli/src/lib.rs
  • codegenerator/cli/src/type_schema.rs
  • codegenerator/cli/templates/dynamic/codegen/index.d.ts.hbs
  • codegenerator/cli/templates/dynamic/codegen/index.js.hbs
  • codegenerator/cli/templates/dynamic/codegen/package.json.hbs
  • codegenerator/cli/templates/dynamic/codegen/src/Generated.res.hbs
  • codegenerator/cli/templates/dynamic/codegen/src/Types.res.hbs
  • codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs
  • codegenerator/cli/templates/dynamic/contract_import_templates/rescript/src/Indexer_test.res.hbs
  • codegenerator/cli/templates/dynamic/contract_import_templates/typescript/src/indexer.test.ts.hbs
  • codegenerator/cli/templates/dynamic/init_templates/shared/package.json.hbs
  • codegenerator/cli/templates/static/blank_template/rescript/rescript.json
  • codegenerator/cli/templates/static/blank_template/rescript/src/Indexer_test.res
  • codegenerator/cli/templates/static/blank_template/rescript/vitest.config.ts
  • codegenerator/cli/templates/static/codegen/src/TestIndexerWorker.res
  • codegenerator/cli/templates/static/erc20_template/typescript/config.yaml
  • codegenerator/cli/templates/static/erc20_template/typescript/src/indexer.test.ts
  • codegenerator/cli/templates/static/factory_template/typescript/src/indexer.test.ts
  • codegenerator/cli/templates/static/greeter_template/typescript/src/indexer.test.ts
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/src/indexer.test.ts
  • codegenerator/cli/templates/static/svmblock_template/typescript/src/indexer.test.ts
  • scenarios/erc20_multichain_factory/test/Handler_Test.res
  • scenarios/test_codegen/src/handlers/EventHandlers.res
  • scenarios/test_codegen/test/EventHandler_test.ts
💤 Files with no reviewable changes (2)
  • codegenerator/cli/templates/dynamic/codegen/src/Types.res.hbs
  • codegenerator/cli/templates/static/blank_template/rescript/rescript.json
🧰 Additional context used
📓 Path-based instructions (5)
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/package.json.hbs
  • codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs
  • codegenerator/cli/templates/dynamic/init_templates/shared/package.json.hbs
  • codegenerator/cli/templates/dynamic/codegen/src/Generated.res.hbs
  • codegenerator/cli/templates/dynamic/contract_import_templates/rescript/src/Indexer_test.res.hbs
  • codegenerator/cli/templates/dynamic/codegen/index.d.ts.hbs
  • codegenerator/cli/templates/dynamic/contract_import_templates/typescript/src/indexer.test.ts.hbs
  • codegenerator/cli/templates/dynamic/codegen/index.js.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 using ref function
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:

  • scenarios/test_codegen/src/handlers/EventHandlers.res
  • codegenerator/cli/templates/static/blank_template/rescript/src/Indexer_test.res
  • codegenerator/cli/npm/envio/src/bindings/Vitest.res
  • codegenerator/cli/npm/envio/src/TestIndexerProxyStorage.res
  • scenarios/erc20_multichain_factory/test/Handler_Test.res
  • codegenerator/cli/npm/envio/src/bindings/NodeJs.res
  • codegenerator/cli/templates/static/codegen/src/TestIndexerWorker.res
  • codegenerator/cli/npm/envio/src/Main.res
  • codegenerator/cli/npm/envio/src/TestIndexer.res
**/*.res

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Prefer reading ReScript .res modules directly; ignore compiled .js artifacts

Files:

  • scenarios/test_codegen/src/handlers/EventHandlers.res
  • codegenerator/cli/templates/static/blank_template/rescript/src/Indexer_test.res
  • codegenerator/cli/npm/envio/src/bindings/Vitest.res
  • codegenerator/cli/npm/envio/src/TestIndexerProxyStorage.res
  • scenarios/erc20_multichain_factory/test/Handler_Test.res
  • codegenerator/cli/npm/envio/src/bindings/NodeJs.res
  • codegenerator/cli/templates/static/codegen/src/TestIndexerWorker.res
  • codegenerator/cli/npm/envio/src/Main.res
  • codegenerator/cli/npm/envio/src/TestIndexer.res
**/*.{test,spec}.{ts,tsx,js,jsx,res}

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

**/*.{test,spec}.{ts,tsx,js,jsx,res}: Always use single assert to check the whole value instead of multiple asserts for every field
Prefer Public module API for testing
Use _only to specify which tests to run during test development

Files:

  • codegenerator/cli/templates/static/greeter_template/typescript/src/indexer.test.ts
  • codegenerator/cli/templates/static/erc20_template/typescript/src/indexer.test.ts
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/src/indexer.test.ts
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/blank_template/rescript/src/Indexer_test.res
  • codegenerator/cli/templates/static/codegen/src/TestIndexerWorker.res
🧠 Learnings (52)
📓 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: After any change to TypeScript files, run `pnpm tsc --noEmit` to ensure successful compilation

Applied to files:

  • codegenerator/cli/templates/dynamic/codegen/package.json.hbs
  • codegenerator/cli/templates/dynamic/init_templates/shared/package.json.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/package.json.hbs
  • codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs
  • codegenerator/cli/templates/dynamic/init_templates/shared/package.json.hbs
  • codegenerator/cli/templates/static/greeter_template/typescript/src/indexer.test.ts
  • codegenerator/cli/templates/static/erc20_template/typescript/src/indexer.test.ts
  • codegenerator/cli/npm/envio/index.d.ts
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/src/indexer.test.ts
  • codegenerator/cli/src/hbs_templating/contract_import_templates.rs
  • codegenerator/cli/templates/static/erc20_template/typescript/config.yaml
  • codegenerator/cli/templates/dynamic/contract_import_templates/typescript/src/indexer.test.ts.hbs
  • codegenerator/cli/src/config_parsing/entity_parsing.rs
  • 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/templates/dynamic/codegen/package.json.hbs
  • scenarios/test_codegen/src/handlers/EventHandlers.res
  • codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs
  • codegenerator/cli/templates/dynamic/init_templates/shared/package.json.hbs
  • codegenerator/cli/templates/static/greeter_template/typescript/src/indexer.test.ts
  • codegenerator/cli/templates/static/erc20_template/typescript/src/indexer.test.ts
  • codegenerator/cli/npm/envio/index.d.ts
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/src/indexer.test.ts
  • codegenerator/cli/src/hbs_templating/contract_import_templates.rs
  • codegenerator/cli/templates/dynamic/codegen/src/Generated.res.hbs
  • codegenerator/cli/templates/dynamic/contract_import_templates/rescript/src/Indexer_test.res.hbs
  • codegenerator/cli/templates/dynamic/codegen/index.d.ts.hbs
  • codegenerator/cli/templates/static/codegen/src/TestIndexerWorker.res
  • codegenerator/cli/templates/dynamic/contract_import_templates/typescript/src/indexer.test.ts.hbs
  • codegenerator/cli/templates/dynamic/codegen/index.js.hbs
  • 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/templates/dynamic/codegen/package.json.hbs
  • codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs
  • codegenerator/cli/templates/dynamic/init_templates/shared/package.json.hbs
  • codegenerator/cli/templates/static/erc20_template/typescript/src/indexer.test.ts
  • codegenerator/cli/src/hbs_templating/contract_import_templates.rs
  • codegenerator/cli/src/type_schema.rs
  • codegenerator/cli/templates/dynamic/contract_import_templates/typescript/src/indexer.test.ts.hbs
  • codegenerator/cli/src/config_parsing/entity_parsing.rs
  • 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} : 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/package.json.hbs
  • scenarios/test_codegen/src/handlers/EventHandlers.res
  • codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs
  • codegenerator/cli/templates/dynamic/init_templates/shared/package.json.hbs
  • codegenerator/cli/templates/static/greeter_template/typescript/src/indexer.test.ts
  • codegenerator/cli/templates/static/erc20_template/typescript/src/indexer.test.ts
  • codegenerator/cli/npm/envio/index.d.ts
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/src/indexer.test.ts
  • codegenerator/cli/src/hbs_templating/contract_import_templates.rs
  • codegenerator/cli/templates/dynamic/contract_import_templates/rescript/src/Indexer_test.res.hbs
  • codegenerator/cli/templates/dynamic/codegen/index.d.ts.hbs
  • codegenerator/cli/templates/static/codegen/src/TestIndexerWorker.res
  • codegenerator/cli/templates/static/erc20_template/typescript/config.yaml
  • codegenerator/cli/templates/dynamic/contract_import_templates/typescript/src/indexer.test.ts.hbs
  • codegenerator/cli/templates/dynamic/codegen/index.js.hbs
  • codegenerator/cli/src/config_parsing/entity_parsing.rs
  • 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} : Use `!context.isPreload` check to prevent logic from running during preload in HyperIndex handlers

Applied to files:

  • codegenerator/cli/templates/dynamic/codegen/package.json.hbs
  • codegenerator/cli/templates/dynamic/codegen/src/Generated.res.hbs
  • 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 : 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/package.json.hbs
  • scenarios/test_codegen/test/EventHandler_test.ts
  • scenarios/test_codegen/src/handlers/EventHandlers.res
  • codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs
  • codegenerator/cli/templates/static/greeter_template/typescript/src/indexer.test.ts
  • codegenerator/cli/templates/static/erc20_template/typescript/src/indexer.test.ts
  • codegenerator/cli/npm/envio/index.d.ts
  • codegenerator/cli/src/config_parsing/event_parsing.rs
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/src/indexer.test.ts
  • codegenerator/cli/src/hbs_templating/contract_import_templates.rs
  • codegenerator/cli/src/lib.rs
  • codegenerator/cli/templates/dynamic/contract_import_templates/rescript/src/Indexer_test.res.hbs
  • codegenerator/cli/templates/dynamic/codegen/index.d.ts.hbs
  • codegenerator/cli/templates/dynamic/contract_import_templates/typescript/src/indexer.test.ts.hbs
  • codegenerator/cli/src/config_parsing/entity_parsing.rs
  • 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/package.json.hbs
  • scenarios/test_codegen/test/EventHandler_test.ts
  • codegenerator/cli/templates/dynamic/init_templates/shared/package.json.hbs
  • codegenerator/cli/npm/envio/index.d.ts
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/src/indexer.test.ts
  • codegenerator/cli/src/hbs_templating/contract_import_templates.rs
  • codegenerator/cli/templates/dynamic/codegen/src/Generated.res.hbs
  • codegenerator/cli/templates/dynamic/contract_import_templates/rescript/src/Indexer_test.res.hbs
  • codegenerator/cli/templates/dynamic/codegen/index.d.ts.hbs
  • codegenerator/cli/templates/static/erc20_template/typescript/config.yaml
  • codegenerator/cli/templates/dynamic/contract_import_templates/typescript/src/indexer.test.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/package.json.hbs
  • scenarios/test_codegen/test/EventHandler_test.ts
  • codegenerator/cli/templates/dynamic/init_templates/shared/package.json.hbs
  • codegenerator/cli/templates/static/greeter_template/typescript/src/indexer.test.ts
  • codegenerator/cli/templates/static/erc20_template/typescript/src/indexer.test.ts
  • codegenerator/cli/npm/envio/index.d.ts
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/src/indexer.test.ts
  • codegenerator/cli/templates/dynamic/codegen/src/Generated.res.hbs
  • codegenerator/cli/templates/dynamic/contract_import_templates/rescript/src/Indexer_test.res.hbs
  • codegenerator/cli/templates/dynamic/contract_import_templates/typescript/src/indexer.test.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/package.json.hbs
  • 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: Verify tests pass by running compiler `pnpm rescript` and tests `pnpm mocha`

Applied to files:

  • codegenerator/cli/templates/dynamic/codegen/package.json.hbs
  • codegenerator/cli/templates/dynamic/init_templates/shared/package.json.hbs
  • codegenerator/cli/templates/static/blank_template/rescript/src/Indexer_test.res
  • codegenerator/cli/templates/dynamic/contract_import_templates/rescript/src/Indexer_test.res.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 codegenerator/cli/templates/static/**/*.res : Static ReScript template files live under `codegenerator/cli/templates/static/` and are copied verbatim

Applied to files:

  • codegenerator/cli/templates/dynamic/codegen/package.json.hbs
  • codegenerator/cli/templates/dynamic/init_templates/shared/package.json.hbs
  • codegenerator/cli/templates/static/blank_template/rescript/src/Indexer_test.res
  • codegenerator/cli/src/hbs_templating/contract_import_templates.rs
  • codegenerator/cli/templates/dynamic/codegen/src/Generated.res.hbs
  • codegenerator/cli/src/lib.rs
  • codegenerator/cli/templates/dynamic/contract_import_templates/rescript/src/Indexer_test.res.hbs
  • codegenerator/cli/templates/static/blank_template/rescript/vitest.config.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} : Use `_only` to specify which tests to run during test development

Applied to files:

  • codegenerator/cli/templates/dynamic/codegen/package.json.hbs
  • codegenerator/cli/templates/dynamic/init_templates/shared/package.json.hbs
  • codegenerator/cli/templates/static/blank_template/rescript/vitest.config.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 **/*.res : Prefer reading ReScript `.res` modules directly; ignore compiled `.js` artifacts

Applied to files:

  • codegenerator/cli/templates/dynamic/codegen/package.json.hbs
  • codegenerator/cli/src/lib.rs
  • codegenerator/cli/templates/static/blank_template/rescript/vitest.config.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: Whitelist the following commands for HyperIndex development: `pnpm codegen` and `pnpm tsc --noEmit`

Applied to files:

  • codegenerator/cli/templates/dynamic/codegen/package.json.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:

  • scenarios/test_codegen/test/EventHandler_test.ts
  • codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs
  • codegenerator/cli/templates/static/greeter_template/typescript/src/indexer.test.ts
  • codegenerator/cli/templates/static/erc20_template/typescript/src/indexer.test.ts
  • codegenerator/cli/npm/envio/index.d.ts
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/src/indexer.test.ts
  • scenarios/erc20_multichain_factory/test/Handler_Test.res
  • codegenerator/cli/templates/dynamic/contract_import_templates/rescript/src/Indexer_test.res.hbs
  • codegenerator/cli/templates/dynamic/codegen/index.d.ts.hbs
  • codegenerator/cli/templates/static/codegen/src/TestIndexerWorker.res
  • codegenerator/cli/templates/dynamic/codegen/index.js.hbs
  • codegenerator/cli/npm/envio/src/TestIndexer.res
📚 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
  • codegenerator/cli/templates/dynamic/codegen/src/Generated.res.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:

  • scenarios/test_codegen/test/EventHandler_test.ts
  • codegenerator/cli/src/hbs_templating/contract_import_templates.rs
  • codegenerator/cli/templates/dynamic/codegen/src/Generated.res.hbs
  • codegenerator/cli/templates/dynamic/contract_import_templates/rescript/src/Indexer_test.res.hbs
  • codegenerator/cli/templates/dynamic/codegen/index.d.ts.hbs
  • codegenerator/cli/templates/static/erc20_template/typescript/config.yaml
  • codegenerator/cli/templates/dynamic/contract_import_templates/typescript/src/indexer.test.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:

  • scenarios/test_codegen/test/EventHandler_test.ts
  • codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs
  • codegenerator/cli/templates/static/greeter_template/typescript/src/indexer.test.ts
  • codegenerator/cli/templates/static/erc20_template/typescript/src/indexer.test.ts
  • codegenerator/cli/npm/envio/index.d.ts
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/src/indexer.test.ts
  • codegenerator/cli/templates/dynamic/codegen/src/Generated.res.hbs
  • codegenerator/cli/templates/dynamic/contract_import_templates/rescript/src/Indexer_test.res.hbs
  • codegenerator/cli/templates/dynamic/codegen/index.d.ts.hbs
  • codegenerator/cli/templates/dynamic/codegen/index.js.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:

  • scenarios/test_codegen/test/EventHandler_test.ts
  • codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs
  • codegenerator/cli/npm/envio/index.d.ts
  • scenarios/erc20_multichain_factory/test/Handler_Test.res
  • codegenerator/cli/templates/dynamic/codegen/index.d.ts.hbs
  • codegenerator/cli/templates/static/codegen/src/TestIndexerWorker.res
  • codegenerator/cli/templates/static/erc20_template/typescript/config.yaml
  • codegenerator/cli/templates/dynamic/codegen/index.js.hbs
  • 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/**/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:

  • scenarios/test_codegen/src/handlers/EventHandlers.res
  • codegenerator/cli/src/hbs_templating/contract_import_templates.rs
  • codegenerator/cli/src/type_schema.rs
  • codegenerator/cli/src/config_parsing/entity_parsing.rs
  • 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 : For entity creation patterns, always include all required fields in a single object literal and use `context.Entity.set(entity)` (without await). Update patterns should spread existing entity data and update only changed fields: `const updated = { ...existing, field: newValue }; context.Entity.set(updated);`

Applied to files:

  • scenarios/test_codegen/src/handlers/EventHandlers.res
  • codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs
  • codegenerator/cli/templates/dynamic/contract_import_templates/typescript/src/indexer.test.ts.hbs
  • 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/templates/dynamic/codegen/src/Types.ts.hbs
  • codegenerator/cli/src/config_parsing/entity_parsing.rs
  • 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/utils/**/*.ts : When implementing Step 5a (Helper Functions), examine ALL function calls within helper functions and recursively implement any dependencies that have NO entity/handler dependencies

Applied to files:

  • codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs
  • codegenerator/cli/templates/dynamic/codegen/src/Generated.res.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/init_templates/shared/package.json.hbs
  • codegenerator/cli/templates/static/greeter_template/typescript/src/indexer.test.ts
  • codegenerator/cli/templates/static/blank_template/rescript/src/Indexer_test.res
  • codegenerator/cli/npm/envio/src/bindings/Vitest.res
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/src/indexer.test.ts
  • codegenerator/cli/templates/dynamic/contract_import_templates/rescript/src/Indexer_test.res.hbs
  • adr/why-vitest.md
  • codegenerator/cli/templates/dynamic/contract_import_templates/typescript/src/indexer.test.ts.hbs
  • codegenerator/cli/templates/static/blank_template/rescript/vitest.config.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} : Always use single assert to check the whole value instead of multiple asserts for every field

Applied to files:

  • codegenerator/cli/templates/static/greeter_template/typescript/src/indexer.test.ts
  • codegenerator/cli/templates/static/erc20_template/typescript/src/indexer.test.ts
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/src/indexer.test.ts
  • codegenerator/cli/templates/dynamic/contract_import_templates/rescript/src/Indexer_test.res.hbs
  • codegenerator/cli/templates/dynamic/contract_import_templates/typescript/src/indexer.test.ts.hbs
  • codegenerator/cli/templates/static/blank_template/rescript/vitest.config.ts
📚 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 **/*.test.{res,resi} : Never use `Js.Console.log` in test files. Use `Assert` module for all verifications

Applied to files:

  • codegenerator/cli/templates/static/greeter_template/typescript/src/indexer.test.ts
  • codegenerator/cli/templates/static/erc20_template/typescript/src/indexer.test.ts
  • codegenerator/cli/npm/envio/src/bindings/Vitest.res
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/src/indexer.test.ts
  • codegenerator/cli/templates/dynamic/contract_import_templates/typescript/src/indexer.test.ts.hbs
  • codegenerator/cli/templates/static/blank_template/rescript/vitest.config.ts
📚 Learning: 2025-05-27T17:07:12.878Z
Learnt from: JonoPrest
Repo: enviodev/hyperindex PR: 555
File: scenarios/test_codegen/test/lib_tests/EntityHistory_test.res:631-659
Timestamp: 2025-05-27T17:07:12.878Z
Learning: In isolated tests for EntityHistory rollbacks with controlled mock data setup, the ordering of getRollbackDiff results is deterministic and doesn't require sorting before comparison with deepStrictEqual.

Applied to files:

  • codegenerator/cli/templates/static/greeter_template/typescript/src/indexer.test.ts
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/src/indexer.test.ts
  • codegenerator/cli/templates/dynamic/contract_import_templates/typescript/src/indexer.test.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} : 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/static/erc20_template/typescript/src/indexer.test.ts
  • codegenerator/cli/npm/envio/index.d.ts
  • codegenerator/cli/templates/dynamic/codegen/index.d.ts.hbs
  • codegenerator/cli/templates/static/erc20_template/typescript/config.yaml
📚 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-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/npm/envio/src/bindings/Vitest.res
  • codegenerator/cli/src/lib.rs
  • codegenerator/cli/src/fuel/abi.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 **/*.test.{res,resi} : Use try/catch as expressions instead of refs for tracking success/failure in tests

Applied to files:

  • codegenerator/cli/npm/envio/src/bindings/Vitest.res
📚 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/contract_import_templates.rs
  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
📚 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: For multichain indexing, prefix all entity IDs with `event.chainId`: `${event.chainId}-${originalId}`, never hardcode `chainId = 1`, always use `event.chainId`, and use chain-specific Bundle IDs like `${chainId}-1` for accurate pricing per network

Applied to files:

  • codegenerator/cli/src/hbs_templating/contract_import_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/dynamic/**/*.hbs : Templates in Handlebars format (.hbs) live under `codegenerator/cli/templates/dynamic/`

Applied to files:

  • codegenerator/cli/templates/dynamic/codegen/src/Generated.res.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/src/Generated.res.hbs
  • codegenerator/cli/templates/dynamic/codegen/index.d.ts.hbs
  • codegenerator/cli/templates/dynamic/codegen/index.js.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: Entry point for the Rust CLI is `codegenerator/cli/src/lib.rs`

Applied to files:

  • .cursor/commands/testrust.md
📚 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: Command dispatcher for Rust CLI is `codegenerator/cli/src/commands.rs`

Applied to files:

  • .cursor/commands/testrust.md
📚 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
📚 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/**/config.yaml : When using multichain indexing, ensure contract names in config.yaml are unique across all networks, place contract definitions in the global contracts section (not in network sections), and only define addresses for those contracts in network sections

Applied to files:

  • codegenerator/cli/templates/static/erc20_template/typescript/config.yaml
📚 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/**/config.yaml : For dynamic contracts created by factories, remove the `address` field from contract definitions in config.yaml since they don't have a fixed address

Applied to files:

  • codegenerator/cli/templates/static/erc20_template/typescript/config.yaml
📚 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,yaml,yml} : Ensure case consistency when matching addresses in configuration objects, using lowercase keys to match `address.toLowerCase()` lookups

Applied to files:

  • codegenerator/cli/templates/static/erc20_template/typescript/config.yaml
📚 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 : Never hardcode contract addresses or configuration values - always use constants defined in the original subgraph or utility files. Reference original subgraph patterns for constants like FACTORY_ADDRESS, ADDRESS_ZERO, etc.

Applied to files:

  • codegenerator/cli/templates/static/erc20_template/typescript/config.yaml
📚 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/**/*.{yaml,yml} : Use the Envio EVM schema file for YAML validation in config.yaml: `yaml-language-server: $schema=./node_modules/envio/evm.schema.json`

Applied to files:

  • codegenerator/cli/templates/static/erc20_template/typescript/config.yaml
📚 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 **/*.test.{res,resi} : When testing with multiple iterations, collect results in data structures and assert on them

Applied to files:

  • codegenerator/cli/templates/dynamic/contract_import_templates/typescript/src/indexer.test.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 : 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: 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/**/*.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.rs
  • 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/**/schema.graphql : CRITICAL ENVIO REQUIREMENT: All entity arrays like `[Mint!]!` MUST have `derivedFrom` directives. Without this, codegen will fail with error 'EE211: Arrays of entities is unsupported'

Applied to files:

  • codegenerator/cli/src/config_parsing/entity_parsing.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 : NEVER use arrays of entities (e.g., `[Enter!]!` or `[User!]!`) in HyperIndex GraphQL schemas - use `entity_id` fields instead

Applied to files:

  • codegenerator/cli/src/config_parsing/entity_parsing.rs
🧬 Code graph analysis (5)
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/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/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_rescript_schema (28-66)
  • to_rescript_schema (158-181)
  • to_rescript_schema (240-288)
  • to_rescript_schema (551-608)
  • option (779-781)
⏰ 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

Comment thread codegenerator/cli/npm/envio/src/TestIndexer.res Outdated
Comment thread codegenerator/cli/npm/envio/src/TestIndexerProxyStorage.res
Comment thread codegenerator/cli/templates/dynamic/codegen/index.d.ts.hbs
Comment thread codegenerator/cli/templates/static/erc20_template/typescript/config.yaml Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

🤖 Fix all issues with AI agents
In @codegenerator/cli/npm/envio/src/TestIndexer.res:
- Around line 36-46: handleLoadByIds currently drops missing ids which breaks
"OrThrow" semantics and positional alignment; update handleLoadByIds to (1)
resolve entities in the same order as the input ids (so results array aligns
with ids) and (2) detect any missing ids and throw an error instead of silently
omitting them. Specifically, inside handleLoadByIds use ids->Array.map to look
up each id in entityDict via Js.Dict.get, collect missing ids, and if any exist
call Js.Exn.raiseError (or raise with a descriptive message including the
missing id list) so the test stub matches Persistence.storage.loadByIdsOrThrow
behavior.
- Around line 158-192: The loop uses getUnsafe on multiple arrays
(checkpointIds, checkpointBlockNumbers, checkpointBlockHashes,
checkpointChainIds, checkpointEventsProcessed) assuming they all have identical
lengths; add a single invariant check before the for loop that compares
checkpointIds->Array.length against each of the other checkpoint arrays and
throws/returns a clear error message (e.g., "mismatched checkpoint metadata
lengths") if any differ, so the code fails fast with a helpful message instead
of throwing later from getUnsafe.
- Around line 326-336: The onExit callback currently uses
reject(Js.Exn.raiseError(...)) which throws immediately instead of returning a
rejected promise; change it to call reject with an Error value (e.g. create an
Error with the `Worker exited with code ...` message) so the promise is actually
rejected rather than an exception being thrown inside
worker->NodeJs.WorkerThreads.onExit; update the branch that handles code !== 0
to call reject(new Error(...)) (or otherwise construct an exception object)
instead of using Js.Exn.raiseError.
- Around line 48-82: handleLoadByField currently compares raw Js.Json.t values
with ==, >, < which is unsafe and non‑exhaustive; update the matching in
handleLoadByField to first classify/decode both entityFieldValue and fieldValue
into concrete JS types (number, string, bool, null, object, array) and perform
type‑aware comparisons (numeric comparisons for numbers, lexicographic for
strings, strict equality for booleans/null, deep structural equality for
objects/arrays using a deterministic deepEqual or JSON.stringify fallback), and
make the Persistence.operator match exhaustive (handle any additional operators
like !=, >=, <=) so every operator path is implemented. Ensure you reference
entity->Js.Json.decodeObject and obj->Js.Dict.get(fieldName) to retrieve values,
then decode via Js.Json.classify / Js.Json.decodeNumber / Js.Json.decodeString
and use a deterministic deep equality for complex types before pushing to
results.
- Around line 284-318: The message handler in
worker->NodeJs.WorkerThreads.onMessage currently calls store methods
(handleLoadByIds, handleLoadByField, handleWriteBatch) directly so exceptions
never send a response; wrap each handler invocation in a try/catch, call the
existing respond function in both success and failure paths, and on exception
send TestIndexerProxyStorage.Error({message: Js.Exn.message(exception) |>
Belt.Option.getWithDefault("unknown")}) (or equivalent) as the payload so the
worker-side sendRequest promise always resolves/rejects; apply this to the
LoadByIds, LoadByField branches and the WriteBatch branch (ensure WriteBatch
still responds with Js.Json.null on success and an Error payload on exception).
- Around line 195-221: The code in makeInitialState currently parses chainIdStr
with Int.fromString->Option.getWithDefault(0), which silently converts invalid
keys to 0; instead, detect parse failure and raise a clear error. Replace the
getWithDefault(0) usage by explicitly handling the Option from Int.fromString
(e.g., pattern-match or use an Option.getExn) and throw a descriptive exception
referencing chainIdStr when parsing fails so malformed processConfigChains keys
do not become chainId 0; keep the subsequent use of ChainMap.Chain.makeUnsafe
and the existing validation that the chain exists in config.
- Around line 343-374: The workerData type currently includes an unused
processConfig field; remove that field from the workerData type declaration
(symbol: workerData) and eliminate where processConfig is serialized when
spawning the worker (the earlier workerData construction), ensuring you only
serialize initialState into NodeJs.WorkerThreads.workerData; verify there are no
remaining references to processConfig in this module or in the worker
initialization path (symbols to check: TestIndexerProxyStorage.make,
TestIndexerProxyStorage.makeStorage, Main.start) and adjust any related
serialization logic so the worker receives just the initialState to avoid extra
overhead.
- Around line 84-156: handleWriteBatch currently only processes
update.latestChange and thus ignores update.history; update.history entries must
be applied in order before applying latestChange so all intermediate Set/Delete
events update store.entities and changesByCheckpoint correctly. Modify the loop
over updates in handleWriteBatch to iterate update.history (in order) and apply
each historical change using the same logic used for update.latestChange
(handling Set and Delete: update entityDict via Js.Dict.set/unsafeDeleteKey,
compute checkpointKey from checkpointId->Float.toString, lookup/create
entityChanges and entityChange, parse Set entities with
store.entityConfigs->Js.Dict.unsafeGet(...).schema and push into
entityChange.sets, or push entityId into entityChange.deleted), then apply
update.latestChange last; ensure you reuse the existing code paths for Set and
Delete to avoid duplication.

In @codegenerator/cli/npm/envio/src/TestIndexerProxyStorage.res:
- Around line 96-107: sendRequest currently creates a never-settling Promise and
leaves entries in pendingRequests if the worker never responds; update
sendRequest (and if needed nextRequestId) to start a per-request timeout when
creating the promise that will call reject with a timeout error and remove the
pendingRequests entry (Js.Dict.delete) when the timer fires or when the response
resolves, and ensure the timer is cleared on resolve/reject; keep using
Promise.make and postMessage to parentPort but add the timeout logic tied to the
same request id so pendingRequests cannot leak forever.
- Around line 68-91: The message handler currently calls
reject(Js.Exn.raiseError(message)) which throws instead of rejecting the
promise; change it to construct an exception value and pass that to reject
without raising. In the make function's onPortMessage callback (the switch on
msg.payload), replace the direct call to Js.Exn.raiseError with creating an
exception value (e.g., via a Js.Exn constructor/helper) and call reject(err) so
the promise rejects cleanly; ensure proxy.pendingRequests cleanup stays the
same.
🧹 Nitpick comments (2)
codegenerator/cli/npm/envio/src/TestIndexerProxyStorage.res (2)

76-91: Unknown response id should not hard-crash the worker.
Line 83 raises if no pending request exists. That can take down tests if the main thread double-sends / sends late after cleanup. Consider logging + ignoring (or at least not throwing) for robustness.


109-212: Avoid silent no-ops / Obj.magic() in storage methods that could be called.
setOrThrow being a no-op (Lines 139-142) and executeUnsafe / setChainMeta returning Obj.magic() (Lines 191-193) can hide real usage bugs and create confusing failures downstream. Prefer explicit raiseError("...not supported in TestIndexer...") for unsupported operations.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d43493f and 0cce5a5.

📒 Files selected for processing (2)
  • codegenerator/cli/npm/envio/src/TestIndexer.res
  • codegenerator/cli/npm/envio/src/TestIndexerProxyStorage.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 using ref function
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/TestIndexerProxyStorage.res
  • codegenerator/cli/npm/envio/src/TestIndexer.res
**/*.res

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Prefer reading ReScript .res modules directly; ignore compiled .js artifacts

Files:

  • codegenerator/cli/npm/envio/src/TestIndexerProxyStorage.res
  • codegenerator/cli/npm/envio/src/TestIndexer.res
🧠 Learnings (4)
📓 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/TestIndexer.res
📚 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/npm/envio/src/TestIndexer.res
📚 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/npm/envio/src/TestIndexer.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/TestIndexerProxyStorage.res (1)

7-54: Good separation of worker/main message envelopes and tagged payloads.
The @tag("type") + @as(...) approach looks consistent for cross-thread discriminated messaging.

codegenerator/cli/npm/envio/src/TestIndexer.res (2)

26-34: Store initialization looks straightforward and keeps entity configs alongside data.
This is a clean base for schema-aware parsing later in handleWriteBatch.


231-341: [Rewritten review comment]
[Exactly ONE classification tag]

Comment on lines +36 to +46
let handleLoadByIds = (store: store, ~tableName: string, ~ids: array<string>): Js.Json.t => {
let entityDict = store.entities->Js.Dict.get(tableName)->Option.getWithDefault(Js.Dict.empty())
let results = []
ids->Array.forEach(id => {
switch entityDict->Js.Dict.get(id) {
| Some(entity) => results->Array.push(entity)->ignore
| None => ()
}
})
results->Js.Json.array
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

handleLoadByIds likely violates “OrThrow” expectations (missing ids are silently dropped).
If Persistence.storage.loadByIdsOrThrow is expected to error on missing ids (or preserve positional alignment), this will diverge from production behavior and can make tests misleading.

🤖 Prompt for AI Agents
In @codegenerator/cli/npm/envio/src/TestIndexer.res around lines 36 - 46,
handleLoadByIds currently drops missing ids which breaks "OrThrow" semantics and
positional alignment; update handleLoadByIds to (1) resolve entities in the same
order as the input ids (so results array aligns with ids) and (2) detect any
missing ids and throw an error instead of silently omitting them. Specifically,
inside handleLoadByIds use ids->Array.map to look up each id in entityDict via
Js.Dict.get, collect missing ids, and if any exist call Js.Exn.raiseError (or
raise with a descriptive message including the missing id list) so the test stub
matches Persistence.storage.loadByIdsOrThrow behavior.

Comment thread codegenerator/cli/npm/envio/src/TestIndexer.res
Comment thread codegenerator/cli/npm/envio/src/TestIndexer.res
Comment thread codegenerator/cli/npm/envio/src/TestIndexer.res
Comment on lines +195 to +221
let makeInitialState = (
~config: Config.t,
~processConfigChains: Js.Dict.t<chainConfig>,
): Persistence.initialState => {
let chainKeys = processConfigChains->Js.Dict.keys
let chains = chainKeys->Array.map(chainIdStr => {
let chainId = chainIdStr->Int.fromString->Option.getWithDefault(0)
let chain = ChainMap.Chain.makeUnsafe(~chainId)

if !(config.chainMap->ChainMap.has(chain)) {
Js.Exn.raiseError(`Chain ${chainIdStr} is not configured in config.yaml`)
}

let processChainConfig = processConfigChains->Js.Dict.unsafeGet(chainIdStr)
{
Persistence.id: chainId,
startBlock: processChainConfig.startBlock,
endBlock: Some(processChainConfig.endBlock),
maxReorgDepth: 0, // No reorg support in test indexer
progressBlockNumber: -1,
numEventsProcessed: 0,
firstEventBlockNumber: None,
timestampCaughtUpToHeadOrEndblock: None,
dynamicContracts: [],
}
})

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Chain id parsing should not default to 0 on invalid keys.
Line 201 falls back to 0, which can mask malformed process configs and potentially produce confusing “wrong chain” behavior. Prefer throwing when Int.fromString fails.

Proposed fix
-    let chainId = chainIdStr->Int.fromString->Option.getWithDefault(0)
+    let chainId = switch chainIdStr->Int.fromString {
+    | Some(v) => v
+    | None => Js.Exn.raiseError(`Invalid chain id key: ${chainIdStr}`)
+    }
📝 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.

Suggested change
let makeInitialState = (
~config: Config.t,
~processConfigChains: Js.Dict.t<chainConfig>,
): Persistence.initialState => {
let chainKeys = processConfigChains->Js.Dict.keys
let chains = chainKeys->Array.map(chainIdStr => {
let chainId = chainIdStr->Int.fromString->Option.getWithDefault(0)
let chain = ChainMap.Chain.makeUnsafe(~chainId)
if !(config.chainMap->ChainMap.has(chain)) {
Js.Exn.raiseError(`Chain ${chainIdStr} is not configured in config.yaml`)
}
let processChainConfig = processConfigChains->Js.Dict.unsafeGet(chainIdStr)
{
Persistence.id: chainId,
startBlock: processChainConfig.startBlock,
endBlock: Some(processChainConfig.endBlock),
maxReorgDepth: 0, // No reorg support in test indexer
progressBlockNumber: -1,
numEventsProcessed: 0,
firstEventBlockNumber: None,
timestampCaughtUpToHeadOrEndblock: None,
dynamicContracts: [],
}
})
let makeInitialState = (
~config: Config.t,
~processConfigChains: Js.Dict.t<chainConfig>,
): Persistence.initialState => {
let chainKeys = processConfigChains->Js.Dict.keys
let chains = chainKeys->Array.map(chainIdStr => {
let chainId = switch chainIdStr->Int.fromString {
| Some(v) => v
| None => Js.Exn.raiseError(`Invalid chain id key: ${chainIdStr}`)
}
let chain = ChainMap.Chain.makeUnsafe(~chainId)
if !(config.chainMap->ChainMap.has(chain)) {
Js.Exn.raiseError(`Chain ${chainIdStr} is not configured in config.yaml`)
}
let processChainConfig = processConfigChains->Js.Dict.unsafeGet(chainIdStr)
{
Persistence.id: chainId,
startBlock: processChainConfig.startBlock,
endBlock: Some(processChainConfig.endBlock),
maxReorgDepth: 0, // No reorg support in test indexer
progressBlockNumber: -1,
numEventsProcessed: 0,
firstEventBlockNumber: None,
timestampCaughtUpToHeadOrEndblock: None,
dynamicContracts: [],
}
})
🤖 Prompt for AI Agents
In @codegenerator/cli/npm/envio/src/TestIndexer.res around lines 195 - 221, The
code in makeInitialState currently parses chainIdStr with
Int.fromString->Option.getWithDefault(0), which silently converts invalid keys
to 0; instead, detect parse failure and raise a clear error. Replace the
getWithDefault(0) usage by explicitly handling the Option from Int.fromString
(e.g., pattern-match or use an Option.getExn) and throw a descriptive exception
referencing chainIdStr when parsing fails so malformed processConfigChains keys
do not become chainId 0; keep the subsequent use of ChainMap.Chain.makeUnsafe
and the existing validation that the chain exists in config.

Comment on lines +284 to +318
// Handle messages from worker
worker->NodeJs.WorkerThreads.onMessage((msg: TestIndexerProxyStorage.workerMessage) => {
let respond = data =>
worker->NodeJs.WorkerThreads.workerPostMessage(
{
TestIndexerProxyStorage.id: msg.id,
payload: TestIndexerProxyStorage.Response({data: data}),
}->Utils.magic,
)

switch msg.payload {
| LoadByIds({tableName, ids}) => store->handleLoadByIds(~tableName, ~ids)->respond

| LoadByField({tableName, fieldName, fieldValue, operator}) =>
store->handleLoadByField(~tableName, ~fieldName, ~fieldValue, ~operator)->respond

| WriteBatch({
updatedEntities,
checkpointIds,
checkpointChainIds,
checkpointBlockNumbers,
checkpointBlockHashes,
checkpointEventsProcessed,
}) =>
store->handleWriteBatch(
~updatedEntities,
~checkpointIds,
~checkpointChainIds,
~checkpointBlockNumbers,
~checkpointBlockHashes,
~checkpointEventsProcessed,
)
Js.Json.null->respond
}
})

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Main-thread message handler should return Error payloads on exceptions (avoid deadlocks).
If handleLoadByIds / handleLoadByField / handleWriteBatch throws, the worker-side sendRequest promise never resolves/rejects, and the test run can hang. Wrap handler execution and respond with TestIndexerProxyStorage.Error.

Proposed fix (try/catch + Error response)
           // Handle messages from worker
           worker->NodeJs.WorkerThreads.onMessage((msg: TestIndexerProxyStorage.workerMessage) => {
             let respond = data =>
               worker->NodeJs.WorkerThreads.workerPostMessage(
                 {
                   TestIndexerProxyStorage.id: msg.id,
                   payload: TestIndexerProxyStorage.Response({data: data}),
                 }->Utils.magic,
               )
+            let respondError = (exn: exn) =>
+              worker->NodeJs.WorkerThreads.workerPostMessage(
+                {
+                  TestIndexerProxyStorage.id: msg.id,
+                  payload: TestIndexerProxyStorage.Error({
+                    message: exn->Js.Exn.message->Option.getWithDefault("Unknown error"),
+                  }),
+                }->Utils.magic,
+              )
 
-            switch msg.payload {
-            | LoadByIds({tableName, ids}) => store->handleLoadByIds(~tableName, ~ids)->respond
+            try {
+              switch msg.payload {
+              | LoadByIds({tableName, ids}) =>
+                store->handleLoadByIds(~tableName, ~ids)->respond
 
-            | LoadByField({tableName, fieldName, fieldValue, operator}) =>
-              store->handleLoadByField(~tableName, ~fieldName, ~fieldValue, ~operator)->respond
+              | LoadByField({tableName, fieldName, fieldValue, operator}) =>
+                store->handleLoadByField(~tableName, ~fieldName, ~fieldValue, ~operator)->respond
 
-            | WriteBatch({
+              | WriteBatch({
                   updatedEntities,
                   checkpointIds,
                   checkpointChainIds,
                   checkpointBlockNumbers,
                   checkpointBlockHashes,
                   checkpointEventsProcessed,
                 }) =>
                 store->handleWriteBatch(
                   ~updatedEntities,
                   ~checkpointIds,
                   ~checkpointChainIds,
                   ~checkpointBlockNumbers,
                   ~checkpointBlockHashes,
                   ~checkpointEventsProcessed,
                 )
                 Js.Json.null->respond
+              }
+            } catch {
+            | exn => respondError(exn)
             }
           })
🤖 Prompt for AI Agents
In @codegenerator/cli/npm/envio/src/TestIndexer.res around lines 284 - 318, The
message handler in worker->NodeJs.WorkerThreads.onMessage currently calls store
methods (handleLoadByIds, handleLoadByField, handleWriteBatch) directly so
exceptions never send a response; wrap each handler invocation in a try/catch,
call the existing respond function in both success and failure paths, and on
exception send TestIndexerProxyStorage.Error({message: Js.Exn.message(exception)
|> Belt.Option.getWithDefault("unknown")}) (or equivalent) as the payload so the
worker-side sendRequest promise always resolves/rejects; apply this to the
LoadByIds, LoadByField branches and the WriteBatch branch (ensure WriteBatch
still responds with Js.Json.null on success and an Error payload on exception).

Comment thread codegenerator/cli/npm/envio/src/TestIndexer.res
Comment thread codegenerator/cli/npm/envio/src/TestIndexerProxyStorage.res
Comment on lines +96 to +107
let nextRequestId = (proxy: t): requestId => {
proxy.requestCounter = proxy.requestCounter + 1
proxy.requestCounter
}

let sendRequest = (proxy: t, ~payload: workerPayload): promise<Js.Json.t> => {
Promise.make((resolve, reject) => {
let id = proxy->nextRequestId
proxy.pendingRequests->Js.Dict.set(id->Int.toString, {resolve, reject})
proxy.parentPort->NodeJs.WorkerThreads.postMessage({id, payload})
})
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

sendRequest can leak pendingRequests forever (no timeout / cancellation).
If the main thread never responds (worker crash, logic bug, port closed), the promise never settles and pendingRequests grows unbounded. Consider a per-request timeout that rejects + deletes the entry.

🤖 Prompt for AI Agents
In @codegenerator/cli/npm/envio/src/TestIndexerProxyStorage.res around lines 96
- 107, sendRequest currently creates a never-settling Promise and leaves entries
in pendingRequests if the worker never responds; update sendRequest (and if
needed nextRequestId) to start a per-request timeout when creating the promise
that will call reject with a timeout error and remove the pendingRequests entry
(Js.Dict.delete) when the timer fires or when the response resolves, and ensure
the timer is cleared on resolve/reject; keep using Promise.make and postMessage
to parentPort but add the timeout logic tied to the same request id so
pendingRequests cannot leak forever.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @codegenerator/cli/npm/envio/src/TestIndexer.res:
- Around line 380-397: The onExit handler uses Js.Exn.raiseError which throws
immediately, preventing reject from being invoked; instead create and pass an
Error object to reject (e.g., build a message string using code->Int.toString
and call reject(new Error(message)) or use Js.Exn.raiseErrorToJs if you prefer a
non-throwing conversion), leaving state.processInProgress assignment intact and
keeping the same success branch that resolves with { changes:
state.processChanges } and the loop that updates state.progressBlockByChain.
🧹 Nitpick comments (3)
codegenerator/cli/templates/static/erc20_template/typescript/src/indexer.test.ts (1)

88-96: Consider defensive array access instead of non-null assertions.

The non-null assertions (!) on mockAddresses[0] and mockAddresses[1] assume the array has at least 2 elements. While this is likely always true for the mock helpers, explicit handling would be more robust.

🔧 Suggested improvement
-    const userAddress1 = Addresses.mockAddresses[0]!;
-    const userAddress2 = Addresses.mockAddresses[1]!;
+    const userAddress1 = Addresses.mockAddresses[0];
+    const userAddress2 = Addresses.mockAddresses[1];
+    if (!userAddress1 || !userAddress2) {
+      throw new Error("Mock addresses not available");
+    }

Alternatively, if mockAddresses is guaranteed to have sufficient elements by design, this can be left as-is.

scenarios/test_codegen/test/EventHandler_test.ts (1)

15-15: Duplicate import from "generated".

createTestIndexer is imported separately but could be consolidated with the existing import from "generated" on lines 3-12.

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/TestIndexer.res (1)

327-333: Error handling in worker creation catch block may cause unexpected behavior.

The catch block calls reject(exn->Utils.magic) and then raise(exn). Since raise throws synchronously, the code after the try-catch block will not execute, but the promise will still be pending (reject was called but the Promise.make callback exits abnormally via exception).

This may work in practice since reject was called, but the pattern is unusual.

Consider returning after reject to avoid the re-throw
           let worker = try {
             NodeJs.WorkerThreads.makeWorker(workerPath, {workerData: workerData})
           } catch {
           | exn =>
             reject(exn->Utils.magic)
-            raise(exn)
+            // Early return - reject handles the error propagation
+            %raw(`return`)
           }

Alternatively, if the intention is to exit the Promise.make callback after rejection, the current pattern does work (the exception bubbles up but the promise is already rejected).

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0cce5a5 and 605255e.

📒 Files selected for processing (11)
  • codegenerator/cli/npm/envio/index.d.ts
  • codegenerator/cli/npm/envio/src/Env.res
  • codegenerator/cli/npm/envio/src/Main.res
  • codegenerator/cli/npm/envio/src/PgStorage.res
  • codegenerator/cli/npm/envio/src/TestIndexer.res
  • codegenerator/cli/npm/envio/src/bindings/Pino.res
  • codegenerator/cli/templates/static/erc20_template/typescript/config.yaml
  • codegenerator/cli/templates/static/erc20_template/typescript/src/indexer.test.ts
  • scenarios/test_codegen/src/handlers/EventHandlers.ts
  • scenarios/test_codegen/test/EventHandler_test.ts
  • scenarios/test_codegen/test/LoadLinkedEntities.res
💤 Files with no reviewable changes (1)
  • scenarios/test_codegen/src/handlers/EventHandlers.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • codegenerator/cli/templates/static/erc20_template/typescript/config.yaml
🧰 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 using ref function
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:

  • scenarios/test_codegen/test/LoadLinkedEntities.res
  • codegenerator/cli/npm/envio/src/bindings/Pino.res
  • codegenerator/cli/npm/envio/src/PgStorage.res
  • codegenerator/cli/npm/envio/src/Main.res
  • codegenerator/cli/npm/envio/src/Env.res
  • codegenerator/cli/npm/envio/src/TestIndexer.res
**/*.res

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Prefer reading ReScript .res modules directly; ignore compiled .js artifacts

Files:

  • scenarios/test_codegen/test/LoadLinkedEntities.res
  • codegenerator/cli/npm/envio/src/bindings/Pino.res
  • codegenerator/cli/npm/envio/src/PgStorage.res
  • codegenerator/cli/npm/envio/src/Main.res
  • codegenerator/cli/npm/envio/src/Env.res
  • codegenerator/cli/npm/envio/src/TestIndexer.res
**/*.{test,spec}.{ts,tsx,js,jsx,res}

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

**/*.{test,spec}.{ts,tsx,js,jsx,res}: Always use single assert to check the whole value instead of multiple asserts for every field
Prefer Public module API for testing
Use _only to specify which tests to run during test development

Files:

  • codegenerator/cli/templates/static/erc20_template/typescript/src/indexer.test.ts
🧠 Learnings (22)
📓 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`
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: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:

  • scenarios/test_codegen/test/LoadLinkedEntities.res
  • codegenerator/cli/templates/static/erc20_template/typescript/src/indexer.test.ts
  • codegenerator/cli/npm/envio/index.d.ts
  • scenarios/test_codegen/test/EventHandler_test.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} : 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/test/LoadLinkedEntities.res
  • codegenerator/cli/templates/static/erc20_template/typescript/src/indexer.test.ts
  • codegenerator/cli/npm/envio/index.d.ts
  • codegenerator/cli/npm/envio/src/TestIndexer.res
📚 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/static/erc20_template/typescript/src/indexer.test.ts
  • codegenerator/cli/npm/envio/index.d.ts
  • scenarios/test_codegen/test/EventHandler_test.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/templates/static/erc20_template/typescript/src/indexer.test.ts
  • 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/templates/static/erc20_template/typescript/src/indexer.test.ts
  • codegenerator/cli/npm/envio/index.d.ts
  • scenarios/test_codegen/test/EventHandler_test.ts
  • codegenerator/cli/npm/envio/src/TestIndexer.res
📚 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/static/erc20_template/typescript/src/indexer.test.ts
  • codegenerator/cli/npm/envio/index.d.ts
  • codegenerator/cli/npm/envio/src/TestIndexer.res
📚 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/static/erc20_template/typescript/src/indexer.test.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/templates/static/erc20_template/typescript/src/indexer.test.ts
  • codegenerator/cli/npm/envio/index.d.ts
  • codegenerator/cli/npm/envio/src/TestIndexer.res
📚 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/static/erc20_template/typescript/src/indexer.test.ts
  • codegenerator/cli/npm/envio/index.d.ts
  • scenarios/test_codegen/test/EventHandler_test.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 cast timestamps to BigInt using `BigInt(event.block.timestamp)` instead of using raw timestamps from events

Applied to files:

  • codegenerator/cli/templates/static/erc20_template/typescript/src/indexer.test.ts
  • 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: 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 : 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: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
  • scenarios/test_codegen/test/EventHandler_test.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: 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: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: 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:

  • scenarios/test_codegen/test/EventHandler_test.ts
📚 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/npm/envio/src/TestIndexer.res
📚 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/npm/envio/src/TestIndexer.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: For multichain indexing, prefix all entity IDs with `event.chainId`: `${event.chainId}-${originalId}`, never hardcode `chainId = 1`, always use `event.chainId`, and use chain-specific Bundle IDs like `${chainId}-1` for accurate pricing per network

Applied to files:

  • codegenerator/cli/npm/envio/src/TestIndexer.res
🧬 Code graph analysis (1)
codegenerator/cli/templates/static/erc20_template/typescript/src/indexer.test.ts (1)
codegenerator/cli/npm/envio/src/bindings/Ethers.res.d.mts (1)
  • Addresses (5-5)
⏰ 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 (19)
scenarios/test_codegen/test/LoadLinkedEntities.res (1)

167-189: LGTM! Type references correctly updated to use public entity module paths.

The migration from Types.c, Types.b, Types.a to Entities.C.t, Entities.B.t, Entities.A.t aligns with the PR's goal of unifying type paths across the codebase. The test logic remains unchanged.

codegenerator/cli/npm/envio/src/bindings/Pino.res (1)

1-9: LGTM! Adding #silent log level is appropriate.

The #silent variant is a valid Pino log level that suppresses all logging output. This is particularly useful for test scenarios where log noise should be minimized.

codegenerator/cli/templates/static/erc20_template/typescript/src/indexer.test.ts (3)

1-6: LGTM! Good test setup with Vitest and generated helpers.

The imports are well-organized, separating the test framework (vitest), types (Account), and test utilities (TestHelpers, createTestIndexer).


7-81: LGTM! Comprehensive end-to-end indexer test.

The test effectively validates:

  1. Initial mint event processing at block 10,861,674
  2. Balance updates on subsequent transfers at block 10,861,766

Using inline snapshots for complex state verification is appropriate here as it captures the full expected output structure including block hashes and chain IDs.


98-137: LGTM! Well-structured unit test for Transfer event handling.

The test clearly demonstrates:

  • MockDb setup with initial entity state
  • Creating mock events with specific parameters
  • Processing events and verifying resulting state changes
  • Good use of descriptive assertion messages

The comments explaining MockDb immutability are helpful for template users.

codegenerator/cli/npm/envio/src/Env.res (2)

28-43: LGTM! Well-structured log level schema with optional handling.

The logLevelSchema enum covers all standard Pino levels plus custom user levels and the new #silent option. Making userLogLevel optional with explicit defaulting provides clearer semantics for distinguishing "not configured" from explicit configuration.


127-134: LGTM! Clean logger initialization with explicit default.

Using Belt.Option.getWithDefault(#info) clearly shows the fallback behavior when LOG_LEVEL is not set.

codegenerator/cli/npm/envio/src/PgStorage.res (1)

16-20: LGTM! Correctly adapted to optional userLogLevel type.

The comparison against Some(#warn) and Some(#error) properly handles the updated option type from Env.res. The logic remains the same: suppress Postgres notices for high-severity log levels.

scenarios/test_codegen/test/EventHandler_test.ts (1)

638-756: LGTM! Comprehensive test coverage for createTestIndexer.

The tests thoroughly cover:

  • Basic happy path returning { changes: [] }
  • Validation for exactly one chain requirement
  • Mutual exclusion (only one process at a time)
  • Block range validation against config and previously processed blocks

The synchronous vs async error handling is correctly distinguished using assert.throws vs assert.rejects.

codegenerator/cli/npm/envio/index.d.ts (2)

18-19: LGTM! Useful utility type for IDE display.

The Prettify<T> type is a well-known pattern that expands complex intersection types for better IDE tooltips and error messages.


476-529: LGTM! Well-designed test indexer type surface.

The types correctly model the test indexer constraints:

  • TestIndexerChainConfig requires both startBlock and endBlock (no open-ended ranges in tests)
  • TestIndexerChainIds extracts chain IDs from whichever ecosystem is configured
  • TestIndexerProcessConfig uses Partial<Record<...>> appropriately - runtime validation in TestIndexer.res enforces exactly one chain

The JSDoc comments provide clear documentation for the public API.

codegenerator/cli/npm/envio/src/Main.res (2)

249-264: LGTM! Clean test mode integration.

The ~isTest parameter correctly:

  • Disables TUI for clean test output
  • Forces isDevelopmentMode to false to ensure proper process exit behavior
  • Disables rollback on reorg (not needed for deterministic test runs)

The default value of false ensures backward compatibility.


275-327: LGTM! Server startup correctly gated by test mode.

Skipping the HTTP server in test mode is appropriate - tests don't need the metrics/console endpoints and this avoids port conflicts when running multiple test processes.

codegenerator/cli/npm/envio/src/TestIndexer.res (6)

25-39: LGTM!

Clean implementation for ID-based entity lookups with appropriate handling of missing tables/entities.


59-63: JSON value comparison may produce unexpected results for non-primitive types.

The operators > and < on Js.Json.t values work correctly for numbers but may produce unexpected results for strings (lexicographic comparison) or objects/arrays (reference comparison, typically always false).

If field queries are expected to work only with numeric fields, consider documenting this limitation. Otherwise, type-aware comparison logic may be needed.

Is this intentional behavior? If only numeric/primitive comparisons are expected, consider adding a comment or runtime validation.


77-189: LGTM! Well-structured batch write handling.

The function correctly:

  • Updates the in-memory entity store for subsequent load operations
  • Tracks changes per checkpoint for test inspection
  • Handles both Set and Delete operations appropriately

The use of Js.Dict.unsafeGet on line 122 is safe since entityConfigs is populated from allEntities during initialization, and the worker would have failed earlier if an unknown entity was referenced.


191-225: LGTM!

Correctly initializes state for test runs with appropriate defaults:

  • maxReorgDepth: 0 - no reorg handling needed in tests
  • cleanRun: true - fresh state per test indexer instance
  • Validates chains exist in config before proceeding

227-260: LGTM! Thorough block range validation.

The validation covers all edge cases:

  • Prevents starting before config's start block
  • Prevents ending after config's end block
  • Prevents re-processing already processed blocks

The error messages are clear and provide actionable guidance.


409-442: LGTM! Proper worker initialization with appropriate guards.

The function correctly:

  • Validates it's running in a worker thread
  • Handles missing parentPort/workerData gracefully
  • Configures log level appropriately for test mode
  • Starts the indexer in test mode

The ->ignore on Main.start is fine since the worker's lifetime is managed by the main thread via the exit handler.

Comment thread codegenerator/cli/npm/envio/src/TestIndexer.res
@DZakh
DZakh changed the base branch from main to dz/use-vitest-as-suggested-testing-framework January 12, 2026 13:30
Self::Single(gql_scalar) => gql_scalar.to_rescript_type(schema)?,
Self::ListType(field_type) => {
RescriptTypeIdent::Array(Box::new(field_type.to_rescript_type(schema)?))
TypeIdent::Array(Box::new(field_type.to_rescript_type(schema)?))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice api at some point

Suggested change
TypeIdent::Array(Box::new(field_type.to_rescript_type(schema)?))
TypeIdent::array(field_type.to_rescript_type(schema)?)

@DZakh
DZakh marked this pull request as draft January 13, 2026 11:52
Comment on lines -37 to -42
//Re-exporting types for backwards compatability
{{#each entities as | entity |}}
@genType.as("{{entity.name.original}}")
type {{entity.name.uncapitalized}} = Entities.{{entity.name.capitalized}}.t
{{/each}}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note breaking change

Comment thread codegenerator/cli/npm/envio/src/TestIndexer.res Outdated

@JonoPrest JonoPrest left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👏🏼

@DZakh DZakh changed the title Integrate New Testing Framework to templates New Testing Framework (main PR) Jan 13, 2026
@DZakh
DZakh marked this pull request as ready for review January 13, 2026 14:17
@DZakh DZakh mentioned this pull request Jan 13, 2026
@DZakh
DZakh changed the base branch from dz/use-vitest-as-suggested-testing-framework to main January 13, 2026 14:22

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
codegenerator/cli/src/hbs_templating/codegen_templates.rs (1)

2372-2385: Tests reference non-existent field internal_config_ts_code.

Lines 2376 and 2383 access project_template.internal_config_ts_code, but this field does not exist in the ProjectTemplate struct. The actual field is named internal_config_json_code. These tests will fail to compile.

Change project_template.internal_config_ts_code to project_template.internal_config_json_code on both lines.

🤖 Fix all issues with AI agents
In @codegenerator/cli/npm/envio/src/TestIndexer.res:
- Around line 196-198: The current mapping silently defaults invalid chainIdStr
to 0 (chainKeys->Array.map ... chainIdStr ->
Int.fromString->Option.getWithDefault(0)), which can mask bad config; change the
logic to explicitly handle parse failures by raising a clear error or returning
a Result instead of defaulting to 0: replace the getWithDefault(0) usage with an
explicit Option match or getExn that throws a descriptive exception when
Int.fromString returns None (include chainIdStr in the message), then pass the
validated chainId into ChainMap.Chain.makeUnsafe; this ensures invalid IDs are
surfaced rather than treated as chain 0.

In @codegenerator/cli/npm/envio/src/TestIndexerProxyStorage.res:
- Around line 188-192: The functions executeUnsafe and setChainMeta in
TestIndexerProxyStorage.res currently return Obj.magic(), which yields undefined
at runtime; replace these with explicit failures or proper typed returns like
the other rollback helpers: throw a clear Error (e.g., "executeUnsafe not
implemented" and "setChainMeta not implemented") or implement/return the correct
expected types for executeUnsafe and setChainMeta so callers cannot receive
unexpected undefined values; locate the functions by name (executeUnsafe,
setChainMeta) and make their behavior consistent with the other methods that
throw on unsupported operations.

In @codegenerator/cli/templates/static/greeter_template/typescript/README.md:
- Line 21: Decide whether the project target is Node.js v20 or v22+ and make the
versions consistent: if moving to v22+/v24, update the cursor rule in
hyperindex.mdc (the Node.js version constraint there) to allow v22+ (or
specifically v24 if preferred); if sticking with v20, revert the README entry
"[Node.js v22+ (v24 recommended)]" in greeter_template README.md (and the
identical lines in blank_template, erc20_template, factory_template,
greeteronfuel_template, svmblock_template) back to "Node.js v20" so the
templates and the .cursor/rules/hyperindex.mdc agree.
🧹 Nitpick comments (5)
adr/why-workers-for-test-indexer.md (1)

1-46: Well-structured ADR with clear rationale.

The document effectively explains the decision to use worker threads for test indexer isolation. The context, alternatives, decision, and consequences are all well-documented and follow ADR best practices.

Optional: Consider adding debugging and memory implications

While the document is comprehensive, you could optionally enhance the "Negative" consequences section by mentioning:

  • Debugging complexity: Debugging across worker boundaries can be more challenging than debugging in a single process
  • Memory implications: Multiple workers running in parallel may increase memory usage compared to sequential execution

These additions would provide a more complete picture of the trade-offs, though the current documentation is already sufficient.

Additionally, the phrase on Line 20 about "handler registration is a global singleton that would conflict with top-level await" could be clarified. The connection between global singleton registration and top-level await isn't immediately clear and might benefit from a brief explanation.

CONTRIBUTING.md (1)

21-21: Optional: Consider using a markdown link to avoid bare URL.

The URL on this line triggers a markdown linting rule (MD034). While functional, wrapping it in markdown link syntax improves consistency.

♻️ Proposed fix
-1. Node.js v22+ (v24 recommended) https://nodejs.org/en
+1. [Node.js v22+ (v24 recommended)](https://nodejs.org/en)
codegenerator/cli/npm/envio/src/TestIndexerProxyStorage.res (1)

96-107: Consider adding a timeout to prevent hanging tests.

The sendRequest function correctly stores the pending request before posting the message to avoid race conditions. However, there's no timeout mechanism - if the main thread doesn't respond (e.g., due to a crash), the promise will hang indefinitely. This could cause tests to hang rather than fail cleanly.

💡 Optional: Add timeout to sendRequest
 let sendRequest = (proxy: t, ~payload: workerPayload): promise<Js.Json.t> => {
-  Promise.make((resolve, reject) => {
-    let id = proxy->nextRequestId
-    proxy.pendingRequests->Js.Dict.set(id->Int.toString, {resolve, reject})
-    proxy.parentPort->NodeJs.WorkerThreads.postMessage({id, payload})
-  })
+  Promise.make((resolve, reject) => {
+    let id = proxy->nextRequestId
+    let idStr = id->Int.toString
+    proxy.pendingRequests->Js.Dict.set(idStr, {resolve, reject})
+    proxy.parentPort->NodeJs.WorkerThreads.postMessage({id, payload})
+    // Optional: Add timeout for debugging hung tests
+    // let _ = Js.Global.setTimeout(() => {
+    //   switch proxy.pendingRequests->Utils.Dict.dangerouslyGetNonOption(idStr) {
+    //   | Some(_) => reject(Utils.Error.make(`Request ${idStr} timed out`))
+    //   | None => ()
+    //   }
+    // }, 30000)
+  })
 }
codegenerator/cli/npm/envio/src/TestIndexer.res (2)

328-334: Double error handling on worker creation failure.

When worker creation fails, both reject(exn) and raise(exn) are called. The reject will properly fail the promise, but raise will also throw synchronously. Since Promise.make catches synchronous exceptions, this should still work, but the dual handling is redundant.

💡 Simplify error handling
           let worker = try {
             NodeJs.WorkerThreads.makeWorker(workerPath, {workerData: workerData})
           } catch {
           | exn =>
             reject(exn->Utils.magic)
-            raise(exn)
+            // Return early from Promise.make callback - the rejection is handled
+            %raw(`return`)
           }

Alternatively, just let the exception propagate since Promise.make will catch it and reject:

-          let worker = try {
-            NodeJs.WorkerThreads.makeWorker(workerPath, {workerData: workerData})
-          } catch {
-          | exn =>
-            reject(exn->Utils.magic)
-            raise(exn)
-          }
+          let worker = NodeJs.WorkerThreads.makeWorker(workerPath, {workerData: workerData})

59-63: Use type-aware comparison for Js.Json.t values instead of direct operators.

The comparison operators (>, <) on Js.Json.t rely on JavaScript's loose comparison semantics, which can produce unexpected results when comparing different JSON types. While the current schema-based conversion ensures both values undergo the same type mapping, this approach is fragile and error-prone. Consider deserializing both values to their proper types before comparison, or implementing explicit type-aware comparison logic that validates type consistency before applying operators.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 605255e and edddbc5.

⛔ Files ignored due to path filters (10)
  • codegenerator/cli/src/hbs_templating/snapshots/envio__hbs_templating__codegen_templates__test__envio_dts_code_generated_for_evm.snap is excluded by !**/*.snap
  • codegenerator/cli/src/hbs_templating/snapshots/envio__hbs_templating__codegen_templates__test__envio_dts_code_generated_for_fuel.snap is excluded by !**/*.snap
  • codegenerator/cli/src/hbs_templating/snapshots/envio__hbs_templating__codegen_templates__test__indexer_code_generates_correct_types_and_values.snap is excluded by !**/*.snap
  • codegenerator/cli/src/hbs_templating/snapshots/envio__hbs_templating__codegen_templates__test__indexer_code_multiple_chains.snap is excluded by !**/*.snap
  • codegenerator/cli/src/hbs_templating/snapshots/envio__hbs_templating__codegen_templates__test__internal_config_json_code_generated_for_evm.snap is excluded by !**/*.snap
  • codegenerator/cli/src/hbs_templating/snapshots/envio__hbs_templating__codegen_templates__test__internal_config_json_code_generated_for_fuel.snap is excluded by !**/*.snap
  • codegenerator/cli/src/hbs_templating/snapshots/envio__hbs_templating__codegen_templates__test__internal_config_json_code_omits_default_values.snap is excluded by !**/*.snap
  • codegenerator/cli/src/hbs_templating/snapshots/envio__hbs_templating__codegen_templates__test__internal_config_json_code_with_all_options.snap is excluded by !**/*.snap
  • codegenerator/cli/src/hbs_templating/snapshots/envio__hbs_templating__codegen_templates__test__internal_config_ts_code_omits_default_values.snap is excluded by !**/*.snap
  • codegenerator/cli/src/hbs_templating/snapshots/envio__hbs_templating__codegen_templates__test__internal_config_ts_code_with_all_options.snap is excluded by !**/*.snap
📒 Files selected for processing (24)
  • CONTRIBUTING.md
  • adr/why-workers-for-test-indexer.md
  • codegenerator/cli/npm/envio/index.d.ts
  • codegenerator/cli/npm/envio/src/Main.res
  • codegenerator/cli/npm/envio/src/PgStorage.res
  • codegenerator/cli/npm/envio/src/TestIndexer.res
  • codegenerator/cli/npm/envio/src/TestIndexerProxyStorage.res
  • codegenerator/cli/npm/envio/src/bindings/NodeJs.res
  • codegenerator/cli/npm/envio/src/bindings/Pino.res
  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
  • codegenerator/cli/templates/dynamic/codegen/envio.d.ts.hbs
  • codegenerator/cli/templates/dynamic/codegen/internal.config.json.hbs
  • codegenerator/cli/templates/dynamic/codegen/internal.config.ts.hbs
  • codegenerator/cli/templates/dynamic/codegen/package.json.hbs
  • codegenerator/cli/templates/dynamic/codegen/src/Generated.res.hbs
  • codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs
  • codegenerator/cli/templates/static/blank_template/shared/README.md
  • codegenerator/cli/templates/static/erc20_template/shared/README.md
  • codegenerator/cli/templates/static/erc20_template/typescript/src/indexer.test.ts
  • codegenerator/cli/templates/static/factory_template/shared/README.md
  • codegenerator/cli/templates/static/greeter_template/typescript/README.md
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/README.md
  • codegenerator/cli/templates/static/svmblock_template/typescript/README.md
  • codegenerator/integration_tests/tests/test_indexers/wildcard-uni-factory/README.md
💤 Files with no reviewable changes (1)
  • codegenerator/cli/templates/dynamic/codegen/internal.config.ts.hbs
✅ Files skipped from review due to trivial changes (2)
  • codegenerator/cli/templates/dynamic/codegen/internal.config.json.hbs
  • codegenerator/cli/templates/dynamic/codegen/envio.d.ts.hbs
🚧 Files skipped from review as they are similar to previous changes (4)
  • codegenerator/cli/templates/static/erc20_template/typescript/src/indexer.test.ts
  • codegenerator/cli/npm/envio/src/PgStorage.res
  • codegenerator/cli/templates/dynamic/codegen/package.json.hbs
  • codegenerator/cli/npm/envio/src/bindings/Pino.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 using ref function
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
  • codegenerator/cli/npm/envio/src/TestIndexerProxyStorage.res
  • codegenerator/cli/npm/envio/src/bindings/NodeJs.res
  • codegenerator/cli/npm/envio/src/TestIndexer.res
**/*.res

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Prefer reading ReScript .res modules directly; ignore compiled .js artifacts

Files:

  • codegenerator/cli/npm/envio/src/Main.res
  • codegenerator/cli/npm/envio/src/TestIndexerProxyStorage.res
  • codegenerator/cli/npm/envio/src/bindings/NodeJs.res
  • codegenerator/cli/npm/envio/src/TestIndexer.res
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/Generated.res.hbs
  • codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs
🧠 Learnings (41)
📓 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`
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: Use pnpm as the package manager

Applied to files:

  • CONTRIBUTING.md
  • codegenerator/cli/templates/static/erc20_template/shared/README.md
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/README.md
  • codegenerator/cli/templates/static/blank_template/shared/README.md
  • codegenerator/integration_tests/tests/test_indexers/wildcard-uni-factory/README.md
  • codegenerator/cli/templates/static/greeter_template/typescript/README.md
📚 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: Use `pnpm` over `npm`/`npx`

Applied to files:

  • CONTRIBUTING.md
  • codegenerator/cli/templates/static/erc20_template/shared/README.md
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/README.md
  • codegenerator/cli/templates/static/blank_template/shared/README.md
  • codegenerator/integration_tests/tests/test_indexers/wildcard-uni-factory/README.md
  • codegenerator/cli/templates/static/greeter_template/typescript/README.md
📚 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: Always use Node.js v20 only (no higher or lower versions)

Applied to files:

  • CONTRIBUTING.md
  • codegenerator/cli/templates/static/erc20_template/shared/README.md
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/README.md
  • codegenerator/cli/templates/static/blank_template/shared/README.md
  • codegenerator/integration_tests/tests/test_indexers/wildcard-uni-factory/README.md
  • codegenerator/cli/templates/static/greeter_template/typescript/README.md
📚 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: Once compilation is successful, run `TUI_OFF=true pnpm dev` to catch runtime errors in HyperIndex indexers

Applied to files:

  • CONTRIBUTING.md
  • codegenerator/cli/templates/static/svmblock_template/typescript/README.md
  • codegenerator/cli/templates/static/factory_template/shared/README.md
📚 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: Verify tests pass by running compiler `pnpm rescript` and tests `pnpm mocha`

Applied to files:

  • CONTRIBUTING.md
📚 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: After any change to TypeScript files, run `pnpm tsc --noEmit` to ensure successful compilation

Applied to files:

  • CONTRIBUTING.md
📚 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: Whitelist the following commands for HyperIndex development: `pnpm codegen` and `pnpm tsc --noEmit`

Applied to files:

  • CONTRIBUTING.md
📚 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} : Never add raw amounts from different tokens without normalization using helper functions like `normalizeAmountToUSD()`

Applied to files:

  • codegenerator/cli/templates/static/erc20_template/shared/README.md
  • codegenerator/cli/templates/static/svmblock_template/typescript/README.md
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/README.md
📚 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/static/erc20_template/shared/README.md
  • codegenerator/cli/templates/static/svmblock_template/typescript/README.md
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/README.md
  • codegenerator/cli/templates/static/factory_template/shared/README.md
  • codegenerator/cli/templates/dynamic/codegen/src/Generated.res.hbs
  • codegenerator/cli/templates/static/blank_template/shared/README.md
  • codegenerator/cli/templates/static/greeter_template/typescript/README.md
  • codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs
  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
  • codegenerator/cli/npm/envio/index.d.ts
  • codegenerator/cli/npm/envio/src/TestIndexer.res
📚 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/static/erc20_template/shared/README.md
  • codegenerator/cli/templates/static/svmblock_template/typescript/README.md
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/README.md
  • codegenerator/cli/templates/static/greeter_template/typescript/README.md
  • codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs
  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
  • codegenerator/cli/npm/envio/index.d.ts
  • codegenerator/cli/npm/envio/src/TestIndexer.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} : 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/static/erc20_template/shared/README.md
  • codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs
  • 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 : 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/static/erc20_template/shared/README.md
  • codegenerator/cli/templates/static/svmblock_template/typescript/README.md
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/README.md
  • codegenerator/cli/templates/dynamic/codegen/src/Generated.res.hbs
  • codegenerator/cli/templates/static/blank_template/shared/README.md
  • codegenerator/cli/templates/static/greeter_template/typescript/README.md
  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
  • 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/templates/static/erc20_template/shared/README.md
  • codegenerator/cli/templates/static/svmblock_template/typescript/README.md
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/README.md
  • codegenerator/cli/templates/dynamic/codegen/src/Generated.res.hbs
  • codegenerator/cli/templates/static/blank_template/shared/README.md
  • codegenerator/integration_tests/tests/test_indexers/wildcard-uni-factory/README.md
  • codegenerator/cli/templates/static/greeter_template/typescript/README.md
  • codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs
  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
  • codegenerator/cli/npm/envio/index.d.ts
  • codegenerator/cli/npm/envio/src/TestIndexer.res
📚 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:

  • codegenerator/cli/templates/static/erc20_template/shared/README.md
  • codegenerator/cli/templates/static/blank_template/shared/README.md
📚 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/static/erc20_template/shared/README.md
  • codegenerator/cli/templates/static/svmblock_template/typescript/README.md
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/README.md
  • codegenerator/cli/templates/dynamic/codegen/src/Generated.res.hbs
  • codegenerator/cli/templates/static/greeter_template/typescript/README.md
  • codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs
  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
  • 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 : For entity creation patterns, always include all required fields in a single object literal and use `context.Entity.set(entity)` (without await). Update patterns should spread existing entity data and update only changed fields: `const updated = { ...existing, field: newValue }; context.Entity.set(updated);`

Applied to files:

  • codegenerator/cli/templates/static/erc20_template/shared/README.md
  • codegenerator/cli/templates/static/svmblock_template/typescript/README.md
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/README.md
  • codegenerator/cli/templates/static/factory_template/shared/README.md
  • codegenerator/cli/templates/static/greeter_template/typescript/README.md
  • codegenerator/cli/templates/dynamic/codegen/src/Types.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 : Never hardcode contract addresses or configuration values - always use constants defined in the original subgraph or utility files. Reference original subgraph patterns for constants like FACTORY_ADDRESS, ADDRESS_ZERO, etc.

Applied to files:

  • codegenerator/cli/templates/static/erc20_template/shared/README.md
📚 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/static/erc20_template/shared/README.md
  • codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs
  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
  • 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: Ensure docker is installed

Applied to files:

  • codegenerator/cli/templates/static/erc20_template/shared/README.md
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/README.md
  • codegenerator/cli/templates/static/blank_template/shared/README.md
  • codegenerator/integration_tests/tests/test_indexers/wildcard-uni-factory/README.md
  • codegenerator/cli/templates/static/greeter_template/typescript/README.md
📚 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: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/templates/static/svmblock_template/typescript/README.md
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/README.md
  • codegenerator/cli/templates/static/factory_template/shared/README.md
  • codegenerator/cli/templates/static/greeter_template/typescript/README.md
  • codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs
  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
  • codegenerator/cli/npm/envio/src/TestIndexer.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} : Always cast timestamps to BigInt using `BigInt(event.block.timestamp)` instead of using raw timestamps from events

Applied to files:

  • codegenerator/cli/templates/static/svmblock_template/typescript/README.md
📚 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/static/svmblock_template/typescript/README.md
  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/README.md
  • codegenerator/cli/templates/static/greeter_template/typescript/README.md
  • codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs
  • 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/templates/static/svmblock_template/typescript/README.md
  • codegenerator/cli/templates/static/factory_template/shared/README.md
  • codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs
  • codegenerator/cli/npm/envio/index.d.ts
  • codegenerator/cli/npm/envio/src/TestIndexer.res
📚 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/utils/**/*.ts : When implementing helper functions with no entity or handler dependencies, implement the COMPLETE business logic from the original subgraph immediately, not just placeholder TODO comments

Applied to files:

  • codegenerator/cli/templates/static/greeteronfuel_template/typescript/README.md
  • codegenerator/cli/templates/static/greeter_template/typescript/README.md
📚 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/templates/dynamic/codegen/src/Generated.res.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 codegenerator/cli/templates/dynamic/**/*.hbs : Templates in Handlebars format (.hbs) live under `codegenerator/cli/templates/dynamic/`

Applied to files:

  • codegenerator/cli/templates/dynamic/codegen/src/Generated.res.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: Config parsing flows: `human_config.rs` → `system_config.rs` → `hbs_templating/codegen_templates.rs`

Applied to files:

  • codegenerator/cli/templates/dynamic/codegen/src/Generated.res.hbs
  • 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/src/Generated.res.hbs
  • codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs
  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
  • 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 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/src/Generated.res.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/Generated.res.hbs
  • codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs
  • 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 : All TypeScript handler and utility files must have proper async/await for database operations. Use `await` for `context.Entity.get()`, `context.Entity.getWhere().field.eq()` calls. Note: `context.Entity.set()` does NOT need `await` - it's synchronous

Applied to files:

  • codegenerator/cli/templates/static/greeter_template/typescript/README.md
📚 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: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/**/*.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: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/**/*.{yaml,yml} : Use the Envio EVM schema file for YAML validation in config.yaml: `yaml-language-server: $schema=./node_modules/envio/evm.schema.json`

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/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-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/npm/envio/src/TestIndexer.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: For multichain indexing, prefix all entity IDs with `event.chainId`: `${event.chainId}-${originalId}`, never hardcode `chainId = 1`, always use `event.chainId`, and use chain-specific Bundle IDs like `${chainId}-1` for accurate pricing per network

Applied to files:

  • codegenerator/cli/npm/envio/src/TestIndexer.res
🪛 markdownlint-cli2 (0.18.1)
CONTRIBUTING.md

21-21: Bare URL used

(MD034, no-bare-urls)

🔇 Additional comments (36)
codegenerator/integration_tests/tests/test_indexers/wildcard-uni-factory/README.md (1)

21-21: No action needed. The Node.js v22+ (v24 recommended) specification in this README is correct and aligns with the project's established standards. The repository has already standardized on Node.js >=22.0.0 across all package.json files and runs v22.10.0 in all CI/CD workflows.

Likely an incorrect or invalid review comment.

codegenerator/cli/templates/static/blank_template/shared/README.md (1)

21-21: No changes needed. The Node.js v22+ (v24 recommended) requirement is correct and consistent throughout the codebase. All package.json files specify ">=22.0.0", and all template README files document this same requirement. The change aligns with the actual project constraints.

Likely an incorrect or invalid review comment.

CONTRIBUTING.md (1)

21-21: Update the template file hyperindex.mdc to reflect the project's actual Node.js requirement.

The CONTRIBUTING.md change to Node.js v22+ is correct and aligns with the project's package.json ("node": ">=22.0.0") and all CI/CD workflows (using 22.10.0). However, the template file at ./codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc still specifies "Node.js v20 only (no higher or lower versions)". This template should be updated to match the actual project requirement of v22+ to avoid misleading generated guidance.

Likely an incorrect or invalid review comment.

codegenerator/cli/templates/static/factory_template/shared/README.md (1)

36-36: LGTM!

The Node.js prerequisite update to "v22+ (v24 recommended)" is consistent with other template READMEs updated in this PR.

codegenerator/cli/templates/static/erc20_template/shared/README.md (2)

3-3: LGTM!

Formatting change from bold to italic is consistent with other template documentation.


21-21: LGTM!

Node.js prerequisite update aligns with the project-wide version requirement change.

codegenerator/cli/npm/envio/src/Main.res (2)

249-264: LGTM!

The test mode parameter cleanly integrates into the start function:

  • Disables TUI and development mode appropriately
  • Disables rollback on reorg for deterministic test behavior
  • Uses idiomatic ReScript spread operator for config modification

275-327: LGTM!

Server startup and state retrieval logic are correctly guarded by !isTest, ensuring test isolation. The getState callback logic is preserved for production use while being skipped entirely in test mode.

codegenerator/cli/npm/envio/src/bindings/NodeJs.res (2)

39-39: LGTM!

Adding execArgv to Process.t enables passing execution arguments to worker threads, which is necessary for the test indexer infrastructure.


84-109: Excellent FFI bindings for worker_threads

The WorkerThreads module provides accurate bindings to the Node.js worker_threads API:

  • isMainThread and workerData correctly use Js.Nullable.t for nullable values
  • @send annotations properly map instance methods (postMessage, on, terminate)
  • workerOptions correctly exposes common options (workerData, execArgv) as a record with optional fields
  • Array syntax follows ReScript 11 conventions (array<string> not [| |])
  • Event handling via @as("message"), @as("error"), @as("exit") correctly maps to Node.js EventEmitter API
codegenerator/cli/npm/envio/index.d.ts (3)

18-19: LGTM!

The Prettify<T> utility type is a well-known TypeScript pattern that expands complex intersection types for better IDE tooltips and error messages.


343-354: LGTM!

IndexerConfigTypes provides a minimal constraint that allows IndexerFromConfig and related types to work without requiring the full IndexerConfig structure, improving ergonomics for type inference.


492-546: LGTM!

The TestIndexer type system is well-designed:

  • TestIndexerChainConfig clearly defines the block range interface
  • TestIndexerChainIds correctly extracts chain IDs from the first configured ecosystem
  • TestIndexerProcessConfig uses mapped types with optional chains
  • TestIndexerFromConfig exposes a clean process method returning the result type
codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs (4)

9-10: LGTM!

The IsEmptyObject<T> utility type correctly uses keyof T extends never to detect empty object types, enabling conditional type exports based on ecosystem configuration.


52-67: LGTM!

The Config type correctly constructs a composite type from all configured ecosystems using conditional intersection types. This enables IndexerFromConfig to derive the correct indexer shape.


82-87: LGTM!

The TestIndexer type is correctly imported from envio and parameterized with the generated Config, providing type-safe access to the test indexer API.


150-151: LGTM!

Exporting per-entity type aliases (e.g., export type Gravatar = Entities.Gravatar_t) improves developer experience by providing cleaner imports without the _t suffix.

codegenerator/cli/templates/dynamic/codegen/src/Generated.res.hbs (3)

1-1: LGTM!

The @@directive syntax for JSON imports with with { type: 'json' } is the correct approach for importing JSON files in ReScript with ES modules.


26-30: LGTM!

Filtering out test and spec files prevents them from being auto-loaded as handlers:

  • .test. - Jest/Vitest convention
  • .spec. - Jasmine/Mocha convention
  • _test. - ReScript convention

This ensures only production handlers are registered.


89-89: LGTM!

Using %raw(\internalConfigJson`)correctly references the directive-imported JSON value, passing it toConfig.fromPublic` for configuration initialization.

codegenerator/cli/npm/envio/src/TestIndexerProxyStorage.res (3)

1-66: Well-structured type definitions for worker-main thread messaging.

The use of @tag for discriminated unions and Js.Json.t for cross-worker serialization is appropriate. The type hierarchy clearly separates worker-to-main (workerPayload) and main-to-worker (mainPayload) message types.


68-94: LGTM - Proper request/response correlation with cleanup.

The message listener correctly correlates responses by ID, removes pending requests after handling, and throws clear errors for unexpected response IDs. The pattern of using Obj.magic with Js.Dict.unsafeDeleteKey is idiomatic for dict mutation in ReScript.


143-187: WriteBatch implementation correctly serializes entities for cross-worker messaging.

The entity serialization logic properly handles both Set and Delete change types, encoding entities to JSON using the entity schema before sending to the main thread. The checkpoint metadata is correctly forwarded.

codegenerator/cli/npm/envio/src/TestIndexer.res (5)

1-24: LGTM - Type definitions appropriately model test indexer state.

The use of unknown for changes and sets provides flexibility for heterogeneous entity types. The testIndexerState correctly uses mutable for fields that need mutation during processing.


77-189: Complex but well-structured batch write handling.

The function correctly:

  • Groups changes by checkpoint ID for proper ordering
  • Updates in-memory entity state for subsequent load operations
  • Parses entities with their schemas before storing in the changes array
  • Handles null blockHash values appropriately

One consideration: S.parseOrThrow at line 123 could throw if there's a schema mismatch. Ensure upstream error handling catches this.


228-261: Thorough block range validation with clear error messages.

The validation correctly enforces:

  1. startBlock >= config.startBlock
  2. endBlock <= config.endBlock (if configured)
  3. startBlock > progressBlock (for sequential test runs)

Error messages helpfully suggest using createTestIndexer() for a fresh state.


263-403: Well-designed test indexer factory with proper lifecycle management.

The implementation correctly:

  • Prevents concurrent process calls
  • Enforces single-chain restriction (with clear error message about multichain limitation)
  • Validates block ranges before starting
  • Manages worker lifecycle with proper error/exit handlers
  • Tracks progress for sequential test runs

410-443: Proper worker initialization with good defaults.

The function correctly:

  • Guards against being called from the main thread
  • Validates required parentPort and workerData
  • Defaults to silent logging for clean test output (while respecting explicit LOG_LEVEL)
  • Exits cleanly with error code on missing worker data
codegenerator/cli/src/hbs_templating/codegen_templates.rs (8)

39-114: Well-structured internal config types with appropriate serde annotations.

The design correctly:

  • Uses skip_serializing_if to omit default values, keeping output minimal
  • Separates ecosystem-specific config into optional fields
  • Uses Box<RawValue> for ABI to preserve exact JSON format without re-parsing overhead
  • Applies rename_all = "camelCase" consistently for JavaScript interop

151-186: Type-safe refactor from String to TypeIdent.

The change to use TypeIdent directly instead of converting to String immediately improves type safety and enables richer type comparisons throughout the codebase.


219-243: Consistent type refactoring in EntityRecordTypeTemplate.

The changes from RescriptRecordField to RecordField and RescriptSchemaMode to SchemaMode are consistent naming simplifications that improve code clarity without changing functionality.


616-711: EventTemplate properly updated to use new type system.

Key improvements:

  • TypeIdent::Address comparison (line 631) is more type-safe than string comparison
  • TypeExpr::Identifier(TypeIdent::Unit) (line 637) correctly represents empty event params
  • RecordField::new and to_valid_rescript_name provide consistent field handling

1539-1624: Internal config JSON generation with proper ecosystem handling.

The implementation correctly:

  • Parses and re-serializes ABIs to ensure compact JSON format
  • Creates ecosystem-specific config structures (EVM includes addressFormat/eventDecoder, Fuel has contracts, SVM is chains-only)
  • Omits multichain when "unordered" (the default)
  • Uses to_string_pretty for readable output

1626-1743: TypeScript declaration generation for ecosystem types.

The implementation correctly generates all ecosystem types (EvmChains, EvmContracts, FuelChains, FuelContracts, SvmChains) regardless of which ecosystem is active. Non-active ecosystems get empty {} types, providing a consistent interface for consumers.


2023-2038: Test constants properly updated to use TypeIdent.

The test helper EventParamTypeTemplate::new correctly uses TypeIdent for type-safe comparisons and value generation.


1494-1517: Test indexer integration code generation is correct.

The generated code properly:

  • Creates per-chain optional config fields using @as annotation for numeric keys
  • Constructs the worker path using ESM-compatible import.meta.url
  • References TestIndexerWorker.res.mjs, which is automatically compiled from TestIndexerWorker.res via ReScript's .res.mjs suffix configuration
  • Integrates with Generated.configWithoutRegistrations and Generated.codegenPersistence, both properly defined in the generated Generated.res module

Comment on lines +196 to +198
let chains = chainKeys->Array.map(chainIdStr => {
let chainId = chainIdStr->Int.fromString->Option.getWithDefault(0)
let chain = ChainMap.Chain.makeUnsafe(~chainId)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Silently defaulting invalid chain ID to 0 could hide configuration errors.

If chainIdStr is not a valid integer, it defaults to 0 which may inadvertently match a valid Fuel chain (chain ID 0). Consider raising an error for invalid chain IDs.

💡 Suggested fix
   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} is not a valid integer`)
+    }
     let chain = ChainMap.Chain.makeUnsafe(~chainId)
📝 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.

Suggested change
let chains = chainKeys->Array.map(chainIdStr => {
let chainId = chainIdStr->Int.fromString->Option.getWithDefault(0)
let chain = ChainMap.Chain.makeUnsafe(~chainId)
let chains = chainKeys->Array.map(chainIdStr => {
let chainId = switch chainIdStr->Int.fromString {
| Some(id) => id
| None => Js.Exn.raiseError(`Invalid chain ID: ${chainIdStr} is not a valid integer`)
}
let chain = ChainMap.Chain.makeUnsafe(~chainId)
🤖 Prompt for AI Agents
In @codegenerator/cli/npm/envio/src/TestIndexer.res around lines 196 - 198, The
current mapping silently defaults invalid chainIdStr to 0 (chainKeys->Array.map
... chainIdStr -> Int.fromString->Option.getWithDefault(0)), which can mask bad
config; change the logic to explicitly handle parse failures by raising a clear
error or returning a Result instead of defaulting to 0: replace the
getWithDefault(0) usage with an explicit Option match or getExn that throws a
descriptive exception when Int.fromString returns None (include chainIdStr in
the message), then pass the validated chainId into ChainMap.Chain.makeUnsafe;
this ensures invalid IDs are surfaced rather than treated as chain 0.

Comment on lines +188 to +192
setEffectCacheOrThrow: async (~effect as _, ~items as _, ~initialize as _) => (),
dumpEffectCache: async () => (),
executeUnsafe: async _ => Obj.magic(),
setChainMeta: async _ => Obj.magic(),
pruneStaleCheckpoints: async (~safeCheckpointId as _) => (),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Potential runtime issues with Obj.magic() returns.

executeUnsafe and setChainMeta return Obj.magic() which is essentially undefined. If these functions are called and their return values are used, this could cause subtle runtime errors. Consider throwing explicit errors (like the rollback functions) or documenting that these are intentional no-ops.

💡 Suggested fix: throw explicit errors or return proper types
-  executeUnsafe: async _ => Obj.magic(),
-  setChainMeta: async _ => Obj.magic(),
+  executeUnsafe: async _ => {
+    Js.Exn.raiseError("TestIndexer: executeUnsafe is not supported in test mode")
+  },
+  setChainMeta: async _ => {
+    // No-op: chain metadata updates are not persisted in test mode
+    ()
+  },
📝 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.

Suggested change
setEffectCacheOrThrow: async (~effect as _, ~items as _, ~initialize as _) => (),
dumpEffectCache: async () => (),
executeUnsafe: async _ => Obj.magic(),
setChainMeta: async _ => Obj.magic(),
pruneStaleCheckpoints: async (~safeCheckpointId as _) => (),
setEffectCacheOrThrow: async (~effect as _, ~items as _, ~initialize as _) => (),
dumpEffectCache: async () => (),
executeUnsafe: async _ => {
Js.Exn.raiseError("TestIndexer: executeUnsafe is not supported in test mode")
},
setChainMeta: async _ => {
// No-op: chain metadata updates are not persisted in test mode
()
},
pruneStaleCheckpoints: async (~safeCheckpointId as _) => (),
🤖 Prompt for AI Agents
In @codegenerator/cli/npm/envio/src/TestIndexerProxyStorage.res around lines 188
- 192, The functions executeUnsafe and setChainMeta in
TestIndexerProxyStorage.res currently return Obj.magic(), which yields undefined
at runtime; replace these with explicit failures or proper typed returns like
the other rollback helpers: throw a clear Error (e.g., "executeUnsafe not
implemented" and "setChainMeta not implemented") or implement/return the correct
expected types for executeUnsafe and setChainMeta so callers cannot receive
unexpected undefined values; locate the functions by name (executeUnsafe,
setChainMeta) and make their behavior consistent with the other methods that
throw on unsupported operations.

DZakh and others added 5 commits January 13, 2026 19:34
* Fix test indexer field comparison for bigint and BigDecimal

Store decoded entities instead of JSON to enable proper comparison.
The previous implementation stored JSON values and compared them
directly, which fails for bigint and BigDecimal since they serialize
as strings. Now entities are parsed when received from the worker
thread, and comparisons use the TableIndices.FieldValue logic that
properly handles numeric type comparisons.

* Simplify field comparison using schema-based conversion

Use entityConfig.table field schema with S.convertOrThrow to parse
JSON field values instead of manual type-based parsing. This reuses
the existing schema infrastructure and follows the same pattern as
InMemoryTable for field value comparison.

---------

Co-authored-by: Claude <noreply@anthropic.com>
Instead of scanning from block 0, set startBlock to match endBlock
(10_861_674) for more efficient targeted block testing.

Co-authored-by: Claude <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@codegenerator/cli/templates/dynamic/codegen/package.json.hbs`:
- Around line 15-20: The "start" script in the package.json.hbs template
currently hardcodes a nested tsx path (node_modules/envio/node_modules/tsx/...),
which breaks under pnpm/other package managers; update the "start" script to set
NODE_OPTIONS='--import tsx' on the node invocation instead of importing the
nested tsx path, preserving the existing tsc step when {{is_typescript}} is true
and keeping the same {{relative_path_to_root_from_generated}} and
{{relative_path_to_generated_from_root}} usages so the command becomes: run tsc
--noEmit when needed, then run node with NODE_OPTIONS='--import tsx' and the
entry {{relative_path_to_generated_from_root}}/src/Index.res.mjs.
♻️ Duplicate comments (6)
codegenerator/cli/npm/envio/src/TestIndexer.res (6)

26-44: handleLoadByIds silently drops missing IDs, diverging from "OrThrow" semantics.

The function filters out missing IDs rather than throwing when an ID is not found. If Persistence.storage.loadByIdsOrThrow is expected to error on missing IDs (or preserve positional alignment), this will produce different behavior in tests vs production, potentially hiding bugs.

Consider either:

  1. Throwing when any ID is missing, or
  2. Returning results in the same order as input IDs (with null for missing entries) to maintain positional alignment

116-167: handleWriteBatch only processes latestChange, ignoring update.history.

Line 117 only handles update.latestChange. If update.history contains earlier changes that should be applied/tracked, this could result in:

  • Incorrect store state for subsequent loads
  • Incomplete checkpoint change output

If historical changes need to be preserved for accurate test behavior, iterate through update.history before applying latestChange.


169-206: Add length validation before getUnsafe on checkpoint arrays.

The loop at lines 170-206 uses Array.getUnsafe on multiple arrays (checkpointIds, checkpointBlockNumbers, checkpointBlockHashes, checkpointChainIds, checkpointEventsProcessed) assuming they all have identical lengths. Any mismatch would cause a runtime exception that's hard to debug.

💡 Suggested invariant check
// Add before the for loop at line 170
let len = checkpointIds->Array.length
if checkpointBlockNumbers->Array.length !== len ||
   checkpointBlockHashes->Array.length !== len ||
   checkpointChainIds->Array.length !== len ||
   checkpointEventsProcessed->Array.length !== len {
  Js.Exn.raiseError("Checkpoint metadata arrays have mismatched lengths")
}

214-215: Silently defaulting invalid chain ID to 0 could hide configuration errors.

Line 215 defaults to 0 when Int.fromString fails. Chain ID 0 may be a valid chain (e.g., Fuel), so this could mask malformed process configs and produce confusing "wrong chain" behavior.

🐛 Proposed fix
-    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} is not a valid integer`)
+    }

323-324: Same chain ID parsing issue exists here.

Line 324 also defaults invalid chain IDs to 0. Apply the same fix as suggested for line 215.


365-399: Main-thread message handler should catch exceptions to avoid deadlocks.

If handleLoadByIds, handleLoadByField, or handleWriteBatch throws, the worker-side sendRequest promise never resolves/rejects, and the test run can hang indefinitely. Wrap handler execution in try/catch and respond with TestIndexerProxyStorage.Error on failure.

🐛 Proposed fix sketch
           worker->NodeJs.WorkerThreads.onMessage((msg: TestIndexerProxyStorage.workerMessage) => {
             let respond = data =>
               worker->NodeJs.WorkerThreads.workerPostMessage(
                 {
                   TestIndexerProxyStorage.id: msg.id,
                   payload: TestIndexerProxyStorage.Response({data: data}),
                 }->Utils.magic,
               )
+            let respondError = message =>
+              worker->NodeJs.WorkerThreads.workerPostMessage(
+                {
+                  TestIndexerProxyStorage.id: msg.id,
+                  payload: TestIndexerProxyStorage.Error({message: message}),
+                }->Utils.magic,
+              )
 
-            switch msg.payload {
+            try {
+              switch msg.payload {
             | LoadByIds({tableName, ids}) => state->handleLoadByIds(~tableName, ~ids)->respond
             ...
-            }
+              }
+            } catch {
+            | exn => respondError(exn->Js.Exn.message->Option.getWithDefault("Unknown error"))
+            }
           })
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dc0b23d and 94f7243.

⛔ Files ignored due to path filters (2)
  • codegenerator/cli/npm/envio/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • scenarios/test_codegen/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (6)
  • codegenerator/cli/npm/envio/package.json
  • codegenerator/cli/npm/envio/package.json.tmpl
  • codegenerator/cli/npm/envio/src/Benchmark.res
  • codegenerator/cli/npm/envio/src/TestIndexer.res
  • codegenerator/cli/npm/envio/src/bindings/NodeJs.res
  • codegenerator/cli/templates/dynamic/codegen/package.json.hbs
🧰 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 using ref function
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/Benchmark.res
  • codegenerator/cli/npm/envio/src/TestIndexer.res
  • codegenerator/cli/npm/envio/src/bindings/NodeJs.res
**/*.res

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Prefer reading ReScript .res modules directly; ignore compiled .js artifacts

Files:

  • codegenerator/cli/npm/envio/src/Benchmark.res
  • codegenerator/cli/npm/envio/src/TestIndexer.res
  • codegenerator/cli/npm/envio/src/bindings/NodeJs.res
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/package.json.hbs
🧠 Learnings (22)
📓 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/package.json
  • codegenerator/cli/npm/envio/package.json.tmpl
  • codegenerator/cli/templates/dynamic/codegen/package.json.hbs
  • codegenerator/cli/npm/envio/src/TestIndexer.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} : Import and use the Effect API (`S`, `createEffect`) from 'envio' package for external calls in HyperIndex handlers

Applied to files:

  • codegenerator/cli/npm/envio/package.json
  • codegenerator/cli/templates/dynamic/codegen/package.json.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,**/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/npm/envio/package.json
  • codegenerator/cli/npm/envio/package.json.tmpl
  • codegenerator/cli/templates/dynamic/codegen/package.json.hbs
  • codegenerator/cli/npm/envio/src/TestIndexer.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: After any change to TypeScript files, run `pnpm tsc --noEmit` to ensure successful compilation

Applied to files:

  • codegenerator/cli/npm/envio/package.json
  • codegenerator/cli/npm/envio/package.json.tmpl
📚 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/package.json
  • codegenerator/cli/npm/envio/package.json.tmpl
  • codegenerator/cli/templates/dynamic/codegen/package.json.hbs
  • codegenerator/cli/npm/envio/src/TestIndexer.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} : 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/package.json.tmpl
  • codegenerator/cli/templates/dynamic/codegen/package.json.hbs
  • codegenerator/cli/npm/envio/src/TestIndexer.res
📚 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 entity creation patterns, always include all required fields in a single object literal and use `context.Entity.set(entity)` (without await). Update patterns should spread existing entity data and update only changed fields: `const updated = { ...existing, field: newValue }; context.Entity.set(updated);`

Applied to files:

  • codegenerator/cli/npm/envio/package.json.tmpl
📚 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/package.json.tmpl
  • codegenerator/cli/templates/dynamic/codegen/package.json.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/npm/envio/package.json.tmpl
📚 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 cast timestamps to BigInt using `BigInt(event.block.timestamp)` instead of using raw timestamps from events

Applied to files:

  • codegenerator/cli/npm/envio/package.json.tmpl
📚 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/package.json.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 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/package.json.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 : All TypeScript handler and utility files must have proper async/await for database operations. Use `await` for `context.Entity.get()`, `context.Entity.getWhere().field.eq()` calls. Note: `context.Entity.set()` does NOT need `await` - it's synchronous

Applied to files:

  • codegenerator/cli/templates/dynamic/codegen/package.json.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/utils/**/*.ts : When implementing helper functions with no entity or handler dependencies, implement the COMPLETE business logic from the original subgraph immediately, not just placeholder TODO comments

Applied to files:

  • codegenerator/cli/templates/dynamic/codegen/package.json.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 codegenerator/cli/templates/static/**/*.res : Static ReScript template files live under `codegenerator/cli/templates/static/` and are copied verbatim

Applied to files:

  • codegenerator/cli/templates/dynamic/codegen/package.json.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 **/*.res : Prefer reading ReScript `.res` modules directly; ignore compiled `.js` artifacts

Applied to files:

  • codegenerator/cli/templates/dynamic/codegen/package.json.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: Verify tests pass by running compiler `pnpm rescript` and tests `pnpm mocha`

Applied to files:

  • codegenerator/cli/templates/dynamic/codegen/package.json.hbs
📚 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/templates/dynamic/codegen/package.json.hbs
  • codegenerator/cli/npm/envio/src/TestIndexer.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.res
📚 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/src/TestIndexer.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: For multichain indexing, prefix all entity IDs with `event.chainId`: `${event.chainId}-${originalId}`, never hardcode `chainId = 1`, always use `event.chainId`, and use chain-specific Bundle IDs like `${chainId}-1` for accurate pricing per network

Applied to files:

  • codegenerator/cli/npm/envio/src/TestIndexer.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 (7)
codegenerator/cli/npm/envio/package.json (1)

48-49: LGTM - Consistent with template.

The tsx dependency addition is consistent with package.json.tmpl, ensuring the development and release configurations remain in sync.

codegenerator/cli/npm/envio/package.json.tmpl (1)

59-60: LGTM - tsx dependency for TestIndexer worker thread support.

The addition of tsx as a runtime dependency aligns with the PR objective to "Apply tsx for TestIndexer worker thread." This enables running TypeScript files directly in worker threads without pre-compilation. The version 4.21.0 is current and has no known security advisories.

codegenerator/cli/npm/envio/src/Benchmark.res (1)

219-219: LGTM! ESM-compatible dirname resolution.

This correctly switches from the CommonJS __dirname to the ESM-compatible pattern using import.meta.url, which is necessary for ES modules.

codegenerator/cli/npm/envio/src/bindings/NodeJs.res (1)

83-112: LGTM! Well-structured WorkerThreads bindings.

The bindings correctly expose the Node.js worker_threads API surface needed for the test indexer worker communication. The getDirname helper provides a clean ESM-compatible replacement for __dirname.

One minor note: the polymorphic types on workerData and message handlers ('a) rely on consistent type usage at call sites. This is acceptable for internal use but requires care to ensure type safety.

codegenerator/cli/npm/envio/src/TestIndexer.res (3)

46-91: Good fix for JSON comparisons using TableIndices.FieldValue.

The implementation now properly handles type-aware comparisons for bigint and BigDecimal by parsing the JSON field value using the field's schema and using TableIndices.FieldValue comparison methods. This addresses the previous concern about unsafe JSON comparisons.


407-424: Good fix for worker exit error handling.

The onExit handler now correctly uses Utils.Error.make instead of Js.Exn.raiseError, ensuring the promise is properly rejected on non-zero exit codes.


436-468: LGTM! Worker initialization is well-structured.

The initTestWorker function properly:

  • Validates it's running in a worker thread
  • Handles missing parent port gracefully
  • Sets up the proxy storage for main-thread communication
  • Respects user log level preferences while defaulting to silent

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines +15 to +20
"db-up": "cd {{relative_path_to_root_from_generated}} && node -e 'import(\"{{relative_path_to_generated_from_root}}/src/db/Migrations.res.mjs\").then(m => m.runUpMigrations(true))'",
"db-down": "cd {{relative_path_to_root_from_generated}} && node -e 'import(\"{{relative_path_to_generated_from_root}}/src/db/Migrations.res.mjs\").then(m => m.runDownMigrations(true))'",
"db-setup": "cd {{relative_path_to_root_from_generated}} && node -e 'import(\"{{relative_path_to_generated_from_root}}/src/db/Migrations.res.mjs\").then(m => m.runUpMigrations(true, true))'",
"print-benchmark-summary": "cd {{relative_path_to_root_from_generated}} && node -e 'import(\"{{relative_path_to_generated_from_root}}/src/Benchmark.res.mjs\").then(m => m.Summary.printSummary())'",
{{!-- tsx is needed for start script to support TypeScript handlers --}}
"start": "cd {{relative_path_to_root_from_generated}}{{#if is_typescript}} && tsc --noEmit{{/if}} && node --no-warnings --import {{relative_path_to_generated_from_root}}/node_modules/envio/node_modules/tsx/dist/esm/index.mjs {{relative_path_to_generated_from_root}}/src/Index.res.mjs"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Locate and check the envio package.json for tsx dependency
find . -path "*/node_modules/envio/package.json" -o -path "*/envio/package.json" | head -5

Repository: enviodev/hyperindex

Length of output: 105


🏁 Script executed:

#!/bin/bash
# Check multiple possible locations for envio's package.json
if [ -f "codegenerator/cli/npm/envio/package.json" ]; then
  echo "=== Found at codegenerator/cli/npm/envio/package.json ==="
  cat codegenerator/cli/npm/envio/package.json | jq '.dependencies.tsx // .devDependencies.tsx // .optionalDependencies.tsx // "NOT_FOUND"'
fi

# Also try to find it elsewhere
find . -type f -name "package.json" -path "*/envio/*" 2>/dev/null | grep -v node_modules | head -5

Repository: enviodev/hyperindex

Length of output: 172


🏁 Script executed:

#!/bin/bash
# List the structure to understand the layout
ls -la codegenerator/cli/npm/envio/ 2>/dev/null || echo "Path not found at expected location"

Repository: enviodev/hyperindex

Length of output: 992


🏁 Script executed:

#!/bin/bash
# View the full envio package.json to understand tsx dependency declaration
cat codegenerator/cli/npm/envio/package.json

Repository: enviodev/hyperindex

Length of output: 1550


🏁 Script executed:

#!/bin/bash
# Check if tsx is also in the package.json.tmpl (template)
if [ -f "codegenerator/cli/npm/envio/package.json.tmpl" ]; then
  echo "=== package.json.tmpl ===" 
  cat codegenerator/cli/npm/envio/package.json.tmpl
fi

Repository: enviodev/hyperindex

Length of output: 1799


🏁 Script executed:

#!/bin/bash
# Search for other references to tsx in templates/dynamic to see if there are patterns
rg "tsx" codegenerator/cli/templates/dynamic/ -A 2 -B 2

Repository: enviodev/hyperindex

Length of output: 1213


🏁 Script executed:

#!/bin/bash
# Check if there's a pnpm-lock.yaml at the root (indicating pnpm usage)
if [ -f "pnpm-lock.yaml" ]; then
  echo "Project uses pnpm"
  ls -la pnpm-lock.yaml
fi

Repository: enviodev/hyperindex

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Check what package manager the project uses
if [ -f "package-lock.json" ]; then
  echo "Uses npm"
elif [ -f "pnpm-lock.yaml" ]; then
  echo "Uses pnpm"
elif [ -f "yarn.lock" ]; then
  echo "Uses yarn"
else
  echo "No lock file found at root"
fi

# Check the package.json at root for package manager clues
if [ -f "package.json" ]; then
  echo ""
  echo "=== Root package.json ===" 
  head -20 package.json
fi

Repository: enviodev/hyperindex

Length of output: 89


🏁 Script executed:

#!/bin/bash
# Check if the nested tsx path actually resolves when installed via npm
# by looking at how tsx is actually referenced elsewhere in the codebase
rg "import.*tsx" codegenerator/cli/templates/ -t ts -t js -t mjs 2>/dev/null | head -10

Repository: enviodev/hyperindex

Length of output: 45


🏁 Script executed:

#!/antml:bash
# Check if there's documentation or examples showing how tsx is used in generated projects
find codegenerator/cli/templates/dynamic -name "*.hbs" -o -name "*.ts" | xargs grep -l "tsx" 2>/dev/null

Repository: enviodev/hyperindex

Length of output: 123


🏁 Script executed:

#!/bin/bash
# Check if generated projects have tsx as a dependency
# Look for templates that show what dependencies are generated
rg "dependencies" codegenerator/cli/templates/dynamic/ -A 10 | grep -A 5 "tsx"

Repository: enviodev/hyperindex

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Check if there's any tooling that tells us what the default package manager is
# Look in package.json or other config files
rg "packageManager" . --type json 2>/dev/null | head -5

Repository: enviodev/hyperindex

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Verify the tsx path by checking what the dist/esm/index.mjs file actually is
# in case it's something special or if there's an alternative
if [ -d "codegenerator/cli/npm/envio/node_modules/tsx" ]; then
  ls -la codegenerator/cli/npm/envio/node_modules/tsx/dist/esm/index.mjs 2>/dev/null && echo "Path exists in dev environment"
elif [ -d "node_modules/tsx" ]; then
  echo "tsx found at root node_modules"
  ls -la node_modules/tsx/dist/esm/index.mjs 2>/dev/null
fi

Repository: enviodev/hyperindex

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Check the generated package.json template to see what dependencies are included
# Look for the main package.json.hbs or package.json generation logic
find codegenerator/cli/templates/dynamic -name "*.hbs" -exec grep -l '"dependencies"' {} \;

Repository: enviodev/hyperindex

Length of output: 198


🏁 Script executed:

#!/bin/bash
# Check if there's documentation about generated project structure
find . -name "README*" -o -name "GUIDE*" | xargs grep -l "package.json" 2>/dev/null | head -3

Repository: enviodev/hyperindex

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Look more carefully at what dependencies the generated projects are supposed to have
# by examining all package.json related templates
find codegenerator/cli/templates -name "*package.json*" -type f | while read f; do
  echo "=== $f ==="
  head -50 "$f"
done

Repository: enviodev/hyperindex

Length of output: 3285


🏁 Script executed:

#!/bin/bash
# Check the Node.js version requirement to see if import.meta.resolve is available
# Node 18.19.0+ and 20.10.0+ support import.meta.resolve()
rg "engines" codegenerator/cli/templates/dynamic/codegen/package.json.hbs -A 2

Repository: enviodev/hyperindex

Length of output: 105


🏁 Script executed:

#!/antml:bash
# Search for how tsx is actually used in the generated code
# Look for any tests or documentation about tsx usage
rg "tsx" codegenerator/cli/templates/ -B 5 -A 5 --type hbs

Repository: enviodev/hyperindex

Length of output: 2051


🏁 Script executed:

#!/bin/bash
# Check if there's any alternative tsx resolution or if it's consistently nested
rg "node_modules" codegenerator/cli/templates/dynamic/codegen/package.json.hbs

Repository: enviodev/hyperindex

Length of output: 351


🏁 Script executed:

#!/bin/bash
# Check if there's any pnpm configuration that would affect node_modules structure
if [ -f "pnpm-workspace.yaml" ] || [ -f ".npmrc" ] || [ -f "pnpm-lock.yaml" ]; then
  echo "Project uses pnpm"
fi

# Also check what the actual recommended package manager is
rg "pnpm" . --type json 2>/dev/null | head -5

Repository: enviodev/hyperindex

Length of output: 496


🏁 Script executed:

#!/an/bash
# Look for any existing generated projects or test fixtures that show how the nested path works
find . -path "*/generated/package.json" -type f 2>/dev/null | head -3 | xargs cat 2>/dev/null | grep -A 5 -B 5 "tsx\|envio"

Repository: enviodev/hyperindex

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Check if there are any integration tests or examples showing the actual generated output
find . -name "*.test.*" -o -name "*.spec.*" | xargs grep -l "start.*script\|tsx" 2>/dev/null | head -3

Repository: enviodev/hyperindex

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Check if there are any known issues or TODOs about the tsx path
rg "tsx.*path\|tsx.*nested\|tsx.*hoisting" . --type hbs --type ts --type js 2>/dev/null

Repository: enviodev/hyperindex

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Look for how tsx is actually referenced in generated projects
# by checking if there are any build/config files that might reference it
find scenarios -name "package.json" -exec grep -l "tsx" {} \; 2>/dev/null

Repository: enviodev/hyperindex

Length of output: 243


🏁 Script executed:

#!/bin/bash
# Check the actual structure: does the nested tsx path exist when envio is installed?
# Let's look at what the start script would resolve to with pnpm
if [ -f "pnpm-lock.yaml" ]; then
  echo "Project uses pnpm - checking how tsx is resolved"
  # Check if tsx appears in the lock file
  grep "tsx" pnpm-lock.yaml | head -5
fi

Repository: enviodev/hyperindex

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Check one of the scenario package.json files that mentions tsx to see if they have the nested path
echo "=== scenarios/test_codegen/package.json ==="
cat scenarios/test_codegen/package.json | grep -A 50 '"scripts"'

Repository: enviodev/hyperindex

Length of output: 1745


🏁 Script executed:

#!/bin/bash
# Check if any of the scenario generated projects have the tsx nested path in their start script
for f in scenarios/*/package.json scenarios/*/generated/package.json; do
  if [ -f "$f" ]; then
    if grep -q "node_modules/envio/node_modules/tsx" "$f"; then
      echo "=== Found nested tsx path in $f ==="
      grep "start" "$f"
    fi
  fi
done

Repository: enviodev/hyperindex

Length of output: 45


Use NODE_OPTIONS='--import tsx' instead of nested tsx path for better package manager compatibility.

The start script references a nested path node_modules/envio/node_modules/tsx/dist/esm/index.mjs, which assumes npm's dependency tree structure. This breaks with pnpm (which flattens node_modules via symlinks) and may vary across package managers.

The test scenarios in this repository use a more portable pattern: NODE_OPTIONS='--import tsx'. Consider using this approach instead, which works consistently across npm, pnpm, and yarn without relying on nested dependency paths.

🤖 Prompt for AI Agents
In `@codegenerator/cli/templates/dynamic/codegen/package.json.hbs` around lines 15
- 20, The "start" script in the package.json.hbs template currently hardcodes a
nested tsx path (node_modules/envio/node_modules/tsx/...), which breaks under
pnpm/other package managers; update the "start" script to set
NODE_OPTIONS='--import tsx' on the node invocation instead of importing the
nested tsx path, preserving the existing tsc step when {{is_typescript}} is true
and keeping the same {{relative_path_to_root_from_generated}} and
{{relative_path_to_generated_from_root}} usages so the command becomes: run tsc
--noEmit when needed, then run node with NODE_OPTIONS='--import tsx' and the
entry {{relative_path_to_generated_from_root}}/src/Index.res.mjs.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@codegenerator/cli/npm/envio/src/TestIndexer.res`:
- Around line 116-167: handleWriteBatch in TestIndexer.res currently only
inspects update.latestChange, skipping earlier entries in update.history; change
it to iterate over update.history (each change) and apply the same logic used
for the Set/Delete branches (parse entity via S.parseOrThrow, update entityDict,
compute checkpointKey from checkpointId, get/create entityChanges and
entityChange, push to sets or deleted) for each history item so every historical
change is recorded in changesByCheckpoint; reuse the existing logic inside the
switch on update.latestChange but run it for each change in update.history (and
still include latestChange if history doesn't contain it) to mirror
PgStorage.res behavior.
♻️ Duplicate comments (4)
codegenerator/cli/npm/envio/src/TestIndexer.res (4)

214-216: Chain ID parsing silently defaults to 0 on invalid keys.

Int.fromString->Option.getWithDefault(0) masks malformed config keys. Chain ID 0 may be valid (Fuel), causing confusing "wrong chain" behavior instead of a clear error.

💡 Proposed fix
   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} is not a valid integer`)
+    }
     let chain = ChainMap.Chain.makeUnsafe(~chainId)

323-325: Same chain ID parsing issue repeated here.

Line 324 has the same getWithDefault(0) pattern that silently masks invalid chain IDs.

💡 Proposed fix
         chainKeys->Array.forEach(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 in process config: ${chainIdStr}`)
+          }
           let chain = ChainMap.Chain.makeUnsafe(~chainId)

169-206: Add length validation before getUnsafe calls on checkpoint arrays.

Lines 170-184 use Array.getUnsafe on multiple parallel arrays (checkpointIds, checkpointBlockNumbers, checkpointBlockHashes, checkpointChainIds, checkpointEventsProcessed) assuming identical lengths. A mismatch would cause a silent out-of-bounds access.

💡 Proposed fix: Add invariant check
 let handleWriteBatch = (
   ...
 ): unit => {
+  // Validate checkpoint arrays have matching lengths
+  let checkpointCount = checkpointIds->Array.length
+  if checkpointBlockNumbers->Array.length !== checkpointCount ||
+     checkpointBlockHashes->Array.length !== checkpointCount ||
+     checkpointChainIds->Array.length !== checkpointCount ||
+     checkpointEventsProcessed->Array.length !== checkpointCount {
+    Js.Exn.raiseError("Checkpoint metadata arrays have mismatched lengths")
+  }
+
   // Group entity changes by checkpointId
   ...

362-396: Unhandled exceptions in message handler will cause deadlocks.

If handleLoadByIds, handleLoadByField, or handleWriteBatch throws (e.g., via raiseError when a field is not found), no response is sent to the worker. The worker-side sendRequest promise never resolves/rejects, causing the test run to hang indefinitely.

Wrap the switch statement in try/catch:

Proposed fix
           worker->NodeJs.WorkerThreads.onMessage((msg: TestIndexerProxyStorage.workerMessage) => {
             let respond = data =>
               worker->NodeJs.WorkerThreads.workerPostMessage(
                 {
                   TestIndexerProxyStorage.id: msg.id,
                   payload: TestIndexerProxyStorage.Response({data: data}),
                 }->Utils.magic,
               )
+            let respondError = message =>
+              worker->NodeJs.WorkerThreads.workerPostMessage(
+                {
+                  TestIndexerProxyStorage.id: msg.id,
+                  payload: TestIndexerProxyStorage.Error({message: message}),
+                }->Utils.magic,
+              )

-            switch msg.payload {
-            | LoadByIds({tableName, ids}) => state->handleLoadByIds(~tableName, ~ids)->respond
-            | LoadByField({tableName, fieldName, fieldValue, operator}) =>
-              state->handleLoadByField(~tableName, ~fieldName, ~fieldValue, ~operator)->respond
-            | WriteBatch({...}) =>
-              state->handleWriteBatch(...)
-              Js.Json.null->respond
-            }
+            try {
+              switch msg.payload {
+              | LoadByIds({tableName, ids}) => state->handleLoadByIds(~tableName, ~ids)->respond
+              | LoadByField({tableName, fieldName, fieldValue, operator}) =>
+                state->handleLoadByField(~tableName, ~fieldName, ~fieldValue, ~operator)->respond
+              | WriteBatch({...}) =>
+                state->handleWriteBatch(...)
+                Js.Json.null->respond
+              }
+            } catch {
+            | exn => respondError(exn->Utils.prettifyExn)
+            }
           })
🧹 Nitpick comments (1)
codegenerator/cli/templates/dynamic/codegen/src/Generated.res.hbs (1)

26-30: Test file filtering looks good, but verify pattern coverage.

The filter excludes files containing .test., .spec., or _test. which covers common conventions. However, files like foo_spec.ts or foo.tests.ts (plural) would not be filtered.

Consider extending patterns for completeness
-    files->Js.Array2.filter(file => {
-      !(file->Js.String2.includes(".test.") || file->Js.String2.includes(".spec.") || file->Js.String2.includes("_test."))
-    })
+    files->Js.Array2.filter(file => {
+      !(file->Js.String2.includes(".test.") || file->Js.String2.includes(".spec.") || file->Js.String2.includes("_test.") || file->Js.String2.includes("_spec."))
+    })
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8b3943b and 59f80fc.

📒 Files selected for processing (6)
  • .cursor/rules/navigation.mdc
  • AGENTS.md
  • CLAUDE.md
  • codegenerator/cli/npm/envio/src/TestIndexer.res
  • codegenerator/cli/templates/dynamic/codegen/src/Generated.res.hbs
  • codegenerator/cli/templates/static/codegen/src/TestIndexerWorker.res
💤 Files with no reviewable changes (1)
  • .cursor/rules/navigation.mdc
✅ Files skipped from review due to trivial changes (1)
  • CLAUDE.md
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{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 using ref function
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/templates/static/codegen/src/TestIndexerWorker.res
  • codegenerator/cli/npm/envio/src/TestIndexer.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
**/*.res

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Prefer reading ReScript .res modules directly; ignore compiled .js artifacts

Files:

  • codegenerator/cli/templates/static/codegen/src/TestIndexerWorker.res
  • codegenerator/cli/npm/envio/src/TestIndexer.res
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/Generated.res.hbs
🧠 Learnings (18)
📓 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-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/static/codegen/src/TestIndexerWorker.res
  • codegenerator/cli/npm/envio/src/TestIndexer.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:

  • codegenerator/cli/templates/static/codegen/src/TestIndexerWorker.res
  • codegenerator/cli/npm/envio/src/TestIndexer.res
  • codegenerator/cli/templates/dynamic/codegen/src/Generated.res.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/static/codegen/src/TestIndexerWorker.res
  • codegenerator/cli/npm/envio/src/TestIndexer.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} : Use `!context.isPreload` check to prevent logic from running during preload in HyperIndex handlers

Applied to files:

  • codegenerator/cli/templates/static/codegen/src/TestIndexerWorker.res
  • codegenerator/cli/templates/dynamic/codegen/src/Generated.res.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/static/codegen/src/TestIndexerWorker.res
  • codegenerator/cli/templates/dynamic/codegen/src/Generated.res.hbs
📚 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/npm/envio/src/TestIndexer.res
  • codegenerator/cli/templates/dynamic/codegen/src/Generated.res.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,**/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/npm/envio/src/TestIndexer.res
📚 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/src/TestIndexer.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} : 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/src/TestIndexer.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: For multichain indexing, prefix all entity IDs with `event.chainId`: `${event.chainId}-${originalId}`, never hardcode `chainId = 1`, always use `event.chainId`, and use chain-specific Bundle IDs like `${chainId}-1` for accurate pricing per network

Applied to files:

  • codegenerator/cli/npm/envio/src/TestIndexer.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: 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/templates/dynamic/codegen/src/Generated.res.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 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/src/Generated.res.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 codegenerator/cli/templates/dynamic/**/*.hbs : Templates in Handlebars format (.hbs) live under `codegenerator/cli/templates/dynamic/`

Applied to files:

  • codegenerator/cli/templates/dynamic/codegen/src/Generated.res.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: Config parsing flows: `human_config.rs` → `system_config.rs` → `hbs_templating/codegen_templates.rs`

Applied to files:

  • codegenerator/cli/templates/dynamic/codegen/src/Generated.res.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/src/Generated.res.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/Generated.res.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/src/Generated.res.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 (9)
AGENTS.md (1)

1-5: Verify this file belongs in this PR.

This file appears unrelated to the PR objectives (TestIndexer framework, Vitest migration) and is not mentioned in the commit message. No references to AGENTS.md were found in the codebase. If this was included unintentionally, it should be removed from this PR.

Note: .cursor/rules/ exists but contains .mdc files. CLAUDE.md is similarly placed at the repository root, suggesting root-level placement may be intentional for agent/AI guidance files.

codegenerator/cli/templates/dynamic/codegen/src/Generated.res.hbs (2)

1-1: LGTM! Inline JSON import directive.

Using the @@directive to import JSON with with { type: 'json' } is the correct approach for ES module JSON imports in ReScript, replacing the previous external binding pattern.


88-92: Verify %raw access to directive-imported value.

Using %raw(internalConfigJson) to reference the @@directive-imported JSON is necessary since the directive creates a runtime binding not visible to ReScript's type system. This is the expected pattern.

codegenerator/cli/npm/envio/src/TestIndexer.res (5)

1-24: LGTM! Type definitions are well-structured.

The type declarations for chainConfig, processResult, t<'processConfig>, entityChange, and testIndexerState provide a clean public API surface for the test indexer.


46-91: Field comparison logic correctly uses typed comparisons via TableIndices.FieldValue.

The implementation properly parses JSON to typed values using the field schema and delegates comparisons to TableIndices.FieldValue.eq/gt/lt, which handles bigint and BigDecimal correctly. This addresses the previous concern about raw JSON comparisons.


246-279: LGTM! Block range validation is comprehensive.

The validateBlockRange function provides clear, actionable error messages for invalid configurations, checking startBlock/endBlock bounds and preventing overlap with previously processed ranges.


433-466: LGTM! Worker initialization is well-structured.

The initTestWorker function properly validates it's running in a worker thread, extracts parent port, handles missing worker data gracefully, and silences logs by default in test mode while respecting explicit LOG_LEVEL settings.


26-44: > Likely an incorrect or invalid review comment.

codegenerator/cli/templates/static/codegen/src/TestIndexerWorker.res (1)

1-17: LGTM! Worker entry point is cleanly structured.

The worker bootstrap correctly:

  1. Registers the tsx loader before any TypeScript imports
  2. Wires up the generated handlers and config
  3. Constructs persistence with the required entity and enum configurations

The inline ~makePersistence function avoids circular dependencies by constructing Persistence.make at runtime.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment thread codegenerator/cli/npm/envio/src/TestIndexer.res
DZakh and others added 4 commits January 14, 2026 17:02
Previously, handleWriteBatch only inspected update.latestChange, skipping
earlier entries in update.history. This change mirrors PgStorage.res behavior
by iterating over all history entries and applying Set/Delete logic for each.

Includes a fallback to process latestChange when history is empty for
backwards compatibility.

Co-authored-by: Claude <noreply@anthropic.com>
@DZakh
DZakh merged commit 5f59a68 into main Jan 14, 2026
2 checks passed
@DZakh
DZakh deleted the dz/test-indexer-with-vitest branch January 14, 2026 13:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants