Skip to content
Open
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
4 changes: 2 additions & 2 deletions apps/ensapi/src/handlers/amirealtime-api.routes.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { createRoute } from "@hono/zod-openapi";
import { createRoute, z } from "@hono/zod-openapi";
import { minutesToSeconds } from "date-fns";
import { z } from "zod/v4";

import type { Duration } from "@ensnode/ensnode-sdk";
import { makeDurationSchema } from "@ensnode/ensnode-sdk/internal";
Expand Down Expand Up @@ -32,6 +31,7 @@ export const amIRealtimeGetMeta = createRoute({
})
.pipe(makeDurationSchema("maxWorstCaseDistance query param")),
)
.openapi({ type: "integer", minimum: 0 })
.describe("Maximum acceptable worst-case indexing distance in seconds"),
}),
},
Expand Down
5 changes: 3 additions & 2 deletions apps/ensapi/src/handlers/ensanalytics-api-v1.routes.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createRoute } from "@hono/zod-openapi";
import { createRoute, z } from "@hono/zod-openapi";
import {
MAX_EDITIONS_PER_REQUEST,
REFERRERS_PER_LEADERBOARD_PAGE_MAX,
Expand All @@ -7,7 +7,6 @@ import {
makeReferralProgramEditionSlugSchema,
makeReferrerMetricsEditionsArraySchema,
} from "@namehash/ens-referrals/v1/internal";
import { z } from "zod/v4";

import { makeLowercaseAddressSchema } from "@ensnode/ensnode-sdk/internal";

Expand All @@ -21,6 +20,7 @@ const referrerLeaderboardPageQuerySchema = z.object({
edition: makeReferralProgramEditionSlugSchema("edition"),
page: z
.optional(z.coerce.number().int().min(1, "Page must be a positive integer"))
.openapi({ type: "integer", minimum: 1 })
.describe("Page number for pagination"),
recordsPerPage: z
.optional(
Expand All @@ -33,6 +33,7 @@ const referrerLeaderboardPageQuerySchema = z.object({
`Records per page must not exceed ${REFERRERS_PER_LEADERBOARD_PAGE_MAX}`,
),
)
.openapi({ type: "integer", minimum: 1, maximum: REFERRERS_PER_LEADERBOARD_PAGE_MAX })
.describe("Number of referrers per page"),
});

Expand Down
5 changes: 3 additions & 2 deletions apps/ensapi/src/handlers/ensanalytics-api.routes.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { createRoute } from "@hono/zod-openapi";
import { createRoute, z } from "@hono/zod-openapi";
import { REFERRERS_PER_LEADERBOARD_PAGE_MAX } from "@namehash/ens-referrals";
import { z } from "zod/v4";

import { makeLowercaseAddressSchema } from "@ensnode/ensnode-sdk/internal";

Expand All @@ -10,6 +9,7 @@ export const basePath = "/ensanalytics";
const paginationQuerySchema = z.object({
page: z
.optional(z.coerce.number().int().min(1, "Page must be a positive integer"))
.openapi({ type: "integer", minimum: 1 })
.describe("Page number for pagination"),
recordsPerPage: z
.optional(
Expand All @@ -22,6 +22,7 @@ const paginationQuerySchema = z.object({
`Records per page must not exceed ${REFERRERS_PER_LEADERBOARD_PAGE_MAX}`,
),
)
.openapi({ type: "integer", minimum: 1, maximum: REFERRERS_PER_LEADERBOARD_PAGE_MAX })
.describe("Number of referrers per page"),
});

Expand Down
3 changes: 1 addition & 2 deletions apps/ensapi/src/handlers/name-tokens-api.routes.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { createRoute } from "@hono/zod-openapi";
import { z } from "zod/v4";
import { createRoute, z } from "@hono/zod-openapi";

import {
ErrorResponseSchema,
Expand Down
13 changes: 10 additions & 3 deletions apps/ensapi/src/handlers/registrar-actions-api.routes.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { createRoute } from "@hono/zod-openapi";
import { z } from "zod/v4";
import { createRoute, z } from "@hono/zod-openapi";

import {
RECORDS_PER_PAGE_DEFAULT,
Expand Down Expand Up @@ -30,19 +29,27 @@ export const registrarActionsQuerySchema = z
.default(1)
.pipe(z.coerce.number())
.pipe(makePositiveIntegerSchema("page"))
.openapi({ type: "integer", minimum: 1, default: 1 })
.describe("Page number for pagination"),

recordsPerPage: params.queryParam
.optional()
.default(RECORDS_PER_PAGE_DEFAULT)
.pipe(z.coerce.number())
.pipe(makePositiveIntegerSchema("recordsPerPage").max(RECORDS_PER_PAGE_MAX))
.openapi({
type: "integer",
minimum: 1,
maximum: RECORDS_PER_PAGE_MAX,
default: RECORDS_PER_PAGE_DEFAULT,
})
.describe("Number of records per page"),

withReferral: params.boolstring
.optional()
.default(false)
.describe("Filter to only include actions with referrals"),
.describe("Filter to only include actions with referrals")
.openapi({ default: false }),

decodedReferrer: makeLowercaseAddressSchema("decodedReferrer")
.optional()
Expand Down
3 changes: 1 addition & 2 deletions apps/ensapi/src/handlers/resolution-api.routes.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { createRoute } from "@hono/zod-openapi";
import { z } from "zod/v4";
import { createRoute, z } from "@hono/zod-openapi";

import {
makeResolvePrimaryNameResponseSchema,
Expand Down
4 changes: 1 addition & 3 deletions apps/ensapi/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,7 @@ app.route("/v1/ensanalytics", ensanalyticsApiV1);
app.route("/amirealtime", amIRealtimeApi);

// serve pre-generated OpenAPI 3.1 document
const openApi31Document = generateOpenApi31Document([
{ url: `http://localhost:${config.port}`, description: "Local Development" },
]);
const openApi31Document = generateOpenApi31Document();
app.get("/openapi.json", (c) => {
return c.json(openApi31Document);
});
Expand Down
9 changes: 5 additions & 4 deletions apps/ensapi/src/lib/handlers/params.schema.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { z } from "zod/v4";
import { z } from "@hono/zod-openapi";

import {
DEFAULT_EVM_CHAIN_ID,
Expand All @@ -23,7 +23,8 @@ const excludingDefaultChainId = z
const boolstring = z
.string()
.pipe(z.enum(["true", "false"]))
.transform((val) => val === "true");
.transform((val) => val === "true")
.openapi({ type: "boolean" });

const stringarray = z
.string()
Expand All @@ -38,8 +39,8 @@ const name = z
.refine(isNormalizedName, "Must be normalized, see https://docs.ens.domains/resolution/names/")
.transform((val) => val as Name);

const trace = z.optional(boolstring).default(false);
const accelerate = z.optional(boolstring).default(false);
const trace = z.optional(boolstring).default(false).openapi({ default: false });
const accelerate = z.optional(boolstring).default(false).openapi({ default: false });
const address = makeLowercaseAddressSchema();
const defaultableChainId = makeDefaultableChainIdStringSchema();
const coinType = makeCoinTypeStringSchema();
Expand Down
11 changes: 2 additions & 9 deletions apps/ensapi/src/openapi-document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,7 @@ function createStubRoutesForSpec() {

/**
* Generates an OpenAPI 3.1 document from stub route definitions.
* Accepts optional additional servers (e.g. a localhost entry derived from
* runtime config) so that the core generation has no runtime dependencies.
*/
export function generateOpenApi31Document(
additionalServers: { url: string; description: string }[] = [],
): ReturnType<OpenAPIHono["getOpenAPI31Document"]> {
return createStubRoutesForSpec().getOpenAPI31Document({
...openapiMeta,
servers: [...openapiMeta.servers, ...additionalServers],
});
export function generateOpenApi31Document(): ReturnType<OpenAPIHono["getOpenAPI31Document"]> {
return createStubRoutesForSpec().getOpenAPI31Document(openapiMeta);
}
31 changes: 14 additions & 17 deletions docs/docs.ensnode.io/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,25 @@

[docs.ensnode.io](https://docs.ensnode.io) runs on [Mintlify](https://mintlify.com).

## Local Development

### Getting Started
Learn more about [ENSNode](https://ensnode.io) from [the "Starlight" ENSNode docs](https://ensnode.io/docs/). Everything from these "Starlight" docs is planned to be transitioned into these Mintlify docs soon.

1. Clone the repository:

```bash
git clone https://github.com/namehash/ensnode.git
```
## Local Development

2. Navigate to the docs directory:
1. `git clone https://github.com/namehash/ensnode.git`
2. `cd ensnode`
3. `cd docs/docs.ensnode.io`
4. `pnpm mint dev`
5. Open [http://localhost:3000](http://localhost:3000) in your browser

```bash
cd ensnode/docs/docs.ensnode.io
```
### Regenerating the OpenAPI Spec

3. Start the local development server:
The ENSApi OpenAPI spec (`ensapi-openapi.json`) is generated from the route definitions in `apps/ensapi`. To regenerate it after making changes to route schemas:

```bash
pnpm mint dev
```
```sh
pnpm generate:openapi
```

4. Open [http://localhost:3000](http://localhost:3000) in your browser
This runs from the repo root and outputs the formatted spec to `docs/docs.ensnode.io/ensapi-openapi.json`.

### Troubleshooting

Expand All @@ -38,3 +34,4 @@ Changes pushed to the main branch are automatically deployed to production.
## Resources

- [Mintlify documentation](https://mintlify.com/docs)
- [ENSNode "Starlight" docs](https://ensnode.io/docs/)
8 changes: 7 additions & 1 deletion docs/docs.ensnode.io/docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,13 @@
},
{
"group": "API Reference",
"openapi": "https://gist.githubusercontent.com/notrab/94b637e77468cbddd895d7933ce88f64/raw/12cb5ed183558a9bdda5d1c7004db6c794dbd13e/green-ensnode-openapi.json"
"openapi": "https://api.alpha.ensnode.io/openapi.json"
},
{
"group": "Preview",
"pages": ["ensapi/preview"],
"openapi": "ensapi-openapi.json",
"hidden": true
}
]
}
Expand Down
Loading
Loading