Skip to content

feat(ensapi): add forward and reverse resolution to Omnigraph#1974

Merged
sevenzing merged 38 commits into
mainfrom
ll/omnigraph-resolution-api
May 30, 2026
Merged

feat(ensapi): add forward and reverse resolution to Omnigraph#1974
sevenzing merged 38 commits into
mainfrom
ll/omnigraph-resolution-api

Conversation

@sevenzing
Copy link
Copy Markdown
Member

@sevenzing sevenzing commented Apr 21, 2026

Summary

  • Add Domain.records to Omnigraph for live ENS forward resolution (texts, addresses, contenthash, pubkey, ABI, interfaces, etc.), driven by the GraphQL field selection.
  • Add Account.primaryNames for ENSIP-19 multichain primary name resolution, with optional chainIds filtering.
  • Add example queries for the new fields

Why

Omnigraph previously exposed only indexed ENS state. Resolution is important thing for ENS developers so this PR adds resolution alongside that data so GraphQL clients can fetch live records and primary names in the same query shape as the rest of the API! It's cool, is it?


Testing

  • Unit tests: build-records-selection.test.ts (GraphQL selection → ResolverRecordsSelection), validate-primary-names-chain-ids.test.ts.
  • Integration tests: domain.integration.test.ts (Domain.records for address/text and all record types), account.integration.test.ts (Account.primaryNames per-chain, all chains, and invalid chain id rejection).
  • SDK example queries added for domain-records and account-primary-names.
  • Run ensnode against devnet and tested queries in ensadmin locally 👍

Notes for Reviewer (Optional)

  • Record types to resolve are inferred from the GraphQL selection set on Domain.records (e.g. records { texts(keys: [...]) addresses(coinTypes: [...]) })
  • Both resolution fields accept disableAcceleration; acceleration is gated by request context (canAccelerate). Since we want to enable acceleration by default decided to rename old accelecate param to disableAcceleration
  • Please @shrugs take a closer look at apps/ensapi/src/omnigraph-api/lib/build-records-selection.ts. This is my first dive into graphql query world, still not an expert in this.

Pre-Review Checklist (Blocking)

  • This PR does not introduce significant changes and is low-risk to review quickly.
  • Relevant changesets are included (or are not required)

@sevenzing sevenzing requested a review from a team as a code owner April 21, 2026 17:03
@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Apr 21, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
admin.ensnode.io Ready Ready Preview, Comment May 30, 2026 2:14pm
enskit-react-example.ensnode.io Ready Ready Preview, Comment May 30, 2026 2:14pm
ensnode.io Ready Ready Preview, Comment May 30, 2026 2:14pm
ensrainbow.io Ready Ready Preview, Comment May 30, 2026 2:14pm

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 21, 2026

🦋 Changeset detected

Latest commit: 514e12b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 24 packages
Name Type
ensapi Patch
ensindexer Patch
ensadmin Patch
ensrainbow Patch
fallback-ensapi Patch
enssdk Patch
enscli Patch
enskit Patch
ensskills Patch
@ensnode/datasources Patch
@ensnode/ensrainbow-sdk Patch
@ensnode/ensdb-sdk Patch
@ensnode/ensnode-sdk Patch
@ensnode/integration-test-env Patch
@ensnode/ponder-sdk Patch
@ensnode/ponder-subgraph Patch
@ensnode/shared-configs Patch
@docs/ensnode Patch
@docs/ensrainbow Patch
@namehash/ens-referrals Patch
@namehash/namehash-ui Patch
@ensnode/ensindexer-perf-testing Patch
@ensnode/enskit-react-example Patch
@ensnode/enssdk-example Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@sevenzing sevenzing marked this pull request as draft April 21, 2026 17:03
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 21, 2026

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR adds two new ENS resolution GraphQL fields to the Omnigraph API: Domain.records for forward resolution of ENS record data (text, addresses, ABI, etc.) and Account.primaryNames for ENSIP-19 multichain primary name lookups. Both support optional acceleration controls. The changes include GraphQL scalar/type definitions, records selection parsing from GraphQL query info, resolver implementations with tracing, integration tests, context/middleware wiring for acceleration eligibility, and cache exchange configuration.

Changes

Omnigraph Resolution API Integration

