Skip to content

Conversation

@tk-o
Copy link
Contributor

@tk-o tk-o commented Jan 16, 2026

Substantial PR


Reviewer Focus (Read This First)

What reviewers should focus on

Where should reviewers spend most of their time?

Call out:

  • The risky or non-obvious parts
  • Areas where you're least confident
  • The kind of feedback you actually want

If your answer is "everything," explain why targeted review isn't possible.

Limit this to 1-3 areas.

ENSNode SDK has a new result module to introduce standardized response data model for ENSNode APIs.


Problem & Motivation

Why this exists

Explain:

  • What problem this PR is solving
  • What's broken, fragile, or getting worse without it
  • Why this change is happening now
  • Links to issues, incidents, or prior discussion

Keep this tight. Bullets are fine.

  • This PR is to introduce a data model suitable for ENSNode API responses.
  • Right now, each ENSNode API has its own data model, which decreases developer experience.
  • The team needs to soon enhance multiple ENSNode APIs, and this PR defines foundation for all of the APIs data model enhancements.
  • Prior discussion: https://namehash.slack.com/archives/C086Z6FNBHN/p1768234891200099

What Changed (Concrete)

What actually changed

List the concrete behavioral or structural changes in this PR.

This should be a factual inventory, not a narrative.
Prefer numbered bullets.

If this list starts getting long, that's a signal the PR may need splitting.

  1. ENSNode SDK includes new data types.

Design & Planning

How this approach was chosen
  • Link any design docs or notes that existed before or during implementation
  • If this didn't warrant upfront design, say why
  • Mention the most realistic alternatives you considered and why you didn't take them
  • If planning was lightweight, be explicit about that

Self-Review

What you caught yourself

Describe what changed after you reviewed your own diff end-to-end.

This is not optional.

  • Bugs caught:
  • Logic simplified:
  • Naming / terminology improved:
  • Dead or unnecessary code removed (or why none was):

Cross-Codebase Alignment

Related code you checked

Show that you looked beyond just the files in this PR.

  • Terms you searched for to find related code or docs
  • Files or packages you reviewed but intentionally didn't change
  • Areas you left alone on purpose (and why)

Focus on directly related domains. Don't boil the ocean.

  • Search terms used:
  • Reviewed but unchanged:
  • Deferred alignment (with rationale):

Downstream & Consumer Impact

Who this affects and how

Explain how this change impacts:

  • Callers
  • Readers
  • Operators
  • Future maintainers

Call out:

  • Terminology or concepts that might confuse someone new
  • What you changed to reduce that confusion

Point to actual diffs where possible.

  • Public APIs affected:
  • Docs updated:
  • Naming decisions worth calling out:

Testing Evidence

How this was validated

Explain:

  • How this was tested locally and/or in CI
  • What important behavior is not covered by tests
  • If this is wrong, what breaks first
  • Testing performed:
  • Known gaps:
  • What reviewers have to reason about manually (and why):

Scope Reductions

What you intentionally didn't do

List follow-ups you identified but explicitly deferred to keep this PR reviewable.

Link issues where applicable and explain the tradeoffs.

  • Follow-ups:
  • Why they were deferred:

Risk Analysis

How this could go wrong

Call out:

  • Assumptions this PR relies on
  • Likely failure modes
  • Blast radius if it breaks
  • Risk areas:
  • Mitigations or rollback options:
  • Named owner if this causes problems:

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

  • New Features

    • Added standardized Result pattern system for operation outcome handling across the SDK
    • Introduced result classifications for success, error, and loading states
    • Added common error result builders and utilities
    • Included comprehensive examples for client and server implementations
    • Made result module publicly available through shared package exports
  • Tests

    • Added test coverage for result builders and validation utilities

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

@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 17, 2026 6:31pm
ensnode.io Ready Ready Preview, Comment Jan 17, 2026 6:31pm
ensrainbow.io Ready Ready Preview, Comment Jan 17, 2026 6:31pm

@changeset-bot
Copy link

changeset-bot bot commented Jan 16, 2026

⚠️ No Changeset found

