Skip to content

Commit 220b71f

Browse files
Add getDefaultEnsNodeUrl (#1553)
1 parent 3bc61ab commit 220b71f

File tree

6 files changed

+123
-20
lines changed

6 files changed

+123
-20
lines changed

.changeset/brown-pears-help.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@ensnode/ensnode-sdk": patch
3+
---
4+
5+
Added getDefaultEnsNodeUrl utility to get the URL for the default ENSNode deployment for a given ENS namespace

packages/ensnode-sdk/src/client.test.ts

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@ import {
1111
type SerializedIndexingStatusResponseOk,
1212
serializeIndexingStatusResponse,
1313
} from "./api";
14-
import { DEFAULT_ENSNODE_API_URL, ENSNodeClient } from "./client";
14+
import { ENSNodeClient } from "./client";
1515
import { ClientError } from "./client-error";
16-
import type { Name } from "./ens";
16+
import { DEFAULT_ENSNODE_API_URL_MAINNET, getDefaultEnsNodeUrl } from "./deployments";
17+
import { ENSNamespaceIds, type Name } from "./ens";
1718
import { deserializeENSApiPublicConfig, type SerializedENSApiPublicConfig } from "./ensapi";
1819
import {
1920
ChainIndexingConfigTypeIds,
@@ -210,7 +211,7 @@ describe("ENSNodeClient", () => {
210211
const client = new ENSNodeClient();
211212
const options = client.getOptions();
212213

213-
expect(options).toEqual({ url: new URL(DEFAULT_ENSNODE_API_URL) });
214+
expect(options).toEqual({ url: getDefaultEnsNodeUrl(ENSNamespaceIds.Mainnet) });
214215
});
215216

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

241-
const expectedUrl = new URL(`/api/resolve/records/${EXAMPLE_NAME}`, DEFAULT_ENSNODE_API_URL);
242+
const expectedUrl = new URL(
243+
`/api/resolve/records/${EXAMPLE_NAME}`,
244+
DEFAULT_ENSNODE_API_URL_MAINNET,
245+
);
242246
expectedUrl.searchParams.set("addresses", EXAMPLE_SELECTION.addresses.join(","));
243247
expectedUrl.searchParams.set("texts", EXAMPLE_SELECTION.texts.join(","));
244248

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

258-
const expectedUrl = new URL(`/api/resolve/records/${EXAMPLE_NAME}`, DEFAULT_ENSNODE_API_URL);
262+
const expectedUrl = new URL(
263+
`/api/resolve/records/${EXAMPLE_NAME}`,
264+
DEFAULT_ENSNODE_API_URL_MAINNET,
265+
);
259266
expectedUrl.searchParams.set("addresses", EXAMPLE_SELECTION.addresses.join(","));
260267
expectedUrl.searchParams.set("texts", EXAMPLE_SELECTION.texts.join(","));
261268
expectedUrl.searchParams.set("trace", "true");
@@ -286,7 +293,7 @@ describe("ENSNodeClient", () => {
286293

287294
const expectedUrl = new URL(
288295
`/api/resolve/primary-name/${EXAMPLE_ADDRESS}/1`,
289-
DEFAULT_ENSNODE_API_URL,
296+
DEFAULT_ENSNODE_API_URL_MAINNET,
290297
);
291298

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

303310
const expectedUrl = new URL(
304311
`/api/resolve/primary-name/${EXAMPLE_ADDRESS}/1`,
305-
DEFAULT_ENSNODE_API_URL,
312+
DEFAULT_ENSNODE_API_URL_MAINNET,
306313
);
307314
expectedUrl.searchParams.set("trace", "true");
308315

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

322329
const expectedUrl = new URL(
323330
`/api/resolve/primary-name/${EXAMPLE_ADDRESS}/1`,
324-
DEFAULT_ENSNODE_API_URL,
331+
DEFAULT_ENSNODE_API_URL_MAINNET,
325332
);
326333
expectedUrl.searchParams.set("accelerate", "true");
327334

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

349356
const expectedUrl = new URL(
350357
`/api/resolve/primary-names/${EXAMPLE_ADDRESS}`,
351-
DEFAULT_ENSNODE_API_URL,
358+
DEFAULT_ENSNODE_API_URL_MAINNET,
352359
);
353360

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

367374
const expectedUrl = new URL(
368375
`/api/resolve/primary-names/${EXAMPLE_ADDRESS}`,
369-
DEFAULT_ENSNODE_API_URL,
376+
DEFAULT_ENSNODE_API_URL_MAINNET,
370377
);
371378
expectedUrl.searchParams.set("chainIds", "1,10");
372379

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

383390
const expectedUrl = new URL(
384391
`/api/resolve/primary-names/${EXAMPLE_ADDRESS}`,
385-
DEFAULT_ENSNODE_API_URL,
392+
DEFAULT_ENSNODE_API_URL_MAINNET,
386393
);
387394
expectedUrl.searchParams.set("trace", "true");
388395

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

402409
const expectedUrl = new URL(
403410
`/api/resolve/primary-names/${EXAMPLE_ADDRESS}`,
404-
DEFAULT_ENSNODE_API_URL,
411+
DEFAULT_ENSNODE_API_URL_MAINNET,
405412
);
406413
expectedUrl.searchParams.set("accelerate", "true");
407414

@@ -419,7 +426,7 @@ describe("ENSNodeClient", () => {
419426
describe("Config API", () => {
420427
it("can fetch config object successfully", async () => {
421428
// arrange
422-
const requestUrl = new URL(`/api/config`, DEFAULT_ENSNODE_API_URL);
429+
const requestUrl = new URL(`/api/config`, DEFAULT_ENSNODE_API_URL_MAINNET);
423430
const serializedMockedResponse = EXAMPLE_CONFIG_RESPONSE;
424431
const mockedResponse = deserializeENSApiPublicConfig(serializedMockedResponse);
425432
const client = new ENSNodeClient();
@@ -446,7 +453,7 @@ describe("ENSNodeClient", () => {
446453
describe("Indexing Status API", () => {
447454
it("can fetch overall indexing 'backfill' status object successfully", async () => {
448455
// arrange
449-
const requestUrl = new URL(`/api/indexing-status`, DEFAULT_ENSNODE_API_URL);
456+
const requestUrl = new URL(`/api/indexing-status`, DEFAULT_ENSNODE_API_URL_MAINNET);
450457
const mockedResponse = EXAMPLE_INDEXING_STATUS_BACKFILL_RESPONSE;
451458

452459
const client = new ENSNodeClient();

packages/ensnode-sdk/src/client.ts

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,9 @@ import {
2727
type SerializedRegistrarActionsResponse,
2828
} from "./api";
2929
import { ClientError } from "./client-error";
30+
import { getDefaultEnsNodeUrl } from "./deployments";
3031
import type { ResolverRecordsSelection } from "./resolution";
3132

32-
/**
33-
* Default ENSNode API endpoint URL
34-
*/
35-
export const DEFAULT_ENSNODE_API_URL = "https://api.alpha.ensnode.io" as const;
36-
3733
/**
3834
* Configuration options for ENSNode API client
3935
*/
@@ -52,6 +48,8 @@ export interface ClientOptions {
5248
*
5349
* @example
5450
* ```typescript
51+
* import { ENSNodeClient } from "@ensnode/ensnode-sdk";
52+
*
5553
* // Create client with default options
5654
* const client = new ENSNodeClient();
5755
*
@@ -64,6 +62,28 @@ export interface ClientOptions {
6462
*
6563
* @example
6664
* ```typescript
65+
* import { ENSNamespaceIds, ENSNodeClient, getDefaultEnsNodeUrl } from "@ensnode/ensnode-sdk";
66+
*
67+
* // Use default ENSNode API URL for Mainnet
68+
* const client = new ENSNodeClient({
69+
* url: getDefaultEnsNodeUrl(ENSNamespaceIds.Mainnet),
70+
* });
71+
* ```
72+
*
73+
* @example
74+
* ```typescript
75+
* import { ENSNamespaceIds, ENSNodeClient, getDefaultEnsNodeUrl } from "@ensnode/ensnode-sdk";
76+
*
77+
* // Use default ENSNode API URL for Sepolia
78+
* const client = new ENSNodeClient({
79+
* url: getDefaultEnsNodeUrl(ENSNamespaceIds.Sepolia),
80+
* });
81+
* ```
82+
*
83+
* @example
84+
* ```typescript
85+
* import { ENSNodeClient } from "@ensnode/ensnode-sdk";
86+
*
6787
* // Custom configuration
6888
* const client = new ENSNodeClient({
6989
* url: new URL("https://my-ensnode-instance.com"),
@@ -75,7 +95,7 @@ export class ENSNodeClient {
7595

7696
static defaultOptions(): ClientOptions {
7797
return {
78-
url: new URL(DEFAULT_ENSNODE_API_URL),
98+
url: getDefaultEnsNodeUrl(),
7999
};
80100
}
81101

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { describe, expect, it } from "vitest";
2+
3+
import {
4+
DEFAULT_ENSNODE_API_URL_MAINNET,
5+
DEFAULT_ENSNODE_API_URL_SEPOLIA,
6+
getDefaultEnsNodeUrl,
7+
} from "./deployments";
8+
import { ENSNamespaceIds } from "./ens";
9+
10+
describe("getDefaultEnsNodeUrl", () => {
11+
it("returns the mainnet default URL when no namespace is provided", () => {
12+
const url = getDefaultEnsNodeUrl();
13+
14+
expect(url.href).toBe(`${DEFAULT_ENSNODE_API_URL_MAINNET}/`);
15+
});
16+
17+
it("returns the mainnet default URL", () => {
18+
const url = getDefaultEnsNodeUrl(ENSNamespaceIds.Mainnet);
19+
20+
expect(url.href).toBe(`${DEFAULT_ENSNODE_API_URL_MAINNET}/`);
21+
});
22+
23+
it("returns the sepolia default URL", () => {
24+
const url = getDefaultEnsNodeUrl(ENSNamespaceIds.Sepolia);
25+
26+
expect(url.href).toBe(`${DEFAULT_ENSNODE_API_URL_SEPOLIA}/`);
27+
});
28+
29+
it("throws for unsupported namespaces", () => {
30+
const unsupportedNamespace = ENSNamespaceIds.EnsTestEnv;
31+
32+
expect(() => getDefaultEnsNodeUrl(unsupportedNamespace)).toThrow(
33+
`ENSNamespaceId ${unsupportedNamespace} does not have a default ENSNode URL defined`,
34+
);
35+
});
36+
});
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { type ENSNamespaceId, ENSNamespaceIds } from "@ensnode/datasources";
2+
3+
/**
4+
* Default ENSNode API endpoint URL for Mainnet
5+
*/
6+
export const DEFAULT_ENSNODE_API_URL_MAINNET = "https://api.alpha.ensnode.io" as const;
7+
8+
/**
9+
* Default ENSNode API endpoint URL for Sepolia
10+
*/
11+
export const DEFAULT_ENSNODE_API_URL_SEPOLIA = "https://api.alpha-sepolia.ensnode.io" as const;
12+
13+
/**
14+
* Gets the default ENSNode URL for the provided ENSNamespaceId.
15+
*
16+
* @param namespace - Optional. The ENSNamespaceId to get the default ENSNode URL for. If not
17+
* provided, defaults to Mainnet.
18+
* @returns The default ENSNode URL for the provided ENSNamespaceId, or for Mainnet if no
19+
* namespace is provided.
20+
* @throws If the provided ENSNamespaceId does not have a default ENSNode URL defined
21+
*/
22+
export const getDefaultEnsNodeUrl = (namespace?: ENSNamespaceId): URL => {
23+
const effectiveNamespace = namespace ?? ENSNamespaceIds.Mainnet;
24+
switch (effectiveNamespace) {
25+
case ENSNamespaceIds.Mainnet:
26+
return new URL(DEFAULT_ENSNODE_API_URL_MAINNET);
27+
case ENSNamespaceIds.Sepolia:
28+
return new URL(DEFAULT_ENSNODE_API_URL_SEPOLIA);
29+
default:
30+
throw new Error(
31+
`ENSNamespaceId ${effectiveNamespace} does not have a default ENSNode URL defined`,
32+
);
33+
}
34+
};

packages/ensnode-sdk/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export * from "./api";
22
export { type ClientOptions, ENSNodeClient } from "./client";
33
export * from "./client-error";
4+
export * from "./deployments";
45
export * from "./ens";
56
export * from "./ensapi";
67
export * from "./ensindexer";

0 commit comments

Comments
 (0)