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

Filter by extension

Filter by extension

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

Create shared module for `pagination` features.
12 changes: 12 additions & 0 deletions packages/ensnode-sdk/src/api/config/deserialize.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { deserializeENSApiPublicConfig } from "../../ensapi";
import type { ConfigResponse } from "./response";
import type { SerializedConfigResponse } from "./serialized-response";

/**
* Deserialize a {@link ConfigResponse} object.
*/
export function deserializeConfigResponse(
serializedResponse: SerializedConfigResponse,
): ConfigResponse {
return deserializeENSApiPublicConfig(serializedResponse);
}
4 changes: 4 additions & 0 deletions packages/ensnode-sdk/src/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/api/config/response.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import type { ENSApiPublicConfig } from "../../ensapi";

/**
* ENSApi Public Config Response
*/
export type ConfigResponse = ENSApiPublicConfig;
7 changes: 7 additions & 0 deletions packages/ensnode-sdk/src/api/config/serialize.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { serializeENSApiPublicConfig } from "../../ensapi";
import type { ConfigResponse } from "./response";
import type { SerializedConfigResponse } from "./serialized-response";

export function serializeConfigResponse(response: ConfigResponse): SerializedConfigResponse {
return serializeENSApiPublicConfig(response);
}
3 changes: 3 additions & 0 deletions packages/ensnode-sdk/src/api/config/serialized-response.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import type { SerializedENSApiPublicConfig } from "../../ensapi";

export type SerializedConfigResponse = SerializedENSApiPublicConfig;
48 changes: 0 additions & 48 deletions packages/ensnode-sdk/src/api/deserialize.ts

This file was deleted.

8 changes: 4 additions & 4 deletions packages/ensnode-sdk/src/api/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export * from "./deserialize";
export * from "./config";
export * from "./indexing-status";
export * from "./registrar-actions";
export * from "./serialize";
export * from "./serialized-types";
export * from "./types";
export * from "./resolution";
export * from "./shared";
20 changes: 20 additions & 0 deletions packages/ensnode-sdk/src/api/indexing-status/deserialize.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { prettifyError } from "zod/v4";

import type { IndexingStatusResponse } from "./response";
import type { SerializedIndexingStatusResponse } from "./serialized-response";
import { makeIndexingStatusResponseSchema } from "./zod-schemas";

/**
* Deserialize a {@link IndexingStatusResponse} object.
*/
export function deserializeIndexingStatusResponse(
maybeResponse: SerializedIndexingStatusResponse,
): IndexingStatusResponse {
const parsed = makeIndexingStatusResponseSchema().safeParse(maybeResponse);

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

return parsed.data;
}
5 changes: 5 additions & 0 deletions packages/ensnode-sdk/src/api/indexing-status/index.ts
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";
4 changes: 4 additions & 0 deletions packages/ensnode-sdk/src/api/indexing-status/request.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/**
* Represents a request to Indexing Status API.
*/
export type IndexingStatusRequest = {};
45 changes: 45 additions & 0 deletions packages/ensnode-sdk/src/api/indexing-status/response.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import type { RealtimeIndexingStatusProjection } from "../../ensindexer";