Layer / File(s) Summary
InterfaceId scalar and builder registration
apps/ensapi/src/omnigraph-api/schema/scalars.ts, apps/ensapi/src/omnigraph-api/builder.ts, packages/enssdk/src/omnigraph/graphql.ts
New InterfaceId GraphQL scalar with ERC-165 selector validation, integrated into Pothos builder and enssdk type mappings.
Context factory and runtime middleware setup
apps/ensapi/src/omnigraph-api/context.ts, apps/ensapi/src/omnigraph-api/yoga.ts, apps/ensapi/src/handlers/api/omnigraph/omnigraph-api.ts, apps/ensapi/src/omnigraph-api/lib/find-domains/find-domains-resolver.ts
Refactor per-request context factory to receive serverContext with canAccelerate flag; wire realtime and acceleration eligibility middlewares into handler and Yoga; update resolvers to use shared Context type.
Resolved records GraphQL object refs
apps/ensapi/src/omnigraph-api/schema/resolution.ts
Define GraphQL types for PrimaryNameByChain and resolved ENS records: ResolvedTextRecord, ResolvedAddressRecord, ResolvedPubkeyRecord, ResolvedAbiRecord, ResolvedInterfaceRecord, and the aggregate ResolvedRecords with list fields for parametric selection.
Records selection configuration and parsing
apps/ensapi/src/omnigraph-api/lib/resolution/records-selection-config.ts, apps/ensapi/src/omnigraph-api/lib/resolution/build-records-selection.ts, apps/ensapi/src/omnigraph-api/lib/resolution/build-records-selection.test.ts
Define config for mapping GraphQL ResolvedRecords fields to ResolverRecordsSelection keys; implement buildRecordsSelectionFromResolveInfo to extract and validate selections from GraphQL query info; add comprehensive test coverage.
Domain.records resolver and integration tests
apps/ensapi/src/omnigraph-api/schema/domain.ts, apps/ensapi/src/omnigraph-api/schema.ts, apps/ensapi/src/omnigraph-api/schema/domain.integration.test.ts
Add Domain.records GraphQL field to resolve ENS records (text, address, ABI, etc.) via forward resolution under tracing with acceleration controls; include integration tests for address/text resolution.
Account.primaryNames resolver and integration tests
apps/ensapi/src/omnigraph-api/schema/account.ts, apps/ensapi/src/omnigraph-api/schema/account.integration.test.ts
Add Account.primaryNames GraphQL field with optional chainIds and disableAcceleration arguments; resolve ENSIP-19 primary names under tracing; include integration tests for single/multiple chain queries and validation errors.
Cache configuration and changeset
packages/enskit/src/react/omnigraph/_lib/cache-exchange.ts, .changeset/omnigraph-resolution-api.md
Mark new omnigraph record/lookup entity types as embedded (non-keyable) in graphcache; document patch release with new resolution fields.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

The PR spans multiple layers of the Omnigraph API with new GraphQL types, selection parsing logic, middleware wiring, and two new resolver implementations. The selection parsing and resolver logic are dense, and the changes require understanding the acceleration control flow and context propagation across Hono→Yoga→resolver boundaries.

Possibly related issues

  • namehash/ensnode#1802: Directly addresses the same feature—adding Domain.records and Account.primaryNames with selection-driven record resolution and acceleration controls.

Possibly related PRs

  • namehash/ensnode#2163: Also updates packages/enskit/src/react/omnigraph/_lib/cache-exchange.ts to mark resolved entity types as embedded in graphcache.
  • namehash/ensnode#1967: The new Domain.records resolver wires into the expanded ResolverRecordsResponseBase forward-resolution model introduced in that PR.
  • namehash/ensnode#1867: Adds React URQL cache-exchange handling for the same new resolved record types defined in this PR.

Poem

🐰 Fresh records bloom in the Omnigraph today,
Domains and accounts find their data way,
Selection guides us through the fields we crave,
While canAccelerate helps us behave,
A schema that dances, both fast and complete!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 38.89% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description check ✅ Passed The description follows the template structure with all required sections completed: Summary (3 bullets with specific features), Why (context and motivation), Testing (detailed unit/integration tests and manual testing), and Notes for Reviewer (important implementation details). Pre-Review Checklist is also marked complete.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The PR title clearly and concisely summarizes the main changes: adding forward resolution (Domain.records) and reverse resolution (Account.primaryNames) capabilities to the Omnigraph API.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ll/omnigraph-resolution-api

Warning

Review ran into problems

🔥 Problems

Stopped waiting for pipeline failures after 30000ms. One of your pipelines takes longer than our 30000ms fetch window to run, so review may not consider pipeline-failure results for inline comments if any failures occurred after the fetch window. Increase the timeout if you want to wait longer or run a @coderabbit review after the pipeline has finished.


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.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 21, 2026

Greptile Summary

This PR adds live ENS forward resolution (Domain.resolve.records) and ENSIP-19 primary name resolution (Account.resolve.primaryName/primaryNames) to the Omnigraph GraphQL API. Record types to resolve are derived from the GraphQL selection set at runtime via buildRecordsSelectionFromResolveContainerInfo, which inspects the query AST to build a flat ResolverRecordsSelection for the underlying resolution layer.

  • Domain.resolve (new ForwardResolve type) performs forward resolution driven by the records { ... } sub-selection; returns null for non-canonical or non-normalised names and skips resolution when no records are selected.
  • Account.resolve (new ReverseResolve type) pre-fetches all coin types needed by primaryName/primaryNames via buildAccountPrimaryNamesSelection, returns an empty model when no primary-name fields are selected, and uses a new resolvePrimaryNamesByCoinTypes function that resolves by coin type directly (rather than going through chain ID).
  • CanonicalNameRef was refactored from holding a full Domain to an InterpretedName string; resolveReverse was split into a coin-type variant (resolveReverse) and a chain-ID shim (resolveReverseByChainId) for the REST API boundary.

Confidence Score: 5/5

Safe to merge; all previously-flagged bugs are addressed and the new resolution layer handles edge cases (non-canonical names, empty selections, unsupported coin types) correctly.

