Skip to content

New Testing Framework#887

Closed
DZakh wants to merge 7 commits into
mainfrom
dz/create-test-indexer
Closed

New Testing Framework#887
DZakh wants to merge 7 commits into
mainfrom
dz/create-test-indexer

Conversation

@DZakh

@DZakh DZakh commented Jan 8, 2026

Copy link
Copy Markdown
Member

Related to: #802

Summary by CodeRabbit

  • New Features

    • Added a Test Indexer API with createTestIndexer to run in-memory test runs that return progress and change results.
    • Exposed worker-backed test execution to isolate test runs from the live server.
  • Public API

    • Introduced Prettify helper type.
    • Standardized public type names (Rescript-* → Type*), added TestIndexer types, and replaced legacy generated entity aliases with per-entity exports.
  • Tests

    • Added E2E and unit tests covering success, validation cases, and concurrent-call protection.

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

@coderabbitai

coderabbitai Bot commented Jan 8, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds a TestIndexer feature including in-memory proxy storage, a worker-thread test worker, public TestIndexer types/typings, createTestIndexer factory exported from generated packages, Node.js worker_threads bindings, and widespread refactor of Rescript-specific type names to a generalized type_schema API.

Changes

Cohort / File(s) Summary
Envio Type Definitions
codegenerator/cli/npm/envio/index.d.ts
Add public types: Prettify<T>, TestIndexerChainConfig, TestIndexerProgress, TestIndexerProcessConfig<Config>, TestIndexerFromConfig<Config>.
ReScript Runtime: Main & Test Indexer
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/TestIndexerWorker.res
Introduce TestIndexer implementation and proxy storage; add worker-based processing, in-memory store, request/response RPC types, single-concurrency/process validation, makeInitialState/makeStore, and worker init wiring. Update Main.start to accept ~isTest flag and gate server startup.
Node.js Worker Bindings
codegenerator/cli/npm/envio/src/bindings/NodeJs.res
Add WorkerThreads bindings (isMainThread, workerData, parentPort/messagePort, postMessage, onMessage/onError/onExit, makeWorker, terminate, workerPostMessage).
Generated API Surface
codegenerator/cli/templates/dynamic/codegen/index.js.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/Types.res.hbs
Export createTestIndexer from generated index; add TestIndexer type into generated typings; remove legacy per-entity backward-compat aliases.
Codegen Templates & Integration
codegenerator/cli/src/hbs_templating/codegen_templates.rs
Emit test-indexer scaffolding into generated indexer code and switch template internals to use the new type_schema types.
Type Schema Refactor (widespread)
codegenerator/cli/src/type_schema.rs, codegenerator/cli/src/*_parsing.rs, codegenerator/cli/src/hbs_templating/*, codegenerator/cli/src/config_parsing/*, codegenerator/cli/src/lib.rs, codegenerator/cli/src/hbs_templating/contract_import_templates.rs
Replace Rescript-specific names (RescriptTypeDecl/RescriptTypeExpr/RescriptTypeIdent/RescriptRecordField/RescriptVariantConstr/RescriptSchemaMode) with generalized TypeDecl/TypeExpr/TypeIdent/RecordField/VariantConstr/SchemaMode; add TypeScript string generation and adapt call sites and tests.
Tests / Scenarios
scenarios/test_codegen/test/EventHandler_test.ts, scenarios/erc20_multichain_factory/test/Handler_Test.res, scenarios/test_codegen/src/handlers/EventHandlers.res
Add unit and E2E tests for createTestIndexer/process behavior (success, missing/multiple-chain validation, concurrent invocation protection); minor handler type adjustments.

Sequence Diagram(s)

sequenceDiagram
  participant Consumer as Test Consumer
  participant Factory as createTestIndexer()
  participant Main as Main thread / Proxy
  participant Worker as TestIndexer Worker
  participant Store as In-memory Store

  Consumer->>Factory: call createTestIndexer()
  Factory->>Consumer: returns TestIndexer.handle.process
  Consumer->>Main: call process(processConfig)
  Main->>Main: validate exactly one chain, check processInProgress
  alt already running
    Main->>Consumer: throw "process already in progress"
  else proceed
    Main->>Worker: spawn Worker (workerData: initialState, processConfig)
    Worker->>Main: RPC LoadByIds / LoadByField requests
    Main->>Store: perform loadByIds/loadByField/writeBatch on in-memory store
    Store-->>Main: return data (JSON)
    Worker->>Main: send WriteBatch / checkpoints
    Main->>Consumer: return { checkpoints: [...], changes: {...} }
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • JonoPrest

Poem

🐰 I hop through templates, types, and threads,
A tiny indexer where the test-bed treads,
One chain to check, one process to mind,
Empty checkpoints and tidy changes we find,
The rabbit hums — the scaffolding spreads.

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 32.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'New Testing Framework' accurately reflects the main changes in this PR, which introduce a comprehensive testing framework with TestIndexer types, utilities, worker-based processing, and integration across TypeScript, ReScript, and Rust components.

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

✨ Finishing touches
  • 📝 Generate docstrings

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: 0

🧹 Nitpick comments (2)
scenarios/test_codegen/test/EventHandler_test.ts (1)

15-15: Consider consolidating imports from "generated".

The createTestIndexer import is on a separate line from the existing "generated" imports (lines 3-12). For consistency and cleaner code, consider merging it into the existing import block.

♻️ Suggested consolidation
 import {
   TestHelpers,
   indexer,
   type User,
   type Indexer,
   type EvmChainId,
   type EvmChainName,
   type FuelChainId,
   type SvmChainId,
+  createTestIndexer,
 } from "generated";
 import { type Address } from "envio";
 import { expectType, type TypeEqual } from "ts-expect";
-import { createTestIndexer } from "generated";
codegenerator/cli/npm/envio/src/Main.res (1)

358-368: Type parameter should be constrained when implementing actual logic.

The 'processConfig type parameter is free and unconstrained in the current scaffolding. When this mock is replaced with actual implementation, consider constraining it to testIndexerChainConfig (or the appropriate config shape) to ensure type safety at call sites. Currently, the unconstrained type parameter could require explicit type annotations for callers, though this scaffolding phase uses a mock that ignores the parameter entirely.

Replace the mock implementation with actual indexer chain processing logic once the API is further developed.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

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

⛔ 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 (8)
  • codegenerator/cli/npm/envio/index.d.ts
  • codegenerator/cli/npm/envio/src/Main.res
  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
  • codegenerator/cli/templates/dynamic/codegen/index.d.ts.hbs
  • codegenerator/cli/templates/dynamic/codegen/index.js.hbs
  • codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs
  • scenarios/erc20_multichain_factory/test/Handler_Test.res
  • scenarios/test_codegen/test/EventHandler_test.ts
🧰 Additional context used
📓 Path-based instructions (3)
codegenerator/cli/templates/dynamic/**/*.hbs

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

Templates in Handlebars format (.hbs) live under codegenerator/cli/templates/dynamic/

Files:

  • codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs
  • codegenerator/cli/templates/dynamic/codegen/index.js.hbs
  • codegenerator/cli/templates/dynamic/codegen/index.d.ts.hbs
**/*.{res,resi}

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

**/*.{res,resi}: Always use ReScript 11 documentation
Never suggest ReasonML syntax
Never use [| item |] to create an array. Use [ item ] instead
Must always use = for setting value to a field. Use := only for ref values created 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
  • scenarios/erc20_multichain_factory/test/Handler_Test.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
  • scenarios/erc20_multichain_factory/test/Handler_Test.res
🧠 Learnings (19)
📓 Common learnings
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.245Z
Learning: AFTER EVERY SINGLE CODE CHANGE, you MUST test the indexer with `TUI_OFF=true pnpm dev` to catch runtime errors early, as TypeScript compilation only catches syntax and type errors while runtime errors (database issues, missing entities, logic errors) only appear when running the indexer
Learnt from: nikbhintade
Repo: enviodev/hyperindex PR: 822
File: codegenerator/cli/templates/static/multichain_indexer_template/typescript/src/EventHandlers.ts:10-18
Timestamp: 2025-11-19T05:36:33.975Z
Learning: The multichain_indexer_template in codegenerator/cli/templates/static/ is designed to demonstrate multichain indexing features. It intentionally uses minimal event parameters (e.g., only capturing the `pool` address from Uniswap V3 PoolCreated events) to keep the focus on multichain functionality rather than comprehensive event indexing.
📚 Learning: 2025-12-04T12:12:49.547Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-12-04T12:12:49.547Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.{ts,js} : In Envio HyperIndex, use `entity_id` fields (e.g., `token_id: string`) instead of direct object references for entity relationships

Applied to files:

  • codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs
  • codegenerator/cli/npm/envio/index.d.ts
  • codegenerator/cli/templates/dynamic/codegen/index.js.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/src/Types.ts.hbs
  • scenarios/test_codegen/test/EventHandler_test.ts
  • codegenerator/cli/templates/dynamic/codegen/index.d.ts.hbs
📚 Learning: 2025-12-04T12:12:49.547Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-12-04T12:12:49.547Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.{ts,js} : Import and use the Effect API (`S`, `createEffect`) from 'envio' package for external calls in HyperIndex handlers

Applied to files:

  • codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs
  • scenarios/test_codegen/test/EventHandler_test.ts
  • codegenerator/cli/templates/dynamic/codegen/index.js.hbs
  • codegenerator/cli/templates/dynamic/codegen/index.d.ts.hbs
📚 Learning: 2025-12-04T12:12:49.547Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-12-04T12:12:49.547Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : Use `string | undefined` for optional string fields in Envio types, not `string | null`, as generated types are strict about null vs undefined

Applied to files:

  • codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs
📚 Learning: 2025-12-04T12:12:49.547Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-12-04T12:12:49.547Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.{ts,js} : When updating existing entities in HyperIndex handlers, always use the spread operator for immutability since returned objects are read-only

Applied to files:

  • codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs
  • codegenerator/cli/templates/dynamic/codegen/index.js.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 : Always verify entity type field names match exactly with the generated entity types. For example, use `token0_id` not `token0`, and `transaction_id` not `transaction`. Run `pnpm tsc --noEmit` to catch type mismatches

Applied to files:

  • codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs
📚 Learning: 2025-12-04T12:13:23.245Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.245Z
Learning: AFTER EVERY SINGLE CODE CHANGE, you MUST test the indexer with `TUI_OFF=true pnpm dev` to catch runtime errors early, as TypeScript compilation only catches syntax and type errors while runtime errors (database issues, missing entities, logic errors) only appear when running the indexer

Applied to files:

  • codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs
  • scenarios/test_codegen/test/EventHandler_test.ts
  • codegenerator/cli/npm/envio/index.d.ts
  • codegenerator/cli/templates/dynamic/codegen/index.js.hbs
  • codegenerator/cli/npm/envio/src/Main.res
  • scenarios/erc20_multichain_factory/test/Handler_Test.res
  • codegenerator/cli/templates/dynamic/codegen/index.d.ts.hbs
📚 Learning: 2025-11-19T05:36:33.975Z
Learnt from: nikbhintade
Repo: enviodev/hyperindex PR: 822
File: codegenerator/cli/templates/static/multichain_indexer_template/typescript/src/EventHandlers.ts:10-18
Timestamp: 2025-11-19T05:36:33.975Z
Learning: The multichain_indexer_template in codegenerator/cli/templates/static/ is designed to demonstrate multichain indexing features. It intentionally uses minimal event parameters (e.g., only capturing the `pool` address from Uniswap V3 PoolCreated events) to keep the focus on multichain functionality rather than comprehensive event indexing.

Applied to files:

  • codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs
  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
  • codegenerator/cli/npm/envio/index.d.ts
  • codegenerator/cli/templates/dynamic/codegen/index.js.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/**/EventHandlers.ts : For Step 1 - Clear all boilerplate code from EventHandlers.ts and replace with empty handlers containing TODO comments referencing the original subgraph implementation

Applied to files:

  • scenarios/test_codegen/test/EventHandler_test.ts
📚 Learning: 2026-01-05T11:20:07.222Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/navigation.mdc:0-0
Timestamp: 2026-01-05T11:20:07.222Z
Learning: Config parsing flows: `human_config.rs` → `system_config.rs` → `hbs_templating/codegen_templates.rs`

Applied to files:

  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
📚 Learning: 2025-12-04T12:13:23.246Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.246Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/src/**/*.ts : For Step 3 - Refactor file structure to mirror the original subgraph EXACTLY using the same filenames, create separate handler files by contract (e.g., contract1.ts, contract2.ts) instead of a single EventHandlers.ts file, and move handlers from EventHandlers.ts to contract-specific files

Applied to files:

  • codegenerator/cli/templates/dynamic/codegen/index.js.hbs
  • codegenerator/cli/templates/dynamic/codegen/index.d.ts.hbs
📚 Learning: 2025-12-04T12:12:49.547Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-12-04T12:12:49.547Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.{ts,js} : Use `context.effect` to make external calls in HyperIndex handlers and prevent double execution during preload optimization

Applied to files:

  • codegenerator/cli/templates/dynamic/codegen/index.js.hbs
  • codegenerator/cli/templates/dynamic/codegen/index.d.ts.hbs
📚 Learning: 2026-01-05T11:20:07.222Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/navigation.mdc:0-0
Timestamp: 2026-01-05T11:20:07.222Z
Learning: Applies to **/*.{test,spec}.{ts,tsx,js,jsx,res} : Prefer Public module API for testing

Applied to files:

  • codegenerator/cli/templates/dynamic/codegen/index.js.hbs
📚 Learning: 2025-12-04T12:13:23.246Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.246Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : MAINTAIN BigDecimal precision from the original subgraph. Use BigDecimal and BigInt types for financial calculations, never simplify to JavaScript number type which loses precision. Always use BigDecimal constants (ZERO_BD, ONE_BD) and BigInt constants (ZERO_BI, ONE_BI)

Applied to files:

  • codegenerator/cli/templates/dynamic/codegen/index.js.hbs
📚 Learning: 2025-12-04T12:12:49.547Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-12-04T12:12:49.547Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.{ts,js} : ALWAYS normalize amounts when adding tokens with different decimal places in HyperIndex handlers, creating helper functions to convert to standard decimals (e.g., 18 decimals)

Applied to files:

  • codegenerator/cli/templates/dynamic/codegen/index.d.ts.hbs
📚 Learning: 2025-12-04T12:12:49.547Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-12-04T12:12:49.547Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.{ts,js} : Use `!context.isPreload` check to prevent logic from running during preload in HyperIndex handlers

Applied to files:

  • codegenerator/cli/templates/dynamic/codegen/index.d.ts.hbs
📚 Learning: 2025-12-04T12:13:23.246Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.246Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : For Step 6 - Final Migration Verification: Go through each handler and helper function systematically, comparing the logic line-by-line to the original subgraph implementation. Iterate multiple times until logic is completely correct, as first pass often misses subtle differences

Applied to files:

  • codegenerator/cli/templates/dynamic/codegen/index.d.ts.hbs
📚 Learning: 2025-12-04T12:13:23.246Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.246Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/src/**/*.ts : For Step 4 - Implement contract registration for factory events using `contractRegister` above the handler to track dynamically created contracts: `Factory.EventName.contractRegister(({ event, context }) => { context.addContractName(event.params.contractAddress); });`

Applied to files:

  • codegenerator/cli/templates/dynamic/codegen/index.d.ts.hbs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build_and_test
🔇 Additional comments (11)
codegenerator/cli/src/hbs_templating/codegen_templates.rs (1)

1421-1447: Test indexer scaffolding looks well-integrated.

The generated ReScript types and factory function align with the public API surface. A few observations:

  1. The testIndexerProcessConfigChains uses optional fields (?) which correctly matches Partial<Record<...>> in the TypeScript types.
  2. The factory delegates to Main.makeCreateTestIndexer with the config, maintaining consistency with the runtime implementation.

One consideration: the generated chain field names use chain{id} format (e.g., chain1, chain137), but the tests in EventHandler_test.ts pass chain IDs directly as keys (1, 100, etc.). The @as("{id}") annotation should handle this mapping correctly.

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

638-654: Test case validates the basic API contract.

The test correctly validates that createTestIndexer returns an indexer with a process method that resolves to the expected structure. The empty result assertion aligns with the mock implementation in Main.res.

codegenerator/cli/templates/dynamic/codegen/index.d.ts.hbs (1)

10-12: Public API surface correctly exposes the test indexer.

The template properly imports TestIndexer from the types module and exports the createTestIndexer factory with the correct return type.

codegenerator/cli/templates/dynamic/codegen/index.js.hbs (1)

7-7: Export correctly added to the public module surface.

The createTestIndexer is properly exported from the ReScript-compiled module alongside the existing exports.

codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs (1)

87-98: TestIndexer type definition follows established patterns.

The conditional type correctly extracts the config from Global and delegates to TestIndexerFromConfig<Config>, consistent with how the Indexer type is defined. The fallback message provides helpful guidance when codegen hasn't been run.

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

476-481: Clear type definition for chain configuration.

The TestIndexerChainConfig type is straightforward with required startBlock and endBlock fields. Good documentation with JSDoc comments.


483-489: Progress type uses unknown for flexibility.

Using unknown[] for checkpoints and unknown[] for change arrays provides flexibility but trades off type safety. Consider adding more specific types in a future iteration once the structure is finalized.


491-511: Chain ID extraction assumes single ecosystem.

The TestIndexerChainIds helper type uses a cascading conditional that only extracts chain IDs from the first matching ecosystem (EVM → Fuel → SVM). This aligns with the current architecture where indexers typically target a single ecosystem, matching the pattern in SingleEcosystemChains.


513-528: Well-designed public API types.

The TestIndexerProcessConfig using Partial<Record<...>> allows tests to specify only a subset of configured chains, which is practical for targeted testing. The TestIndexerFromConfig provides a clean interface with a single process method.

scenarios/erc20_multichain_factory/test/Handler_Test.res (1)

5-27: No changes needed. The test correctly uses chain1 for chain ID 1.

Chain ID 1 is configured in the scenario, and the generated types map chain IDs to field names using the pattern chain{id} (e.g., @as("1") chain1?: Main.testIndexerChainConfig). The test code will compile correctly without type mismatch.

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

346-356: Type definitions look good.

The Test Indexer API type definitions are well-structured:

  • testIndexerChainConfig appropriately captures block range
  • testIndexerProgress correctly uses dict and array types for checkpoints and changes
  • testIndexer properly defines a generic record with a process method

@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/Main.res:
- Around line 375-376: The code is using Utils.magic twice to extract `chains`
from `processConfig`, bypassing type safety; define a concrete type
`processConfig` with a `chains: Js.Dict.t<testIndexerChainConfig>` field, update
the `testIndexer` type/signature so its `process` parameter uses this
`processConfig` type (e.g., `process: processConfig =>
promise<testIndexerProgress>`), and replace the double `Utils.magic` extraction
with a typed access to `processConfig.chains` so you no longer need any
`Utils.magic` casts.
🧹 Nitpick comments (2)
codegenerator/cli/npm/envio/src/Main.res (2)

362-365: Consider removing the unused config parameter.

The _config parameter is currently unused in the mock implementation. If it's not needed for the factory signature, consider removing it to reduce clutter. If it's reserved for future implementation, the current approach is acceptable.