Latest commit: 9375823

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

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

@tk-o
Copy link
Contributor Author

tk-o commented Jan 16, 2026

@greptile review

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Jan 16, 2026

Greptile Summary

Introduced a standardized Result<OkType, ErrorType> type to provide consistent response handling across ENSNode APIs. The implementation includes type-safe value/error codes, transient error marking for retry logic, utility functions for construction, and comprehensive type guards for narrowing.

  • New result module with types, utilities, and comprehensive tests
  • Generic Result type supports discriminated unions via resultCode field
  • ResultOk requires valueCode property for granular success state differentiation
  • ResultError requires errorCode property with optional transient flag for retry scenarios
  • Type guards (isResult, isResultOk, isResultError, isErrorTransient) enable type-safe pattern matching
  • Test suite demonstrates real-world usage patterns with multiple success/error states

Confidence Score: 5/5

  • Safe to merge - well-designed foundation with comprehensive tests and no runtime impact
  • This is purely additive code introducing new types and utilities without modifying existing functionality. The implementation follows TypeScript best practices with proper generics, type guards, and discriminated unions. Comprehensive test coverage validates all code paths and demonstrates intended usage patterns.
  • No files require special attention

Important Files Changed

Filename Overview
packages/ensnode-sdk/src/shared/result/types.ts Defines generic Result<OkType, ErrorType> type with value/error codes, transient error marking
packages/ensnode-sdk/src/shared/result/utils.ts Provides utility functions for creating results and type guards with proper type narrowing
packages/ensnode-sdk/src/shared/result/utils.test.ts Comprehensive test suite demonstrating Result type usage and validating all utility functions

Sequence Diagram

sequenceDiagram
    participant Client as API Consumer
    participant API as ENSNode API
    participant Result as Result Module
    
    Note over Client,Result: Success Path
    Client->>API: Call operation(params)
    API->>Result: resultOk({ valueCode, data })
    Result-->>API: ResultOk<ValueType>
    API-->>Client: { resultCode: "ok", value: { valueCode, ...data } }
    Client->>Client: isResultOk() → true
    Client->>Client: Switch on value.valueCode
    
    Note over Client,Result: Error Path (Non-Transient)
    Client->>API: Call operation(invalid_params)
    API->>Result: resultError({ errorCode, message })
    Result-->>API: ResultError<ErrorType>
    API-->>Client: { resultCode: "error", value: { errorCode, message } }
    Client->>Client: isResultError() → true
    Client->>Client: Handle error based on errorCode
    
    Note over Client,Result: Error Path (Transient)
    Client->>API: Call operation(params)
    API->>Result: errorTransient({ errorCode })
    Result->>Result: Add transient: true flag
    API->>Result: resultError(transientError)
    Result-->>API: ResultError<ErrorTransient<ErrorType>>
    API-->>Client: { resultCode: "error", value: { errorCode, transient: true } }
    Client->>Client: isResultError() → true
    Client->>Client: isErrorTransient() → true
    Client->>Client: Retry operation
Loading

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.

5 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

@tk-o
Copy link
Contributor Author

tk-o commented Jan 16, 2026

@greptile review

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 a new generic Result type to the ENSNode SDK, providing a standardized way to represent operation outcomes with both successful and error states. The Result type follows functional programming patterns and includes utilities for type checking and error handling.

Changes:

  • Added a new result module with generic types for representing operation outcomes
  • Implemented builder functions and type guards for working with Result types
  • Added support for marking errors as transient for retry logic
  • Included comprehensive tests demonstrating usage patterns

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
packages/ensnode-sdk/src/shared/result/types.ts Defines the core Result type system including ResultOk, ResultError, and ErrorTransient types
packages/ensnode-sdk/src/shared/result/utils.ts Provides utility functions for building and type-checking Result instances
packages/ensnode-sdk/src/shared/result/utils.test.ts Comprehensive test suite demonstrating Result type usage patterns
packages/ensnode-sdk/src/shared/result/index.ts Exports all public types and utilities from the result module
packages/ensnode-sdk/src/shared/index.ts Re-exports the result module for SDK consumers

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

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.