The three architectural correctness concerns from earlier rounds — encoded-label names throwing in the forward resolver, empty records { __typename } propagating null to Domain, and Account.resolve throwing when no primary-name fields are selected — are all fixed in this revision. The selection-introspection layer correctly merges fragments, aliases, and variables. The pre-fetch/lookup invariant in ReverseResolve.primaryName is sound, and unsupported coin types are included in the records map (with name: null) so downstream resolvers never hit the defensive throw in normal operation.

apps/ensapi/src/omnigraph-api/schema/reverse-resolve.ts — the defensive throws in primaryName and primaryNames use bare Error rather than GraphQLError; worth a quick look before the next release cycle.

Important Files Changed

Filename Overview
apps/ensapi/src/omnigraph-api/schema/domain.ts Adds Domain.resolve (ForwardResolve, nullable:false) with isNormalizedName guard before calling resolveForward; returns safe null model for non-canonical, non-normalised, or selection-less queries.
apps/ensapi/src/omnigraph-api/schema/account.ts Adds Account.resolve (ReverseResolve, nullable:false); returns empty model when no primaryName/primaryNames fields are selected, preventing null-propagation to the parent Account.
apps/ensapi/src/omnigraph-api/lib/resolution/records-selection.ts GraphQL AST introspection layer that translates a records sub-selection into a flat ResolverRecordsSelection; handles fragments, aliases, merging across multiple field nodes, and the __typename-only edge case (returns null instead of throwing).
apps/ensapi/src/omnigraph-api/lib/resolution/account-primary-names-selection.ts Derives the union of all coin types needed by primaryName/primaryNames from the query AST; handles aliases, fragments, and variable resolution via getArgumentValues.
apps/ensapi/src/omnigraph-api/schema/reverse-resolve.ts ReverseResolve type implementing primaryName/primaryNames resolvers; both fields are nullable:false and throw when a record is missing from the pre-fetched set — a defensive invariant that propagates through the non-nullable Account.resolve chain if it ever fires.
apps/ensapi/src/omnigraph-api/schema/records.ts ResolvedRecords GraphQL type with texts, addresses, abi, interfaces, contenthash, pubkey, dnszonehash, version fields; abi alias merging and per-alias contentTypeMask filtering is handled correctly.
apps/ensapi/src/omnigraph-api/schema/primary-name-record.ts PrimaryNameRecord type with nested ForwardResolve; uses isNormalizedName guard and returns safe null model when the primary name is absent or not normalised.
apps/ensapi/src/lib/resolution/reverse-resolution.ts resolveReverse refactored to accept coinType directly; thin resolveReverseByChainId shim added for the REST API boundary — clean separation of concerns.
apps/ensapi/src/omnigraph-api/lib/resolution/resolve-primary-name-records.ts Resolves primary names for a list of coin types; unsupported coin types are included in the result as name:null records rather than being dropped, so downstream resolvers always find their record.
apps/ensapi/src/omnigraph-api/schema/canonical-name.ts CanonicalNameRef refactored from Domain→InterpretedName parent; invariant guard for null canonicalName moved to DomainCanonical.name resolver in domain-canonical.ts.

Sequence Diagram

sequenceDiagram
    participant Client as GraphQL Client
    participant DR as Domain.resolve resolver
    participant BSI as buildRecordsSelection<br/>FromResolveContainerInfo
    participant RF as resolveForward
    participant AR as Account.resolve resolver
    participant BAP as buildAccountPrimaryNames<br/>Selection
    participant RPNR as resolvePrimaryNameRecords
    participant RR as resolveReverse (per coinType)

    Client->>DR: "query { domain { resolve { records { texts addresses } } } }"
    DR->>BSI: info (GraphQL AST)
    BSI-->>DR: ResolverRecordsSelection
    DR->>RF: resolveForward(name, selection, opts)
    RF-->>DR: "{trace, result}"
    DR-->>Client: "ForwardResolve {records, acceleration, trace}"

    Client->>AR: "query { account { resolve { primaryNames(where:{...}) { name } } } }"
    AR->>BAP: info (GraphQL AST)
    BAP-->>AR: coinTypes[] (merged across all primaryName/primaryNames args)
    AR->>RPNR: resolvePrimaryNameRecords(address, coinTypes, opts)
    RPNR->>RR: resolveReverse(address, coinType1, opts)
    RPNR->>RR: resolveReverse(address, coinType2, opts)
    RR-->>RPNR: ReverseResolutionResult (parallel)
    RPNR-->>AR: "{trace, records: PrimaryNameRecordModel[]}"
    AR-->>Client: "ReverseResolve {primaryNames, acceleration, trace}"
Loading

Reviews (23): Last reviewed commit: "fix tests" | Re-trigger Greptile