390-398: Consider adding error handling for future-proofing.

The current mock implementation safely resets processInProgress in the success path. If this is later converted to a real async implementation that can fail, ensure the flag is also reset in error cases (e.g., using Promise.catch or try/finally pattern). For the current mock implementation, this is acceptable.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 590a59d and b2ef3d4.

📒 Files selected for processing (2)
  • codegenerator/cli/npm/envio/src/Main.res
  • scenarios/test_codegen/test/EventHandler_test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • scenarios/test_codegen/test/EventHandler_test.ts
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{res,resi}

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

**/*.{res,resi}: Always use ReScript 11 documentation
Never suggest ReasonML syntax
Never use [| item |] to create an array. Use [ item ] instead
Must always use = for setting value to a field. Use := only for ref values created 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
**/*.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
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.245Z
Learning: AFTER EVERY SINGLE CODE CHANGE, you MUST test the indexer with `TUI_OFF=true pnpm dev` to catch runtime errors early, as TypeScript compilation only catches syntax and type errors while runtime errors (database issues, missing entities, logic errors) only appear when running the indexer
📚 Learning: 2025-12-04T12:13:23.245Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.245Z
Learning: AFTER EVERY SINGLE CODE CHANGE, you MUST test the indexer with `TUI_OFF=true pnpm dev` to catch runtime errors early, as TypeScript compilation only catches syntax and type errors while runtime errors (database issues, missing entities, logic errors) only appear when running the indexer

Applied to files:

  • codegenerator/cli/npm/envio/src/Main.res
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build_and_test
🔇 Additional comments (2)
codegenerator/cli/npm/envio/src/Main.res (2)

344-360: LGTM! Clean type definitions.

The type definitions for the Test Indexer API are well-structured and appropriate for the mock implementation.


344-401: The suggested test location is incorrect. scenarios/test_codegen is a separate example indexer project that would not test this CLI code. No specific tests exist for this new Test Indexer API in the Main.res codebase, and the guidance to test in scenarios/test_codegen would not verify this implementation.

If unit tests are needed for makeCreateTestIndexer, they should be added to the appropriate test suite within codegenerator/cli/npm/envio with other Main.res tests, not run against a separate example indexer project.

Likely an incorrect or invalid review comment.

Comment on lines +375 to +376
let chains: Js.Dict.t<testIndexerChainConfig> =
(processConfig->Utils.magic)["chains"]->Utils.magic

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

Unsafe type casting bypasses type safety.

Using Utils.magic twice to extract and cast the chains field from processConfig completely bypasses ReScript's type system. This can lead to runtime errors if the structure doesn't match expectations.

Instead of using a generic 'processConfig type parameter with magic casts, define a proper type for the process config:

type processConfig = {
  chains: Js.Dict.t<testIndexerChainConfig>
}

// Then update the testIndexer type to use the concrete type
type testIndexer = {process: processConfig => promise<testIndexerProgress>}

This aligns with the coding guideline principle: "Never use %raw to access object fields if you know the type" (similar principle applies to magic).

🔧 Proposed fix

Add a proper type definition before the testIndexer type:

+type testIndexerProcessConfig = {
+  chains: Js.Dict.t<testIndexerChainConfig>,
+}
+
-type testIndexer<'processConfig> = {process: 'processConfig => promise<testIndexerProgress>}
+type testIndexer = {process: testIndexerProcessConfig => promise<testIndexerProgress>}

Then update the factory signature and implementation:

-let makeCreateTestIndexer = (~config as _config: Config.t): (unit => testIndexer<'processConfig>) => {
+let makeCreateTestIndexer = (~config as _config: Config.t): (unit => testIndexer) => {
   () => {
     let state = {processInProgress: false}
     {
       process: processConfig => {
         // ... validation code ...
         
-        let chains: Js.Dict.t<testIndexerChainConfig> =
-          (processConfig->Utils.magic)["chains"]->Utils.magic
+        let chains = processConfig.chains
         let chainKeys = chains->Js.Dict.keys
🤖 Prompt for AI Agents
In @codegenerator/cli/npm/envio/src/Main.res around lines 375 - 376, The code is
using Utils.magic twice to extract `chains` from `processConfig`, bypassing type
safety; define a concrete type `processConfig` with a `chains:
Js.Dict.t<testIndexerChainConfig>` field, update the `testIndexer`
type/signature so its `process` parameter uses this `processConfig` type (e.g.,
`process: processConfig => promise<testIndexerProgress>`), and replace the
double `Utils.magic` extraction with a typed access to `processConfig.chains` so
you no longer need any `Utils.magic` casts.

@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

🤖 Fix all issues with AI agents
In @codegenerator/cli/npm/envio/src/bindings/NodeJs.res:
- Line 103: The onMessage external binding exposes a polymorphic type parameter
'a for the message callback which bypasses serialization/type-safety (same issue
as postMessage/workerData); change the callback signature in onMessage to accept
a concrete serializable type (e.g., Js.Json.t or a specific DTO type) instead of
'a, update the @as("message") param accordingly, and document that callers must
decode/encode messages to/from JSON to ensure safe serialization across worker
boundaries.
- Around line 89-94: The polymorphic type 'a used in workerData, postMessage and
onMessage allows non-serializable values and can cause DataCloneError at
runtime; change those polymorphic types to Js.Json.t (i.e., update external
workerData: Js.Nullable.t<'a> -> Js.Nullable.t<Js.Json.t>, postMessage:
(messagePort, 'a) => unit -> (messagePort, Js.Json.t) => unit, and the onMessage
handler signature likewise) so the bindings only accept structured-clone-able
JSON values, and update any related helper functions or docs to reflect the
Js.Json.t contract.

In @codegenerator/cli/npm/envio/src/Main.res:
- Around line 375-386: The code is unsafely casting processConfig->Utils.magic
to Js.Dict.t<testIndexerChainConfig> via Utils.magic; replace the magic casts
with a typed access and runtime validation: change the function signature or the
surrounding type for processConfig so it includes a chains:
Js.Dict.t<testIndexerChainConfig> field (or extract chains via a safe accessor
that returns option), remove Utils.magic usages, then validate the extracted
value (e.g., pattern-match Some(dict) vs None or use Js.Json decoding) before
computing chainKeys and running createTestIndexer logic to ensure you never
assume the shape at runtime.
🧹 Nitpick comments (3)
codegenerator/cli/npm/envio/src/Main.res (2)

388-397: Consider adding error handling for robustness.

The processInProgress flag is reset in thenResolve (line 395), which only handles the success case. For the current mock implementation this is acceptable, but when implementing real functionality, consider using a finally block or catch handler to ensure the flag is reset even if an error occurs.

♻️ Suggested pattern for future implementation
-        Promise.resolve({
-          checkpoints: [],
-          changes: Js.Dict.empty(),
-        })->Promise.thenResolve(result => {
-          state.processInProgress = false
-          result
-        })
+        Promise.resolve({
+          checkpoints: [],
+          changes: Js.Dict.empty(),
+        })
+        ->Promise.then(result => {
+          state.processInProgress = false
+          Promise.resolve(result)
+        })
+        ->Promise.catch(error => {
+          state.processInProgress = false
+          Promise.reject(error)
+        })

Or use a try/finally pattern when adding real async work.


360-361: Mock implementation: config parameter unused.

The _config parameter is intentionally unused (indicated by the underscore prefix), which is appropriate for this mock implementation. When you're ready to implement the actual test indexer functionality, the config will likely be needed for chain configuration, contract setup, and event processing.

Would you like me to help implement the actual test indexer logic that uses the config to process events, or should this remain a stub for now?

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

98-98: The workerOptions type is currently unused in the codebase.

The workerOptions type only includes the workerData field. While Node.js WorkerOptions does support additional fields (eval, execArgv, stdin, stdout, stderr, resourceLimits, etc.), there are no usages of makeWorker or workerOptions in the codebase. The current minimal binding appears intentional. Expand this type only when those options are actually needed.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b2ef3d4 and 8cf0ffa.

📒 Files selected for processing (2)
  • codegenerator/cli/npm/envio/src/Main.res
  • codegenerator/cli/npm/envio/src/bindings/NodeJs.res
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{res,resi}

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

**/*.{res,resi}: Always use ReScript 11 documentation
Never suggest ReasonML syntax
Never use [| item |] to create an array. Use [ item ] instead
Must always use = for setting value to a field. Use := only for ref values created 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/bindings/NodeJs.res
  • codegenerator/cli/npm/envio/src/Main.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/bindings/NodeJs.res
  • codegenerator/cli/npm/envio/src/Main.res
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.245Z
Learning: AFTER EVERY SINGLE CODE CHANGE, you MUST test the indexer with `TUI_OFF=true pnpm dev` to catch runtime errors early, as TypeScript compilation only catches syntax and type errors while runtime errors (database issues, missing entities, logic errors) only appear when running the indexer
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/navigation.mdc:0-0
Timestamp: 2026-01-05T11:20:07.222Z
Learning: Verify tests pass by running compiler `pnpm rescript` and tests `pnpm mocha`
📚 Learning: 2025-12-04T12:13:23.245Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.245Z
Learning: AFTER EVERY SINGLE CODE CHANGE, you MUST test the indexer with `TUI_OFF=true pnpm dev` to catch runtime errors early, as TypeScript compilation only catches syntax and type errors while runtime errors (database issues, missing entities, logic errors) only appear when running the indexer

Applied to files:

  • codegenerator/cli/npm/envio/src/Main.res
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build_and_test
🔇 Additional comments (3)
codegenerator/cli/npm/envio/src/Main.res (3)

346-354: LGTM! Clean type definitions.

The type definitions follow ReScript 11 conventions correctly and provide a clear API surface for the test indexer.


356-358: LGTM! Appropriate type definitions for the API.

The generic testIndexer type and mutable state tracking are well-designed for handling concurrent access control.


368-372: LGTM! Effective concurrency guard.

The check prevents overlapping process calls with a clear error message.

Comment on lines +89 to +94
@module("worker_threads") external workerData: Js.Nullable.t<'a> = "workerData"

// MessagePort for communication with parent
type messagePort
@module("worker_threads") external parentPort: Js.Nullable.t<messagePort> = "parentPort"
@send external postMessage: (messagePort, 'a) => unit = "postMessage"

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

🧩 Analysis chain

🌐 Web query:

Node.js worker_threads workerData postMessage serialization requirements structured clone

💡 Result:

Short answer: workerData and postMessage in worker_threads use the HTML structured clone algorithm — values must be structured-cloneable (primitives, plain objects/arrays, Map/Set, Date, RegExp (with some caveats), TypedArrays/ArrayBuffer, SharedArrayBuffer, MessagePort, etc.). Functions, DOM nodes and other non‑cloneable things will throw (DataCloneError). You can also transfer ownership of transferable objects (e.g. ArrayBuffer, MessagePort) via the second argument to postMessage. See Node.js docs and the Structured Clone spec/MDN for full lists and details. [1][2]

References

  • Node.js worker_threads (workerData / postMessage & transfer support). [1]
  • MDN: The structured clone algorithm (supported/unsupported types and caveats). [2]

🏁 Script executed:

cat -n codegenerator/cli/npm/envio/src/bindings/NodeJs.res | sed -n '84,107p'

Repository: enviodev/hyperindex

Length of output: 1243


Type safety concern: polymorphic types do not enforce serializability constraint.

The polymorphic type 'a used in workerData (line 89), postMessage (line 94), and onMessage (line 103) does not enforce that data must be structured-cloneable. Node.js worker_threads uses the structured clone algorithm, which only supports certain data types (primitives, objects, arrays, Map/Set, Date, RegExp, TypedArrays, SharedArrayBuffer, MessagePort, etc.). Non-serializable data (functions, symbols, DOM nodes, etc.) will cause runtime errors (DataCloneError).

This is inconsistent with workerOptions.workerData (line 98), which correctly uses Js.Json.t to provide stronger compile-time safety. Consider using Js.Json.t for all bindings or documenting this serializability constraint clearly for developers.

🤖 Prompt for AI Agents
In @codegenerator/cli/npm/envio/src/bindings/NodeJs.res around lines 89 - 94,
The polymorphic type 'a used in workerData, postMessage and onMessage allows
non-serializable values and can cause DataCloneError at runtime; change those
polymorphic types to Js.Json.t (i.e., update external workerData:
Js.Nullable.t<'a> -> Js.Nullable.t<Js.Json.t>, postMessage: (messagePort, 'a) =>
unit -> (messagePort, Js.Json.t) => unit, and the onMessage handler signature
likewise) so the bindings only accept structured-clone-able JSON values, and
update any related helper functions or docs to reflect the Js.Json.t contract.

@new @module("worker_threads")
external makeWorker: (string, workerOptions) => worker = "Worker"

@send external onMessage: (worker, @as("message") _, 'a => unit) => unit = "on"

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

Note: Same type safety concern as postMessage.

The onMessage callback uses polymorphic type 'a for the message parameter, which has the same serialization concerns mentioned in the earlier comment about postMessage and workerData.

🤖 Prompt for AI Agents
In @codegenerator/cli/npm/envio/src/bindings/NodeJs.res at line 103, The
onMessage external binding exposes a polymorphic type parameter 'a for the
message callback which bypasses serialization/type-safety (same issue as
postMessage/workerData); change the callback signature in onMessage to accept a
concrete serializable type (e.g., Js.Json.t or a specific DTO type) instead of
'a, update the @as("message") param accordingly, and document that callers must
decode/encode messages to/from JSON to ensure safe serialization across worker
boundaries.

Comment thread codegenerator/cli/npm/envio/src/Main.res 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: 0

🧹 Nitpick comments (3)
codegenerator/cli/src/type_schema.rs (2)

19-66: Guard against cycles in TypeDeclMulti::to_rescript_schema

The dependency-based sorting loop will never terminate if there is a cycle between type declarations, since sorted.len() will stop increasing but the while condition remains true. Even if current inputs are acyclic, this is a brittle failure mode.

Consider detecting lack of progress in an iteration and either:

  • returning an error with the offending types, or
  • falling back to a stable order with a warning.

This keeps generation robust against accidental cyclic declarations.


290-323: TypeScript type strings: handle non-identifier field names and expand tests

TypeExpr::to_ts_type_string currently emits object types like { dashed-field: boolean }, which is invalid TS when field.name (or as_name) contains characters that require quoting (dashes, spaces, etc.). RecordField::to_valid_rescript_name doesn’t sanitize such characters, so this is reachable for schemas with those field names.

To avoid generating invalid TS:

  • Detect when field_name is not a valid identifier and emit a quoted key instead:
    • e.g. { "dashed-field": boolean } or { ['dashed-field']: boolean }.

And to pin behavior, add TS-string tests that cover:

  • A RecordField where as_name is set (reserved word or renamed field).
  • A field name with characters like - that force quoting.
Example adjustment
-                            let field_name = field
-                                .as_name
-                                .as_ref()
-                                .map_or(field.name.as_str(), |name| name.as_str());
-                            format!("{}: {}", field_name, field.type_ident.to_ts_type_string())
+                            let field_name = field
+                                .as_name
+                                .as_ref()
+                                .map_or(field.name.as_str(), |name| name.as_str());
+                            let needs_quotes = !field_name
+                                .chars()
+                                .next()
+                                .is_some_and(|c| c == '_' || c.is_alphabetic())
+                                || !field_name
+                                    .chars()
+                                    .all(|c| c == '_' || c.is_alphanumeric());
+                            let rendered_name = if needs_quotes {
+                                format!("\"{field_name}\"")
+                            } else {
+                                field_name.to_string()
+                            };
+                            format!(
+                                "{}: {}",
+                                rendered_name,
+                                field.type_ident.to_ts_type_string()
+                            )

Also, these TS string helpers are now part of the codegen surface; after regenerating an indexer that exercises them, please run TUI_OFF=true pnpm dev to catch any runtime/typing regressions. Based on learnings, this is expected after schema/type changes.

Also applies to: 347-373, 794-804, 1168-1277

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

3-4: Eth ABI → TypeIdent mapping looks correct (name can be modernized later)

The updated abi_to_rescript_type correctly builds TypeIdent trees (BigInt/Bool/Address/String/Array/Tuple) and the tests cover arrays, fixed arrays, tuples, and default values, so behavior matches prior expectations.

At some point you might want to rename abi_to_rescript_type to something like abi_to_type_ident to reflect the generalized TypeIdent abstraction, but that’s purely cosmetic and can be deferred.

Also applies to: 110-151, 193-251

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8cf0ffa and df19236.

📒 Files selected for processing (8)
  • 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
🧰 Additional context used
🧠 Learnings (16)
📓 Common learnings
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.245Z
Learning: AFTER EVERY SINGLE CODE CHANGE, you MUST test the indexer with `TUI_OFF=true pnpm dev` to catch runtime errors early, as TypeScript compilation only catches syntax and type errors while runtime errors (database issues, missing entities, logic errors) only appear when running the indexer
Learnt from: nikbhintade
Repo: enviodev/hyperindex PR: 822
File: codegenerator/cli/templates/static/multichain_indexer_template/typescript/src/EventHandlers.ts:10-18
Timestamp: 2025-11-19T05:36:33.975Z
Learning: The multichain_indexer_template in codegenerator/cli/templates/static/ is designed to demonstrate multichain indexing features. It intentionally uses minimal event parameters (e.g., only capturing the `pool` address from Uniswap V3 PoolCreated events) to keep the focus on multichain functionality rather than comprehensive event indexing.
📚 Learning: 2025-12-04T12:12:49.547Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-12-04T12:12:49.547Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.{ts,js} : In Envio HyperIndex, use `entity_id` fields (e.g., `token_id: string`) instead of direct object references for entity relationships

Applied to files:

  • codegenerator/cli/src/hbs_templating/contract_import_templates.rs
  • codegenerator/cli/src/config_parsing/system_config.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 : Import entity types from `generated/src/db/Entities.gen` for type annotations (e.g., `Pair_t`, `Token_t`), NOT from `generated` which exports contract handlers. Use the correct entity type imports to prevent TypeScript errors like 'refers to a value, but is being used as a type'

Applied to files:

  • codegenerator/cli/src/hbs_templating/contract_import_templates.rs
  • codegenerator/cli/src/config_parsing/event_parsing.rs
  • codegenerator/cli/src/config_parsing/entity_parsing.rs
  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
📚 Learning: 2026-01-05T11:20:07.222Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/navigation.mdc:0-0
Timestamp: 2026-01-05T11:20:07.222Z
Learning: Applies to codegenerator/cli/templates/static/**/*.res : Static ReScript template files live under `codegenerator/cli/templates/static/` and are copied verbatim

Applied to files:

  • codegenerator/cli/src/hbs_templating/contract_import_templates.rs
  • codegenerator/cli/src/lib.rs
📚 Learning: 2025-12-04T12:13:23.246Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.246Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : Always verify entity type field names match exactly with the generated entity types. For example, use `token0_id` not `token0`, and `transaction_id` not `transaction`. Run `pnpm tsc --noEmit` to catch type mismatches

Applied to files:

  • codegenerator/cli/src/hbs_templating/contract_import_templates.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/**/src/**/*.ts : For Step 3 - Refactor file structure to mirror the original subgraph EXACTLY using the same filenames, create separate handler files by contract (e.g., contract1.ts, contract2.ts) instead of a single EventHandlers.ts file, and move handlers from EventHandlers.ts to contract-specific files

Applied to files:

  • codegenerator/cli/src/hbs_templating/contract_import_templates.rs
📚 Learning: 2025-11-25T12:40:26.435Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/rescript.mdc:0-0
Timestamp: 2025-11-25T12:40:26.435Z
Learning: Applies to **/*.{res,resi} : Always use ReScript 11 documentation

Applied to files:

  • codegenerator/cli/src/fuel/abi.rs
  • codegenerator/cli/src/lib.rs
📚 Learning: 2025-12-04T12:13:23.246Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.246Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/schema.graphql : For Step 2 - Migrate GraphQL schema from TheGraph format to Envio format: remove `entity` decorators, convert `Bytes!` to `String!`, convert `ID!` to `ID!` (keep as is), and ensure ALL entity arrays have `derivedFrom(field: "fieldName")` directives to prevent 'EE211: Arrays of entities is unsupported' error

Applied to files:

  • codegenerator/cli/src/config_parsing/entity_parsing.rs
  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
  • codegenerator/cli/src/type_schema.rs
📚 Learning: 2025-12-04T12:12:49.547Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-12-04T12:12:49.547Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.graphql : Use `entity_id` fields for relationships in GraphQL schemas (e.g., `user_id: String!`) instead of direct entity references or entity arrays

Applied to files:

  • codegenerator/cli/src/config_parsing/entity_parsing.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,**/schema.graphql} : Ensure database schema compatibility: verify that the types you're setting in code match the schema entity property types exactly. Compare with schema.graphql - for example, `Int!` in schema requires `number` in code, `BigInt!` requires `BigInt`, `BigDecimal!` requires `BigDecimal`

Applied to files:

  • codegenerator/cli/src/config_parsing/entity_parsing.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/**/*.graphql : Do not add the entity decorator to GraphQL schema types in HyperIndex

Applied to files:

  • 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/src/hbs_templating/codegen_templates.rs
📚 Learning: 2025-12-04T12:13:23.246Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.246Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : When accessing entity fields that represent relationships, use the `_id` suffix convention. For example, use `token0_id` not `token0` when storing relationships in entity types

Applied to files:

  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
📚 Learning: 2025-11-19T05:36:33.975Z
Learnt from: nikbhintade
Repo: enviodev/hyperindex PR: 822
File: codegenerator/cli/templates/static/multichain_indexer_template/typescript/src/EventHandlers.ts:10-18
Timestamp: 2025-11-19T05:36:33.975Z
Learning: The multichain_indexer_template in codegenerator/cli/templates/static/ is designed to demonstrate multichain indexing features. It intentionally uses minimal event parameters (e.g., only capturing the `pool` address from Uniswap V3 PoolCreated events) to keep the focus on multichain functionality rather than comprehensive event indexing.

Applied to files:

  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
📚 Learning: 2026-01-05T11:20:07.222Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/navigation.mdc:0-0
Timestamp: 2026-01-05T11:20:07.222Z
Learning: Applies to **/*.res : Prefer reading ReScript `.res` modules directly; ignore compiled `.js` artifacts

Applied to files:

  • codegenerator/cli/src/lib.rs
📚 Learning: 2025-11-25T12:40:26.435Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/rescript.mdc:0-0
Timestamp: 2025-11-25T12:40:26.435Z
Learning: Applies to **/*.{res,resi} : Use records when working with structured data, and objects to conveniently pass payload data between functions

Applied to files:

  • codegenerator/cli/src/type_schema.rs
🧬 Code graph analysis (6)
codegenerator/cli/src/hbs_templating/contract_import_templates.rs (1)
codegenerator/cli/src/type_schema.rs (1)
  • to_valid_rescript_name (348-364)
codegenerator/cli/src/fuel/abi.rs (1)
codegenerator/cli/src/type_schema.rs (5)
  • new (20-26)
  • new (113-121)
  • new (366-373)
  • new (398-401)
  • constructors (311-320)
codegenerator/cli/src/config_parsing/event_parsing.rs (1)
codegenerator/cli/src/type_schema.rs (4)
  • new (20-26)
  • new (113-121)
  • new (366-373)
  • new (398-401)
codegenerator/cli/src/config_parsing/entity_parsing.rs (1)
codegenerator/cli/src/type_schema.rs (4)
  • new (20-26)
  • new (113-121)
  • new (366-373)
  • new (398-401)
codegenerator/cli/src/hbs_templating/codegen_templates.rs (1)
codegenerator/cli/src/type_schema.rs (5)
  • to_valid_rescript_name (348-364)
  • to_rescript_schema (28-66)
  • to_rescript_schema (158-181)
  • to_rescript_schema (240-288)
  • to_rescript_schema (551-608)
codegenerator/cli/src/type_schema.rs (2)
codegenerator/cli/src/fuel/abi.rs (1)
  • vec (348-351)
codegenerator/cli/src/config_parsing/event_parsing.rs (1)
  • params (73-83)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build_and_test
🔇 Additional comments (11)
codegenerator/cli/src/lib.rs (1)

13-13: Module wiring for type_schema looks correct

Declaring mod type_schema; here cleanly exposes the new internal module to the rest of the crate without altering the public surface. No issues spotted.

codegenerator/cli/src/hbs_templating/contract_import_templates.rs (1)

190-200: Centralizing ReScript param name normalization is a good move

Using RecordField::to_valid_rescript_name(&js_name) here reuses the same reserved-word and identifier normalization as the rest of the type system, so event param names and entity field names stay aligned across generators. No functional issues spotted in this refactor.

Also applies to: 465-481

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

22-24: TypeIdent migration in field selection appears consistent

The switch from RescriptTypeIdent to TypeIdent for FuelEventKind::LogData, SelectedField.data_type, and the Block/Transaction field mappings preserves the existing semantics:

  • Fuel defaults (FieldSelection::fuel) still map id/height/time to String/Int.
  • EVM block/transaction fields use the expected Int/BigInt/Address/String/array/option combinations, including the HyperSyncClient.ResponseTypes.* applications.

Nothing problematic stands out in the new TypeIdent-based wiring.

Also applies to: 1277-1717

codegenerator/cli/src/fuel/abi.rs (1)

6-8: Fuel ABI → type_schema integration is coherent

The refactor cleanly moves Fuel decoding onto the new type_schema surface:

  • FuelType.type_decl: TypeDecl and FuelLog.data_type: TypeIdent line up with to_type_decl_multi returning a TypeDeclMulti.
  • unified_type_application_to_type_ident correctly distinguishes named type applications from generic parameters and recursively builds TypeIdent::TypeApplication/GenericParam graphs.
  • Structs/enums/tuples/arrays are mapped into TypeExpr::{Record, Variant} and TypeIdent::Tuple/Array as expected.

Behavior is equivalent to the previous Rescript-specific types, just on the new abstractions.

Also applies to: 79-116, 144-193, 216-324, 338-355, 472-481

codegenerator/cli/src/config_parsing/entity_parsing.rs (2)

823-849: GraphQL → TypeIdent mapping for scalars, nullability, and lists is consistent and well-tested

The new UserDefinedFieldType::to_rescript_type / FieldType::to_rescript_type pipeline correctly encodes:

  • Nullable scalars as TypeIdent::Option(<scalar>) (e.g. "Int"option<int>).
  • Non-null scalars as the bare type (e.g. "Int!"int).
  • Non-null lists of non-null scalars as Array<scalar> (e.g. "[Int!]!"array<int>).
  • Nullable lists as Option<Array<inner>>, producing shapes like option<array<option<int>>> for [Int].

The tests around gql_type_to_rescript_type_* and gql_type_to_rescript_type_entity/enum exercise these paths and confirm the expected string forms, so the migration to TypeIdent preserves behavior. Field::get_postgres_field also correctly uses SchemaMode::ForDb when emitting res_schema_code.

Also applies to: 1063-1085, 1672-1730, 1894-1914


1434-1452: GqlScalarTypeIdent mapping looks correct across built-ins, Big types, and enums*

The new GqlScalar::to_rescript_type implementation maps:

  • Built-ins (ID, String, Int, Float, Boolean, Bytes, Json, Timestamp) onto the corresponding TypeIdent primitives.
  • BigInt/BigDecimal to TypeIdent::BigInt/BigDecimal.
  • Custom scalars to:
    • TypeIdent::ID for entity references.
    • TypeIdent::SchemaEnum(name.to_capitalized_options()) for enums.

This aligns with how entity and enum fields are rendered elsewhere (and matches expectations in tests like gql_type_to_rescript_type_entity and gql_type_to_rescript_type_enum). No mismatches spotted.

codegenerator/cli/src/hbs_templating/codegen_templates.rs (5)

29-29: LGTM! Clean refactoring of type imports.

The migration from Rescript* types to general Type* types is consistent with the usage throughout the file and aligns with the broader refactoring effort described in the AI summary.


76-165: LGTM! Type system migration is consistent and complete.

The changes from RescriptTypeIdent to TypeIdent, RescriptRecordField to RecordField, and RescriptTypeExpr to TypeExpr are applied consistently throughout entity and record type template generation. The use of SchemaMode::ForDb (line 165) is appropriate for database schema generation.


402-610: LGTM! Event template generation correctly uses the new type system.

The use of RecordField::to_valid_rescript_name for parameter name validation, TypeIdent for type comparisons, and TypeExpr for building event argument types is consistent throughout. The schema generation with SchemaMode::ForDb is appropriate for event parameter schemas.


1934-1949: LGTM! Test helper constants and functions updated correctly.

The test constants (RESCRIPT_BIG_INT_TYPE, RESCRIPT_ADDRESS_TYPE, RESCRIPT_STRING_TYPE) are updated to use TypeIdent, and the EventParamTypeTemplate::new helper function correctly uses the new type system.


1419-1445: LGTM! Test indexer scaffolding is well-structured.

The new test indexer code generates appropriate types and a factory function. The optional chain configuration fields and the use of Main.makeCreateTestIndexer with the config are well-designed. All referenced types (Main.testIndexerChainConfig, Main.testIndexer, Main.makeCreateTestIndexer) and config (Generated.configWithoutRegistrations) are properly defined in the codebase.

@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: 0

🧹 Nitpick comments (1)
codegenerator/cli/npm/envio/index.d.ts (1)

487-492: Consider more specific types for better type safety.

The unknown[] types for checkpoints and changes values reduce type safety. Consider defining more specific types if the structure is known (e.g., checkpoint shape, entity change shape), or at least documenting the expected structure in JSDoc comments to help consumers understand what to expect.

💡 Potential type refinement example
+/** A checkpoint representing a processed block. */
+export type TestIndexerCheckpoint = {
+  chainId: number;
+  blockNumber: number;
+  // ... other checkpoint fields
+};
+
+/** An entity change captured during processing. */
+export type TestIndexerEntityChange = {
+  id: string;
+  operation: 'create' | 'update' | 'delete';
+  // ... other change fields
+};
+
 /** Progress returned after processing blocks with the test indexer. */
 export type TestIndexerProgress = {
   /** Array of checkpoints processed. */
-  checkpoints: unknown[];
+  checkpoints: TestIndexerCheckpoint[];
   /** Entity changes keyed by entity name. */
-  changes: Record<string, unknown[]>;
+  changes: Record<string, TestIndexerEntityChange[]>;
 };
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between df19236 and bcae3c4.

📒 Files selected for processing (3)
  • codegenerator/cli/npm/envio/index.d.ts
  • codegenerator/cli/templates/dynamic/codegen/src/Types.res.hbs
  • codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs
💤 Files with no reviewable changes (1)
  • codegenerator/cli/templates/dynamic/codegen/src/Types.res.hbs
🚧 Files skipped from review as they are similar to previous changes (1)
  • codegenerator/cli/templates/dynamic/codegen/src/Types.ts.hbs
🧰 Additional context used
🧠 Learnings (14)
📓 Common learnings
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.245Z
Learning: AFTER EVERY SINGLE CODE CHANGE, you MUST test the indexer with `TUI_OFF=true pnpm dev` to catch runtime errors early, as TypeScript compilation only catches syntax and type errors while runtime errors (database issues, missing entities, logic errors) only appear when running the indexer
📚 Learning: 2025-12-04T12:12:49.547Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-12-04T12:12:49.547Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.{ts,js} : In Envio HyperIndex, use `entity_id` fields (e.g., `token_id: string`) instead of direct object references for entity relationships

Applied to files:

  • codegenerator/cli/npm/envio/index.d.ts
📚 Learning: 2025-12-04T12:12:49.547Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-12-04T12:12:49.547Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.{ts,js} : When updating existing entities in HyperIndex handlers, always use the spread operator for immutability since returned objects are read-only

Applied to files:

  • codegenerator/cli/npm/envio/index.d.ts
📚 Learning: 2025-12-04T12:13:23.246Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.246Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : Import entity types from `generated/src/db/Entities.gen` for type annotations (e.g., `Pair_t`, `Token_t`), NOT from `generated` which exports contract handlers. Use the correct entity type imports to prevent TypeScript errors like 'refers to a value, but is being used as a type'

Applied to files:

  • codegenerator/cli/npm/envio/index.d.ts
📚 Learning: 2025-12-04T12:13:23.246Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.246Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : Always verify entity type field names match exactly with the generated entity types. For example, use `token0_id` not `token0`, and `transaction_id` not `transaction`. Run `pnpm tsc --noEmit` to catch type mismatches

Applied to files:

  • codegenerator/cli/npm/envio/index.d.ts
📚 Learning: 2026-01-05T11:20:07.222Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/navigation.mdc:0-0
Timestamp: 2026-01-05T11:20:07.222Z
Learning: Applies to **/*.{test,spec}.{ts,tsx,js,jsx,res} : Prefer Public module API for testing

Applied to files:

  • codegenerator/cli/npm/envio/index.d.ts
📚 Learning: 2025-12-04T12:12:49.547Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-12-04T12:12:49.547Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.{ts,js} : ALWAYS normalize amounts when adding tokens with different decimal places in HyperIndex handlers, creating helper functions to convert to standard decimals (e.g., 18 decimals)

Applied to files:

  • codegenerator/cli/npm/envio/index.d.ts
📚 Learning: 2025-12-04T12:12:49.547Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-12-04T12:12:49.547Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.{ts,js} : Import and use the Effect API (`S`, `createEffect`) from 'envio' package for external calls in HyperIndex handlers

Applied to files:

  • codegenerator/cli/npm/envio/index.d.ts
📚 Learning: 2025-12-04T12:13:23.246Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.246Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/src/**/*.ts : For Step 3 - Refactor file structure to mirror the original subgraph EXACTLY using the same filenames, create separate handler files by contract (e.g., contract1.ts, contract2.ts) instead of a single EventHandlers.ts file, and move handlers from EventHandlers.ts to contract-specific files

Applied to files:

  • codegenerator/cli/npm/envio/index.d.ts
📚 Learning: 2025-12-04T12:12:49.547Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-12-04T12:12:49.547Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : Use `string | undefined` for optional string fields in Envio types, not `string | null`, as generated types are strict about null vs undefined

Applied to files:

  • codegenerator/cli/npm/envio/index.d.ts
📚 Learning: 2025-12-04T12:13:23.245Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.245Z
Learning: AFTER EVERY SINGLE CODE CHANGE, you MUST test the indexer with `TUI_OFF=true pnpm dev` to catch runtime errors early, as TypeScript compilation only catches syntax and type errors while runtime errors (database issues, missing entities, logic errors) only appear when running the indexer

Applied to files:

  • codegenerator/cli/npm/envio/index.d.ts
📚 Learning: 2025-12-04T12:13:23.246Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.246Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/{src/handlers,src/**}/*.ts : ALL external calls (RPC calls, API calls, blockchain state fetching) MUST use the Effect API with `context.effect()` to enable preload optimization and parallelization. Create Effect API functions in `src/effects/` folder for better organization

Applied to files:

  • codegenerator/cli/npm/envio/index.d.ts
📚 Learning: 2025-12-04T12:13:23.246Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.246Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/src/effects/**/*.ts : When making external RPC calls, use viem with createPublicClient and batching for efficiency. Define Effect functions with proper schemas using the S module from 'envio': S.object(), S.string, S.number, etc.

Applied to files:

  • codegenerator/cli/npm/envio/index.d.ts
📚 Learning: 2025-11-19T05:36:33.975Z
Learnt from: nikbhintade
Repo: enviodev/hyperindex PR: 822
File: codegenerator/cli/templates/static/multichain_indexer_template/typescript/src/EventHandlers.ts:10-18
Timestamp: 2025-11-19T05:36:33.975Z
Learning: The multichain_indexer_template in codegenerator/cli/templates/static/ is designed to demonstrate multichain indexing features. It intentionally uses minimal event parameters (e.g., only capturing the `pool` address from Uniswap V3 PoolCreated events) to keep the focus on multichain functionality rather than comprehensive event indexing.

Applied to files:

  • codegenerator/cli/npm/envio/index.d.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build_and_test
🔇 Additional comments (4)
codegenerator/cli/npm/envio/index.d.ts (4)

18-19: LGTM! Standard TypeScript utility pattern.

The Prettify utility type is correctly implemented and will help improve IDE type hints for complex intersection types.


479-484: LGTM! Clean configuration type.

The TestIndexerChainConfig type is well-defined with clear start and end block boundaries for testing scenarios.


476-531: Well-structured test indexer type system.

The test indexer types integrate cleanly with the existing IndexerConfig infrastructure and follow established patterns. The conditional type logic for extracting chain IDs correctly handles all three ecosystems (EVM, Fuel, SVM).


517-520: No changes needed—runtime validation is already in place.

The type definition using Partial<Record<...>> allows type-level flexibility, but the implementation validates that exactly one chain must be configured. Empty chains or multiple chains will throw errors with clear messages: "createTestIndexer requires exactly one chain to be defined" and "createTestIndexer does not support processing multiple chains at once."

Likely an incorrect or invalid review comment.

@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/TestIndexer.res:
- Around line 63-67: The current match using operator with direct comparisons of
Js.Json.t (variables matches, operator, entityFieldValue, fieldValue) can yield
wrong results for objects/arrays or non-numeric values; implement a helper
(e.g., compareValues) that decodes Js.Json.t to primitives then compares: first
try decodeString on both and apply "="/">"/"<" as string compare, else try
decodeNumber on both and apply numeric compare, otherwise fall back to strict
equality only for identical JSON primitives or return false; replace the
existing switch that sets matches with a call to this compareValues helper so
field matching behaves deterministically for strings and numbers.
- Around line 232-244: The onExit handler currently calls
reject(Js.Exn.raiseError(...)) which throws synchronously and prevents the
promise rejection from running; change the handler in
NodeJs.WorkerThreads.onExit (the code block using state.processInProgress and
reject/resolve) to create and pass an Error-like value to reject (e.g.,
construct an Error with the message "Worker exited with code X") instead of
calling Js.Exn.raiseError so the reject callback actually receives the error
object.
- Around line 193-199: In the catch block around NodeJs.WorkerThreads.makeWorker
where you call reject(exn->Utils.magic), remove the subsequent raise(exn) (or
otherwise return/stop after calling reject) so the exception isn't re-thrown
synchronously; ensure the catch only rejects the promise with the error (using
reject) and does not propagate the exception by calling raise, referencing the
worker creation code that uses workerPath, workerData, and reject.

In @codegenerator/cli/npm/envio/src/TestIndexerProxyStorage.res:
- Around line 62-65: The match on msg.payload currently calls
Js.Exn.raiseError(message) inside reject which throws immediately; replace that
call so reject receives an Error/exception object instead of throwing — e.g., in
the Error({message}) branch call reject(Js.Exn.error(message)) or reject(new
Error(message)) rather than reject(Js.Exn.raiseError(message)) so the promise
rejection happens correctly.
🧹 Nitpick comments (1)
codegenerator/cli/npm/envio/src/TestIndexer.res (1)

119-127: Consider explicit error for invalid chain ID strings.

Line 121 silently defaults to 0 when Int.fromString fails. This could mask configuration errors where an invalid chain ID string is provided.

♻️ Proposed fix for explicit error handling
   let chains = chainKeys->Array.map(chainIdStr => {
-    let chainId = chainIdStr->Int.fromString->Option.getWithDefault(0)
+    let chainId = switch chainIdStr->Int.fromString {
+    | Some(id) => id
+    | None => Js.Exn.raiseError(`Invalid chain ID: ${chainIdStr}. Expected an integer.`)
+    }
     let chain = ChainMap.Chain.makeUnsafe(~chainId)
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bcae3c4 and d0171c6.

⛔ 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 (7)
  • 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/src/hbs_templating/codegen_templates.rs
  • codegenerator/cli/templates/static/codegen/src/TestIndexerWorker.res
  • scenarios/test_codegen/src/handlers/EventHandlers.res
🚧 Files skipped from review as they are similar to previous changes (1)
  • codegenerator/cli/npm/envio/src/bindings/NodeJs.res
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{res,resi}

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

**/*.{res,resi}: Always use ReScript 11 documentation
Never suggest ReasonML syntax
Never use [| item |] to create an array. Use [ item ] instead
Must always use = for setting value to a field. Use := only for ref values created 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
  • scenarios/test_codegen/src/handlers/EventHandlers.res
  • codegenerator/cli/npm/envio/src/TestIndexer.res
  • codegenerator/cli/templates/static/codegen/src/TestIndexerWorker.res
  • codegenerator/cli/npm/envio/src/TestIndexerProxyStorage.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
  • scenarios/test_codegen/src/handlers/EventHandlers.res
  • codegenerator/cli/npm/envio/src/TestIndexer.res
  • codegenerator/cli/templates/static/codegen/src/TestIndexerWorker.res
  • codegenerator/cli/npm/envio/src/TestIndexerProxyStorage.res
codegenerator/cli/templates/static/**/*.res

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

Static ReScript template files live under codegenerator/cli/templates/static/ and are copied verbatim

Files:

  • codegenerator/cli/templates/static/codegen/src/TestIndexerWorker.res
🧠 Learnings (15)
📓 Common learnings
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.245Z
Learning: AFTER EVERY SINGLE CODE CHANGE, you MUST test the indexer with `TUI_OFF=true pnpm dev` to catch runtime errors early, as TypeScript compilation only catches syntax and type errors while runtime errors (database issues, missing entities, logic errors) only appear when running the indexer
📚 Learning: 2025-12-04T12:13:23.246Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.246Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : For Step 6 - Final Migration Verification: Go through each handler and helper function systematically, comparing the logic line-by-line to the original subgraph implementation. Iterate multiple times until logic is completely correct, as first pass often misses subtle differences

Applied to files:

  • codegenerator/cli/npm/envio/src/Main.res
📚 Learning: 2026-01-05T11:20:07.222Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/navigation.mdc:0-0
Timestamp: 2026-01-05T11:20:07.222Z
Learning: Entry module for generated runtime is `Index.res` which starts HTTP server, loads `Config.res`, calls `RegisterHandlers.res`, spins up `GlobalStateManager.res`

Applied to files:

  • codegenerator/cli/npm/envio/src/Main.res
📚 Learning: 2025-12-04T12:12:49.547Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-12-04T12:12:49.547Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.{ts,js} : In Envio HyperIndex, use `entity_id` fields (e.g., `token_id: string`) instead of direct object references for entity relationships

Applied to files:

  • scenarios/test_codegen/src/handlers/EventHandlers.res
  • 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:

  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
📚 Learning: 2025-12-04T12:13:23.246Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.246Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : Import entity types from `generated/src/db/Entities.gen` for type annotations (e.g., `Pair_t`, `Token_t`), NOT from `generated` which exports contract handlers. Use the correct entity type imports to prevent TypeScript errors like 'refers to a value, but is being used as a type'

Applied to files:

  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
📚 Learning: 2025-12-04T12:13:23.246Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.246Z
Learning: Applies to codegenerator/cli/templates/static/shared/{**/*.ts,**/schema.graphql} : Ensure database schema compatibility: verify that the types you're setting in code match the schema entity property types exactly. Compare with schema.graphql - for example, `Int!` in schema requires `number` in code, `BigInt!` requires `BigInt`, `BigDecimal!` requires `BigDecimal`

Applied to files:

  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
📚 Learning: 2025-12-04T12:12:49.547Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-12-04T12:12:49.547Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.graphql : Use `entity_id` fields for relationships in GraphQL schemas (e.g., `user_id: String!`) instead of direct entity references or entity arrays

Applied to files:

  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
📚 Learning: 2025-12-04T12:13:23.246Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.246Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : Always verify entity type field names match exactly with the generated entity types. For example, use `token0_id` not `token0`, and `transaction_id` not `transaction`. Run `pnpm tsc --noEmit` to catch type mismatches

Applied to files:

  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
📚 Learning: 2025-12-04T12:13:23.246Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.246Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.ts : When accessing entity fields that represent relationships, use the `_id` suffix convention. For example, use `token0_id` not `token0` when storing relationships in entity types

Applied to files:

  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
📚 Learning: 2025-12-04T12:12:49.547Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-12-04T12:12:49.547Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.graphql : Do not add the entity decorator to GraphQL schema types in HyperIndex

Applied to files:

  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
📚 Learning: 2025-12-04T12:12:49.547Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-12-04T12:12:49.547Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.{ts,js} : When updating existing entities in HyperIndex handlers, always use the spread operator for immutability since returned objects are read-only

Applied to files:

  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
📚 Learning: 2025-12-04T12:12:49.547Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/hyperindex.mdc:0-0
Timestamp: 2025-12-04T12:12:49.547Z
Learning: Applies to codegenerator/cli/templates/static/shared/**/*.graphql : Avoid schema fields like dailyVolume or other time-series fields that aggregate over time in HyperIndex schemas, as these are typically inaccurate

Applied to files:

  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
📚 Learning: 2025-11-19T05:36:33.975Z
Learnt from: nikbhintade
Repo: enviodev/hyperindex PR: 822
File: codegenerator/cli/templates/static/multichain_indexer_template/typescript/src/EventHandlers.ts:10-18
Timestamp: 2025-11-19T05:36:33.975Z
Learning: The multichain_indexer_template in codegenerator/cli/templates/static/ is designed to demonstrate multichain indexing features. It intentionally uses minimal event parameters (e.g., only capturing the `pool` address from Uniswap V3 PoolCreated events) to keep the focus on multichain functionality rather than comprehensive event indexing.

Applied to files:

  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
  • codegenerator/cli/templates/static/codegen/src/TestIndexerWorker.res
📚 Learning: 2025-12-04T12:13:23.245Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-12-04T12:13:23.245Z
Learning: AFTER EVERY SINGLE CODE CHANGE, you MUST test the indexer with `TUI_OFF=true pnpm dev` to catch runtime errors early, as TypeScript compilation only catches syntax and type errors while runtime errors (database issues, missing entities, logic errors) only appear when running the indexer

Applied to files:

  • codegenerator/cli/npm/envio/src/TestIndexer.res
  • codegenerator/cli/templates/static/codegen/src/TestIndexerWorker.res
🧬 Code graph analysis (1)
codegenerator/cli/src/hbs_templating/codegen_templates.rs (1)
codegenerator/cli/src/type_schema.rs (5)
  • to_valid_rescript_name (348-364)
  • to_rescript_schema (28-66)
  • to_rescript_schema (158-181)
  • to_rescript_schema (240-288)
  • to_rescript_schema (551-608)
🔇 Additional comments (10)
codegenerator/cli/templates/static/codegen/src/TestIndexerWorker.res (1)

1-13: LGTM! Clean worker entry point.

The worker initialization correctly wires all dependencies (handlers, config, persistence) using a factory pattern that enables storage injection for the test indexer. The labeled arguments make the API clear and self-documenting.

codegenerator/cli/src/hbs_templating/codegen_templates.rs (3)

1415-1443: Test indexer code generation looks correct.

The test indexer scaffolding properly generates:

  • Chain configuration types with optional chain fields
  • Worker path construction using Node.js path utilities for ESM compatibility
  • Factory function wiring config, worker path, and entity configs

The use of NodeJs.Path.join and NodeJs.Url.fileURLToPath ensures correct path resolution in ESM modules.


30-30: Type import updated correctly.

The import now uses the generalized TypeIdent, TypeExpr, RecordField, and SchemaMode types from type_schema, replacing the previous Rescript-specific type names.


692-705: No issues found with Fuel ABI type declaration generation.

The to_type_decl_multi() method and to_rescript_schema(&SchemaMode::ForDb) are correctly implemented and well-tested. The error handling with .context() appropriately wraps the Result type, and comprehensive unit tests in type_schema.rs validate schema generation across all supported types (primitives, BigInt, BigDecimal, Address, Arrays, Tuples, Unions, and Objects). The code integration at lines 692-705 is correct.

scenarios/test_codegen/src/handlers/EventHandlers.res (1)

28-35: LGTM! Entity type annotation updated correctly.

The change from Types.gravatar to Entities.Gravatar.t follows the proper convention for entity type references. The gravatarObject now correctly includes all required fields (imageUrl, updatesCount, size) matching the entity schema.

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

245-258: LGTM! Test mode integration properly implemented.

The ~isTest parameter correctly:

  • Disables TUI in test mode
  • Sets isDevelopmentMode to false during tests to prevent exposing debug endpoints
  • Gates server startup to avoid port conflicts during testing

This clean separation allows the test indexer to reuse the main processing logic without side effects.


271-323: Server startup correctly gated by test mode.

When isTest is true, the HTTP server is not started, which:

  • Avoids port binding conflicts when running multiple tests
  • Reduces test overhead
  • Prevents accidental exposure of debug endpoints during testing

The getState callback and chain data construction are only evaluated when the server is actually needed.

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

84-117: LGTM! Storage proxy methods correctly delegate to worker.

The loadByIdsOrThrow and loadByFieldOrThrow methods properly:

  • Send typed RPC requests via sendRequest
  • Parse responses using the provided schemas
  • Handle the async nature of worker communication

The setOrThrow no-op is acceptable since it's documented as unused.


138-152: Clear error messages for unsupported rollback operations.

The rollback-related methods provide explicit error messages directing users to disable rollbackOnReorg in config. This is appropriate since the in-memory test storage doesn't support rollback semantics.

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

256-283: LGTM! Worker initialization with proper error handling.

The initTestWorker function correctly:

  • Validates it's running in a worker thread
  • Retrieves parentPort and workerData with proper null checks
  • Creates the proxy storage and persistence layer
  • Calls Main.start with ~isTest=true to skip server startup
  • Handles missing worker data by logging and exiting with failure code

Comment on lines +63 to +67
let matches = switch operator {
| #"=" => entityFieldValue == fieldValue
| #">" => entityFieldValue > fieldValue
| #"<" => entityFieldValue < fieldValue
}

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

Verify JSON comparison semantics for field matching.

The comparison operators (==, >, <) on Js.Json.t values may not behave as expected for complex types. JSON objects compared with == use reference equality in JavaScript, and > / < operators on non-numeric JSON values may produce unexpected results.

Consider parsing field values to their expected types before comparison, or documenting that only primitive field types (strings, numbers) are supported for field queries.

💡 Suggested approach

For reliable comparisons, consider converting to primitive types:

let compareValues = (a: Js.Json.t, b: Js.Json.t, operator: Persistence.operator): bool => {
  // For strings
  switch (a->Js.Json.decodeString, b->Js.Json.decodeString) {
  | (Some(aStr), Some(bStr)) =>
    switch operator {
    | #"=" => aStr == bStr
    | #">" => aStr > bStr
    | #"<" => aStr < bStr
    }
  // For numbers
  | _ =>
    switch (a->Js.Json.decodeNumber, b->Js.Json.decodeNumber) {
    | (Some(aNum), Some(bNum)) =>
      switch operator {
      | #"=" => aNum == bNum
      | #">" => aNum > bNum
      | #"<" => aNum < bNum
      }
    | _ => a == b // Fallback for other types
    }
  }
}
🤖 Prompt for AI Agents
In @codegenerator/cli/npm/envio/src/TestIndexer.res around lines 63 - 67, The
current match using operator with direct comparisons of Js.Json.t (variables
matches, operator, entityFieldValue, fieldValue) can yield wrong results for
objects/arrays or non-numeric values; implement a helper (e.g., compareValues)
that decodes Js.Json.t to primitives then compares: first try decodeString on
both and apply "="/">"/"<" as string compare, else try decodeNumber on both and
apply numeric compare, otherwise fall back to strict equality only for identical
JSON primitives or return false; replace the existing switch that sets matches
with a call to this compareValues helper so field matching behaves
deterministically for strings and numbers.

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

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

Redundant raise after reject in catch block.

When the worker creation fails, both reject(exn) and raise(exn) are called. The raise will propagate the exception synchronously, potentially bypassing the promise rejection flow and causing unhandled exceptions.

🐛 Proposed fix
          let worker = try {
            NodeJs.WorkerThreads.makeWorker(workerPath, {workerData: workerData})
          } catch {
          | exn =>
            reject(exn->Utils.magic)
-           raise(exn)
+           // Return early - the promise will be rejected
+           // Use a sentinel that won't be used since we rejected
+           Obj.magic()
          }

Or restructure to avoid the issue:

-         let worker = try {
-           NodeJs.WorkerThreads.makeWorker(workerPath, {workerData: workerData})
-         } catch {
-         | exn =>
-           reject(exn->Utils.magic)
-           raise(exn)
-         }
+         let workerResult = try {
+           Ok(NodeJs.WorkerThreads.makeWorker(workerPath, {workerData: workerData}))
+         } catch {
+         | exn => Error(exn)
+         }
+         
+         switch workerResult {
+         | Error(exn) => reject(exn->Utils.magic)
+         | Ok(worker) =>
+           // ... rest of the worker setup
+         }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In @codegenerator/cli/npm/envio/src/TestIndexer.res around lines 193 - 199, In
the catch block around NodeJs.WorkerThreads.makeWorker where you call
reject(exn->Utils.magic), remove the subsequent raise(exn) (or otherwise
return/stop after calling reject) so the exception isn't re-thrown
synchronously; ensure the catch only rejects the promise with the error (using
reject) and does not propagate the exception by calling raise, referencing the
worker creation code that uses workerPath, workerData, and reject.

Comment on lines +232 to +244
worker->NodeJs.WorkerThreads.onExit(code => {
state.processInProgress = false
if code !== 0 {
reject(Js.Exn.raiseError(`Worker exited with code ${code->Int.toString}`))
} else {
// Worker exited successfully (SuccessExit was dispatched in GlobalState)
let changes = store->extractChanges
resolve({
checkpoints: [],
changes,
})
}
})

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

Bug: Js.Exn.raiseError in onExit throws instead of rejecting.

Same issue as in TestIndexerProxyStorage.res - Js.Exn.raiseError throws synchronously, so the reject callback is never invoked.

🐛 Proposed fix
          worker->NodeJs.WorkerThreads.onExit(code => {
            state.processInProgress = false
            if code !== 0 {
-             reject(Js.Exn.raiseError(`Worker exited with code ${code->Int.toString}`))
+             let exn: exn = %raw(`new Error("Worker exited with code " + code)`)
+             reject(exn)
            } else {
              // Worker exited successfully (SuccessExit was dispatched in GlobalState)
              let changes = store->extractChanges
              resolve({
                checkpoints: [],
                changes,
              })
            }
          })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
worker->NodeJs.WorkerThreads.onExit(code => {
state.processInProgress = false
if code !== 0 {
reject(Js.Exn.raiseError(`Worker exited with code ${code->Int.toString}`))
} else {
// Worker exited successfully (SuccessExit was dispatched in GlobalState)
let changes = store->extractChanges
resolve({
checkpoints: [],
changes,
})
}
})
worker->NodeJs.WorkerThreads.onExit(code => {
state.processInProgress = false
if code !== 0 {
reject(Js.Exn.error(`Worker exited with code ${code->Int.toString}`))
} else {
// Worker exited successfully (SuccessExit was dispatched in GlobalState)
let changes = store->extractChanges
resolve({
checkpoints: [],
changes,
})
}
})
🤖 Prompt for AI Agents
In @codegenerator/cli/npm/envio/src/TestIndexer.res around lines 232 - 244, The
onExit handler currently calls reject(Js.Exn.raiseError(...)) which throws
synchronously and prevents the promise rejection from running; change the
handler in NodeJs.WorkerThreads.onExit (the code block using
state.processInProgress and reject/resolve) to create and pass an Error-like
value to reject (e.g., construct an Error with the message "Worker exited with
code X") instead of calling Js.Exn.raiseError so the reject callback actually
receives the error object.

Comment on lines +62 to +65
switch msg.payload {
| Response({data}) => resolve(data)
| Error({message}) => reject(Js.Exn.raiseError(message))
}

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

Bug: Js.Exn.raiseError throws immediately, preventing reject from being called.

Js.Exn.raiseError(message) will throw synchronously, so the reject callback is never invoked. This means error handling in the promise chain won't work correctly.

🐛 Proposed fix
     switch msg.payload {
     | Response({data}) => resolve(data)
-    | Error({message}) => reject(Js.Exn.raiseError(message))
+    | Error({message}) => reject(Js.Exn.anyToExnInternal({"message": message}->Obj.magic))
     }

Alternatively, create the exception without throwing:

     switch msg.payload {
     | Response({data}) => resolve(data)
-    | Error({message}) => reject(Js.Exn.raiseError(message))
+    | Error({message}) => {
+        let exn: exn = %raw(`new Error(message)`)
+        reject(exn)
+      }
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
switch msg.payload {
| Response({data}) => resolve(data)
| Error({message}) => reject(Js.Exn.raiseError(message))
}
switch msg.payload {
| Response({data}) => resolve(data)
| Error({message}) => reject(Js.Exn.error(message))
}
🤖 Prompt for AI Agents
In @codegenerator/cli/npm/envio/src/TestIndexerProxyStorage.res around lines 62
- 65, The match on msg.payload currently calls Js.Exn.raiseError(message) inside
reject which throws immediately; replace that call so reject receives an
Error/exception object instead of throwing — e.g., in the Error({message})
branch call reject(Js.Exn.error(message)) or reject(new Error(message)) rather
than reject(Js.Exn.raiseError(message)) so the promise rejection happens
correctly.

@DZakh

DZakh commented Jan 13, 2026

Copy link
Copy Markdown
Member Author

Closed in favor of #889

@DZakh DZakh closed this Jan 13, 2026
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.

1 participant