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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/petite-rings-accept.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@ensnode/ensnode-sdk": minor
---

Introduces `EnsIndexerClient` class, which allows interacting with ENSIndexer APIs.
Comment thread
tk-o marked this conversation as resolved.
Outdated
13 changes: 13 additions & 0 deletions packages/ensnode-sdk/src/ensindexer/api/config/deserialize.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { Unvalidated } from "../../../shared/types";
import { deserializeEnsIndexerPublicConfig } from "../../config/deserialize";
import type { EnsIndexerConfigResponse } from "./response";
import type { SerializedEnsIndexerConfigResponse } from "./serialized-response";

/**
* Deserialize value into {@link EnsIndexerConfigResponse} object.
*/
export function deserializeEnsIndexerConfigResponse(
maybeResponse: Unvalidated<SerializedEnsIndexerConfigResponse>,
): EnsIndexerConfigResponse {
return deserializeEnsIndexerPublicConfig(maybeResponse, "EnsIndexerConfigResponse");
}
4 changes: 4 additions & 0 deletions packages/ensnode-sdk/src/ensindexer/api/config/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from "./deserialize";
export * from "./response";
export * from "./serialize";
export * from "./serialized-response";
6 changes: 6 additions & 0 deletions packages/ensnode-sdk/src/ensindexer/api/config/response.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import type { EnsIndexerPublicConfig } from "../../config/types";

/**
* ENSIndexer Public Config Response
*/
export type EnsIndexerConfigResponse = EnsIndexerPublicConfig;
9 changes: 9 additions & 0 deletions packages/ensnode-sdk/src/ensindexer/api/config/serialize.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { serializeEnsIndexerPublicConfig } from "../../config/serialize";
import type { EnsIndexerConfigResponse } from "./response";
import type { SerializedEnsIndexerConfigResponse } from "./serialized-response";