Comment thread apps/ensapi/src/omnigraph-api/schema/domain.ts Outdated
Comment thread apps/ensapi/src/omnigraph-api/schema/resolution.ts Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/ensapi/src/omnigraph-api/schema/domain.ts`:
- Around line 224-249: Domain.records currently lacks an accelerate arg and
always calls resolveForward with accelerate: false; add a GraphQL arg
"accelerate" to the Domain.records field (the field defined at records: t.field)
and forward its value along with context.canAccelerate into resolveForward
(i.e., call resolveForward(name, {...}, { accelerate: args.accelerate,
canAccelerate: context.canAccelerate })). Also wire up the acceleration
middleware chain to the omnigraph-api router by applying
makeIsRealtimeMiddleware, indexingStatusMiddleware and canAccelerateMiddleware
(same order used in resolution-api) and update the omnigraph-api context factory
to accept the initial context param that contains canAccelerate from the
middleware so context.canAccelerate is available in the resolver; keep
getDomainInterpretedName usage unchanged.

In `@apps/ensapi/src/omnigraph-api/schema/resolution.ts`:
- Around line 16-18: Update the description string for the texts field in
resolution.ts to fix the malformed example; locate the texts: t.stringList({ ...
}) declaration and replace the example snippet "Text record keys to resolve
(e.g. `avatar`, `description`, `com.)." with a correctly punctuated example such
as "Text record keys to resolve (e.g. `avatar`, `description`, `com`)." ensuring
matching backticks and proper parentheses/period placement.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 909769d3-67ea-4cf4-873d-e0d220e4bdd9

📥 Commits

Reviewing files that changed from the base of the PR and between d9ab6b0 and eae25f6.

⛔ Files ignored due to path filters (1)
  • packages/enssdk/src/omnigraph/generated/schema.graphql is excluded by !**/generated/**
📒 Files selected for processing (4)
  • apps/ensapi/src/omnigraph-api/schema.ts
  • apps/ensapi/src/omnigraph-api/schema/domain.integration.test.ts
  • apps/ensapi/src/omnigraph-api/schema/domain.ts
  • apps/ensapi/src/omnigraph-api/schema/resolution.ts

Comment thread apps/ensapi/src/omnigraph-api/schema/domain.ts Outdated
Comment thread apps/ensapi/src/omnigraph-api/schema/resolution.ts Outdated
Copy link
Copy Markdown
Member

@shrugs shrugs left a comment

Choose a reason for hiding this comment

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

So i mentioned this in the original issue, which is that i'm not sure we want to allow people to query the trace and other meta information, like whether it was accelerated or not via the graphql api because i'm not convinced the ergonomics of it makes sense. but if you find a format that feels good, we can totally do so. For example, we could make the signature

query GetRecords {
  domain(by: { name: "eth" }) {
    resolve([accelerate: True]) {
      records { # equivalent to a ResolverRecordsSelection
        name
        texts(keys: ["description"]) { key value }
        addresses(coinType: [60]) { coinType address }
      }
      acceleration { requested attempted }
      trace
    }
  }
}

query GetPrimaryNames {
  account(by: { address: "0xabcd" }) {
    resolve(accelerate: False) {
      primaryNames(coinTypes: [60]) { coinType name }
      acceleration { requested attempted }
      trace
    }
  }
}

then that feels good; let's do that! then the pattern is clear; Domain.resolve.records and Account.resolve.primaryNames — feels good to me!


Note that within enskit, we need to update the cache client to mark these fields as EMBEDDED_DATA because they don't have a global key. Also, feel free to update the example app to render these records. So maybe add a new component that fetches a name's records by Domain.id or (name from the params, whatever) and then plug it into the name page.


Overall, this is definitely the correct direction and the data loader usage is correct. Let's move that helper into its own library.


to access the pothos context type, let's

  1. define a type Context = ReturnType<typeof createContext> in apps/ensapi/src/omnigraph-api/context.ts
  2. use that everywhere we currently use context: ReturnType<typeof createContext>
  3. make sure the helper you extracted here uses said type as well.

no need to alias it to graphqlContext; within the omnigraph graphql server module, "context" is always the graphql context

Comment thread apps/ensapi/src/omnigraph-api/schema/domain.integration.test.ts Outdated
Comment thread apps/ensapi/src/omnigraph-api/schema/domain.integration.test.ts Outdated
Comment thread apps/ensapi/src/omnigraph-api/schema/domain.integration.test.ts Outdated
Comment thread apps/ensapi/src/omnigraph-api/schema/domain.ts Outdated
Comment thread apps/ensapi/src/omnigraph-api/schema/resolution.ts Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
apps/ensapi/src/omnigraph-api/schema/domain.ts (1)

185-201: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Domain.records still ignores the acceleration contract.

Line 197 hardcodes accelerate: false, canAccelerate: false, so clients cannot use the documented default accelerated path (accelerate default true) and context capability is bypassed.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/ensapi/src/omnigraph-api/schema/domain.ts` around lines 185 - 201, The
Domain.records resolver currently hardcodes acceleration by calling
resolveForward(name, selection, { accelerate: false, canAccelerate: false }),
which prevents using the default accelerated path and ignores context
capabilities; update the resolve function in the records field to stop forcing
those flags — either omit the options so resolveForward uses its defaults
(allowing accelerate default true) or explicitly pass accelerate from args and
canAccelerate from the GraphQL context (e.g., use _args.accelerate ?? true and
_context.canAccelerate) when invoking resolveForward so acceleration behavior
respects client requests and context capability checks.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/ensapi/src/omnigraph-api/lib/build-records-selection.ts`:
- Around line 45-48: The code currently uses only the first
GraphQLResolveInfo.fieldNodes element (fieldNode) when building the selection
and thus drops merged selections; update the build logic in
build-records-selection (where fieldNode is referenced) to merge all
info.fieldNodes by iterating over info.fieldNodes, collecting each
node.selectionSet?.selections and concatenating them into a single combined
selection array (or combined selectionSet), then use that combined selectionSet
for further processing; if no selection sets are present across all nodes, still
throw the existing GraphQLError with EMPTY_RECORDS_SELECTION_MESSAGE.

In `@apps/ensapi/src/omnigraph-api/schema/account.ts`:
- Around line 75-95: The Account.primaryNames field currently accepts chainIds
and forces acceleration off; change its args to match the contract (accept
optional accelerate?: boolean and coinTypes?: ["CoinType"] or appropriate type)
and stop hard-disabling acceleration: call resolvePrimaryNames(account.id,
/*pass coinTypes or equivalent*/ coinTypes ?? undefined, { accelerate:
accelerate ?? context.canAccelerate, canAccelerate: context.canAccelerate })
instead of {accelerate:false, canAccelerate:false}; keep input validation
(replace or adapt validatePrimaryNamesChainIds to validate the new
coinTypes/args if necessary) and ensure runWithTrace still wraps the
resolvePrimaryNames call.

