Skip to content

feat(ensnode-sdk): introduce EnsIndexerClient#1643

Merged
tk-o merged 18 commits intomainfrom
feat/ensindexer-client
Feb 17, 2026
Merged

feat(ensnode-sdk): introduce EnsIndexerClient#1643
tk-o merged 18 commits intomainfrom
feat/ensindexer-client

Conversation

@tk-o
Copy link
Contributor

@tk-o tk-o commented Feb 17, 2026

Lite PR

Tip: Review docs on the ENSNode PR process

Summary

  • EnsIndexerClient is introduced to ENSNode SDK

Why


Testing

  • Ran static code checks and testing suite.
  • Tested major HTTP API endpoints for both, ENSApi and ENSIndexer services.

Notes for Reviewer (Optional)


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)

tk-o added 8 commits February 17, 2026 17:30
The goal of this change is to apply deserialization protocol where data is first transformed into serialized data model in order to be deserialized to business data model.
The goal of this change is to apply deserialization protocol where data is first transformed into serialized data model in order to be deserialized to business data model.
Follows `EnsApiClient` class, but is limited to only two methods: `config()` and `indexingStatus()`.
Copilot AI review requested due to automatic review settings February 17, 2026 17:44
@vercel
Copy link
Contributor

vercel bot commented Feb 17, 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 Feb 17, 2026 9:25pm
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
ensnode.io Skipped Skipped Feb 17, 2026 9:25pm
ensrainbow.io Skipped Skipped Feb 17, 2026 9:25pm

@changeset-bot
Copy link

changeset-bot bot commented Feb 17, 2026

🦋 Changeset detected

Latest commit: 55b839c

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

This PR includes changesets to release 19 packages
Name Type
@ensnode/ensnode-sdk Major
ensadmin Major
ensapi Major
ensindexer Major
ensrainbow Major
fallback-ensapi Major
@namehash/ens-referrals Major
@ensnode/ensnode-react Major
@ensnode/ensrainbow-sdk Major
@namehash/namehash-ui Major
@ensnode/datasources Major
@ensnode/ponder-metadata Major
@ensnode/ensnode-schema Major
@ensnode/ponder-sdk Major
@ensnode/ponder-subgraph Major
@ensnode/shared-configs Major
@docs/ensnode Major
@docs/ensrainbow Major
@docs/mintlify Major

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

@coderabbitai
Copy link

coderabbitai bot commented Feb 17, 2026

📝 Walkthrough

Walkthrough

Adds a new exported EnsIndexerClient and a public ENSIndexer API layer: config and indexing-status endpoints, serialized types, serializers/deserializers, Zod validation schemas, shared error handling, mocks/tests, and updated barrel re-exports to expose the new client and API surface. (48 words)

Changes