@tk-o Thanks. Reviewed and shared feedback

Co-authored-by: Copilot <[email protected]>
Co-authored-by: Tomasz Kopacki <[email protected]>
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 12 out of 12 changed files in this pull request and generated 9 comments.


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

return buildResultExampleOpOk("example.eth");
} else {
return buildResultInternalServerError(
"Invariant violation: random number is not less than 0.5",
Copy link

Copilot AI Jan 17, 2026

Choose a reason for hiding this comment

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

The error message is confusing. When Math.random() < 0.5 is false, it means the random number is greater than or equal to 0.5. The message "random number is not less than 0.5" is technically correct but awkward. Consider using a clearer message such as "random number is greater than or equal to 0.5" or "random number exceeded threshold".

Suggested change
"Invariant violation: random number is not less than 0.5",
"Invariant violation: random number is greater than or equal to 0.5",

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +143
/**
* Classifies a result returned by an operation.
*/
export const ResultCodes = {
/**
* Indefinite result.
*/
Loading: "loading",

/**
* Successful result.
*/
Ok: "ok",

/**
* Server error: the operation failed due to an unexpected error internally within the server.
*/
InternalServerError: "internal-server-error",

/**
* Server error: the requested resource was not found.
*/
NotFound: "not-found",

/**
* Server error: the request was invalid.
*/
InvalidRequest: "invalid-request",

/**
* Client error: the connection to the server failed.
*/
ConnectionError: "connection-error",

/**
* Client error: the request timed out.
*/
RequestTimeout: "request-timeout",

/**
* Client error: received an unrecognized result from the server for an operation.
*/
ClientUnrecognizedOperationResult: "client-unrecognized-operation-result",
} as const;

/**
* List of ResultCodes that represent server error results.
*/
export const RESULT_CODE_SERVER_ERROR_CODES = [
ResultCodes.InternalServerError,
ResultCodes.NotFound,
ResultCodes.InvalidRequest,
] as const;

/**
* List of ResultCodes that represent client error results.
*/
export const RESULT_CODE_CLIENT_ERROR_CODES = [
ResultCodes.ConnectionError,
ResultCodes.RequestTimeout,
ResultCodes.ClientUnrecognizedOperationResult,
] as const;

/**
* List of all error codes the client can return (client-originated + relayed from server).
*/
export const RESULT_CODE_ALL_ERROR_CODES = [
...RESULT_CODE_CLIENT_ERROR_CODES,
...RESULT_CODE_SERVER_ERROR_CODES,
] as const;

/**
* List of all ResultCodes.
*/
export const RESULT_CODE_ALL_CODES = [
ResultCodes.Loading,
ResultCodes.Ok,
...RESULT_CODE_ALL_ERROR_CODES,
] as const;

/**
* Classifies a result returned by an operation.
*/
export type ResultCode = (typeof ResultCodes)[keyof typeof ResultCodes];

/**
* ResultCode for a result that is not yet determined.
*/
export type ResultCodeIndefinite = typeof ResultCodes.Loading;

/**
* ResultCode for a result that has been determined.
*/
export type ResultCodeDefinite = Exclude<ResultCode, ResultCodeIndefinite>;

/**
* ResultCode for an error result that may be determined by the server.
*/
export type ResultCodeServerError = (typeof RESULT_CODE_SERVER_ERROR_CODES)[number];

/**
* ResultCode for an error result that may be determined by the client.
*/
export type ResultCodeClientError = (typeof RESULT_CODE_CLIENT_ERROR_CODES)[number];

/************************************************************
* Compile-time helpers to ensure invariants expected of
* definitions above are maintained and don't become
* out of sync.
************************************************************/

export type ExpectTrue<T extends true> = T;

export type ResultCodesFromList<List extends readonly ResultCode[]> = List[number];

export type AssertResultCodeSuperset<
Union extends ResultCode,
List extends readonly ResultCode[],
> = Union extends ResultCodesFromList<List> ? true : false;

export type AssertResultCodeSubset<
Union extends ResultCode,
List extends readonly ResultCode[],
> = ResultCodesFromList<List> extends Union ? true : false;

export type AssertResultCodeExact<
Union extends ResultCode,
List extends readonly ResultCode[],
> = AssertResultCodeSuperset<Union, List> extends true
? AssertResultCodeSubset<Union, List> extends true
? true
: false
: false;

/**
* Intentionally unused type alias used only for compile-time verification that
* the `ResultCode` union exactly matches the entries in `RESULT_CODE_ALL_CODES`.
* If this type ever fails to compile, it indicates that one of the above
* invariants has been broken and the result code definitions are out of sync.
*/
type _CompileTimeCheck_ResultCodeMatchesUnion = ExpectTrue<
AssertResultCodeExact<ResultCode, typeof RESULT_CODE_ALL_CODES>
>;
Copy link

Copilot AI Jan 17, 2026

Choose a reason for hiding this comment

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

The result-code.ts file lacks dedicated test coverage. While the compile-time type assertions provide some validation, runtime tests would be valuable for verifying the exported constants and type guards. Consider adding a result-code.test.ts file to test the structure of ResultCodes, the correctness of the categorized lists (RESULT_CODE_SERVER_ERROR_CODES, RESULT_CODE_CLIENT_ERROR_CODES, RESULT_CODE_ALL_CODES), and any runtime behavior.

Copilot uses AI. Check for mistakes.
): ResultInternalServerError => {
return {
resultCode: ResultCodes.InternalServerError,
errorMessage: errorMessage ?? "An unknown internal server error occurred.",
Copy link

Copilot AI Jan 17, 2026

Choose a reason for hiding this comment

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

The error message parameter uses the nullish coalescing operator which only checks for null or undefined. If an empty string is passed, it will be used instead of the default message, potentially resulting in error results with empty error messages. Consider using a truthy check instead, such as errorMessage || "An unknown internal server error occurred." to fall back to the default message when an empty string is provided.

Copilot uses AI. Check for mistakes.
): ResultInvalidRequest => {
return {
resultCode: ResultCodes.InvalidRequest,
errorMessage: errorMessage ?? "Invalid request.",
Copy link

Copilot AI Jan 17, 2026

Choose a reason for hiding this comment

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

The error message parameter uses the nullish coalescing operator which only checks for null or undefined. If an empty string is passed, it will be used instead of the default message, potentially resulting in error results with empty error messages. Consider using a truthy check instead, such as errorMessage || "Invalid request." to fall back to the default message when an empty string is provided.

Copilot uses AI. Check for mistakes.
): ResultConnectionError => {
return {
resultCode: ResultCodes.ConnectionError,
errorMessage: errorMessage ?? "Connection error.",
Copy link

Copilot AI Jan 17, 2026

Choose a reason for hiding this comment

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

The error message parameter uses the nullish coalescing operator which only checks for null or undefined. If an empty string is passed, it will be used instead of the default message, potentially resulting in error results with empty error messages. Consider using a truthy check instead, such as errorMessage || "Connection error." to fall back to the default message when an empty string is provided.

Copilot uses AI. Check for mistakes.
"errorMessage" in unrecognizedResult &&
typeof unrecognizedResult.errorMessage === "string"
) {
errorMessage = unrecognizedResult.errorMessage;
Copy link

Copilot AI Jan 17, 2026

Choose a reason for hiding this comment

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

The extracted errorMessage is not validated for empty strings. If the unrecognizedResult object contains an empty string for errorMessage, it will be used instead of the default message, potentially resulting in an error result with an empty error message. Consider adding a truthy check, such as checking if the errorMessage is not empty before using it.

Suggested change
errorMessage = unrecognizedResult.errorMessage;
const candidateErrorMessage = unrecognizedResult.errorMessage;
if (candidateErrorMessage.trim().length > 0) {
errorMessage = candidateErrorMessage;
}

Copilot uses AI. Check for mistakes.
Comment on lines +48 to +54
} catch (error) {
// handle client-side errors
if (error === "connection-error") {
return buildResultConnectionError();
} else {
return buildResultRequestTimeout();
}
Copy link

Copilot AI Jan 17, 2026

Choose a reason for hiding this comment

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

The error handling pattern here is unrealistic. The condition error === "connection-error" suggests errors are thrown as string literals, which is not typical JavaScript/TypeScript practice. While this is example code meant for demonstration, it could mislead developers. Consider using a more realistic pattern such as checking error types or error codes from actual Error objects, or add a comment explaining that this is simplified for demonstration purposes.

Copilot uses AI. Check for mistakes.
): ResultNotFound => {
return {
resultCode: ResultCodes.NotFound,
errorMessage: errorMessage ?? "Requested resource not found.",
Copy link

Copilot AI Jan 17, 2026

Choose a reason for hiding this comment

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

The error message parameter uses the nullish coalescing operator which only checks for null or undefined. If an empty string is passed, it will be used instead of the default message, potentially resulting in error results with empty error messages. Consider using a truthy check instead, such as errorMessage || "Requested resource not found." to fall back to the default message when an empty string is provided.

Copilot uses AI. Check for mistakes.
): ResultRequestTimeout => {
return {
resultCode: ResultCodes.RequestTimeout,
errorMessage: errorMessage ?? "Request timed out.",
Copy link

Copilot AI Jan 17, 2026

Choose a reason for hiding this comment

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

The error message parameter uses the nullish coalescing operator which only checks for null or undefined. If an empty string is passed, it will be used instead of the default message, potentially resulting in error results with empty error messages. Consider using a truthy check instead, such as errorMessage || "Request timed out." to fall back to the default message when an empty string is provided.

Copilot uses AI. Check for mistakes.
@coderabbitai
Copy link

coderabbitai bot commented Jan 17, 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 introduces a comprehensive result handling system for the ENSNode SDK. It establishes abstract base interfaces for different result states (Ok, Error, Loading), defines a centralized result code classification system with server and client error variants, provides concrete error result types with builder functions, and includes practical examples demonstrating how to structure server operations, client wrappers, React hooks, and routing patterns using the Result data model.

Changes

Cohort / File(s) Summary
Result System Foundation
packages/ensnode-sdk/src/shared/result/result-code.ts
Introduces ResultCodes constant with string literals for all possible outcomes (Loading, Ok, InternalServerError, InvalidRequest, NotFound, ConnectionError, RequestTimeout, ClientUnrecognizedOperationResult). Provides type aggregations for server error codes, client error codes, and all codes. Includes compile-time verification utilities (ExpectTrue, AssertResultCodeExact, AssertResultCodeSuperset, AssertResultCodeSubset) to enforce type safety and consistency between code definitions and unions.
Result System Foundation
packages/ensnode-sdk/src/shared/result/result-base.ts
Defines abstract base interfaces: AbstractResult, AbstractResultOk with fixed Ok resultCode and data field, AbstractResultError with errorMessage/suggestRetry/optional data, and AbstractResultLoading with optional data. Establishes the type hierarchy for all result variants.
Result System Foundation
packages/ensnode-sdk/src/shared/result/result-common.ts
Implements concrete error result types (InternalServerError, NotFound, InvalidRequest, ConnectionError, RequestTimeout, ClientUnrecognizedOperationResult) and corresponding builder functions with default error messages and suggestRetry flags. Provides isRecognizedResultCodeForOperation() utility for result code validation. Defines ResultClientError discriminated union.
Testing
packages/ensnode-sdk/src/shared/result/result-common.test.ts
Comprehensive test suite covering all builder functions with various input scenarios (custom/default messages, suggestRetry handling, edge cases like null/undefined inputs, object property extraction, extraneous properties). Tests isRecognizedResultCodeForOperation utility with known/unknown codes and empty lists.
Module Exports
packages/ensnode-sdk/src/shared/result/index.ts, packages/ensnode-sdk/src/shared/index.ts
Centralizes public API by re-exporting result-base, result-code, and result-common from result/index.ts. Exposes result module through shared/index.ts for top-level access.
Server-Side Example
packages/ensnode-sdk/src/shared/result/examples/op-server.ts
Demonstrates a Result-driven server operation exampleOp(address) returning ExampleOpServerResult union (Ok, InternalServerError, InvalidRequest). Defines ResultExampleOpOkData interface with name field, buildResultExampleOpOk builder, EXAMPLE_OP_RECOGNIZED_SERVER_RESULT_CODES constant, and runtime logic that returns InvalidRequest for zero address, otherwise randomly returns Ok or InternalServerError. Includes compile-time assertion validating union matches recognized codes.
Client-Side Wrapper
packages/ensnode-sdk/src/shared/result/examples/op-client.ts
Wraps server operation with client error handling. Defines callExampleOp() that invokes server exampleOp(), validates resultCode against EXAMPLE_OP_RECOGNIZED_SERVER_RESULT_CODES via isRecognizedResultCodeForOperation, returns unrecognized-operation client result when unrecognized, catches connection errors and request timeouts, and maps to appropriate client error results.
Hook-Based Example
packages/ensnode-sdk/src/shared/result/examples/op-hook.ts
Provides useExampleOp() hook returning ExampleOpHookResult (union of operation result or loading state). Defines ExampleOpLoadingData interface and ResultExampleOpLoading type extending AbstractResultLoading. Implements buildResultExampleOpLoading() builder. Hook randomly returns loading state or delegates to callExampleOp for concrete result.
Developer Experience Example
packages/ensnode-sdk/src/shared/result/examples/dx-client.ts
Shows how to consume operation result in client code. Function myExampleDXClient(address) calls callExampleOp(), branches on resultCode (Ok vs error), logs data.name on success, logs error details including resultCode/errorMessage on failure, and conditionally logs retry hint when suggestRetry is true. Includes inline type-narrowing comments.
Developer Experience Hook Example
packages/ensnode-sdk/src/shared/result/examples/dx-hook.ts
Demonstrates hook consumption pattern. Function myExampleDXHook(address) uses useExampleOp(), handles Loading/Ok/error cases with appropriate logging, displays data.name on success, logs error with resultCode, and shows retry prompt when suggestRetry is true.
Router Pattern Example
packages/ensnode-sdk/src/shared/result/examples/server-router.ts
Illustrates server-side routing with Result model. Function _routeRequest(path) routes "/example" to exampleOp, returns NotFound for unmatched paths, catches errors and returns InternalServerError. Demonstrates consistent Result return type across all paths.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Client Code
    participant Wrapper as op-client<br/>(callExampleOp)
    participant Server as op-server<br/>(exampleOp)
    participant ErrorHandler as Error Handler

    Client->>Wrapper: callExampleOp(address)
    Wrapper->>Server: exampleOp(address)
    alt Valid Address
        Server-->>Wrapper: Ok or InternalServerError
        Wrapper->>Wrapper: isRecognized?
        alt Recognized ResultCode
            Wrapper-->>Client: ExampleOpServerResult
        else Unrecognized Code
            Wrapper-->>Client: ClientUnrecognizedOperationResult
        end
    else Invalid Address (zero)
        Server-->>Wrapper: InvalidRequest
        Wrapper-->>Client: InvalidRequest
    else Exception Thrown
        ErrorHandler->>ErrorHandler: Catch error
        alt Connection Error
            ErrorHandler-->>Client: ResultConnectionError
        else Request Timeout
            ErrorHandler-->>Client: ResultRequestTimeout
        end
    end
Loading
sequenceDiagram
    participant DXHook as dx-hook<br/>(myExampleDXHook)
    participant Hook as op-hook<br/>(useExampleOp)
    participant Wrapper as op-client<br/>(callExampleOp)
    participant Server as op-server<br/>(exampleOp)

    DXHook->>Hook: useExampleOp(address)
    alt Random: Return Loading
        Hook->>Hook: buildResultExampleOpLoading()
        Hook-->>DXHook: ResultExampleOpLoading
        DXHook->>DXHook: Log loading state
    else Random: Return Result
        Hook->>Wrapper: callExampleOp(address)
        Wrapper->>Server: exampleOp(address)
        Server-->>Wrapper: ExampleOpServerResult
        Wrapper-->>Hook: ExampleOpClientResult
        Hook-->>DXHook: ExampleOpClientResult
        alt Success (Ok)
            DXHook->>DXHook: Log data.name
        else Error
            DXHook->>DXHook: Log resultCode & errorMessage
            alt suggestRetry = true
                DXHook->>DXHook: Log retry hint
            end
        end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 A system of Results, both grand and small,
With codes that dance and builders that call,
From server to client, through hooks we glide,
Error and success walking side by side! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is largely a template with incomplete sections; critical sections like Self-Review, Cross-Codebase Alignment, Testing Evidence, and Risk Analysis remain unfilled or contain only placeholders. Complete the template sections, especially Self-Review (what was caught), Testing Evidence (how it was tested), and Risk Analysis (assumptions and failure modes), to provide reviewers with actionable context.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(ensnode-sdk): define a generic Result type' is specific and clearly describes the main change - introducing a standardized Result type to the ENSNode SDK.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ 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/ensnode-result-type

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

@lightwalker-eth
Copy link
Member

@CodeRabbit review

@coderabbitai
Copy link

coderabbitai bot commented Jan 17, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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

🤖 Fix all issues with AI agents
In `@packages/ensnode-sdk/src/shared/result/examples/op-hook.ts`:
- Around line 28-34: The function useExampleOp misleadingly uses the React "use"
prefix but does not call any hooks; rename the exported symbol useExampleOp to
getExampleOpResult (and update all internal references/imports) to avoid
violating the Hooks naming convention, or alternatively add a top-of-file
comment above the function clarifying that it is a synchronous example and not a
React hook; update any tests or imports that reference useExampleOp and keep the
existing logic in buildResultExampleOpLoading and callExampleOp unchanged.
♻️ Duplicate comments (3)
packages/ensnode-sdk/src/shared/result/result-common.ts (1)

8-23: Standard builder pattern for internal server errors.

The interface and builder correctly implement the error result pattern with sensible defaults (suggestRetry: true for transient server errors).

The use of ?? for errorMessage was previously discussed. Empty strings would be accepted rather than falling back to the default.

packages/ensnode-sdk/src/shared/result/examples/op-client.ts (1)

48-54: Error handling uses unrealistic pattern for example code.

The condition error === "connection-error" suggests errors are thrown as string literals, which is not typical JavaScript/TypeScript practice. Consider adding a clarifying comment or using a more realistic pattern like checking error instanceof Error and inspecting error properties.

packages/ensnode-sdk/src/shared/result/examples/op-server.ts (1)

66-68: Consider a clearer error message wording.

The message "random number is not less than 0.5" is technically accurate but reads awkwardly. A clearer phrasing would be "random number is greater than or equal to 0.5" or "random number exceeded threshold".

Comment on lines +28 to +34
export const useExampleOp = (address: Address): ExampleOpHookResult => {
if (Math.random() < 0.5) {
return buildResultExampleOpLoading(address);
} else {
return callExampleOp(address);
}
};
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Hook naming may mislead developers.

The function useExampleOp uses the use prefix convention for React hooks, but it doesn't use any React hooks internally (no useState, useEffect, etc.). In React, the use prefix signals that a function follows the Rules of Hooks. Consider either:

  1. Adding a comment clarifying this is a simplified example
  2. Renaming to something like getExampleOpResult to avoid confusion
🤖 Prompt for AI Agents
In `@packages/ensnode-sdk/src/shared/result/examples/op-hook.ts` around lines 28 -
34, The function useExampleOp misleadingly uses the React "use" prefix but does
not call any hooks; rename the exported symbol useExampleOp to
getExampleOpResult (and update all internal references/imports) to avoid
violating the Hooks naming convention, or alternatively add a top-of-file
comment above the function clarifying that it is a synchronous example and not a
React hook; update any tests or imports that reference useExampleOp and keep the
existing logic in buildResultExampleOpLoading and callExampleOp unchanged.

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