export function serializeEnsIndexerConfigResponse(
response: EnsIndexerConfigResponse,
): SerializedEnsIndexerConfigResponse {
return serializeEnsIndexerPublicConfig(response);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import type { SerializedEnsIndexerPublicConfig } from "../../config/serialized-types";

export type SerializedEnsIndexerConfigResponse = SerializedEnsIndexerPublicConfig;
2 changes: 2 additions & 0 deletions packages/ensnode-sdk/src/ensindexer/api/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./config";
export * from "./indexing-status";
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { prettifyError } from "zod/v4";

import { buildUnvalidatedRealtimeIndexingStatusProjection } from "../../../indexing-status/deserialize/realtime-indexing-status-projection";
import type { Unvalidated } from "../../../shared/types";
import {
type EnsIndexerIndexingStatusResponse,
EnsIndexerIndexingStatusResponseCodes,
} from "./response";
import type { SerializedEnsIndexerIndexingStatusResponse } from "./serialized-response";
import {
makeEnsIndexerIndexingStatusResponseSchema,
makeSerializedEnsIndexerIndexingStatusResponseSchema,
} from "./zod-schemas";

/**
* Builds an unvalidated {@link EnsIndexerIndexingStatusResponse} object to be
* validated with {@link makeEnsIndexerIndexingStatusResponseSchema}.
*
* @param serializedResponse - The serialized response to build from.
* @return An unvalidated {@link EnsIndexerIndexingStatusResponse} object.
*/
function buildUnvalidatedEnsIndexerIndexingStatusResponse(
serializedResponse: SerializedEnsIndexerIndexingStatusResponse,
): Unvalidated<EnsIndexerIndexingStatusResponse> {
if (serializedResponse.responseCode !== EnsIndexerIndexingStatusResponseCodes.Ok) {
return serializedResponse;
}

return {
...serializedResponse,
realtimeProjection: buildUnvalidatedRealtimeIndexingStatusProjection(
serializedResponse.realtimeProjection,
),
};
}

/**
* Deserialize a {@link EnsIndexerIndexingStatusResponse} object.
*/
export function deserializeEnsIndexerIndexingStatusResponse(
maybeResponse: Unvalidated<SerializedEnsIndexerIndexingStatusResponse>,
): EnsIndexerIndexingStatusResponse {
const parsed = makeSerializedEnsIndexerIndexingStatusResponseSchema()
.transform(buildUnvalidatedEnsIndexerIndexingStatusResponse)
.pipe(makeEnsIndexerIndexingStatusResponseSchema())
.safeParse(maybeResponse);

if (parsed.error) {
throw new Error(
`Cannot deserialize EnsIndexerIndexingStatusResponse:\n${prettifyError(parsed.error)}\n`,
);
}

return parsed.data;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export * from "./deserialize";
export * from "./request";
export * from "./response";
export * from "./serialize";
export * from "./serialized-response";
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/**
* Represents a request to ENSIndexer Indexing Status API.
*/
export type EnsIndexerIndexingStatusRequest = {};
Comment thread
tk-o marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import type { RealtimeIndexingStatusProjection } from "../../../indexing-status/realtime-indexing-status-projection";

/**
* A status code for ENSIndexer indexing status responses.
*/
export const EnsIndexerIndexingStatusResponseCodes = {
/**
* Represents that the indexing status is available.
*/
Ok: "ok",

/**
* Represents that the indexing status is unavailable.
*/
Error: "error",
} as const;

/**
* The derived string union of possible {@link EnsIndexerIndexingStatusResponseCodes}.
*/
export type EnsIndexerIndexingStatusResponseCode =
(typeof EnsIndexerIndexingStatusResponseCodes)[keyof typeof EnsIndexerIndexingStatusResponseCodes];

/**
* An ENSIndexer indexing status response when the indexing status is available.
*/
export type EnsIndexerIndexingStatusResponseOk = {
responseCode: typeof EnsIndexerIndexingStatusResponseCodes.Ok;
realtimeProjection: RealtimeIndexingStatusProjection;
};

/**
* An ENSIndexer indexing status response when the indexing status is unavailable.
*/
export type EnsIndexerIndexingStatusResponseError = {
responseCode: typeof EnsIndexerIndexingStatusResponseCodes.Error;
};

/**
* ENSIndexer indexing status response.
*
* Use the `responseCode` field to determine the specific type interpretation
* at runtime.
*/
export type EnsIndexerIndexingStatusResponse =
| EnsIndexerIndexingStatusResponseOk
| EnsIndexerIndexingStatusResponseError;
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { serializeRealtimeIndexingStatusProjection } from "../../../indexing-status/serialize/realtime-indexing-status-projection";
import {
type EnsIndexerIndexingStatusResponse,
EnsIndexerIndexingStatusResponseCodes,
} from "./response";
import type {
SerializedEnsIndexerIndexingStatusResponse,
SerializedEnsIndexerIndexingStatusResponseOk,
} from "./serialized-response";

export function serializeEnsIndexerIndexingStatusResponse(
response: EnsIndexerIndexingStatusResponse,
): SerializedEnsIndexerIndexingStatusResponse {
switch (response.responseCode) {
case EnsIndexerIndexingStatusResponseCodes.Ok:
return {
responseCode: response.responseCode,
realtimeProjection: serializeRealtimeIndexingStatusProjection(response.realtimeProjection),
} satisfies SerializedEnsIndexerIndexingStatusResponseOk;

case EnsIndexerIndexingStatusResponseCodes.Error:
return response;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import type { SerializedRealtimeIndexingStatusProjection } from "../../../indexing-status/serialize/realtime-indexing-status-projection";
import type {
EnsIndexerIndexingStatusResponseError,
EnsIndexerIndexingStatusResponseOk,
} from "./response";

/**
* Serialized representation of {@link EnsIndexerIndexingStatusResponseError}.
*/
export type SerializedEnsIndexerIndexingStatusResponseError = EnsIndexerIndexingStatusResponseError;

/**
* Serialized representation of {@link EnsIndexerIndexingStatusResponseOk}.
*/
export interface SerializedEnsIndexerIndexingStatusResponseOk
extends Omit<EnsIndexerIndexingStatusResponseOk, "realtimeProjection"> {
realtimeProjection: SerializedRealtimeIndexingStatusProjection;
}

/**
* Serialized representation of {@link EnsIndexerIndexingStatusResponse}.
*/
export type SerializedEnsIndexerIndexingStatusResponse =
| SerializedEnsIndexerIndexingStatusResponseOk
| SerializedEnsIndexerIndexingStatusResponseError;
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { z } from "zod/v4";

import {
makeRealtimeIndexingStatusProjectionSchema,
makeSerializedRealtimeIndexingStatusProjectionSchema,
} from "../../../indexing-status/zod-schema/realtime-indexing-status-projection";
import {
type EnsIndexerIndexingStatusResponse,
Comment thread
tk-o marked this conversation as resolved.
EnsIndexerIndexingStatusResponseCodes,
type EnsIndexerIndexingStatusResponseError,
Comment thread
tk-o marked this conversation as resolved.
type EnsIndexerIndexingStatusResponseOk,
Comment thread
tk-o marked this conversation as resolved.
} from "./response";
import {
SerializedEnsIndexerIndexingStatusResponse,
Comment thread
tk-o marked this conversation as resolved.
SerializedEnsIndexerIndexingStatusResponseOk,
Comment thread
tk-o marked this conversation as resolved.
} from "./serialized-response";
Comment thread
tk-o marked this conversation as resolved.
Outdated
Comment thread
github-code-quality[bot] marked this conversation as resolved.
Fixed
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

/**
* Schema for {@link EnsIndexerIndexingStatusResponseOk}
**/
export const makeEnsIndexerIndexingStatusResponseOkSchema = (
valueLabel: string = "Indexing Status Response OK",
) =>
z.strictObject({
responseCode: z.literal(EnsIndexerIndexingStatusResponseCodes.Ok),
realtimeProjection: makeRealtimeIndexingStatusProjectionSchema(valueLabel),
});

/**
* Schema for {@link EnsIndexerIndexingStatusResponseError}
**/
export const makeEnsIndexerIndexingStatusResponseErrorSchema = (
_valueLabel: string = "Indexing Status Response Error",
Comment thread
tk-o marked this conversation as resolved.
) =>
z.strictObject({
responseCode: z.literal(EnsIndexerIndexingStatusResponseCodes.Error),
});
Comment thread
tk-o marked this conversation as resolved.
Comment thread
tk-o marked this conversation as resolved.

/**
* Schema for {@link EnsIndexerIndexingStatusResponse}
**/
export const makeEnsIndexerIndexingStatusResponseSchema = (
valueLabel: string = "Indexing Status Response",
) =>
z.discriminatedUnion("responseCode", [
makeEnsIndexerIndexingStatusResponseOkSchema(valueLabel),
makeEnsIndexerIndexingStatusResponseErrorSchema(valueLabel),
]);

/**
* Schema for {@link SerializedEnsIndexerIndexingStatusResponseOk}
**/
export const makeSerializedEnsIndexerIndexingStatusResponseOkSchema = (
valueLabel: string = "Serialized Indexing Status Response OK",
) =>
z.strictObject({
responseCode: z.literal(EnsIndexerIndexingStatusResponseCodes.Ok),
realtimeProjection: makeSerializedRealtimeIndexingStatusProjectionSchema(valueLabel),
});

/**
* Schema for {@link SerializedEnsIndexerIndexingStatusResponse}
**/
export const makeSerializedEnsIndexerIndexingStatusResponseSchema = (
valueLabel: string = "Serialized Indexing Status Response",
) =>
z.discriminatedUnion("responseCode", [
makeSerializedEnsIndexerIndexingStatusResponseOkSchema(valueLabel),
makeEnsIndexerIndexingStatusResponseErrorSchema(valueLabel),
]);
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { prettifyError } from "zod/v4";

import type { ErrorResponse } from "./response";
import { ErrorResponseSchema } from "./zod-schemas";

/**
* Deserialize a {@link ErrorResponse} object.
*/
export function deserializeErrorResponse(maybeErrorResponse: unknown): ErrorResponse {
const parsed = ErrorResponseSchema.safeParse(maybeErrorResponse);

if (parsed.error) {
throw new Error(`Cannot deserialize ErrorResponse:\n${prettifyError(parsed.error)}\n`);
}

return parsed.data;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./deserialize";
export * from "./response";
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import type { z } from "zod/v4";

import type { ErrorResponseSchema } from "./zod-schemas";

/**
* API Error Response Type
*/
export type ErrorResponse = z.infer<typeof ErrorResponseSchema>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { z } from "zod/v4";

import type { ErrorResponse } from "./response";
Comment thread
tk-o marked this conversation as resolved.

Comment thread
tk-o marked this conversation as resolved.
/**
* Schema for {@link ErrorResponse}.
*/
export const ErrorResponseSchema = z.object({
Comment thread
tk-o marked this conversation as resolved.
message: z.string(),
details: z.optional(z.unknown()),
});
Loading