Cohort / File(s) Summary
Package Metadata
\.changeset/petite-rings-accept.md
Version bump for @ensnode/ensnode-sdk to include the new ENSIndexer exports.
Indexer Client & Barrel
packages/ensnode-sdk/src/ensindexer/client.ts, packages/ensnode-sdk/src/ensindexer/index.ts
Adds EnsIndexerClient and EnsIndexerClientOptions; implements config() and indexingStatus() with fetch, JSON parsing, error handling and deserialization; re-exports via package barrel.
Config API (types + i/o)
packages/ensnode-sdk/src/ensindexer/api/config/..., packages/ensnode-sdk/src/ensindexer/api/config/index.ts
New API-layer aliases/types (EnsIndexerConfigResponse, SerializedEnsIndexerConfigResponse) and serialize/deserialize helpers with a barrel index.
Indexing‑Status API (types + i/o + schemas)
packages/ensnode-sdk/src/ensindexer/api/indexing-status/...
Adds request/response types, serialized variants, serializers/deserializers, Zod schema factories, and an index barrel; deserializer enriches realtimeProjection when present.
Shared Error Handling
packages/ensnode-sdk/src/ensindexer/api/shared/errors/...
Adds ErrorResponse type, ErrorResponseSchema, and deserializeErrorResponse utility that validates and pretty-prints Zod errors; re-exported via errors index.
Zod Schema Factories
packages/ensnode-sdk/src/ensindexer/api/indexing-status/zod-schemas.ts, .../shared/errors/zod-schemas.ts
Schema factory functions for indexing-status (ok/error/serialized) and an ErrorResponse schema for runtime validation.
Serialized Types
packages/ensnode-sdk/src/ensindexer/api/indexing-status/serialized-response.ts, packages/ensnode-sdk/src/ensindexer/api/config/serialized-response.ts
Adds serialized-response type aliases/interfaces representing network payload shapes.
Mocks & Tests
packages/ensnode-sdk/src/ensindexer/client.mock.ts, packages/ensnode-sdk/src/ensindexer/client.test.ts, packages/ensnode-sdk/src/ensapi/client.test.ts
Adds mock serialized payloads and comprehensive tests for EnsIndexerClient; updates an unrelated test to use Vitest's vi.stubGlobal for fetch.
API Aggregation / Barrels
packages/ensnode-sdk/src/ensindexer/api/index.ts, packages/ensnode-sdk/src/ensindexer/index.ts, packages/ensnode-sdk/src/ensapi/index.ts
New/updated barrel files re-export config, indexing-status, api, client modules and expose EnsApiClientOptions type from ensapi client.

Sequence Diagram(s)

sequenceDiagram
    participant C as EnsIndexerClient
    participant S as ENSIndexer HTTP
    participant P as JSON Parser
    participant V as Zod Validator
    participant D as Deserializer

    C->>S: GET /api/config or /api/indexing-status
    S-->>C: HTTP response (JSON payload)
    C->>P: parse JSON
    P-->>C: unvalidated object
    C->>V: validate with appropriate Zod schema
    V-->>C: validated or validation error
    alt Validation Success
        C->>D: deserialize (may enrich realtimeProjection)
        D-->>C: typed EnsIndexer*Response
        C-->>C: return typed response
    else Validation Failure
        V-->>C: prettified Zod error
        C-->>C: throw Error with details
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰
I hopped to fetch the config at night,
Zod lit the path with soft delight,
Projections stitched and mocks in sight,
Client ready—typed and tested tight,
Thump-thump! The indexer takes flight.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% 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
Title check ✅ Passed The title clearly summarizes the main change: introducing EnsIndexerClient to the ENSNode SDK, which aligns with the changeset's primary focus.
Description check ✅ Passed The description follows the template structure with all required sections completed: Summary, Why, Testing, Notes for Reviewer, and Pre-Review Checklist, providing clear context for the changes.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/ensindexer-client

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.

@tk-o
Copy link
Contributor Author

tk-o commented Feb 17, 2026

@greptile review

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 17, 2026

Greptile Summary

This PR introduces EnsIndexerClient to the ENSNode SDK — a typed HTTP client for the ENSIndexer service's /api/config and /api/indexing-status endpoints — along with all supporting serialization, deserialization, response type, and Zod schema infrastructure. It also renames ClientOptions to EnsApiClientOptions in the ENSApi client (keeping a deprecated alias) and replaces a global.fetch assignment with vi.stubGlobal in the EnsApi test suite.

Key observations:

  • The new EnsIndexerClient.config() correctly throws on non-OK responses, which addresses feedback from prior review threads.
  • The indexingStatus() dual-branch error handling (generic ErrorResponse vs. domain-specific IndexingStatusResponseError) is sound in production, but a test covering the generic-error branch uses a body { error: "..." } that does not match ErrorResponseSchema (which requires { message: string }), causing the test to pass via the wrong code path.
  • Two @throws JSDoc annotations in EnsApiClient.config() and EnsApiClient.indexingStatus() were changed to say "ENSIndexer" instead of "ENSApi", likely a copy-paste error.
  • The shared/errors module is intentionally not re-exported from the public API surface, which is correct — it is only used internally by the client.
  • No naming conflicts introduced in the public SDK barrel exports.