/**
* A status code for indexing status responses.
*/
export const IndexingStatusResponseCodes = {
/**
* 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 IndexingStatusResponseCodes}.
*/
export type IndexingStatusResponseCode =
(typeof IndexingStatusResponseCodes)[keyof typeof IndexingStatusResponseCodes];

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

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

/**
* Indexing status response.
*
* Use the `responseCode` field to determine the specific type interpretation
* at runtime.
*/
export type IndexingStatusResponse = IndexingStatusResponseOk | IndexingStatusResponseError;
21 changes: 21 additions & 0 deletions packages/ensnode-sdk/src/api/indexing-status/serialize.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { serializeRealtimeIndexingStatusProjection } from "../../ensindexer";
import { type IndexingStatusResponse, IndexingStatusResponseCodes } from "./response";
import type {
SerializedIndexingStatusResponse,
SerializedIndexingStatusResponseOk,
} from "./serialized-response";

export function serializeIndexingStatusResponse(
response: IndexingStatusResponse,
): SerializedIndexingStatusResponse {
switch (response.responseCode) {
case IndexingStatusResponseCodes.Ok:
return {
responseCode: response.responseCode,
realtimeProjection: serializeRealtimeIndexingStatusProjection(response.realtimeProjection),
} satisfies SerializedIndexingStatusResponseOk;

case IndexingStatusResponseCodes.Error:
return response;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type { SerializedRealtimeIndexingStatusProjection } from "../../ensindexer";
import type { IndexingStatusResponseError, IndexingStatusResponseOk } from "./response";

/**
* Serialized representation of {@link IndexingStatusResponseError}.
*/
export type SerializedIndexingStatusResponseError = IndexingStatusResponseError;

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

/**
* Serialized representation of {@link IndexingStatusResponse}.
*/
export type SerializedIndexingStatusResponse =
| SerializedIndexingStatusResponseOk
| SerializedIndexingStatusResponseError;
39 changes: 39 additions & 0 deletions packages/ensnode-sdk/src/api/indexing-status/zod-schemas.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import z from "zod/v4";

import { makeRealtimeIndexingStatusProjectionSchema } from "../../internal";
import {
type IndexingStatusResponse,
IndexingStatusResponseCodes,
type IndexingStatusResponseError,
type IndexingStatusResponseOk,
} from "./response";

/**
* Schema for {@link IndexingStatusResponseOk}
**/
export const makeIndexingStatusResponseOkSchema = (
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems there's an opportunity to share this pattern of ok vs error across each of our APIs, such that we don't have to repeat this implementation for each one.

A few questions:

  1. What do you think about this idea?
  2. If this is a fair idea, what do you think about implementing it in this PR vs creating a separate issue for it?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that the basic response status codes should be defined as ok and error. I'll log an issue for that.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

valueLabel: string = "Indexing Status Response OK",
) =>
z.strictObject({
responseCode: z.literal(IndexingStatusResponseCodes.Ok),
realtimeProjection: makeRealtimeIndexingStatusProjectionSchema(valueLabel),
});

/**
* Schema for {@link IndexingStatusResponseError}
**/
export const makeIndexingStatusResponseErrorSchema = (
_valueLabel: string = "Indexing Status Response Error",
) =>
z.strictObject({
responseCode: z.literal(IndexingStatusResponseCodes.Error),
});

/**
* Schema for {@link IndexingStatusResponse}
**/
export const makeIndexingStatusResponseSchema = (valueLabel: string = "Indexing Status Response") =>
z.discriminatedUnion("responseCode", [
makeIndexingStatusResponseOkSchema(valueLabel),
makeIndexingStatusResponseErrorSchema(valueLabel),
]);
22 changes: 22 additions & 0 deletions packages/ensnode-sdk/src/api/registrar-actions/deserialize.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { prettifyError } from "zod/v4";

import type { RegistrarActionsResponse } from "./response";
import type { SerializedRegistrarActionsResponse } from "./serialized-response";
import { makeRegistrarActionsResponseSchema } from "./zod-schemas";

/**
* Deserialize a {@link RegistrarActionsResponse} object.
*/
export function deserializeRegistrarActionsResponse(
maybeResponse: SerializedRegistrarActionsResponse,
): RegistrarActionsResponse {
const parsed = makeRegistrarActionsResponseSchema().safeParse(maybeResponse);

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

return parsed.data;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
type RegistrarActionsFilter,
RegistrarActionsFilterTypes,
type RegistrarActionsFilterWithEncodedReferral,
} from "../types";
} from "./request";

/**
* Build a "parent node" filter object for Registrar Actions query.
Expand Down
5 changes: 5 additions & 0 deletions packages/ensnode-sdk/src/api/registrar-actions/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,7 @@
export * from "./deserialize";
export * from "./filters";
export * from "./prerequisites";
export * from "./request";
export * from "./response";
export * from "./serialize";
export * from "./serialized-response";
57 changes: 57 additions & 0 deletions packages/ensnode-sdk/src/api/registrar-actions/request.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import type { Node } from "../../ens";

/**
* Records Filters: Filter Types
*/
export const RegistrarActionsFilterTypes = {
BySubregistryNode: "bySubregistryNode",
WithEncodedReferral: "withEncodedReferral",
} as const;

export type RegistrarActionsFilterType =
(typeof RegistrarActionsFilterTypes)[keyof typeof RegistrarActionsFilterTypes];

export type RegistrarActionsFilterBySubregistryNode = {
filterType: typeof RegistrarActionsFilterTypes.BySubregistryNode;
value: Node;
};

export type RegistrarActionsFilterWithEncodedReferral = {
filterType: typeof RegistrarActionsFilterTypes.WithEncodedReferral;
};

export type RegistrarActionsFilter =
| RegistrarActionsFilterBySubregistryNode
| RegistrarActionsFilterWithEncodedReferral;

/**
* Records Orders
*/
export const RegistrarActionsOrders = {
LatestRegistrarActions: "orderBy[timestamp]=desc",
} as const;

export type RegistrarActionsOrder =
(typeof RegistrarActionsOrders)[keyof typeof RegistrarActionsOrders];

/**
* Represents a request to Registrar Actions API.
*/
export type RegistrarActionsRequest = {
/**
* Filters to be applied while generating results.
*/
filters?: RegistrarActionsFilter[];

/**
* Order applied while generating results.
*/
order?: RegistrarActionsOrder;

/**
* Limit the count of items per page to selected count of records.
*
* Guaranteed to be a positive integer (if defined).
*/
itemsPerPage?: number;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll need to add the ability to fully paginate through registrar actions. Therefore we need the ability to request a page number in addition to an itemsPerPage.

Suggest that we also work to standardize the max items per page across all our APIs that have pagination so that we can share the same constant.

Do you suggest we solve this goal in this PR, or create a separate follow-up issue?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'll be a follow-up PR, we'll extend from the generic request pagination param type from packages/ensnode-sdk/src/api/shared/pagination/request.ts

};
Loading