From a50cc287be77ae1fd90b7ff40ad99bdc6f554c78 Mon Sep 17 00:00:00 2001 From: Tomasz Kopacki Date: Thu, 23 Apr 2026 17:38:59 +0200 Subject: [PATCH 01/21] Create `EnsIndexerStackInfo`, and `EnsDbStackInfo` data model --- .../deserialize/ensdb-stack-info.ts | 46 +++++++++++++++++ .../deserialize/ensindexer-stack-info.ts | 45 ++++++++++++++++ .../deserialize/ensnode-stack-info.ts | 14 ++--- .../src/stack-info/ensdb-stack-info.ts | 29 +++++++++++ .../src/stack-info/ensindexer-stack-info.ts | 31 +++++++++++ .../src/stack-info/ensnode-stack-info.ts | 29 +++-------- packages/ensnode-sdk/src/stack-info/index.ts | 6 +++ .../stack-info/serialize/ensdb-stack-info.ts | 23 +++++++++ .../serialize/ensindexer-stack-info.ts | 24 +++++++++ .../serialize/ensnode-stack-info.ts | 14 ++--- .../zod-schemas/ensdb-stack-info.ts | 24 +++++++++ .../zod-schemas/ensindexer-stack-info.ts | 51 +++++++++++++++++++ .../zod-schemas/ensnode-stack-info.ts | 4 +- 13 files changed, 294 insertions(+), 46 deletions(-) create mode 100644 packages/ensnode-sdk/src/stack-info/deserialize/ensdb-stack-info.ts create mode 100644 packages/ensnode-sdk/src/stack-info/deserialize/ensindexer-stack-info.ts create mode 100644 packages/ensnode-sdk/src/stack-info/ensdb-stack-info.ts create mode 100644 packages/ensnode-sdk/src/stack-info/ensindexer-stack-info.ts create mode 100644 packages/ensnode-sdk/src/stack-info/serialize/ensdb-stack-info.ts create mode 100644 packages/ensnode-sdk/src/stack-info/serialize/ensindexer-stack-info.ts create mode 100644 packages/ensnode-sdk/src/stack-info/zod-schemas/ensdb-stack-info.ts create mode 100644 packages/ensnode-sdk/src/stack-info/zod-schemas/ensindexer-stack-info.ts diff --git a/packages/ensnode-sdk/src/stack-info/deserialize/ensdb-stack-info.ts b/packages/ensnode-sdk/src/stack-info/deserialize/ensdb-stack-info.ts new file mode 100644 index 0000000000..3bfe398d97 --- /dev/null +++ b/packages/ensnode-sdk/src/stack-info/deserialize/ensdb-stack-info.ts @@ -0,0 +1,46 @@ +import { prettifyError } from "zod/v4"; + +import type { Unvalidated } from "../../shared/types"; +import type { EnsDbStackInfo } from "../ensdb-stack-info"; +import type { SerializedEnsDbStackInfo } from "../serialize/ensdb-stack-info"; +import { + makeEnsDbStackInfoSchema, + makeSerializedEnsDbStackInfoSchema, +} from "../zod-schemas/ensdb-stack-info"; +import { buildUnvalidatedEnsIndexerStackInfo } from "./ensindexer-stack-info"; + +/** + * Builds an unvalidated {@link EnsDbStackInfo} object to be + * validated with {@link makeEnsDbStackInfoSchema}. + * + * @param serializedStackInfo - The serialized stack info to build from. + * @return An unvalidated {@link EnsDbStackInfo} object. + */ +export function buildUnvalidatedEnsDbStackInfo( + serializedStackInfo: SerializedEnsDbStackInfo, +): Unvalidated { + const { ensDb, ...serializedEnsindexerStackInfo } = serializedStackInfo; + return { + ...buildUnvalidatedEnsIndexerStackInfo(serializedEnsindexerStackInfo), + ensDb, // ENSDb Public Config is already in a serialized form, so we can include it directly + }; +} + +/** + * Deserialize value into {@link EnsDbStackInfo} object. + */ +export function deserializeEnsDbStackInfo( + maybeStackInfo: Unvalidated, + valueLabel?: string, +): EnsDbStackInfo { + const parsed = makeSerializedEnsDbStackInfoSchema(valueLabel) + .transform(buildUnvalidatedEnsDbStackInfo) + .pipe(makeEnsDbStackInfoSchema(valueLabel)) + .safeParse(maybeStackInfo); + + if (parsed.error) { + throw new Error(`Cannot deserialize EnsDbStackInfo:\n${prettifyError(parsed.error)}\n`); + } + + return parsed.data; +} diff --git a/packages/ensnode-sdk/src/stack-info/deserialize/ensindexer-stack-info.ts b/packages/ensnode-sdk/src/stack-info/deserialize/ensindexer-stack-info.ts new file mode 100644 index 0000000000..da22b2ff1d --- /dev/null +++ b/packages/ensnode-sdk/src/stack-info/deserialize/ensindexer-stack-info.ts @@ -0,0 +1,45 @@ +import { prettifyError } from "zod/v4"; + +import { buildUnvalidatedEnsIndexerPublicConfig } from "../../ensindexer/config/deserialize"; +import type { Unvalidated } from "../../shared/types"; +import type { EnsIndexerStackInfo } from "../ensindexer-stack-info"; +import type { SerializedEnsIndexerStackInfo } from "../serialize/ensindexer-stack-info"; +import { + makeEnsIndexerStackInfoSchema, + makeSerializedEnsIndexerStackInfoSchema, +} from "../zod-schemas/ensindexer-stack-info"; + +/** + * Builds an unvalidated {@link EnsIndexerStackInfo} object to be + * validated with {@link makeEnsIndexerStackInfoSchema}. + * + * @param serializedStackInfo - The serialized stack info to build from. + * @return An unvalidated {@link EnsIndexerStackInfo} object. + */ +export function buildUnvalidatedEnsIndexerStackInfo( + serializedStackInfo: SerializedEnsIndexerStackInfo, +): Unvalidated { + return { + ensIndexer: buildUnvalidatedEnsIndexerPublicConfig(serializedStackInfo.ensIndexer), + ensRainbow: serializedStackInfo.ensRainbow, // ENSRainbow Public Config is already in a serialized form, so we can include it directly + }; +} + +/** + * Deserialize value into {@link EnsIndexerStackInfo} object. + */ +export function deserializeEnsIndexerStackInfo( + maybeStackInfo: Unvalidated, + valueLabel?: string, +): EnsIndexerStackInfo { + const parsed = makeSerializedEnsIndexerStackInfoSchema(valueLabel) + .transform(buildUnvalidatedEnsIndexerStackInfo) + .pipe(makeEnsIndexerStackInfoSchema(valueLabel)) + .safeParse(maybeStackInfo); + + if (parsed.error) { + throw new Error(`Cannot deserialize EnsIndexerStackInfo:\n${prettifyError(parsed.error)}\n`); + } + + return parsed.data; +} diff --git a/packages/ensnode-sdk/src/stack-info/deserialize/ensnode-stack-info.ts b/packages/ensnode-sdk/src/stack-info/deserialize/ensnode-stack-info.ts index 40ee912e5a..7e130dfa92 100644 --- a/packages/ensnode-sdk/src/stack-info/deserialize/ensnode-stack-info.ts +++ b/packages/ensnode-sdk/src/stack-info/deserialize/ensnode-stack-info.ts @@ -1,7 +1,6 @@ import { prettifyError } from "zod/v4"; -import { buildUnvalidatedEnsApiPublicConfig } from "../../ensapi/config/deserialize"; -import { buildUnvalidatedEnsIndexerPublicConfig } from "../../ensindexer/config/deserialize"; +import { buildUnvalidatedEnsApiPublicConfig } from "../../ensapi"; import type { Unvalidated } from "../../shared/types"; import type { EnsNodeStackInfo } from "../ensnode-stack-info"; import type { SerializedEnsNodeStackInfo } from "../serialize/ensnode-stack-info"; @@ -9,6 +8,7 @@ import { makeEnsNodeStackInfoSchema, makeSerializedEnsNodeStackInfoSchema, } from "../zod-schemas/ensnode-stack-info"; +import { buildUnvalidatedEnsDbStackInfo } from "./ensdb-stack-info"; /** * Builds an unvalidated {@link EnsNodeStackInfo} object to be @@ -20,16 +20,10 @@ import { export function buildUnvalidatedEnsNodeStackInfo( serializedStackInfo: SerializedEnsNodeStackInfo, ): Unvalidated { - // Stack info for ENSApi and ENSIndexer requires deserialization, - // so we handle them separately here before returning - // the final stack info object. Stack info for ENSDb and ENSRainbow can be - // passed through directly since they don't require deserialization. - const { ensApi, ensIndexer, ...rest } = serializedStackInfo; - + const { ensApi, ...serializedEnsDbStackInfo } = serializedStackInfo; return { - ...rest, + ...buildUnvalidatedEnsDbStackInfo(serializedEnsDbStackInfo), ensApi: buildUnvalidatedEnsApiPublicConfig(ensApi), - ensIndexer: buildUnvalidatedEnsIndexerPublicConfig(ensIndexer), }; } diff --git a/packages/ensnode-sdk/src/stack-info/ensdb-stack-info.ts b/packages/ensnode-sdk/src/stack-info/ensdb-stack-info.ts new file mode 100644 index 0000000000..e29ad7a906 --- /dev/null +++ b/packages/ensnode-sdk/src/stack-info/ensdb-stack-info.ts @@ -0,0 +1,29 @@ +import type { EnsDbPublicConfig } from "../ensdb/config"; +import type { EnsIndexerPublicConfig } from "../ensindexer/config/types"; +import type { EnsRainbowPublicConfig } from "../ensrainbow/config"; +import { buildEnsIndexerStackInfo, type EnsIndexerStackInfo } from "./ensindexer-stack-info"; + +/** + * Information about the stack of services inside an ENSDb instance. + */ +export interface EnsDbStackInfo extends EnsIndexerStackInfo { + /** + * ENSDb Public Config + */ + ensDb: EnsDbPublicConfig; +} + +/** + * Build a complete {@link EnsDbStackInfo} object from + * the given public configs of ENSDb, ENSIndexer, and ENSRainbow. + */ +export function buildEnsDbStackInfo( + ensDbPublicConfig: EnsDbPublicConfig, + ensIndexerPublicConfig: EnsIndexerPublicConfig, + ensRainbowPublicConfig: EnsRainbowPublicConfig, +): EnsDbStackInfo { + return { + ...buildEnsIndexerStackInfo(ensIndexerPublicConfig, ensRainbowPublicConfig), + ensDb: ensDbPublicConfig, + }; +} diff --git a/packages/ensnode-sdk/src/stack-info/ensindexer-stack-info.ts b/packages/ensnode-sdk/src/stack-info/ensindexer-stack-info.ts new file mode 100644 index 0000000000..b3d2ac95ce --- /dev/null +++ b/packages/ensnode-sdk/src/stack-info/ensindexer-stack-info.ts @@ -0,0 +1,31 @@ +import type { EnsIndexerPublicConfig } from "../ensindexer/config/types"; +import type { EnsRainbowPublicConfig } from "../ensrainbow/config"; + +/** + * Information about the stack of services inside an ENSIndexer instance. + */ +export interface EnsIndexerStackInfo { + /** + * ENSIndexer Public Config + */ + ensIndexer: EnsIndexerPublicConfig; + + /** + * ENSRainbow Public Config + */ + ensRainbow: EnsRainbowPublicConfig; +} + +/** + * Build a complete {@link EnsIndexerStackInfo} object from + * the given public configs of ENSIndexer and ENSRainbow. + */ +export function buildEnsIndexerStackInfo( + ensIndexerPublicConfig: EnsIndexerPublicConfig, + ensRainbowPublicConfig: EnsRainbowPublicConfig, +): EnsIndexerStackInfo { + return { + ensIndexer: ensIndexerPublicConfig, + ensRainbow: ensRainbowPublicConfig, + }; +} diff --git a/packages/ensnode-sdk/src/stack-info/ensnode-stack-info.ts b/packages/ensnode-sdk/src/stack-info/ensnode-stack-info.ts index 94f39d1955..d8847d356d 100644 --- a/packages/ensnode-sdk/src/stack-info/ensnode-stack-info.ts +++ b/packages/ensnode-sdk/src/stack-info/ensnode-stack-info.ts @@ -1,34 +1,17 @@ import type { EnsApiPublicConfig } from "../ensapi/config/types"; import type { EnsDbPublicConfig } from "../ensdb/config"; import type { EnsIndexerPublicConfig } from "../ensindexer/config/types"; -import type { EnsRainbowPublicConfig } from "../ensrainbow/config"; +import type { EnsRainbowPublicConfig } from "../ensrainbow"; +import { buildEnsDbStackInfo, type EnsDbStackInfo } from "./ensdb-stack-info"; /** * Information about the stack of services inside an ENSNode instance. */ -export interface EnsNodeStackInfo { +export interface EnsNodeStackInfo extends EnsDbStackInfo { /** * ENSApi Public Config */ ensApi: EnsApiPublicConfig; - - /** - * ENSDb Public Config - */ - ensDb: EnsDbPublicConfig; - - /** - * ENSIndexer Public Config - */ - ensIndexer: EnsIndexerPublicConfig; - - /** - * ENSRainbow Public Config - * - * If undefined, represents that ENSRainbow is currently undergoing - * a cold start and may take up to an hour to become ready. - */ - ensRainbow?: EnsRainbowPublicConfig; } /** @@ -38,11 +21,11 @@ export interface EnsNodeStackInfo { export function buildEnsNodeStackInfo( ensApiPublicConfig: EnsApiPublicConfig, ensDbPublicConfig: EnsDbPublicConfig, + ensIndexerPublicConfig: EnsIndexerPublicConfig, + ensRainbowPublicConfig: EnsRainbowPublicConfig, ): EnsNodeStackInfo { return { + ...buildEnsDbStackInfo(ensDbPublicConfig, ensIndexerPublicConfig, ensRainbowPublicConfig), ensApi: ensApiPublicConfig, - ensDb: ensDbPublicConfig, - ensIndexer: ensApiPublicConfig.ensIndexerPublicConfig, - ensRainbow: ensApiPublicConfig.ensIndexerPublicConfig.ensRainbowPublicConfig, }; } diff --git a/packages/ensnode-sdk/src/stack-info/index.ts b/packages/ensnode-sdk/src/stack-info/index.ts index f3bf014196..b439a614a2 100644 --- a/packages/ensnode-sdk/src/stack-info/index.ts +++ b/packages/ensnode-sdk/src/stack-info/index.ts @@ -1,3 +1,9 @@ +export * from "./deserialize/ensdb-stack-info"; +export * from "./deserialize/ensindexer-stack-info"; export * from "./deserialize/ensnode-stack-info"; +export * from "./ensdb-stack-info"; +export * from "./ensindexer-stack-info"; export * from "./ensnode-stack-info"; +export * from "./serialize/ensdb-stack-info"; +export * from "./serialize/ensindexer-stack-info"; export * from "./serialize/ensnode-stack-info"; diff --git a/packages/ensnode-sdk/src/stack-info/serialize/ensdb-stack-info.ts b/packages/ensnode-sdk/src/stack-info/serialize/ensdb-stack-info.ts new file mode 100644 index 0000000000..34f2546b53 --- /dev/null +++ b/packages/ensnode-sdk/src/stack-info/serialize/ensdb-stack-info.ts @@ -0,0 +1,23 @@ +import type { SerializedEnsDbPublicConfig } from "../../ensdb/serialize/config"; +import type { EnsDbStackInfo } from "../ensdb-stack-info"; +import { + type SerializedEnsIndexerStackInfo, + serializeEnsIndexerStackInfo, +} from "./ensindexer-stack-info"; + +/** + * Serialized representation of {@link EnsDbStackInfo}. + */ +export interface SerializedEnsDbStackInfo extends SerializedEnsIndexerStackInfo { + ensDb: SerializedEnsDbPublicConfig; +} + +/** + * Serialize a {@link EnsDbStackInfo} object. + */ +export function serializeEnsDbStackInfo(stackInfo: EnsDbStackInfo): SerializedEnsDbStackInfo { + return { + ...serializeEnsIndexerStackInfo(stackInfo), + ensDb: stackInfo.ensDb, // ENSDb Public Config is already in a serialized form, so we can include it directly + }; +} diff --git a/packages/ensnode-sdk/src/stack-info/serialize/ensindexer-stack-info.ts b/packages/ensnode-sdk/src/stack-info/serialize/ensindexer-stack-info.ts new file mode 100644 index 0000000000..8dbca65805 --- /dev/null +++ b/packages/ensnode-sdk/src/stack-info/serialize/ensindexer-stack-info.ts @@ -0,0 +1,24 @@ +import { serializeEnsIndexerPublicConfig } from "../../ensindexer/config/serialize"; +import type { SerializedEnsIndexerPublicConfig } from "../../ensindexer/config/serialized-types"; +import type { SerializedEnsRainbowPublicConfig } from "../../ensrainbow/serialize/config"; +import type { EnsIndexerStackInfo } from "../ensindexer-stack-info"; + +/** + * Serialized representation of {@link EnsIndexerStackInfo}. + */ +export interface SerializedEnsIndexerStackInfo { + ensIndexer: SerializedEnsIndexerPublicConfig; + ensRainbow: SerializedEnsRainbowPublicConfig; +} + +/** + * Serialize a {@link EnsIndexerStackInfo} object. + */ +export function serializeEnsIndexerStackInfo( + stackInfo: EnsIndexerStackInfo, +): SerializedEnsIndexerStackInfo { + return { + ensIndexer: serializeEnsIndexerPublicConfig(stackInfo.ensIndexer), + ensRainbow: stackInfo.ensRainbow, + }; +} diff --git a/packages/ensnode-sdk/src/stack-info/serialize/ensnode-stack-info.ts b/packages/ensnode-sdk/src/stack-info/serialize/ensnode-stack-info.ts index 1c1f2f2638..559ed87295 100644 --- a/packages/ensnode-sdk/src/stack-info/serialize/ensnode-stack-info.ts +++ b/packages/ensnode-sdk/src/stack-info/serialize/ensnode-stack-info.ts @@ -1,19 +1,13 @@ import { serializeEnsApiPublicConfig } from "../../ensapi/config/serialize"; import type { SerializedEnsApiPublicConfig } from "../../ensapi/config/serialized-types"; -import type { SerializedEnsDbPublicConfig } from "../../ensdb/serialize/config"; -import { serializeEnsIndexerPublicConfig } from "../../ensindexer/config/serialize"; -import type { SerializedEnsIndexerPublicConfig } from "../../ensindexer/config/serialized-types"; -import type { SerializedEnsRainbowPublicConfig } from "../../ensrainbow/serialize/config"; import type { EnsNodeStackInfo } from "../ensnode-stack-info"; +import { type SerializedEnsDbStackInfo, serializeEnsDbStackInfo } from "./ensdb-stack-info"; /** * Serialized representation of {@link EnsNodeStackInfo}. */ -export interface SerializedEnsNodeStackInfo { +export interface SerializedEnsNodeStackInfo extends SerializedEnsDbStackInfo { ensApi: SerializedEnsApiPublicConfig; - ensDb: SerializedEnsDbPublicConfig; - ensIndexer: SerializedEnsIndexerPublicConfig; - ensRainbow?: SerializedEnsRainbowPublicConfig; } /** @@ -21,9 +15,7 @@ export interface SerializedEnsNodeStackInfo { */ export function serializeEnsNodeStackInfo(stackInfo: EnsNodeStackInfo): SerializedEnsNodeStackInfo { return { + ...serializeEnsDbStackInfo(stackInfo), ensApi: serializeEnsApiPublicConfig(stackInfo.ensApi), - ensDb: stackInfo.ensDb, - ensIndexer: serializeEnsIndexerPublicConfig(stackInfo.ensIndexer), - ensRainbow: stackInfo.ensRainbow, }; } diff --git a/packages/ensnode-sdk/src/stack-info/zod-schemas/ensdb-stack-info.ts b/packages/ensnode-sdk/src/stack-info/zod-schemas/ensdb-stack-info.ts new file mode 100644 index 0000000000..47a1fdcd4a --- /dev/null +++ b/packages/ensnode-sdk/src/stack-info/zod-schemas/ensdb-stack-info.ts @@ -0,0 +1,24 @@ +import { makeEnsDbPublicConfigSchema } from "../../ensdb/zod-schemas/config"; +import { + invariant_ensRainbowCompatibilityWithEnsIndexer, + makeEnsIndexerStackInfoSchema, + makeSerializedEnsIndexerStackInfoSchema, +} from "./ensindexer-stack-info"; + +export function makeSerializedEnsDbStackInfoSchema(valueLabel?: string) { + const label = valueLabel ?? "EnsDbStackInfo"; + + return makeSerializedEnsIndexerStackInfoSchema(valueLabel).extend({ + ensDb: makeEnsDbPublicConfigSchema(`${label}.ensDb`), + }); +} + +export function makeEnsDbStackInfoSchema(valueLabel?: string) { + const label = valueLabel ?? "EnsDbStackInfo"; + + return makeEnsIndexerStackInfoSchema(valueLabel) + .extend({ + ensDb: makeEnsDbPublicConfigSchema(`${label}.ensDb`), + }) + .check(invariant_ensRainbowCompatibilityWithEnsIndexer); +} diff --git a/packages/ensnode-sdk/src/stack-info/zod-schemas/ensindexer-stack-info.ts b/packages/ensnode-sdk/src/stack-info/zod-schemas/ensindexer-stack-info.ts new file mode 100644 index 0000000000..e654bd5c97 --- /dev/null +++ b/packages/ensnode-sdk/src/stack-info/zod-schemas/ensindexer-stack-info.ts @@ -0,0 +1,51 @@ +import { z } from "zod/v4"; + +import { + makeEnsIndexerPublicConfigSchema, + makeSerializedEnsIndexerPublicConfigSchema, +} from "../../ensindexer/config/zod-schemas"; +import { makeEnsRainbowPublicConfigSchema } from "../../ensrainbow/zod-schemas/config"; +import type { ZodCheckFnInput } from "../../shared/zod-types"; +import type { EnsIndexerStackInfo } from "../ensindexer-stack-info"; + +export function makeSerializedEnsIndexerStackInfoSchema(valueLabel?: string) { + const label = valueLabel ?? "ENSIndexerStackInfo"; + + return z.object({ + ensIndexer: makeSerializedEnsIndexerPublicConfigSchema(`${label}.ensIndexer`), + ensRainbow: makeEnsRainbowPublicConfigSchema(`${label}.ensRainbow`), + }); +} + +export function invariant_ensRainbowCompatibilityWithEnsIndexer( + ctx: ZodCheckFnInput, +) { + const { ensIndexer, ensRainbow } = ctx.value; + + if (ensIndexer.labelSet.labelSetId !== ensRainbow.labelSet.labelSetId) { + ctx.issues.push({ + code: "custom", + input: ctx.value, + message: `ENSRainbow's label set (id: ${ensRainbow.labelSet.labelSetId}) must be same as ENSIndexer's label set (id: ${ensIndexer.labelSet.labelSetId}).`, + }); + } + + if (ensIndexer.labelSet.labelSetVersion > ensRainbow.labelSet.highestLabelSetVersion) { + ctx.issues.push({ + code: "custom", + input: ctx.value, + message: `ENSRainbow's label set version (highest: ${ensRainbow.labelSet.highestLabelSetVersion}) must be greater than or equal to ENSIndexer's label set version (current: ${ensIndexer.labelSet.labelSetVersion}).`, + }); + } +} + +export function makeEnsIndexerStackInfoSchema(valueLabel?: string) { + const label = valueLabel ?? "ENSIndexerStackInfo"; + + return z + .object({ + ensIndexer: makeEnsIndexerPublicConfigSchema(`${label}.ensIndexer`), + ensRainbow: makeEnsRainbowPublicConfigSchema(`${label}.ensRainbow`), + }) + .check(invariant_ensRainbowCompatibilityWithEnsIndexer); +} diff --git a/packages/ensnode-sdk/src/stack-info/zod-schemas/ensnode-stack-info.ts b/packages/ensnode-sdk/src/stack-info/zod-schemas/ensnode-stack-info.ts index 094a17d078..a1e2e4c575 100644 --- a/packages/ensnode-sdk/src/stack-info/zod-schemas/ensnode-stack-info.ts +++ b/packages/ensnode-sdk/src/stack-info/zod-schemas/ensnode-stack-info.ts @@ -18,7 +18,7 @@ export function makeSerializedEnsNodeStackInfoSchema(valueLabel?: string) { ensApi: makeSerializedEnsApiPublicConfigSchema(`${label}.ensApi`), ensDb: makeEnsDbPublicConfigSchema(`${label}.ensDb`), ensIndexer: makeSerializedEnsIndexerPublicConfigSchema(`${label}.ensIndexer`), - ensRainbow: makeEnsRainbowPublicConfigSchema(`${label}.ensRainbow`).optional(), + ensRainbow: makeEnsRainbowPublicConfigSchema(`${label}.ensRainbow`), }); } @@ -29,6 +29,6 @@ export function makeEnsNodeStackInfoSchema(valueLabel?: string) { ensApi: makeEnsApiPublicConfigSchema(`${label}.ensApi`), ensDb: makeEnsDbPublicConfigSchema(`${label}.ensDb`), ensIndexer: makeEnsIndexerPublicConfigSchema(`${label}.ensIndexer`), - ensRainbow: makeEnsRainbowPublicConfigSchema(`${label}.ensRainbow`).optional(), + ensRainbow: makeEnsRainbowPublicConfigSchema(`${label}.ensRainbow`), }); } From 194e4e7f7033ad4cb26c23e515057973a308c74f Mon Sep 17 00:00:00 2001 From: Tomasz Kopacki Date: Thu, 23 Apr 2026 17:43:29 +0200 Subject: [PATCH 02/21] Rename ENSAdmin files for presenting ENSNode Stack Info --- .../app/@breadcrumbs/mock/{config-info => stack-info}/page.tsx | 0 apps/ensadmin/src/app/mock/{config-info => stack-info}/page.tsx | 0 .../mock/{config-info/data.json => stack-info/stack-info.mock.ts} | 0 .../connection/cards/{ensnode-info.tsx => ensnode-stack-info.tsx} | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename apps/ensadmin/src/app/@breadcrumbs/mock/{config-info => stack-info}/page.tsx (100%) rename apps/ensadmin/src/app/mock/{config-info => stack-info}/page.tsx (100%) rename apps/ensadmin/src/app/mock/{config-info/data.json => stack-info/stack-info.mock.ts} (100%) rename apps/ensadmin/src/components/connection/cards/{ensnode-info.tsx => ensnode-stack-info.tsx} (100%) diff --git a/apps/ensadmin/src/app/@breadcrumbs/mock/config-info/page.tsx b/apps/ensadmin/src/app/@breadcrumbs/mock/stack-info/page.tsx similarity index 100% rename from apps/ensadmin/src/app/@breadcrumbs/mock/config-info/page.tsx rename to apps/ensadmin/src/app/@breadcrumbs/mock/stack-info/page.tsx diff --git a/apps/ensadmin/src/app/mock/config-info/page.tsx b/apps/ensadmin/src/app/mock/stack-info/page.tsx similarity index 100% rename from apps/ensadmin/src/app/mock/config-info/page.tsx rename to apps/ensadmin/src/app/mock/stack-info/page.tsx diff --git a/apps/ensadmin/src/app/mock/config-info/data.json b/apps/ensadmin/src/app/mock/stack-info/stack-info.mock.ts similarity index 100% rename from apps/ensadmin/src/app/mock/config-info/data.json rename to apps/ensadmin/src/app/mock/stack-info/stack-info.mock.ts diff --git a/apps/ensadmin/src/components/connection/cards/ensnode-info.tsx b/apps/ensadmin/src/components/connection/cards/ensnode-stack-info.tsx similarity index 100% rename from apps/ensadmin/src/components/connection/cards/ensnode-info.tsx rename to apps/ensadmin/src/components/connection/cards/ensnode-stack-info.tsx From a14378c779b5b14844d0369c15d9519aa320701c Mon Sep 17 00:00:00 2001 From: Tomasz Kopacki Date: Thu, 23 Apr 2026 17:44:26 +0200 Subject: [PATCH 03/21] Update naming convetion for components presenting ENSNode Stack Info --- apps/ensadmin/src/app/mock/page.tsx | 4 +- .../ensadmin/src/app/mock/stack-info/page.tsx | 66 +- .../app/mock/stack-info/stack-info.mock.ts | 564 ++++++++++++------ .../connection/cards/ensnode-stack-info.tsx | 40 +- .../src/components/connection/index.tsx | 4 +- 5 files changed, 444 insertions(+), 234 deletions(-) diff --git a/apps/ensadmin/src/app/mock/page.tsx b/apps/ensadmin/src/app/mock/page.tsx index ebbfc8937b..27eae62019 100644 --- a/apps/ensadmin/src/app/mock/page.tsx +++ b/apps/ensadmin/src/app/mock/page.tsx @@ -19,8 +19,8 @@ export default function MockList() {
- ))} + {[...Object.keys(mockSerializedEnsNodeStackInfo), "Loading", "Loading Error"].map( + (variant) => ( + + ), + )}
- + ); } diff --git a/apps/ensadmin/src/app/mock/stack-info/stack-info.mock.ts b/apps/ensadmin/src/app/mock/stack-info/stack-info.mock.ts index c339d9615a..da1364294a 100644 --- a/apps/ensadmin/src/app/mock/stack-info/stack-info.mock.ts +++ b/apps/ensadmin/src/app/mock/stack-info/stack-info.mock.ts @@ -1,197 +1,413 @@ -{ +import type { SerializedEnsNodeStackInfo } from "@ensnode/ensnode-sdk"; + +/** + * Record of mock SerializedEnsNodeStackInfo objects keyed by variant name. + * These can be deserialized to simulate the full deserialization process. + */ +export const mockSerializedEnsNodeStackInfo = { "Alpha Mainnet": { - "versionInfo": { - "ensApi": "0.35.0", - "ensNormalize": "1.11.1" - }, - "theGraphFallback": { - "canFallback": false, - "reason": "no-api-key" - }, - "ensIndexerPublicConfig": { - "labelSet": { - "labelSetId": "subgraph", - "labelSetVersion": 0 - }, - "indexedChainIds": [1, 8453, 59144, 10, 42161, 534352, 567], - "ensIndexerSchemaName": "alphaSchema0.34.0", - "ensRainbowPublicConfig": { - "version": "0.34.0", - "labelSet": { - "labelSetId": "subgraph", - "highestLabelSetVersion": 0 - }, - "recordsCount": 100 - }, - "isSubgraphCompatible": false, - "namespace": "mainnet", - "plugins": [ + ensApi: { + versionInfo: { + ensApi: "0.35.0", + ensNormalize: "1.11.1", + }, + theGraphFallback: { + canFallback: false, + reason: "no-api-key", + }, + ensIndexerPublicConfig: { + labelSet: { + labelSetId: "subgraph", + labelSetVersion: 0, + }, + indexedChainIds: [1, 8453, 59144, 10, 42161, 534352, 567], + ensIndexerSchemaName: "alphaSchema0.34.0", + isSubgraphCompatible: false, + namespace: "mainnet", + plugins: [ + "subgraph", + "basenames", + "lineanames", + "threedns", + "protocol-acceleration", + "registrars", + "tokenscope", + ], + versionInfo: { + ponder: "0.11.43", + ensDb: "0.35.0", + ensIndexer: "0.35.0", + ensNormalize: "1.11.1", + }, + ensRainbowPublicConfig: { + version: "0.34.0", + labelSet: { + labelSetId: "subgraph", + highestLabelSetVersion: 0, + }, + recordsCount: 100, + }, + }, + }, + ensDb: { + versionInfo: { + postgresql: "18.1", + }, + }, + ensIndexer: { + labelSet: { + labelSetId: "subgraph", + labelSetVersion: 0, + }, + indexedChainIds: [1, 8453, 59144, 10, 42161, 534352, 567], + ensIndexerSchemaName: "alphaSchema0.34.0", + isSubgraphCompatible: false, + namespace: "mainnet", + plugins: [ "subgraph", "basenames", "lineanames", "threedns", "protocol-acceleration", "registrars", - "tokenscope" + "tokenscope", ], - "versionInfo": { - "nodejs": "22.18.0", - "ponder": "0.11.43", - "ensDb": "0.35.0", - "ensIndexer": "0.35.0", - "ensNormalize": "1.11.1" - } - } + versionInfo: { + ponder: "0.11.43", + ensDb: "0.35.0", + ensIndexer: "0.35.0", + ensNormalize: "1.11.1", + }, + ensRainbowPublicConfig: { + version: "0.34.0", + labelSet: { + labelSetId: "subgraph", + highestLabelSetVersion: 0, + }, + recordsCount: 100, + }, + }, + ensRainbow: { + version: "0.34.0", + labelSet: { + labelSetId: "subgraph", + highestLabelSetVersion: 0, + }, + recordsCount: 100, + }, }, "Alpha Sepolia": { - "versionInfo": { - "ensApi": "0.35.0", - "ensNormalize": "1.11.1" - }, - "theGraphFallback": { - "canFallback": true, - "url": "" - }, - "ensIndexerPublicConfig": { - "labelSet": { - "labelSetId": "subgraph", - "labelSetVersion": 0 - }, - "versionInfo": { - "nodejs": "22.18.0", - "ponder": "0.11.43", - "ensDb": "0.35.0", - "ensIndexer": "0.35.0", - "ensNormalize": "1.11.1" - }, - "indexedChainIds": [11155111, 84532, 59141, 11155420, 421614, 534351], - "namespace": "sepolia", - "plugins": [ + ensApi: { + versionInfo: { + ensApi: "0.35.0", + ensNormalize: "1.11.1", + }, + theGraphFallback: { + canFallback: true, + url: "", + }, + ensIndexerPublicConfig: { + labelSet: { + labelSetId: "subgraph", + labelSetVersion: 0, + }, + versionInfo: { + ponder: "0.11.43", + ensDb: "0.35.0", + ensIndexer: "0.35.0", + ensNormalize: "1.11.1", + }, + indexedChainIds: [11155111, 84532, 59141, 11155420, 421614, 534351], + namespace: "sepolia", + plugins: [ + "subgraph", + "basenames", + "lineanames", + "threedns", + "protocol-acceleration", + "registrars", + ], + ensIndexerSchemaName: "alphaSepoliaSchema0.34.0", + isSubgraphCompatible: false, + ensRainbowPublicConfig: { + version: "0.34.0", + labelSet: { + labelSetId: "subgraph", + highestLabelSetVersion: 0, + }, + recordsCount: 100, + }, + }, + }, + ensDb: { + versionInfo: { + postgresql: "18.1", + }, + }, + ensIndexer: { + labelSet: { + labelSetId: "subgraph", + labelSetVersion: 0, + }, + versionInfo: { + ponder: "0.11.43", + ensDb: "0.35.0", + ensIndexer: "0.35.0", + ensNormalize: "1.11.1", + }, + indexedChainIds: [11155111, 84532, 59141, 11155420, 421614, 534351], + namespace: "sepolia", + plugins: [ "subgraph", "basenames", "lineanames", "threedns", "protocol-acceleration", - "registrars" + "registrars", ], - "ensIndexerSchemaName": "alphaSepoliaSchema0.34.0", - "ensRainbowPublicConfig": { - "version": "0.34.0", - "labelSet": { - "labelSetId": "subgraph", - "highestLabelSetVersion": 0 + ensIndexerSchemaName: "alphaSepoliaSchema0.34.0", + isSubgraphCompatible: false, + ensRainbowPublicConfig: { + version: "0.34.0", + labelSet: { + labelSetId: "subgraph", + highestLabelSetVersion: 0, }, - "recordsCount": 100 + recordsCount: 100, + }, + }, + ensRainbow: { + version: "0.34.0", + labelSet: { + labelSetId: "subgraph", + highestLabelSetVersion: 0, }, - "isSubgraphCompatible": false - } + recordsCount: 100, + }, }, "Subgraph Mainnet": { - "versionInfo": { - "ensApi": "0.35.0", - "ensNormalize": "1.11.1" - }, - "theGraphFallback": { - "canFallback": false, - "reason": "no-api-key" - }, - "ensIndexerPublicConfig": { - "labelSet": { - "labelSetId": "subgraph", - "labelSetVersion": 0 - }, - "versionInfo": { - "nodejs": "22.18.0", - "ponder": "0.11.43", - "ensDb": "0.35.0", - "ensIndexer": "0.35.0", - "ensNormalize": "1.11.1" - }, - "indexedChainIds": [1], - "namespace": "mainnet", - "plugins": ["subgraph"], - "ensIndexerSchemaName": "mainnetSchema0.34.0", - "ensRainbowPublicConfig": { - "version": "0.34.0", - "labelSet": { - "labelSetId": "subgraph", - "highestLabelSetVersion": 0 - }, - "recordsCount": 100 - }, - "isSubgraphCompatible": true - } + ensApi: { + versionInfo: { + ensApi: "0.35.0", + ensNormalize: "1.11.1", + }, + theGraphFallback: { + canFallback: false, + reason: "no-api-key", + }, + ensIndexerPublicConfig: { + labelSet: { + labelSetId: "subgraph", + labelSetVersion: 0, + }, + versionInfo: { + ponder: "0.11.43", + ensDb: "0.35.0", + ensIndexer: "0.35.0", + ensNormalize: "1.11.1", + }, + indexedChainIds: [1], + namespace: "mainnet", + plugins: ["subgraph"], + ensIndexerSchemaName: "mainnetSchema0.34.0", + isSubgraphCompatible: true, + ensRainbowPublicConfig: { + version: "0.34.0", + labelSet: { + labelSetId: "subgraph", + highestLabelSetVersion: 0, + }, + recordsCount: 100, + }, + }, + }, + ensDb: { + versionInfo: { + postgresql: "18.1", + }, + }, + ensIndexer: { + labelSet: { + labelSetId: "subgraph", + labelSetVersion: 0, + }, + versionInfo: { + ponder: "0.11.43", + ensDb: "0.35.0", + ensIndexer: "0.35.0", + ensNormalize: "1.11.1", + }, + indexedChainIds: [1], + namespace: "mainnet", + plugins: ["subgraph"], + ensIndexerSchemaName: "mainnetSchema0.34.0", + isSubgraphCompatible: true, + ensRainbowPublicConfig: { + version: "0.34.0", + labelSet: { + labelSetId: "subgraph", + highestLabelSetVersion: 0, + }, + recordsCount: 100, + }, + }, + ensRainbow: { + version: "0.34.0", + labelSet: { + labelSetId: "subgraph", + highestLabelSetVersion: 0, + }, + recordsCount: 100, + }, }, "Subgraph Sepolia": { - "versionInfo": { - "ensApi": "0.35.0", - "ensNormalize": "1.11.1" - }, - "theGraphFallback": { - "canFallback": false, - "reason": "no-api-key" - }, - "ensIndexerPublicConfig": { - "labelSet": { - "labelSetId": "subgraph", - "labelSetVersion": 0 - }, - "versionInfo": { - "nodejs": "22.18.0", - "ponder": "0.11.43", - "ensDb": "0.35.0", - "ensIndexer": "0.35.0", - "ensNormalize": "1.11.1" - }, - "indexedChainIds": [11155111], - "namespace": "sepolia", - "plugins": ["subgraph"], - "ensIndexerSchemaName": "sepoliaSchema0.34.0", - "ensRainbowPublicConfig": { - "version": "0.34.0", - "labelSet": { - "labelSetId": "subgraph", - "highestLabelSetVersion": 0 - }, - "recordsCount": 100 - }, - "isSubgraphCompatible": true - } + ensApi: { + versionInfo: { + ensApi: "0.35.0", + ensNormalize: "1.11.1", + }, + theGraphFallback: { + canFallback: false, + reason: "no-api-key", + }, + ensIndexerPublicConfig: { + labelSet: { + labelSetId: "subgraph", + labelSetVersion: 0, + }, + versionInfo: { + ponder: "0.11.43", + ensDb: "0.35.0", + ensIndexer: "0.35.0", + ensNormalize: "1.11.1", + }, + indexedChainIds: [11155111], + namespace: "sepolia", + plugins: ["subgraph"], + ensIndexerSchemaName: "sepoliaSchema0.34.0", + isSubgraphCompatible: true, + ensRainbowPublicConfig: { + version: "0.34.0", + labelSet: { + labelSetId: "subgraph", + highestLabelSetVersion: 0, + }, + recordsCount: 100, + }, + }, + }, + ensDb: { + versionInfo: { + postgresql: "18.1", + }, + }, + ensIndexer: { + labelSet: { + labelSetId: "subgraph", + labelSetVersion: 0, + }, + versionInfo: { + ponder: "0.11.43", + ensDb: "0.35.0", + ensIndexer: "0.35.0", + ensNormalize: "1.11.1", + }, + indexedChainIds: [11155111], + namespace: "sepolia", + plugins: ["subgraph"], + ensIndexerSchemaName: "sepoliaSchema0.34.0", + isSubgraphCompatible: true, + ensRainbowPublicConfig: { + version: "0.34.0", + labelSet: { + labelSetId: "subgraph", + highestLabelSetVersion: 0, + }, + recordsCount: 100, + }, + }, + ensRainbow: { + version: "0.34.0", + labelSet: { + labelSetId: "subgraph", + highestLabelSetVersion: 0, + }, + recordsCount: 100, + }, + }, + "Deserialization Error": { + ensApi: { + versionInfo: { + ensApi: "0.35.0", + ensNormalize: "1.11.1", + }, + theGraphFallback: { + canFallback: false, + reason: "no-api-key", + }, + ensIndexerPublicConfig: { + labelSet: { + labelSetId: "", + labelSetVersion: 0, + }, + versionInfo: { + ponder: "", + ensDb: "", + ensIndexer: "", + ensNormalize: "", + }, + indexedChainIds: [11155111], + namespace: "sepolia", + plugins: ["subgraph"], + ensIndexerSchemaName: "DeserializationSchema0.34.0", + isSubgraphCompatible: true, + ensRainbowPublicConfig: { + version: "", + labelSet: { + labelSetId: "", + highestLabelSetVersion: -1, + }, + recordsCount: -1, + }, + }, + }, + ensDb: { + versionInfo: { + postgresql: "18.1", + }, + }, + ensIndexer: { + labelSet: { + labelSetId: "", + labelSetVersion: 0, + }, + versionInfo: { + ponder: "", + ensDb: "", + ensIndexer: "", + ensNormalize: "", + }, + indexedChainIds: [11155111], + namespace: "sepolia", + plugins: ["subgraph"], + ensIndexerSchemaName: "DeserializationSchema0.34.0", + isSubgraphCompatible: true, + ensRainbowPublicConfig: { + version: "", + labelSet: { + labelSetId: "", + highestLabelSetVersion: -1, + }, + recordsCount: -1, + }, + }, + ensRainbow: { + version: "", + labelSet: { + labelSetId: "", + highestLabelSetVersion: -1, + }, + recordsCount: -1, + }, }, - "Serialization Error": { - "versionInfo": { - "ensApi": "0.35.0", - "ensNormalize": "1.11.1" - }, - "theGraphFallback": { - "canFallback": false, - "reason": "no-api-key" - }, - "ensIndexerPublicConfig": { - "labelSet": { - "labelSetId": "", - "labelSetVersion": 0 - }, - "versionInfo": { - "nodejs": "", - "ponder": "", - "ensDb": "", - "ensIndexer": "", - "ensNormalize": "" - }, - "indexedChainIds": [11155111], - "namespace": "sepolia", - "plugins": ["subgraph"], - "ensIndexerSchemaName": "DeserializationSchema0.34.0", - "ensRainbowPublicConfig": { - "version": "", - "labelSet": { - "labelSetId": "", - "highestLabelSetVersion": -1 - }, - "recordsCount": -1 - }, - "isSubgraphCompatible": true - } - } -} +} as const satisfies Record; diff --git a/apps/ensadmin/src/components/connection/cards/ensnode-stack-info.tsx b/apps/ensadmin/src/components/connection/cards/ensnode-stack-info.tsx index 47baa1022f..80776d4c79 100644 --- a/apps/ensadmin/src/components/connection/cards/ensnode-stack-info.tsx +++ b/apps/ensadmin/src/components/connection/cards/ensnode-stack-info.tsx @@ -93,27 +93,29 @@ function ENSNodeCardLoadingSkeleton() { } /** - * Props for ENSNodeConfigCardDisplay - display component that accepts props for testing/mocking + * Props for EnsNodeStackInfoCardDisplay - display component that accepts props for testing/mocking */ -export interface ENSNodeConfigCardDisplayProps { +export interface EnsNodeStackInfoCardDisplayProps { ensNodeStackInfo: EnsNodeStackInfo; } /** * Display component that receives props - used for reusable/mockable presentation */ -export function ENSNodeConfigCardDisplay({ ensNodeStackInfo }: ENSNodeConfigCardDisplayProps) { +export function EnsNodeStackInfoCardDisplay({ + ensNodeStackInfo, +}: EnsNodeStackInfoCardDisplayProps) { return ( - + ); } /** - * Props for ENSNodeConfigInfoView - internal component that accepts props for testing/mocking + * Props for DisplayEnsNodeStackInfo - internal component that accepts props for testing/mocking */ -export interface ENSNodeConfigInfoViewProps { +export interface DisplayEnsNodeStackInfoProps { ensNodeStackInfo?: EnsNodeStackInfo; error?: ErrorInfoProps; isLoading?: boolean; @@ -122,11 +124,11 @@ export interface ENSNodeConfigInfoViewProps { /** * Internal view component that accepts props - used by both the main component and mock pages */ -export function ENSNodeConfigInfoView({ +export function DisplayEnsNodeStackInfo({ ensNodeStackInfo, error, isLoading = false, -}: ENSNodeConfigInfoViewProps) { +}: DisplayEnsNodeStackInfoProps) { if (error) { return ; } @@ -140,18 +142,18 @@ export function ENSNodeConfigInfoView({ ); } - return ; + return ; } /** - * ENSNodeConfigInfo component - fetches and displays ENSNode configuration data + * LoadAndDisplayEnsNodeStackInfo component - fetches and displays ENSNode configuration data */ -export function ENSNodeConfigInfo() { +export function LoadAndDisplayEnsNodeStackInfo() { const ensNodeStackInfo = useEnsNodeStackInfo(); if (ensNodeStackInfo.isError) { return ( - ; + return ; } - return ; + return ; } -function ENSNodeConfigCardContent({ ensNodeStackInfo }: { ensNodeStackInfo: EnsNodeStackInfo }) { +function EnsNodeStackInfoCardContent({ ensNodeStackInfo }: { ensNodeStackInfo: EnsNodeStackInfo }) { const cardItemValueStyles = "text-sm leading-6 font-normal text-black"; const { @@ -597,7 +599,7 @@ function ENSNodeConfigCardContent({ ensNodeStackInfo }: { ensNodeStackInfo: EnsN icon={} version={

- v{ensIndexerPublicConfig.ensRainbowPublicConfig.version} + v{ensRainbowPublicConfig.version}

} docsLink={new URL("https://ensnode.io/ensrainbow")} @@ -607,8 +609,8 @@ function ENSNodeConfigCardContent({ ensNodeStackInfo }: { ensNodeStackInfo: EnsN label="Server LabelSet" value={

- {ensIndexerPublicConfig.ensRainbowPublicConfig.labelSet.labelSetId}: - {ensIndexerPublicConfig.ensRainbowPublicConfig.labelSet.highestLabelSetVersion} + {ensRainbowPublicConfig.labelSet.labelSetId}: + {ensRainbowPublicConfig.labelSet.highestLabelSetVersion}

} additionalInfo={ @@ -627,7 +629,7 @@ function ENSNodeConfigCardContent({ ensNodeStackInfo }: { ensNodeStackInfo: EnsN label="Records Count" value={

- {ensIndexerPublicConfig.ensRainbowPublicConfig.recordsCount.toLocaleString()} + {ensRainbowPublicConfig.recordsCount.toLocaleString()}

} additionalInfo={ diff --git a/apps/ensadmin/src/components/connection/index.tsx b/apps/ensadmin/src/components/connection/index.tsx index 0d58bde069..af79e327e6 100644 --- a/apps/ensadmin/src/components/connection/index.tsx +++ b/apps/ensadmin/src/components/connection/index.tsx @@ -4,7 +4,7 @@ import { InfoCardConnector } from "@/components/connection/shared/info-card"; import { ConnectionInfo } from "./cards/connection-info"; import { ENSAdminInfo } from "./cards/ensadmin-info"; -import { ENSNodeConfigInfo } from "./cards/ensnode-info"; +import { LoadAndDisplayEnsNodeStackInfo } from "./cards/ensnode-stack-info"; export default function DisplayConnectionDetails() { return ( @@ -18,7 +18,7 @@ export default function DisplayConnectionDetails() { - + ); From 7f3d3e77223b65ee3c263941e44eb91d2035121f Mon Sep 17 00:00:00 2001 From: Tomasz Kopacki Date: Thu, 23 Apr 2026 17:45:31 +0200 Subject: [PATCH 04/21] Integrate updated `EnsNodeStackInfo` data model into ENSApi --- apps/ensapi/src/cache/stack-info.cache.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/ensapi/src/cache/stack-info.cache.ts b/apps/ensapi/src/cache/stack-info.cache.ts index 7bc864bf6f..3a94a38b5c 100644 --- a/apps/ensapi/src/cache/stack-info.cache.ts +++ b/apps/ensapi/src/cache/stack-info.cache.ts @@ -30,8 +30,15 @@ async function loadEnsNodeStackInfo( const ensApiPublicConfig = buildEnsApiPublicConfig(config); const ensDbPublicConfig = await ensDbClient.buildEnsDbPublicConfig(); + const ensIndexerPublicConfig = ensApiPublicConfig.ensIndexerPublicConfig; + const ensRainbowPublicConfig = ensIndexerPublicConfig.ensRainbowPublicConfig; - return buildEnsNodeStackInfo(ensApiPublicConfig, ensDbPublicConfig); + return buildEnsNodeStackInfo( + ensApiPublicConfig, + ensDbPublicConfig, + ensIndexerPublicConfig, + ensRainbowPublicConfig, + ); } // lazyProxy defers construction until first use so that this module can be From f7249e0d2e144a6de426066161069def556ff79e Mon Sep 17 00:00:00 2001 From: Tomasz Kopacki Date: Thu, 23 Apr 2026 17:52:26 +0200 Subject: [PATCH 05/21] docs(changeset): Introduced a set of "stack info" data models: `EnsIndexerStackInfo`, `EnsDbStackInfo`, `EnsNodeStackInfo`. --- .changeset/fifty-games-smash.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/fifty-games-smash.md diff --git a/.changeset/fifty-games-smash.md b/.changeset/fifty-games-smash.md new file mode 100644 index 0000000000..c0e8ec97c4 --- /dev/null +++ b/.changeset/fifty-games-smash.md @@ -0,0 +1,5 @@ +--- +"@ensnode/ensnode-sdk": minor +--- + +Introduced a set of "stack info" data models: `EnsIndexerStackInfo`, `EnsDbStackInfo`, `EnsNodeStackInfo`. From 64c4fa8a3cc27c2aa78e2bba446cf4da922cb37c Mon Sep 17 00:00:00 2001 From: Tomasz Kopacki Date: Thu, 23 Apr 2026 17:54:12 +0200 Subject: [PATCH 06/21] docs(changeset): Renamed `ENSNodeConfig*` components to follow the `EnsNodeStackInfo*` pattern. --- .changeset/clear-rabbits-punch.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/clear-rabbits-punch.md diff --git a/.changeset/clear-rabbits-punch.md b/.changeset/clear-rabbits-punch.md new file mode 100644 index 0000000000..19b91950c7 --- /dev/null +++ b/.changeset/clear-rabbits-punch.md @@ -0,0 +1,5 @@ +--- +"ensadmin": minor +--- + +Renamed `ENSNodeConfig*` components to follow the `EnsNodeStackInfo*` pattern. From fb2285fa116ec8b2d57ff555569d81ed8649ed5d Mon Sep 17 00:00:00 2001 From: Tomasz Kopacki Date: Thu, 23 Apr 2026 18:18:11 +0200 Subject: [PATCH 07/21] Apply AI PR feedback for ENSNode SDK --- .../ensnode-sdk/src/ensnode/client.test.ts | 18 ++--- .../src/stack-info/ensnode-stack-info.ts | 2 +- .../zod-schemas/ensdb-stack-info.ts | 4 +- .../zod-schemas/ensindexer-stack-info.ts | 2 +- .../zod-schemas/ensnode-stack-info.ts | 75 ++++++++++++++----- 5 files changed, 70 insertions(+), 31 deletions(-) diff --git a/packages/ensnode-sdk/src/ensnode/client.test.ts b/packages/ensnode-sdk/src/ensnode/client.test.ts index d23e7a9ce0..a3e5b7dcf5 100644 --- a/packages/ensnode-sdk/src/ensnode/client.test.ts +++ b/packages/ensnode-sdk/src/ensnode/client.test.ts @@ -71,7 +71,7 @@ const EXAMPLE_ENSAPI_CONFIG_RESPONSE = { }, ensIndexerPublicConfig: { ensRainbowPublicConfig: { - version: "0.31.0", + version: "1.9.0", labelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, recordsCount: 100, }, @@ -80,7 +80,7 @@ const EXAMPLE_ENSAPI_CONFIG_RESPONSE = { labelSetVersion: 0, }, indexedChainIds: [1, 8453, 59144, 10, 42161, 534352], - ensIndexerSchemaName: "alphaSchema0.31.0", + ensIndexerSchemaName: "alphaSchema1.9.0", isSubgraphCompatible: false, namespace: "mainnet", plugins: [ @@ -93,8 +93,8 @@ const EXAMPLE_ENSAPI_CONFIG_RESPONSE = { ], versionInfo: { ponder: "0.11.43", - ensDb: "0.32.0", - ensIndexer: "0.32.0", + ensDb: "1.9.0", + ensIndexer: "1.9.0", ensNormalize: "1.11.1", }, }, @@ -108,7 +108,7 @@ const EXAMPLE_ENSDB_PUBLIC_RESPONSE = { const EXAMPLE_ENSINDEXER_PUBLIC_CONFIG = { ensRainbowPublicConfig: { - version: "0.31.0", + version: "1.9.0", labelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, recordsCount: 100, }, @@ -117,7 +117,7 @@ const EXAMPLE_ENSINDEXER_PUBLIC_CONFIG = { labelSetVersion: 0, }, indexedChainIds: [1, 8453, 59144, 10, 42161, 534352], - ensIndexerSchemaName: "alphaSchema0.31.0", + ensIndexerSchemaName: "alphaSchema1.9.0", isSubgraphCompatible: false, namespace: "mainnet", plugins: [ @@ -130,14 +130,14 @@ const EXAMPLE_ENSINDEXER_PUBLIC_CONFIG = { ], versionInfo: { ponder: "0.11.43", - ensDb: "0.32.0", - ensIndexer: "0.32.0", + ensDb: "1.9.0", + ensIndexer: "1.9.0", ensNormalize: "1.11.1", }, } satisfies SerializedEnsIndexerPublicConfig; const EXAMPLE_ENSRAINBOW_PUBLIC_CONFIG = { - version: "0.31.0", + version: "1.9.0", labelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, recordsCount: 100, } satisfies SerializedEnsRainbowPublicConfig; diff --git a/packages/ensnode-sdk/src/stack-info/ensnode-stack-info.ts b/packages/ensnode-sdk/src/stack-info/ensnode-stack-info.ts index d8847d356d..9c8d374353 100644 --- a/packages/ensnode-sdk/src/stack-info/ensnode-stack-info.ts +++ b/packages/ensnode-sdk/src/stack-info/ensnode-stack-info.ts @@ -16,7 +16,7 @@ export interface EnsNodeStackInfo extends EnsDbStackInfo { /** * Build a complete {@link EnsNodeStackInfo} object from - * the given public configs of ENSApi and ENSDb. + * the given public configs of ENSApi, ENSDb, ENSIndexer, and ENSRainbow. */ export function buildEnsNodeStackInfo( ensApiPublicConfig: EnsApiPublicConfig, diff --git a/packages/ensnode-sdk/src/stack-info/zod-schemas/ensdb-stack-info.ts b/packages/ensnode-sdk/src/stack-info/zod-schemas/ensdb-stack-info.ts index 47a1fdcd4a..7cc8edbc89 100644 --- a/packages/ensnode-sdk/src/stack-info/zod-schemas/ensdb-stack-info.ts +++ b/packages/ensnode-sdk/src/stack-info/zod-schemas/ensdb-stack-info.ts @@ -8,7 +8,7 @@ import { export function makeSerializedEnsDbStackInfoSchema(valueLabel?: string) { const label = valueLabel ?? "EnsDbStackInfo"; - return makeSerializedEnsIndexerStackInfoSchema(valueLabel).extend({ + return makeSerializedEnsIndexerStackInfoSchema(label).extend({ ensDb: makeEnsDbPublicConfigSchema(`${label}.ensDb`), }); } @@ -16,7 +16,7 @@ export function makeSerializedEnsDbStackInfoSchema(valueLabel?: string) { export function makeEnsDbStackInfoSchema(valueLabel?: string) { const label = valueLabel ?? "EnsDbStackInfo"; - return makeEnsIndexerStackInfoSchema(valueLabel) + return makeEnsIndexerStackInfoSchema(label) .extend({ ensDb: makeEnsDbPublicConfigSchema(`${label}.ensDb`), }) diff --git a/packages/ensnode-sdk/src/stack-info/zod-schemas/ensindexer-stack-info.ts b/packages/ensnode-sdk/src/stack-info/zod-schemas/ensindexer-stack-info.ts index e654bd5c97..fda9973029 100644 --- a/packages/ensnode-sdk/src/stack-info/zod-schemas/ensindexer-stack-info.ts +++ b/packages/ensnode-sdk/src/stack-info/zod-schemas/ensindexer-stack-info.ts @@ -26,7 +26,7 @@ export function invariant_ensRainbowCompatibilityWithEnsIndexer( ctx.issues.push({ code: "custom", input: ctx.value, - message: `ENSRainbow's label set (id: ${ensRainbow.labelSet.labelSetId}) must be same as ENSIndexer's label set (id: ${ensIndexer.labelSet.labelSetId}).`, + message: `ENSRainbow's label set (id: ${ensRainbow.labelSet.labelSetId}) must be same as the ENSIndexer's label set (id: ${ensIndexer.labelSet.labelSetId}).`, }); } diff --git a/packages/ensnode-sdk/src/stack-info/zod-schemas/ensnode-stack-info.ts b/packages/ensnode-sdk/src/stack-info/zod-schemas/ensnode-stack-info.ts index a1e2e4c575..ebf513016b 100644 --- a/packages/ensnode-sdk/src/stack-info/zod-schemas/ensnode-stack-info.ts +++ b/packages/ensnode-sdk/src/stack-info/zod-schemas/ensnode-stack-info.ts @@ -1,34 +1,73 @@ -import { z } from "zod/v4"; - import { makeEnsApiPublicConfigSchema, makeSerializedEnsApiPublicConfigSchema, } from "../../ensapi/config/zod-schemas"; -import { makeEnsDbPublicConfigSchema } from "../../ensdb/zod-schemas/config"; -import { - makeEnsIndexerPublicConfigSchema, - makeSerializedEnsIndexerPublicConfigSchema, -} from "../../ensindexer/config/zod-schemas"; -import { makeEnsRainbowPublicConfigSchema } from "../../ensrainbow/zod-schemas/config"; +import type { ZodCheckFnInput } from "../../shared/zod-types"; +import type { EnsNodeStackInfo } from "../ensnode-stack-info"; +import { makeEnsDbStackInfoSchema, makeSerializedEnsDbStackInfoSchema } from "./ensdb-stack-info"; +import { invariant_ensRainbowCompatibilityWithEnsIndexer } from "./ensindexer-stack-info"; + +function invariant_ensApiCompatibilityWithEnsIndexerAndEnsRainbow( + ctx: ZodCheckFnInput, +) { + const { ensApi, ensIndexer, ensRainbow } = ctx.value; + + // Invariant: ENSApi & ENSDB must match version numbers + if (ensIndexer.versionInfo.ensDb !== ensApi.versionInfo.ensApi) { + ctx.issues.push({ + code: "custom", + path: ["ensIndexer.versionInfo.ensDb"], + input: ensIndexer.versionInfo.ensDb, + message: `Version Mismatch: ENSDB@${ensIndexer.versionInfo.ensDb} !== ENSApi@${ensApi.versionInfo.ensApi}`, + }); + } + + // Invariant: ENSApi & ENSIndexer must match version numbers + if (ensIndexer.versionInfo.ensIndexer !== ensApi.versionInfo.ensApi) { + ctx.issues.push({ + code: "custom", + path: ["ensIndexer.versionInfo.ensIndexer"], + input: ensIndexer.versionInfo.ensIndexer, + message: `Version Mismatch: ENSIndexer@${ensIndexer.versionInfo.ensIndexer} !== ENSApi@${ensApi.versionInfo.ensApi}`, + }); + } + + // Invariant: ENSApi & ENSRainbow must match version numbers + if (ensRainbow.version !== ensApi.versionInfo.ensApi) { + ctx.issues.push({ + code: "custom", + path: ["ensRainbow.version"], + input: ensRainbow.version, + message: `Version Mismatch: ENSRainbow@${ensRainbow.version} !== ENSApi@${ensApi.versionInfo.ensApi}`, + }); + } + + // Invariant: `@adraffy/ens-normalize` package version must match between ENSApi & ENSIndexer + if (ensIndexer.versionInfo.ensNormalize !== ensApi.versionInfo.ensNormalize) { + ctx.issues.push({ + code: "custom", + path: ["ensIndexer.versionInfo.ensNormalize"], + input: ensIndexer.versionInfo.ensNormalize, + message: `Dependency Version Mismatch: '@adraffy/ens-normalize' version must be the same between ENSIndexer and ENSApi. Found ENSApi@${ensApi.versionInfo.ensNormalize} and ENSIndexer@${ensIndexer.versionInfo.ensNormalize}`, + }); + } +} export function makeSerializedEnsNodeStackInfoSchema(valueLabel?: string) { const label = valueLabel ?? "ENSNodeStackInfo"; - return z.object({ + return makeSerializedEnsDbStackInfoSchema(label).extend({ ensApi: makeSerializedEnsApiPublicConfigSchema(`${label}.ensApi`), - ensDb: makeEnsDbPublicConfigSchema(`${label}.ensDb`), - ensIndexer: makeSerializedEnsIndexerPublicConfigSchema(`${label}.ensIndexer`), - ensRainbow: makeEnsRainbowPublicConfigSchema(`${label}.ensRainbow`), }); } export function makeEnsNodeStackInfoSchema(valueLabel?: string) { const label = valueLabel ?? "ENSNodeStackInfo"; - return z.object({ - ensApi: makeEnsApiPublicConfigSchema(`${label}.ensApi`), - ensDb: makeEnsDbPublicConfigSchema(`${label}.ensDb`), - ensIndexer: makeEnsIndexerPublicConfigSchema(`${label}.ensIndexer`), - ensRainbow: makeEnsRainbowPublicConfigSchema(`${label}.ensRainbow`), - }); + return makeEnsDbStackInfoSchema(label) + .extend({ + ensApi: makeEnsApiPublicConfigSchema(`${label}.ensApi`), + }) + .check(invariant_ensApiCompatibilityWithEnsIndexerAndEnsRainbow) + .check(invariant_ensRainbowCompatibilityWithEnsIndexer); } From ab5f265b8b14a656f1d533bd59f69a87c38ddab8 Mon Sep 17 00:00:00 2001 From: Tomasz Kopacki Date: Thu, 23 Apr 2026 18:18:17 +0200 Subject: [PATCH 08/21] Apply AI PR feedback for ENSAdmin --- .../ensadmin/src/app/mock/stack-info/page.tsx | 10 +- .../app/mock/stack-info/stack-info.mock.ts | 587 +++++++----------- 2 files changed, 244 insertions(+), 353 deletions(-) diff --git a/apps/ensadmin/src/app/mock/stack-info/page.tsx b/apps/ensadmin/src/app/mock/stack-info/page.tsx index 5966495326..de8c02b610 100644 --- a/apps/ensadmin/src/app/mock/stack-info/page.tsx +++ b/apps/ensadmin/src/app/mock/stack-info/page.tsx @@ -27,8 +27,8 @@ export default function MockConfigPage() { case "Loading Error": return { error: { - title: "ENSNodeConfigInfo Error", - description: "Failed to fetch ENSIndexer Config.", + title: "EnsNodeStackInfo Error", + description: "Failed to fetch EnsNodeStackInfo.", }, }; @@ -47,7 +47,7 @@ export default function MockConfigPage() { : "Unknown EnsNodeStackInfo deserialization error"; return { error: { - title: "Deserialization Error", + title: "EnsNodeStackInfo Deserialization Error", description: errorMessage, }, }; @@ -59,8 +59,8 @@ export default function MockConfigPage() {
- Mock: ENSNodeStackInfo - Select a mock ENSNodeStackInfo variant + Mock: EnsNodeStackInfo + Select a mock EnsNodeStackInfo variant diff --git a/apps/ensadmin/src/app/mock/stack-info/stack-info.mock.ts b/apps/ensadmin/src/app/mock/stack-info/stack-info.mock.ts index da1364294a..3a1e7b8359 100644 --- a/apps/ensadmin/src/app/mock/stack-info/stack-info.mock.ts +++ b/apps/ensadmin/src/app/mock/stack-info/stack-info.mock.ts @@ -1,350 +1,209 @@ -import type { SerializedEnsNodeStackInfo } from "@ensnode/ensnode-sdk"; +import type { + SerializedEnsApiPublicConfig, + SerializedEnsIndexerPublicConfig, + SerializedEnsNodeStackInfo, + TheGraphFallback, +} from "@ensnode/ensnode-sdk"; -/** - * Record of mock SerializedEnsNodeStackInfo objects keyed by variant name. - * These can be deserialized to simulate the full deserialization process. - */ -export const mockSerializedEnsNodeStackInfo = { - "Alpha Mainnet": { - ensApi: { - versionInfo: { - ensApi: "0.35.0", - ensNormalize: "1.11.1", - }, - theGraphFallback: { - canFallback: false, - reason: "no-api-key", - }, - ensIndexerPublicConfig: { - labelSet: { - labelSetId: "subgraph", - labelSetVersion: 0, - }, - indexedChainIds: [1, 8453, 59144, 10, 42161, 534352, 567], - ensIndexerSchemaName: "alphaSchema0.34.0", - isSubgraphCompatible: false, - namespace: "mainnet", - plugins: [ - "subgraph", - "basenames", - "lineanames", - "threedns", - "protocol-acceleration", - "registrars", - "tokenscope", - ], - versionInfo: { - ponder: "0.11.43", - ensDb: "0.35.0", - ensIndexer: "0.35.0", - ensNormalize: "1.11.1", - }, - ensRainbowPublicConfig: { - version: "0.34.0", - labelSet: { - labelSetId: "subgraph", - highestLabelSetVersion: 0, - }, - recordsCount: 100, - }, - }, - }, - ensDb: { - versionInfo: { - postgresql: "18.1", - }, - }, - ensIndexer: { - labelSet: { - labelSetId: "subgraph", - labelSetVersion: 0, - }, - indexedChainIds: [1, 8453, 59144, 10, 42161, 534352, 567], - ensIndexerSchemaName: "alphaSchema0.34.0", - isSubgraphCompatible: false, - namespace: "mainnet", - plugins: [ - "subgraph", - "basenames", - "lineanames", - "threedns", - "protocol-acceleration", - "registrars", - "tokenscope", - ], - versionInfo: { - ponder: "0.11.43", - ensDb: "0.35.0", - ensIndexer: "0.35.0", - ensNormalize: "1.11.1", - }, - ensRainbowPublicConfig: { - version: "0.34.0", - labelSet: { - labelSetId: "subgraph", - highestLabelSetVersion: 0, - }, - recordsCount: 100, - }, - }, - ensRainbow: { - version: "0.34.0", - labelSet: { - labelSetId: "subgraph", - highestLabelSetVersion: 0, - }, - recordsCount: 100, - }, +// ============================================================================ +// Shared Constants +// ============================================================================ + +const COMMON_ENS_DB = { + versionInfo: { + postgresql: "18.1", }, - "Alpha Sepolia": { - ensApi: { - versionInfo: { - ensApi: "0.35.0", - ensNormalize: "1.11.1", - }, - theGraphFallback: { - canFallback: true, - url: "", - }, - ensIndexerPublicConfig: { - labelSet: { - labelSetId: "subgraph", - labelSetVersion: 0, - }, - versionInfo: { - ponder: "0.11.43", - ensDb: "0.35.0", - ensIndexer: "0.35.0", - ensNormalize: "1.11.1", - }, - indexedChainIds: [11155111, 84532, 59141, 11155420, 421614, 534351], - namespace: "sepolia", - plugins: [ - "subgraph", - "basenames", - "lineanames", - "threedns", - "protocol-acceleration", - "registrars", - ], - ensIndexerSchemaName: "alphaSepoliaSchema0.34.0", - isSubgraphCompatible: false, - ensRainbowPublicConfig: { - version: "0.34.0", - labelSet: { - labelSetId: "subgraph", - highestLabelSetVersion: 0, - }, - recordsCount: 100, - }, - }, - }, - ensDb: { - versionInfo: { - postgresql: "18.1", - }, - }, - ensIndexer: { - labelSet: { - labelSetId: "subgraph", - labelSetVersion: 0, - }, - versionInfo: { - ponder: "0.11.43", - ensDb: "0.35.0", - ensIndexer: "0.35.0", - ensNormalize: "1.11.1", - }, - indexedChainIds: [11155111, 84532, 59141, 11155420, 421614, 534351], - namespace: "sepolia", - plugins: [ - "subgraph", - "basenames", - "lineanames", - "threedns", - "protocol-acceleration", - "registrars", - ], - ensIndexerSchemaName: "alphaSepoliaSchema0.34.0", - isSubgraphCompatible: false, - ensRainbowPublicConfig: { - version: "0.34.0", - labelSet: { - labelSetId: "subgraph", - highestLabelSetVersion: 0, - }, - recordsCount: 100, - }, - }, - ensRainbow: { - version: "0.34.0", - labelSet: { - labelSetId: "subgraph", - highestLabelSetVersion: 0, - }, - recordsCount: 100, - }, +} as const; + +const COMMON_VERSION_INFO = { + ponder: "0.11.43", + ensDb: "1.9.0", + ensIndexer: "1.9.0", + ensNormalize: "1.11.1", +} as const; + +const COMMON_ENS_API_VERSION_INFO = { + ensApi: "1.9.0", + ensNormalize: "1.11.1", +} as const; + +const COMMON_LABEL_SET = { + labelSetId: "subgraph", + labelSetVersion: 0, +} as const; + +const COMMON_ENS_RAINBOW = { + version: "1.9.0", + labelSet: { + labelSetId: "subgraph", + highestLabelSetVersion: 0, }, - "Subgraph Mainnet": { - ensApi: { - versionInfo: { - ensApi: "0.35.0", - ensNormalize: "1.11.1", - }, - theGraphFallback: { - canFallback: false, - reason: "no-api-key", - }, - ensIndexerPublicConfig: { - labelSet: { - labelSetId: "subgraph", - labelSetVersion: 0, - }, - versionInfo: { - ponder: "0.11.43", - ensDb: "0.35.0", - ensIndexer: "0.35.0", - ensNormalize: "1.11.1", - }, - indexedChainIds: [1], - namespace: "mainnet", - plugins: ["subgraph"], - ensIndexerSchemaName: "mainnetSchema0.34.0", - isSubgraphCompatible: true, - ensRainbowPublicConfig: { - version: "0.34.0", - labelSet: { - labelSetId: "subgraph", - highestLabelSetVersion: 0, - }, - recordsCount: 100, - }, - }, - }, - ensDb: { - versionInfo: { - postgresql: "18.1", - }, - }, - ensIndexer: { - labelSet: { - labelSetId: "subgraph", - labelSetVersion: 0, - }, - versionInfo: { - ponder: "0.11.43", - ensDb: "0.35.0", - ensIndexer: "0.35.0", - ensNormalize: "1.11.1", - }, - indexedChainIds: [1], - namespace: "mainnet", - plugins: ["subgraph"], - ensIndexerSchemaName: "mainnetSchema0.34.0", - isSubgraphCompatible: true, - ensRainbowPublicConfig: { - version: "0.34.0", - labelSet: { - labelSetId: "subgraph", - highestLabelSetVersion: 0, - }, - recordsCount: 100, - }, - }, - ensRainbow: { - version: "0.34.0", - labelSet: { - labelSetId: "subgraph", - highestLabelSetVersion: 0, - }, - recordsCount: 100, - }, + recordsCount: 100, +} as const; + +const ENS_RAINBOW_PUBLIC_CONFIG = { + version: "1.9.0", + labelSet: { + labelSetId: "subgraph", + highestLabelSetVersion: 0, }, - "Subgraph Sepolia": { - ensApi: { - versionInfo: { - ensApi: "0.35.0", - ensNormalize: "1.11.1", - }, - theGraphFallback: { - canFallback: false, - reason: "no-api-key", - }, - ensIndexerPublicConfig: { - labelSet: { - labelSetId: "subgraph", - labelSetVersion: 0, - }, - versionInfo: { - ponder: "0.11.43", - ensDb: "0.35.0", - ensIndexer: "0.35.0", - ensNormalize: "1.11.1", - }, - indexedChainIds: [11155111], - namespace: "sepolia", - plugins: ["subgraph"], - ensIndexerSchemaName: "sepoliaSchema0.34.0", - isSubgraphCompatible: true, - ensRainbowPublicConfig: { - version: "0.34.0", - labelSet: { - labelSetId: "subgraph", - highestLabelSetVersion: 0, - }, - recordsCount: 100, - }, - }, - }, - ensDb: { - versionInfo: { - postgresql: "18.1", - }, - }, - ensIndexer: { - labelSet: { - labelSetId: "subgraph", - labelSetVersion: 0, - }, - versionInfo: { - ponder: "0.11.43", - ensDb: "0.35.0", - ensIndexer: "0.35.0", - ensNormalize: "1.11.1", - }, - indexedChainIds: [11155111], - namespace: "sepolia", - plugins: ["subgraph"], - ensIndexerSchemaName: "sepoliaSchema0.34.0", - isSubgraphCompatible: true, - ensRainbowPublicConfig: { - version: "0.34.0", - labelSet: { - labelSetId: "subgraph", - highestLabelSetVersion: 0, - }, - recordsCount: 100, - }, - }, - ensRainbow: { - version: "0.34.0", - labelSet: { - labelSetId: "subgraph", - highestLabelSetVersion: 0, - }, - recordsCount: 100, + recordsCount: 100, +} as const; + +const THE_GRAPH_FALLBACK_DISABLED: TheGraphFallback = { + canFallback: false, + reason: "no-api-key", +} as const; + +// ============================================================================ +// Variant-Specific Configurations +// ============================================================================ + +const ALPHA_PLUGINS = [ + "subgraph", + "basenames", + "lineanames", + "threedns", + "protocol-acceleration", + "registrars", + "tokenscope", +] as const satisfies string[]; + +const ALPHA_SEPOLIA_PLUGINS = [ + "subgraph", + "basenames", + "lineanames", + "threedns", + "protocol-acceleration", + "registrars", +] as const satisfies string[]; + +const SUBGRAPH_PLUGINS = ["subgraph"] as const satisfies string[]; + +const ALPHA_MAINNET_CHAINS: SerializedEnsIndexerPublicConfig["indexedChainIds"] = [ + 1, 8453, 59144, 10, 42161, 534352, 567, +]; +const ALPHA_SEPOLIA_CHAINS: SerializedEnsIndexerPublicConfig["indexedChainIds"] = [ + 11155111, 84532, 59141, 11155420, 421614, 534351, +]; +const SUBGRAPH_MAINNET_CHAINS: SerializedEnsIndexerPublicConfig["indexedChainIds"] = [1]; +const SUBGRAPH_SEPOLIA_CHAINS: SerializedEnsIndexerPublicConfig["indexedChainIds"] = [11155111]; + +// ============================================================================ +// Helper Functions for Creating Variants +// ============================================================================ + +function createEnsRainbow() { + return { ...COMMON_ENS_RAINBOW }; +} + +function createEnsIndexer( + namespace: SerializedEnsIndexerPublicConfig["namespace"], + indexedChainIds: SerializedEnsIndexerPublicConfig["indexedChainIds"], + plugins: SerializedEnsIndexerPublicConfig["plugins"], + ensIndexerSchemaName: string, + isSubgraphCompatible: boolean, +): SerializedEnsIndexerPublicConfig { + return { + labelSet: { ...COMMON_LABEL_SET }, + indexedChainIds, + ensIndexerSchemaName, + isSubgraphCompatible, + namespace, + plugins, + versionInfo: { ...COMMON_VERSION_INFO }, + ensRainbowPublicConfig: { ...ENS_RAINBOW_PUBLIC_CONFIG }, + }; +} + +function createEnsApi( + namespace: SerializedEnsIndexerPublicConfig["namespace"], + indexedChainIds: SerializedEnsIndexerPublicConfig["indexedChainIds"], + plugins: SerializedEnsIndexerPublicConfig["plugins"], + ensIndexerSchemaName: string, + isSubgraphCompatible: boolean, + theGraphFallback: TheGraphFallback, +): SerializedEnsApiPublicConfig { + return { + versionInfo: { ...COMMON_ENS_API_VERSION_INFO }, + theGraphFallback, + ensIndexerPublicConfig: { + labelSet: { ...COMMON_LABEL_SET }, + versionInfo: { ...COMMON_VERSION_INFO }, + indexedChainIds, + namespace, + plugins, + ensIndexerSchemaName, + isSubgraphCompatible, + ensRainbowPublicConfig: { ...ENS_RAINBOW_PUBLIC_CONFIG }, }, - }, - "Deserialization Error": { + }; +} + +function createAlphaEnsIndexer( + namespace: "mainnet" | "sepolia", + isMainnet: boolean, +): SerializedEnsIndexerPublicConfig { + return createEnsIndexer( + namespace, + isMainnet ? ALPHA_MAINNET_CHAINS : ALPHA_SEPOLIA_CHAINS, + [...(isMainnet ? ALPHA_PLUGINS : ALPHA_SEPOLIA_PLUGINS)], + isMainnet ? "alphaSchema1.9.0" : "alphaSepoliaSchema1.9.0", + false, + ); +} + +function createAlphaEnsApi( + namespace: "mainnet" | "sepolia", + isMainnet: boolean, + theGraphFallback: TheGraphFallback, +): SerializedEnsApiPublicConfig { + return createEnsApi( + namespace, + isMainnet ? ALPHA_MAINNET_CHAINS : ALPHA_SEPOLIA_CHAINS, + [...(isMainnet ? ALPHA_PLUGINS : ALPHA_SEPOLIA_PLUGINS)], + isMainnet ? "alphaSchema1.9.0" : "alphaSepoliaSchema1.9.0", + false, + theGraphFallback, + ); +} + +function createSubgraphEnsIndexer( + namespace: "mainnet" | "sepolia", + isMainnet: boolean, +): SerializedEnsIndexerPublicConfig { + return createEnsIndexer( + namespace, + isMainnet ? SUBGRAPH_MAINNET_CHAINS : SUBGRAPH_SEPOLIA_CHAINS, + [...SUBGRAPH_PLUGINS], + isMainnet ? "mainnetSchema1.9.0" : "sepoliaSchema1.9.0", + true, + ); +} + +function createSubgraphEnsApi( + namespace: "mainnet" | "sepolia", + isMainnet: boolean, +): SerializedEnsApiPublicConfig { + return createEnsApi( + namespace, + isMainnet ? SUBGRAPH_MAINNET_CHAINS : SUBGRAPH_SEPOLIA_CHAINS, + [...SUBGRAPH_PLUGINS], + isMainnet ? "mainnetSchema1.9.0" : "sepoliaSchema1.9.0", + true, + { ...THE_GRAPH_FALLBACK_DISABLED }, + ); +} + +// ============================================================================ +// Error Variant (Deserialization Error) +// ============================================================================ + +function createDeserializationErrorVariant(): SerializedEnsNodeStackInfo { + return { ensApi: { - versionInfo: { - ensApi: "0.35.0", - ensNormalize: "1.11.1", - }, - theGraphFallback: { - canFallback: false, - reason: "no-api-key", - }, + versionInfo: { ...COMMON_ENS_API_VERSION_INFO }, + theGraphFallback: { ...THE_GRAPH_FALLBACK_DISABLED }, ensIndexerPublicConfig: { labelSet: { labelSetId: "", @@ -359,7 +218,7 @@ export const mockSerializedEnsNodeStackInfo = { indexedChainIds: [11155111], namespace: "sepolia", plugins: ["subgraph"], - ensIndexerSchemaName: "DeserializationSchema0.34.0", + ensIndexerSchemaName: "DeserializationSchema1.9.0", isSubgraphCompatible: true, ensRainbowPublicConfig: { version: "", @@ -371,11 +230,7 @@ export const mockSerializedEnsNodeStackInfo = { }, }, }, - ensDb: { - versionInfo: { - postgresql: "18.1", - }, - }, + ensDb: { ...COMMON_ENS_DB }, ensIndexer: { labelSet: { labelSetId: "", @@ -390,7 +245,7 @@ export const mockSerializedEnsNodeStackInfo = { indexedChainIds: [11155111], namespace: "sepolia", plugins: ["subgraph"], - ensIndexerSchemaName: "DeserializationSchema0.34.0", + ensIndexerSchemaName: "DeserializationSchema1.9.0", isSubgraphCompatible: true, ensRainbowPublicConfig: { version: "", @@ -409,5 +264,41 @@ export const mockSerializedEnsNodeStackInfo = { }, recordsCount: -1, }, + }; +} + +// ============================================================================ +// Record of Mock Variants +// ============================================================================ + +/** + * Record of mock SerializedEnsNodeStackInfo objects keyed by variant name. + * These can be deserialized to simulate the full deserialization process. + */ +export const mockSerializedEnsNodeStackInfo = { + "Alpha Mainnet": { + ensApi: createAlphaEnsApi("mainnet", true, { ...THE_GRAPH_FALLBACK_DISABLED }), + ensDb: { ...COMMON_ENS_DB }, + ensIndexer: createAlphaEnsIndexer("mainnet", true), + ensRainbow: createEnsRainbow(), + }, + "Alpha Sepolia": { + ensApi: createAlphaEnsApi("sepolia", false, { canFallback: true, url: "" }), + ensDb: { ...COMMON_ENS_DB }, + ensIndexer: createAlphaEnsIndexer("sepolia", false), + ensRainbow: createEnsRainbow(), + }, + "Subgraph Mainnet": { + ensApi: createSubgraphEnsApi("mainnet", true), + ensDb: { ...COMMON_ENS_DB }, + ensIndexer: createSubgraphEnsIndexer("mainnet", true), + ensRainbow: createEnsRainbow(), + }, + "Subgraph Sepolia": { + ensApi: createSubgraphEnsApi("sepolia", false), + ensDb: { ...COMMON_ENS_DB }, + ensIndexer: createSubgraphEnsIndexer("sepolia", false), + ensRainbow: createEnsRainbow(), }, + "Deserialization Error": createDeserializationErrorVariant(), } as const satisfies Record; From 2955218d6ccf4bf3546027f0f3b7673f510b2f37 Mon Sep 17 00:00:00 2001 From: Tomasz Kopacki Date: Thu, 23 Apr 2026 18:20:32 +0200 Subject: [PATCH 09/21] Update OpenAPI Spec --- docs/ensnode.io/ensapi-openapi.json | 234 ++++++++++++++-------------- 1 file changed, 117 insertions(+), 117 deletions(-) diff --git a/docs/ensnode.io/ensapi-openapi.json b/docs/ensnode.io/ensapi-openapi.json index 2e27b8e27a..64887e3414 100644 --- a/docs/ensnode.io/ensapi-openapi.json +++ b/docs/ensnode.io/ensapi-openapi.json @@ -2,7 +2,7 @@ "openapi": "3.1.0", "info": { "title": "ENSApi APIs", - "version": "1.10.0", + "version": "1.10.1", "description": "APIs for ENS resolution, navigating the ENS nameforest, and metadata about an ENSNode" }, "servers": [ @@ -782,6 +782,121 @@ "stackInfo": { "type": "object", "properties": { + "ensIndexer": { + "type": "object", + "properties": { + "ensIndexerSchemaName": { "type": "string", "minLength": 1 }, + "ensRainbowPublicConfig": { + "type": "object", + "properties": { + "version": { "type": "string", "minLength": 1 }, + "labelSet": { + "type": "object", + "properties": { + "labelSetId": { + "type": "string", + "minLength": 1, + "maxLength": 50, + "pattern": "^[a-z-]+$" + }, + "highestLabelSetVersion": { "type": "integer", "minimum": 0 } + }, + "required": ["labelSetId", "highestLabelSetVersion"] + }, + "recordsCount": { "type": "integer", "minimum": 0 } + }, + "required": ["version", "labelSet", "recordsCount"] + }, + "indexedChainIds": { + "type": "array", + "items": { "type": "integer", "exclusiveMinimum": 0 }, + "minItems": 1 + }, + "isSubgraphCompatible": { "type": "boolean" }, + "labelSet": { + "type": "object", + "properties": { + "labelSetId": { + "type": "string", + "minLength": 1, + "maxLength": 50, + "pattern": "^[a-z-]+$" + }, + "labelSetVersion": { "type": ["number", "null"] } + }, + "required": ["labelSetId", "labelSetVersion"] + }, + "namespace": { + "type": "string", + "enum": ["mainnet", "sepolia", "sepolia-v2", "ens-test-env"] + }, + "plugins": { + "type": "array", + "items": { "type": "string" }, + "minItems": 1 + }, + "versionInfo": { + "type": "object", + "properties": { + "ponder": { "type": "string", "minLength": 1 }, + "ensDb": { "type": "string", "minLength": 1 }, + "ensIndexer": { "type": "string", "minLength": 1 }, + "ensNormalize": { "type": "string", "minLength": 1 } + }, + "required": ["ponder", "ensDb", "ensIndexer", "ensNormalize"] + } + }, + "required": [ + "ensIndexerSchemaName", + "ensRainbowPublicConfig", + "indexedChainIds", + "isSubgraphCompatible", + "labelSet", + "namespace", + "plugins", + "versionInfo" + ] + }, + "ensRainbow": { + "type": "object", + "properties": { + "version": { "type": "string", "minLength": 1 }, + "labelSet": { + "type": "object", + "properties": { + "labelSetId": { + "type": "string", + "minLength": 1, + "maxLength": 50, + "pattern": "^[a-z-]+$" + }, + "highestLabelSetVersion": { "type": "integer", "minimum": 0 } + }, + "required": ["labelSetId", "highestLabelSetVersion"] + }, + "recordsCount": { "type": "integer", "minimum": 0 } + }, + "required": ["version", "labelSet", "recordsCount"] + }, + "ensDb": { + "type": "object", + "properties": { + "versionInfo": { + "type": "object", + "properties": { + "postgresql": { + "type": "string", + "minLength": 1, + "description": "Version of the PostgreSQL server hosting the ENSDb instance." + } + }, + "required": ["postgresql"], + "description": "Serialized Indexing Status Response OK.ensDb.versionInfo" + } + }, + "required": ["versionInfo"], + "description": "Serialized Indexing Status Response OK.ensDb" + }, "ensApi": { "type": "object", "properties": { @@ -902,124 +1017,9 @@ } }, "required": ["ensIndexerPublicConfig", "theGraphFallback", "versionInfo"] - }, - "ensDb": { - "type": "object", - "properties": { - "versionInfo": { - "type": "object", - "properties": { - "postgresql": { - "type": "string", - "minLength": 1, - "description": "Version of the PostgreSQL server hosting the ENSDb instance." - } - }, - "required": ["postgresql"], - "description": "Serialized Indexing Status Response OK.ensDb.versionInfo" - } - }, - "required": ["versionInfo"], - "description": "Serialized Indexing Status Response OK.ensDb" - }, - "ensIndexer": { - "type": "object", - "properties": { - "ensIndexerSchemaName": { "type": "string", "minLength": 1 }, - "ensRainbowPublicConfig": { - "type": "object", - "properties": { - "version": { "type": "string", "minLength": 1 }, - "labelSet": { - "type": "object", - "properties": { - "labelSetId": { - "type": "string", - "minLength": 1, - "maxLength": 50, - "pattern": "^[a-z-]+$" - }, - "highestLabelSetVersion": { "type": "integer", "minimum": 0 } - }, - "required": ["labelSetId", "highestLabelSetVersion"] - }, - "recordsCount": { "type": "integer", "minimum": 0 } - }, - "required": ["version", "labelSet", "recordsCount"] - }, - "indexedChainIds": { - "type": "array", - "items": { "type": "integer", "exclusiveMinimum": 0 }, - "minItems": 1 - }, - "isSubgraphCompatible": { "type": "boolean" }, - "labelSet": { - "type": "object", - "properties": { - "labelSetId": { - "type": "string", - "minLength": 1, - "maxLength": 50, - "pattern": "^[a-z-]+$" - }, - "labelSetVersion": { "type": ["number", "null"] } - }, - "required": ["labelSetId", "labelSetVersion"] - }, - "namespace": { - "type": "string", - "enum": ["mainnet", "sepolia", "sepolia-v2", "ens-test-env"] - }, - "plugins": { - "type": "array", - "items": { "type": "string" }, - "minItems": 1 - }, - "versionInfo": { - "type": "object", - "properties": { - "ponder": { "type": "string", "minLength": 1 }, - "ensDb": { "type": "string", "minLength": 1 }, - "ensIndexer": { "type": "string", "minLength": 1 }, - "ensNormalize": { "type": "string", "minLength": 1 } - }, - "required": ["ponder", "ensDb", "ensIndexer", "ensNormalize"] - } - }, - "required": [ - "ensIndexerSchemaName", - "ensRainbowPublicConfig", - "indexedChainIds", - "isSubgraphCompatible", - "labelSet", - "namespace", - "plugins", - "versionInfo" - ] - }, - "ensRainbow": { - "type": "object", - "properties": { - "version": { "type": "string", "minLength": 1 }, - "labelSet": { - "type": "object", - "properties": { - "labelSetId": { - "type": "string", - "minLength": 1, - "maxLength": 50, - "pattern": "^[a-z-]+$" - }, - "highestLabelSetVersion": { "type": "integer", "minimum": 0 } - }, - "required": ["labelSetId", "highestLabelSetVersion"] - }, - "recordsCount": { "type": "integer", "minimum": 0 } - }, - "required": ["version", "labelSet", "recordsCount"] } }, - "required": ["ensApi", "ensDb", "ensIndexer"] + "required": ["ensIndexer", "ensRainbow", "ensDb", "ensApi"] } }, "required": ["responseCode", "realtimeProjection", "stackInfo"] From eef4decf169db18858ee583a18c5aaacb8daaad1 Mon Sep 17 00:00:00 2001 From: Tomasz Kopacki Date: Fri, 24 Apr 2026 12:04:58 +0200 Subject: [PATCH 10/21] Merge `EnsDbStackInfo` data model into `EnsIndexerStackInfo` --- .../deserialize/ensdb-stack-info.ts | 46 ------------------- .../deserialize/ensnode-stack-info.ts | 7 ++- .../src/stack-info/ensdb-stack-info.ts | 29 ------------ .../src/stack-info/ensindexer-stack-info.ts | 17 +++++-- .../src/stack-info/ensnode-stack-info.ts | 15 +++--- packages/ensnode-sdk/src/stack-info/index.ts | 5 +- .../stack-info/serialize/ensdb-stack-info.ts | 23 ---------- .../serialize/ensindexer-stack-info.ts | 15 +++++- .../serialize/ensnode-stack-info.ts | 9 ++-- .../validate/ensindexer-stack-info.ts | 21 +++++++++ .../stack-info/validate/ensnode-stack-info.ts | 21 +++++++++ .../zod-schemas/ensdb-stack-info.ts | 24 ---------- .../zod-schemas/ensindexer-stack-info.ts | 3 ++ .../zod-schemas/ensnode-stack-info.ts | 11 +++-- 14 files changed, 97 insertions(+), 149 deletions(-) delete mode 100644 packages/ensnode-sdk/src/stack-info/deserialize/ensdb-stack-info.ts delete mode 100644 packages/ensnode-sdk/src/stack-info/ensdb-stack-info.ts delete mode 100644 packages/ensnode-sdk/src/stack-info/serialize/ensdb-stack-info.ts create mode 100644 packages/ensnode-sdk/src/stack-info/validate/ensindexer-stack-info.ts create mode 100644 packages/ensnode-sdk/src/stack-info/validate/ensnode-stack-info.ts delete mode 100644 packages/ensnode-sdk/src/stack-info/zod-schemas/ensdb-stack-info.ts diff --git a/packages/ensnode-sdk/src/stack-info/deserialize/ensdb-stack-info.ts b/packages/ensnode-sdk/src/stack-info/deserialize/ensdb-stack-info.ts deleted file mode 100644 index 3bfe398d97..0000000000 --- a/packages/ensnode-sdk/src/stack-info/deserialize/ensdb-stack-info.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { prettifyError } from "zod/v4"; - -import type { Unvalidated } from "../../shared/types"; -import type { EnsDbStackInfo } from "../ensdb-stack-info"; -import type { SerializedEnsDbStackInfo } from "../serialize/ensdb-stack-info"; -import { - makeEnsDbStackInfoSchema, - makeSerializedEnsDbStackInfoSchema, -} from "../zod-schemas/ensdb-stack-info"; -import { buildUnvalidatedEnsIndexerStackInfo } from "./ensindexer-stack-info"; - -/** - * Builds an unvalidated {@link EnsDbStackInfo} object to be - * validated with {@link makeEnsDbStackInfoSchema}. - * - * @param serializedStackInfo - The serialized stack info to build from. - * @return An unvalidated {@link EnsDbStackInfo} object. - */ -export function buildUnvalidatedEnsDbStackInfo( - serializedStackInfo: SerializedEnsDbStackInfo, -): Unvalidated { - const { ensDb, ...serializedEnsindexerStackInfo } = serializedStackInfo; - return { - ...buildUnvalidatedEnsIndexerStackInfo(serializedEnsindexerStackInfo), - ensDb, // ENSDb Public Config is already in a serialized form, so we can include it directly - }; -} - -/** - * Deserialize value into {@link EnsDbStackInfo} object. - */ -export function deserializeEnsDbStackInfo( - maybeStackInfo: Unvalidated, - valueLabel?: string, -): EnsDbStackInfo { - const parsed = makeSerializedEnsDbStackInfoSchema(valueLabel) - .transform(buildUnvalidatedEnsDbStackInfo) - .pipe(makeEnsDbStackInfoSchema(valueLabel)) - .safeParse(maybeStackInfo); - - if (parsed.error) { - throw new Error(`Cannot deserialize EnsDbStackInfo:\n${prettifyError(parsed.error)}\n`); - } - - return parsed.data; -} diff --git a/packages/ensnode-sdk/src/stack-info/deserialize/ensnode-stack-info.ts b/packages/ensnode-sdk/src/stack-info/deserialize/ensnode-stack-info.ts index 7e130dfa92..d0c3d541d9 100644 --- a/packages/ensnode-sdk/src/stack-info/deserialize/ensnode-stack-info.ts +++ b/packages/ensnode-sdk/src/stack-info/deserialize/ensnode-stack-info.ts @@ -8,7 +8,7 @@ import { makeEnsNodeStackInfoSchema, makeSerializedEnsNodeStackInfoSchema, } from "../zod-schemas/ensnode-stack-info"; -import { buildUnvalidatedEnsDbStackInfo } from "./ensdb-stack-info"; +import { buildUnvalidatedEnsIndexerStackInfo } from "./ensindexer-stack-info"; /** * Builds an unvalidated {@link EnsNodeStackInfo} object to be @@ -20,10 +20,9 @@ import { buildUnvalidatedEnsDbStackInfo } from "./ensdb-stack-info"; export function buildUnvalidatedEnsNodeStackInfo( serializedStackInfo: SerializedEnsNodeStackInfo, ): Unvalidated { - const { ensApi, ...serializedEnsDbStackInfo } = serializedStackInfo; return { - ...buildUnvalidatedEnsDbStackInfo(serializedEnsDbStackInfo), - ensApi: buildUnvalidatedEnsApiPublicConfig(ensApi), + ...buildUnvalidatedEnsIndexerStackInfo(serializedStackInfo), + ensApi: buildUnvalidatedEnsApiPublicConfig(serializedStackInfo.ensApi), }; } diff --git a/packages/ensnode-sdk/src/stack-info/ensdb-stack-info.ts b/packages/ensnode-sdk/src/stack-info/ensdb-stack-info.ts deleted file mode 100644 index e29ad7a906..0000000000 --- a/packages/ensnode-sdk/src/stack-info/ensdb-stack-info.ts +++ /dev/null @@ -1,29 +0,0 @@ -import type { EnsDbPublicConfig } from "../ensdb/config"; -import type { EnsIndexerPublicConfig } from "../ensindexer/config/types"; -import type { EnsRainbowPublicConfig } from "../ensrainbow/config"; -import { buildEnsIndexerStackInfo, type EnsIndexerStackInfo } from "./ensindexer-stack-info"; - -/** - * Information about the stack of services inside an ENSDb instance. - */ -export interface EnsDbStackInfo extends EnsIndexerStackInfo { - /** - * ENSDb Public Config - */ - ensDb: EnsDbPublicConfig; -} - -/** - * Build a complete {@link EnsDbStackInfo} object from - * the given public configs of ENSDb, ENSIndexer, and ENSRainbow. - */ -export function buildEnsDbStackInfo( - ensDbPublicConfig: EnsDbPublicConfig, - ensIndexerPublicConfig: EnsIndexerPublicConfig, - ensRainbowPublicConfig: EnsRainbowPublicConfig, -): EnsDbStackInfo { - return { - ...buildEnsIndexerStackInfo(ensIndexerPublicConfig, ensRainbowPublicConfig), - ensDb: ensDbPublicConfig, - }; -} diff --git a/packages/ensnode-sdk/src/stack-info/ensindexer-stack-info.ts b/packages/ensnode-sdk/src/stack-info/ensindexer-stack-info.ts index b3d2ac95ce..503977684d 100644 --- a/packages/ensnode-sdk/src/stack-info/ensindexer-stack-info.ts +++ b/packages/ensnode-sdk/src/stack-info/ensindexer-stack-info.ts @@ -1,10 +1,17 @@ -import type { EnsIndexerPublicConfig } from "../ensindexer/config/types"; +import type { EnsDbPublicConfig } from "../ensdb/config"; +import type { EnsIndexerPublicConfig } from "../ensindexer/config"; import type { EnsRainbowPublicConfig } from "../ensrainbow/config"; +import { validateEnsIndexerStackInfo } from "./validate/ensindexer-stack-info"; /** * Information about the stack of services inside an ENSIndexer instance. */ export interface EnsIndexerStackInfo { + /** + * ENSDb Public Config + */ + ensDb: EnsDbPublicConfig; + /** * ENSIndexer Public Config */ @@ -18,14 +25,16 @@ export interface EnsIndexerStackInfo { /** * Build a complete {@link EnsIndexerStackInfo} object from - * the given public configs of ENSIndexer and ENSRainbow. + * the given public configs of ENSDb, ENSIndexer, and ENSRainbow. */ export function buildEnsIndexerStackInfo( + ensDbPublicConfig: EnsDbPublicConfig, ensIndexerPublicConfig: EnsIndexerPublicConfig, ensRainbowPublicConfig: EnsRainbowPublicConfig, ): EnsIndexerStackInfo { - return { + return validateEnsIndexerStackInfo({ + ensDb: ensDbPublicConfig, ensIndexer: ensIndexerPublicConfig, ensRainbow: ensRainbowPublicConfig, - }; + }); } diff --git a/packages/ensnode-sdk/src/stack-info/ensnode-stack-info.ts b/packages/ensnode-sdk/src/stack-info/ensnode-stack-info.ts index 9c8d374353..3d16287c5d 100644 --- a/packages/ensnode-sdk/src/stack-info/ensnode-stack-info.ts +++ b/packages/ensnode-sdk/src/stack-info/ensnode-stack-info.ts @@ -1,13 +1,14 @@ -import type { EnsApiPublicConfig } from "../ensapi/config/types"; +import type { EnsApiPublicConfig } from "../ensapi/config"; import type { EnsDbPublicConfig } from "../ensdb/config"; -import type { EnsIndexerPublicConfig } from "../ensindexer/config/types"; +import type { EnsIndexerPublicConfig } from "../ensindexer/config"; import type { EnsRainbowPublicConfig } from "../ensrainbow"; -import { buildEnsDbStackInfo, type EnsDbStackInfo } from "./ensdb-stack-info"; +import { buildEnsIndexerStackInfo, type EnsIndexerStackInfo } from "./ensindexer-stack-info"; +import { validateEnsNodeStackInfo } from "./validate/ensnode-stack-info"; /** * Information about the stack of services inside an ENSNode instance. */ -export interface EnsNodeStackInfo extends EnsDbStackInfo { +export interface EnsNodeStackInfo extends EnsIndexerStackInfo { /** * ENSApi Public Config */ @@ -24,8 +25,8 @@ export function buildEnsNodeStackInfo( ensIndexerPublicConfig: EnsIndexerPublicConfig, ensRainbowPublicConfig: EnsRainbowPublicConfig, ): EnsNodeStackInfo { - return { - ...buildEnsDbStackInfo(ensDbPublicConfig, ensIndexerPublicConfig, ensRainbowPublicConfig), + return validateEnsNodeStackInfo({ + ...buildEnsIndexerStackInfo(ensDbPublicConfig, ensIndexerPublicConfig, ensRainbowPublicConfig), ensApi: ensApiPublicConfig, - }; + }); } diff --git a/packages/ensnode-sdk/src/stack-info/index.ts b/packages/ensnode-sdk/src/stack-info/index.ts index b439a614a2..f12f414254 100644 --- a/packages/ensnode-sdk/src/stack-info/index.ts +++ b/packages/ensnode-sdk/src/stack-info/index.ts @@ -1,9 +1,8 @@ -export * from "./deserialize/ensdb-stack-info"; export * from "./deserialize/ensindexer-stack-info"; export * from "./deserialize/ensnode-stack-info"; -export * from "./ensdb-stack-info"; export * from "./ensindexer-stack-info"; export * from "./ensnode-stack-info"; -export * from "./serialize/ensdb-stack-info"; export * from "./serialize/ensindexer-stack-info"; export * from "./serialize/ensnode-stack-info"; +export * from "./validate/ensindexer-stack-info"; +export * from "./validate/ensnode-stack-info"; diff --git a/packages/ensnode-sdk/src/stack-info/serialize/ensdb-stack-info.ts b/packages/ensnode-sdk/src/stack-info/serialize/ensdb-stack-info.ts deleted file mode 100644 index 34f2546b53..0000000000 --- a/packages/ensnode-sdk/src/stack-info/serialize/ensdb-stack-info.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { SerializedEnsDbPublicConfig } from "../../ensdb/serialize/config"; -import type { EnsDbStackInfo } from "../ensdb-stack-info"; -import { - type SerializedEnsIndexerStackInfo, - serializeEnsIndexerStackInfo, -} from "./ensindexer-stack-info"; - -/** - * Serialized representation of {@link EnsDbStackInfo}. - */ -export interface SerializedEnsDbStackInfo extends SerializedEnsIndexerStackInfo { - ensDb: SerializedEnsDbPublicConfig; -} - -/** - * Serialize a {@link EnsDbStackInfo} object. - */ -export function serializeEnsDbStackInfo(stackInfo: EnsDbStackInfo): SerializedEnsDbStackInfo { - return { - ...serializeEnsIndexerStackInfo(stackInfo), - ensDb: stackInfo.ensDb, // ENSDb Public Config is already in a serialized form, so we can include it directly - }; -} diff --git a/packages/ensnode-sdk/src/stack-info/serialize/ensindexer-stack-info.ts b/packages/ensnode-sdk/src/stack-info/serialize/ensindexer-stack-info.ts index 8dbca65805..47e39ac2da 100644 --- a/packages/ensnode-sdk/src/stack-info/serialize/ensindexer-stack-info.ts +++ b/packages/ensnode-sdk/src/stack-info/serialize/ensindexer-stack-info.ts @@ -1,3 +1,4 @@ +import type { SerializedEnsDbPublicConfig } from "../../ensdb/serialize/config"; import { serializeEnsIndexerPublicConfig } from "../../ensindexer/config/serialize"; import type { SerializedEnsIndexerPublicConfig } from "../../ensindexer/config/serialized-types"; import type { SerializedEnsRainbowPublicConfig } from "../../ensrainbow/serialize/config"; @@ -7,6 +8,7 @@ import type { EnsIndexerStackInfo } from "../ensindexer-stack-info"; * Serialized representation of {@link EnsIndexerStackInfo}. */ export interface SerializedEnsIndexerStackInfo { + ensDb: SerializedEnsDbPublicConfig; ensIndexer: SerializedEnsIndexerPublicConfig; ensRainbow: SerializedEnsRainbowPublicConfig; } @@ -17,8 +19,17 @@ export interface SerializedEnsIndexerStackInfo { export function serializeEnsIndexerStackInfo( stackInfo: EnsIndexerStackInfo, ): SerializedEnsIndexerStackInfo { + // `ensDb` and `ensRainbow` are already in a serialized form, so we can include them directly + const { + ensDb: serializedEnsDbPublicConfig, + ensRainbow: serializedEnsRainbowPublicConfig, + ensIndexer, + } = stackInfo; + const serializedEnsIndexerPublicConfig = serializeEnsIndexerPublicConfig(ensIndexer); + return { - ensIndexer: serializeEnsIndexerPublicConfig(stackInfo.ensIndexer), - ensRainbow: stackInfo.ensRainbow, + ensDb: serializedEnsDbPublicConfig, + ensIndexer: serializedEnsIndexerPublicConfig, + ensRainbow: serializedEnsRainbowPublicConfig, }; } diff --git a/packages/ensnode-sdk/src/stack-info/serialize/ensnode-stack-info.ts b/packages/ensnode-sdk/src/stack-info/serialize/ensnode-stack-info.ts index 559ed87295..3852fef5de 100644 --- a/packages/ensnode-sdk/src/stack-info/serialize/ensnode-stack-info.ts +++ b/packages/ensnode-sdk/src/stack-info/serialize/ensnode-stack-info.ts @@ -1,12 +1,15 @@ import { serializeEnsApiPublicConfig } from "../../ensapi/config/serialize"; import type { SerializedEnsApiPublicConfig } from "../../ensapi/config/serialized-types"; import type { EnsNodeStackInfo } from "../ensnode-stack-info"; -import { type SerializedEnsDbStackInfo, serializeEnsDbStackInfo } from "./ensdb-stack-info"; +import { + type SerializedEnsIndexerStackInfo, + serializeEnsIndexerStackInfo, +} from "./ensindexer-stack-info"; /** * Serialized representation of {@link EnsNodeStackInfo}. */ -export interface SerializedEnsNodeStackInfo extends SerializedEnsDbStackInfo { +export interface SerializedEnsNodeStackInfo extends SerializedEnsIndexerStackInfo { ensApi: SerializedEnsApiPublicConfig; } @@ -15,7 +18,7 @@ export interface SerializedEnsNodeStackInfo extends SerializedEnsDbStackInfo { */ export function serializeEnsNodeStackInfo(stackInfo: EnsNodeStackInfo): SerializedEnsNodeStackInfo { return { - ...serializeEnsDbStackInfo(stackInfo), + ...serializeEnsIndexerStackInfo(stackInfo), ensApi: serializeEnsApiPublicConfig(stackInfo.ensApi), }; } diff --git a/packages/ensnode-sdk/src/stack-info/validate/ensindexer-stack-info.ts b/packages/ensnode-sdk/src/stack-info/validate/ensindexer-stack-info.ts new file mode 100644 index 0000000000..46396745ac --- /dev/null +++ b/packages/ensnode-sdk/src/stack-info/validate/ensindexer-stack-info.ts @@ -0,0 +1,21 @@ +import { prettifyError } from "zod/v4"; + +import type { Unvalidated } from "../../shared/types"; +import type { EnsIndexerStackInfo } from "../ensindexer-stack-info"; +import { makeEnsIndexerStackInfoSchema } from "../zod-schemas/ensindexer-stack-info"; + +/** + * Validate a maybe {@link EnsIndexerStackInfo} object. + */ +export function validateEnsIndexerStackInfo( + maybeStackInfo: Unvalidated, + valueLabel?: string, +): EnsIndexerStackInfo { + const parsed = makeEnsIndexerStackInfoSchema(valueLabel).safeParse(maybeStackInfo); + + if (parsed.error) { + throw new Error(`Cannot validate EnsIndexerStackInfo:\n${prettifyError(parsed.error)}\n`); + } + + return parsed.data; +} diff --git a/packages/ensnode-sdk/src/stack-info/validate/ensnode-stack-info.ts b/packages/ensnode-sdk/src/stack-info/validate/ensnode-stack-info.ts new file mode 100644 index 0000000000..1c24211267 --- /dev/null +++ b/packages/ensnode-sdk/src/stack-info/validate/ensnode-stack-info.ts @@ -0,0 +1,21 @@ +import { prettifyError } from "zod/v4"; + +import type { Unvalidated } from "../../shared/types"; +import type { EnsNodeStackInfo } from "../ensnode-stack-info"; +import { makeEnsNodeStackInfoSchema } from "../zod-schemas/ensnode-stack-info"; + +/** + * Validate a maybe {@link EnsNodeStackInfo} object. + */ +export function validateEnsNodeStackInfo( + maybeStackInfo: Unvalidated, + valueLabel?: string, +): EnsNodeStackInfo { + const parsed = makeEnsNodeStackInfoSchema(valueLabel).safeParse(maybeStackInfo); + + if (parsed.error) { + throw new Error(`Cannot validate EnsNodeStackInfo:\n${prettifyError(parsed.error)}\n`); + } + + return parsed.data; +} diff --git a/packages/ensnode-sdk/src/stack-info/zod-schemas/ensdb-stack-info.ts b/packages/ensnode-sdk/src/stack-info/zod-schemas/ensdb-stack-info.ts deleted file mode 100644 index 7cc8edbc89..0000000000 --- a/packages/ensnode-sdk/src/stack-info/zod-schemas/ensdb-stack-info.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { makeEnsDbPublicConfigSchema } from "../../ensdb/zod-schemas/config"; -import { - invariant_ensRainbowCompatibilityWithEnsIndexer, - makeEnsIndexerStackInfoSchema, - makeSerializedEnsIndexerStackInfoSchema, -} from "./ensindexer-stack-info"; - -export function makeSerializedEnsDbStackInfoSchema(valueLabel?: string) { - const label = valueLabel ?? "EnsDbStackInfo"; - - return makeSerializedEnsIndexerStackInfoSchema(label).extend({ - ensDb: makeEnsDbPublicConfigSchema(`${label}.ensDb`), - }); -} - -export function makeEnsDbStackInfoSchema(valueLabel?: string) { - const label = valueLabel ?? "EnsDbStackInfo"; - - return makeEnsIndexerStackInfoSchema(label) - .extend({ - ensDb: makeEnsDbPublicConfigSchema(`${label}.ensDb`), - }) - .check(invariant_ensRainbowCompatibilityWithEnsIndexer); -} diff --git a/packages/ensnode-sdk/src/stack-info/zod-schemas/ensindexer-stack-info.ts b/packages/ensnode-sdk/src/stack-info/zod-schemas/ensindexer-stack-info.ts index fda9973029..3e1b382cc0 100644 --- a/packages/ensnode-sdk/src/stack-info/zod-schemas/ensindexer-stack-info.ts +++ b/packages/ensnode-sdk/src/stack-info/zod-schemas/ensindexer-stack-info.ts @@ -1,5 +1,6 @@ import { z } from "zod/v4"; +import { makeEnsDbPublicConfigSchema } from "../../ensdb/zod-schemas/config"; import { makeEnsIndexerPublicConfigSchema, makeSerializedEnsIndexerPublicConfigSchema, @@ -12,6 +13,7 @@ export function makeSerializedEnsIndexerStackInfoSchema(valueLabel?: string) { const label = valueLabel ?? "ENSIndexerStackInfo"; return z.object({ + ensDb: makeEnsDbPublicConfigSchema(`${label}.ensDb`), ensIndexer: makeSerializedEnsIndexerPublicConfigSchema(`${label}.ensIndexer`), ensRainbow: makeEnsRainbowPublicConfigSchema(`${label}.ensRainbow`), }); @@ -44,6 +46,7 @@ export function makeEnsIndexerStackInfoSchema(valueLabel?: string) { return z .object({ + ensDb: makeEnsDbPublicConfigSchema(`${label}.ensDb`), ensIndexer: makeEnsIndexerPublicConfigSchema(`${label}.ensIndexer`), ensRainbow: makeEnsRainbowPublicConfigSchema(`${label}.ensRainbow`), }) diff --git a/packages/ensnode-sdk/src/stack-info/zod-schemas/ensnode-stack-info.ts b/packages/ensnode-sdk/src/stack-info/zod-schemas/ensnode-stack-info.ts index ebf513016b..adc9a64a26 100644 --- a/packages/ensnode-sdk/src/stack-info/zod-schemas/ensnode-stack-info.ts +++ b/packages/ensnode-sdk/src/stack-info/zod-schemas/ensnode-stack-info.ts @@ -4,8 +4,11 @@ import { } from "../../ensapi/config/zod-schemas"; import type { ZodCheckFnInput } from "../../shared/zod-types"; import type { EnsNodeStackInfo } from "../ensnode-stack-info"; -import { makeEnsDbStackInfoSchema, makeSerializedEnsDbStackInfoSchema } from "./ensdb-stack-info"; -import { invariant_ensRainbowCompatibilityWithEnsIndexer } from "./ensindexer-stack-info"; +import { + invariant_ensRainbowCompatibilityWithEnsIndexer, + makeEnsIndexerStackInfoSchema, + makeSerializedEnsIndexerStackInfoSchema, +} from "./ensindexer-stack-info"; function invariant_ensApiCompatibilityWithEnsIndexerAndEnsRainbow( ctx: ZodCheckFnInput, @@ -56,7 +59,7 @@ function invariant_ensApiCompatibilityWithEnsIndexerAndEnsRainbow( export function makeSerializedEnsNodeStackInfoSchema(valueLabel?: string) { const label = valueLabel ?? "ENSNodeStackInfo"; - return makeSerializedEnsDbStackInfoSchema(label).extend({ + return makeSerializedEnsIndexerStackInfoSchema(label).extend({ ensApi: makeSerializedEnsApiPublicConfigSchema(`${label}.ensApi`), }); } @@ -64,7 +67,7 @@ export function makeSerializedEnsNodeStackInfoSchema(valueLabel?: string) { export function makeEnsNodeStackInfoSchema(valueLabel?: string) { const label = valueLabel ?? "ENSNodeStackInfo"; - return makeEnsDbStackInfoSchema(label) + return makeEnsIndexerStackInfoSchema(label) .extend({ ensApi: makeEnsApiPublicConfigSchema(`${label}.ensApi`), }) From 8b67fc488432c965271ddf81b96d4a1e7ebcdcaa Mon Sep 17 00:00:00 2001 From: Tomasz Kopacki Date: Fri, 24 Apr 2026 12:05:22 +0200 Subject: [PATCH 11/21] Apply PR feedback Apply more precise language --- .../app/mock/stack-info/stack-info.mock.ts | 107 ++++++++---------- .../src/stack-info/ensindexer-stack-info.ts | 2 +- .../zod-schemas/ensindexer-stack-info.ts | 4 +- 3 files changed, 53 insertions(+), 60 deletions(-) diff --git a/apps/ensadmin/src/app/mock/stack-info/stack-info.mock.ts b/apps/ensadmin/src/app/mock/stack-info/stack-info.mock.ts index 3a1e7b8359..833ca9ccde 100644 --- a/apps/ensadmin/src/app/mock/stack-info/stack-info.mock.ts +++ b/apps/ensadmin/src/app/mock/stack-info/stack-info.mock.ts @@ -9,39 +9,30 @@ import type { // Shared Constants // ============================================================================ -const COMMON_ENS_DB = { +const COMMON_ENSDB_CONFIG = { versionInfo: { postgresql: "18.1", }, } as const; -const COMMON_VERSION_INFO = { +const COMMON_ENSINDEXER_VERSION_INFO = { ponder: "0.11.43", ensDb: "1.9.0", ensIndexer: "1.9.0", ensNormalize: "1.11.1", } as const; -const COMMON_ENS_API_VERSION_INFO = { +const COMMON_ENSAPI_VERSION_INFO = { ensApi: "1.9.0", ensNormalize: "1.11.1", } as const; -const COMMON_LABEL_SET = { +const COMMON_CLIENT_LABEL_SET = { labelSetId: "subgraph", labelSetVersion: 0, } as const; -const COMMON_ENS_RAINBOW = { - version: "1.9.0", - labelSet: { - labelSetId: "subgraph", - highestLabelSetVersion: 0, - }, - recordsCount: 100, -} as const; - -const ENS_RAINBOW_PUBLIC_CONFIG = { +const COMMON_ENSRAINBOW_CONFIG = { version: "1.9.0", labelSet: { labelSetId: "subgraph", @@ -93,11 +84,15 @@ const SUBGRAPH_SEPOLIA_CHAINS: SerializedEnsIndexerPublicConfig["indexedChainIds // Helper Functions for Creating Variants // ============================================================================ -function createEnsRainbow() { - return { ...COMMON_ENS_RAINBOW }; +function createEnsDbConfig() { + return { ...COMMON_ENSDB_CONFIG }; } -function createEnsIndexer( +function createEnsRainbowConfig() { + return { ...COMMON_ENSRAINBOW_CONFIG }; +} + +function createEnsIndexerConfig( namespace: SerializedEnsIndexerPublicConfig["namespace"], indexedChainIds: SerializedEnsIndexerPublicConfig["indexedChainIds"], plugins: SerializedEnsIndexerPublicConfig["plugins"], @@ -105,18 +100,18 @@ function createEnsIndexer( isSubgraphCompatible: boolean, ): SerializedEnsIndexerPublicConfig { return { - labelSet: { ...COMMON_LABEL_SET }, + labelSet: { ...COMMON_CLIENT_LABEL_SET }, indexedChainIds, ensIndexerSchemaName, isSubgraphCompatible, namespace, plugins, - versionInfo: { ...COMMON_VERSION_INFO }, - ensRainbowPublicConfig: { ...ENS_RAINBOW_PUBLIC_CONFIG }, + versionInfo: { ...COMMON_ENSINDEXER_VERSION_INFO }, + ensRainbowPublicConfig: createEnsRainbowConfig(), }; } -function createEnsApi( +function createEnsApiConfig( namespace: SerializedEnsIndexerPublicConfig["namespace"], indexedChainIds: SerializedEnsIndexerPublicConfig["indexedChainIds"], plugins: SerializedEnsIndexerPublicConfig["plugins"], @@ -125,26 +120,24 @@ function createEnsApi( theGraphFallback: TheGraphFallback, ): SerializedEnsApiPublicConfig { return { - versionInfo: { ...COMMON_ENS_API_VERSION_INFO }, + versionInfo: { ...COMMON_ENSAPI_VERSION_INFO }, theGraphFallback, ensIndexerPublicConfig: { - labelSet: { ...COMMON_LABEL_SET }, - versionInfo: { ...COMMON_VERSION_INFO }, - indexedChainIds, - namespace, - plugins, - ensIndexerSchemaName, - isSubgraphCompatible, - ensRainbowPublicConfig: { ...ENS_RAINBOW_PUBLIC_CONFIG }, + ...createEnsIndexerConfig( + namespace, + indexedChainIds, + plugins, + ensIndexerSchemaName, + isSubgraphCompatible, + ), }, }; } - -function createAlphaEnsIndexer( +function createAlphaEnsIndexerConfig( namespace: "mainnet" | "sepolia", isMainnet: boolean, ): SerializedEnsIndexerPublicConfig { - return createEnsIndexer( + return createEnsIndexerConfig( namespace, isMainnet ? ALPHA_MAINNET_CHAINS : ALPHA_SEPOLIA_CHAINS, [...(isMainnet ? ALPHA_PLUGINS : ALPHA_SEPOLIA_PLUGINS)], @@ -153,12 +146,12 @@ function createAlphaEnsIndexer( ); } -function createAlphaEnsApi( +function createAlphaEnsApiConfig( namespace: "mainnet" | "sepolia", isMainnet: boolean, theGraphFallback: TheGraphFallback, ): SerializedEnsApiPublicConfig { - return createEnsApi( + return createEnsApiConfig( namespace, isMainnet ? ALPHA_MAINNET_CHAINS : ALPHA_SEPOLIA_CHAINS, [...(isMainnet ? ALPHA_PLUGINS : ALPHA_SEPOLIA_PLUGINS)], @@ -168,11 +161,11 @@ function createAlphaEnsApi( ); } -function createSubgraphEnsIndexer( +function createSubgraphEnsIndexerConfig( namespace: "mainnet" | "sepolia", isMainnet: boolean, ): SerializedEnsIndexerPublicConfig { - return createEnsIndexer( + return createEnsIndexerConfig( namespace, isMainnet ? SUBGRAPH_MAINNET_CHAINS : SUBGRAPH_SEPOLIA_CHAINS, [...SUBGRAPH_PLUGINS], @@ -181,11 +174,11 @@ function createSubgraphEnsIndexer( ); } -function createSubgraphEnsApi( +function createSubgraphEnsApiConfig( namespace: "mainnet" | "sepolia", isMainnet: boolean, ): SerializedEnsApiPublicConfig { - return createEnsApi( + return createEnsApiConfig( namespace, isMainnet ? SUBGRAPH_MAINNET_CHAINS : SUBGRAPH_SEPOLIA_CHAINS, [...SUBGRAPH_PLUGINS], @@ -202,7 +195,7 @@ function createSubgraphEnsApi( function createDeserializationErrorVariant(): SerializedEnsNodeStackInfo { return { ensApi: { - versionInfo: { ...COMMON_ENS_API_VERSION_INFO }, + versionInfo: { ...COMMON_ENSAPI_VERSION_INFO }, theGraphFallback: { ...THE_GRAPH_FALLBACK_DISABLED }, ensIndexerPublicConfig: { labelSet: { @@ -230,7 +223,7 @@ function createDeserializationErrorVariant(): SerializedEnsNodeStackInfo { }, }, }, - ensDb: { ...COMMON_ENS_DB }, + ensDb: createEnsDbConfig(), ensIndexer: { labelSet: { labelSetId: "", @@ -277,28 +270,28 @@ function createDeserializationErrorVariant(): SerializedEnsNodeStackInfo { */ export const mockSerializedEnsNodeStackInfo = { "Alpha Mainnet": { - ensApi: createAlphaEnsApi("mainnet", true, { ...THE_GRAPH_FALLBACK_DISABLED }), - ensDb: { ...COMMON_ENS_DB }, - ensIndexer: createAlphaEnsIndexer("mainnet", true), - ensRainbow: createEnsRainbow(), + ensApi: createAlphaEnsApiConfig("mainnet", true, { ...THE_GRAPH_FALLBACK_DISABLED }), + ensDb: createEnsDbConfig(), + ensIndexer: createAlphaEnsIndexerConfig("mainnet", true), + ensRainbow: createEnsRainbowConfig(), }, "Alpha Sepolia": { - ensApi: createAlphaEnsApi("sepolia", false, { canFallback: true, url: "" }), - ensDb: { ...COMMON_ENS_DB }, - ensIndexer: createAlphaEnsIndexer("sepolia", false), - ensRainbow: createEnsRainbow(), + ensApi: createAlphaEnsApiConfig("sepolia", false, { canFallback: true, url: "" }), + ensDb: createEnsDbConfig(), + ensIndexer: createAlphaEnsIndexerConfig("sepolia", false), + ensRainbow: createEnsRainbowConfig(), }, "Subgraph Mainnet": { - ensApi: createSubgraphEnsApi("mainnet", true), - ensDb: { ...COMMON_ENS_DB }, - ensIndexer: createSubgraphEnsIndexer("mainnet", true), - ensRainbow: createEnsRainbow(), + ensApi: createSubgraphEnsApiConfig("mainnet", true), + ensDb: createEnsDbConfig(), + ensIndexer: createSubgraphEnsIndexerConfig("mainnet", true), + ensRainbow: createEnsRainbowConfig(), }, "Subgraph Sepolia": { - ensApi: createSubgraphEnsApi("sepolia", false), - ensDb: { ...COMMON_ENS_DB }, - ensIndexer: createSubgraphEnsIndexer("sepolia", false), - ensRainbow: createEnsRainbow(), + ensApi: createSubgraphEnsApiConfig("sepolia", false), + ensDb: createEnsDbConfig(), + ensIndexer: createSubgraphEnsIndexerConfig("sepolia", false), + ensRainbow: createEnsRainbowConfig(), }, "Deserialization Error": createDeserializationErrorVariant(), } as const satisfies Record; diff --git a/packages/ensnode-sdk/src/stack-info/ensindexer-stack-info.ts b/packages/ensnode-sdk/src/stack-info/ensindexer-stack-info.ts index 503977684d..482dfad3eb 100644 --- a/packages/ensnode-sdk/src/stack-info/ensindexer-stack-info.ts +++ b/packages/ensnode-sdk/src/stack-info/ensindexer-stack-info.ts @@ -4,7 +4,7 @@ import type { EnsRainbowPublicConfig } from "../ensrainbow/config"; import { validateEnsIndexerStackInfo } from "./validate/ensindexer-stack-info"; /** - * Information about the stack of services inside an ENSIndexer instance. + * Information about the stack of services associated with an ENSIndexer instance. */ export interface EnsIndexerStackInfo { /** diff --git a/packages/ensnode-sdk/src/stack-info/zod-schemas/ensindexer-stack-info.ts b/packages/ensnode-sdk/src/stack-info/zod-schemas/ensindexer-stack-info.ts index 3e1b382cc0..bbbfed17da 100644 --- a/packages/ensnode-sdk/src/stack-info/zod-schemas/ensindexer-stack-info.ts +++ b/packages/ensnode-sdk/src/stack-info/zod-schemas/ensindexer-stack-info.ts @@ -28,7 +28,7 @@ export function invariant_ensRainbowCompatibilityWithEnsIndexer( ctx.issues.push({ code: "custom", input: ctx.value, - message: `ENSRainbow's label set (id: ${ensRainbow.labelSet.labelSetId}) must be same as the ENSIndexer's label set (id: ${ensIndexer.labelSet.labelSetId}).`, + message: `ENSRainbow's label set (id: ${ensRainbow.labelSet.labelSetId}) must be the same as the ENSIndexer's label set (id: ${ensIndexer.labelSet.labelSetId}).`, }); } @@ -36,7 +36,7 @@ export function invariant_ensRainbowCompatibilityWithEnsIndexer( ctx.issues.push({ code: "custom", input: ctx.value, - message: `ENSRainbow's label set version (highest: ${ensRainbow.labelSet.highestLabelSetVersion}) must be greater than or equal to ENSIndexer's label set version (current: ${ensIndexer.labelSet.labelSetVersion}).`, + message: `ENSRainbow's server label set version (highest: ${ensRainbow.labelSet.highestLabelSetVersion}) must be greater than or equal to ENSIndexer's client label set version (current: ${ensIndexer.labelSet.labelSetVersion}).`, }); } } From 64359186b82bbcfcef387e338643574d1481a0ca Mon Sep 17 00:00:00 2001 From: Tomasz Kopacki Date: Fri, 24 Apr 2026 12:33:07 +0200 Subject: [PATCH 12/21] Rename `labelSet` field to `clientLabelSet` for `EnsIndexerConfig` and `EnsIndexerPublicConfig` data models --- .../src/app/mock/indexing-status-api.mock.ts | 12 +++---- .../app/mock/stack-info/stack-info.mock.ts | 6 ++-- .../connection/cards/ensnode-stack-info.tsx | 4 +-- .../components/require-ensadmin-feature.tsx | 2 +- apps/ensapi/src/config/config.schema.test.ts | 16 ++------- apps/ensindexer/src/config/config.schema.ts | 4 +-- apps/ensindexer/src/config/config.test.ts | 20 +++++------ .../src/config/environment-defaults.test.ts | 6 ++-- apps/ensindexer/src/config/serialize.ts | 2 +- .../ensindexer/src/config/serialized-types.ts | 2 +- apps/ensindexer/src/config/types.ts | 2 +- .../ensdb-writer-worker.mock.ts | 2 +- .../src/lib/ensrainbow/singleton.ts | 4 +-- .../public-config-builder.test.ts | 8 ++--- .../public-config-builder.ts | 2 +- .../indexing-behavior-injection-contract.ts | 6 ++-- .../concepts/typescript-interfaces.mdx | 10 +++--- .../docs/ensrainbow/usage/client-sdk.mdx | 2 +- .../ensdb-sdk/src/client/ensdb-client.mock.ts | 2 +- .../src/ensapi/config/conversions.test.ts | 4 +-- .../ensnode-sdk/src/ensindexer/client.mock.ts | 2 +- .../ensindexer/config/compatibility.test.ts | 18 +++++----- .../src/ensindexer/config/compatibility.ts | 16 ++++----- .../src/ensindexer/config/conversions.test.ts | 4 +-- .../config/is-subgraph-compatible.test.ts | 14 ++++---- .../config/is-subgraph-compatible.ts | 7 ++-- .../src/ensindexer/config/serialize.ts | 4 +-- .../src/ensindexer/config/types.ts | 2 +- .../src/ensindexer/config/zod-schemas.test.ts | 16 ++++----- .../src/ensindexer/config/zod-schemas.ts | 15 ++++---- .../ensnode-sdk/src/ensnode/client.test.ts | 4 +-- .../deserialize/ensindexer-stack-info.ts | 9 +++-- .../zod-schemas/ensindexer-stack-info.ts | 8 ++--- packages/ensrainbow-sdk/src/client.test.ts | 12 +++---- packages/ensrainbow-sdk/src/client.ts | 35 ++++++++++--------- 35 files changed, 141 insertions(+), 141 deletions(-) diff --git a/apps/ensadmin/src/app/mock/indexing-status-api.mock.ts b/apps/ensadmin/src/app/mock/indexing-status-api.mock.ts index b23533fbc5..d5e0fd596a 100644 --- a/apps/ensadmin/src/app/mock/indexing-status-api.mock.ts +++ b/apps/ensadmin/src/app/mock/indexing-status-api.mock.ts @@ -24,14 +24,14 @@ import { } from "@ensnode/ensnode-sdk"; const serializedEnsIndexerPublicConfig = { - labelSet: { + clientLabelSet: { labelSetId: "subgraph", labelSetVersion: 0, }, indexedChainIds: [1, 8453, 59144, 10, 42161, 534352, 567], - ensIndexerSchemaName: "alphaSchema0.34.0", + ensIndexerSchemaName: "alphaSchema1.9.0", ensRainbowPublicConfig: { - version: "0.34.0", + version: "1.9.0", labelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0, @@ -51,8 +51,8 @@ const serializedEnsIndexerPublicConfig = { ], versionInfo: { ponder: "0.11.43", - ensIndexer: "0.35.0", - ensDb: "0.35.0", + ensIndexer: "1.9.0", + ensDb: "1.9.0", ensNormalize: "1.11.1", }, } satisfies SerializedEnsIndexerPublicConfig; @@ -64,7 +64,7 @@ export const serializedEnsApiPublicConfig = { url: "https://api.thegraph.com/subgraphs/name/ensdomains/ens", }, versionInfo: { - ensApi: "0.35.0", + ensApi: "1.9.0", ensNormalize: "1.11.1", }, } satisfies SerializedEnsApiPublicConfig; diff --git a/apps/ensadmin/src/app/mock/stack-info/stack-info.mock.ts b/apps/ensadmin/src/app/mock/stack-info/stack-info.mock.ts index 833ca9ccde..3c10b69cd2 100644 --- a/apps/ensadmin/src/app/mock/stack-info/stack-info.mock.ts +++ b/apps/ensadmin/src/app/mock/stack-info/stack-info.mock.ts @@ -100,7 +100,7 @@ function createEnsIndexerConfig( isSubgraphCompatible: boolean, ): SerializedEnsIndexerPublicConfig { return { - labelSet: { ...COMMON_CLIENT_LABEL_SET }, + clientLabelSet: { ...COMMON_CLIENT_LABEL_SET }, indexedChainIds, ensIndexerSchemaName, isSubgraphCompatible, @@ -198,7 +198,7 @@ function createDeserializationErrorVariant(): SerializedEnsNodeStackInfo { versionInfo: { ...COMMON_ENSAPI_VERSION_INFO }, theGraphFallback: { ...THE_GRAPH_FALLBACK_DISABLED }, ensIndexerPublicConfig: { - labelSet: { + clientLabelSet: { labelSetId: "", labelSetVersion: 0, }, @@ -225,7 +225,7 @@ function createDeserializationErrorVariant(): SerializedEnsNodeStackInfo { }, ensDb: createEnsDbConfig(), ensIndexer: { - labelSet: { + clientLabelSet: { labelSetId: "", labelSetVersion: 0, }, diff --git a/apps/ensadmin/src/components/connection/cards/ensnode-stack-info.tsx b/apps/ensadmin/src/components/connection/cards/ensnode-stack-info.tsx index 80776d4c79..a4543fec07 100644 --- a/apps/ensadmin/src/components/connection/cards/ensnode-stack-info.tsx +++ b/apps/ensadmin/src/components/connection/cards/ensnode-stack-info.tsx @@ -570,8 +570,8 @@ function EnsNodeStackInfoCardContent({ ensNodeStackInfo }: { ensNodeStackInfo: E value={
  • - {ensIndexerPublicConfig.labelSet.labelSetId}: - {ensIndexerPublicConfig.labelSet.labelSetVersion} + {ensIndexerPublicConfig.clientLabelSet.labelSetId}: + {ensIndexerPublicConfig.clientLabelSet.labelSetVersion}
} diff --git a/apps/ensadmin/src/components/require-ensadmin-feature.tsx b/apps/ensadmin/src/components/require-ensadmin-feature.tsx index 30929794b8..f638805c77 100644 --- a/apps/ensadmin/src/components/require-ensadmin-feature.tsx +++ b/apps/ensadmin/src/components/require-ensadmin-feature.tsx @@ -82,7 +82,7 @@ export function RequireENSAdminFeatureView({ ) : ( )} diff --git a/apps/ensapi/src/config/config.schema.test.ts b/apps/ensapi/src/config/config.schema.test.ts index f5b10fb14d..9ac9c6d4bf 100644 --- a/apps/ensapi/src/config/config.schema.test.ts +++ b/apps/ensapi/src/config/config.schema.test.ts @@ -48,7 +48,7 @@ const ENSINDEXER_PUBLIC_CONFIG = { }, indexedChainIds: new Set([1]), isSubgraphCompatible: false, - labelSet: { labelSetId: "subgraph", labelSetVersion: 0 }, + clientLabelSet: { labelSetId: "subgraph", labelSetVersion: 0 }, plugins: [PluginName.Subgraph], versionInfo: { ensDb: packageJson.version, @@ -196,19 +196,7 @@ describe("buildEnsApiPublicConfig", () => { const result = buildEnsApiPublicConfig(mockConfig); // Verify that all ENSIndexer public config fields are preserved - expect(result.ensIndexerPublicConfig.namespace).toBe(ENSINDEXER_PUBLIC_CONFIG.namespace); - expect(result.ensIndexerPublicConfig.plugins).toEqual(ENSINDEXER_PUBLIC_CONFIG.plugins); - expect(result.ensIndexerPublicConfig.versionInfo).toEqual(ENSINDEXER_PUBLIC_CONFIG.versionInfo); - expect(result.ensIndexerPublicConfig.indexedChainIds).toEqual( - ENSINDEXER_PUBLIC_CONFIG.indexedChainIds, - ); - expect(result.ensIndexerPublicConfig.isSubgraphCompatible).toBe( - ENSINDEXER_PUBLIC_CONFIG.isSubgraphCompatible, - ); - expect(result.ensIndexerPublicConfig.labelSet).toEqual(ENSINDEXER_PUBLIC_CONFIG.labelSet); - expect(result.ensIndexerPublicConfig.ensIndexerSchemaName).toBe( - ENSINDEXER_PUBLIC_CONFIG.ensIndexerSchemaName, - ); + expect(result.ensIndexerPublicConfig).toStrictEqual(ENSINDEXER_PUBLIC_CONFIG); }); it("includes the theGraphFallback and redacts api key", () => { diff --git a/apps/ensindexer/src/config/config.schema.ts b/apps/ensindexer/src/config/config.schema.ts index 5e4239cde9..a419ad1b34 100644 --- a/apps/ensindexer/src/config/config.schema.ts +++ b/apps/ensindexer/src/config/config.schema.ts @@ -94,7 +94,7 @@ const ENSIndexerConfigSchema = z isSubgraphCompatible: IsSubgraphCompatibleSchema, globalBlockrange: BlockrangeSchema, ensRainbowUrl: EnsRainbowUrlSchema, - labelSet: LabelSetSchema, + clientLabelSet: LabelSetSchema, // include the ENSDbConfig params in the ENSIndexerConfigSchema ensDbUrl: z.string(), @@ -177,7 +177,7 @@ export function buildConfigFromEnvironment(_env: ENSIndexerEnvironment): EnsInde endBlock: env.END_BLOCK, }, ensRainbowUrl: env.ENSRAINBOW_URL, - labelSet: { + clientLabelSet: { labelSetId: env.LABEL_SET_ID, labelSetVersion: env.LABEL_SET_VERSION, }, diff --git a/apps/ensindexer/src/config/config.test.ts b/apps/ensindexer/src/config/config.test.ts index 40a21dfbb9..3c6208b3f1 100644 --- a/apps/ensindexer/src/config/config.test.ts +++ b/apps/ensindexer/src/config/config.test.ts @@ -100,7 +100,7 @@ describe("config (with base env)", () => { vi.stubEnv("LABEL_SET_ID", "subgraph"); const newConfig = await getConfig(); - expect(newConfig.labelSet.labelSetId).toBe("subgraph"); + expect(newConfig.clientLabelSet.labelSetId).toBe("subgraph"); expect(newConfig).not.toBe(initialConfig); }); }); @@ -566,12 +566,12 @@ describe("config (with base env)", () => { }); }); - describe(".labelSet", () => { - it("returns the labelSet configuration if both LABEL_SET_ID and LABEL_SET_VERSION are valid", async () => { + describe(".clientLabelSet", () => { + it("returns the clientLabelSet configuration if both LABEL_SET_ID and LABEL_SET_VERSION are valid", async () => { vi.stubEnv("LABEL_SET_ID", "subgraph"); vi.stubEnv("LABEL_SET_VERSION", "5"); const config = await getConfig(); - expect(config.labelSet).toEqual({ + expect(config.clientLabelSet).toEqual({ labelSetId: "subgraph", labelSetVersion: 5, }); @@ -587,7 +587,7 @@ describe("config (with base env)", () => { vi.stubEnv("LABEL_SET_VERSION", undefined); await expect(getConfig()).resolves.toMatchObject({ - labelSet: { labelSetId: "subgraph", labelSetVersion: 0 }, + clientLabelSet: { labelSetId: "subgraph", labelSetVersion: 0 }, }); }); }); @@ -602,7 +602,7 @@ describe("config (with base env)", () => { vi.stubEnv("LABEL_SET_VERSION", undefined); await expect(getConfig()).resolves.toMatchObject({ - labelSet: { labelSetId: "subgraph", labelSetVersion: 0 }, + clientLabelSet: { labelSetId: "subgraph", labelSetVersion: 0 }, }); }); }); @@ -635,7 +635,7 @@ describe("config (with base env)", () => { it("accepts valid LABEL_SET_ID with hyphens", async () => { vi.stubEnv("LABEL_SET_ID", "ens-test-env"); const config = await getConfig(); - expect(config.labelSet.labelSetId).toBe("ens-test-env"); + expect(config.clientLabelSet.labelSetId).toBe("ens-test-env"); }); it("throws an error when LABEL_SET_VERSION is negative", async () => { @@ -656,7 +656,7 @@ describe("config (with base env)", () => { it("accepts zero as a valid LABEL_SET_VERSION", async () => { vi.stubEnv("LABEL_SET_VERSION", "0"); const config = await getConfig(); - expect(config.labelSet.labelSetVersion).toBe(0); + expect(config.clientLabelSet.labelSetVersion).toBe(0); }); }); }); @@ -848,7 +848,7 @@ describe("config (minimal base env)", () => { stubEnv({ SUBGRAPH_COMPAT: "true" }); }); - it("ens-test-env namespace/labelset is subgraph-compatible", async () => { + it("ens-test-env namespace/clientLabelSet is subgraph-compatible", async () => { stubEnv({ NAMESPACE: "ens-test-env", LABEL_SET_ID: "ens-test-env", @@ -857,7 +857,7 @@ describe("config (minimal base env)", () => { }); await expect(getConfig()).resolves.toMatchObject({ namespace: ENSNamespaceIds.EnsTestEnv, - labelSet: { + clientLabelSet: { labelSetId: "ens-test-env", labelSetVersion: 0, }, diff --git a/apps/ensindexer/src/config/environment-defaults.test.ts b/apps/ensindexer/src/config/environment-defaults.test.ts index 47a02de67b..0f888277bc 100644 --- a/apps/ensindexer/src/config/environment-defaults.test.ts +++ b/apps/ensindexer/src/config/environment-defaults.test.ts @@ -55,14 +55,14 @@ describe("environment-defaults", () => { // test runtime behavior for specific cases. // partial config provided by user - const PROVIDED: any = { labelSet: { labelSetVersion: "1" } }; + const PROVIDED: any = { clientLabelSet: { labelSetVersion: "1" } }; // full default set - const DEFAULTS: any = { labelSet: { labelSetId: "subgraph", labelSetVersion: "0" } }; + const DEFAULTS: any = { clientLabelSet: { labelSetId: "subgraph", labelSetVersion: "0" } }; // applyDefaults correctly provides the nested value without clobbering user-provided nested value expect(applyDefaults(PROVIDED, DEFAULTS)).toStrictEqual({ - labelSet: { + clientLabelSet: { labelSetId: "subgraph", labelSetVersion: "1", }, diff --git a/apps/ensindexer/src/config/serialize.ts b/apps/ensindexer/src/config/serialize.ts index 509668379d..563970289e 100644 --- a/apps/ensindexer/src/config/serialize.ts +++ b/apps/ensindexer/src/config/serialize.ts @@ -44,7 +44,7 @@ export function serializeRedactedENSIndexerConfig( ensIndexerSchemaName: redactedConfig.ensIndexerSchemaName, ensDbUrl: redactedConfig.ensDbUrl, ensRainbowUrl: serializeUrl(redactedConfig.ensRainbowUrl), - labelSet: redactedConfig.labelSet, + clientLabelSet: redactedConfig.clientLabelSet, globalBlockrange: redactedConfig.globalBlockrange, indexedChainIds: serializeIndexedChainIds(redactedConfig.indexedChainIds), isSubgraphCompatible: redactedConfig.isSubgraphCompatible, diff --git a/apps/ensindexer/src/config/serialized-types.ts b/apps/ensindexer/src/config/serialized-types.ts index 1d67489100..167b4d572e 100644 --- a/apps/ensindexer/src/config/serialized-types.ts +++ b/apps/ensindexer/src/config/serialized-types.ts @@ -35,7 +35,7 @@ export interface SerializedENSIndexerConfig /** * The "fully pinned" label set reference that ENSIndexer will request ENSRainbow use for deterministic label healing across time. This label set reference is "fully pinned" as it requires both the labelSetId and labelSetVersion fields to be defined. */ - labelSet: Required; + clientLabelSet: Required; /** * Serialized representation of {@link ENSIndexerConfig.indexedChainIds}. diff --git a/apps/ensindexer/src/config/types.ts b/apps/ensindexer/src/config/types.ts index 924e062cae..2518d43069 100644 --- a/apps/ensindexer/src/config/types.ts +++ b/apps/ensindexer/src/config/types.ts @@ -33,7 +33,7 @@ export interface EnsIndexerConfig { /** * The "fully pinned" label set reference that ENSIndexer will request ENSRainbow use for deterministic label healing across time. This label set reference is "fully pinned" as it requires both the labelSetId and labelSetVersion fields to be defined. */ - labelSet: Required; + clientLabelSet: Required; /** * The name of the ENSIndexer Schema in ENSDb where ENSIndexer will create diff --git a/apps/ensindexer/src/lib/ensdb-writer-worker/ensdb-writer-worker.mock.ts b/apps/ensindexer/src/lib/ensdb-writer-worker/ensdb-writer-worker.mock.ts index c4d5d48422..ccba1cee8a 100644 --- a/apps/ensindexer/src/lib/ensdb-writer-worker/ensdb-writer-worker.mock.ts +++ b/apps/ensindexer/src/lib/ensdb-writer-worker/ensdb-writer-worker.mock.ts @@ -36,7 +36,7 @@ export const mockVersionInfo: EnsIndexerVersionInfo = { // Test fixture for EnsIndexerPublicConfig export const mockPublicConfig: EnsIndexerPublicConfig = { ensIndexerSchemaName: "ensindexer_0", - labelSet: { labelSetId: "subgraph", labelSetVersion: 0 }, + clientLabelSet: { labelSetId: "subgraph", labelSetVersion: 0 }, ensRainbowPublicConfig: mockEnsRainbowPublicConfig, indexedChainIds: new Set([1, 8453]), isSubgraphCompatible: true, diff --git a/apps/ensindexer/src/lib/ensrainbow/singleton.ts b/apps/ensindexer/src/lib/ensrainbow/singleton.ts index c6785560c0..331d62e6a9 100644 --- a/apps/ensindexer/src/lib/ensrainbow/singleton.ts +++ b/apps/ensindexer/src/lib/ensrainbow/singleton.ts @@ -7,7 +7,7 @@ import { EnsRainbowApiClient } from "@ensnode/ensrainbow-sdk"; import { logger } from "@/lib/logger"; -const { ensRainbowUrl, labelSet } = config; +const { ensRainbowUrl, clientLabelSet } = config; if (ensRainbowUrl.href === EnsRainbowApiClient.defaultOptions().endpointUrl.href) { logger.warn({ @@ -21,7 +21,7 @@ if (ensRainbowUrl.href === EnsRainbowApiClient.defaultOptions().endpointUrl.href */ export const ensRainbowClient = new EnsRainbowApiClient({ endpointUrl: ensRainbowUrl, - labelSet, + clientLabelSet, }); /** diff --git a/apps/ensindexer/src/lib/public-config-builder/public-config-builder.test.ts b/apps/ensindexer/src/lib/public-config-builder/public-config-builder.test.ts index 56b396976c..8dcaf969a1 100644 --- a/apps/ensindexer/src/lib/public-config-builder/public-config-builder.test.ts +++ b/apps/ensindexer/src/lib/public-config-builder/public-config-builder.test.ts @@ -15,7 +15,7 @@ import { PublicConfigBuilder } from "./public-config-builder"; vi.mock("@/config", () => ({ default: { ensIndexerSchemaName: "ensindexer_0", - labelSet: { labelSetId: "subgraph", labelSetVersion: 0 }, + clientLabelSet: { labelSetId: "subgraph", labelSetVersion: 0 }, indexedChainIds: new Set([1, 8453]), isSubgraphCompatible: true, namespace: ENSNamespaceIds.Mainnet, @@ -67,7 +67,7 @@ const mockVersionInfo: EnsIndexerVersionInfo = { function createMockPublicConfig(overrides: Partial = {}) { return { ensIndexerSchemaName: "ensindexer_0", - labelSet: { labelSetId: "subgraph", labelSetVersion: 0 }, + clientLabelSet: { labelSetId: "subgraph", labelSetVersion: 0 }, ensRainbowPublicConfig: mockEnsRainbowConfig, indexedChainIds: new Set([1, 8453]), isSubgraphCompatible: true, @@ -122,7 +122,7 @@ describe("PublicConfigBuilder", () => { expect(validateEnsIndexerPublicConfig).toHaveBeenCalledWith({ ensIndexerSchemaName: config.ensIndexerSchemaName, ensRainbowPublicConfig: mockEnsRainbowConfig, - labelSet: config.labelSet, + clientLabelSet: config.clientLabelSet, indexedChainIds: config.indexedChainIds, isSubgraphCompatible: config.isSubgraphCompatible, namespace: config.namespace, @@ -203,7 +203,7 @@ describe("PublicConfigBuilder", () => { // Arrange const customConfig = createMockPublicConfig({ isSubgraphCompatible: false, - labelSet: { labelSetId: "custom", labelSetVersion: 1 }, + clientLabelSet: { labelSetId: "custom", labelSetVersion: 1 }, }); const customEnsRainbowConfig: EnsRainbowPublicConfig = { diff --git a/apps/ensindexer/src/lib/public-config-builder/public-config-builder.ts b/apps/ensindexer/src/lib/public-config-builder/public-config-builder.ts index a34a8465f0..7229af0367 100644 --- a/apps/ensindexer/src/lib/public-config-builder/public-config-builder.ts +++ b/apps/ensindexer/src/lib/public-config-builder/public-config-builder.ts @@ -53,7 +53,7 @@ export class PublicConfigBuilder { this.immutablePublicConfig = validateEnsIndexerPublicConfig({ ensIndexerSchemaName: config.ensIndexerSchemaName, ensRainbowPublicConfig, - labelSet: config.labelSet, + clientLabelSet: config.clientLabelSet, indexedChainIds: config.indexedChainIds, isSubgraphCompatible: config.isSubgraphCompatible, namespace: config.namespace, diff --git a/apps/ensindexer/src/ponder/indexing-behavior-injection-contract.ts b/apps/ensindexer/src/ponder/indexing-behavior-injection-contract.ts index 311f3a2aef..f738d34a76 100644 --- a/apps/ensindexer/src/ponder/indexing-behavior-injection-contract.ts +++ b/apps/ensindexer/src/ponder/indexing-behavior-injection-contract.ts @@ -47,12 +47,12 @@ interface IndexingBehaviorDependencies { isSubgraphCompatible: boolean; /** - * Label Set + * Label Set for ENSIndexer client requests to ENSRainbow * * When `labelSet` changes, the label "healing" results may change during indexing, * which influences the indexing behavior. */ - labelSet: EnsIndexerConfig["labelSet"]; + clientLabelSet: EnsIndexerConfig["clientLabelSet"]; /** * ENSDb Schema Checksum @@ -112,7 +112,7 @@ const indexingBehaviorDependencies = { // injected here to ensure that, if they are configured differently, ponder generates a unique // build id to differentiate between runs with otherwise-identical configs (see above). isSubgraphCompatible: config.isSubgraphCompatible, - labelSet: config.labelSet, + clientLabelSet: config.clientLabelSet, ensDbSchemaChecksum: ENSDB_SCHEMA_CHECKSUM, } satisfies IndexingBehaviorDependencies; diff --git a/docs/ensnode.io/src/content/docs/ensrainbow/concepts/typescript-interfaces.mdx b/docs/ensnode.io/src/content/docs/ensrainbow/concepts/typescript-interfaces.mdx index e998b50476..76d5a59bb0 100644 --- a/docs/ensnode.io/src/content/docs/ensrainbow/concepts/typescript-interfaces.mdx +++ b/docs/ensnode.io/src/content/docs/ensrainbow/concepts/typescript-interfaces.mdx @@ -42,9 +42,9 @@ interface EnsRainbowClientLabelSet { #### Usage Guidelines -1. **Neither field** → accept any labelset and use the latest version (default behaviour). -2. **Only `labelSetId`** → insist on a specific labelset and use the latest version. -3. **Both fields** → insist on a specific labelset and version, locking the client to an exact snapshot. +1. **Neither field** → accept any client labelset and use the latest version (default behaviour). +2. **Only `labelSetId`** → insist on a specific client labelset and use the latest version. +3. **Both fields** → insist on a specific client labelset and version, locking the client to an exact snapshot. This handshake that occurs when **both fields** are set ensures both client and server interpret every heal operation against the **same logical labelset snapshot**, enabling deterministic and reproducible healing results across time. @@ -63,13 +63,13 @@ const client1 = new EnsRainbowApiClient({ // Pin to subgraph labelset, use latest version const client2 = new EnsRainbowApiClient({ baseUrl: 'https://api.ensrainbow.io', - labelSet: { labelSetId: 'subgraph' } + clientLabelSet: { labelSetId: 'subgraph' } }); // Pin to exact labelset snapshot for deterministic results across time const client3 = new EnsRainbowApiClient({ baseUrl: 'https://api.ensrainbow.io', - labelSet: { + clientLabelSet: { labelSetId: 'subgraph', labelSetVersion: 0 } diff --git a/docs/ensnode.io/src/content/docs/ensrainbow/usage/client-sdk.mdx b/docs/ensnode.io/src/content/docs/ensrainbow/usage/client-sdk.mdx index 6e0b4623a0..250bb887de 100644 --- a/docs/ensnode.io/src/content/docs/ensrainbow/usage/client-sdk.mdx +++ b/docs/ensnode.io/src/content/docs/ensrainbow/usage/client-sdk.mdx @@ -30,7 +30,7 @@ import { EnsRainbowApiClient } from '@ensnode/ensrainbow-sdk'; const client = new EnsRainbowApiClient({ baseUrl: 'https://api.ensrainbow.io', - labelSet: { labelSetId: 'subgraph', labelSetVersion: 0 } + clientLabelSet: { labelSetId: 'subgraph', labelSetVersion: 0 } }); const res = await client.healLabel('0xaf2caa1c2ca1d027f1ac823b529d0a67cd144264b2789fa2ea4d63a67c7103cc'); diff --git a/packages/ensdb-sdk/src/client/ensdb-client.mock.ts b/packages/ensdb-sdk/src/client/ensdb-client.mock.ts index 926d2ca4f3..d3a1a646b4 100644 --- a/packages/ensdb-sdk/src/client/ensdb-client.mock.ts +++ b/packages/ensdb-sdk/src/client/ensdb-client.mock.ts @@ -33,7 +33,7 @@ export const publicConfig = { }, recordsCount: 100, }, - labelSet: { + clientLabelSet: { labelSetId: "subgraph", labelSetVersion: 0, }, diff --git a/packages/ensnode-sdk/src/ensapi/config/conversions.test.ts b/packages/ensnode-sdk/src/ensapi/config/conversions.test.ts index 7f4bf6afa1..cae5dc2b70 100644 --- a/packages/ensnode-sdk/src/ensapi/config/conversions.test.ts +++ b/packages/ensnode-sdk/src/ensapi/config/conversions.test.ts @@ -27,7 +27,7 @@ const MOCK_ENSAPI_PUBLIC_CONFIG = { }, indexedChainIds: new Set([1]), isSubgraphCompatible: false, - labelSet: { labelSetId: "subgraph", labelSetVersion: 0 }, + clientLabelSet: { labelSetId: "subgraph", labelSetVersion: 0 }, plugins: [PluginName.Subgraph], versionInfo: { ensDb: "0.36.0", @@ -64,7 +64,7 @@ describe("ENSApi Config Serialization/Deserialization", () => { }, indexedChainIds: [1], isSubgraphCompatible: false, - labelSet: { labelSetId: "subgraph", labelSetVersion: 0 }, + clientLabelSet: { labelSetId: "subgraph", labelSetVersion: 0 }, plugins: [PluginName.Subgraph], versionInfo: { ensDb: "0.36.0", diff --git a/packages/ensnode-sdk/src/ensindexer/client.mock.ts b/packages/ensnode-sdk/src/ensindexer/client.mock.ts index 3bfd76b3cd..86e7f43554 100644 --- a/packages/ensnode-sdk/src/ensindexer/client.mock.ts +++ b/packages/ensnode-sdk/src/ensindexer/client.mock.ts @@ -8,7 +8,7 @@ import type { SerializedEnsIndexerIndexingStatusResponse } from "./api/indexing- import { PluginName } from "./config/types"; export const configResponseMock = { - labelSet: { + clientLabelSet: { labelSetId: "subgraph", labelSetVersion: 0, }, diff --git a/packages/ensnode-sdk/src/ensindexer/config/compatibility.test.ts b/packages/ensnode-sdk/src/ensindexer/config/compatibility.test.ts index c7da25c5b9..9a9e24b55a 100644 --- a/packages/ensnode-sdk/src/ensindexer/config/compatibility.test.ts +++ b/packages/ensnode-sdk/src/ensindexer/config/compatibility.test.ts @@ -12,7 +12,7 @@ describe("EnsIndexerConfig compatibility", () => { describe("validateEnsIndexerPublicConfigCompatibility()", () => { const config = { indexedChainIds: new Set([1, 10, 8453]), - labelSet: { + clientLabelSet: { labelSetId: "test-label-set", labelSetVersion: 1, }, @@ -72,30 +72,30 @@ describe("EnsIndexerConfig compatibility", () => { const configB = { ...structuredClone(config), - labelSet: { - ...structuredClone(config.labelSet), + clientLabelSet: { + ...structuredClone(config.clientLabelSet), labelSetId: "different-label-set", }, } satisfies EnsIndexerPublicConfigCompatibilityCheck; expect(() => validateEnsIndexerPublicConfigCompatibility(configA, configB)).toThrowError( - /'labelSet.labelSetId' must be compatible. Stored Config 'labelSet.labelSetId': 'test-label-set'. Current Config 'labelSet.labelSetId': 'different-label-set'/i, + /'clientLabelSet.labelSetId' must be compatible. Stored Config 'clientLabelSet.labelSetId': 'test-label-set'. Current Config 'clientLabelSet.labelSetId': 'different-label-set'/i, ); }); - it("throws error when 'configA.labelSet.labelSetVersion' is not same as 'configB.labelSet.labelSetVersion'", () => { + it("throws error when 'configA.clientLabelSet.labelSetVersion' is not same as 'configB.clientLabelSet.labelSetVersion'", () => { const configA = structuredClone(config); const configB = { ...structuredClone(config), - labelSet: { - ...structuredClone(config.labelSet), - labelSetVersion: config.labelSet.labelSetVersion + 1, + clientLabelSet: { + ...structuredClone(config.clientLabelSet), + labelSetVersion: config.clientLabelSet.labelSetVersion + 1, }, } satisfies EnsIndexerPublicConfigCompatibilityCheck; expect(() => validateEnsIndexerPublicConfigCompatibility(configA, configB)).toThrowError( - /'labelSet.labelSetVersion' must be compatible. Stored Config 'labelSet.labelSetVersion': '1'. Current Config 'labelSet.labelSetVersion': '2'/i, + /'clientLabelSet.labelSetVersion' must be compatible. Stored Config 'clientLabelSet.labelSetVersion': '1'. Current Config 'clientLabelSet.labelSetVersion': '2'/i, ); }); diff --git a/packages/ensnode-sdk/src/ensindexer/config/compatibility.ts b/packages/ensnode-sdk/src/ensindexer/config/compatibility.ts index b38f3769c1..dfd6ecaa38 100644 --- a/packages/ensnode-sdk/src/ensindexer/config/compatibility.ts +++ b/packages/ensnode-sdk/src/ensindexer/config/compatibility.ts @@ -44,22 +44,22 @@ export function validateEnsIndexerPublicConfigCompatibility( ); } - if (configA.labelSet.labelSetId !== configB.labelSet.labelSetId) { + if (configA.clientLabelSet.labelSetId !== configB.clientLabelSet.labelSetId) { throw new Error( [ - `'labelSet.labelSetId' must be compatible.`, - `Stored Config 'labelSet.labelSetId': '${configA.labelSet.labelSetId}'.`, - `Current Config 'labelSet.labelSetId': '${configB.labelSet.labelSetId}'.`, + `'clientLabelSet.labelSetId' must be compatible.`, + `Stored Config 'clientLabelSet.labelSetId': '${configA.clientLabelSet.labelSetId}'.`, + `Current Config 'clientLabelSet.labelSetId': '${configB.clientLabelSet.labelSetId}'.`, ].join(" "), ); } - if (configA.labelSet.labelSetVersion !== configB.labelSet.labelSetVersion) { + if (configA.clientLabelSet.labelSetVersion !== configB.clientLabelSet.labelSetVersion) { throw new Error( [ - `'labelSet.labelSetVersion' must be compatible.`, - `Stored Config 'labelSet.labelSetVersion': '${configA.labelSet.labelSetVersion}'.`, - `Current Config 'labelSet.labelSetVersion': '${configB.labelSet.labelSetVersion}'.`, + `'clientLabelSet.labelSetVersion' must be compatible.`, + `Stored Config 'clientLabelSet.labelSetVersion': '${configA.clientLabelSet.labelSetVersion}'.`, + `Current Config 'clientLabelSet.labelSetVersion': '${configB.clientLabelSet.labelSetVersion}'.`, ].join(" "), ); } diff --git a/packages/ensnode-sdk/src/ensindexer/config/conversions.test.ts b/packages/ensnode-sdk/src/ensindexer/config/conversions.test.ts index 4dd5c05493..35a9fba527 100644 --- a/packages/ensnode-sdk/src/ensindexer/config/conversions.test.ts +++ b/packages/ensnode-sdk/src/ensindexer/config/conversions.test.ts @@ -16,7 +16,7 @@ describe("ENSIndexer: Config", () => { labelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, recordsCount: 100, }, - labelSet: { + clientLabelSet: { labelSetId: "subgraph", labelSetVersion: 0, }, @@ -58,7 +58,7 @@ describe("ENSIndexer: Config", () => { labelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, recordsCount: 100, }, - labelSet: { + clientLabelSet: { labelSetId: "subgraph", labelSetVersion: 0, }, diff --git a/packages/ensnode-sdk/src/ensindexer/config/is-subgraph-compatible.test.ts b/packages/ensnode-sdk/src/ensindexer/config/is-subgraph-compatible.test.ts index 6320299249..44a1623b8b 100644 --- a/packages/ensnode-sdk/src/ensindexer/config/is-subgraph-compatible.test.ts +++ b/packages/ensnode-sdk/src/ensindexer/config/is-subgraph-compatible.test.ts @@ -6,7 +6,7 @@ import { isSubgraphCompatible } from "./is-subgraph-compatible"; import { PluginName } from "./types"; describe("isSubgraphCompatible", () => { - const subgraphCompatibleLabelSet = { + const subgraphCompatibleClientLabelSet = { labelSetId: "subgraph" as const, labelSetVersion: 0, }; @@ -16,7 +16,7 @@ describe("isSubgraphCompatible", () => { isSubgraphCompatible({ namespace: ENSNamespaceIds.Mainnet, plugins: [PluginName.Subgraph], - labelSet: subgraphCompatibleLabelSet, + clientLabelSet: subgraphCompatibleClientLabelSet, }), ).toBe(true); }); @@ -26,7 +26,7 @@ describe("isSubgraphCompatible", () => { isSubgraphCompatible({ namespace: ENSNamespaceIds.Mainnet, plugins: [], - labelSet: subgraphCompatibleLabelSet, + clientLabelSet: subgraphCompatibleClientLabelSet, }), ).toBe(false); @@ -34,7 +34,7 @@ describe("isSubgraphCompatible", () => { isSubgraphCompatible({ namespace: ENSNamespaceIds.Mainnet, plugins: [PluginName.Subgraph, PluginName.Lineanames], - labelSet: subgraphCompatibleLabelSet, + clientLabelSet: subgraphCompatibleClientLabelSet, }), ).toBe(false); }); @@ -44,7 +44,7 @@ describe("isSubgraphCompatible", () => { isSubgraphCompatible({ namespace: ENSNamespaceIds.Mainnet, plugins: [PluginName.Subgraph], - labelSet: { + clientLabelSet: { labelSetId: "other-label-set", labelSetVersion: 0, }, @@ -57,7 +57,7 @@ describe("isSubgraphCompatible", () => { isSubgraphCompatible({ namespace: ENSNamespaceIds.Mainnet, plugins: [PluginName.Subgraph], - labelSet: { + clientLabelSet: { labelSetId: "subgraph", labelSetVersion: 1, }, @@ -70,7 +70,7 @@ describe("isSubgraphCompatible", () => { isSubgraphCompatible({ namespace: ENSNamespaceIds.EnsTestEnv, plugins: [PluginName.Subgraph], - labelSet: { + clientLabelSet: { labelSetId: "ens-test-env", labelSetVersion: 0, }, diff --git a/packages/ensnode-sdk/src/ensindexer/config/is-subgraph-compatible.ts b/packages/ensnode-sdk/src/ensindexer/config/is-subgraph-compatible.ts index b1587c7dc3..ab859f5485 100644 --- a/packages/ensnode-sdk/src/ensindexer/config/is-subgraph-compatible.ts +++ b/packages/ensnode-sdk/src/ensindexer/config/is-subgraph-compatible.ts @@ -9,7 +9,7 @@ import { type EnsIndexerPublicConfig, PluginName } from "./types"; * @see https://ensnode.io/docs/concepts/what-is-the-ens-subgraph */ export function isSubgraphCompatible( - config: Pick, + config: Pick, ): boolean { // 1. only the subgraph plugin is active const onlySubgraphPluginActivated = @@ -17,10 +17,11 @@ export function isSubgraphCompatible( // 2. label set id must be "subgraph" and version must be 0 const isSubgraphLabelSet = - config.labelSet.labelSetId === "subgraph" && config.labelSet.labelSetVersion === 0; + config.clientLabelSet.labelSetId === "subgraph" && config.clientLabelSet.labelSetVersion === 0; const isEnsTestEnvLabelSet = - config.labelSet.labelSetId === "ens-test-env" && config.labelSet.labelSetVersion === 0; + config.clientLabelSet.labelSetId === "ens-test-env" && + config.clientLabelSet.labelSetVersion === 0; // config should be considered subgraph-compatible if in ens-test-env namespace with ens-test-env labelset const labelSetIsSubgraphCompatible = diff --git a/packages/ensnode-sdk/src/ensindexer/config/serialize.ts b/packages/ensnode-sdk/src/ensindexer/config/serialize.ts index da32387442..7f7a3fc6aa 100644 --- a/packages/ensnode-sdk/src/ensindexer/config/serialize.ts +++ b/packages/ensnode-sdk/src/ensindexer/config/serialize.ts @@ -24,7 +24,7 @@ export function serializeEnsIndexerPublicConfig( ensRainbowPublicConfig, indexedChainIds, isSubgraphCompatible, - labelSet, + clientLabelSet, namespace, plugins, versionInfo, @@ -35,7 +35,7 @@ export function serializeEnsIndexerPublicConfig( ensRainbowPublicConfig, indexedChainIds: serializeIndexedChainIds(indexedChainIds), isSubgraphCompatible, - labelSet, + clientLabelSet, namespace, plugins, versionInfo, diff --git a/packages/ensnode-sdk/src/ensindexer/config/types.ts b/packages/ensnode-sdk/src/ensindexer/config/types.ts index 0476e7d377..8851a0a478 100644 --- a/packages/ensnode-sdk/src/ensindexer/config/types.ts +++ b/packages/ensnode-sdk/src/ensindexer/config/types.ts @@ -78,7 +78,7 @@ export interface EnsIndexerPublicConfig { /** * The "fully pinned" label set reference that ENSIndexer will request ENSRainbow use for deterministic label healing across time. This label set reference is "fully pinned" as it requires both the labelSetId and labelSetVersion fields to be defined. */ - labelSet: Required; + clientLabelSet: Required; /** * The name of the ENSIndexer Schema in the ENSDb instance, diff --git a/packages/ensnode-sdk/src/ensindexer/config/zod-schemas.test.ts b/packages/ensnode-sdk/src/ensindexer/config/zod-schemas.test.ts index fcc9adab74..a65888f7d5 100644 --- a/packages/ensnode-sdk/src/ensindexer/config/zod-schemas.test.ts +++ b/packages/ensnode-sdk/src/ensindexer/config/zod-schemas.test.ts @@ -167,7 +167,7 @@ describe("ENSIndexer: Config", () => { makeEnsIndexerPublicConfigSchema().safeParse( buildUnvalidatedEnsIndexerPublicConfig({ ...baseConfig, - labelSet: { labelSetId: "custom-labels", labelSetVersion: 0 }, + clientLabelSet: { labelSetId: "custom-labels", labelSetVersion: 0 }, }), ), ), @@ -181,7 +181,7 @@ describe("ENSIndexer: Config", () => { makeEnsIndexerPublicConfigSchema().safeParse( buildUnvalidatedEnsIndexerPublicConfig({ ...baseConfig, - labelSet: { labelSetId: "subgraph", labelSetVersion: 5 }, + clientLabelSet: { labelSetId: "subgraph", labelSetVersion: 5 }, }), ), ), @@ -198,7 +198,7 @@ describe("ENSIndexer: Config", () => { }, recordsCount: 100, }, - labelSet: { + clientLabelSet: { labelSetId: "subgraph", labelSetVersion: 0, }, @@ -226,11 +226,11 @@ describe("ENSIndexer: Config", () => { makeEnsIndexerPublicConfigSchema().safeParse( buildUnvalidatedEnsIndexerPublicConfig({ ...validConfig, - labelSet: { ...validConfig.labelSet, labelSetId: "" }, + clientLabelSet: { ...validConfig.clientLabelSet, labelSetId: "" }, }), ), ), - ).toContain("labelSet.labelSetId must be 1-50 characters long"); + ).toContain("clientLabelSet.labelSetId must be 1-50 characters long"); // Test invalid labelSetVersion expect( @@ -238,14 +238,14 @@ describe("ENSIndexer: Config", () => { makeEnsIndexerPublicConfigSchema().safeParse( buildUnvalidatedEnsIndexerPublicConfig({ ...validConfig, - labelSet: { - ...validConfig.labelSet, + clientLabelSet: { + ...validConfig.clientLabelSet, labelSetVersion: "not-a-number" as unknown as number, }, }), ), ), - ).toContain("labelSet.labelSetVersion must be a non-negative integer"); + ).toContain("clientLabelSet.labelSetVersion must be a non-negative integer"); }); }); diff --git a/packages/ensnode-sdk/src/ensindexer/config/zod-schemas.ts b/packages/ensnode-sdk/src/ensindexer/config/zod-schemas.ts index 68f32f9987..0a7e6ca163 100644 --- a/packages/ensnode-sdk/src/ensindexer/config/zod-schemas.ts +++ b/packages/ensnode-sdk/src/ensindexer/config/zod-schemas.ts @@ -118,7 +118,10 @@ export const makeENSIndexerVersionInfoSchema = makeEnsIndexerVersionInfoSchema; // Invariant: If config.isSubgraphCompatible, the config must pass isSubgraphCompatible(config) export function invariant_isSubgraphCompatibleRequirements( ctx: ZodCheckFnInput< - Pick + Pick< + EnsIndexerPublicConfig, + "namespace" | "plugins" | "isSubgraphCompatible" | "clientLabelSet" + > >, ) { const { value: config } = ctx; @@ -127,15 +130,15 @@ export function invariant_isSubgraphCompatibleRequirements( ctx.issues.push({ code: "custom", input: config, - message: `'isSubgraphCompatible' requires only the '${PluginName.Subgraph}' plugin to be active and labelSet must be {labelSetId: "subgraph", labelSetVersion: 0}`, + message: `'isSubgraphCompatible' requires only the '${PluginName.Subgraph}' plugin to be active and 'clientLabelSet' must be {labelSetId: "subgraph", labelSetVersion: 0}`, }); } } export function invariant_ensRainbowSupportedLabelSetAndVersion( - ctx: ZodCheckFnInput>, + ctx: ZodCheckFnInput>, ) { - const clientLabelSet = ctx.value.labelSet satisfies EnsRainbowClientLabelSet; + const clientLabelSet = ctx.value.clientLabelSet satisfies EnsRainbowClientLabelSet; const serverLabelSet = ctx.value.ensRainbowPublicConfig .labelSet satisfies EnsRainbowServerLabelSet; @@ -169,7 +172,7 @@ export const makeEnsIndexerPublicConfigSchema = (valueLabel: string = "ENSIndexe isSubgraphCompatible: z.boolean({ error: `${valueLabel}.isSubgraphCompatible must be a boolean value.`, }), - labelSet: makeFullyPinnedLabelSetSchema(`${valueLabel}.labelSet`), + clientLabelSet: makeFullyPinnedLabelSetSchema(`${valueLabel}.clientLabelSet`), namespace: makeENSNamespaceIdSchema(`${valueLabel}.namespace`), plugins: makePluginsListSchema(`${valueLabel}.plugins`), versionInfo: makeEnsIndexerVersionInfoSchema(`${valueLabel}.versionInfo`), @@ -201,7 +204,7 @@ export const makeSerializedEnsIndexerPublicConfigSchema = ( isSubgraphCompatible: z.boolean({ error: `${valueLabel}.isSubgraphCompatible must be a boolean value.`, }), - labelSet: makeFullyPinnedLabelSetSchema(`${valueLabel}.labelSet`), + clientLabelSet: makeFullyPinnedLabelSetSchema(`${valueLabel}.clientLabelSet`), namespace: makeENSNamespaceIdSchema(`${valueLabel}.namespace`), plugins: makePluginsListSchema(`${valueLabel}.plugins`), versionInfo: makeEnsIndexerVersionInfoSchema(`${valueLabel}.versionInfo`), diff --git a/packages/ensnode-sdk/src/ensnode/client.test.ts b/packages/ensnode-sdk/src/ensnode/client.test.ts index a3e5b7dcf5..98c42ebf2b 100644 --- a/packages/ensnode-sdk/src/ensnode/client.test.ts +++ b/packages/ensnode-sdk/src/ensnode/client.test.ts @@ -75,7 +75,7 @@ const EXAMPLE_ENSAPI_CONFIG_RESPONSE = { labelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, recordsCount: 100, }, - labelSet: { + clientLabelSet: { labelSetId: "subgraph", labelSetVersion: 0, }, @@ -112,7 +112,7 @@ const EXAMPLE_ENSINDEXER_PUBLIC_CONFIG = { labelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, recordsCount: 100, }, - labelSet: { + clientLabelSet: { labelSetId: "subgraph", labelSetVersion: 0, }, diff --git a/packages/ensnode-sdk/src/stack-info/deserialize/ensindexer-stack-info.ts b/packages/ensnode-sdk/src/stack-info/deserialize/ensindexer-stack-info.ts index da22b2ff1d..aa1d146f73 100644 --- a/packages/ensnode-sdk/src/stack-info/deserialize/ensindexer-stack-info.ts +++ b/packages/ensnode-sdk/src/stack-info/deserialize/ensindexer-stack-info.ts @@ -19,9 +19,14 @@ import { export function buildUnvalidatedEnsIndexerStackInfo( serializedStackInfo: SerializedEnsIndexerStackInfo, ): Unvalidated { + // `ensDb` and `ensRainbow` are already in a deserialized form, so we can include them directly + const { ensDb, ensRainbow } = serializedStackInfo; + const ensIndexer = buildUnvalidatedEnsIndexerPublicConfig(serializedStackInfo.ensIndexer); + return { - ensIndexer: buildUnvalidatedEnsIndexerPublicConfig(serializedStackInfo.ensIndexer), - ensRainbow: serializedStackInfo.ensRainbow, // ENSRainbow Public Config is already in a serialized form, so we can include it directly + ensDb, + ensIndexer, + ensRainbow, }; } diff --git a/packages/ensnode-sdk/src/stack-info/zod-schemas/ensindexer-stack-info.ts b/packages/ensnode-sdk/src/stack-info/zod-schemas/ensindexer-stack-info.ts index bbbfed17da..2447541a17 100644 --- a/packages/ensnode-sdk/src/stack-info/zod-schemas/ensindexer-stack-info.ts +++ b/packages/ensnode-sdk/src/stack-info/zod-schemas/ensindexer-stack-info.ts @@ -24,19 +24,19 @@ export function invariant_ensRainbowCompatibilityWithEnsIndexer( ) { const { ensIndexer, ensRainbow } = ctx.value; - if (ensIndexer.labelSet.labelSetId !== ensRainbow.labelSet.labelSetId) { + if (ensIndexer.clientLabelSet.labelSetId !== ensRainbow.labelSet.labelSetId) { ctx.issues.push({ code: "custom", input: ctx.value, - message: `ENSRainbow's label set (id: ${ensRainbow.labelSet.labelSetId}) must be the same as the ENSIndexer's label set (id: ${ensIndexer.labelSet.labelSetId}).`, + message: `ENSRainbow's label set (id: ${ensRainbow.labelSet.labelSetId}) must be the same as the ENSIndexer's label set (id: ${ensIndexer.clientLabelSet.labelSetId}).`, }); } - if (ensIndexer.labelSet.labelSetVersion > ensRainbow.labelSet.highestLabelSetVersion) { + if (ensIndexer.clientLabelSet.labelSetVersion > ensRainbow.labelSet.highestLabelSetVersion) { ctx.issues.push({ code: "custom", input: ctx.value, - message: `ENSRainbow's server label set version (highest: ${ensRainbow.labelSet.highestLabelSetVersion}) must be greater than or equal to ENSIndexer's client label set version (current: ${ensIndexer.labelSet.labelSetVersion}).`, + message: `ENSRainbow's server label set version (highest: ${ensRainbow.labelSet.highestLabelSetVersion}) must be greater than or equal to ENSIndexer's client label set version (current: ${ensIndexer.clientLabelSet.labelSetVersion}).`, }); } } diff --git a/packages/ensrainbow-sdk/src/client.test.ts b/packages/ensrainbow-sdk/src/client.test.ts index 16b57ca5e2..f8d791bd0d 100644 --- a/packages/ensrainbow-sdk/src/client.test.ts +++ b/packages/ensrainbow-sdk/src/client.test.ts @@ -28,7 +28,7 @@ describe("EnsRainbowApiClient", () => { expect(client.getOptions()).toEqual({ endpointUrl: new URL(DEFAULT_ENSRAINBOW_URL), cacheCapacity: EnsRainbowApiClient.DEFAULT_CACHE_CAPACITY, - labelSet: { + clientLabelSet: { labelSetId: undefined, labelSetVersion: undefined, }, @@ -45,7 +45,7 @@ describe("EnsRainbowApiClient", () => { expect(client.getOptions()).toEqual({ endpointUrl: customEndpointUrl, cacheCapacity: 0, - labelSet: { + clientLabelSet: { labelSetId: undefined, labelSetVersion: undefined, }, @@ -57,7 +57,7 @@ describe("EnsRainbowApiClient", () => { client = new EnsRainbowApiClient({ endpointUrl: customEndpointUrl, cacheCapacity: 0, - labelSet: { + clientLabelSet: { labelSetId: "subgraph", labelSetVersion: undefined, }, @@ -66,7 +66,7 @@ describe("EnsRainbowApiClient", () => { expect(client.getOptions()).toEqual({ endpointUrl: customEndpointUrl, cacheCapacity: 0, - labelSet: { + clientLabelSet: { labelSetId: "subgraph", labelSetVersion: undefined, }, @@ -97,7 +97,7 @@ describe("EnsRainbowApiClient", () => { new EnsRainbowApiClient({ endpointUrl: customEndpointUrl, cacheCapacity: 0, - labelSet: { + clientLabelSet: { labelSetId: undefined, labelSetVersion: 0, }, @@ -275,7 +275,7 @@ describe("EnsRainbowApiClient", () => { it("should request /v1/config and return public config on success", async () => { const configData: EnsRainbow.ENSRainbowPublicConfig = { version: "2.0.0", - labelSet: { + serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 5, }, diff --git a/packages/ensrainbow-sdk/src/client.ts b/packages/ensrainbow-sdk/src/client.ts index f6511d5d0f..3144a35b6c 100644 --- a/packages/ensrainbow-sdk/src/client.ts +++ b/packages/ensrainbow-sdk/src/client.ts @@ -145,7 +145,7 @@ export interface EnsRainbowApiClientOptions { endpointUrl: URL; /** - * Optional label set preferences that the ENSRainbow server at endpointUrl is expected to + * Optional client label set preferences that the ENSRainbow server at endpointUrl is expected to * support. If provided, enables deterministic heal results across time, such that only * labels from label sets with versions less than or equal to this value will be returned. * Therefore, even if the ENSRainbow server later ingests label sets with greater versions @@ -159,7 +159,7 @@ export interface EnsRainbowApiClientOptions { * will be returned. * When `labelSetVersion` is defined, `labelSetId` must also be defined. */ - labelSet?: EnsRainbowClientLabelSet; + clientLabelSet?: EnsRainbowClientLabelSet; } /** @@ -178,7 +178,7 @@ export interface EnsRainbowApiClientOptions { export class EnsRainbowApiClient implements EnsRainbow.ApiClient { private readonly options: EnsRainbowApiClientOptions; private readonly cache: Cache; - private readonly labelSetSearchParams: URLSearchParams; + private readonly clientLabelSetSearchParams: URLSearchParams; public static readonly DEFAULT_CACHE_CAPACITY = 1000; @@ -191,23 +191,23 @@ export class EnsRainbowApiClient implements EnsRainbow.ApiClient { return { endpointUrl: new URL(DEFAULT_ENSRAINBOW_URL), cacheCapacity: EnsRainbowApiClient.DEFAULT_CACHE_CAPACITY, - labelSet: buildEnsRainbowClientLabelSet(), + clientLabelSet: buildEnsRainbowClientLabelSet(), }; } constructor(options: Partial = {}) { - const { labelSet: optionsLabelSet, ...rest } = options; + const { clientLabelSet: optionsClientLabelSet, ...rest } = options; const defaultOptions = EnsRainbowApiClient.defaultOptions(); const copiedLabelSet = buildEnsRainbowClientLabelSet( - optionsLabelSet?.labelSetId, - optionsLabelSet?.labelSetVersion, + optionsClientLabelSet?.labelSetId, + optionsClientLabelSet?.labelSetVersion, ); this.options = { ...defaultOptions, ...rest, - labelSet: copiedLabelSet, + clientLabelSet: copiedLabelSet, }; this.cache = new LruCache( @@ -215,14 +215,17 @@ export class EnsRainbowApiClient implements EnsRainbow.ApiClient { ); // Pre-compute query parameters for label set options - this.labelSetSearchParams = new URLSearchParams(); - if (this.options.labelSet?.labelSetId !== undefined) { - this.labelSetSearchParams.append("label_set_id", this.options.labelSet.labelSetId); + this.clientLabelSetSearchParams = new URLSearchParams(); + if (this.options.clientLabelSet?.labelSetId !== undefined) { + this.clientLabelSetSearchParams.append( + "label_set_id", + this.options.clientLabelSet.labelSetId, + ); } - if (this.options.labelSet?.labelSetVersion !== undefined) { - this.labelSetSearchParams.append( + if (this.options.clientLabelSet?.labelSetVersion !== undefined) { + this.clientLabelSetSearchParams.append( "label_set_version", - this.options.labelSet.labelSetVersion.toString(), + this.options.clientLabelSet.labelSetVersion.toString(), ); } } @@ -291,7 +294,7 @@ export class EnsRainbowApiClient implements EnsRainbow.ApiClient { const url = new URL(`/v1/heal/${normalizedLabelHash}`, this.options.endpointUrl); // Apply pre-computed label set query parameters - this.labelSetSearchParams.forEach((value, key) => { + this.clientLabelSetSearchParams.forEach((value, key) => { url.searchParams.append(key, value); }); @@ -375,7 +378,7 @@ export class EnsRainbowApiClient implements EnsRainbow.ApiClient { const deepCopy = { cacheCapacity: this.options.cacheCapacity, endpointUrl: new URL(this.options.endpointUrl.href), - labelSet: this.options.labelSet ? { ...this.options.labelSet } : undefined, + clientLabelSet: this.options.clientLabelSet ? { ...this.options.clientLabelSet } : undefined, } satisfies EnsRainbowApiClientOptions; return Object.freeze(deepCopy); From ac04e08c2a8954819705eb05d501575e3925fd4e Mon Sep 17 00:00:00 2001 From: Tomasz Kopacki Date: Fri, 24 Apr 2026 13:20:35 +0200 Subject: [PATCH 13/21] Rename `labelSet` field to `serverLabelSet` for `EnsRainbowPublicConfig` and ENSRainbow internal data models --- apps/ensadmin/src/app/mock/indexing-status-api.mock.ts | 2 +- .../src/app/mock/stack-info/stack-info.mock.ts | 8 ++++---- .../components/connection/cards/ensnode-stack-info.tsx | 4 ++-- apps/ensapi/src/config/config.schema.test.ts | 2 +- .../ensdb-writer-worker/ensdb-writer-worker.mock.ts | 2 +- .../public-config-builder.test.ts | 4 ++-- apps/ensrainbow/src/commands/server-command.test.ts | 8 ++++---- apps/ensrainbow/src/config/config.schema.test.ts | 4 ++-- apps/ensrainbow/src/config/public.ts | 2 +- apps/ensrainbow/src/config/types.ts | 2 +- apps/ensrainbow/src/lib/database.ts | 10 +++++----- apps/ensrainbow/src/lib/server.ts | 2 +- packages/ensdb-sdk/src/client/ensdb-client.mock.ts | 2 +- .../ensnode-sdk/src/ensapi/config/conversions.test.ts | 4 ++-- packages/ensnode-sdk/src/ensindexer/client.mock.ts | 2 +- .../src/ensindexer/config/conversions.test.ts | 4 ++-- .../src/ensindexer/config/zod-schemas.test.ts | 4 ++-- .../ensnode-sdk/src/ensindexer/config/zod-schemas.ts | 6 ++---- packages/ensnode-sdk/src/ensnode/client.test.ts | 6 +++--- packages/ensnode-sdk/src/ensrainbow/config.ts | 2 +- .../ensnode-sdk/src/ensrainbow/zod-schemas/config.ts | 6 +++--- .../stack-info/zod-schemas/ensindexer-stack-info.ts | 10 ++++++---- 22 files changed, 48 insertions(+), 48 deletions(-) diff --git a/apps/ensadmin/src/app/mock/indexing-status-api.mock.ts b/apps/ensadmin/src/app/mock/indexing-status-api.mock.ts index d5e0fd596a..b8584cfd4e 100644 --- a/apps/ensadmin/src/app/mock/indexing-status-api.mock.ts +++ b/apps/ensadmin/src/app/mock/indexing-status-api.mock.ts @@ -32,7 +32,7 @@ const serializedEnsIndexerPublicConfig = { ensIndexerSchemaName: "alphaSchema1.9.0", ensRainbowPublicConfig: { version: "1.9.0", - labelSet: { + serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0, }, diff --git a/apps/ensadmin/src/app/mock/stack-info/stack-info.mock.ts b/apps/ensadmin/src/app/mock/stack-info/stack-info.mock.ts index 3c10b69cd2..33c30c6a25 100644 --- a/apps/ensadmin/src/app/mock/stack-info/stack-info.mock.ts +++ b/apps/ensadmin/src/app/mock/stack-info/stack-info.mock.ts @@ -34,7 +34,7 @@ const COMMON_CLIENT_LABEL_SET = { const COMMON_ENSRAINBOW_CONFIG = { version: "1.9.0", - labelSet: { + serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0, }, @@ -215,7 +215,7 @@ function createDeserializationErrorVariant(): SerializedEnsNodeStackInfo { isSubgraphCompatible: true, ensRainbowPublicConfig: { version: "", - labelSet: { + serverLabelSet: { labelSetId: "", highestLabelSetVersion: -1, }, @@ -242,7 +242,7 @@ function createDeserializationErrorVariant(): SerializedEnsNodeStackInfo { isSubgraphCompatible: true, ensRainbowPublicConfig: { version: "", - labelSet: { + serverLabelSet: { labelSetId: "", highestLabelSetVersion: -1, }, @@ -251,7 +251,7 @@ function createDeserializationErrorVariant(): SerializedEnsNodeStackInfo { }, ensRainbow: { version: "", - labelSet: { + serverLabelSet: { labelSetId: "", highestLabelSetVersion: -1, }, diff --git a/apps/ensadmin/src/components/connection/cards/ensnode-stack-info.tsx b/apps/ensadmin/src/components/connection/cards/ensnode-stack-info.tsx index a4543fec07..1279719d3e 100644 --- a/apps/ensadmin/src/components/connection/cards/ensnode-stack-info.tsx +++ b/apps/ensadmin/src/components/connection/cards/ensnode-stack-info.tsx @@ -609,8 +609,8 @@ function EnsNodeStackInfoCardContent({ ensNodeStackInfo }: { ensNodeStackInfo: E label="Server LabelSet" value={

- {ensRainbowPublicConfig.labelSet.labelSetId}: - {ensRainbowPublicConfig.labelSet.highestLabelSetVersion} + {ensRainbowPublicConfig.serverLabelSet.labelSetId}: + {ensRainbowPublicConfig.serverLabelSet.highestLabelSetVersion}

} additionalInfo={ diff --git a/apps/ensapi/src/config/config.schema.test.ts b/apps/ensapi/src/config/config.schema.test.ts index 9ac9c6d4bf..1b050b002e 100644 --- a/apps/ensapi/src/config/config.schema.test.ts +++ b/apps/ensapi/src/config/config.schema.test.ts @@ -43,7 +43,7 @@ const ENSINDEXER_PUBLIC_CONFIG = { ensIndexerSchemaName: "ensindexer_0", ensRainbowPublicConfig: { version: packageJson.version, - labelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, + serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, recordsCount: 100, }, indexedChainIds: new Set([1]), diff --git a/apps/ensindexer/src/lib/ensdb-writer-worker/ensdb-writer-worker.mock.ts b/apps/ensindexer/src/lib/ensdb-writer-worker/ensdb-writer-worker.mock.ts index ccba1cee8a..0904b430e9 100644 --- a/apps/ensindexer/src/lib/ensdb-writer-worker/ensdb-writer-worker.mock.ts +++ b/apps/ensindexer/src/lib/ensdb-writer-worker/ensdb-writer-worker.mock.ts @@ -21,7 +21,7 @@ import type { PublicConfigBuilder } from "@/lib/public-config-builder"; // Test fixture for EnsRainbowPublicConfig export const mockEnsRainbowPublicConfig: EnsRainbowPublicConfig = { version: "1.0.0", - labelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, + serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, recordsCount: 1000, }; diff --git a/apps/ensindexer/src/lib/public-config-builder/public-config-builder.test.ts b/apps/ensindexer/src/lib/public-config-builder/public-config-builder.test.ts index 8dcaf969a1..6455dd6185 100644 --- a/apps/ensindexer/src/lib/public-config-builder/public-config-builder.test.ts +++ b/apps/ensindexer/src/lib/public-config-builder/public-config-builder.test.ts @@ -52,7 +52,7 @@ import { getEnsIndexerVersion, getPackageVersion } from "@/lib/version-info"; // Test fixtures const mockEnsRainbowConfig: EnsRainbowPublicConfig = { version: "1.0.0", - labelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, + serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, recordsCount: 1000, }; @@ -208,7 +208,7 @@ describe("PublicConfigBuilder", () => { const customEnsRainbowConfig: EnsRainbowPublicConfig = { version: "1.0.0", - labelSet: { labelSetId: "custom", highestLabelSetVersion: 1 }, + serverLabelSet: { labelSetId: "custom", highestLabelSetVersion: 1 }, recordsCount: 2000, }; diff --git a/apps/ensrainbow/src/commands/server-command.test.ts b/apps/ensrainbow/src/commands/server-command.test.ts index 50f9bc26ca..a7557a1fdd 100644 --- a/apps/ensrainbow/src/commands/server-command.test.ts +++ b/apps/ensrainbow/src/commands/server-command.test.ts @@ -167,8 +167,8 @@ describe("Server Command Tests", () => { expect(typeof data.version).toBe("string"); expect(data.version.length).toBeGreaterThan(0); - expect(data.labelSet.labelSetId).toBe("test-label-set-id"); - expect(data.labelSet.highestLabelSetVersion).toBe(0); + expect(data.serverLabelSet.labelSetId).toBe("test-label-set-id"); + expect(data.serverLabelSet.highestLabelSetVersion).toBe(0); // Config is built on startup with count = 0, so it returns the startup value expect(data.recordsCount).toBe(0); }); @@ -184,8 +184,8 @@ describe("Server Command Tests", () => { expect(typeof data.version).toBe("string"); expect(data.version.length).toBeGreaterThan(0); - expect(data.labelSet.labelSetId).toBe("test-label-set-id"); - expect(data.labelSet.highestLabelSetVersion).toBe(0); + expect(data.serverLabelSet.labelSetId).toBe("test-label-set-id"); + expect(data.serverLabelSet.highestLabelSetVersion).toBe(0); // Config is built on startup with count = 0, so changing the DB doesn't affect it expect(data.recordsCount).toBe(0); }); diff --git a/apps/ensrainbow/src/config/config.schema.test.ts b/apps/ensrainbow/src/config/config.schema.test.ts index 5b80d4982b..e09efe944c 100644 --- a/apps/ensrainbow/src/config/config.schema.test.ts +++ b/apps/ensrainbow/src/config/config.schema.test.ts @@ -385,7 +385,7 @@ describe("parseDataDirFromCli", () => { describe("buildEnsRainbowPublicConfig", () => { const dbConfig: DbConfig = { - labelSet: { + serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0, }, @@ -397,7 +397,7 @@ describe("buildEnsRainbowPublicConfig", () => { expect(result).toStrictEqual({ version: packageJson.version, - labelSet: dbConfig.labelSet, + serverLabelSet: dbConfig.serverLabelSet, recordsCount: dbConfig.recordsCount, }); }); diff --git a/apps/ensrainbow/src/config/public.ts b/apps/ensrainbow/src/config/public.ts index 906a361e64..72b7cb2a33 100644 --- a/apps/ensrainbow/src/config/public.ts +++ b/apps/ensrainbow/src/config/public.ts @@ -7,7 +7,7 @@ import type { DbConfig } from "./types"; export function buildEnsRainbowPublicConfig(dbConfig: DbConfig): EnsRainbow.ENSRainbowPublicConfig { return { version: packageJson.version, - labelSet: dbConfig.labelSet, + serverLabelSet: dbConfig.serverLabelSet, recordsCount: dbConfig.recordsCount, }; } diff --git a/apps/ensrainbow/src/config/types.ts b/apps/ensrainbow/src/config/types.ts index eb5d822542..1301dc77c5 100644 --- a/apps/ensrainbow/src/config/types.ts +++ b/apps/ensrainbow/src/config/types.ts @@ -38,6 +38,6 @@ export interface ServeCommandConfig { * Metadata read from an opened ENSRainbow database. */ export interface DbConfig { - labelSet: EnsRainbowServerLabelSet; + serverLabelSet: EnsRainbowServerLabelSet; recordsCount: number; } diff --git a/apps/ensrainbow/src/lib/database.ts b/apps/ensrainbow/src/lib/database.ts index 3452a869fb..8d4b9ea0f7 100644 --- a/apps/ensrainbow/src/lib/database.ts +++ b/apps/ensrainbow/src/lib/database.ts @@ -577,11 +577,11 @@ export class ENSRainbowDB { } // 3. Check Label Set ID and Highest Label Set Version Existence and Validity - let labelSet: EnsRainbowServerLabelSet; + let serverLabelSet: EnsRainbowServerLabelSet; try { - labelSet = await this.getLabelSet(); + serverLabelSet = await this.getLabelSet(); logger.info( - `Label set verified - ID: ${labelSet.labelSetId}, highest version: ${labelSet.highestLabelSetVersion}`, + `Label set verified - ID: ${serverLabelSet.labelSetId}, highest version: ${serverLabelSet.highestLabelSetVersion}`, ); } catch (error) { const errorMsg = generatePurgeErrorMessage(`Error checking label set: ${error}`); @@ -650,9 +650,9 @@ export class ENSRainbowDB { // Only proceed with further checks if decoding was successful // Label set version comparison - if (versionedRainbowRecord.labelSetVersion > labelSet.highestLabelSetVersion) { + if (versionedRainbowRecord.labelSetVersion > serverLabelSet.highestLabelSetVersion) { logger.error( - `Label set version mismatch for label "${value}": record set ${versionedRainbowRecord.labelSetVersion} > highest set ${labelSet.highestLabelSetVersion}`, + `Label set version mismatch for label "${value}": record set ${versionedRainbowRecord.labelSetVersion} > highest set ${serverLabelSet.highestLabelSetVersion}`, ); labelSetVersionMismatches++; } diff --git a/apps/ensrainbow/src/lib/server.ts b/apps/ensrainbow/src/lib/server.ts index b3da287c5a..6892869e75 100644 --- a/apps/ensrainbow/src/lib/server.ts +++ b/apps/ensrainbow/src/lib/server.ts @@ -29,7 +29,7 @@ export async function buildDbConfig(server: ENSRainbowServer): Promise } return { - labelSet: server.serverLabelSet, + serverLabelSet: server.serverLabelSet, recordsCount: countResult.count, }; } diff --git a/packages/ensdb-sdk/src/client/ensdb-client.mock.ts b/packages/ensdb-sdk/src/client/ensdb-client.mock.ts index d3a1a646b4..486ec9b0f1 100644 --- a/packages/ensdb-sdk/src/client/ensdb-client.mock.ts +++ b/packages/ensdb-sdk/src/client/ensdb-client.mock.ts @@ -27,7 +27,7 @@ export const publicConfig = { ensIndexerSchemaName, ensRainbowPublicConfig: { version: "0.32.0", - labelSet: { + serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0, }, diff --git a/packages/ensnode-sdk/src/ensapi/config/conversions.test.ts b/packages/ensnode-sdk/src/ensapi/config/conversions.test.ts index cae5dc2b70..e87fc94457 100644 --- a/packages/ensnode-sdk/src/ensapi/config/conversions.test.ts +++ b/packages/ensnode-sdk/src/ensapi/config/conversions.test.ts @@ -22,7 +22,7 @@ const MOCK_ENSAPI_PUBLIC_CONFIG = { ensIndexerSchemaName: "ensindexer_0", ensRainbowPublicConfig: { version: "0.36.0", - labelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, + serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, recordsCount: 100, }, indexedChainIds: new Set([1]), @@ -59,7 +59,7 @@ describe("ENSApi Config Serialization/Deserialization", () => { ensIndexerSchemaName: "ensindexer_0", ensRainbowPublicConfig: { version: "0.36.0", - labelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, + serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, recordsCount: 100, }, indexedChainIds: [1], diff --git a/packages/ensnode-sdk/src/ensindexer/client.mock.ts b/packages/ensnode-sdk/src/ensindexer/client.mock.ts index 86e7f43554..29d33fbaac 100644 --- a/packages/ensnode-sdk/src/ensindexer/client.mock.ts +++ b/packages/ensnode-sdk/src/ensindexer/client.mock.ts @@ -16,7 +16,7 @@ export const configResponseMock = { ensIndexerSchemaName: "alphaSchema0.31.0", ensRainbowPublicConfig: { version: "0.31.0", - labelSet: { + serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0, }, diff --git a/packages/ensnode-sdk/src/ensindexer/config/conversions.test.ts b/packages/ensnode-sdk/src/ensindexer/config/conversions.test.ts index 35a9fba527..72c3228080 100644 --- a/packages/ensnode-sdk/src/ensindexer/config/conversions.test.ts +++ b/packages/ensnode-sdk/src/ensindexer/config/conversions.test.ts @@ -13,7 +13,7 @@ describe("ENSIndexer: Config", () => { ensIndexerSchemaName: "ensindexer_0", ensRainbowPublicConfig: { version: "0.32.0", - labelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, + serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, recordsCount: 100, }, clientLabelSet: { @@ -55,7 +55,7 @@ describe("ENSIndexer: Config", () => { ensIndexerSchemaName: "ensindexer_0", ensRainbowPublicConfig: { version: "0.32.0", - labelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, + serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, recordsCount: 100, }, clientLabelSet: { diff --git a/packages/ensnode-sdk/src/ensindexer/config/zod-schemas.test.ts b/packages/ensnode-sdk/src/ensindexer/config/zod-schemas.test.ts index a65888f7d5..4705fa1e59 100644 --- a/packages/ensnode-sdk/src/ensindexer/config/zod-schemas.test.ts +++ b/packages/ensnode-sdk/src/ensindexer/config/zod-schemas.test.ts @@ -142,7 +142,7 @@ describe("ENSIndexer: Config", () => { const baseConfig = { ensRainbowPublicConfig: { version: "0.32.0", - labelSet: { + serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0, }, @@ -192,7 +192,7 @@ describe("ENSIndexer: Config", () => { const validConfig = { ensRainbowPublicConfig: { version: "0.32.0", - labelSet: { + serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0, }, diff --git a/packages/ensnode-sdk/src/ensindexer/config/zod-schemas.ts b/packages/ensnode-sdk/src/ensindexer/config/zod-schemas.ts index 0a7e6ca163..a4d4d47606 100644 --- a/packages/ensnode-sdk/src/ensindexer/config/zod-schemas.ts +++ b/packages/ensnode-sdk/src/ensindexer/config/zod-schemas.ts @@ -8,7 +8,6 @@ */ import { z } from "zod/v4"; -import type { EnsRainbowClientLabelSet, EnsRainbowServerLabelSet } from "../../ensrainbow/types"; import { makeEnsRainbowPublicConfigSchema, makeLabelSetIdSchema, @@ -138,9 +137,8 @@ export function invariant_isSubgraphCompatibleRequirements( export function invariant_ensRainbowSupportedLabelSetAndVersion( ctx: ZodCheckFnInput>, ) { - const clientLabelSet = ctx.value.clientLabelSet satisfies EnsRainbowClientLabelSet; - const serverLabelSet = ctx.value.ensRainbowPublicConfig - .labelSet satisfies EnsRainbowServerLabelSet; + const { clientLabelSet } = ctx.value; + const { serverLabelSet } = ctx.value.ensRainbowPublicConfig; try { validateSupportedLabelSetAndVersion(serverLabelSet, clientLabelSet); diff --git a/packages/ensnode-sdk/src/ensnode/client.test.ts b/packages/ensnode-sdk/src/ensnode/client.test.ts index 98c42ebf2b..e7b70d6cf4 100644 --- a/packages/ensnode-sdk/src/ensnode/client.test.ts +++ b/packages/ensnode-sdk/src/ensnode/client.test.ts @@ -72,7 +72,7 @@ const EXAMPLE_ENSAPI_CONFIG_RESPONSE = { ensIndexerPublicConfig: { ensRainbowPublicConfig: { version: "1.9.0", - labelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, + serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, recordsCount: 100, }, clientLabelSet: { @@ -109,7 +109,7 @@ const EXAMPLE_ENSDB_PUBLIC_RESPONSE = { const EXAMPLE_ENSINDEXER_PUBLIC_CONFIG = { ensRainbowPublicConfig: { version: "1.9.0", - labelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, + serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, recordsCount: 100, }, clientLabelSet: { @@ -138,7 +138,7 @@ const EXAMPLE_ENSINDEXER_PUBLIC_CONFIG = { const EXAMPLE_ENSRAINBOW_PUBLIC_CONFIG = { version: "1.9.0", - labelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, + serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, recordsCount: 100, } satisfies SerializedEnsRainbowPublicConfig; diff --git a/packages/ensnode-sdk/src/ensrainbow/config.ts b/packages/ensnode-sdk/src/ensrainbow/config.ts index d5f141c59d..cdf17e983b 100644 --- a/packages/ensnode-sdk/src/ensrainbow/config.ts +++ b/packages/ensnode-sdk/src/ensrainbow/config.ts @@ -17,7 +17,7 @@ export interface EnsRainbowPublicConfig { /** * The label set reference managed by the ENSRainbow server. */ - labelSet: EnsRainbowServerLabelSet; + serverLabelSet: EnsRainbowServerLabelSet; /** * The total count of records managed by the ENSRainbow service. diff --git a/packages/ensnode-sdk/src/ensrainbow/zod-schemas/config.ts b/packages/ensnode-sdk/src/ensrainbow/zod-schemas/config.ts index b8aff5a513..25f208649e 100644 --- a/packages/ensnode-sdk/src/ensrainbow/zod-schemas/config.ts +++ b/packages/ensnode-sdk/src/ensrainbow/zod-schemas/config.ts @@ -46,10 +46,10 @@ export const makeLabelSetVersionStringSchema = (valueLabel: string = "Label set export const makeEnsRainbowPublicConfigSchema = (valueLabel: string = "EnsRainbowPublicConfig") => z.object({ version: z.string().nonempty({ error: `${valueLabel}.version must be a non-empty string.` }), - labelSet: z.object({ - labelSetId: makeLabelSetIdSchema(`${valueLabel}.labelSet.labelSetId`), + serverLabelSet: z.object({ + labelSetId: makeLabelSetIdSchema(`${valueLabel}.serverLabelSet.labelSetId`), highestLabelSetVersion: makeLabelSetVersionSchema( - `${valueLabel}.labelSet.highestLabelSetVersion`, + `${valueLabel}.serverLabelSet.highestLabelSetVersion`, ), }), recordsCount: makeNonNegativeIntegerSchema(`${valueLabel}.recordsCount`), diff --git a/packages/ensnode-sdk/src/stack-info/zod-schemas/ensindexer-stack-info.ts b/packages/ensnode-sdk/src/stack-info/zod-schemas/ensindexer-stack-info.ts index 2447541a17..7e1e6abc2b 100644 --- a/packages/ensnode-sdk/src/stack-info/zod-schemas/ensindexer-stack-info.ts +++ b/packages/ensnode-sdk/src/stack-info/zod-schemas/ensindexer-stack-info.ts @@ -23,20 +23,22 @@ export function invariant_ensRainbowCompatibilityWithEnsIndexer( ctx: ZodCheckFnInput, ) { const { ensIndexer, ensRainbow } = ctx.value; + const { clientLabelSet } = ensIndexer; + const { serverLabelSet } = ensRainbow; - if (ensIndexer.clientLabelSet.labelSetId !== ensRainbow.labelSet.labelSetId) { + if (clientLabelSet.labelSetId !== serverLabelSet.labelSetId) { ctx.issues.push({ code: "custom", input: ctx.value, - message: `ENSRainbow's label set (id: ${ensRainbow.labelSet.labelSetId}) must be the same as the ENSIndexer's label set (id: ${ensIndexer.clientLabelSet.labelSetId}).`, + message: `ENSRainbow's label set (id: ${serverLabelSet.labelSetId}) must be the same as the ENSIndexer's label set (id: ${clientLabelSet.labelSetId}).`, }); } - if (ensIndexer.clientLabelSet.labelSetVersion > ensRainbow.labelSet.highestLabelSetVersion) { + if (clientLabelSet.labelSetVersion > serverLabelSet.highestLabelSetVersion) { ctx.issues.push({ code: "custom", input: ctx.value, - message: `ENSRainbow's server label set version (highest: ${ensRainbow.labelSet.highestLabelSetVersion}) must be greater than or equal to ENSIndexer's client label set version (current: ${ensIndexer.clientLabelSet.labelSetVersion}).`, + message: `ENSRainbow's server label set version (highest: ${serverLabelSet.highestLabelSetVersion}) must be greater than or equal to ENSIndexer's client label set version (current: ${clientLabelSet.labelSetVersion}).`, }); } } From a26dfcc45ce004584fdf354d3d62a07a65667715 Mon Sep 17 00:00:00 2001 From: Tomasz Kopacki Date: Fri, 24 Apr 2026 13:41:56 +0200 Subject: [PATCH 14/21] Remove `recordsCount` field from `EnsRainbowPublicConfig` data model --- .../src/app/mock/indexing-status-api.mock.ts | 1 - .../app/mock/stack-info/stack-info.mock.ts | 4 ---- .../connection/cards/ensnode-stack-info.tsx | 19 ------------------- apps/ensapi/src/config/config.schema.test.ts | 1 - .../ensdb-writer-worker.mock.ts | 1 - .../public-config-builder.test.ts | 2 -- .../src/commands/server-command.test.ts | 17 +---------------- .../ensrainbow/src/commands/server-command.ts | 2 +- .../src/config/config.schema.test.ts | 1 - apps/ensrainbow/src/config/public.ts | 1 - apps/ensrainbow/src/lib/api.ts | 4 +++- .../ensdb-sdk/src/client/ensdb-client.mock.ts | 1 - .../src/ensapi/config/conversions.test.ts | 2 -- .../ensnode-sdk/src/ensindexer/client.mock.ts | 1 - .../src/ensindexer/config/conversions.test.ts | 2 -- .../src/ensindexer/config/zod-schemas.test.ts | 2 -- .../ensnode-sdk/src/ensnode/client.test.ts | 3 --- packages/ensnode-sdk/src/ensrainbow/config.ts | 5 ----- .../src/ensrainbow/zod-schemas/config.ts | 1 - packages/ensrainbow-sdk/src/client.test.ts | 1 - 20 files changed, 5 insertions(+), 66 deletions(-) diff --git a/apps/ensadmin/src/app/mock/indexing-status-api.mock.ts b/apps/ensadmin/src/app/mock/indexing-status-api.mock.ts index b8584cfd4e..099f079979 100644 --- a/apps/ensadmin/src/app/mock/indexing-status-api.mock.ts +++ b/apps/ensadmin/src/app/mock/indexing-status-api.mock.ts @@ -36,7 +36,6 @@ const serializedEnsIndexerPublicConfig = { labelSetId: "subgraph", highestLabelSetVersion: 0, }, - recordsCount: 100, }, isSubgraphCompatible: false, namespace: "mainnet", diff --git a/apps/ensadmin/src/app/mock/stack-info/stack-info.mock.ts b/apps/ensadmin/src/app/mock/stack-info/stack-info.mock.ts index 33c30c6a25..57c474e96a 100644 --- a/apps/ensadmin/src/app/mock/stack-info/stack-info.mock.ts +++ b/apps/ensadmin/src/app/mock/stack-info/stack-info.mock.ts @@ -38,7 +38,6 @@ const COMMON_ENSRAINBOW_CONFIG = { labelSetId: "subgraph", highestLabelSetVersion: 0, }, - recordsCount: 100, } as const; const THE_GRAPH_FALLBACK_DISABLED: TheGraphFallback = { @@ -219,7 +218,6 @@ function createDeserializationErrorVariant(): SerializedEnsNodeStackInfo { labelSetId: "", highestLabelSetVersion: -1, }, - recordsCount: -1, }, }, }, @@ -246,7 +244,6 @@ function createDeserializationErrorVariant(): SerializedEnsNodeStackInfo { labelSetId: "", highestLabelSetVersion: -1, }, - recordsCount: -1, }, }, ensRainbow: { @@ -255,7 +252,6 @@ function createDeserializationErrorVariant(): SerializedEnsNodeStackInfo { labelSetId: "", highestLabelSetVersion: -1, }, - recordsCount: -1, }, }; } diff --git a/apps/ensadmin/src/components/connection/cards/ensnode-stack-info.tsx b/apps/ensadmin/src/components/connection/cards/ensnode-stack-info.tsx index 1279719d3e..3845d81212 100644 --- a/apps/ensadmin/src/components/connection/cards/ensnode-stack-info.tsx +++ b/apps/ensadmin/src/components/connection/cards/ensnode-stack-info.tsx @@ -624,25 +624,6 @@ function EnsNodeStackInfoCardContent({ ensNodeStackInfo }: { ensNodeStackInfo: E

} /> - - - {ensRainbowPublicConfig.recordsCount.toLocaleString()} -

- } - additionalInfo={ -

- The total number of Rainbow Records.{" "} - - Learn more. - -

- } - /> diff --git a/apps/ensapi/src/config/config.schema.test.ts b/apps/ensapi/src/config/config.schema.test.ts index 1b050b002e..09780ab00e 100644 --- a/apps/ensapi/src/config/config.schema.test.ts +++ b/apps/ensapi/src/config/config.schema.test.ts @@ -44,7 +44,6 @@ const ENSINDEXER_PUBLIC_CONFIG = { ensRainbowPublicConfig: { version: packageJson.version, serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, - recordsCount: 100, }, indexedChainIds: new Set([1]), isSubgraphCompatible: false, diff --git a/apps/ensindexer/src/lib/ensdb-writer-worker/ensdb-writer-worker.mock.ts b/apps/ensindexer/src/lib/ensdb-writer-worker/ensdb-writer-worker.mock.ts index 0904b430e9..187a8fe041 100644 --- a/apps/ensindexer/src/lib/ensdb-writer-worker/ensdb-writer-worker.mock.ts +++ b/apps/ensindexer/src/lib/ensdb-writer-worker/ensdb-writer-worker.mock.ts @@ -22,7 +22,6 @@ import type { PublicConfigBuilder } from "@/lib/public-config-builder"; export const mockEnsRainbowPublicConfig: EnsRainbowPublicConfig = { version: "1.0.0", serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, - recordsCount: 1000, }; // Test fixture for EnsIndexerVersionInfo diff --git a/apps/ensindexer/src/lib/public-config-builder/public-config-builder.test.ts b/apps/ensindexer/src/lib/public-config-builder/public-config-builder.test.ts index 6455dd6185..45ea4a20b2 100644 --- a/apps/ensindexer/src/lib/public-config-builder/public-config-builder.test.ts +++ b/apps/ensindexer/src/lib/public-config-builder/public-config-builder.test.ts @@ -53,7 +53,6 @@ import { getEnsIndexerVersion, getPackageVersion } from "@/lib/version-info"; const mockEnsRainbowConfig: EnsRainbowPublicConfig = { version: "1.0.0", serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, - recordsCount: 1000, }; const mockVersionInfo: EnsIndexerVersionInfo = { @@ -209,7 +208,6 @@ describe("PublicConfigBuilder", () => { const customEnsRainbowConfig: EnsRainbowPublicConfig = { version: "1.0.0", serverLabelSet: { labelSetId: "custom", highestLabelSetVersion: 1 }, - recordsCount: 2000, }; const ensRainbowClientMock = { diff --git a/apps/ensrainbow/src/commands/server-command.test.ts b/apps/ensrainbow/src/commands/server-command.test.ts index a7557a1fdd..d78916a91e 100644 --- a/apps/ensrainbow/src/commands/server-command.test.ts +++ b/apps/ensrainbow/src/commands/server-command.test.ts @@ -35,7 +35,7 @@ describe("Server Command Tests", () => { const ensRainbowServer = await ENSRainbowServer.init(db); const dbConfig = await buildDbConfig(ensRainbowServer); const publicConfig = buildEnsRainbowPublicConfig(dbConfig); - app = createApi(ensRainbowServer, publicConfig); + app = createApi(ensRainbowServer, publicConfig, dbConfig); // Start the server on a different port than what ENSRainbow defaults to server = serve({ @@ -144,17 +144,6 @@ describe("Server Command Tests", () => { expect(data).toEqual(expectedData); expect(() => new Date(data.timestamp as string)).not.toThrow(); }); - - it("should match recordsCount in /v1/config", async () => { - const [countRes, configRes] = await Promise.all([ - fetch(`http://localhost:${nonDefaultPort}/v1/labels/count`), - fetch(`http://localhost:${nonDefaultPort}/v1/config`), - ]); - const countData = (await countRes.json()) as EnsRainbow.CountSuccess; - const configData = (await configRes.json()) as EnsRainbow.ENSRainbowPublicConfig; - expect(countData.status).toBe(StatusCode.Success); - expect(countData.count).toBe(configData.recordsCount); - }); }); describe("GET /v1/config", () => { @@ -169,8 +158,6 @@ describe("Server Command Tests", () => { expect(data.version.length).toBeGreaterThan(0); expect(data.serverLabelSet.labelSetId).toBe("test-label-set-id"); expect(data.serverLabelSet.highestLabelSetVersion).toBe(0); - // Config is built on startup with count = 0, so it returns the startup value - expect(data.recordsCount).toBe(0); }); it("should return same config even if database count changes", async () => { @@ -186,8 +173,6 @@ describe("Server Command Tests", () => { expect(data.version.length).toBeGreaterThan(0); expect(data.serverLabelSet.labelSetId).toBe("test-label-set-id"); expect(data.serverLabelSet.highestLabelSetVersion).toBe(0); - // Config is built on startup with count = 0, so changing the DB doesn't affect it - expect(data.recordsCount).toBe(0); }); }); diff --git a/apps/ensrainbow/src/commands/server-command.ts b/apps/ensrainbow/src/commands/server-command.ts index 1288c9b469..f5c940044a 100644 --- a/apps/ensrainbow/src/commands/server-command.ts +++ b/apps/ensrainbow/src/commands/server-command.ts @@ -30,7 +30,7 @@ export async function serverCommand(options: ServerCommandOptions): Promise { expect(result).toStrictEqual({ version: packageJson.version, serverLabelSet: dbConfig.serverLabelSet, - recordsCount: dbConfig.recordsCount, }); }); }); diff --git a/apps/ensrainbow/src/config/public.ts b/apps/ensrainbow/src/config/public.ts index 72b7cb2a33..5fb893274d 100644 --- a/apps/ensrainbow/src/config/public.ts +++ b/apps/ensrainbow/src/config/public.ts @@ -8,6 +8,5 @@ export function buildEnsRainbowPublicConfig(dbConfig: DbConfig): EnsRainbow.ENSR return { version: packageJson.version, serverLabelSet: dbConfig.serverLabelSet, - recordsCount: dbConfig.recordsCount, }; } diff --git a/apps/ensrainbow/src/lib/api.ts b/apps/ensrainbow/src/lib/api.ts index dd754a3ce0..ca590d0554 100644 --- a/apps/ensrainbow/src/lib/api.ts +++ b/apps/ensrainbow/src/lib/api.ts @@ -12,6 +12,7 @@ import { } from "@ensnode/ensnode-sdk"; import { type EnsRainbow, ErrorCode, StatusCode } from "@ensnode/ensrainbow-sdk"; +import type { DbConfig } from "@/config/types"; import type { ENSRainbowServer } from "@/lib/server"; import { getErrorMessage } from "@/utils/error-utils"; import { logger } from "@/utils/logger"; @@ -22,6 +23,7 @@ import { logger } from "@/utils/logger"; export function createApi( server: ENSRainbowServer, publicConfig: EnsRainbow.ENSRainbowPublicConfig, + dbConfig: DbConfig, ): Hono { const api = new Hono(); @@ -89,7 +91,7 @@ export function createApi( api.get("/v1/labels/count", (c: HonoContext) => { const countResponse: EnsRainbow.CountSuccess = { status: StatusCode.Success, - count: publicConfig.recordsCount, + count: dbConfig.recordsCount, timestamp: new Date().toISOString(), }; return c.json(countResponse); diff --git a/packages/ensdb-sdk/src/client/ensdb-client.mock.ts b/packages/ensdb-sdk/src/client/ensdb-client.mock.ts index 486ec9b0f1..d5262d90d1 100644 --- a/packages/ensdb-sdk/src/client/ensdb-client.mock.ts +++ b/packages/ensdb-sdk/src/client/ensdb-client.mock.ts @@ -31,7 +31,6 @@ export const publicConfig = { labelSetId: "subgraph", highestLabelSetVersion: 0, }, - recordsCount: 100, }, clientLabelSet: { labelSetId: "subgraph", diff --git a/packages/ensnode-sdk/src/ensapi/config/conversions.test.ts b/packages/ensnode-sdk/src/ensapi/config/conversions.test.ts index e87fc94457..5574b784eb 100644 --- a/packages/ensnode-sdk/src/ensapi/config/conversions.test.ts +++ b/packages/ensnode-sdk/src/ensapi/config/conversions.test.ts @@ -23,7 +23,6 @@ const MOCK_ENSAPI_PUBLIC_CONFIG = { ensRainbowPublicConfig: { version: "0.36.0", serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, - recordsCount: 100, }, indexedChainIds: new Set([1]), isSubgraphCompatible: false, @@ -60,7 +59,6 @@ describe("ENSApi Config Serialization/Deserialization", () => { ensRainbowPublicConfig: { version: "0.36.0", serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, - recordsCount: 100, }, indexedChainIds: [1], isSubgraphCompatible: false, diff --git a/packages/ensnode-sdk/src/ensindexer/client.mock.ts b/packages/ensnode-sdk/src/ensindexer/client.mock.ts index 29d33fbaac..e894a27dc8 100644 --- a/packages/ensnode-sdk/src/ensindexer/client.mock.ts +++ b/packages/ensnode-sdk/src/ensindexer/client.mock.ts @@ -20,7 +20,6 @@ export const configResponseMock = { labelSetId: "subgraph", highestLabelSetVersion: 0, }, - recordsCount: 100, }, isSubgraphCompatible: false, namespace: "mainnet", diff --git a/packages/ensnode-sdk/src/ensindexer/config/conversions.test.ts b/packages/ensnode-sdk/src/ensindexer/config/conversions.test.ts index 72c3228080..226f7a9f59 100644 --- a/packages/ensnode-sdk/src/ensindexer/config/conversions.test.ts +++ b/packages/ensnode-sdk/src/ensindexer/config/conversions.test.ts @@ -14,7 +14,6 @@ describe("ENSIndexer: Config", () => { ensRainbowPublicConfig: { version: "0.32.0", serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, - recordsCount: 100, }, clientLabelSet: { labelSetId: "subgraph", @@ -56,7 +55,6 @@ describe("ENSIndexer: Config", () => { ensRainbowPublicConfig: { version: "0.32.0", serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, - recordsCount: 100, }, clientLabelSet: { labelSetId: "subgraph", diff --git a/packages/ensnode-sdk/src/ensindexer/config/zod-schemas.test.ts b/packages/ensnode-sdk/src/ensindexer/config/zod-schemas.test.ts index 4705fa1e59..ccb0f13216 100644 --- a/packages/ensnode-sdk/src/ensindexer/config/zod-schemas.test.ts +++ b/packages/ensnode-sdk/src/ensindexer/config/zod-schemas.test.ts @@ -146,7 +146,6 @@ describe("ENSIndexer: Config", () => { labelSetId: "subgraph", highestLabelSetVersion: 0, }, - recordsCount: 100, }, indexedChainIds: [1], // Use array for serialized config isSubgraphCompatible: false, // Set to false to bypass isSubgraphCompatible invariant @@ -196,7 +195,6 @@ describe("ENSIndexer: Config", () => { labelSetId: "subgraph", highestLabelSetVersion: 0, }, - recordsCount: 100, }, clientLabelSet: { labelSetId: "subgraph", diff --git a/packages/ensnode-sdk/src/ensnode/client.test.ts b/packages/ensnode-sdk/src/ensnode/client.test.ts index e7b70d6cf4..ae74b14318 100644 --- a/packages/ensnode-sdk/src/ensnode/client.test.ts +++ b/packages/ensnode-sdk/src/ensnode/client.test.ts @@ -73,7 +73,6 @@ const EXAMPLE_ENSAPI_CONFIG_RESPONSE = { ensRainbowPublicConfig: { version: "1.9.0", serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, - recordsCount: 100, }, clientLabelSet: { labelSetId: "subgraph", @@ -110,7 +109,6 @@ const EXAMPLE_ENSINDEXER_PUBLIC_CONFIG = { ensRainbowPublicConfig: { version: "1.9.0", serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, - recordsCount: 100, }, clientLabelSet: { labelSetId: "subgraph", @@ -139,7 +137,6 @@ const EXAMPLE_ENSINDEXER_PUBLIC_CONFIG = { const EXAMPLE_ENSRAINBOW_PUBLIC_CONFIG = { version: "1.9.0", serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, - recordsCount: 100, } satisfies SerializedEnsRainbowPublicConfig; const serializedStackInfo = { diff --git a/packages/ensnode-sdk/src/ensrainbow/config.ts b/packages/ensnode-sdk/src/ensrainbow/config.ts index cdf17e983b..748b296d6b 100644 --- a/packages/ensnode-sdk/src/ensrainbow/config.ts +++ b/packages/ensnode-sdk/src/ensrainbow/config.ts @@ -18,9 +18,4 @@ export interface EnsRainbowPublicConfig { * The label set reference managed by the ENSRainbow server. */ serverLabelSet: EnsRainbowServerLabelSet; - - /** - * The total count of records managed by the ENSRainbow service. - */ - recordsCount: number; } diff --git a/packages/ensnode-sdk/src/ensrainbow/zod-schemas/config.ts b/packages/ensnode-sdk/src/ensrainbow/zod-schemas/config.ts index 25f208649e..16b72bcf47 100644 --- a/packages/ensnode-sdk/src/ensrainbow/zod-schemas/config.ts +++ b/packages/ensnode-sdk/src/ensrainbow/zod-schemas/config.ts @@ -52,5 +52,4 @@ export const makeEnsRainbowPublicConfigSchema = (valueLabel: string = "EnsRainbo `${valueLabel}.serverLabelSet.highestLabelSetVersion`, ), }), - recordsCount: makeNonNegativeIntegerSchema(`${valueLabel}.recordsCount`), }); diff --git a/packages/ensrainbow-sdk/src/client.test.ts b/packages/ensrainbow-sdk/src/client.test.ts index f8d791bd0d..8a46813c2a 100644 --- a/packages/ensrainbow-sdk/src/client.test.ts +++ b/packages/ensrainbow-sdk/src/client.test.ts @@ -279,7 +279,6 @@ describe("EnsRainbowApiClient", () => { labelSetId: "subgraph", highestLabelSetVersion: 5, }, - recordsCount: 133856894, }; mockFetch.mockResolvedValueOnce({ From 4fa82fbcbb2c021046f49650b8c6fcdb4f8a7553 Mon Sep 17 00:00:00 2001 From: Tomasz Kopacki Date: Fri, 24 Apr 2026 14:07:41 +0200 Subject: [PATCH 15/21] Replace the `version` field on `EnsRainbowPublicConfig` data model with `versionInfo` --- .../src/app/mock/indexing-status-api.mock.ts | 4 +++- .../app/mock/stack-info/stack-info.mock.ts | 16 +++++++++---- .../connection/cards/ensnode-stack-info.tsx | 2 +- apps/ensapi/src/config/config.schema.test.ts | 4 +++- apps/ensapi/src/config/validations.ts | 10 ++++---- .../ensdb-writer-worker.mock.ts | 4 +++- .../public-config-builder.test.ts | 8 +++++-- .../src/commands/server-command.test.ts | 8 +++---- .../src/config/config.schema.test.ts | 8 +++++-- apps/ensrainbow/src/config/public.ts | 7 +++++- .../ensdb-sdk/src/client/ensdb-client.mock.ts | 4 +++- .../src/ensapi/config/conversions.test.ts | 8 +++++-- .../ensnode-sdk/src/ensindexer/client.mock.ts | 4 +++- .../src/ensindexer/config/conversions.test.ts | 8 +++++-- .../src/ensindexer/config/zod-schemas.test.ts | 8 +++++-- .../ensnode-sdk/src/ensnode/client.test.ts | 12 +++++++--- packages/ensnode-sdk/src/ensrainbow/config.ts | 23 +++++++++++++------ .../src/ensrainbow/zod-schemas/config.ts | 7 +++++- .../zod-schemas/ensindexer-stack-info.ts | 2 +- .../zod-schemas/ensnode-stack-info.ts | 8 +++---- packages/ensrainbow-sdk/src/client.test.ts | 4 +++- 21 files changed, 113 insertions(+), 46 deletions(-) diff --git a/apps/ensadmin/src/app/mock/indexing-status-api.mock.ts b/apps/ensadmin/src/app/mock/indexing-status-api.mock.ts index 099f079979..a0e35fd205 100644 --- a/apps/ensadmin/src/app/mock/indexing-status-api.mock.ts +++ b/apps/ensadmin/src/app/mock/indexing-status-api.mock.ts @@ -31,11 +31,13 @@ const serializedEnsIndexerPublicConfig = { indexedChainIds: [1, 8453, 59144, 10, 42161, 534352, 567], ensIndexerSchemaName: "alphaSchema1.9.0", ensRainbowPublicConfig: { - version: "1.9.0", serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0, }, + versionInfo: { + ensRainbow: "1.9.0", + }, }, isSubgraphCompatible: false, namespace: "mainnet", diff --git a/apps/ensadmin/src/app/mock/stack-info/stack-info.mock.ts b/apps/ensadmin/src/app/mock/stack-info/stack-info.mock.ts index 57c474e96a..4a6d1b11c4 100644 --- a/apps/ensadmin/src/app/mock/stack-info/stack-info.mock.ts +++ b/apps/ensadmin/src/app/mock/stack-info/stack-info.mock.ts @@ -33,11 +33,13 @@ const COMMON_CLIENT_LABEL_SET = { } as const; const COMMON_ENSRAINBOW_CONFIG = { - version: "1.9.0", serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0, }, + versionInfo: { + ensRainbow: "1.9.0", + }, } as const; const THE_GRAPH_FALLBACK_DISABLED: TheGraphFallback = { @@ -213,11 +215,13 @@ function createDeserializationErrorVariant(): SerializedEnsNodeStackInfo { ensIndexerSchemaName: "DeserializationSchema1.9.0", isSubgraphCompatible: true, ensRainbowPublicConfig: { - version: "", serverLabelSet: { labelSetId: "", highestLabelSetVersion: -1, }, + versionInfo: { + ensRainbow: "", + }, }, }, }, @@ -239,7 +243,9 @@ function createDeserializationErrorVariant(): SerializedEnsNodeStackInfo { ensIndexerSchemaName: "DeserializationSchema1.9.0", isSubgraphCompatible: true, ensRainbowPublicConfig: { - version: "", + versionInfo: { + ensRainbow: "", + }, serverLabelSet: { labelSetId: "", highestLabelSetVersion: -1, @@ -247,7 +253,9 @@ function createDeserializationErrorVariant(): SerializedEnsNodeStackInfo { }, }, ensRainbow: { - version: "", + versionInfo: { + ensRainbow: "", + }, serverLabelSet: { labelSetId: "", highestLabelSetVersion: -1, diff --git a/apps/ensadmin/src/components/connection/cards/ensnode-stack-info.tsx b/apps/ensadmin/src/components/connection/cards/ensnode-stack-info.tsx index 3845d81212..6f7c3f67a7 100644 --- a/apps/ensadmin/src/components/connection/cards/ensnode-stack-info.tsx +++ b/apps/ensadmin/src/components/connection/cards/ensnode-stack-info.tsx @@ -599,7 +599,7 @@ function EnsNodeStackInfoCardContent({ ensNodeStackInfo }: { ensNodeStackInfo: E icon={} version={

- v{ensRainbowPublicConfig.version} + v{ensRainbowPublicConfig.versionInfo.ensRainbow}

} docsLink={new URL("https://ensnode.io/ensrainbow")} diff --git a/apps/ensapi/src/config/config.schema.test.ts b/apps/ensapi/src/config/config.schema.test.ts index 09780ab00e..4f1e9493c1 100644 --- a/apps/ensapi/src/config/config.schema.test.ts +++ b/apps/ensapi/src/config/config.schema.test.ts @@ -42,8 +42,10 @@ const ENSINDEXER_PUBLIC_CONFIG = { namespace: "mainnet", ensIndexerSchemaName: "ensindexer_0", ensRainbowPublicConfig: { - version: packageJson.version, serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, + versionInfo: { + ensRainbow: packageJson.version, + }, }, indexedChainIds: new Set([1]), isSubgraphCompatible: false, diff --git a/apps/ensapi/src/config/validations.ts b/apps/ensapi/src/config/validations.ts index 7bbdd05852..b091e21085 100644 --- a/apps/ensapi/src/config/validations.ts +++ b/apps/ensapi/src/config/validations.ts @@ -36,12 +36,14 @@ export function invariant_ensIndexerPublicConfigVersionInfo( } // Invariant: ENSApi & ENSRainbow must match version numbers - if (ensIndexerPublicConfig.ensRainbowPublicConfig.version !== packageJson.version) { + if ( + ensIndexerPublicConfig.ensRainbowPublicConfig.versionInfo.ensRainbow !== packageJson.version + ) { ctx.issues.push({ code: "custom", - path: ["ensIndexerPublicConfig.ensRainbowPublicConfig.version"], - input: ensIndexerPublicConfig.ensRainbowPublicConfig.version, - message: `Version Mismatch: ENSRainbow@${ensIndexerPublicConfig.ensRainbowPublicConfig.version} !== ENSApi@${packageJson.version}`, + path: ["ensIndexerPublicConfig.ensRainbowPublicConfig.versionInfo.ensRainbow"], + input: ensIndexerPublicConfig.ensRainbowPublicConfig.versionInfo.ensRainbow, + message: `Version Mismatch: ENSRainbow@${ensIndexerPublicConfig.ensRainbowPublicConfig.versionInfo.ensRainbow} !== ENSApi@${packageJson.version}`, }); } diff --git a/apps/ensindexer/src/lib/ensdb-writer-worker/ensdb-writer-worker.mock.ts b/apps/ensindexer/src/lib/ensdb-writer-worker/ensdb-writer-worker.mock.ts index 187a8fe041..50da45a6ff 100644 --- a/apps/ensindexer/src/lib/ensdb-writer-worker/ensdb-writer-worker.mock.ts +++ b/apps/ensindexer/src/lib/ensdb-writer-worker/ensdb-writer-worker.mock.ts @@ -20,8 +20,10 @@ import type { PublicConfigBuilder } from "@/lib/public-config-builder"; // Test fixture for EnsRainbowPublicConfig export const mockEnsRainbowPublicConfig: EnsRainbowPublicConfig = { - version: "1.0.0", serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, + versionInfo: { + ensRainbow: "1.0.0", + }, }; // Test fixture for EnsIndexerVersionInfo diff --git a/apps/ensindexer/src/lib/public-config-builder/public-config-builder.test.ts b/apps/ensindexer/src/lib/public-config-builder/public-config-builder.test.ts index 45ea4a20b2..c52966478f 100644 --- a/apps/ensindexer/src/lib/public-config-builder/public-config-builder.test.ts +++ b/apps/ensindexer/src/lib/public-config-builder/public-config-builder.test.ts @@ -51,8 +51,10 @@ import { getEnsIndexerVersion, getPackageVersion } from "@/lib/version-info"; // Test fixtures const mockEnsRainbowConfig: EnsRainbowPublicConfig = { - version: "1.0.0", serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, + versionInfo: { + ensRainbow: "1.0.0", + }, }; const mockVersionInfo: EnsIndexerVersionInfo = { @@ -206,8 +208,10 @@ describe("PublicConfigBuilder", () => { }); const customEnsRainbowConfig: EnsRainbowPublicConfig = { - version: "1.0.0", serverLabelSet: { labelSetId: "custom", highestLabelSetVersion: 1 }, + versionInfo: { + ensRainbow: "1.0.0", + }, }; const ensRainbowClientMock = { diff --git a/apps/ensrainbow/src/commands/server-command.test.ts b/apps/ensrainbow/src/commands/server-command.test.ts index d78916a91e..e24b1fb650 100644 --- a/apps/ensrainbow/src/commands/server-command.test.ts +++ b/apps/ensrainbow/src/commands/server-command.test.ts @@ -154,8 +154,8 @@ describe("Server Command Tests", () => { expect(response.status).toBe(200); const data = (await response.json()) as EnsRainbow.ENSRainbowPublicConfig; - expect(typeof data.version).toBe("string"); - expect(data.version.length).toBeGreaterThan(0); + expect(typeof data.versionInfo.ensRainbow).toBe("string"); + expect(data.versionInfo.ensRainbow.length).toBeGreaterThan(0); expect(data.serverLabelSet.labelSetId).toBe("test-label-set-id"); expect(data.serverLabelSet.highestLabelSetVersion).toBe(0); }); @@ -169,8 +169,8 @@ describe("Server Command Tests", () => { expect(response.status).toBe(200); const data = (await response.json()) as EnsRainbow.ENSRainbowPublicConfig; - expect(typeof data.version).toBe("string"); - expect(data.version.length).toBeGreaterThan(0); + expect(typeof data.versionInfo.ensRainbow).toBe("string"); + expect(data.versionInfo.ensRainbow.length).toBeGreaterThan(0); expect(data.serverLabelSet.labelSetId).toBe("test-label-set-id"); expect(data.serverLabelSet.highestLabelSetVersion).toBe(0); }); diff --git a/apps/ensrainbow/src/config/config.schema.test.ts b/apps/ensrainbow/src/config/config.schema.test.ts index a365f58724..6197f2e8a1 100644 --- a/apps/ensrainbow/src/config/config.schema.test.ts +++ b/apps/ensrainbow/src/config/config.schema.test.ts @@ -4,6 +4,8 @@ import { isAbsolute, resolve } from "node:path"; import { describe, expect, it } from "vitest"; +import type { EnsRainbowPublicConfig } from "@ensnode/ensnode-sdk"; + import { DB_SCHEMA_VERSION } from "@/lib/database"; import { @@ -396,8 +398,10 @@ describe("buildEnsRainbowPublicConfig", () => { const result = buildEnsRainbowPublicConfig(dbConfig); expect(result).toStrictEqual({ - version: packageJson.version, serverLabelSet: dbConfig.serverLabelSet, - }); + versionInfo: { + ensRainbow: packageJson.version, + }, + } satisfies EnsRainbowPublicConfig); }); }); diff --git a/apps/ensrainbow/src/config/public.ts b/apps/ensrainbow/src/config/public.ts index 5fb893274d..d6b75ee090 100644 --- a/apps/ensrainbow/src/config/public.ts +++ b/apps/ensrainbow/src/config/public.ts @@ -1,12 +1,17 @@ import packageJson from "@/../package.json" with { type: "json" }; +import type { EnsRainbowVersionInfo } from "@ensnode/ensnode-sdk"; import type { EnsRainbow } from "@ensnode/ensrainbow-sdk"; import type { DbConfig } from "./types"; export function buildEnsRainbowPublicConfig(dbConfig: DbConfig): EnsRainbow.ENSRainbowPublicConfig { + const versionInfo = { + ensRainbow: packageJson.version, + } satisfies EnsRainbowVersionInfo; + return { - version: packageJson.version, serverLabelSet: dbConfig.serverLabelSet, + versionInfo, }; } diff --git a/packages/ensdb-sdk/src/client/ensdb-client.mock.ts b/packages/ensdb-sdk/src/client/ensdb-client.mock.ts index d5262d90d1..d9444acd56 100644 --- a/packages/ensdb-sdk/src/client/ensdb-client.mock.ts +++ b/packages/ensdb-sdk/src/client/ensdb-client.mock.ts @@ -26,11 +26,13 @@ export const ensIndexerSchemaName = "ensindexer_0"; export const publicConfig = { ensIndexerSchemaName, ensRainbowPublicConfig: { - version: "0.32.0", serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0, }, + versionInfo: { + ensRainbow: "0.32.0", + }, }, clientLabelSet: { labelSetId: "subgraph", diff --git a/packages/ensnode-sdk/src/ensapi/config/conversions.test.ts b/packages/ensnode-sdk/src/ensapi/config/conversions.test.ts index 5574b784eb..548294d009 100644 --- a/packages/ensnode-sdk/src/ensapi/config/conversions.test.ts +++ b/packages/ensnode-sdk/src/ensapi/config/conversions.test.ts @@ -21,8 +21,10 @@ const MOCK_ENSAPI_PUBLIC_CONFIG = { namespace: ENSNamespaceIds.Mainnet, ensIndexerSchemaName: "ensindexer_0", ensRainbowPublicConfig: { - version: "0.36.0", serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, + versionInfo: { + ensRainbow: "0.36.0", + }, }, indexedChainIds: new Set([1]), isSubgraphCompatible: false, @@ -57,8 +59,10 @@ describe("ENSApi Config Serialization/Deserialization", () => { namespace: ENSNamespaceIds.Mainnet, ensIndexerSchemaName: "ensindexer_0", ensRainbowPublicConfig: { - version: "0.36.0", serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, + versionInfo: { + ensRainbow: "0.36.0", + }, }, indexedChainIds: [1], isSubgraphCompatible: false, diff --git a/packages/ensnode-sdk/src/ensindexer/client.mock.ts b/packages/ensnode-sdk/src/ensindexer/client.mock.ts index e894a27dc8..fcae370c64 100644 --- a/packages/ensnode-sdk/src/ensindexer/client.mock.ts +++ b/packages/ensnode-sdk/src/ensindexer/client.mock.ts @@ -15,11 +15,13 @@ export const configResponseMock = { indexedChainIds: [1, 8453, 59144, 10, 42161, 534352], ensIndexerSchemaName: "alphaSchema0.31.0", ensRainbowPublicConfig: { - version: "0.31.0", serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0, }, + versionInfo: { + ensRainbow: "0.31.0", + }, }, isSubgraphCompatible: false, namespace: "mainnet", diff --git a/packages/ensnode-sdk/src/ensindexer/config/conversions.test.ts b/packages/ensnode-sdk/src/ensindexer/config/conversions.test.ts index 226f7a9f59..9d8fdda275 100644 --- a/packages/ensnode-sdk/src/ensindexer/config/conversions.test.ts +++ b/packages/ensnode-sdk/src/ensindexer/config/conversions.test.ts @@ -12,8 +12,10 @@ describe("ENSIndexer: Config", () => { const config = { ensIndexerSchemaName: "ensindexer_0", ensRainbowPublicConfig: { - version: "0.32.0", serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, + versionInfo: { + ensRainbow: "0.32.0", + }, }, clientLabelSet: { labelSetId: "subgraph", @@ -53,8 +55,10 @@ describe("ENSIndexer: Config", () => { const correctSerializedConfig = { ensIndexerSchemaName: "ensindexer_0", ensRainbowPublicConfig: { - version: "0.32.0", serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, + versionInfo: { + ensRainbow: "0.32.0", + }, }, clientLabelSet: { labelSetId: "subgraph", diff --git a/packages/ensnode-sdk/src/ensindexer/config/zod-schemas.test.ts b/packages/ensnode-sdk/src/ensindexer/config/zod-schemas.test.ts index ccb0f13216..6af6a116fe 100644 --- a/packages/ensnode-sdk/src/ensindexer/config/zod-schemas.test.ts +++ b/packages/ensnode-sdk/src/ensindexer/config/zod-schemas.test.ts @@ -141,11 +141,13 @@ describe("ENSIndexer: Config", () => { it("validates ENSRainbow label set and version compatibility", () => { const baseConfig = { ensRainbowPublicConfig: { - version: "0.32.0", serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0, }, + versionInfo: { + ensRainbow: "0.32.0", + }, }, indexedChainIds: [1], // Use array for serialized config isSubgraphCompatible: false, // Set to false to bypass isSubgraphCompatible invariant @@ -190,11 +192,13 @@ describe("ENSIndexer: Config", () => { it("can parse full ENSIndexerPublicConfig with label set", () => { const validConfig = { ensRainbowPublicConfig: { - version: "0.32.0", serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0, }, + versionInfo: { + ensRainbow: "0.32.0", + }, }, clientLabelSet: { labelSetId: "subgraph", diff --git a/packages/ensnode-sdk/src/ensnode/client.test.ts b/packages/ensnode-sdk/src/ensnode/client.test.ts index ae74b14318..c10a4ec4d0 100644 --- a/packages/ensnode-sdk/src/ensnode/client.test.ts +++ b/packages/ensnode-sdk/src/ensnode/client.test.ts @@ -71,8 +71,10 @@ const EXAMPLE_ENSAPI_CONFIG_RESPONSE = { }, ensIndexerPublicConfig: { ensRainbowPublicConfig: { - version: "1.9.0", serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, + versionInfo: { + ensRainbow: "1.9.0", + }, }, clientLabelSet: { labelSetId: "subgraph", @@ -107,8 +109,10 @@ const EXAMPLE_ENSDB_PUBLIC_RESPONSE = { const EXAMPLE_ENSINDEXER_PUBLIC_CONFIG = { ensRainbowPublicConfig: { - version: "1.9.0", serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, + versionInfo: { + ensRainbow: "1.9.0", + }, }, clientLabelSet: { labelSetId: "subgraph", @@ -135,8 +139,10 @@ const EXAMPLE_ENSINDEXER_PUBLIC_CONFIG = { } satisfies SerializedEnsIndexerPublicConfig; const EXAMPLE_ENSRAINBOW_PUBLIC_CONFIG = { - version: "1.9.0", serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 0 }, + versionInfo: { + ensRainbow: "1.9.0", + }, } satisfies SerializedEnsRainbowPublicConfig; const serializedStackInfo = { diff --git a/packages/ensnode-sdk/src/ensrainbow/config.ts b/packages/ensnode-sdk/src/ensrainbow/config.ts index 748b296d6b..e271a0dd82 100644 --- a/packages/ensnode-sdk/src/ensrainbow/config.ts +++ b/packages/ensnode-sdk/src/ensrainbow/config.ts @@ -1,21 +1,30 @@ import type { EnsRainbowServerLabelSet } from "./types"; /** - * Complete public configuration object for ENSRainbow. - * - * Contains all public configuration information about the ENSRainbow service instance, - * including version, label set information, and record counts. + * Version info about ENSRainbow and its dependencies. */ -export interface EnsRainbowPublicConfig { +export interface EnsRainbowVersionInfo { /** * ENSRainbow service version * * @see https://ghcr.io/namehash/ensnode/ensrainbow - */ - version: string; + **/ + ensRainbow: string; +} +/** + * Complete public configuration object for ENSRainbow. + * + * Contains all public configuration information about the ENSRainbow service instance. + */ +export interface EnsRainbowPublicConfig { /** * The label set reference managed by the ENSRainbow server. */ serverLabelSet: EnsRainbowServerLabelSet; + + /** + * ENSRainbow version info + */ + versionInfo: EnsRainbowVersionInfo; } diff --git a/packages/ensnode-sdk/src/ensrainbow/zod-schemas/config.ts b/packages/ensnode-sdk/src/ensrainbow/zod-schemas/config.ts index 16b72bcf47..c49a2e26b2 100644 --- a/packages/ensnode-sdk/src/ensrainbow/zod-schemas/config.ts +++ b/packages/ensnode-sdk/src/ensrainbow/zod-schemas/config.ts @@ -45,11 +45,16 @@ export const makeLabelSetVersionStringSchema = (valueLabel: string = "Label set */ export const makeEnsRainbowPublicConfigSchema = (valueLabel: string = "EnsRainbowPublicConfig") => z.object({ - version: z.string().nonempty({ error: `${valueLabel}.version must be a non-empty string.` }), serverLabelSet: z.object({ labelSetId: makeLabelSetIdSchema(`${valueLabel}.serverLabelSet.labelSetId`), highestLabelSetVersion: makeLabelSetVersionSchema( `${valueLabel}.serverLabelSet.highestLabelSetVersion`, ), }), + + versionInfo: z.object({ + ensRainbow: z + .string() + .nonempty({ error: `${valueLabel}.versionInfo.ensRainbow must be a non-empty string.` }), + }), }); diff --git a/packages/ensnode-sdk/src/stack-info/zod-schemas/ensindexer-stack-info.ts b/packages/ensnode-sdk/src/stack-info/zod-schemas/ensindexer-stack-info.ts index 7e1e6abc2b..185981932b 100644 --- a/packages/ensnode-sdk/src/stack-info/zod-schemas/ensindexer-stack-info.ts +++ b/packages/ensnode-sdk/src/stack-info/zod-schemas/ensindexer-stack-info.ts @@ -30,7 +30,7 @@ export function invariant_ensRainbowCompatibilityWithEnsIndexer( ctx.issues.push({ code: "custom", input: ctx.value, - message: `ENSRainbow's label set (id: ${serverLabelSet.labelSetId}) must be the same as the ENSIndexer's label set (id: ${clientLabelSet.labelSetId}).`, + message: `ENSRainbow's label set (id: ${serverLabelSet.labelSetId}) must be the same as ENSIndexer's label set (id: ${clientLabelSet.labelSetId}).`, }); } diff --git a/packages/ensnode-sdk/src/stack-info/zod-schemas/ensnode-stack-info.ts b/packages/ensnode-sdk/src/stack-info/zod-schemas/ensnode-stack-info.ts index adc9a64a26..4a04ddd43f 100644 --- a/packages/ensnode-sdk/src/stack-info/zod-schemas/ensnode-stack-info.ts +++ b/packages/ensnode-sdk/src/stack-info/zod-schemas/ensnode-stack-info.ts @@ -36,12 +36,12 @@ function invariant_ensApiCompatibilityWithEnsIndexerAndEnsRainbow( } // Invariant: ENSApi & ENSRainbow must match version numbers - if (ensRainbow.version !== ensApi.versionInfo.ensApi) { + if (ensRainbow.versionInfo.ensRainbow !== ensApi.versionInfo.ensApi) { ctx.issues.push({ code: "custom", - path: ["ensRainbow.version"], - input: ensRainbow.version, - message: `Version Mismatch: ENSRainbow@${ensRainbow.version} !== ENSApi@${ensApi.versionInfo.ensApi}`, + path: ["ensRainbow.versionInfo.ensRainbow"], + input: ensRainbow.versionInfo.ensRainbow, + message: `Version Mismatch: ENSRainbow@${ensRainbow.versionInfo.ensRainbow} !== ENSApi@${ensApi.versionInfo.ensApi}`, }); } diff --git a/packages/ensrainbow-sdk/src/client.test.ts b/packages/ensrainbow-sdk/src/client.test.ts index 8a46813c2a..c2312ae911 100644 --- a/packages/ensrainbow-sdk/src/client.test.ts +++ b/packages/ensrainbow-sdk/src/client.test.ts @@ -274,11 +274,13 @@ describe("EnsRainbowApiClient", () => { describe("config", () => { it("should request /v1/config and return public config on success", async () => { const configData: EnsRainbow.ENSRainbowPublicConfig = { - version: "2.0.0", serverLabelSet: { labelSetId: "subgraph", highestLabelSetVersion: 5, }, + versionInfo: { + ensRainbow: "2.0.0", + }, }; mockFetch.mockResolvedValueOnce({ From e376718b11dfa1bdffc6aad587b5a72eea4a8681 Mon Sep 17 00:00:00 2001 From: Tomasz Kopacki Date: Fri, 24 Apr 2026 14:10:58 +0200 Subject: [PATCH 16/21] Update OpenAPI Spec --- docs/ensnode.io/ensapi-openapi.json | 77 +++++++++++-------- .../src/ensdb/zod-schemas/config.ts | 22 +++--- 2 files changed, 53 insertions(+), 46 deletions(-) diff --git a/docs/ensnode.io/ensapi-openapi.json b/docs/ensnode.io/ensapi-openapi.json index 64887e3414..487ad34b48 100644 --- a/docs/ensnode.io/ensapi-openapi.json +++ b/docs/ensnode.io/ensapi-openapi.json @@ -782,6 +782,23 @@ "stackInfo": { "type": "object", "properties": { + "ensDb": { + "type": "object", + "properties": { + "versionInfo": { + "type": "object", + "properties": { + "postgresql": { + "type": "string", + "minLength": 1, + "description": "Version of the PostgreSQL server hosting the ENSDb instance." + } + }, + "required": ["postgresql"] + } + }, + "required": ["versionInfo"] + }, "ensIndexer": { "type": "object", "properties": { @@ -789,8 +806,7 @@ "ensRainbowPublicConfig": { "type": "object", "properties": { - "version": { "type": "string", "minLength": 1 }, - "labelSet": { + "serverLabelSet": { "type": "object", "properties": { "labelSetId": { @@ -803,9 +819,15 @@ }, "required": ["labelSetId", "highestLabelSetVersion"] }, - "recordsCount": { "type": "integer", "minimum": 0 } + "versionInfo": { + "type": "object", + "properties": { + "ensRainbow": { "type": "string", "minLength": 1 } + }, + "required": ["ensRainbow"] + } }, - "required": ["version", "labelSet", "recordsCount"] + "required": ["serverLabelSet", "versionInfo"] }, "indexedChainIds": { "type": "array", @@ -813,7 +835,7 @@ "minItems": 1 }, "isSubgraphCompatible": { "type": "boolean" }, - "labelSet": { + "clientLabelSet": { "type": "object", "properties": { "labelSetId": { @@ -851,7 +873,7 @@ "ensRainbowPublicConfig", "indexedChainIds", "isSubgraphCompatible", - "labelSet", + "clientLabelSet", "namespace", "plugins", "versionInfo" @@ -860,8 +882,7 @@ "ensRainbow": { "type": "object", "properties": { - "version": { "type": "string", "minLength": 1 }, - "labelSet": { + "serverLabelSet": { "type": "object", "properties": { "labelSetId": { @@ -874,28 +895,13 @@ }, "required": ["labelSetId", "highestLabelSetVersion"] }, - "recordsCount": { "type": "integer", "minimum": 0 } - }, - "required": ["version", "labelSet", "recordsCount"] - }, - "ensDb": { - "type": "object", - "properties": { "versionInfo": { "type": "object", - "properties": { - "postgresql": { - "type": "string", - "minLength": 1, - "description": "Version of the PostgreSQL server hosting the ENSDb instance." - } - }, - "required": ["postgresql"], - "description": "Serialized Indexing Status Response OK.ensDb.versionInfo" + "properties": { "ensRainbow": { "type": "string", "minLength": 1 } }, + "required": ["ensRainbow"] } }, - "required": ["versionInfo"], - "description": "Serialized Indexing Status Response OK.ensDb" + "required": ["serverLabelSet", "versionInfo"] }, "ensApi": { "type": "object", @@ -907,8 +913,7 @@ "ensRainbowPublicConfig": { "type": "object", "properties": { - "version": { "type": "string", "minLength": 1 }, - "labelSet": { + "serverLabelSet": { "type": "object", "properties": { "labelSetId": { @@ -924,9 +929,15 @@ }, "required": ["labelSetId", "highestLabelSetVersion"] }, - "recordsCount": { "type": "integer", "minimum": 0 } + "versionInfo": { + "type": "object", + "properties": { + "ensRainbow": { "type": "string", "minLength": 1 } + }, + "required": ["ensRainbow"] + } }, - "required": ["version", "labelSet", "recordsCount"] + "required": ["serverLabelSet", "versionInfo"] }, "indexedChainIds": { "type": "array", @@ -934,7 +945,7 @@ "minItems": 1 }, "isSubgraphCompatible": { "type": "boolean" }, - "labelSet": { + "clientLabelSet": { "type": "object", "properties": { "labelSetId": { @@ -972,7 +983,7 @@ "ensRainbowPublicConfig", "indexedChainIds", "isSubgraphCompatible", - "labelSet", + "clientLabelSet", "namespace", "plugins", "versionInfo" @@ -1019,7 +1030,7 @@ "required": ["ensIndexerPublicConfig", "theGraphFallback", "versionInfo"] } }, - "required": ["ensIndexer", "ensRainbow", "ensDb", "ensApi"] + "required": ["ensDb", "ensIndexer", "ensRainbow", "ensApi"] } }, "required": ["responseCode", "realtimeProjection", "stackInfo"] diff --git a/packages/ensnode-sdk/src/ensdb/zod-schemas/config.ts b/packages/ensnode-sdk/src/ensdb/zod-schemas/config.ts index 1d9db9ed3b..3de6ede62c 100644 --- a/packages/ensnode-sdk/src/ensdb/zod-schemas/config.ts +++ b/packages/ensnode-sdk/src/ensdb/zod-schemas/config.ts @@ -3,22 +3,18 @@ import { z } from "zod/v4"; const makeEnsDbVersionInfoSchema = (valueLabel?: string) => { const label = valueLabel ?? "EnsDbVersionInfo"; - return z - .object({ - postgresql: z - .string() - .nonempty(`${label}.postgresql must be a non-empty string`) - .describe("Version of the PostgreSQL server hosting the ENSDb instance."), - }) - .describe(label); + return z.object({ + postgresql: z + .string() + .nonempty(`${label}.postgresql must be a non-empty string`) + .describe("Version of the PostgreSQL server hosting the ENSDb instance."), + }); }; export const makeEnsDbPublicConfigSchema = (valueLabel?: string) => { const label = valueLabel ?? "EnsDbPublicConfig"; - return z - .object({ - versionInfo: makeEnsDbVersionInfoSchema(`${label}.versionInfo`), - }) - .describe(label); + return z.object({ + versionInfo: makeEnsDbVersionInfoSchema(`${label}.versionInfo`), + }); }; From 73a15bc1edd94aa8a094ae1d5fe3e5833f26fc34 Mon Sep 17 00:00:00 2001 From: Tomasz Kopacki Date: Fri, 24 Apr 2026 14:12:39 +0200 Subject: [PATCH 17/21] Update changeset files --- .changeset/fifty-games-smash.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/fifty-games-smash.md b/.changeset/fifty-games-smash.md index c0e8ec97c4..472f0e246b 100644 --- a/.changeset/fifty-games-smash.md +++ b/.changeset/fifty-games-smash.md @@ -2,4 +2,4 @@ "@ensnode/ensnode-sdk": minor --- -Introduced a set of "stack info" data models: `EnsIndexerStackInfo`, `EnsDbStackInfo`, `EnsNodeStackInfo`. +Introduced a set of "stack info" data models: `EnsIndexerStackInfo`, `EnsNodeStackInfo`. From 35c60ac60645a16a4c31eda792248f245b726d96 Mon Sep 17 00:00:00 2001 From: Tomasz Kopacki Date: Fri, 24 Apr 2026 14:21:52 +0200 Subject: [PATCH 18/21] docs(changeset): **Breaking**: Updated core ENSNode data models. --- .changeset/all-kids-smash.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/all-kids-smash.md diff --git a/.changeset/all-kids-smash.md b/.changeset/all-kids-smash.md new file mode 100644 index 0000000000..92f489ebb3 --- /dev/null +++ b/.changeset/all-kids-smash.md @@ -0,0 +1,6 @@ +--- +"@ensnode/ensrainbow-sdk": minor +"@ensnode/ensnode-sdk": minor +--- + +**Breaking**: Updated core ENSNode data models. From d96021d8f706280222487d183061a1ee49c797b6 Mon Sep 17 00:00:00 2001 From: Tomasz Kopacki Date: Fri, 24 Apr 2026 14:24:11 +0200 Subject: [PATCH 19/21] docs(changeset): Removed _Records Count_ info from the ENSRainbow card UI on the _Connection_ page. --- .changeset/calm-ravens-feel.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/calm-ravens-feel.md diff --git a/.changeset/calm-ravens-feel.md b/.changeset/calm-ravens-feel.md new file mode 100644 index 0000000000..643262d81b --- /dev/null +++ b/.changeset/calm-ravens-feel.md @@ -0,0 +1,5 @@ +--- +"ensadmin": minor +--- + +Removed _Records Count_ info from the ENSRainbow card UI on the _Connection_ page. From 0cce2c36d6ebddd21790c8ffa55aadc2ca6bbfe3 Mon Sep 17 00:00:00 2001 From: Tomasz Kopacki Date: Fri, 24 Apr 2026 14:36:29 +0200 Subject: [PATCH 20/21] Apply AI PR feedback --- .changeset/all-kids-smash.md | 9 +++++++++ apps/ensadmin/src/app/mock/indexing-status-api.mock.ts | 2 +- apps/ensadmin/src/app/mock/stack-info/page.tsx | 4 ++-- .../components/connection/cards/ensnode-stack-info.tsx | 8 ++++---- apps/ensindexer/src/config/types.ts | 2 +- .../src/ponder/indexing-behavior-injection-contract.ts | 2 +- apps/ensrainbow/src/commands/server-command.test.ts | 2 +- .../docs/ensrainbow/concepts/typescript-interfaces.mdx | 10 +++++----- .../src/ensindexer/config/compatibility.test.ts | 2 +- packages/ensnode-sdk/src/ensindexer/config/types.ts | 2 +- .../src/stack-info/zod-schemas/ensnode-stack-info.ts | 8 ++++---- 11 files changed, 30 insertions(+), 21 deletions(-) diff --git a/.changeset/all-kids-smash.md b/.changeset/all-kids-smash.md index 92f489ebb3..98827bd74d 100644 --- a/.changeset/all-kids-smash.md +++ b/.changeset/all-kids-smash.md @@ -4,3 +4,12 @@ --- **Breaking**: Updated core ENSNode data models. + +- `EnsIndexerPublicConfig` + - Renamed `labelSet` field to `clientLabelSet`. +- `EnsRainbowApiClientOptions` + - Renamed `labelSet` field to `clientLabelSet`. +- `EnsRainbowPublicConfig` + - Replaced `version: string` field with `versionInfo: EnsRainbowVersionInfo`. + - Renamed `labelSet` field to `serverLabelSet`. + - Removed `recordsCount` field from `EnsRainbowPublicConfig`. diff --git a/apps/ensadmin/src/app/mock/indexing-status-api.mock.ts b/apps/ensadmin/src/app/mock/indexing-status-api.mock.ts index a0e35fd205..13de3f219d 100644 --- a/apps/ensadmin/src/app/mock/indexing-status-api.mock.ts +++ b/apps/ensadmin/src/app/mock/indexing-status-api.mock.ts @@ -16,7 +16,7 @@ import { type SerializedEnsDbPublicConfig, type SerializedEnsIndexerPublicConfig, type SerializedEnsNodeStackInfo, - SerializedEnsRainbowPublicConfig, + type SerializedEnsRainbowPublicConfig, type SerializedOmnichainIndexingStatusSnapshotBackfill, type SerializedOmnichainIndexingStatusSnapshotCompleted, type SerializedOmnichainIndexingStatusSnapshotFollowing, diff --git a/apps/ensadmin/src/app/mock/stack-info/page.tsx b/apps/ensadmin/src/app/mock/stack-info/page.tsx index de8c02b610..87027b62f5 100644 --- a/apps/ensadmin/src/app/mock/stack-info/page.tsx +++ b/apps/ensadmin/src/app/mock/stack-info/page.tsx @@ -16,8 +16,8 @@ import { mockSerializedEnsNodeStackInfo } from "./stack-info.mock"; type LoadingVariant = "Loading" | "Loading Error"; type Variants = keyof typeof mockSerializedEnsNodeStackInfo | LoadingVariant; -const DEFAULT_VARIANT = "Alpha Mainnet"; -export default function MockConfigPage() { +const DEFAULT_VARIANT: Variants = "Alpha Mainnet"; +export default function MockEnsNodeStackInfoPage() { const [selectedConfig, setSelectedConfig] = useState(DEFAULT_VARIANT); const props: DisplayEnsNodeStackInfoProps = useMemo(() => { switch (selectedConfig) { diff --git a/apps/ensadmin/src/components/connection/cards/ensnode-stack-info.tsx b/apps/ensadmin/src/components/connection/cards/ensnode-stack-info.tsx index 6f7c3f67a7..d0b9f4bf2b 100644 --- a/apps/ensadmin/src/components/connection/cards/ensnode-stack-info.tsx +++ b/apps/ensadmin/src/components/connection/cards/ensnode-stack-info.tsx @@ -577,9 +577,9 @@ function EnsNodeStackInfoCardContent({ ensNodeStackInfo }: { ensNodeStackInfo: E } additionalInfo={

- The "fully pinned" labelset id and version used for deterministic healing of unknown - labels across time. The label set version may be equal to or less than the highest - label set version offered by the connected ENSRainbow server.{" "} + The "fully pinned" label set id and version used for deterministic healing of + unknown labels across time. The label set version may be equal to or less than the + highest label set version offered by the connected ENSRainbow server.{" "} @@ -615,7 +615,7 @@ function EnsNodeStackInfoCardContent({ ensNodeStackInfo }: { ensNodeStackInfo: E } additionalInfo={

- The labelset id and highest labelset version offered by the ENSRainbow server.{" "} + The label set id and highest label set version offered by the ENSRainbow server.{" "} diff --git a/apps/ensindexer/src/config/types.ts b/apps/ensindexer/src/config/types.ts index 2518d43069..c41b68b951 100644 --- a/apps/ensindexer/src/config/types.ts +++ b/apps/ensindexer/src/config/types.ts @@ -150,7 +150,7 @@ export interface EnsIndexerConfig { * * If {@link isSubgraphCompatible} is true, the following invariants are true for the ENSIndexerConfig: * 1. only the 'subgraph' plugin is enabled, and - * 2. the labelSet must be { labelSetId: 'subgraph', labelSetVersion: 0 } + * 2. the {@link clientLabelSet} must be { labelSetId: 'subgraph', labelSetVersion: 0 } * * If {@link isSubgraphCompatible} is false, ENSIndexer will additionally: * diff --git a/apps/ensindexer/src/ponder/indexing-behavior-injection-contract.ts b/apps/ensindexer/src/ponder/indexing-behavior-injection-contract.ts index f738d34a76..17c9e95316 100644 --- a/apps/ensindexer/src/ponder/indexing-behavior-injection-contract.ts +++ b/apps/ensindexer/src/ponder/indexing-behavior-injection-contract.ts @@ -49,7 +49,7 @@ interface IndexingBehaviorDependencies { /** * Label Set for ENSIndexer client requests to ENSRainbow * - * When `labelSet` changes, the label "healing" results may change during indexing, + * When `clientLabelSet` changes, the label "healing" results may change during indexing, * which influences the indexing behavior. */ clientLabelSet: EnsIndexerConfig["clientLabelSet"]; diff --git a/apps/ensrainbow/src/commands/server-command.test.ts b/apps/ensrainbow/src/commands/server-command.test.ts index e24b1fb650..82b93931e0 100644 --- a/apps/ensrainbow/src/commands/server-command.test.ts +++ b/apps/ensrainbow/src/commands/server-command.test.ts @@ -129,7 +129,7 @@ describe("Server Command Tests", () => { }); describe("GET /v1/labels/count", () => { - it("should return count snapshot from startup (same as /v1/config)", async () => { + it("should return count snapshot from startup (from dbConfig.recordsCount)", async () => { // Count is fixed at server start; changing the DB does not affect the response await db.setPrecalculatedRainbowRecordCount(42); diff --git a/docs/ensnode.io/src/content/docs/ensrainbow/concepts/typescript-interfaces.mdx b/docs/ensnode.io/src/content/docs/ensrainbow/concepts/typescript-interfaces.mdx index 76d5a59bb0..1659127367 100644 --- a/docs/ensnode.io/src/content/docs/ensrainbow/concepts/typescript-interfaces.mdx +++ b/docs/ensnode.io/src/content/docs/ensrainbow/concepts/typescript-interfaces.mdx @@ -31,7 +31,7 @@ interface EnsRainbowServerLabelSet { ### `EnsRainbowClientLabelSet` -Provided when constructing `new EnsRainbowApiClient({ labelSet: … })` to pin client expectations: +Provided when constructing `new EnsRainbowApiClient({ clientLabelSet: … })` to pin client expectations: ```ts interface EnsRainbowClientLabelSet { @@ -42,11 +42,11 @@ interface EnsRainbowClientLabelSet { #### Usage Guidelines -1. **Neither field** → accept any client labelset and use the latest version (default behaviour). -2. **Only `labelSetId`** → insist on a specific client labelset and use the latest version. -3. **Both fields** → insist on a specific client labelset and version, locking the client to an exact snapshot. +1. **Neither field** → accept any client label set and use the latest version (default behaviour). +2. **Only `labelSetId`** → insist on a specific client label set and use the latest version. +3. **Both fields** → insist on a specific client label set and version, locking the client to an exact snapshot. -This handshake that occurs when **both fields** are set ensures both client and server interpret every heal operation against the **same logical labelset snapshot**, enabling deterministic and reproducible healing results across time. +This handshake that occurs when **both fields** are set ensures both client and server interpret every heal operation against the **same logical label set snapshot**, enabling deterministic and reproducible healing results across time. ## Example Usage diff --git a/packages/ensnode-sdk/src/ensindexer/config/compatibility.test.ts b/packages/ensnode-sdk/src/ensindexer/config/compatibility.test.ts index 9a9e24b55a..341a426e5f 100644 --- a/packages/ensnode-sdk/src/ensindexer/config/compatibility.test.ts +++ b/packages/ensnode-sdk/src/ensindexer/config/compatibility.test.ts @@ -67,7 +67,7 @@ describe("EnsIndexerConfig compatibility", () => { ); }); - it("throws error when 'configA.labelSet.labelSetId' is not same as 'configB.labelSet.labelSetId'", () => { + it("throws error when 'configA.clientLabelSet.labelSetId' is not same as 'configB.clientLabelSet.labelSetId'", () => { const configA = structuredClone(config); const configB = { diff --git a/packages/ensnode-sdk/src/ensindexer/config/types.ts b/packages/ensnode-sdk/src/ensindexer/config/types.ts index 8851a0a478..e6779a98fd 100644 --- a/packages/ensnode-sdk/src/ensindexer/config/types.ts +++ b/packages/ensnode-sdk/src/ensindexer/config/types.ts @@ -127,7 +127,7 @@ export interface EnsIndexerPublicConfig { * * If {@link isSubgraphCompatible} is true, the following invariants are true for the ENSIndexerConfig: * 1. only the 'subgraph' plugin is enabled, and - * 2. the labelSet must be { labelSetId: 'subgraph', labelSetVersion: 0 } + * 2. the {@link clientLabelSet} must be { labelSetId: 'subgraph', labelSetVersion: 0 } * * If {@link isSubgraphCompatible} is false, ENSIndexer will additionally: * diff --git a/packages/ensnode-sdk/src/stack-info/zod-schemas/ensnode-stack-info.ts b/packages/ensnode-sdk/src/stack-info/zod-schemas/ensnode-stack-info.ts index 4a04ddd43f..f8a1bece01 100644 --- a/packages/ensnode-sdk/src/stack-info/zod-schemas/ensnode-stack-info.ts +++ b/packages/ensnode-sdk/src/stack-info/zod-schemas/ensnode-stack-info.ts @@ -19,7 +19,7 @@ function invariant_ensApiCompatibilityWithEnsIndexerAndEnsRainbow( if (ensIndexer.versionInfo.ensDb !== ensApi.versionInfo.ensApi) { ctx.issues.push({ code: "custom", - path: ["ensIndexer.versionInfo.ensDb"], + path: ["ensIndexer", "versionInfo", "ensDb"], input: ensIndexer.versionInfo.ensDb, message: `Version Mismatch: ENSDB@${ensIndexer.versionInfo.ensDb} !== ENSApi@${ensApi.versionInfo.ensApi}`, }); @@ -29,7 +29,7 @@ function invariant_ensApiCompatibilityWithEnsIndexerAndEnsRainbow( if (ensIndexer.versionInfo.ensIndexer !== ensApi.versionInfo.ensApi) { ctx.issues.push({ code: "custom", - path: ["ensIndexer.versionInfo.ensIndexer"], + path: ["ensIndexer", "versionInfo", "ensIndexer"], input: ensIndexer.versionInfo.ensIndexer, message: `Version Mismatch: ENSIndexer@${ensIndexer.versionInfo.ensIndexer} !== ENSApi@${ensApi.versionInfo.ensApi}`, }); @@ -39,7 +39,7 @@ function invariant_ensApiCompatibilityWithEnsIndexerAndEnsRainbow( if (ensRainbow.versionInfo.ensRainbow !== ensApi.versionInfo.ensApi) { ctx.issues.push({ code: "custom", - path: ["ensRainbow.versionInfo.ensRainbow"], + path: ["ensRainbow", "versionInfo", "ensRainbow"], input: ensRainbow.versionInfo.ensRainbow, message: `Version Mismatch: ENSRainbow@${ensRainbow.versionInfo.ensRainbow} !== ENSApi@${ensApi.versionInfo.ensApi}`, }); @@ -49,7 +49,7 @@ function invariant_ensApiCompatibilityWithEnsIndexerAndEnsRainbow( if (ensIndexer.versionInfo.ensNormalize !== ensApi.versionInfo.ensNormalize) { ctx.issues.push({ code: "custom", - path: ["ensIndexer.versionInfo.ensNormalize"], + path: ["ensIndexer", "versionInfo", "ensNormalize"], input: ensIndexer.versionInfo.ensNormalize, message: `Dependency Version Mismatch: '@adraffy/ens-normalize' version must be the same between ENSIndexer and ENSApi. Found ENSApi@${ensApi.versionInfo.ensNormalize} and ENSIndexer@${ensIndexer.versionInfo.ensNormalize}`, }); From 7c11fc3dbf6a8528b81208aabcd1c2a557aadaa6 Mon Sep 17 00:00:00 2001 From: Tomasz Kopacki Date: Fri, 24 Apr 2026 14:44:08 +0200 Subject: [PATCH 21/21] Apply AI PR feedback --- .../docs/ensrainbow/concepts/typescript-interfaces.mdx | 6 +++--- .../src/content/docs/ensrainbow/usage/client-sdk.mdx | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/ensnode.io/src/content/docs/ensrainbow/concepts/typescript-interfaces.mdx b/docs/ensnode.io/src/content/docs/ensrainbow/concepts/typescript-interfaces.mdx index 1659127367..420982184e 100644 --- a/docs/ensnode.io/src/content/docs/ensrainbow/concepts/typescript-interfaces.mdx +++ b/docs/ensnode.io/src/content/docs/ensrainbow/concepts/typescript-interfaces.mdx @@ -57,18 +57,18 @@ import { EnsRainbowApiClient } from '@ensnode/ensrainbow-sdk'; // Default: use latest version of any labelset const client1 = new EnsRainbowApiClient({ - baseUrl: 'https://api.ensrainbow.io' + endpointUrl: 'https://api.ensrainbow.io' }); // Pin to subgraph labelset, use latest version const client2 = new EnsRainbowApiClient({ - baseUrl: 'https://api.ensrainbow.io', + endpointUrl: 'https://api.ensrainbow.io', clientLabelSet: { labelSetId: 'subgraph' } }); // Pin to exact labelset snapshot for deterministic results across time const client3 = new EnsRainbowApiClient({ - baseUrl: 'https://api.ensrainbow.io', + endpointUrl: 'https://api.ensrainbow.io', clientLabelSet: { labelSetId: 'subgraph', labelSetVersion: 0 diff --git a/docs/ensnode.io/src/content/docs/ensrainbow/usage/client-sdk.mdx b/docs/ensnode.io/src/content/docs/ensrainbow/usage/client-sdk.mdx index 250bb887de..2729f4a8f0 100644 --- a/docs/ensnode.io/src/content/docs/ensrainbow/usage/client-sdk.mdx +++ b/docs/ensnode.io/src/content/docs/ensrainbow/usage/client-sdk.mdx @@ -29,7 +29,7 @@ pnpm add @ensnode/ensrainbow-sdk import { EnsRainbowApiClient } from '@ensnode/ensrainbow-sdk'; const client = new EnsRainbowApiClient({ - baseUrl: 'https://api.ensrainbow.io', + endpointUrl: 'https://api.ensrainbow.io', clientLabelSet: { labelSetId: 'subgraph', labelSetVersion: 0 } });