Confidence Score: 4/5

  • This PR is safe to merge; issues found are cosmetic (JSDoc wording) and a test quality concern (wrong code path exercised), neither of which affects runtime correctness.
  • The core implementation is sound and the error handling logic is correct in production. The two problems are: (1) a copy-paste error in two JSDoc @throws annotations in EnsApiClient that say "ENSIndexer" instead of "ENSApi", and (2) a test in client.test.ts that asserts the right behaviour but via the wrong code path, giving false confidence in the generic ErrorResponse branch of indexingStatus(). Neither issue causes a runtime bug.
  • Pay attention to packages/ensnode-sdk/src/ensindexer/client.test.ts (test correctness) and packages/ensnode-sdk/src/ensapi/client.ts (JSDoc copy-paste errors).

Important Files Changed

Filename Overview
packages/ensnode-sdk/src/ensindexer/client.ts New EnsIndexerClient with config() and indexingStatus() methods; the config() error handling now correctly throws on non-OK responses; indexingStatus() has complex dual-branch error handling logic that is otherwise sound.
packages/ensnode-sdk/src/ensindexer/client.test.ts Test file covering happy path, error handling, and malformed JSON; the "throws on non-OK response with a generic ErrorResponse payload" test at line 108 uses a body that doesn't match ErrorResponseSchema, meaning it exercises the wrong code path but still passes.
packages/ensnode-sdk/src/ensapi/client.ts EnsApiClient refactored with renamed type (EnsApiClientOptions), console.log removed from indexingStatus(), but two JSDoc @throws annotations incorrectly say 'ENSIndexer' instead of 'ENSApi'.
packages/ensnode-sdk/src/ensindexer/client.mock.ts Mock data for EnsIndexerClient tests; well-structured with typed satisfies constraints, covers both config and indexing status responses.
packages/ensnode-sdk/src/ensindexer/api/indexing-status/zod-schemas.ts Zod schemas for serialized and deserialized indexing status responses using discriminated unions on responseCode; correctly structured with strictObject to prevent extra fields.
packages/ensnode-sdk/src/ensindexer/api/indexing-status/deserialize.ts Deserialization pipeline using zod transform+pipe; correctly branches on responseCode to build unvalidated response before final schema validation.
packages/ensnode-sdk/src/ensindexer/api/shared/errors/zod-schemas.ts ErrorResponseSchema uses z.object() (not z.strictObject()), which correctly tolerates extra fields when distinguishing error responses from other response types.

Sequence Diagram

sequenceDiagram
    participant C as Caller
    participant EIC as EnsIndexerClient
    participant F as fetch()
    participant DE as deserializeErrorResponse
    participant DC as deserializeEnsIndexerConfigResponse
    participant DIS as deserializeEnsIndexerIndexingStatusResponse

    C->>EIC: config()
    EIC->>F: fetch(/api/config)
    F-->>EIC: Response
    alt JSON parse fails
        EIC-->>C: throw "Malformed response data: invalid JSON"
    else !response.ok
        EIC->>DE: deserializeErrorResponse(body)
        DE-->>EIC: ErrorResponse
        EIC-->>C: throw "Fetching ENSIndexer Config Failed: ..."
    else response.ok
        EIC->>DC: deserializeEnsIndexerConfigResponse(body)
        DC-->>EIC: EnsIndexerConfigResponse
        EIC-->>C: EnsIndexerConfigResponse
    end

    C->>EIC: indexingStatus()
    EIC->>F: fetch(/api/indexing-status)
    F-->>EIC: Response
    alt JSON parse fails
        EIC-->>C: throw "Malformed response data: invalid JSON"
    else !response.ok
        EIC->>DE: deserializeErrorResponse(body)
        alt body matches ErrorResponseSchema
            DE-->>EIC: ErrorResponse
            EIC-->>C: throw "Fetching ENSIndexer Indexing Status Failed: ..."
        else body does NOT match ErrorResponseSchema
            DE-->>EIC: throws (caught, no-op)
            EIC->>DIS: deserializeEnsIndexerIndexingStatusResponse(body)
            DIS-->>EIC: EnsIndexerIndexingStatusResponseError
            EIC-->>C: EnsIndexerIndexingStatusResponseError
        end
    else response.ok
        EIC->>DIS: deserializeEnsIndexerIndexingStatusResponse(body)
        DIS-->>EIC: EnsIndexerIndexingStatusResponseOk
        EIC-->>C: EnsIndexerIndexingStatusResponseOk
    end
