Skip to content

Conversation

@Goader
Copy link
Contributor

@Goader Goader commented Jan 16, 2026

Flip Dependency Relationship: ensnode-sdk ↔ ens-referrals

closes: #1519


Reviewer Focus (Read This First)

What reviewers should focus on
  • New ENSReferralsClient class in packages/ens-referrals/src/client.ts - mirrors ENSNodeClient design patterns
  • Packages configuration
  • Encoded Referrers and documentation tweaks regarding it (I was contemplating on whether it should stay in ens-referrals or ensnode-sdk)

Problem & Motivation

Why this exists

What Changed (Concrete)

What actually changed

Package Dependency Changes

  1. Removed ens-referrals dependency from ensnode-sdk/package.json
  2. Added ensnode-sdk dependency to ens-referrals/package.json

Code Moved from ensnode-sdk to ens-referrals

  1. Deleted entire packages/ensnode-sdk/src/ensanalytics/ directory
  2. Removed getReferrerLeaderboardPage() and getReferrerDetail() from ENSNodeClient
  3. Removed related exports

New Client in ens-referrals

  1. Created ENSReferralsClient class with both API methods
  2. Created packages/ens-referrals/src/api/ directory with all the serialization, deserialization and validation
  3. Created packages/ens-referrals/src/internal.ts for internal zod schema exports (similarly to how it's done in ensnode-sdk; let me know if we wanted to drop Zod dependency)
  4. Added related exports

Type Consolidation

  1. Deleted duplicate ChainId, AccountId, UnixTimestamp and Duration definitions
  2. Updated files to import these types from ensnode-sdk, including ENSApi

Design & Planning

How this approach was chosen

The new ENSReferralsClient follows the exact same design as ENSNodeClient, with all the APIs having the same request/response schemas not to introduce any breaking changes on that level.


Self-Review

What you caught yourself
  • Bugs caught: Zod dependency not added to ens-referrals
  • Logic simplified: None
  • Naming / terminology improved: None needed
  • Dead or unnecessary code removed: duplicate type definitions eliminated

Cross-Codebase Alignment

Related code you checked
  • ENSNodeClient for consistency with new ENSReferralsClient
  • All files importing referral types
  • Registrar Actions, where it uses EncodedReferrer
  • ensnode-schema to update docs (definitely requires your opinion)
  • Search terms used: @namehash/ens-referrals, @namehash/ensnode-sdk, EncodedReferrer, ENS Awards, Awards, ensanalytics, ChainId, AccountId, UnixTimestamp, Duration, ENSNodeClient
  • Reviewed but unchanged: timestamp validation function, which is in ens-referrals, while UnixTimestamp is now imported from ensnode-sdk. Not sure if we want to make it more consistent by using Zod everywhere, or drop it altogether. So far, I left it unchanged, not moving into ensnode-sdk, which didn't seem to match, and it already had some Zod schemas for Unix timestamps.
  • Deferred alignment: ENSAwards will need updates in separate PR (different repo), and there is a temporary comment mentioning ENS Awards above accurateAsOf field

Downstream & Consumer Impact

Who this affects and how
  • Mainly developers
  • ENSNode users, when dealing with dependencies
  • ENS Awards now required to use a separate client
  • Public APIs affected: API endpoint URLs unchanged, response formats unchanged (network layer non-breaking)
  • Docs updated: ENSNodeClient dropped mentions of ENS Analytics, removed any mentions of ENS Awards where possible in ensnode-sdk and other ENSNode core code.
  • Naming decisions: ENSReferralsClient to parallel ENSNodeClient naming convention, some docs using "subjective interpretation for ENS Awards" to "required left-zero-padding", mentioned earlier that this would benefit from your opinion on how it should be phrased

Testing Evidence

How this was validated
  • All standard CI testing
  • Manual validation of existing APIs using a running instance
  • Checking if builds correctly, considering the substantial changes in where certain types are now located
  • Testing performed: Automated test scripts + manual validation
  • Known gaps: ENSAwards
  • What reviewers have to reason about manually: EncodedReferrer moved to ensnode-sdk

Scope Reductions

What you intentionally didn't do

Did not update ENSAwards site in this PR

  • Follow-ups: Update ENSAwards to use the new client
  • Why they were deferred: ENSAwards is separate repo

Risk Analysis

How this could go wrong
  • Requires coordinated update with ENSAwards
  • This is a breaking change, and since quite a few places depend on ens-referrals, they all require updating
  • Risk areas: ENSAwards
  • Mitigations or rollback options: No API breaking changes, can revert if needed. ENSAwards should be updated in coordination with this. As far as I understand, we push this into main, and then update ENSAwards to use snapshot release with the new client?
  • Named owner if this causes problems: @Goader

Pre-Review Checklist (Blocking)

  • I reviewed every line of this diff and understand it end-to-end
  • I'm prepared to defend this PR line-by-line in review
  • I'm comfortable being the on-call owner for this change
  • Relevant changesets are included (or explicitly not required)

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced ENSReferralsClient for accessing referral leaderboard and referrer detail APIs with dedicated methods getReferrerLeaderboardPage() and getReferrerDetail().
  • Refactoring

    • Separated referral APIs into a dedicated package; moved functionality from ENSNodeClient to ENSReferralsClient.
    • Consolidated shared type definitions across packages.

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

Copilot AI review requested due to automatic review settings January 16, 2026 21:33
@changeset-bot
Copy link

changeset-bot bot commented Jan 16, 2026

🦋 Changeset detected

Latest commit: dbef3e5

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

This PR includes changesets to release 18 packages
Name Type
@namehash/ens-referrals Major
@ensnode/ensnode-sdk Major
ensapi Major
ensadmin Major
ensindexer Major
ensrainbow Major
fallback-ensapi 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-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

@vercel
Copy link

vercel bot commented Jan 16, 2026

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

Project Deployment Review Updated (UTC)
admin.ensnode.io Ready Ready Preview, Comment Jan 19, 2026 1:25pm
ensnode.io Ready Ready Preview, Comment Jan 19, 2026 1:25pm
ensrainbow.io Ready Ready Preview, Comment Jan 19, 2026 1:25pm

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 flips the dependency relationship between the ens-referrals and ensnode-sdk packages to better align package responsibilities. The ensnode-sdk package now contains shared types and utility code that ens-referrals depends on, reversing the previous dependency direction.

Changes:

  • Moved EncodedReferrer types and encoding/decoding logic from ens-referrals to ensnode-sdk
  • Consolidated duplicate types (ChainId, AccountId, UnixTimestamp, Duration) by having ens-referrals import them from ensnode-sdk
  • Created new ENSReferralsClient in ens-referrals package for referral leaderboard APIs (moved from ensnode-sdk)
  • Removed ensanalytics API endpoints from ENSNodeClient in favor of the new specialized client

Reviewed changes

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

Show a summary per file
File Description
pnpm-lock.yaml Updates dependency graph to reflect the flipped relationship
packages/ensnode-sdk/src/registrars/encoded-referrer.ts Moved encoded referrer logic from ens-referrals with updated documentation
packages/ensnode-sdk/src/registrars/zod-schemas.ts Updates import path for encoded referrer utilities
packages/ensnode-sdk/src/registrars/registrar-action.ts Updates import paths and documentation comments
packages/ensnode-sdk/src/registrars/index.ts Exports new encoded-referrer module
packages/ensnode-sdk/src/client.ts Removes ENSAnalytics API methods (moved to ens-referrals)
packages/ensnode-sdk/src/index.ts Removes ensanalytics export
packages/ensnode-sdk/package.json Removes ens-referrals dependency
packages/ens-referrals/src/time.ts Imports UnixTimestamp and Duration from ensnode-sdk
packages/ens-referrals/src/rules.ts Imports AccountId and UnixTimestamp from ensnode-sdk
packages/ens-referrals/src/client.ts New ENSReferralsClient with referral leaderboard API methods
packages/ens-referrals/src/api/* Updates imports to use local and ensnode-sdk types
packages/ens-referrals/src/index.ts Adds exports for api and client modules
packages/ens-referrals/src/internal.ts New internal exports for zod schemas
packages/ens-referrals/package.json Adds ensnode-sdk dependency and internal export path
packages/ensnode-schema/src/schemas/registrars.schema.ts Updates documentation comments
apps/ensapi/src/handlers/ensanalytics-api.ts Updates imports to use ens-referrals package
apps/ensapi/src/handlers/ensanalytics-api.test.ts Updates imports to use ens-referrals package
apps/ensapi/src/lib/ensanalytics/referrer-leaderboard/mocks.ts Updates imports to use ens-referrals package
.changeset/rich-shirts-spend.md Documents the breaking changes
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported
Comments suppressed due to low confidence (1)

packages/ens-referrals/package.json:40

  • The publishConfig.exports section is missing the /internal export path. This means when the package is published to npm, consumers won't be able to import from @namehash/ens-referrals/internal even though it's defined in the development exports field. Add the internal export configuration to match the pattern used in the main export.
  "publishConfig": {
    "access": "public",
    "exports": {
      ".": {
        "import": {
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        },
        "require": {
          "types": "./dist/index.d.cts",
          "default": "./dist/index.cjs"
        }
      }
    },
    "main": "./dist/index.cjs",
    "module": "./dist/index.js",
    "types": "./dist/index.d.ts"

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

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 37 out of 39 changed files in this pull request and generated 3 comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

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

Copilot AI review requested due to automatic review settings January 17, 2026 21:00
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 37 out of 39 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

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

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Jan 17, 2026

Greptile Summary

Successfully flipped dependency relationship between ens-referrals and ensnode-sdk packages, eliminating circular dependencies and code duplication.

Key Changes:

  • Created new ENSReferralsClient in ens-referrals package with getReferrerLeaderboardPage and getReferrerDetail methods (previously in ENSNodeClient)
  • Removed ens-referrals dependency from ensnode-sdk; added ensnode-sdk dependency to ens-referrals
  • Consolidated duplicate types (ChainId, AccountId, UnixTimestamp, Duration) by importing from ensnode-sdk
  • Moved EncodedReferrer from ens-referrals to ensnode-sdk/registrars with updated documentation (removed "ENS Holiday Awards" references, clarified strict left-zero-padding validation)
  • Added API serialization/deserialization layer in ens-referrals for handling bigint conversions
  • Updated build configuration with noExternal: ["@ensnode/ensnode-sdk"] in ens-referrals/tsup.config.ts

Impact:

  • ENSAwards will need to use both ENSReferralsClient and ENSNodeClient (breaking change at code import level, but network APIs unchanged)
  • ENSApi temporarily depends on both packages during migration phase
  • Enables future extraction of referral backend logic from ENSApi into separate service

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk
  • The PR implements a well-planned architectural refactoring with excellent execution. The dependency flip is clean, type consolidation eliminates duplication, the new ENSReferralsClient follows established patterns from ENSNodeClient, and all API contracts remain unchanged at the network level. The changes are breaking at the import level (as expected and documented), but this is intentional for the planned migration path.
  • No files require special attention

Important Files Changed

Filename Overview
packages/ens-referrals/package.json Added ensnode-sdk and zod as dependencies, added internal export path for zod schemas
packages/ensnode-sdk/package.json Removed @namehash/ens-referrals dependency, completing the dependency flip
packages/ens-referrals/src/client.ts New ENSReferralsClient mirrors ENSNodeClient design patterns with getReferrerLeaderboardPage and getReferrerDetail methods
packages/ensnode-sdk/src/client.ts Removed getReferrerLeaderboardPage and getReferrerDetail methods - migrated to ENSReferralsClient
packages/ensnode-sdk/src/registrars/encoded-referrer.ts Moved from ens-referrals, updated docs from "ENS Holiday Awards subjective interpretation" to "strict left-zero-padding validation"
packages/ens-referrals/tsup.config.ts Added noExternal: ["@ensnode/ensnode-sdk"] to bundle ensnode-sdk types into ens-referrals package

Sequence Diagram

sequenceDiagram
    participant ENSAwards as ENS Awards App
    participant ENSReferralsClient as ENSReferralsClient<br/>(ens-referrals)
    participant ENSNodeClient as ENSNodeClient<br/>(ensnode-sdk)
    participant ENSApi as ENSNode API<br/>(ensapi)
    
    Note over ENSAwards,ENSApi: Before: Single Client, Circular Dependency Issue
    
    Note over ENSAwards,ENSApi: After: Separate Clients, Clean Dependencies
    
    ENSAwards->>ENSReferralsClient: new ENSReferralsClient()
    ENSAwards->>ENSNodeClient: new ENSNodeClient()
    
    ENSAwards->>ENSReferralsClient: getReferrerLeaderboardPage({page, recordsPerPage})
    ENSReferralsClient->>ENSApi: GET /ensanalytics/referrers
    ENSApi-->>ENSReferralsClient: SerializedReferrerLeaderboardPageResponse
    ENSReferralsClient->>ENSReferralsClient: deserializeReferrerLeaderboardPageResponse()
    ENSReferralsClient-->>ENSAwards: ReferrerLeaderboardPageResponse
    
    ENSAwards->>ENSReferralsClient: getReferrerDetail({referrer: "0x..."})
    ENSReferralsClient->>ENSApi: GET /api/ensanalytics/referrers/:address
    ENSApi-->>ENSReferralsClient: SerializedReferrerDetailResponse
    ENSReferralsClient->>ENSReferralsClient: deserializeReferrerDetailResponse()
    ENSReferralsClient-->>ENSAwards: ReferrerDetailResponse
    
    ENSAwards->>ENSNodeClient: resolveRecords(name, selection)
    ENSNodeClient->>ENSApi: GET /api/resolve/records/:name
    ENSApi-->>ENSNodeClient: ResolveRecordsResponse
    ENSNodeClient-->>ENSAwards: records
    
    Note over ENSReferralsClient,ENSNodeClient: Type Flow: ChainId, AccountId,<br/>UnixTimestamp, Duration<br/>flow from ensnode-sdk → ens-referrals
    
    Note over ENSApi: ENSApi uses both packages<br/>temporarily until migration complete
Loading

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Jan 17, 2026

Greptile found no issues!

From now on, if a review finishes and we haven't found any issues, we will not post anything, but you can confirm that we reviewed your changes in the status check section.

This feature can be toggled off in your Code Review Settings by deselecting "Create a status check for each PR".

Copy link
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.

@Goader Great job! Nice work 🚀

@coderabbitai
Copy link

coderabbitai bot commented Jan 19, 2026

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

📝 Walkthrough

Walkthrough

This pull request flips the dependency relationship between ensnode-sdk and ens-referrals packages. The ensnode-sdk package removes its dependency on ens-referrals and removes referral API methods from its client. The ens-referrals package now depends on ensnode-sdk and consolidates duplicate type definitions (ChainId, AccountId, UnixTimestamp, Duration). A new ENSReferralsClient class is introduced in ens-referrals to handle referral-specific API requests, following the design pattern of ENSNodeClient.

Changes

Cohort / File(s) Summary
New ENSReferralsClient
packages/ens-referrals/src/client.ts
Introduces new ENSReferralsClient class with methods getReferrerLeaderboardPage() and getReferrerDetail(), mirroring referral endpoint APIs with URL building, JSON parsing, and deserialization (254 lines).
Dependency and Type Consolidation
packages/ens-referrals/package.json, packages/ensnode-sdk/package.json
Adds @ensnode/ensnode-sdk as a dependency to ens-referrals; removes @namehash/ens-referrals from ensnode-sdk dependencies. Adds ./internal export entry and new public export block in ens-referrals.
Type Re-exports from ensnode-sdk
packages/ens-referrals/src/time.ts, packages/ens-referrals/src/rules.ts, packages/ens-referrals/src/rank.ts, packages/ens-referrals/src/referrer-metrics.ts, packages/ens-referrals/src/leaderboard.ts, packages/ens-referrals/src/leaderboard-page.ts, packages/ens-referrals/src/referrer-detail.ts, packages/ens-referrals/src/aggregations.ts, packages/ens-referrals/src/status.ts, packages/ens-referrals/src/score.ts
Replaces local definitions of UnixTimestamp, Duration, ChainId, and AccountId with imports from @ensnode/ensnode-sdk. Removes exported type definitions from time.ts and rules.ts.
API Module Re-structuring
packages/ens-referrals/src/api/deserialize.ts, packages/ens-referrals/src/api/serialize.ts, packages/ens-referrals/src/api/serialized-types.ts, packages/ens-referrals/src/api/types.ts, packages/ens-referrals/src/api/zod-schemas.ts
Updates import sources from external @namehash/ens-referrals barrel to granular internal modules for types and constants (e.g., AggregatedReferrerMetrics, ReferrerLeaderboardPage, ReferralProgramRules).
Public Exports and Entry Points
packages/ens-referrals/src/index.ts, packages/ens-referrals/src/internal.ts
Adds public exports for ./api and ./client; removes ./encoding export. Introduces new internal-only entry point internal.ts re-exporting zod schemas.
ENSNodeClient Refactoring
packages/ensnode-sdk/src/client.ts, packages/ensnode-sdk/src/index.ts
Removes public methods getReferrerLeaderboardPage() and getReferrerDetail() from ENSNodeClient (196 lines removed). Removes public re-export of ensanalytics module from package entry point.
Registrar Type Consolidation
packages/ensnode-sdk/src/registrars/registrar-action.ts, packages/ensnode-sdk/src/registrars/index.ts, packages/ensnode-sdk/src/registrars/encoded-referrer.ts, packages/ensnode-sdk/src/registrars/encoded-referrer.test.ts, packages/ensnode-sdk/src/registrars/zod-schemas.ts
Moves EncodedReferrer and related functions from @namehash/ens-referrals to new local ./encoded-referrer module. Updates imports and adds barrel export. Minor documentation updates to encoding validation descriptions.
Import Path Updates
apps/ensapi/src/handlers/ensanalytics-api.ts, apps/ensapi/src/handlers/ensanalytics-api.test.ts, apps/ensapi/src/lib/ensanalytics/referrer-leaderboard/get-referrer-leaderboard.ts, apps/ensapi/src/lib/ensanalytics/referrer-leaderboard/mocks.ts
Updates import sources for referral types and functions from @ensnode/ensnode-sdk to @namehash/ens-referrals to align with new package ownership.
Configuration Updates
packages/ens-referrals/tsconfig.json, packages/ens-referrals/tsup.config.ts, packages/ensnode-sdk/tsup.config.ts
Adds rootDir: "." to ens-referrals tsconfig for clarity. Adds noExternal configuration for @ensnode/ensnode-sdk in ens-referrals tsup. Removes noExternal for @namehash/ens-referrals from ensnode-sdk tsup.
Schema Documentation
packages/ensnode-schema/src/schemas/registrars.schema.ts
Updates comment documentation on decodedReferrer field to describe strict left-zero-padding validation.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 The packages did dance, a flip-flop was due,
Types consolidated, dependencies anew!
From SDK to Referrals, the client now flows,
With leaderboards and details wherever it goes. ✨
No circles, no dupes—just cleaner design,
Architecture improved, everything's fine! 🎉

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: flipping the dependency relationship between ens-referrals and ensnode-sdk packages.
Description check ✅ Passed The PR description comprehensively covers all required sections: Problem & Motivation, What Changed, Design & Planning, Self-Review, Testing Evidence, and the Pre-Review Checklist is complete.
Linked Issues check ✅ Passed The PR successfully addresses all coding requirements from issue #1519: removed ensnode-sdk dependency on ens-referrals, moved referral APIs into ens-referrals, added ENSReferralsClient, consolidated duplicate types, and preserved network-layer API compatibility.
Out of Scope Changes check ✅ Passed All changes are directly aligned with issue #1519 objectives. Type consolidations, client implementations, package dependency flipping, and referrer encoding updates are all within scope of the stated goals.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ 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/flip-dependency-ensnode-sdk-ens-referrals

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

@lightwalker-eth lightwalker-eth merged commit 500388b into main Jan 19, 2026
14 of 17 checks passed
@lightwalker-eth lightwalker-eth deleted the feat/flip-dependency-ensnode-sdk-ens-referrals branch January 19, 2026 13:26
@github-actions github-actions bot mentioned this pull request Jan 19, 2026
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: 3

Caution

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

⚠️ Outside diff range comments (1)
packages/ens-referrals/package.json (1)

20-41: Missing ./internal export in publishConfig may break consumers after publishing.

The "./internal" entry point is defined in the development exports (line 22) but is absent from publishConfig.exports. When the package is published, consumers importing from @namehash/ens-referrals/internal will encounter module resolution errors.

If this entry point is intended to be public, add the corresponding mapping to publishConfig.exports:

Proposed fix
   "publishConfig": {
     "access": "public",
     "exports": {
       ".": {
         "import": {
           "types": "./dist/index.d.ts",
           "default": "./dist/index.js"
         },
         "require": {
           "types": "./dist/index.d.cts",
           "default": "./dist/index.cjs"
         }
+      },
+      "./internal": {
+        "import": {
+          "types": "./dist/internal.d.ts",
+          "default": "./dist/internal.js"
+        },
+        "require": {
+          "types": "./dist/internal.d.cts",
+          "default": "./dist/internal.cjs"
+        }
       }
     },

If ./internal is intentionally for monorepo-only consumption, consider documenting this or using a different naming convention to signal internal use.

🤖 Fix all issues with AI agents
In `@packages/ens-referrals/src/client.ts`:
- Around line 137-151: The code unsafely asserts responseData to
SerializedReferrerLeaderboardPageResponse before deserialization; instead remove
the type assertion and explicitly validate responseData with the Zod-backed
deserializer or perform an explicit safeParse call so the shape is checked
before treating it as the expected type—update the call site around responseData
and deserializeReferrerLeaderboardPageResponse (or add a pre-check using the
same schema used by deserializeReferrerLeaderboardPageResponse) and add a short
comment clarifying that validation happens there.
- Around line 15-23: Replace the duplicated DEFAULT_ENSNODE_API_URL constant and
ClientOptions interface in this file by importing them from the shared module in
ensnode-sdk: remove the local export of DEFAULT_ENSNODE_API_URL and the local
ClientOptions interface and add imports for DEFAULT_ENSNODE_API_URL and
ClientOptions from the ensnode-sdk package, then update any local references to
use the imported symbols so the file uses the shared definitions.
- Around line 127-132: getReferrerLeaderboardPage builds the URL with the wrong
path; change the path string in the URL constructor from
`/ensanalytics/referrers` to `/api/ensanalytics/referrers` so it matches
getReferrerDetail and the rest of the SDK; update the URL creation in
packages/ens-referrals/src/client.ts inside the getReferrerLeaderboardPage logic
where new URL(...) is called and ensure subsequent query param handling (page,
recordsPerPage) remains unchanged.
♻️ Duplicate comments (6)
packages/ensnode-sdk/src/api/name-tokens/response.ts (1)

3-3: Unused import: NameTokenOwnershipTypes.

NameTokenOwnershipTypes is only referenced in JSDoc comments (lines 105-112) but never used in runtime code or type definitions. Consider removing it from the import statement.

packages/ens-referrals/tsconfig.json (1)

3-5: Comment could be more descriptive.

The inline comment explaining rootDir is terse. Consider expanding it to explain why this setting resolves the ambiguity, as noted in a prior review.

.changeset/rich-shirts-spend.md (1)

1-7: Version bump for @namehash/ens-referrals should be major.

This change removes previously exported types (UnixTimestamp, Duration, AccountId, ChainId) from @namehash/ens-referrals. Consumers importing these types will need to update their imports to use @ensnode/ensnode-sdk instead. Per semantic versioning, removing public exports constitutes a breaking change requiring a major version bump.

Proposed fix
 ---
-"@namehash/ens-referrals": minor
+"@namehash/ens-referrals": major
 "@ensnode/ensnode-sdk": minor
 "ensapi": patch
 ---
packages/ens-referrals/src/internal.ts (1)

1-15: Misleading documentation about NPM package inclusion.

Line 8 states "This file can never be included in the NPM package" but this contradicts the package.json export configuration. The file must be included in the published package for the @namehash/ens-referrals/internal import path to function.

packages/ensnode-sdk/src/registrars/registrar-action.ts (1)

154-155: Documentation describes decoding from a null value.

The comment states the referrer is "decoded from encodedReferrer using strict left-zero-padding validation" but encodedReferrer is null for this interface. The documentation should clarify that decodedReferrer is null because encodedReferrer is null.

packages/ens-referrals/src/client.ts (1)

50-254: Missing test coverage for ENSReferralsClient.

The new client class lacks unit tests. Other modules in this package have corresponding test files (e.g., leaderboard-page.test.ts). Tests should cover URL construction, success/error response handling, and JSON parsing edge cases.

Comment on lines +15 to +23
export const DEFAULT_ENSNODE_API_URL = "https://api.alpha.ensnode.io" as const;

/**
* Configuration options for ENS Referrals API client
*/
export interface ClientOptions {
/** The ENSNode API URL */
url: URL;
}
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider importing shared constants from ensnode-sdk.

DEFAULT_ENSNODE_API_URL and ClientOptions are duplicated from packages/ensnode-sdk/src/client.ts. Since ens-referrals now depends on ensnode-sdk, consider importing these to avoid duplication and ensure consistency.

♻️ Proposed refactor
+import {
+  DEFAULT_ENSNODE_API_URL,
+  type ClientOptions,
+} from "@ensnode/ensnode-sdk";
+
 import {
   deserializeReferrerDetailResponse,
   deserializeReferrerLeaderboardPageResponse,
   ...
 } from "./api";

-/**
- * Default ENSNode API endpoint URL
- */
-export const DEFAULT_ENSNODE_API_URL = "https://api.alpha.ensnode.io" as const;
-
-/**
- * Configuration options for ENS Referrals API client
- */
-export interface ClientOptions {
-  /** The ENSNode API URL */
-  url: URL;
-}
📝 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
export const DEFAULT_ENSNODE_API_URL = "https://api.alpha.ensnode.io" as const;
/**
* Configuration options for ENS Referrals API client
*/
export interface ClientOptions {
/** The ENSNode API URL */
url: URL;
}
import {
DEFAULT_ENSNODE_API_URL,
type ClientOptions,
} from "@ensnode/ensnode-sdk";
import {
deserializeReferrerDetailResponse,
deserializeReferrerLeaderboardPageResponse,
} from "./api";
🤖 Prompt for AI Agents
In `@packages/ens-referrals/src/client.ts` around lines 15 - 23, Replace the
duplicated DEFAULT_ENSNODE_API_URL constant and ClientOptions interface in this
file by importing them from the shared module in ensnode-sdk: remove the local
export of DEFAULT_ENSNODE_API_URL and the local ClientOptions interface and add
imports for DEFAULT_ENSNODE_API_URL and ClientOptions from the ensnode-sdk
package, then update any local references to use the imported symbols so the
file uses the shared definitions.

Comment on lines +127 to +132
const url = new URL(`/ensanalytics/referrers`, this.options.url);

if (request?.page) url.searchParams.set("page", request.page.toString());
if (request?.recordsPerPage)
url.searchParams.set("recordsPerPage", request.recordsPerPage.toString());

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# First, let's examine the actual file and see both methods in context
cat -n packages/ens-referrals/src/client.ts | sed -n '120,140p'

Repository: namehash/ensnode

Length of output: 943


🏁 Script executed:

# Now let's check the getReferrerDetail method around line 232
cat -n packages/ens-referrals/src/client.ts | sed -n '225,240p'

Repository: namehash/ensnode

Length of output: 711


🏁 Script executed:

# Let's also check the full structure to understand URL construction
cat -n packages/ens-referrals/src/client.ts | sed -n '1,50p'

Repository: namehash/ensnode

Length of output: 1600


🏁 Script executed:

# Search for all URL path patterns in this file
rg -n "new URL|url.searchParams|\/ensanalytics|\/api" packages/ens-referrals/src/client.ts -C 2

Repository: namehash/ensnode

Length of output: 196


🏁 Script executed:

# Let's search for other URL patterns in the file to see if there's a consistent pattern
cat -n packages/ens-referrals/src/client.ts | grep -E "new URL|\/api|ensanalytics" -A 1 -B 1

Repository: namehash/ensnode

Length of output: 968


🏁 Script executed:

# Check if there are other similar methods and their URL patterns
rg "new URL" packages/ens-referrals/src/client.ts -A 2

Repository: namehash/ensnode

Length of output: 527


🏁 Script executed:

# Let's also check the ensnode-sdk client to see what pattern it uses
cat -n packages/ensnode-sdk/src/client.ts | head -100

Repository: namehash/ensnode

Length of output: 3377


🏁 Script executed:

# Search for URL patterns in ensnode-sdk to understand the convention
rg "new URL" packages/ensnode-sdk/src/client.ts -A 2 -B 1

Repository: namehash/ensnode

Length of output: 1649


Fix inconsistent API path in getReferrerLeaderboardPage.

Line 127 uses /ensanalytics/referrers but should use /api/ensanalytics/referrers to match getReferrerDetail (line 232) and the standard pattern used throughout the codebase (all methods in ensnode-sdk use /api/ prefix).

🤖 Prompt for AI Agents
In `@packages/ens-referrals/src/client.ts` around lines 127 - 132,
getReferrerLeaderboardPage builds the URL with the wrong path; change the path
string in the URL constructor from `/ensanalytics/referrers` to
`/api/ensanalytics/referrers` so it matches getReferrerDetail and the rest of
the SDK; update the URL creation in packages/ens-referrals/src/client.ts inside
the getReferrerLeaderboardPage logic where new URL(...) is called and ensure
subsequent query param handling (page, recordsPerPage) remains unchanged.

Comment on lines +137 to +151
let responseData: unknown;
try {
responseData = await response.json();
} catch {
throw new Error("Malformed response data: invalid JSON");
}

// The API can return errors with 500 status, but they're still in the
// PaginatedAggregatedReferrersResponse format with responseCode: 'error'
// So we don't need to check response.ok here, just deserialize and let
// the caller handle the responseCode

return deserializeReferrerLeaderboardPageResponse(
responseData as SerializedReferrerLeaderboardPageResponse,
);
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Unsafe type assertion on unknown response data.

The responseData as SerializedReferrerLeaderboardPageResponse assertion bypasses type checking. While the subsequent deserializeReferrerLeaderboardPageResponse validates via Zod, a more explicit approach would improve clarity.

♻️ Consider explicit unknown handling

The current pattern works because the deserialize functions perform Zod validation. Consider documenting this reliance or adding a comment clarifying that validation occurs in the deserialize step.

-    return deserializeReferrerLeaderboardPageResponse(
-      responseData as SerializedReferrerLeaderboardPageResponse,
-    );
+    // Zod validation occurs within deserializeReferrerLeaderboardPageResponse
+    return deserializeReferrerLeaderboardPageResponse(
+      responseData as SerializedReferrerLeaderboardPageResponse,
+    );
🤖 Prompt for AI Agents
In `@packages/ens-referrals/src/client.ts` around lines 137 - 151, The code
unsafely asserts responseData to SerializedReferrerLeaderboardPageResponse
before deserialization; instead remove the type assertion and explicitly
validate responseData with the Zod-backed deserializer or perform an explicit
safeParse call so the shape is checked before treating it as the expected
type—update the call site around responseData and
deserializeReferrerLeaderboardPageResponse (or add a pre-check using the same
schema used by deserializeReferrerLeaderboardPageResponse) and add a short
comment clarifying that validation happens there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ensanalytics ENSAnalytics related ensnode-sdk ensnode-sdk related

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Flip dependency relationship between the ens-referrals and ensnode-sdk packages

3 participants