Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ErrorResponse } from "./ensapi/api/shared/errors/response";
import type { ErrorResponse } from "./api/shared/errors/response";

export class ClientError extends Error {
details?: unknown;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import type { Address } from "viem";
import { beforeEach, describe, expect, it, vi } from "vitest";

import { ENSNodeClient } from "./client";
import { ClientError } from "./client-error";
import { DEFAULT_ENSNODE_API_URL_MAINNET, getDefaultEnsNodeUrl } from "./deployments";
import { ENSNamespaceIds, type Name } from "./ens";
import { deserializeENSApiPublicConfig, type SerializedENSApiPublicConfig } from "./ensapi";
import { ENSNamespaceIds, type Name } from "../ens";
import { PluginName } from "../ensindexer/config/types";
import {
ChainIndexingConfigTypeIds,
ChainIndexingStatusIds,
} from "../indexing-status/chain-indexing-status-snapshot";
import { CrossChainIndexingStrategyIds } from "../indexing-status/cross-chain-indexing-status-snapshot";
import { OmnichainIndexingStatusIds } from "../indexing-status/omnichain-indexing-status-snapshot";
import type { SerializedOmnichainIndexingStatusSnapshotFollowing } from "../indexing-status/serialize/omnichain-indexing-status-snapshot";
import type { ResolverRecordsSelection } from "../resolution";
import {
deserializeIndexingStatusResponse,
type ErrorResponse,
Expand All @@ -15,16 +20,12 @@ import {
type ResolvePrimaryNamesResponse,
type SerializedIndexingStatusResponseOk,
serializeIndexingStatusResponse,
} from "./ensapi/api";
import { PluginName } from "./ensindexer/config/types";
import {
ChainIndexingConfigTypeIds,
ChainIndexingStatusIds,
} from "./indexing-status/chain-indexing-status-snapshot";
import { CrossChainIndexingStrategyIds } from "./indexing-status/cross-chain-indexing-status-snapshot";
import { OmnichainIndexingStatusIds } from "./indexing-status/omnichain-indexing-status-snapshot";
import type { SerializedOmnichainIndexingStatusSnapshotFollowing } from "./indexing-status/serialize/omnichain-indexing-status-snapshot";
import type { ResolverRecordsSelection } from "./resolution";
} from "./api";
import { ENSApiClient } from "./client";
import { ClientError } from "./client-error";
import { deserializeENSApiPublicConfig } from "./config/deserialize";
import type { SerializedENSApiPublicConfig } from "./config/serialized-types";
import { DEFAULT_ENSNODE_API_URL_MAINNET, getDefaultEnsNodeUrl } from "./deployments";

const EXAMPLE_NAME: Name = "example.eth";
const EXAMPLE_ADDRESS: Address = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045";
Expand Down Expand Up @@ -201,29 +202,29 @@ const _EXAMPLE_INDEXING_STATUS_FOLLOWING_RESPONSE: IndexingStatusResponse =
const mockFetch = vi.fn();
global.fetch = mockFetch;

describe("ENSNodeClient", () => {
describe("ENSApiClient", () => {
beforeEach(() => {
mockFetch.mockClear();
});

describe("constructor and options", () => {
it("should use default options when none provided", () => {
const client = new ENSNodeClient();
const client = new ENSApiClient();
const options = client.getOptions();

expect(options).toEqual({ url: getDefaultEnsNodeUrl(ENSNamespaceIds.Mainnet) });
});

it("should merge provided options with defaults", () => {
const customUrl = new URL("https://custom.api.com");
const client = new ENSNodeClient({ url: customUrl });
const client = new ENSApiClient({ url: customUrl });
const options = client.getOptions();

expect(options).toEqual({ url: customUrl });
});

it("should return frozen options object", () => {
const client = new ENSNodeClient();
const client = new ENSApiClient();
const options = client.getOptions();

expect(Object.isFrozen(options)).toBe(true);
Expand All @@ -236,7 +237,7 @@ describe("ENSNodeClient", () => {
const mockResponse = { records: EXAMPLE_RECORDS_RESPONSE };
mockFetch.mockResolvedValueOnce({ ok: true, json: async () => mockResponse });

const client = new ENSNodeClient();
const client = new ENSApiClient();
const response = await client.resolveRecords(EXAMPLE_NAME, EXAMPLE_SELECTION);

const expectedUrl = new URL(
Expand All @@ -254,7 +255,7 @@ describe("ENSNodeClient", () => {
const mockResponse = { records: EXAMPLE_RECORDS_RESPONSE, trace: [] };
mockFetch.mockResolvedValueOnce({ ok: true, json: async () => mockResponse });

const client = new ENSNodeClient();
const client = new ENSApiClient();
const response = await client.resolveRecords(EXAMPLE_NAME, EXAMPLE_SELECTION, {
trace: true,
});
Expand All @@ -274,7 +275,7 @@ describe("ENSNodeClient", () => {
it("should throw error when API returns error", async () => {
mockFetch.mockResolvedValueOnce({ ok: false, json: async () => EXAMPLE_ERROR_RESPONSE });

const client = new ENSNodeClient();
const client = new ENSApiClient();
await expect(client.resolveRecords(EXAMPLE_NAME, EXAMPLE_SELECTION)).rejects.toThrowError(
ClientError,
);
Expand All @@ -288,7 +289,7 @@ describe("ENSNodeClient", () => {
json: async () => EXAMPLE_PRIMARY_NAME_RESPONSE,
});

const client = new ENSNodeClient();
const client = new ENSApiClient();
const response = await client.resolvePrimaryName(EXAMPLE_ADDRESS, 1);

const expectedUrl = new URL(
Expand All @@ -304,7 +305,7 @@ describe("ENSNodeClient", () => {
const mockResponse = { name: EXAMPLE_NAME, trace: [] };
mockFetch.mockResolvedValueOnce({ ok: true, json: async () => mockResponse });

const client = new ENSNodeClient();
const client = new ENSApiClient();
const response = await client.resolvePrimaryName(EXAMPLE_ADDRESS, 1, { trace: true });

const expectedUrl = new URL(
Expand All @@ -323,7 +324,7 @@ describe("ENSNodeClient", () => {
json: async () => EXAMPLE_PRIMARY_NAME_RESPONSE,
});

const client = new ENSNodeClient();
const client = new ENSApiClient();
await client.resolvePrimaryName(EXAMPLE_ADDRESS, 1, { accelerate: true });

const expectedUrl = new URL(
Expand All @@ -338,7 +339,7 @@ describe("ENSNodeClient", () => {
it("should throw error when API returns error", async () => {
mockFetch.mockResolvedValueOnce({ ok: false, json: async () => EXAMPLE_ERROR_RESPONSE });

const client = new ENSNodeClient();
const client = new ENSApiClient();
await expect(client.resolvePrimaryName(EXAMPLE_ADDRESS, 1)).rejects.toThrowError(ClientError);
});
});
Expand All @@ -350,7 +351,7 @@ describe("ENSNodeClient", () => {
json: async () => EXAMPLE_PRIMARY_NAMES_RESPONSE,
});

const client = new ENSNodeClient();
const client = new ENSApiClient();
const response = await client.resolvePrimaryNames(EXAMPLE_ADDRESS);

const expectedUrl = new URL(
Expand All @@ -368,7 +369,7 @@ describe("ENSNodeClient", () => {
json: async () => EXAMPLE_PRIMARY_NAMES_RESPONSE,
});

const client = new ENSNodeClient();
const client = new ENSApiClient();
await client.resolvePrimaryNames(EXAMPLE_ADDRESS, { chainIds: [1, 10] });

const expectedUrl = new URL(
Expand All @@ -384,7 +385,7 @@ describe("ENSNodeClient", () => {
const mockResponse = { ...EXAMPLE_PRIMARY_NAMES_RESPONSE, trace: [] };
mockFetch.mockResolvedValueOnce({ ok: true, json: async () => mockResponse });

const client = new ENSNodeClient();
const client = new ENSApiClient();
const response = await client.resolvePrimaryNames(EXAMPLE_ADDRESS, { trace: true });

const expectedUrl = new URL(
Expand All @@ -403,7 +404,7 @@ describe("ENSNodeClient", () => {
json: async () => EXAMPLE_PRIMARY_NAMES_RESPONSE,
});

const client = new ENSNodeClient();
const client = new ENSApiClient();
await client.resolvePrimaryNames(EXAMPLE_ADDRESS, { accelerate: true });

const expectedUrl = new URL(
Expand All @@ -418,7 +419,7 @@ describe("ENSNodeClient", () => {
it("should throw error when API returns error", async () => {
mockFetch.mockResolvedValueOnce({ ok: false, json: async () => EXAMPLE_ERROR_RESPONSE });

const client = new ENSNodeClient();
const client = new ENSApiClient();
await expect(client.resolvePrimaryNames(EXAMPLE_ADDRESS)).rejects.toThrowError(ClientError);
});
});
Expand All @@ -429,7 +430,7 @@ describe("ENSNodeClient", () => {
const requestUrl = new URL(`/api/config`, DEFAULT_ENSNODE_API_URL_MAINNET);
const serializedMockedResponse = EXAMPLE_CONFIG_RESPONSE;
const mockedResponse = deserializeENSApiPublicConfig(serializedMockedResponse);
const client = new ENSNodeClient();
const client = new ENSApiClient();

mockFetch.mockResolvedValueOnce({
ok: true,
Expand All @@ -444,7 +445,7 @@ describe("ENSNodeClient", () => {
it("should throw error when API returns error", async () => {
mockFetch.mockResolvedValueOnce({ ok: false, json: async () => EXAMPLE_ERROR_RESPONSE });

const client = new ENSNodeClient();
const client = new ENSApiClient();

await expect(client.config()).rejects.toThrow(/Fetching ENSNode Config Failed/i);
});
Expand All @@ -456,7 +457,7 @@ describe("ENSNodeClient", () => {
const requestUrl = new URL(`/api/indexing-status`, DEFAULT_ENSNODE_API_URL_MAINNET);
const mockedResponse = EXAMPLE_INDEXING_STATUS_BACKFILL_RESPONSE;

const client = new ENSNodeClient();
const client = new ENSApiClient();

mockFetch.mockResolvedValueOnce({
ok: true,
Expand All @@ -470,7 +471,7 @@ describe("ENSNodeClient", () => {

it("should throw error when API returns error other than 503 error", async () => {
// arrange
const client = new ENSNodeClient();
const client = new ENSApiClient();

mockFetch.mockResolvedValueOnce({ ok: false, json: async () => EXAMPLE_ERROR_RESPONSE });

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { ClientError } from "./client-error";
import { getDefaultEnsNodeUrl } from "./deployments";
import type { ResolverRecordsSelection } from "../resolution";
import {
type ConfigResponse,
deserializeConfigResponse,
Expand Down Expand Up @@ -27,8 +26,9 @@ import {
type SerializedIndexingStatusResponse,
type SerializedNameTokensResponse,
type SerializedRegistrarActionsResponse,
} from "./ensapi/api";
import type { ResolverRecordsSelection } from "./resolution";
} from "./api";
import { ClientError } from "./client-error";
import { getDefaultEnsNodeUrl } from "./deployments";

/**
* Configuration options for ENSNode API client
Expand All @@ -48,10 +48,10 @@ export interface ClientOptions {
*
* @example
* ```typescript
* import { ENSNodeClient } from "@ensnode/ensnode-sdk";
* import { ENSApiClient } from "@ensnode/ensnode-sdk";
*
* // Create client with default options
* const client = new ENSNodeClient();
* const client = new ENSApiClient();
*
* // Use resolution methods
* const { records } = await client.resolveRecords("jesse.base.eth", {
Expand All @@ -62,35 +62,35 @@ export interface ClientOptions {
*
* @example
* ```typescript
* import { ENSNamespaceIds, ENSNodeClient, getDefaultEnsNodeUrl } from "@ensnode/ensnode-sdk";
* import { ENSNamespaceIds, ENSApiClient, getDefaultEnsNodeUrl } from "@ensnode/ensnode-sdk";
*
* // Use default ENSNode API URL for Mainnet
* const client = new ENSNodeClient({
* const client = new ENSApiClient({
* url: getDefaultEnsNodeUrl(ENSNamespaceIds.Mainnet),
* });
* ```
*
* @example
* ```typescript
* import { ENSNamespaceIds, ENSNodeClient, getDefaultEnsNodeUrl } from "@ensnode/ensnode-sdk";
* import { ENSNamespaceIds, ENSApiClient, getDefaultEnsNodeUrl } from "@ensnode/ensnode-sdk";
*
* // Use default ENSNode API URL for Sepolia
* const client = new ENSNodeClient({
* const client = new ENSApiClient({
* url: getDefaultEnsNodeUrl(ENSNamespaceIds.Sepolia),
* });
* ```
*
* @example
* ```typescript
* import { ENSNodeClient } from "@ensnode/ensnode-sdk";
* import { ENSApiClient } from "@ensnode/ensnode-sdk";
*
* // Custom configuration
* const client = new ENSNodeClient({
* const client = new ENSApiClient({
* url: new URL("https://my-ensnode-instance.com"),
* });
* ```
*/
export class ENSNodeClient {
export class ENSApiClient {
private readonly options: ClientOptions;

static defaultOptions(): ClientOptions {
Expand All @@ -101,7 +101,7 @@ export class ENSNodeClient {

constructor(options: Partial<ClientOptions> = {}) {
this.options = {
...ENSNodeClient.defaultOptions(),
...ENSApiClient.defaultOptions(),
...options,
};
}
Expand Down Expand Up @@ -399,11 +399,11 @@ export class ENSNodeClient {
* ```ts
* import {
* registrarActionsFilter,
* ENSNodeClient,
* ENSApiClient,
* } from "@ensnode/ensnode-sdk";
* import { namehash } from "viem/ens";
*
* const client: ENSNodeClient;
* const client: ENSApiClient;
*
* // Get first page with default page size (10 records)
* const response = await client.registrarActions();
Expand Down Expand Up @@ -611,11 +611,11 @@ export class ENSNodeClient {
* @example
* ```ts
* import {
* ENSNodeClient,
* ENSApiClient,
* } from "@ensnode/ensnode-sdk";
* import { namehash } from "viem/ens";
*
* const client: ENSNodeClient;
* const client: ENSApiClient;
*
* // get latest name token records from the indexed subregistry based on the requested name
* const response = await client.nameTokens({
Expand Down Expand Up @@ -669,3 +669,10 @@ export class ENSNodeClient {
return deserializedNameTokensResponse(responseData as SerializedNameTokensResponse);
}
}

/**
* ENSNode Client
*
* @deprecated use {@link ENSApiClient} instead
*/
export class ENSNodeClient extends ENSApiClient {}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { describe, expect, it } from "vitest";

import { ENSNamespaceIds } from "../ens";
import {
DEFAULT_ENSNODE_API_URL_MAINNET,
DEFAULT_ENSNODE_API_URL_SEPOLIA,
getDefaultEnsNodeUrl,
} from "./deployments";
import { ENSNamespaceIds } from "./ens";

describe("getDefaultEnsNodeUrl", () => {
it("returns the mainnet default URL when no namespace is provided", () => {
Expand Down
3 changes: 3 additions & 0 deletions packages/ensnode-sdk/src/ensapi/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
export * from "./api";
export { type ClientOptions, ENSApiClient, ENSNodeClient } from "./client";
export * from "./client-error";
export * from "./config";
export * from "./deployments";
3 changes: 0 additions & 3 deletions packages/ensnode-sdk/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
export { type ClientOptions, ENSNodeClient } from "./client";
export * from "./client-error";
export * from "./deployments";
export * from "./ens";
export * from "./ensapi";
export * from "./ensindexer";
Expand Down