Loading

Last reviewed commit: f8b9fec

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

21 files reviewed, no comments

Edit Code Review Agent Settings | Greptile

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces the EnsIndexerClient class to the ENSNode SDK, enabling programmatic access to ENSIndexer's configuration and indexing status APIs. This client follows the same architectural patterns as the existing EnsApiClient and is part of the effort described in issue #1252 to improve the communication between ENSApi and ENSIndexer services.

Changes:

  • Adds EnsIndexerClient class with config() and indexingStatus() methods
  • Implements API response types, schemas, and serialization/deserialization functions for ENSIndexer's config and indexing-status endpoints
  • Adds error response handling following established patterns
  • Includes test coverage for happy path scenarios and mock data

Reviewed changes

Copilot reviewed 21 out of 21 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
packages/ensnode-sdk/src/ensindexer/client.ts Core client implementation with config() and indexingStatus() methods
packages/ensnode-sdk/src/ensindexer/client.test.ts Unit tests for the client (happy paths)
packages/ensnode-sdk/src/ensindexer/client.mock.ts Mock data for testing
packages/ensnode-sdk/src/ensindexer/api/shared/errors/* Error response types, schemas, and deserialization
packages/ensnode-sdk/src/ensindexer/api/indexing-status/* Indexing status API types, schemas, serialization/deserialization
packages/ensnode-sdk/src/ensindexer/api/config/* Config API types, schemas, serialization/deserialization
packages/ensnode-sdk/src/ensindexer/api/index.ts API exports aggregation

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@vercel vercel bot temporarily deployed to Preview – ensnode.io February 17, 2026 17:54 Inactive
@vercel vercel bot temporarily deployed to Preview – ensrainbow.io February 17, 2026 17:54 Inactive
@tk-o tk-o marked this pull request as ready for review February 17, 2026 17:54
@tk-o tk-o requested a review from a team as a code owner February 17, 2026 17:54
Copilot AI review requested due to automatic review settings February 17, 2026 17:54
@tk-o
Copy link
Contributor Author

tk-o commented Feb 17, 2026

@greptile review

Copy link

@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 (1)
packages/ensnode-sdk/src/ensapi/client.ts (1)

370-383: 🛠️ Refactor suggestion | 🟠 Major

Inconsistent error-handling pattern: no-op here vs. console.log in sibling methods.

The catch block here was changed to a silent no-op comment, but registrarActions() (Line 597) and nameTokens() (Line 668) still use console.log in the equivalent catch block. These should be aligned — either all use no-op or all log.

♻️ Suggested fix — align registrarActions and nameTokens

In registrarActions() (~line 594-598):

       } catch {
-        // if errorResponse could not be determined,
-        // it means the response includes data
-        console.log("Registrar Actions API: handling a known server error.");
+        // No-op: allow subsequent deserialization of registrar actions response.
       }

In nameTokens() (~line 665-669):

       } catch {
-        // if errorResponse could not be determined,
-        // it means the response includes data
-        console.log("Name Tokens API: handling a known server error.");
+        // No-op: allow subsequent deserialization of name tokens response.
       }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/ensnode-sdk/src/ensapi/client.ts` around lines 370 - 383, The three
error-handling catch blocks should be consistent: update registrarActions() and
nameTokens() to match the silent no-op pattern used around the
deserializeErrorResponse() logic in the indexing-status path; specifically,
replace the console.log calls in the catch blocks inside registrarActions and
nameTokens with the same empty catch/no-op comment used where
deserializeErrorResponse(responseData) is attempted (the ErrorResponse,
deserializeErrorResponse and responseData handling), so all three locations use
the same silent fallback before attempting subsequent deserialization and then
conditionally throwing based on errorResponse.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/ensnode-sdk/src/ensindexer/client.test.ts`:
- Around line 77-88: The test is mocking a non-OK ErrorResponse but uses the
wrong field name; update the mock so the payload matches the ErrorResponse
schema (use a "message" field) so that deserializeErrorResponse is exercised.
Specifically, in the test for client.indexingStatus(), change the mocked
errorResponse to include message: string (not error) so
deserializeErrorResponse(path) will validate and the code path that throws the
parsed error is tested instead of falling back to
deserializeEnsIndexerConfigResponse; ensure mockFetch.mockResolvedValueOnce
still returns ok: false and json() resolving to that corrected object.

In `@packages/ensnode-sdk/src/ensindexer/client.ts`:
- Around line 72-91: The config() handler currently falls through to
deserializeEnsIndexerConfigResponse when response.ok is false and
deserializeErrorResponse throws, which masks the HTTP error; update config() so
that any non-OK response always results in throwing an error: attempt to
deserializeErrorResponse and, if successful, throw with errorResponse.message,
otherwise throw a generic HTTP error that includes response.status (and
optionally response.statusText or the raw responseData) so the HTTP context
isn't lost; reference the config() function and the deserializeErrorResponse /
deserializeEnsIndexerConfigResponse calls and mirror the intent used in
indexingStatus() but always abort on non-OK.

---

Outside diff comments:
In `@packages/ensnode-sdk/src/ensapi/client.ts`:
- Around line 370-383: The three error-handling catch blocks should be
consistent: update registrarActions() and nameTokens() to match the silent no-op
pattern used around the deserializeErrorResponse() logic in the indexing-status
path; specifically, replace the console.log calls in the catch blocks inside
registrarActions and nameTokens with the same empty catch/no-op comment used
where deserializeErrorResponse(responseData) is attempted (the ErrorResponse,
deserializeErrorResponse and responseData handling), so all three locations use
the same silent fallback before attempting subsequent deserialization and then
conditionally throwing based on errorResponse.

---

Duplicate comments:
In `@packages/ensnode-sdk/src/ensindexer/client.test.ts`:
- Around line 42-57: Add tests covering config() error paths: create three new
it() cases that call client.config() and assert it rejects appropriately when
(1) the mocked fetch returns { ok: false, json: async () => validErrorBody } —
assert the thrown error includes/parses that body, (2) fetch returns { ok:
false, json: async () => { throw new Error("bad json") } } — assert the call
rejects with the json error, and (3) fetch returns { ok: false, json: async ()
=> invalidNonObject } (or other malformed body) — assert rejection/fallback
behavior. Use the same requestUrl construction and
mockFetch.mockResolvedValueOnce to stub responses, and keep assertions that
mockFetch was called with requestUrl; reference client.config(), mockFetch, and
deserializeEnsIndexerConfigResponse to locate existing test setup and
expected-shape helpers.

In `@packages/ensnode-sdk/src/ensindexer/client.ts`:
- Around line 58-137: config() and indexingStatus() duplicate the same fetch →
json → errorResponse handling → deserialization logic; add a private helper
method (e.g. fetchJson(path: string)) that performs fetch(new URL(path,
this.options.url)), awaits response.json() with the existing malformed-JSON
check, attempts deserializeErrorResponse when !response.ok and throws the same
formatted Error message if present, and otherwise returns the parsed
responseData; then refactor config() to call fetchJson('/api/config') and pass
the result into deserializeEnsIndexerConfigResponse, and refactor
indexingStatus() to call fetchJson('/api/indexing-status') and pass the result
into deserializeEnsIndexerIndexingStatusResponse, keeping existing error
messages and using the same helper for both endpoints.

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

24 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 24 out of 24 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

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

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

Inline comments:
In `@packages/ensnode-sdk/src/ensindexer/client.test.ts`:
- Around line 59-76: The test's mocked errorBody uses the wrong shape so
deserializeErrorResponse never validates and the code takes the fallthrough
path; change errorBody to match the ErrorResponse schema (top-level { message:
"Something went wrong", details?: ... }) so deserializeErrorResponse runs, then
tighten the assertion on client.config() to expect the thrown error to include
that message (e.g., await expect(client.config()).rejects.toThrow("Something
went wrong")), and keep the existing expectation that mockFetch was called with
requestUrl; reference functions/types: deserializeErrorResponse, ErrorResponse,
deserializeEnsIndexerConfigResponse, client.config(), and mockFetch.

---

Duplicate comments:
In `@packages/ensnode-sdk/src/ensindexer/client.test.ts`:
- Around line 110-121: The test uses the wrong error payload shape; update the
mocked non-OK response in the test for client.indexingStatus() to return an
ErrorResponse-shaped object { message: "Something went wrong" } (not { error:
... }) so the code takes the error-response branch, and change the assertion to
expect the specific thrown message "Fetching ENSIndexer Indexing Status Failed:
Something went wrong"; ensure the mockFetch resolution still returns ok: false
and json: async () => the new object and that the test still verifies mockFetch
was called with the requestUrl.

@tk-o
Copy link
Contributor Author

tk-o commented Feb 17, 2026

@greptile review

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

25 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 25 out of 25 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

*
* @throws if the ENSApi request fails
* @throws if the ENSApi returns an error response
* @throws if the ENSIndexer returns a non-ok response
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

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

JSDoc for EnsApiClient.config() incorrectly says it may throw when the ENSIndexer returns a non-ok response, but this client calls ENSApi. Update the @throws description to reference ENSApi (or "server") to avoid misleading SDK consumers.

Suggested change
* @throws if the ENSIndexer returns a non-ok response
* @throws if the ENSApi returns a non-ok response

Copilot uses AI. Check for mistakes.
Copy link

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

Caution

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

⚠️ Outside diff range comments (1)
packages/ensnode-sdk/src/ensapi/client.ts (1)

370-383: 🧹 Nitpick | 🔵 Trivial

Logging inconsistency: registrarActions() and nameTokens() still emit console.log in the equivalent catch block.

Line 376 now silently no-ops when deserializeErrorResponse throws, but the analogous catch paths in registrarActions() (line 598) and nameTokens() (line 668) still call console.log(...). Either remove those two surviving logs or restore the log here for consistency.

♻️ Proposed clean-up for the sibling catch blocks (registrarActions / nameTokens)
-      } catch {
-        // if errorResponse could not be determined,
-        // it means the response includes data
-        console.log("Registrar Actions API: handling a known server error.");
-      }
+      } catch {
+        // No-op: allow subsequent deserialization of registrar actions response.
+      }
-      } catch {
-        // if errorResponse could not be determined,
-        // it means the response includes data
-        console.log("Name Tokens API: handling a known server error.");
-      }
+      } catch {
+        // No-op: allow subsequent deserialization of name tokens response.
+      }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/ensnode-sdk/src/ensapi/client.ts` around lines 370 - 383, The
error-deserialization catch in the indexing status fetch (using
deserializeErrorResponse) swallows errors silently, but the sibling functions
registrarActions and nameTokens still call console.log in their equivalent catch
blocks, creating inconsistency; update the code so all three behave the same:
either remove the console.log(...) calls from registrarActions and nameTokens or
add a console.log here inside the catch that mirrors their existing message.
Locate the catch that surrounds deserializeErrorResponse in client.ts (the
response.ok error-handling block) and make the chosen change, ensuring you
reference deserializeErrorResponse, registrarActions, and nameTokens so all
three error-paths are consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/ensnode-sdk/src/ensindexer/client.ts`:
- Around line 72-75: The config() path currently calls
deserializeErrorResponse(responseData) without guarding, so a malformed error
body can throw a Zod error and lose HTTP status; wrap the
deserializeErrorResponse call in a try/catch (same pattern used in
indexingStatus()), and on failure fall back to a generic error that includes the
HTTP status (response.status / response.statusText) and the raw responseData;
ensure you still throw an Error with a clear message like "Fetching ENSIndexer
Config Failed" combined with either errorResponse.message or the fallback
information so callers receive the HTTP status and body when deserialization
fails.

---

Outside diff comments:
In `@packages/ensnode-sdk/src/ensapi/client.ts`:
- Around line 370-383: The error-deserialization catch in the indexing status
fetch (using deserializeErrorResponse) swallows errors silently, but the sibling
functions registrarActions and nameTokens still call console.log in their
equivalent catch blocks, creating inconsistency; update the code so all three
behave the same: either remove the console.log(...) calls from registrarActions
and nameTokens or add a console.log here inside the catch that mirrors their
existing message. Locate the catch that surrounds deserializeErrorResponse in
client.ts (the response.ok error-handling block) and make the chosen change,
ensuring you reference deserializeErrorResponse, registrarActions, and
nameTokens so all three error-paths are consistent.

---

Duplicate comments:
In `@packages/ensnode-sdk/src/ensindexer/client.test.ts`:
- Around line 42-89: Add a test that covers the branch where client.config()
receives response.ok === false but the response body does not match
ErrorResponseSchema so deserializeErrorResponse throws: mockFetch to resolve
with ok: false and a json() that returns an invalid object (e.g., { foo: "bar" }
or throws when validating), then assert that client.config() rejects with the
deserializeErrorResponse error (use rejects.toThrow matching the deserializer's
error message or type) and that mockFetch was called with the same requestUrl;
this targets the unguarded call path involving deserializeErrorResponse in
client.config().
- Around line 59-74: Tighten the test assertion in client.config() to assert the
exact error message emitted after deserializeErrorResponse runs: update the
rejects.toThrow check in the "throws an error when the config endpoint returns a
non-OK response with a valid error body" test so it expects the full message
that includes errorBody.message (e.g., "Fetching ENSIndexer Config Failed:
Something went wrong"), ensuring deserializeErrorResponse actually contributed
its message; keep the existing mockFetch setup and the
expect(mockFetch).toHaveBeenCalledWith(requestUrl) assertion intact and
reference this change around the test for client.config and the
deserializeErrorResponse code path.

In `@packages/ensnode-sdk/src/ensindexer/client.ts`:
- Around line 58-103: Both config() and indexingStatus() duplicate the fetch →
response.json() → invalid-JSON error pattern; extract a shared helper (e.g.,
fetchAndParseJson or fetchJson) used by both methods to reduce duplication. The
helper should accept the endpoint path (or URL), perform fetch(url), attempt
response.json() inside try/catch and rethrow new Error("Malformed response data:
invalid JSON") on parse failure, then return an object containing { response,
responseData } so callers (config() and indexingStatus()) can check response.ok,
deserialize errors with deserializeErrorResponse(responseData) and call the
existing deserializeEnsIndexerConfigResponse /
deserializeEnsIndexerIndexingStatusResponse with the appropriately typed
responseData (keeping Unvalidated typing). Replace the duplicated blocks in
config() and indexingStatus() to call this helper and preserve existing error
messages and behavior.

@tk-o tk-o merged commit 4cf6f41 into main Feb 17, 2026
16 checks passed
@tk-o tk-o deleted the feat/ensindexer-client branch February 17, 2026 21:31
@github-actions github-actions bot mentioned this pull request Feb 17, 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

Comments