---

Duplicate comments:
In `@apps/ensapi/src/omnigraph-api/schema/domain.ts`:
- Around line 185-201: The Domain.records resolver currently hardcodes
acceleration by calling resolveForward(name, selection, { accelerate: false,
canAccelerate: false }), which prevents using the default accelerated path and
ignores context capabilities; update the resolve function in the records field
to stop forcing those flags — either omit the options so resolveForward uses its
defaults (allowing accelerate default true) or explicitly pass accelerate from
args and canAccelerate from the GraphQL context (e.g., use _args.accelerate ??
true and _context.canAccelerate) when invoking resolveForward so acceleration
behavior respects client requests and context capability checks.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: df655b88-c1d7-4207-b684-04d8bbcb87a2

📥 Commits

Reviewing files that changed from the base of the PR and between eae25f6 and 713f1ee.

📒 Files selected for processing (13)
  • apps/ensapi/src/omnigraph-api/builder.ts
  • apps/ensapi/src/omnigraph-api/lib/build-records-selection.test.ts
  • apps/ensapi/src/omnigraph-api/lib/build-records-selection.ts
  • apps/ensapi/src/omnigraph-api/lib/records-selection-config.ts
  • apps/ensapi/src/omnigraph-api/lib/validate-primary-names-chain-ids.test.ts
  • apps/ensapi/src/omnigraph-api/lib/validate-primary-names-chain-ids.ts
  • apps/ensapi/src/omnigraph-api/schema.ts
  • apps/ensapi/src/omnigraph-api/schema/account.integration.test.ts
  • apps/ensapi/src/omnigraph-api/schema/account.ts
  • apps/ensapi/src/omnigraph-api/schema/domain.integration.test.ts
  • apps/ensapi/src/omnigraph-api/schema/domain.ts
  • apps/ensapi/src/omnigraph-api/schema/resolution.ts
  • apps/ensapi/src/omnigraph-api/schema/scalars.ts

Comment thread apps/ensapi/src/omnigraph-api/lib/build-records-selection.ts Outdated
Comment thread apps/ensapi/src/omnigraph-api/schema/account.ts Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (3)
apps/ensapi/src/omnigraph-api/schema/domain.integration.test.ts (1)

551-601: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Prefer await expect(request(...)).resolves.toMatchObject(...) in these async assertions.

Please switch the two updated test cases to the preferred resolves style for consistency.

As per coding guidelines, Prefer the await expect(...).resolves.* format over await-then-expect for async assertions.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/ensapi/src/omnigraph-api/schema/domain.integration.test.ts` around lines
551 - 601, Update the two async tests ("resolves address and text records for
example.eth" and "resolves every supported record type for test.eth") to use the
await expect(...).resolves.toMatchObject(...) pattern instead of awaiting the
request and then calling expect on the result; specifically, call
request<DomainRecordsResult>(DomainRecords, {...}) and
request<DomainAllRecordsResult>(DomainRecordsAll, {...}) inside expect(...) and
append .resolves.toMatchObject(...) so the assertions are written as await
expect(request(...)).resolves.toMatchObject(...).
apps/ensapi/src/omnigraph-api/schema/resolution.ts (1)

196-246: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Parametric record resolvers should enforce argument-scoped output.

interfaces(ids), texts(keys), and addresses(coinTypes) ignore their args and return all entries in r.interfaces/r.texts/r.addresses. That breaks field-level scoping for these parametric fields and can leak supersets when selections are merged.

Proposed fix
       interfaces: t.field({
@@
-        resolve: (r) =>
-          r.interfaces
-            ? Object.entries(r.interfaces).map(([interfaceId, implementer]) => ({
-                interfaceId: interfaceId as InterfaceId,
-                implementer,
-              }))
-            : [],
+        resolve: (r, { ids }) =>
+          ids.map((interfaceId) => ({
+            interfaceId,
+            implementer: r.interfaces?.[interfaceId] ?? null,
+          })),
       }),
@@
       texts: t.field({
@@
-        resolve: (r) =>
-          r.texts ? Object.entries(r.texts).map(([key, value]) => ({ key, value })) : [],
+        resolve: (r, { keys }) =>
+          keys.map((key) => ({
+            key,
+            value: r.texts?.[key] ?? null,
+          })),
       }),
@@
       addresses: t.field({
@@
-        resolve: (r) =>
-          r.addresses
-            ? Object.entries(r.addresses).map(([coinType, address]) => ({
-                coinType: Number(coinType) as CoinType,
-                address,
-              }))
-            : [],
+        resolve: (r, { coinTypes }) =>
+          coinTypes.map((coinType) => ({
+            coinType,
+            address: r.addresses?.[coinType] ?? null,
+          })),
       }),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/ensapi/src/omnigraph-api/schema/resolution.ts` around lines 196 - 246,
