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
5 changes: 5 additions & 0 deletions .changeset/brown-pears-help.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@ensnode/ensnode-sdk": patch
---

Added getDefaultEnsNodeUrl utility to get the URL for the default ENSNode deployment for a given ENS namespace
35 changes: 21 additions & 14 deletions packages/ensnode-sdk/src/client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ import {
type SerializedIndexingStatusResponseOk,
serializeIndexingStatusResponse,
} from "./api";
import { DEFAULT_ENSNODE_API_URL, ENSNodeClient } from "./client";
import { ENSNodeClient } from "./client";
import { ClientError } from "./client-error";
import type { Name } from "./ens";
import { DEFAULT_ENSNODE_API_URL_MAINNET, getDefaultEnsNodeUrl } from "./deployments";
import { ENSNamespaceIds, type Name } from "./ens";
import { deserializeENSApiPublicConfig, type SerializedENSApiPublicConfig } from "./ensapi";
import {
ChainIndexingConfigTypeIds,
Expand Down Expand Up @@ -210,7 +211,7 @@ describe("ENSNodeClient", () => {
const client = new ENSNodeClient();
const options = client.getOptions();

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

it("should merge provided options with defaults", () => {
Expand Down Expand Up @@ -238,7 +239,10 @@ describe("ENSNodeClient", () => {
const client = new ENSNodeClient();
const response = await client.resolveRecords(EXAMPLE_NAME, EXAMPLE_SELECTION);

const expectedUrl = new URL(`/api/resolve/records/${EXAMPLE_NAME}`, DEFAULT_ENSNODE_API_URL);
const expectedUrl = new URL(
`/api/resolve/records/${EXAMPLE_NAME}`,
DEFAULT_ENSNODE_API_URL_MAINNET,
);
expectedUrl.searchParams.set("addresses", EXAMPLE_SELECTION.addresses.join(","));
expectedUrl.searchParams.set("texts", EXAMPLE_SELECTION.texts.join(","));

Expand All @@ -255,7 +259,10 @@ describe("ENSNodeClient", () => {
trace: true,
});

const expectedUrl = new URL(`/api/resolve/records/${EXAMPLE_NAME}`, DEFAULT_ENSNODE_API_URL);
const expectedUrl = new URL(
`/api/resolve/records/${EXAMPLE_NAME}`,
DEFAULT_ENSNODE_API_URL_MAINNET,
);
expectedUrl.searchParams.set("addresses", EXAMPLE_SELECTION.addresses.join(","));
expectedUrl.searchParams.set("texts", EXAMPLE_SELECTION.texts.join(","));
expectedUrl.searchParams.set("trace", "true");
Expand Down Expand Up @@ -286,7 +293,7 @@ describe("ENSNodeClient", () => {

const expectedUrl = new URL(
`/api/resolve/primary-name/${EXAMPLE_ADDRESS}/1`,
DEFAULT_ENSNODE_API_URL,
DEFAULT_ENSNODE_API_URL_MAINNET,
);

expect(mockFetch).toHaveBeenCalledWith(expectedUrl);
Expand All @@ -302,7 +309,7 @@ describe("ENSNodeClient", () => {

const expectedUrl = new URL(
`/api/resolve/primary-name/${EXAMPLE_ADDRESS}/1`,
DEFAULT_ENSNODE_API_URL,
DEFAULT_ENSNODE_API_URL_MAINNET,
);
expectedUrl.searchParams.set("trace", "true");

Expand All @@ -321,7 +328,7 @@ describe("ENSNodeClient", () => {

const expectedUrl = new URL(
`/api/resolve/primary-name/${EXAMPLE_ADDRESS}/1`,
DEFAULT_ENSNODE_API_URL,
DEFAULT_ENSNODE_API_URL_MAINNET,
);
expectedUrl.searchParams.set("accelerate", "true");

Expand All @@ -348,7 +355,7 @@ describe("ENSNodeClient", () => {

const expectedUrl = new URL(
`/api/resolve/primary-names/${EXAMPLE_ADDRESS}`,
DEFAULT_ENSNODE_API_URL,
DEFAULT_ENSNODE_API_URL_MAINNET,
);

expect(mockFetch).toHaveBeenCalledWith(expectedUrl);
Expand All @@ -366,7 +373,7 @@ describe("ENSNodeClient", () => {

const expectedUrl = new URL(
`/api/resolve/primary-names/${EXAMPLE_ADDRESS}`,
DEFAULT_ENSNODE_API_URL,
DEFAULT_ENSNODE_API_URL_MAINNET,
);
expectedUrl.searchParams.set("chainIds", "1,10");

Expand All @@ -382,7 +389,7 @@ describe("ENSNodeClient", () => {

const expectedUrl = new URL(
`/api/resolve/primary-names/${EXAMPLE_ADDRESS}`,
DEFAULT_ENSNODE_API_URL,
DEFAULT_ENSNODE_API_URL_MAINNET,
);
expectedUrl.searchParams.set("trace", "true");

Expand All @@ -401,7 +408,7 @@ describe("ENSNodeClient", () => {

const expectedUrl = new URL(
`/api/resolve/primary-names/${EXAMPLE_ADDRESS}`,
DEFAULT_ENSNODE_API_URL,
DEFAULT_ENSNODE_API_URL_MAINNET,
);
expectedUrl.searchParams.set("accelerate", "true");

Expand All @@ -419,7 +426,7 @@ describe("ENSNodeClient", () => {
describe("Config API", () => {
it("can fetch config object successfully", async () => {
// arrange
const requestUrl = new URL(`/api/config`, DEFAULT_ENSNODE_API_URL);
const requestUrl = new URL(`/api/config`, DEFAULT_ENSNODE_API_URL_MAINNET);
const serializedMockedResponse = EXAMPLE_CONFIG_RESPONSE;
const mockedResponse = deserializeENSApiPublicConfig(serializedMockedResponse);
const client = new ENSNodeClient();
Expand All @@ -446,7 +453,7 @@ describe("ENSNodeClient", () => {
describe("Indexing Status API", () => {
it("can fetch overall indexing 'backfill' status object successfully", async () => {
// arrange
const requestUrl = new URL(`/api/indexing-status`, DEFAULT_ENSNODE_API_URL);
const requestUrl = new URL(`/api/indexing-status`, DEFAULT_ENSNODE_API_URL_MAINNET);
const mockedResponse = EXAMPLE_INDEXING_STATUS_BACKFILL_RESPONSE;

const client = new ENSNodeClient();
Expand Down
32 changes: 26 additions & 6 deletions packages/ensnode-sdk/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,9 @@ import {
type SerializedRegistrarActionsResponse,
} from "./api";
import { ClientError } from "./client-error";
import { getDefaultEnsNodeUrl } from "./deployments";
import type { ResolverRecordsSelection } from "./resolution";

/**
* Default ENSNode API endpoint URL
*/
export const DEFAULT_ENSNODE_API_URL = "https://api.alpha.ensnode.io" as const;

/**
* Configuration options for ENSNode API client
*/
Expand All @@ -52,6 +48,8 @@ export interface ClientOptions {
*
* @example
* ```typescript
* import { ENSNodeClient } from "@ensnode/ensnode-sdk";
*
* // Create client with default options
* const client = new ENSNodeClient();
*
Expand All @@ -64,6 +62,28 @@ export interface ClientOptions {
*
* @example
* ```typescript
* import { ENSNamespaceIds, ENSNodeClient, getDefaultEnsNodeUrl } from "@ensnode/ensnode-sdk";
*
* // Use default ENSNode API URL for Mainnet
* const client = new ENSNodeClient({
* url: getDefaultEnsNodeUrl(ENSNamespaceIds.Mainnet),
* });
* ```
*
* @example
* ```typescript
* import { ENSNamespaceIds, ENSNodeClient, getDefaultEnsNodeUrl } from "@ensnode/ensnode-sdk";
*
* // Use default ENSNode API URL for Sepolia
* const client = new ENSNodeClient({
* url: getDefaultEnsNodeUrl(ENSNamespaceIds.Sepolia),
* });
* ```
*
* @example
* ```typescript
* import { ENSNodeClient } from "@ensnode/ensnode-sdk";
*
* // Custom configuration
* const client = new ENSNodeClient({
* url: new URL("https://my-ensnode-instance.com"),
Expand All @@ -75,7 +95,7 @@ export class ENSNodeClient {

static defaultOptions(): ClientOptions {
return {
url: new URL(DEFAULT_ENSNODE_API_URL),
url: getDefaultEnsNodeUrl(),
};
}

Expand Down
36 changes: 36 additions & 0 deletions packages/ensnode-sdk/src/deployments.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { describe, expect, it } from "vitest";

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", () => {
const url = getDefaultEnsNodeUrl();

expect(url.href).toBe(`${DEFAULT_ENSNODE_API_URL_MAINNET}/`);
});

it("returns the mainnet default URL", () => {
const url = getDefaultEnsNodeUrl(ENSNamespaceIds.Mainnet);

expect(url.href).toBe(`${DEFAULT_ENSNODE_API_URL_MAINNET}/`);
});

it("returns the sepolia default URL", () => {
const url = getDefaultEnsNodeUrl(ENSNamespaceIds.Sepolia);

expect(url.href).toBe(`${DEFAULT_ENSNODE_API_URL_SEPOLIA}/`);
});

it("throws for unsupported namespaces", () => {
const unsupportedNamespace = ENSNamespaceIds.EnsTestEnv;

expect(() => getDefaultEnsNodeUrl(unsupportedNamespace)).toThrow(
`ENSNamespaceId ${unsupportedNamespace} does not have a default ENSNode URL defined`,
);
});
});
34 changes: 34 additions & 0 deletions packages/ensnode-sdk/src/deployments.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { type ENSNamespaceId, ENSNamespaceIds } from "@ensnode/datasources";

/**
* Default ENSNode API endpoint URL for Mainnet
*/
export const DEFAULT_ENSNODE_API_URL_MAINNET = "https://api.alpha.ensnode.io" as const;

/**
* Default ENSNode API endpoint URL for Sepolia
*/
export const DEFAULT_ENSNODE_API_URL_SEPOLIA = "https://api.alpha-sepolia.ensnode.io" as const;

/**
* Gets the default ENSNode URL for the provided ENSNamespaceId.
*
* @param namespace - Optional. The ENSNamespaceId to get the default ENSNode URL for. If not
* provided, defaults to Mainnet.
* @returns The default ENSNode URL for the provided ENSNamespaceId, or for Mainnet if no
* namespace is provided.
* @throws If the provided ENSNamespaceId does not have a default ENSNode URL defined
*/
export const getDefaultEnsNodeUrl = (namespace?: ENSNamespaceId): URL => {
const effectiveNamespace = namespace ?? ENSNamespaceIds.Mainnet;
switch (effectiveNamespace) {
case ENSNamespaceIds.Mainnet:
return new URL(DEFAULT_ENSNODE_API_URL_MAINNET);
case ENSNamespaceIds.Sepolia:
return new URL(DEFAULT_ENSNODE_API_URL_SEPOLIA);
default:
throw new Error(
`ENSNamespaceId ${effectiveNamespace} does not have a default ENSNode URL defined`,
);
}
};
1 change: 1 addition & 0 deletions packages/ensnode-sdk/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export * from "./api";
export { type ClientOptions, ENSNodeClient } from "./client";
export * from "./client-error";
export * from "./deployments";
export * from "./ens";
export * from "./ensapi";
export * from "./ensindexer";
Expand Down
Loading