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 000000000..3bfe398d9 --- /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 000000000..da22b2ff1 --- /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 40ee912e5..7e130dfa9 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 000000000..e29ad7a90 --- /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 000000000..b3d2ac95c --- /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 94f39d195..d8847d356 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 f3bf01419..b439a614a 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 000000000..34f2546b5 --- /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 000000000..8dbca6580 --- /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 1c1f2f263..559ed8729 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 000000000..47a1fdcd4 --- /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 000000000..e654bd5c9 --- /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 094a17d07..a1e2e4c57 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 ebbfc8937..27eae6201 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 c339d9615..da1364294 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 47baa1022..80776d4c7 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 0d58bde06..af79e327e 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 7bc864bf6..3a94a38b5 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 000000000..c0e8ec97c --- /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 000000000..19b91950c --- /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 d23e7a9ce..a3e5b7dcf 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 d8847d356..9c8d37435 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 47a1fdcd4..7cc8edbc8 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 e654bd5c9..fda997302 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 a1e2e4c57..ebf513016 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 596649532..de8c02b61 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 da1364294..3a1e7b835 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 2e27b8e27..64887e341 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 3bfe398d9..000000000 --- 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 7e130dfa9..d0c3d541d 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 e29ad7a90..000000000 --- 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 b3d2ac95c..503977684 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 9c8d37435..3d16287c5 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 b439a614a..f12f41425 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 34f2546b5..000000000 --- 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 8dbca6580..47e39ac2d 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 559ed8729..3852fef5d 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 000000000..46396745a --- /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 000000000..1c2421126 --- /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 7cc8edbc8..000000000 --- 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 fda997302..3e1b382cc 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 ebf513016..adc9a64a2 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 3a1e7b835..833ca9ccd 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 503977684..482dfad3e 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 3e1b382cc..bbbfed17d 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 b23533fbc..d5e0fd596 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 833ca9ccd..3c10b69cd 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 80776d4c7..a4543fec0 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 30929794b..f638805c7 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 f5b10fb14..9ac9c6d4b 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 5e4239cde..a419ad1b3 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 40a21dfbb..3c6208b3f 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 47a02de67..0f888277b 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 509668379..563970289 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 1d6748910..167b4d572 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 924e062ca..2518d4306 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 c4d5d4842..ccba1cee8 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 c6785560c..331d62e6a 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 56b396976..8dcaf969a 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 a34a8465f..7229af036 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 311f3a2ae..f738d34a7 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 e998b5047..76d5a59bb 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 6e0b4623a..250bb887d 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 926d2ca4f..d3a1a646b 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 7f4bf6afa..cae5dc2b7 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 3bfd76b3c..86e7f4355 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 c7da25c5b..9a9e24b55 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 b38f3769c..dfd6ecaa3 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 4dd5c0549..35a9fba52 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 632029924..44a1623b8 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 b1587c7dc..ab859f548 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 da3238744..7f7a3fc6a 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 0476e7d37..8851a0a47 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 fcc9adab7..a65888f7d 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 68f32f998..0a7e6ca16 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 a3e5b7dcf..98c42ebf2 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 da22b2ff1..aa1d146f7 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 bbbfed17d..2447541a1 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 16b57ca5e..f8d791bd0 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 f6511d5d0..3144a35b6 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 d5e0fd596..b8584cfd4 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 3c10b69cd..33c30c6a2 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 a4543fec0..1279719d3 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 9ac9c6d4b..1b050b002 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 ccba1cee8..0904b430e 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 8dcaf969a..6455dd618 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 50f9bc26c..a7557a1fd 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 5b80d4982..e09efe944 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 906a361e6..72b7cb2a3 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 eb5d82254..1301dc77c 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 3452a869f..8d4b9ea0f 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 b3da287c5..6892869e7 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 d3a1a646b..486ec9b0f 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 cae5dc2b7..e87fc9445 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 86e7f4355..29d33fbaa 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 35a9fba52..72c322808 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 a65888f7d..4705fa1e5 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 0a7e6ca16..a4d4d4760 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 98c42ebf2..e7b70d6cf 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 d5f141c59..cdf17e983 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 b8aff5a51..25f208649 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 2447541a1..7e1e6abc2 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 b8584cfd4..099f07997 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 33c30c6a2..57c474e96 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 1279719d3..3845d8121 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 1b050b002..09780ab00 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 0904b430e..187a8fe04 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 6455dd618..45ea4a20b 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 a7557a1fd..d78916a91 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 1288c9b46..f5c940044 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 72b7cb2a3..5fb893274 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 dd754a3ce..ca590d055 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 486ec9b0f..d5262d90d 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 e87fc9445..5574b784e 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 29d33fbaa..e894a27dc 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 72c322808..226f7a9f5 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 4705fa1e5..ccb0f1321 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 e7b70d6cf..ae74b1431 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 cdf17e983..748b296d6 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 25f208649..16b72bcf4 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 f8d791bd0..8a46813c2 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 099f07997..a0e35fd20 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 57c474e96..4a6d1b11c 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 3845d8121..6f7c3f67a 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 09780ab00..4f1e9493c 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 7bbdd0585..b091e2108 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 187a8fe04..50da45a6f 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 45ea4a20b..c52966478 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 d78916a91..e24b1fb65 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 a365f5872..6197f2e8a 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 5fb893274..d6b75ee09 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 d5262d90d..d9444acd5 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 5574b784e..548294d00 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 e894a27dc..fcae370c6 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 226f7a9f5..9d8fdda27 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 ccb0f1321..6af6a116f 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 ae74b1431..c10a4ec4d 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 748b296d6..e271a0dd8 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 16b72bcf4..c49a2e26b 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 7e1e6abc2..185981932 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 adc9a64a2..4a04ddd43 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 8a46813c2..c2312ae91 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 64887e341..487ad34b4 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 1d9db9ed3..3de6ede62 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 c0e8ec97c..472f0e246 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 000000000..92f489ebb --- /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 000000000..643262d81 --- /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 92f489ebb..98827bd74 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 a0e35fd20..13de3f219 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 de8c02b61..87027b62f 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 6f7c3f67a..d0b9f4bf2 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 2518d4306..c41b68b95 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 f738d34a7..17c9e9531 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 e24b1fb65..82b93931e 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 76d5a59bb..165912736 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 9a9e24b55..341a426e5 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 8851a0a47..e6779a98f 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 4a04ddd43..f8a1bece0 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 165912736..420982184 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 250bb887d..2729f4a8f 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 } });