The resolvers for interfaces, texts, and addresses return all records from
r.interfaces/r.texts/r.addresses instead of restricting results to the requested
args; update the resolve functions for interfaces (field interfaces with arg
ids), texts (field texts with arg keys), and addresses (field addresses with arg
coinTypes) to iterate over the provided args (ids, keys, coinTypes) and for each
arg lookup the corresponding value in r.interfaces/r.texts/r.addresses,
returning only entries found (or an explicit null/omit if missing) and
preserving the declared return shape (InterfaceId, key/value, CoinType/address)
so the field output is scoped to the arguments.
apps/ensapi/src/omnigraph-api/lib/records-selection-config.ts (1)

45-78: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Parametric selection assignment is currently lossy (last-write-wins).

applyToRecordsSelection overwrites texts/addresses/interfaces/abi each time. If the same parametric field appears multiple times (aliases/fragments), earlier requested values are dropped.

Proposed fix
   {
@@
     applyToRecordsSelection: (recordsSelection, args) => {
-      recordsSelection.texts = args.keys as string[];
+      const next = args.keys as string[];
+      recordsSelection.texts = [...new Set([...(recordsSelection.texts ?? []), ...next])];
     },
   },
@@
     applyToRecordsSelection: (recordsSelection, args) => {
-      recordsSelection.addresses = args.coinTypes as CoinType[];
+      const next = args.coinTypes as CoinType[];
+      recordsSelection.addresses = [
+        ...new Set([...(recordsSelection.addresses ?? []), ...next]),
+      ];
     },
   },
@@
     applyToRecordsSelection: (recordsSelection, args) => {
-      recordsSelection.abi = args.contentTypeMask as ContentType;
+      const next = args.contentTypeMask as ContentType;
+      recordsSelection.abi = ((recordsSelection.abi ?? 0n) | next) as ContentType;
     },
   },
@@
     applyToRecordsSelection: (recordsSelection, args) => {
-      recordsSelection.interfaces = args.ids as InterfaceId[];
+      const next = args.ids as InterfaceId[];
+      recordsSelection.interfaces = [
+        ...new Set([...(recordsSelection.interfaces ?? []), ...next]),
+      ];
     },
   },
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/ensapi/src/omnigraph-api/lib/records-selection-config.ts` around lines
45 - 78, The current RECORDS_SELECTION_PARAMETRIC_FIELDS entries'
applyToRecordsSelection handlers overwrite recordsSelection.texts / .addresses /
.interfaces / .abi on each call, losing earlier values; change each handler to
merge into existing values instead of replacing: for texts/addresses/interfaces,
if recordsSelection.<field> is unset assign args value, otherwise append new
items and deduplicate (preserve existing entries) so repeated param occurrences
accumulate; for abi (contentTypeMask) combine masks using bitwise OR rather than
assignment; update the applyToRecordsSelection lambdas inside
RECORDS_SELECTION_PARAMETRIC_FIELDS to perform these merge/dedupe steps when
reading args.keys, args.coinTypes, args.ids and args.contentTypeMask.
♻️ Duplicate comments (1)
apps/ensapi/src/omnigraph-api/schema/domain.ts (1)

190-207: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use accelerate (default true) instead of inverse disableAcceleration for this GraphQL field.

This inverts the contract described for Domain.records and makes the API less ergonomic/consistent with the issue objectives.

Proposed fix
       args: {
-        disableAcceleration: t.arg.boolean({
+        accelerate: t.arg.boolean({
           required: false,
-          defaultValue: false,
-          description: "When true, disables protocol acceleration feature.",
+          defaultValue: true,
+          description: "Whether to use protocol acceleration when available.",
         }),
       },
-      resolve: async (domain, { disableAcceleration }, context, info) => {
+      resolve: async (domain, { accelerate }, context, info) => {
@@
         const { result } = await runWithTrace(() =>
           resolveForward(name, recordsSelection, {
-            accelerate: !disableAcceleration,
+            accelerate,
             canAccelerate: context.canAccelerate,
           }),
         );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/ensapi/src/omnigraph-api/schema/domain.ts` around lines 190 - 207, The
GraphQL field currently accepts disableAcceleration and inverts it when calling
resolveForward, which is confusing; change the argument to accelerate:
t.arg.boolean({ required: false, defaultValue: true, description: "When true,
enables protocol acceleration feature." }) (replace the disableAcceleration arg
and its description) and in the resolve function use the incoming accelerate
value directly when calling resolveForward (i.e., pass accelerate instead of
!disableAcceleration), keeping context.canAccelerate unchanged and leaving
buildRecordsSelectionFromResolveInfo(info) and resolveForward intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/ensapi/src/handlers/api/omnigraph/omnigraph-api.ts`:
- Line 15: Add a short explanatory comment above the
MAX_REALTIME_DISTANCE_TO_ACCELERATE constant describing that the 60-second
threshold defines the realtime window used to decide whether to accelerate
processing (e.g., to use realtime data vs. batched processing), and include the
rationale or source for the value (user-experience/latency target, backend
polling interval, or a linked issue/config) so future maintainers understand why
60 seconds was chosen; update the comment near the constant declaration
MAX_REALTIME_DISTANCE_TO_ACCELERATE: Duration = 60 with this brief
justification.

In `@apps/ensapi/src/omnigraph-api/lib/validate-primary-names-chain-ids.ts`:
- Around line 6-18: Update the JSDoc for validatePrimaryNamesChainIds to state
that this function only enforces non-empty arrays and that individual ChainId
values are validated by the GraphQL scalar (so invalid chain IDs like 0 are
rejected upstream), referencing the function name validatePrimaryNamesChainIds,
the ChainId scalar, and the EMPTY_CHAIN_IDS_MESSAGE/GraphQLError behavior to
make the division of responsibility explicit for future maintainers.

---

Outside diff comments:
In `@apps/ensapi/src/omnigraph-api/lib/records-selection-config.ts`:
- Around line 45-78: The current RECORDS_SELECTION_PARAMETRIC_FIELDS entries'
applyToRecordsSelection handlers overwrite recordsSelection.texts / .addresses /
.interfaces / .abi on each call, losing earlier values; change each handler to
merge into existing values instead of replacing: for texts/addresses/interfaces,
if recordsSelection.<field> is unset assign args value, otherwise append new
items and deduplicate (preserve existing entries) so repeated param occurrences
accumulate; for abi (contentTypeMask) combine masks using bitwise OR rather than
assignment; update the applyToRecordsSelection lambdas inside
RECORDS_SELECTION_PARAMETRIC_FIELDS to perform these merge/dedupe steps when
reading args.keys, args.coinTypes, args.ids and args.contentTypeMask.

In `@apps/ensapi/src/omnigraph-api/schema/domain.integration.test.ts`:
- Around line 551-601: Update the two async tests ("resolves address and text
records for example.eth" and "resolves every supported record type for
test.eth") to use the await expect(...).resolves.toMatchObject(...) pattern
instead of awaiting the request and then calling expect on the result;
specifically, call request<DomainRecordsResult>(DomainRecords, {...}) and
request<DomainAllRecordsResult>(DomainRecordsAll, {...}) inside expect(...) and
append .resolves.toMatchObject(...) so the assertions are written as await
expect(request(...)).resolves.toMatchObject(...).

In `@apps/ensapi/src/omnigraph-api/schema/resolution.ts`:
- Around line 196-246: The resolvers for interfaces, texts, and addresses return
all records from r.interfaces/r.texts/r.addresses instead of restricting results
to the requested args; update the resolve functions for interfaces (field
interfaces with arg ids), texts (field texts with arg keys), and addresses
(field addresses with arg coinTypes) to iterate over the provided args (ids,
keys, coinTypes) and for each arg lookup the corresponding value in
r.interfaces/r.texts/r.addresses, returning only entries found (or an explicit
null/omit if missing) and preserving the declared return shape (InterfaceId,
key/value, CoinType/address) so the field output is scoped to the arguments.

---

Duplicate comments:
In `@apps/ensapi/src/omnigraph-api/schema/domain.ts`:
- Around line 190-207: The GraphQL field currently accepts disableAcceleration
and inverts it when calling resolveForward, which is confusing; change the
argument to accelerate: t.arg.boolean({ required: false, defaultValue: true,
description: "When true, enables protocol acceleration feature." }) (replace the
disableAcceleration arg and its description) and in the resolve function use the
incoming accelerate value directly when calling resolveForward (i.e., pass
accelerate instead of !disableAcceleration), keeping context.canAccelerate
unchanged and leaving buildRecordsSelectionFromResolveInfo(info) and
resolveForward intact.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: e0c05acb-eec2-4985-9af4-2595aba12a18

📥 Commits

Reviewing files that changed from the base of the PR and between 713f1ee and e1e5680.

⛔ Files ignored due to path filters (2)
  • packages/enssdk/src/omnigraph/generated/introspection.ts is excluded by !**/generated/**
  • packages/enssdk/src/omnigraph/generated/schema.graphql is excluded by !**/generated/**
📒 Files selected for processing (17)
  • apps/ensapi/src/handlers/api/omnigraph/omnigraph-api.ts
  • apps/ensapi/src/omnigraph-api/builder.ts
  • apps/ensapi/src/omnigraph-api/context.ts
  • apps/ensapi/src/omnigraph-api/lib/build-records-selection.test.ts
  • apps/ensapi/src/omnigraph-api/lib/build-records-selection.ts
  • apps/ensapi/src/omnigraph-api/lib/find-domains/find-domains-resolver.ts
  • apps/ensapi/src/omnigraph-api/lib/records-selection-config.ts
  • apps/ensapi/src/omnigraph-api/lib/validate-primary-names-chain-ids.test.ts
  • apps/ensapi/src/omnigraph-api/lib/validate-primary-names-chain-ids.ts
  • apps/ensapi/src/omnigraph-api/schema/account.integration.test.ts
  • apps/ensapi/src/omnigraph-api/schema/account.ts
  • apps/ensapi/src/omnigraph-api/schema/domain.integration.test.ts
  • apps/ensapi/src/omnigraph-api/schema/domain.ts
  • apps/ensapi/src/omnigraph-api/schema/resolution.ts
  • apps/ensapi/src/omnigraph-api/schema/scalars.ts
  • apps/ensapi/src/omnigraph-api/yoga.ts
  • packages/enssdk/src/omnigraph/graphql.ts
💤 Files with no reviewable changes (3)
  • packages/enssdk/src/omnigraph/graphql.ts
  • apps/ensapi/src/omnigraph-api/lib/validate-primary-names-chain-ids.test.ts
  • apps/ensapi/src/omnigraph-api/schema/scalars.ts

Comment thread apps/ensapi/src/handlers/api/omnigraph/omnigraph-api.ts Outdated
Comment thread apps/ensapi/src/omnigraph-api/lib/validate-primary-names-chain-ids.ts Outdated
@sevenzing
Copy link
Copy Markdown
Member Author

@greptile review

@sevenzing
Copy link
Copy Markdown
Member Author

@greptile

Comment thread apps/ensapi/src/omnigraph-api/schema/domain.ts Outdated
Comment thread apps/ensapi/src/omnigraph-api/schema/domain.ts Outdated
@vercel vercel Bot temporarily deployed to Preview – ensrainbow.io May 28, 2026 12:01 Inactive
@vercel vercel Bot temporarily deployed to Preview – admin.ensnode.io May 28, 2026 12:01 Inactive
@vercel vercel Bot temporarily deployed to Preview – ensnode.io May 28, 2026 12:01 Inactive
@sevenzing
Copy link
Copy Markdown
Member Author

@greptile review

Comment thread .changeset/omnigraph-resolution-api.md Outdated
Comment thread .changeset/omnigraph-resolution-api.md Outdated
Comment thread .changeset/omnigraph-resolution-api.md Outdated
Comment thread apps/ensapi/src/handlers/api/omnigraph/omnigraph-api.ts
Comment thread apps/ensapi/src/lib/resolution/multichain-primary-name-resolution.ts Outdated
Comment thread apps/ensapi/src/omnigraph-api/schema/account.ts Outdated
Comment thread apps/ensapi/src/omnigraph-api/schema/resolution.ts Outdated
Comment thread apps/ensapi/src/omnigraph-api/schema/resolution.ts Outdated
Comment thread packages/enskit/src/react/omnigraph/_lib/cache-exchange.ts
Comment thread packages/enskit/src/react/omnigraph/_lib/records-profile-cache-resolvers.ts Outdated
Copy link
Copy Markdown
Member

@lightwalker-eth lightwalker-eth left a comment

Choose a reason for hiding this comment

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

@sevenzing Super exciting to see your updates here. Reviewed and shared suggestions for how to get this PR ready to merge 👍

Comment thread apps/ensapi/src/omnigraph-api/lib/resolution/chain-coin-type.ts Outdated
Comment thread apps/ensapi/src/omnigraph-api/lib/resolution/chain-coin-type.ts Outdated
Comment thread packages/enssdk/src/omnigraph/generated/schema.graphql Outdated
Comment thread packages/enssdk/src/omnigraph/generated/schema.graphql Outdated
Comment thread packages/enssdk/src/omnigraph/generated/schema.graphql Outdated
Comment thread packages/enskit/src/react/omnigraph/_lib/records-profile-cache-resolvers.ts Outdated
Comment thread apps/ensapi/src/omnigraph-api/schema/account.ts Outdated
Comment thread apps/ensapi/src/omnigraph-api/schema/account.ts Outdated
Comment thread apps/ensapi/src/omnigraph-api/schema/account.ts Outdated
Comment thread apps/ensapi/src/omnigraph-api/lib/resolution/chain-coin-type.ts Outdated
Copy link
Copy Markdown
Member

@lightwalker-eth lightwalker-eth left a comment

Choose a reason for hiding this comment

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

@sevenzing Super exciting to see your updates here. Reviewed and shared suggestions for how to get this PR ready to merge 👍

Comment thread apps/ensapi/src/omnigraph-api/schema/account.ts
@github-actions github-actions Bot mentioned this pull request May 29, 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.

3 participants