From e3f8a946695edf9c7f59242ad0debf257a041f05 Mon Sep 17 00:00:00 2001 From: Jamie Barton Date: Thu, 26 Feb 2026 08:43:05 +0000 Subject: [PATCH 01/10] refactor: use zod-openapi to serve openapi.json route --- apps/ensapi/package.json | 2 - apps/ensapi/src/index.ts | 56 ++------ apps/ensapi/src/lib/handlers/validate.ts | 29 ---- apps/ensapi/src/openapi-meta.ts | 4 +- pnpm-lock.yaml | 169 ----------------------- 5 files changed, 17 insertions(+), 243 deletions(-) delete mode 100644 apps/ensapi/src/lib/handlers/validate.ts diff --git a/apps/ensapi/package.json b/apps/ensapi/package.json index dc880e4a2..bcab653eb 100644 --- a/apps/ensapi/package.json +++ b/apps/ensapi/package.json @@ -27,7 +27,6 @@ "@ensnode/ponder-subgraph": "workspace:*", "@hono/node-server": "^1.19.5", "@hono/otel": "^0.2.2", - "@hono/standard-validator": "^0.2.2", "@hono/zod-openapi": "^1.2.2", "@namehash/ens-referrals": "workspace:*", "@opentelemetry/api": "^1.9.0", @@ -52,7 +51,6 @@ "graphql": "^16.11.0", "graphql-yoga": "^5.16.0", "hono": "catalog:", - "hono-openapi": "^1.1.2", "p-memoize": "^8.0.0", "p-retry": "^7.1.0", "pg-connection-string": "catalog:", diff --git a/apps/ensapi/src/index.ts b/apps/ensapi/src/index.ts index 9483c4f6a..230fa2b0b 100644 --- a/apps/ensapi/src/index.ts +++ b/apps/ensapi/src/index.ts @@ -5,7 +5,6 @@ import { serve } from "@hono/node-server"; import { otel } from "@hono/otel"; import { cors } from "hono/cors"; import { html } from "hono/html"; -import { openAPIRouteHandler } from "hono-openapi"; import { indexingStatusCache } from "@/cache/indexing-status.cache"; import { getReferralLeaderboardEditionsCaches } from "@/cache/referral-leaderboard-editions.cache"; @@ -17,6 +16,8 @@ import { factory } from "@/lib/hono-factory"; import { sdk } from "@/lib/instrumentation"; import logger from "@/lib/logger"; import { indexingStatusMiddleware } from "@/middleware/indexing-status.middleware"; +import { openapiMeta } from "@/openapi-meta"; +import { createStubRoutesForSpec } from "@/stub-routes"; import amIRealtimeApi from "./handlers/amirealtime-api"; import ensanalyticsApi from "./handlers/ensanalytics-api"; @@ -74,47 +75,18 @@ app.route("/v1/ensanalytics", ensanalyticsApiV1); // use Am I Realtime API at /amirealtime app.route("/amirealtime", amIRealtimeApi); -// use OpenAPI Schema -app.get( - "/openapi.json", - openAPIRouteHandler(app, { - documentation: { - info: { - title: "ENSApi APIs", - version: packageJson.version, - description: - "APIs for ENS resolution, navigating the ENS nameforest, and metadata about an ENSNode", - }, - servers: [ - { url: "https://api.alpha.ensnode.io", description: "ENSNode Alpha (Mainnet)" }, - { - url: "https://api.alpha-sepolia.ensnode.io", - description: "ENSNode Alpha (Sepolia Testnet)", - }, - { url: `http://localhost:${config.port}`, description: "Local Development" }, - ], - tags: [ - { - name: "Resolution", - description: "APIs for resolving ENS names and addresses", - }, - { - name: "Meta", - description: "APIs for indexing status, configuration, and realtime monitoring", - }, - { - name: "Explore", - description: - "APIs for exploring the indexed state of ENS, including name tokens and registrar actions", - }, - { - name: "ENSAwards", - description: "APIs for ENSAwards functionality, including referrer data", - }, - ], - }, - }), -); +// use OpenAPI Schema generated from zod-openapi route definitions +const stubApp = createStubRoutesForSpec(); +app.get("/openapi.json", (c) => { + const doc = stubApp.getOpenAPI31Document({ + ...openapiMeta, + servers: [ + ...openapiMeta.servers, + { url: `http://localhost:${config.port}`, description: "Local Development" }, + ], + }); + return c.json(doc); +}); // will automatically 503 if config is not available due to ensIndexerPublicConfigMiddleware app.get("/health", async (c) => { diff --git a/apps/ensapi/src/lib/handlers/validate.ts b/apps/ensapi/src/lib/handlers/validate.ts deleted file mode 100644 index 4316e07bb..000000000 --- a/apps/ensapi/src/lib/handlers/validate.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { SchemaError } from "@standard-schema/utils"; -import type { ValidationTargets } from "hono"; -import { validator } from "hono-openapi"; -import type { ZodType } from "zod/v4"; - -import { errorResponse } from "./error-response"; - -/** - * Creates a Hono validation middleware with custom error formatting. - * - * Wraps the Hono validator with custom error handling that uses the - * errorResponse function for consistent error formatting across the API. - * - * @param target - The validation target (param, query, json, etc.) - * @param schema - The Zod schema to validate against - * @returns Hono middleware that validates the specified target - */ -export const validate = ( - target: Target, - schema: T, -) => - validator(target, schema, (result, c) => { - // if validation failed, return our custom-formatted ErrorResponse instead of default - if (!result.success) { - // Wrap the Standard Schema issues in a SchemaError instance - // for consistent error handling in errorResponse - return errorResponse(c, new SchemaError(result.error)); - } - }); diff --git a/apps/ensapi/src/openapi-meta.ts b/apps/ensapi/src/openapi-meta.ts index 1dfd28a78..7694032ac 100644 --- a/apps/ensapi/src/openapi-meta.ts +++ b/apps/ensapi/src/openapi-meta.ts @@ -1,8 +1,10 @@ +import packageJson from "@/../package.json" with { type: "json" }; + export const openapiMeta = { openapi: "3.1.0" as const, info: { title: "ENSApi APIs", - version: "0.0.0", + version: packageJson.version, description: "APIs for ENS resolution, navigating the ENS nameforest, and metadata about an ENSNode", }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2fe610747..ab5221b80 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -323,9 +323,6 @@ importers: '@hono/otel': specifier: ^0.2.2 version: 0.2.2(hono@4.12.0) - '@hono/standard-validator': - specifier: ^0.2.2 - version: 0.2.2(@standard-schema/spec@1.0.0)(hono@4.12.0) '@hono/zod-openapi': specifier: ^1.2.2 version: 1.2.2(hono@4.12.0)(zod@4.3.6) @@ -398,9 +395,6 @@ importers: hono: specifier: 'catalog:' version: 4.12.0 - hono-openapi: - specifier: ^1.1.2 - version: 1.1.2(@hono/standard-validator@0.2.2(@standard-schema/spec@1.0.0)(hono@4.12.0))(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.0.0)(@types/json-schema@7.0.15)(arktype@2.1.29)(quansync@0.2.11)(zod-to-json-schema@3.24.6(zod@4.3.6))(zod@4.3.6))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.0.0)(@types/json-schema@7.0.15)(arktype@2.1.29)(quansync@0.2.11)(zod-to-json-schema@3.24.6(zod@4.3.6))(zod@4.3.6))(@standard-schema/spec@1.0.0)(arktype@2.1.29)(openapi-types@12.1.3)(zod@4.3.6))(@types/json-schema@7.0.15)(hono@4.12.0)(openapi-types@12.1.3) p-memoize: specifier: ^8.0.0 version: 8.0.0 @@ -1155,12 +1149,6 @@ packages: '@antfu/utils@9.3.0': resolution: {integrity: sha512-9hFT4RauhcUzqOE4f1+frMKLZrgNog5b06I7VmZQV1BkvwvqrbC8EBZf3L1eEL2AKb6rNKjER0sEvJiSP1FXEA==} - '@ark/schema@0.56.0': - resolution: {integrity: sha512-ECg3hox/6Z/nLajxXqNhgPtNdHWC9zNsDyskwO28WinoFEnWow4IsERNz9AnXRhTZJnYIlAJ4uGn3nlLk65vZA==} - - '@ark/util@0.56.0': - resolution: {integrity: sha512-BghfRC8b9pNs3vBoDJhcta0/c1J1rsoS1+HgVUreMFPdhz/CRAKReAu57YEllNaSy98rWAdY1gE+gFup7OXpgA==} - '@asamuzakjp/css-color@4.0.5': resolution: {integrity: sha512-lMrXidNhPGsDjytDy11Vwlb6OIGrT3CmLg3VWNFyWkLWtijKl7xjvForlh8vuj0SHGjgl4qZEQzUmYTeQA2JFQ==} @@ -2240,12 +2228,6 @@ packages: peerDependencies: hono: '*' - '@hono/standard-validator@0.2.2': - resolution: {integrity: sha512-mJ7W84Bt/rSvoIl63Ynew+UZOHAzzRAoAXb3JaWuxAkM/Lzg+ZHTCUiz77KOtn2e623WNN8LkD57Dk0szqUrIw==} - peerDependencies: - '@standard-schema/spec': ^1.0.0 - hono: '>=3.9.0' - '@hono/zod-openapi@1.2.2': resolution: {integrity: sha512-va6vsL23wCJ1d0Vd+vGL1XOt+wPwItxirYafuhlW9iC2MstYr2FvsI7mctb45eBTjZfkqB/3LYDJEppPjOEiHw==} engines: {node: '>=16.0.0'} @@ -3843,67 +3825,6 @@ packages: resolution: {integrity: sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw==} engines: {node: '>=18.0.0'} - '@standard-community/standard-json@0.3.5': - resolution: {integrity: sha512-4+ZPorwDRt47i+O7RjyuaxHRK/37QY/LmgxlGrRrSTLYoFatEOzvqIc85GTlM18SFZ5E91C+v0o/M37wZPpUHA==} - peerDependencies: - '@standard-schema/spec': ^1.0.0 - '@types/json-schema': ^7.0.15 - '@valibot/to-json-schema': ^1.3.0 - arktype: ^2.1.20 - effect: ^3.16.8 - quansync: ^0.2.11 - sury: ^10.0.0 - typebox: ^1.0.17 - valibot: ^1.1.0 - zod: ^3.25.0 || ^4.0.0 - zod-to-json-schema: ^3.24.5 - peerDependenciesMeta: - '@valibot/to-json-schema': - optional: true - arktype: - optional: true - effect: - optional: true - sury: - optional: true - typebox: - optional: true - valibot: - optional: true - zod: - optional: true - zod-to-json-schema: - optional: true - - '@standard-community/standard-openapi@0.2.9': - resolution: {integrity: sha512-htj+yldvN1XncyZi4rehbf9kLbu8os2Ke/rfqoZHCMHuw34kiF3LP/yQPdA0tQ940y8nDq3Iou8R3wG+AGGyvg==} - peerDependencies: - '@standard-community/standard-json': ^0.3.5 - '@standard-schema/spec': ^1.0.0 - arktype: ^2.1.20 - effect: ^3.17.14 - openapi-types: ^12.1.3 - sury: ^10.0.0 - typebox: ^1.0.0 - valibot: ^1.1.0 - zod: ^3.25.0 || ^4.0.0 - zod-openapi: ^4 - peerDependenciesMeta: - arktype: - optional: true - effect: - optional: true - sury: - optional: true - typebox: - optional: true - valibot: - optional: true - zod: - optional: true - zod-openapi: - optional: true - '@standard-schema/spec@1.0.0': resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} @@ -4287,9 +4208,6 @@ packages: '@types/js-yaml@4.0.9': resolution: {integrity: sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==} - '@types/json-schema@7.0.15': - resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - '@types/mdast@4.0.4': resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} @@ -4657,12 +4575,6 @@ packages: resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} engines: {node: '>= 0.4'} - arkregex@0.0.5: - resolution: {integrity: sha512-ncYjBdLlh5/QnVsAA8De16Tc9EqmYM7y/WU9j+236KcyYNUXogpz3sC4ATIZYzzLxwI+0sEOaQLEmLmRleaEXw==} - - arktype@2.1.29: - resolution: {integrity: sha512-jyfKk4xIOzvYNayqnD8ZJQqOwcrTOUbIU4293yrzAjA3O1dWh61j71ArMQ6tS/u4pD7vabSPe7nG3RCyoXW6RQ==} - array-iterate@2.0.1: resolution: {integrity: sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==} @@ -6068,21 +5980,6 @@ packages: help-me@5.0.0: resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==} - hono-openapi@1.1.2: - resolution: {integrity: sha512-toUcO60MftRBxqcVyxsHNYs2m4vf4xkQaiARAucQx3TiBPDtMNNkoh+C4I1vAretQZiGyaLOZNWn1YxfSyUA5g==} - peerDependencies: - '@hono/standard-validator': ^0.2.0 - '@standard-community/standard-json': ^0.3.5 - '@standard-community/standard-openapi': ^0.2.9 - '@types/json-schema': ^7.0.15 - hono: ^4.8.3 - openapi-types: ^12.1.3 - peerDependenciesMeta: - '@hono/standard-validator': - optional: true - hono: - optional: true - hono@4.12.0: resolution: {integrity: sha512-NekXntS5M94pUfiVZ8oXXK/kkri+5WpX2/Ik+LVsl+uvw+soj4roXIsPqO+XsWrAw20mOzaXOZf3Q7PfB9A/IA==} engines: {node: '>=16.9.0'} @@ -7006,9 +6903,6 @@ packages: oniguruma-to-es@4.3.3: resolution: {integrity: sha512-rPiZhzC3wXwE59YQMRDodUwwT9FZ9nNBwQQfsd1wfdtlKEyCdRV0avrTcSZ5xlIvGRVPd/cx6ZN45ECmS39xvg==} - openapi-types@12.1.3: - resolution: {integrity: sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==} - openapi3-ts@4.5.0: resolution: {integrity: sha512-jaL+HgTq2Gj5jRcfdutgRGLosCy/hT8sQf6VOy+P+g36cZOjI1iukdPnijC+4CmeRzg/jEllJUboEic2FhxhtQ==} @@ -8971,14 +8865,6 @@ snapshots: '@antfu/utils@9.3.0': {} - '@ark/schema@0.56.0': - dependencies: - '@ark/util': 0.56.0 - optional: true - - '@ark/util@0.56.0': - optional: true - '@asamuzakjp/css-color@4.0.5': dependencies: '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) @@ -10572,11 +10458,6 @@ snapshots: '@opentelemetry/semantic-conventions': 1.37.0 hono: 4.12.0 - '@hono/standard-validator@0.2.2(@standard-schema/spec@1.0.0)(hono@4.12.0)': - dependencies: - '@standard-schema/spec': 1.0.0 - hono: 4.12.0 - '@hono/zod-openapi@1.2.2(hono@4.12.0)(zod@4.3.6)': dependencies: '@asteasolutions/zod-to-openapi': 8.4.1(zod@4.3.6) @@ -12392,25 +12273,6 @@ snapshots: dependencies: tslib: 2.8.1 - '@standard-community/standard-json@0.3.5(@standard-schema/spec@1.0.0)(@types/json-schema@7.0.15)(arktype@2.1.29)(quansync@0.2.11)(zod-to-json-schema@3.24.6(zod@4.3.6))(zod@4.3.6)': - dependencies: - '@standard-schema/spec': 1.0.0 - '@types/json-schema': 7.0.15 - quansync: 0.2.11 - optionalDependencies: - arktype: 2.1.29 - zod: 4.3.6 - zod-to-json-schema: 3.24.6(zod@4.3.6) - - '@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.0.0)(@types/json-schema@7.0.15)(arktype@2.1.29)(quansync@0.2.11)(zod-to-json-schema@3.24.6(zod@4.3.6))(zod@4.3.6))(@standard-schema/spec@1.0.0)(arktype@2.1.29)(openapi-types@12.1.3)(zod@4.3.6)': - dependencies: - '@standard-community/standard-json': 0.3.5(@standard-schema/spec@1.0.0)(@types/json-schema@7.0.15)(arktype@2.1.29)(quansync@0.2.11)(zod-to-json-schema@3.24.6(zod@4.3.6))(zod@4.3.6) - '@standard-schema/spec': 1.0.0 - openapi-types: 12.1.3 - optionalDependencies: - arktype: 2.1.29 - zod: 4.3.6 - '@standard-schema/spec@1.0.0': {} '@standard-schema/utils@0.3.0': {} @@ -12791,8 +12653,6 @@ snapshots: '@types/js-yaml@4.0.9': {} - '@types/json-schema@7.0.15': {} - '@types/mdast@4.0.4': dependencies: '@types/unist': 3.0.3 @@ -13201,18 +13061,6 @@ snapshots: aria-query@5.3.2: {} - arkregex@0.0.5: - dependencies: - '@ark/util': 0.56.0 - optional: true - - arktype@2.1.29: - dependencies: - '@ark/schema': 0.56.0 - '@ark/util': 0.56.0 - arkregex: 0.0.5 - optional: true - array-iterate@2.0.1: {} array-union@2.1.0: {} @@ -14870,16 +14718,6 @@ snapshots: help-me@5.0.0: {} - hono-openapi@1.1.2(@hono/standard-validator@0.2.2(@standard-schema/spec@1.0.0)(hono@4.12.0))(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.0.0)(@types/json-schema@7.0.15)(arktype@2.1.29)(quansync@0.2.11)(zod-to-json-schema@3.24.6(zod@4.3.6))(zod@4.3.6))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.0.0)(@types/json-schema@7.0.15)(arktype@2.1.29)(quansync@0.2.11)(zod-to-json-schema@3.24.6(zod@4.3.6))(zod@4.3.6))(@standard-schema/spec@1.0.0)(arktype@2.1.29)(openapi-types@12.1.3)(zod@4.3.6))(@types/json-schema@7.0.15)(hono@4.12.0)(openapi-types@12.1.3): - dependencies: - '@standard-community/standard-json': 0.3.5(@standard-schema/spec@1.0.0)(@types/json-schema@7.0.15)(arktype@2.1.29)(quansync@0.2.11)(zod-to-json-schema@3.24.6(zod@4.3.6))(zod@4.3.6) - '@standard-community/standard-openapi': 0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.0.0)(@types/json-schema@7.0.15)(arktype@2.1.29)(quansync@0.2.11)(zod-to-json-schema@3.24.6(zod@4.3.6))(zod@4.3.6))(@standard-schema/spec@1.0.0)(arktype@2.1.29)(openapi-types@12.1.3)(zod@4.3.6) - '@types/json-schema': 7.0.15 - openapi-types: 12.1.3 - optionalDependencies: - '@hono/standard-validator': 0.2.2(@standard-schema/spec@1.0.0)(hono@4.12.0) - hono: 4.12.0 - hono@4.12.0: {} html-encoding-sniffer@4.0.0: @@ -15989,8 +15827,6 @@ snapshots: regex: 6.0.1 regex-recursion: 6.0.2 - openapi-types@12.1.3: {} - openapi3-ts@4.5.0: dependencies: yaml: 2.8.1 @@ -18171,11 +18007,6 @@ snapshots: dependencies: zod: 3.25.76 - zod-to-json-schema@3.24.6(zod@4.3.6): - dependencies: - zod: 4.3.6 - optional: true - zod-to-ts@1.2.0(typescript@5.9.3)(zod@3.25.76): dependencies: typescript: 5.9.3 From 05942772d07cf6718870ca7dd9cbb123ac973835 Mon Sep 17 00:00:00 2001 From: Jamie Barton Date: Thu, 26 Feb 2026 09:09:14 +0000 Subject: [PATCH 02/10] add api prefix for resolve routes --- apps/ensapi/src/handlers/resolution-api.routes.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/ensapi/src/handlers/resolution-api.routes.ts b/apps/ensapi/src/handlers/resolution-api.routes.ts index 1043b0428..dec45a409 100644 --- a/apps/ensapi/src/handlers/resolution-api.routes.ts +++ b/apps/ensapi/src/handlers/resolution-api.routes.ts @@ -3,7 +3,7 @@ import { z } from "zod/v4"; import { params } from "@/lib/handlers/params.schema"; -export const basePath = "/resolve"; +export const basePath = "/api/resolve"; export const resolveRecordsRoute = createRoute({ method: "get", From 69bb301f7aa58ef5546b26c779878999d9fe5186 Mon Sep 17 00:00:00 2001 From: Jamie Barton Date: Thu, 26 Feb 2026 09:58:38 +0000 Subject: [PATCH 03/10] add old formatted operationIds --- apps/ensapi/src/handlers/amirealtime-api.routes.ts | 5 ++++- apps/ensapi/src/handlers/ensanalytics-api-v1.routes.ts | 3 +++ apps/ensapi/src/handlers/ensanalytics-api.routes.ts | 2 ++ apps/ensapi/src/handlers/ensnode-api.routes.ts | 2 ++ apps/ensapi/src/handlers/name-tokens-api.routes.ts | 1 + apps/ensapi/src/handlers/registrar-actions-api.routes.ts | 2 ++ apps/ensapi/src/handlers/resolution-api.routes.ts | 3 +++ 7 files changed, 17 insertions(+), 1 deletion(-) diff --git a/apps/ensapi/src/handlers/amirealtime-api.routes.ts b/apps/ensapi/src/handlers/amirealtime-api.routes.ts index b5eb3fc8a..9a731d8d1 100644 --- a/apps/ensapi/src/handlers/amirealtime-api.routes.ts +++ b/apps/ensapi/src/handlers/amirealtime-api.routes.ts @@ -15,6 +15,7 @@ export const AMIREALTIME_DEFAULT_MAX_WORST_CASE_DISTANCE: Duration = minutesToSe export const amIRealtimeGetMeta = createRoute({ method: "get", path: "/", + operationId: "getAmirealtime", tags: ["Meta"], summary: "Check indexing progress", description: @@ -26,7 +27,9 @@ export const amIRealtimeGetMeta = createRoute({ .default(AMIREALTIME_DEFAULT_MAX_WORST_CASE_DISTANCE) .pipe( z.coerce - .number({ error: "maxWorstCaseDistance query param must be a number" }) + .number({ + error: "maxWorstCaseDistance query param must be a number", + }) .pipe(makeDurationSchema("maxWorstCaseDistance query param")), ) .describe("Maximum acceptable worst-case indexing distance in seconds"), diff --git a/apps/ensapi/src/handlers/ensanalytics-api-v1.routes.ts b/apps/ensapi/src/handlers/ensanalytics-api-v1.routes.ts index 2dfd5634c..12167551e 100644 --- a/apps/ensapi/src/handlers/ensanalytics-api-v1.routes.ts +++ b/apps/ensapi/src/handlers/ensanalytics-api-v1.routes.ts @@ -53,6 +53,7 @@ const editionsQuerySchema = z.object({ export const getReferralLeaderboardRoute = createRoute({ method: "get", path: "/referral-leaderboard", + operationId: "getV1EnsanalyticsReferralLeaderboard", tags: ["ENSAwards"], summary: "Get Referrer Leaderboard (v1)", description: "Returns a paginated page from the referrer leaderboard for a specific edition", @@ -78,6 +79,7 @@ export const getReferralLeaderboardRoute = createRoute({ export const getReferrerDetailRoute = createRoute({ method: "get", path: "/referrer/{referrer}", + operationId: "getV1EnsanalyticsReferrerDetail", tags: ["ENSAwards"], summary: "Get Referrer Detail for Editions (v1)", description: `Returns detailed information for a specific referrer for the requested editions. Requires 1-${MAX_EDITIONS_PER_REQUEST} distinct edition slugs. All requested editions must be recognized and have cached data, or the request fails.`, @@ -107,6 +109,7 @@ export const getReferrerDetailRoute = createRoute({ export const getEditionsRoute = createRoute({ method: "get", path: "/editions", + operationId: "getV1EnsanalyticsEditions", tags: ["ENSAwards"], summary: "Get Edition Config Set (v1)", description: diff --git a/apps/ensapi/src/handlers/ensanalytics-api.routes.ts b/apps/ensapi/src/handlers/ensanalytics-api.routes.ts index 9491ebd8b..57eeacdd1 100644 --- a/apps/ensapi/src/handlers/ensanalytics-api.routes.ts +++ b/apps/ensapi/src/handlers/ensanalytics-api.routes.ts @@ -33,6 +33,7 @@ const referrerAddressSchema = z.object({ export const getReferrerLeaderboardRoute = createRoute({ method: "get", path: "/referrers", + operationId: "getEnsanalyticsReferrers", tags: ["ENSAwards"], summary: "Get Referrer Leaderboard", description: "Returns a paginated page from the referrer leaderboard", @@ -52,6 +53,7 @@ export const getReferrerLeaderboardRoute = createRoute({ export const getReferrerDetailRoute = createRoute({ method: "get", path: "/referrers/{referrer}", + operationId: "getEnsanalyticsReferrers:referrer", tags: ["ENSAwards"], summary: "Get Referrer Detail", description: "Returns detailed information for a specific referrer by address", diff --git a/apps/ensapi/src/handlers/ensnode-api.routes.ts b/apps/ensapi/src/handlers/ensnode-api.routes.ts index be00913b6..a0d5fb3c3 100644 --- a/apps/ensapi/src/handlers/ensnode-api.routes.ts +++ b/apps/ensapi/src/handlers/ensnode-api.routes.ts @@ -11,6 +11,7 @@ export const basePath = "/api"; export const getConfigRoute = createRoute({ method: "get", path: "/config", + operationId: "getApiConfig", tags: ["Meta"], summary: "Get ENSApi Public Config", description: "Gets the public config of the ENSApi instance", @@ -29,6 +30,7 @@ export const getConfigRoute = createRoute({ export const getIndexingStatusRoute = createRoute({ method: "get", path: "/indexing-status", + operationId: "getApiIndexingStatus", tags: ["Meta"], summary: "Get ENSIndexer Indexing Status", description: "Returns the indexing status snapshot most recently captured from ENSIndexer", diff --git a/apps/ensapi/src/handlers/name-tokens-api.routes.ts b/apps/ensapi/src/handlers/name-tokens-api.routes.ts index f3a308c01..38fc2a9c5 100644 --- a/apps/ensapi/src/handlers/name-tokens-api.routes.ts +++ b/apps/ensapi/src/handlers/name-tokens-api.routes.ts @@ -31,6 +31,7 @@ export type NameTokensQuery = z.output; export const getNameTokensRoute = createRoute({ method: "get", path: "/", + operationId: "getApiName-tokens", tags: ["Explore"], summary: "Get Name Tokens", description: "Returns name tokens for the requested identifier (domainId or name)", diff --git a/apps/ensapi/src/handlers/registrar-actions-api.routes.ts b/apps/ensapi/src/handlers/registrar-actions-api.routes.ts index 23b448a4b..6ce165939 100644 --- a/apps/ensapi/src/handlers/registrar-actions-api.routes.ts +++ b/apps/ensapi/src/handlers/registrar-actions-api.routes.ts @@ -79,6 +79,7 @@ export type RegistrarActionsQuery = z.output export const getRegistrarActionsRoute = createRoute({ method: "get", path: "/", + operationId: "getApiRegistrar-actions", tags: ["Explore"], summary: "Get Registrar Actions", description: "Returns all registrar actions with optional filtering and pagination", @@ -101,6 +102,7 @@ export const getRegistrarActionsRoute = createRoute({ export const getRegistrarActionsByParentNodeRoute = createRoute({ method: "get", path: "/{parentNode}", + operationId: "getApiRegistrar-actions:parentNode", tags: ["Explore"], summary: "Get Registrar Actions by Parent Node", description: diff --git a/apps/ensapi/src/handlers/resolution-api.routes.ts b/apps/ensapi/src/handlers/resolution-api.routes.ts index dec45a409..4a311a838 100644 --- a/apps/ensapi/src/handlers/resolution-api.routes.ts +++ b/apps/ensapi/src/handlers/resolution-api.routes.ts @@ -8,6 +8,7 @@ export const basePath = "/api/resolve"; export const resolveRecordsRoute = createRoute({ method: "get", path: "/records/{name}", + operationId: "getApiResolveRecords:name", tags: ["Resolution"], summary: "Resolve ENS Records", description: "Resolves ENS records for a given name", @@ -37,6 +38,7 @@ export const resolveRecordsRoute = createRoute({ export const resolvePrimaryNameRoute = createRoute({ method: "get", path: "/primary-name/{address}/{chainId}", + operationId: "getApiResolvePrimary-name:address:chainId", tags: ["Resolution"], summary: "Resolve Primary Name", description: "Resolves a primary name for a given `address` and `chainId`", @@ -60,6 +62,7 @@ export const resolvePrimaryNameRoute = createRoute({ export const resolvePrimaryNamesRoute = createRoute({ method: "get", path: "/primary-names/{address}", + operationId: "getApiResolvePrimary-names:address", tags: ["Resolution"], summary: "Resolve Primary Names", description: "Resolves all primary names for a given address across multiple chains", From 4b5129f793e3d4d5c4337b81f4facdfb313a979a Mon Sep 17 00:00:00 2001 From: Jamie Barton Date: Thu, 26 Feb 2026 10:59:07 +0000 Subject: [PATCH 04/10] add missing propertyames --- .../src/handlers/resolution-api.routes.ts | 21 +++++++ .../src/ensapi/api/resolution/zod-schemas.ts | 14 ++++- .../omnichain-indexing-status-snapshot.ts | 63 +++++++++++-------- packages/ensnode-sdk/src/shared/zod-types.ts | 10 +++ 4 files changed, 80 insertions(+), 28 deletions(-) diff --git a/apps/ensapi/src/handlers/resolution-api.routes.ts b/apps/ensapi/src/handlers/resolution-api.routes.ts index 4a311a838..315a67da1 100644 --- a/apps/ensapi/src/handlers/resolution-api.routes.ts +++ b/apps/ensapi/src/handlers/resolution-api.routes.ts @@ -1,6 +1,12 @@ import { createRoute } from "@hono/zod-openapi"; import { z } from "zod/v4"; +import { + makeResolvePrimaryNameResponseSchema, + makeResolvePrimaryNamesResponseSchema, + makeResolveRecordsResponseSchema, +} from "@ensnode/ensnode-sdk/internal"; + import { params } from "@/lib/handlers/params.schema"; export const basePath = "/api/resolve"; @@ -31,6 +37,11 @@ export const resolveRecordsRoute = createRoute({ responses: { 200: { description: "Successfully resolved records", + content: { + "application/json": { + schema: makeResolveRecordsResponseSchema(), + }, + }, }, }, }); @@ -55,6 +66,11 @@ export const resolvePrimaryNameRoute = createRoute({ responses: { 200: { description: "Successfully resolved name", + content: { + "application/json": { + schema: makeResolvePrimaryNameResponseSchema(), + }, + }, }, }, }); @@ -79,6 +95,11 @@ export const resolvePrimaryNamesRoute = createRoute({ responses: { 200: { description: "Successfully resolved records", + content: { + "application/json": { + schema: makeResolvePrimaryNamesResponseSchema(), + }, + }, }, }, }); diff --git a/packages/ensnode-sdk/src/ensapi/api/resolution/zod-schemas.ts b/packages/ensnode-sdk/src/ensapi/api/resolution/zod-schemas.ts index e3efbec67..8b24e286a 100644 --- a/packages/ensnode-sdk/src/ensapi/api/resolution/zod-schemas.ts +++ b/packages/ensnode-sdk/src/ensapi/api/resolution/zod-schemas.ts @@ -1,13 +1,19 @@ import { z } from "zod/v4"; +import { withOpenApi } from "../../../shared/zod-types"; + /** * Schema for resolver records response (addresses, texts, name) */ const makeResolverRecordsResponseSchema = () => z.object({ name: z.string().nullable().optional(), - addresses: z.record(z.string(), z.string().nullable()).optional(), - texts: z.record(z.string(), z.string().nullable()).optional(), + addresses: withOpenApi(z.record(z.string(), z.string().nullable()), { + propertyNames: { type: "string" }, + }).optional(), + texts: withOpenApi(z.record(z.string(), z.string().nullable()), { + propertyNames: { type: "string" }, + }).optional(), }); /** @@ -38,7 +44,9 @@ export const makeResolvePrimaryNameResponseSchema = () => */ export const makeResolvePrimaryNamesResponseSchema = () => z.object({ - names: z.record(z.number(), z.string().nullable()), + names: withOpenApi(z.record(z.number(), z.string().nullable()), { + propertyNames: { type: "number" }, + }), accelerationRequested: z.boolean(), accelerationAttempted: z.boolean(), trace: z.array(z.unknown()).optional(), diff --git a/packages/ensnode-sdk/src/indexing-status/zod-schema/omnichain-indexing-status-snapshot.ts b/packages/ensnode-sdk/src/indexing-status/zod-schema/omnichain-indexing-status-snapshot.ts index 971664459..de36bded9 100644 --- a/packages/ensnode-sdk/src/indexing-status/zod-schema/omnichain-indexing-status-snapshot.ts +++ b/packages/ensnode-sdk/src/indexing-status/zod-schema/omnichain-indexing-status-snapshot.ts @@ -6,6 +6,7 @@ import { makeChainIdStringSchema, makeUnixTimestampSchema, } from "../../shared/zod-schemas"; +import { withOpenApi } from "../../shared/zod-types"; import { ChainIndexingStatusIds } from "../chain-indexing-status-snapshot"; import { checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotBackfill, @@ -375,11 +376,14 @@ export const makeOmnichainIndexingStatusSnapshotSchema = ( const makeSerializedOmnichainIndexingStatusSnapshotUnstartedSchema = (valueLabel?: string) => z.object({ omnichainStatus: z.literal(OmnichainIndexingStatusIds.Unstarted), - chains: z.record( - makeChainIdStringSchema(), - z.discriminatedUnion("chainStatus", [ - makeChainIndexingStatusSnapshotQueuedSchema(valueLabel), - ]), + chains: withOpenApi( + z.record( + makeChainIdStringSchema(), + z.discriminatedUnion("chainStatus", [ + makeChainIndexingStatusSnapshotQueuedSchema(valueLabel), + ]), + ), + { propertyNames: { type: "string" } }, ), omnichainIndexingCursor: makeUnixTimestampSchema(valueLabel), }); @@ -390,13 +394,16 @@ const makeSerializedOmnichainIndexingStatusSnapshotUnstartedSchema = (valueLabel const makeSerializedOmnichainIndexingStatusSnapshotBackfillSchema = (valueLabel?: string) => z.object({ omnichainStatus: z.literal(OmnichainIndexingStatusIds.Backfill), - chains: z.record( - makeChainIdStringSchema(), - z.discriminatedUnion("chainStatus", [ - makeChainIndexingStatusSnapshotQueuedSchema(valueLabel), - makeChainIndexingStatusSnapshotBackfillSchema(valueLabel), - makeChainIndexingStatusSnapshotCompletedSchema(valueLabel), - ]), + chains: withOpenApi( + z.record( + makeChainIdStringSchema(), + z.discriminatedUnion("chainStatus", [ + makeChainIndexingStatusSnapshotQueuedSchema(valueLabel), + makeChainIndexingStatusSnapshotBackfillSchema(valueLabel), + makeChainIndexingStatusSnapshotCompletedSchema(valueLabel), + ]), + ), + { propertyNames: { type: "string" } }, ), omnichainIndexingCursor: makeUnixTimestampSchema(valueLabel), }); @@ -407,11 +414,14 @@ const makeSerializedOmnichainIndexingStatusSnapshotBackfillSchema = (valueLabel? const makeSerializedOmnichainIndexingStatusSnapshotCompletedSchema = (valueLabel?: string) => z.object({ omnichainStatus: z.literal(OmnichainIndexingStatusIds.Completed), - chains: z.record( - makeChainIdStringSchema(), - z.discriminatedUnion("chainStatus", [ - makeChainIndexingStatusSnapshotCompletedSchema(valueLabel), - ]), + chains: withOpenApi( + z.record( + makeChainIdStringSchema(), + z.discriminatedUnion("chainStatus", [ + makeChainIndexingStatusSnapshotCompletedSchema(valueLabel), + ]), + ), + { propertyNames: { type: "string" } }, ), omnichainIndexingCursor: makeUnixTimestampSchema(valueLabel), }); @@ -422,14 +432,17 @@ const makeSerializedOmnichainIndexingStatusSnapshotCompletedSchema = (valueLabel const makeSerializedOmnichainIndexingStatusSnapshotFollowingSchema = (valueLabel?: string) => z.object({ omnichainStatus: z.literal(OmnichainIndexingStatusIds.Following), - chains: z.record( - makeChainIdStringSchema(), - z.discriminatedUnion("chainStatus", [ - makeChainIndexingStatusSnapshotQueuedSchema(valueLabel), - makeChainIndexingStatusSnapshotBackfillSchema(valueLabel), - makeChainIndexingStatusSnapshotFollowingSchema(valueLabel), - makeChainIndexingStatusSnapshotCompletedSchema(valueLabel), - ]), + chains: withOpenApi( + z.record( + makeChainIdStringSchema(), + z.discriminatedUnion("chainStatus", [ + makeChainIndexingStatusSnapshotQueuedSchema(valueLabel), + makeChainIndexingStatusSnapshotBackfillSchema(valueLabel), + makeChainIndexingStatusSnapshotFollowingSchema(valueLabel), + makeChainIndexingStatusSnapshotCompletedSchema(valueLabel), + ]), + ), + { propertyNames: { type: "string" } }, ), omnichainIndexingCursor: makeUnixTimestampSchema(valueLabel), }); diff --git a/packages/ensnode-sdk/src/shared/zod-types.ts b/packages/ensnode-sdk/src/shared/zod-types.ts index 166c95a89..acabe6b82 100644 --- a/packages/ensnode-sdk/src/shared/zod-types.ts +++ b/packages/ensnode-sdk/src/shared/zod-types.ts @@ -4,3 +4,13 @@ import type { z } from "zod/v4"; * Zod `.check()` function input. */ export type ZodCheckFnInput = z.core.ParsePayload; + +/** + * Adds additional JSON Schema properties to a zod schema via the `.openapi()` + * extension provided by `@asteasolutions/zod-to-openapi`. The prototype method + * is available at runtime when `@hono/zod-openapi` is imported (which patches + * `ZodType.prototype`), but is not reflected in the `zod/v4` types — hence the + * cast. + */ +export const withOpenApi = (schema: T, metadata: Record): T => + (schema as any).openapi(metadata); From 7249a915fb660aca191a01ef354d31430f68018c Mon Sep 17 00:00:00 2001 From: Jamie Barton Date: Thu, 26 Feb 2026 11:31:25 +0000 Subject: [PATCH 05/10] move out of runtime --- apps/ensapi/src/index.ts | 16 ++++++++-------- .../src/ensapi/api/resolution/zod-schemas.ts | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/ensapi/src/index.ts b/apps/ensapi/src/index.ts index 230fa2b0b..1abcbe682 100644 --- a/apps/ensapi/src/index.ts +++ b/apps/ensapi/src/index.ts @@ -77,15 +77,15 @@ app.route("/amirealtime", amIRealtimeApi); // use OpenAPI Schema generated from zod-openapi route definitions const stubApp = createStubRoutesForSpec(); +const openApi31Document = stubApp.getOpenAPI31Document({ + ...openapiMeta, + servers: [ + ...openapiMeta.servers, + { url: `http://localhost:${config.port}`, description: "Local Development" }, + ], +}); app.get("/openapi.json", (c) => { - const doc = stubApp.getOpenAPI31Document({ - ...openapiMeta, - servers: [ - ...openapiMeta.servers, - { url: `http://localhost:${config.port}`, description: "Local Development" }, - ], - }); - return c.json(doc); + return c.json(openApi31Document); }); // will automatically 503 if config is not available due to ensIndexerPublicConfigMiddleware diff --git a/packages/ensnode-sdk/src/ensapi/api/resolution/zod-schemas.ts b/packages/ensnode-sdk/src/ensapi/api/resolution/zod-schemas.ts index 8b24e286a..a766ed459 100644 --- a/packages/ensnode-sdk/src/ensapi/api/resolution/zod-schemas.ts +++ b/packages/ensnode-sdk/src/ensapi/api/resolution/zod-schemas.ts @@ -45,7 +45,7 @@ export const makeResolvePrimaryNameResponseSchema = () => export const makeResolvePrimaryNamesResponseSchema = () => z.object({ names: withOpenApi(z.record(z.number(), z.string().nullable()), { - propertyNames: { type: "number" }, + propertyNames: { type: "string", pattern: "^[0-9]+$" }, }), accelerationRequested: z.boolean(), accelerationAttempted: z.boolean(), From c95987bcdcc30b16ad7435924c5a91624814a499 Mon Sep 17 00:00:00 2001 From: Jamie Barton Date: Thu, 26 Feb 2026 13:15:37 +0000 Subject: [PATCH 06/10] remove redundant property names --- .../src/ensapi/api/resolution/zod-schemas.ts | 8 +-- .../omnichain-indexing-status-snapshot.ts | 63 ++++++++----------- 2 files changed, 27 insertions(+), 44 deletions(-) diff --git a/packages/ensnode-sdk/src/ensapi/api/resolution/zod-schemas.ts b/packages/ensnode-sdk/src/ensapi/api/resolution/zod-schemas.ts index a766ed459..f68db7fbc 100644 --- a/packages/ensnode-sdk/src/ensapi/api/resolution/zod-schemas.ts +++ b/packages/ensnode-sdk/src/ensapi/api/resolution/zod-schemas.ts @@ -8,12 +8,8 @@ import { withOpenApi } from "../../../shared/zod-types"; const makeResolverRecordsResponseSchema = () => z.object({ name: z.string().nullable().optional(), - addresses: withOpenApi(z.record(z.string(), z.string().nullable()), { - propertyNames: { type: "string" }, - }).optional(), - texts: withOpenApi(z.record(z.string(), z.string().nullable()), { - propertyNames: { type: "string" }, - }).optional(), + addresses: z.record(z.string(), z.string().nullable()).optional(), + texts: z.record(z.string(), z.string().nullable()).optional(), }); /** diff --git a/packages/ensnode-sdk/src/indexing-status/zod-schema/omnichain-indexing-status-snapshot.ts b/packages/ensnode-sdk/src/indexing-status/zod-schema/omnichain-indexing-status-snapshot.ts index de36bded9..971664459 100644 --- a/packages/ensnode-sdk/src/indexing-status/zod-schema/omnichain-indexing-status-snapshot.ts +++ b/packages/ensnode-sdk/src/indexing-status/zod-schema/omnichain-indexing-status-snapshot.ts @@ -6,7 +6,6 @@ import { makeChainIdStringSchema, makeUnixTimestampSchema, } from "../../shared/zod-schemas"; -import { withOpenApi } from "../../shared/zod-types"; import { ChainIndexingStatusIds } from "../chain-indexing-status-snapshot"; import { checkChainIndexingStatusSnapshotsForOmnichainStatusSnapshotBackfill, @@ -376,14 +375,11 @@ export const makeOmnichainIndexingStatusSnapshotSchema = ( const makeSerializedOmnichainIndexingStatusSnapshotUnstartedSchema = (valueLabel?: string) => z.object({ omnichainStatus: z.literal(OmnichainIndexingStatusIds.Unstarted), - chains: withOpenApi( - z.record( - makeChainIdStringSchema(), - z.discriminatedUnion("chainStatus", [ - makeChainIndexingStatusSnapshotQueuedSchema(valueLabel), - ]), - ), - { propertyNames: { type: "string" } }, + chains: z.record( + makeChainIdStringSchema(), + z.discriminatedUnion("chainStatus", [ + makeChainIndexingStatusSnapshotQueuedSchema(valueLabel), + ]), ), omnichainIndexingCursor: makeUnixTimestampSchema(valueLabel), }); @@ -394,16 +390,13 @@ const makeSerializedOmnichainIndexingStatusSnapshotUnstartedSchema = (valueLabel const makeSerializedOmnichainIndexingStatusSnapshotBackfillSchema = (valueLabel?: string) => z.object({ omnichainStatus: z.literal(OmnichainIndexingStatusIds.Backfill), - chains: withOpenApi( - z.record( - makeChainIdStringSchema(), - z.discriminatedUnion("chainStatus", [ - makeChainIndexingStatusSnapshotQueuedSchema(valueLabel), - makeChainIndexingStatusSnapshotBackfillSchema(valueLabel), - makeChainIndexingStatusSnapshotCompletedSchema(valueLabel), - ]), - ), - { propertyNames: { type: "string" } }, + chains: z.record( + makeChainIdStringSchema(), + z.discriminatedUnion("chainStatus", [ + makeChainIndexingStatusSnapshotQueuedSchema(valueLabel), + makeChainIndexingStatusSnapshotBackfillSchema(valueLabel), + makeChainIndexingStatusSnapshotCompletedSchema(valueLabel), + ]), ), omnichainIndexingCursor: makeUnixTimestampSchema(valueLabel), }); @@ -414,14 +407,11 @@ const makeSerializedOmnichainIndexingStatusSnapshotBackfillSchema = (valueLabel? const makeSerializedOmnichainIndexingStatusSnapshotCompletedSchema = (valueLabel?: string) => z.object({ omnichainStatus: z.literal(OmnichainIndexingStatusIds.Completed), - chains: withOpenApi( - z.record( - makeChainIdStringSchema(), - z.discriminatedUnion("chainStatus", [ - makeChainIndexingStatusSnapshotCompletedSchema(valueLabel), - ]), - ), - { propertyNames: { type: "string" } }, + chains: z.record( + makeChainIdStringSchema(), + z.discriminatedUnion("chainStatus", [ + makeChainIndexingStatusSnapshotCompletedSchema(valueLabel), + ]), ), omnichainIndexingCursor: makeUnixTimestampSchema(valueLabel), }); @@ -432,17 +422,14 @@ const makeSerializedOmnichainIndexingStatusSnapshotCompletedSchema = (valueLabel const makeSerializedOmnichainIndexingStatusSnapshotFollowingSchema = (valueLabel?: string) => z.object({ omnichainStatus: z.literal(OmnichainIndexingStatusIds.Following), - chains: withOpenApi( - z.record( - makeChainIdStringSchema(), - z.discriminatedUnion("chainStatus", [ - makeChainIndexingStatusSnapshotQueuedSchema(valueLabel), - makeChainIndexingStatusSnapshotBackfillSchema(valueLabel), - makeChainIndexingStatusSnapshotFollowingSchema(valueLabel), - makeChainIndexingStatusSnapshotCompletedSchema(valueLabel), - ]), - ), - { propertyNames: { type: "string" } }, + chains: z.record( + makeChainIdStringSchema(), + z.discriminatedUnion("chainStatus", [ + makeChainIndexingStatusSnapshotQueuedSchema(valueLabel), + makeChainIndexingStatusSnapshotBackfillSchema(valueLabel), + makeChainIndexingStatusSnapshotFollowingSchema(valueLabel), + makeChainIndexingStatusSnapshotCompletedSchema(valueLabel), + ]), ), omnichainIndexingCursor: makeUnixTimestampSchema(valueLabel), }); From 6e3222832d6fa906d923d654ee8729917e6ef3aa Mon Sep 17 00:00:00 2001 From: Jamie Barton Date: Thu, 26 Feb 2026 13:26:24 +0000 Subject: [PATCH 07/10] simplify logic --- apps/ensapi/src/index.ts | 16 +++---- .../{stub-routes.ts => openapi-document.ts} | 44 +++++++++++++------ .../src/ensapi/api/resolution/zod-schemas.ts | 6 +-- packages/ensnode-sdk/src/shared/zod-types.ts | 10 ----- 4 files changed, 36 insertions(+), 40 deletions(-) rename apps/ensapi/src/{stub-routes.ts => openapi-document.ts} (52%) diff --git a/apps/ensapi/src/index.ts b/apps/ensapi/src/index.ts index 1abcbe682..87fdcb2a1 100644 --- a/apps/ensapi/src/index.ts +++ b/apps/ensapi/src/index.ts @@ -16,8 +16,7 @@ import { factory } from "@/lib/hono-factory"; import { sdk } from "@/lib/instrumentation"; import logger from "@/lib/logger"; import { indexingStatusMiddleware } from "@/middleware/indexing-status.middleware"; -import { openapiMeta } from "@/openapi-meta"; -import { createStubRoutesForSpec } from "@/stub-routes"; +import { generateOpenApi31Document } from "@/openapi-document"; import amIRealtimeApi from "./handlers/amirealtime-api"; import ensanalyticsApi from "./handlers/ensanalytics-api"; @@ -75,15 +74,10 @@ app.route("/v1/ensanalytics", ensanalyticsApiV1); // use Am I Realtime API at /amirealtime app.route("/amirealtime", amIRealtimeApi); -// use OpenAPI Schema generated from zod-openapi route definitions -const stubApp = createStubRoutesForSpec(); -const openApi31Document = stubApp.getOpenAPI31Document({ - ...openapiMeta, - servers: [ - ...openapiMeta.servers, - { url: `http://localhost:${config.port}`, description: "Local Development" }, - ], -}); +// serve pre-generated OpenAPI 3.1 document +const openApi31Document = generateOpenApi31Document([ + { url: `http://localhost:${config.port}`, description: "Local Development" }, +]); app.get("/openapi.json", (c) => { return c.json(openApi31Document); }); diff --git a/apps/ensapi/src/stub-routes.ts b/apps/ensapi/src/openapi-document.ts similarity index 52% rename from apps/ensapi/src/stub-routes.ts rename to apps/ensapi/src/openapi-document.ts index 623748531..e1e26dc7c 100644 --- a/apps/ensapi/src/stub-routes.ts +++ b/apps/ensapi/src/openapi-document.ts @@ -1,5 +1,7 @@ import { OpenAPIHono } from "@hono/zod-openapi"; +import { openapiMeta } from "@/openapi-meta"; + import * as amIRealtimeRoutes from "./handlers/amirealtime-api.routes"; import * as ensanalyticsRoutes from "./handlers/ensanalytics-api.routes"; import * as ensanalyticsV1Routes from "./handlers/ensanalytics-api-v1.routes"; @@ -8,24 +10,24 @@ import * as nameTokensRoutes from "./handlers/name-tokens-api.routes"; import * as registrarActionsRoutes from "./handlers/registrar-actions-api.routes"; import * as resolutionRoutes from "./handlers/resolution-api.routes"; +const routeGroups = [ + amIRealtimeRoutes, + ensnodeRoutes, + ensanalyticsV1Routes, + ensanalyticsRoutes, + nameTokensRoutes, + registrarActionsRoutes, + resolutionRoutes, +]; + /** - * Creates an OpenAPIHono app with all route definitions registered using stub handlers. - * This allows generating the OpenAPI spec without importing any handler code that - * depends on config/env vars. + * Creates an OpenAPIHono app with all route definitions registered using stub + * handlers. This allows generating the OpenAPI spec without importing any + * handler code that depends on config/env vars. */ -export function createStubRoutesForSpec() { +function createStubRoutesForSpec() { const app = new OpenAPIHono(); - const routeGroups = [ - amIRealtimeRoutes, - ensnodeRoutes, - ensanalyticsV1Routes, - ensanalyticsRoutes, - nameTokensRoutes, - registrarActionsRoutes, - resolutionRoutes, - ]; - for (const group of routeGroups) { for (const route of group.routes) { const path = route.path === "/" ? group.basePath : `${group.basePath}${route.path}`; @@ -39,3 +41,17 @@ export function createStubRoutesForSpec() { return app; } + +/** + * 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 { + return createStubRoutesForSpec().getOpenAPI31Document({ + ...openapiMeta, + servers: [...openapiMeta.servers, ...additionalServers], + }); +} diff --git a/packages/ensnode-sdk/src/ensapi/api/resolution/zod-schemas.ts b/packages/ensnode-sdk/src/ensapi/api/resolution/zod-schemas.ts index f68db7fbc..e3efbec67 100644 --- a/packages/ensnode-sdk/src/ensapi/api/resolution/zod-schemas.ts +++ b/packages/ensnode-sdk/src/ensapi/api/resolution/zod-schemas.ts @@ -1,7 +1,5 @@ import { z } from "zod/v4"; -import { withOpenApi } from "../../../shared/zod-types"; - /** * Schema for resolver records response (addresses, texts, name) */ @@ -40,9 +38,7 @@ export const makeResolvePrimaryNameResponseSchema = () => */ export const makeResolvePrimaryNamesResponseSchema = () => z.object({ - names: withOpenApi(z.record(z.number(), z.string().nullable()), { - propertyNames: { type: "string", pattern: "^[0-9]+$" }, - }), + names: z.record(z.number(), z.string().nullable()), accelerationRequested: z.boolean(), accelerationAttempted: z.boolean(), trace: z.array(z.unknown()).optional(), diff --git a/packages/ensnode-sdk/src/shared/zod-types.ts b/packages/ensnode-sdk/src/shared/zod-types.ts index acabe6b82..166c95a89 100644 --- a/packages/ensnode-sdk/src/shared/zod-types.ts +++ b/packages/ensnode-sdk/src/shared/zod-types.ts @@ -4,13 +4,3 @@ import type { z } from "zod/v4"; * Zod `.check()` function input. */ export type ZodCheckFnInput = z.core.ParsePayload; - -/** - * Adds additional JSON Schema properties to a zod schema via the `.openapi()` - * extension provided by `@asteasolutions/zod-to-openapi`. The prototype method - * is available at runtime when `@hono/zod-openapi` is imported (which patches - * `ZodType.prototype`), but is not reflected in the `zod/v4` types — hence the - * cast. - */ -export const withOpenApi = (schema: T, metadata: Record): T => - (schema as any).openapi(metadata); From 475a50d88d58832eb758c9032fd2f32762fead89 Mon Sep 17 00:00:00 2001 From: Jamie Barton Date: Thu, 26 Feb 2026 13:30:01 +0000 Subject: [PATCH 08/10] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- apps/ensapi/src/handlers/name-tokens-api.routes.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/ensapi/src/handlers/name-tokens-api.routes.ts b/apps/ensapi/src/handlers/name-tokens-api.routes.ts index 38fc2a9c5..c74b0aabb 100644 --- a/apps/ensapi/src/handlers/name-tokens-api.routes.ts +++ b/apps/ensapi/src/handlers/name-tokens-api.routes.ts @@ -31,7 +31,7 @@ export type NameTokensQuery = z.output; export const getNameTokensRoute = createRoute({ method: "get", path: "/", - operationId: "getApiName-tokens", + operationId: "getApiNameTokens", tags: ["Explore"], summary: "Get Name Tokens", description: "Returns name tokens for the requested identifier (domainId or name)", From 4da11f4fdebb3e405ee78b3cf9d2f564e98462a8 Mon Sep 17 00:00:00 2001 From: Jamie Barton Date: Thu, 26 Feb 2026 13:44:11 +0000 Subject: [PATCH 09/10] address operationId suggestions --- apps/ensapi/src/handlers/amirealtime-api.routes.ts | 2 +- apps/ensapi/src/handlers/ensanalytics-api-v1.routes.ts | 6 +++--- apps/ensapi/src/handlers/ensanalytics-api.routes.ts | 4 ++-- apps/ensapi/src/handlers/ensnode-api.routes.ts | 4 ++-- apps/ensapi/src/handlers/name-tokens-api.routes.ts | 2 +- apps/ensapi/src/handlers/registrar-actions-api.routes.ts | 4 ++-- apps/ensapi/src/handlers/resolution-api.routes.ts | 6 +++--- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/apps/ensapi/src/handlers/amirealtime-api.routes.ts b/apps/ensapi/src/handlers/amirealtime-api.routes.ts index 9a731d8d1..3d379aa83 100644 --- a/apps/ensapi/src/handlers/amirealtime-api.routes.ts +++ b/apps/ensapi/src/handlers/amirealtime-api.routes.ts @@ -15,7 +15,7 @@ export const AMIREALTIME_DEFAULT_MAX_WORST_CASE_DISTANCE: Duration = minutesToSe export const amIRealtimeGetMeta = createRoute({ method: "get", path: "/", - operationId: "getAmirealtime", + operationId: "isRealtime", tags: ["Meta"], summary: "Check indexing progress", description: diff --git a/apps/ensapi/src/handlers/ensanalytics-api-v1.routes.ts b/apps/ensapi/src/handlers/ensanalytics-api-v1.routes.ts index 12167551e..492495075 100644 --- a/apps/ensapi/src/handlers/ensanalytics-api-v1.routes.ts +++ b/apps/ensapi/src/handlers/ensanalytics-api-v1.routes.ts @@ -53,7 +53,7 @@ const editionsQuerySchema = z.object({ export const getReferralLeaderboardRoute = createRoute({ method: "get", path: "/referral-leaderboard", - operationId: "getV1EnsanalyticsReferralLeaderboard", + operationId: "getReferralLeaderboard_v1", tags: ["ENSAwards"], summary: "Get Referrer Leaderboard (v1)", description: "Returns a paginated page from the referrer leaderboard for a specific edition", @@ -79,7 +79,7 @@ export const getReferralLeaderboardRoute = createRoute({ export const getReferrerDetailRoute = createRoute({ method: "get", path: "/referrer/{referrer}", - operationId: "getV1EnsanalyticsReferrerDetail", + operationId: "getReferrerDetail_v1", tags: ["ENSAwards"], summary: "Get Referrer Detail for Editions (v1)", description: `Returns detailed information for a specific referrer for the requested editions. Requires 1-${MAX_EDITIONS_PER_REQUEST} distinct edition slugs. All requested editions must be recognized and have cached data, or the request fails.`, @@ -109,7 +109,7 @@ export const getReferrerDetailRoute = createRoute({ export const getEditionsRoute = createRoute({ method: "get", path: "/editions", - operationId: "getV1EnsanalyticsEditions", + operationId: "getEditions_v1", tags: ["ENSAwards"], summary: "Get Edition Config Set (v1)", description: diff --git a/apps/ensapi/src/handlers/ensanalytics-api.routes.ts b/apps/ensapi/src/handlers/ensanalytics-api.routes.ts index 57eeacdd1..e331f635b 100644 --- a/apps/ensapi/src/handlers/ensanalytics-api.routes.ts +++ b/apps/ensapi/src/handlers/ensanalytics-api.routes.ts @@ -33,7 +33,7 @@ const referrerAddressSchema = z.object({ export const getReferrerLeaderboardRoute = createRoute({ method: "get", path: "/referrers", - operationId: "getEnsanalyticsReferrers", + operationId: "getReferrerLeaderboard", tags: ["ENSAwards"], summary: "Get Referrer Leaderboard", description: "Returns a paginated page from the referrer leaderboard", @@ -53,7 +53,7 @@ export const getReferrerLeaderboardRoute = createRoute({ export const getReferrerDetailRoute = createRoute({ method: "get", path: "/referrers/{referrer}", - operationId: "getEnsanalyticsReferrers:referrer", + operationId: "getReferrerDetail", tags: ["ENSAwards"], summary: "Get Referrer Detail", description: "Returns detailed information for a specific referrer by address", diff --git a/apps/ensapi/src/handlers/ensnode-api.routes.ts b/apps/ensapi/src/handlers/ensnode-api.routes.ts index a0d5fb3c3..a8487d385 100644 --- a/apps/ensapi/src/handlers/ensnode-api.routes.ts +++ b/apps/ensapi/src/handlers/ensnode-api.routes.ts @@ -11,7 +11,7 @@ export const basePath = "/api"; export const getConfigRoute = createRoute({ method: "get", path: "/config", - operationId: "getApiConfig", + operationId: "getConfig", tags: ["Meta"], summary: "Get ENSApi Public Config", description: "Gets the public config of the ENSApi instance", @@ -30,7 +30,7 @@ export const getConfigRoute = createRoute({ export const getIndexingStatusRoute = createRoute({ method: "get", path: "/indexing-status", - operationId: "getApiIndexingStatus", + operationId: "getIndexingStatus", tags: ["Meta"], summary: "Get ENSIndexer Indexing Status", description: "Returns the indexing status snapshot most recently captured from ENSIndexer", diff --git a/apps/ensapi/src/handlers/name-tokens-api.routes.ts b/apps/ensapi/src/handlers/name-tokens-api.routes.ts index c74b0aabb..e15d9a4fa 100644 --- a/apps/ensapi/src/handlers/name-tokens-api.routes.ts +++ b/apps/ensapi/src/handlers/name-tokens-api.routes.ts @@ -31,7 +31,7 @@ export type NameTokensQuery = z.output; export const getNameTokensRoute = createRoute({ method: "get", path: "/", - operationId: "getApiNameTokens", + operationId: "getNameTokens", tags: ["Explore"], summary: "Get Name Tokens", description: "Returns name tokens for the requested identifier (domainId or name)", diff --git a/apps/ensapi/src/handlers/registrar-actions-api.routes.ts b/apps/ensapi/src/handlers/registrar-actions-api.routes.ts index 6ce165939..3b28b2aec 100644 --- a/apps/ensapi/src/handlers/registrar-actions-api.routes.ts +++ b/apps/ensapi/src/handlers/registrar-actions-api.routes.ts @@ -79,7 +79,7 @@ export type RegistrarActionsQuery = z.output export const getRegistrarActionsRoute = createRoute({ method: "get", path: "/", - operationId: "getApiRegistrar-actions", + operationId: "getRegistrarActions", tags: ["Explore"], summary: "Get Registrar Actions", description: "Returns all registrar actions with optional filtering and pagination", @@ -102,7 +102,7 @@ export const getRegistrarActionsRoute = createRoute({ export const getRegistrarActionsByParentNodeRoute = createRoute({ method: "get", path: "/{parentNode}", - operationId: "getApiRegistrar-actions:parentNode", + operationId: "getRegistrarActionsByParentNode", tags: ["Explore"], summary: "Get Registrar Actions by Parent Node", description: diff --git a/apps/ensapi/src/handlers/resolution-api.routes.ts b/apps/ensapi/src/handlers/resolution-api.routes.ts index 315a67da1..1af335aeb 100644 --- a/apps/ensapi/src/handlers/resolution-api.routes.ts +++ b/apps/ensapi/src/handlers/resolution-api.routes.ts @@ -14,7 +14,7 @@ export const basePath = "/api/resolve"; export const resolveRecordsRoute = createRoute({ method: "get", path: "/records/{name}", - operationId: "getApiResolveRecords:name", + operationId: "resolveRecords", tags: ["Resolution"], summary: "Resolve ENS Records", description: "Resolves ENS records for a given name", @@ -49,7 +49,7 @@ export const resolveRecordsRoute = createRoute({ export const resolvePrimaryNameRoute = createRoute({ method: "get", path: "/primary-name/{address}/{chainId}", - operationId: "getApiResolvePrimary-name:address:chainId", + operationId: "resolvePrimaryName", tags: ["Resolution"], summary: "Resolve Primary Name", description: "Resolves a primary name for a given `address` and `chainId`", @@ -78,7 +78,7 @@ export const resolvePrimaryNameRoute = createRoute({ export const resolvePrimaryNamesRoute = createRoute({ method: "get", path: "/primary-names/{address}", - operationId: "getApiResolvePrimary-names:address", + operationId: "resolvePrimaryNames", tags: ["Resolution"], summary: "Resolve Primary Names", description: "Resolves all primary names for a given address across multiple chains", From c6f77af34f0123a01b3db377d7f12f4f0e561b4e Mon Sep 17 00:00:00 2001 From: Jamie Barton Date: Thu, 26 Feb 2026 20:18:28 +0000 Subject: [PATCH 10/10] chore: update lock --- pnpm-lock.yaml | 169 ------------------------------------------------- 1 file changed, 169 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d03037e73..66b140997 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -324,9 +324,6 @@ importers: '@hono/otel': specifier: ^0.2.2 version: 0.2.2(hono@4.12.2) - '@hono/standard-validator': - specifier: ^0.2.2 - version: 0.2.2(@standard-schema/spec@1.0.0)(hono@4.12.2) '@hono/zod-openapi': specifier: ^1.2.2 version: 1.2.2(hono@4.12.2)(zod@4.3.6) @@ -399,9 +396,6 @@ importers: hono: specifier: 'catalog:' version: 4.12.2 - hono-openapi: - specifier: ^1.1.2 - version: 1.1.2(@hono/standard-validator@0.2.2(@standard-schema/spec@1.0.0)(hono@4.12.2))(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.0.0)(@types/json-schema@7.0.15)(arktype@2.1.29)(quansync@0.2.11)(zod-to-json-schema@3.24.6(zod@4.3.6))(zod@4.3.6))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.0.0)(@types/json-schema@7.0.15)(arktype@2.1.29)(quansync@0.2.11)(zod-to-json-schema@3.24.6(zod@4.3.6))(zod@4.3.6))(@standard-schema/spec@1.0.0)(arktype@2.1.29)(openapi-types@12.1.3)(zod@4.3.6))(@types/json-schema@7.0.15)(hono@4.12.2)(openapi-types@12.1.3) p-memoize: specifier: ^8.0.0 version: 8.0.0 @@ -1156,12 +1150,6 @@ packages: '@antfu/utils@9.3.0': resolution: {integrity: sha512-9hFT4RauhcUzqOE4f1+frMKLZrgNog5b06I7VmZQV1BkvwvqrbC8EBZf3L1eEL2AKb6rNKjER0sEvJiSP1FXEA==} - '@ark/schema@0.56.0': - resolution: {integrity: sha512-ECg3hox/6Z/nLajxXqNhgPtNdHWC9zNsDyskwO28WinoFEnWow4IsERNz9AnXRhTZJnYIlAJ4uGn3nlLk65vZA==} - - '@ark/util@0.56.0': - resolution: {integrity: sha512-BghfRC8b9pNs3vBoDJhcta0/c1J1rsoS1+HgVUreMFPdhz/CRAKReAu57YEllNaSy98rWAdY1gE+gFup7OXpgA==} - '@asamuzakjp/css-color@4.0.5': resolution: {integrity: sha512-lMrXidNhPGsDjytDy11Vwlb6OIGrT3CmLg3VWNFyWkLWtijKl7xjvForlh8vuj0SHGjgl4qZEQzUmYTeQA2JFQ==} @@ -2241,12 +2229,6 @@ packages: peerDependencies: hono: '*' - '@hono/standard-validator@0.2.2': - resolution: {integrity: sha512-mJ7W84Bt/rSvoIl63Ynew+UZOHAzzRAoAXb3JaWuxAkM/Lzg+ZHTCUiz77KOtn2e623WNN8LkD57Dk0szqUrIw==} - peerDependencies: - '@standard-schema/spec': ^1.0.0 - hono: '>=3.9.0' - '@hono/zod-openapi@1.2.2': resolution: {integrity: sha512-va6vsL23wCJ1d0Vd+vGL1XOt+wPwItxirYafuhlW9iC2MstYr2FvsI7mctb45eBTjZfkqB/3LYDJEppPjOEiHw==} engines: {node: '>=16.0.0'} @@ -3859,67 +3841,6 @@ packages: resolution: {integrity: sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw==} engines: {node: '>=18.0.0'} - '@standard-community/standard-json@0.3.5': - resolution: {integrity: sha512-4+ZPorwDRt47i+O7RjyuaxHRK/37QY/LmgxlGrRrSTLYoFatEOzvqIc85GTlM18SFZ5E91C+v0o/M37wZPpUHA==} - peerDependencies: - '@standard-schema/spec': ^1.0.0 - '@types/json-schema': ^7.0.15 - '@valibot/to-json-schema': ^1.3.0 - arktype: ^2.1.20 - effect: ^3.16.8 - quansync: ^0.2.11 - sury: ^10.0.0 - typebox: ^1.0.17 - valibot: ^1.1.0 - zod: ^3.25.0 || ^4.0.0 - zod-to-json-schema: ^3.24.5 - peerDependenciesMeta: - '@valibot/to-json-schema': - optional: true - arktype: - optional: true - effect: - optional: true - sury: - optional: true - typebox: - optional: true - valibot: - optional: true - zod: - optional: true - zod-to-json-schema: - optional: true - - '@standard-community/standard-openapi@0.2.9': - resolution: {integrity: sha512-htj+yldvN1XncyZi4rehbf9kLbu8os2Ke/rfqoZHCMHuw34kiF3LP/yQPdA0tQ940y8nDq3Iou8R3wG+AGGyvg==} - peerDependencies: - '@standard-community/standard-json': ^0.3.5 - '@standard-schema/spec': ^1.0.0 - arktype: ^2.1.20 - effect: ^3.17.14 - openapi-types: ^12.1.3 - sury: ^10.0.0 - typebox: ^1.0.0 - valibot: ^1.1.0 - zod: ^3.25.0 || ^4.0.0 - zod-openapi: ^4 - peerDependenciesMeta: - arktype: - optional: true - effect: - optional: true - sury: - optional: true - typebox: - optional: true - valibot: - optional: true - zod: - optional: true - zod-openapi: - optional: true - '@standard-schema/spec@1.0.0': resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} @@ -4303,9 +4224,6 @@ packages: '@types/js-yaml@4.0.9': resolution: {integrity: sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==} - '@types/json-schema@7.0.15': - resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - '@types/mdast@4.0.4': resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} @@ -4673,12 +4591,6 @@ packages: resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} engines: {node: '>= 0.4'} - arkregex@0.0.5: - resolution: {integrity: sha512-ncYjBdLlh5/QnVsAA8De16Tc9EqmYM7y/WU9j+236KcyYNUXogpz3sC4ATIZYzzLxwI+0sEOaQLEmLmRleaEXw==} - - arktype@2.1.29: - resolution: {integrity: sha512-jyfKk4xIOzvYNayqnD8ZJQqOwcrTOUbIU4293yrzAjA3O1dWh61j71ArMQ6tS/u4pD7vabSPe7nG3RCyoXW6RQ==} - array-iterate@2.0.1: resolution: {integrity: sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==} @@ -6084,21 +5996,6 @@ packages: help-me@5.0.0: resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==} - hono-openapi@1.1.2: - resolution: {integrity: sha512-toUcO60MftRBxqcVyxsHNYs2m4vf4xkQaiARAucQx3TiBPDtMNNkoh+C4I1vAretQZiGyaLOZNWn1YxfSyUA5g==} - peerDependencies: - '@hono/standard-validator': ^0.2.0 - '@standard-community/standard-json': ^0.3.5 - '@standard-community/standard-openapi': ^0.2.9 - '@types/json-schema': ^7.0.15 - hono: ^4.8.3 - openapi-types: ^12.1.3 - peerDependenciesMeta: - '@hono/standard-validator': - optional: true - hono: - optional: true - hono@4.12.2: resolution: {integrity: sha512-gJnaDHXKDayjt8ue0n8Gs0A007yKXj4Xzb8+cNjZeYsSzzwKc0Lr+OZgYwVfB0pHfUs17EPoLvrOsEaJ9mj+Tg==} engines: {node: '>=16.9.0'} @@ -7022,9 +6919,6 @@ packages: oniguruma-to-es@4.3.3: resolution: {integrity: sha512-rPiZhzC3wXwE59YQMRDodUwwT9FZ9nNBwQQfsd1wfdtlKEyCdRV0avrTcSZ5xlIvGRVPd/cx6ZN45ECmS39xvg==} - openapi-types@12.1.3: - resolution: {integrity: sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==} - openapi3-ts@4.5.0: resolution: {integrity: sha512-jaL+HgTq2Gj5jRcfdutgRGLosCy/hT8sQf6VOy+P+g36cZOjI1iukdPnijC+4CmeRzg/jEllJUboEic2FhxhtQ==} @@ -8987,14 +8881,6 @@ snapshots: '@antfu/utils@9.3.0': {} - '@ark/schema@0.56.0': - dependencies: - '@ark/util': 0.56.0 - optional: true - - '@ark/util@0.56.0': - optional: true - '@asamuzakjp/css-color@4.0.5': dependencies: '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) @@ -10588,11 +10474,6 @@ snapshots: '@opentelemetry/semantic-conventions': 1.37.0 hono: 4.12.2 - '@hono/standard-validator@0.2.2(@standard-schema/spec@1.0.0)(hono@4.12.2)': - dependencies: - '@standard-schema/spec': 1.0.0 - hono: 4.12.2 - '@hono/zod-openapi@1.2.2(hono@4.12.2)(zod@4.3.6)': dependencies: '@asteasolutions/zod-to-openapi': 8.4.1(zod@4.3.6) @@ -12417,25 +12298,6 @@ snapshots: dependencies: tslib: 2.8.1 - '@standard-community/standard-json@0.3.5(@standard-schema/spec@1.0.0)(@types/json-schema@7.0.15)(arktype@2.1.29)(quansync@0.2.11)(zod-to-json-schema@3.24.6(zod@4.3.6))(zod@4.3.6)': - dependencies: - '@standard-schema/spec': 1.0.0 - '@types/json-schema': 7.0.15 - quansync: 0.2.11 - optionalDependencies: - arktype: 2.1.29 - zod: 4.3.6 - zod-to-json-schema: 3.24.6(zod@4.3.6) - - '@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.0.0)(@types/json-schema@7.0.15)(arktype@2.1.29)(quansync@0.2.11)(zod-to-json-schema@3.24.6(zod@4.3.6))(zod@4.3.6))(@standard-schema/spec@1.0.0)(arktype@2.1.29)(openapi-types@12.1.3)(zod@4.3.6)': - dependencies: - '@standard-community/standard-json': 0.3.5(@standard-schema/spec@1.0.0)(@types/json-schema@7.0.15)(arktype@2.1.29)(quansync@0.2.11)(zod-to-json-schema@3.24.6(zod@4.3.6))(zod@4.3.6) - '@standard-schema/spec': 1.0.0 - openapi-types: 12.1.3 - optionalDependencies: - arktype: 2.1.29 - zod: 4.3.6 - '@standard-schema/spec@1.0.0': {} '@standard-schema/utils@0.3.0': {} @@ -12816,8 +12678,6 @@ snapshots: '@types/js-yaml@4.0.9': {} - '@types/json-schema@7.0.15': {} - '@types/mdast@4.0.4': dependencies: '@types/unist': 3.0.3 @@ -13226,18 +13086,6 @@ snapshots: aria-query@5.3.2: {} - arkregex@0.0.5: - dependencies: - '@ark/util': 0.56.0 - optional: true - - arktype@2.1.29: - dependencies: - '@ark/schema': 0.56.0 - '@ark/util': 0.56.0 - arkregex: 0.0.5 - optional: true - array-iterate@2.0.1: {} array-union@2.1.0: {} @@ -14895,16 +14743,6 @@ snapshots: help-me@5.0.0: {} - hono-openapi@1.1.2(@hono/standard-validator@0.2.2(@standard-schema/spec@1.0.0)(hono@4.12.2))(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.0.0)(@types/json-schema@7.0.15)(arktype@2.1.29)(quansync@0.2.11)(zod-to-json-schema@3.24.6(zod@4.3.6))(zod@4.3.6))(@standard-community/standard-openapi@0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.0.0)(@types/json-schema@7.0.15)(arktype@2.1.29)(quansync@0.2.11)(zod-to-json-schema@3.24.6(zod@4.3.6))(zod@4.3.6))(@standard-schema/spec@1.0.0)(arktype@2.1.29)(openapi-types@12.1.3)(zod@4.3.6))(@types/json-schema@7.0.15)(hono@4.12.2)(openapi-types@12.1.3): - dependencies: - '@standard-community/standard-json': 0.3.5(@standard-schema/spec@1.0.0)(@types/json-schema@7.0.15)(arktype@2.1.29)(quansync@0.2.11)(zod-to-json-schema@3.24.6(zod@4.3.6))(zod@4.3.6) - '@standard-community/standard-openapi': 0.2.9(@standard-community/standard-json@0.3.5(@standard-schema/spec@1.0.0)(@types/json-schema@7.0.15)(arktype@2.1.29)(quansync@0.2.11)(zod-to-json-schema@3.24.6(zod@4.3.6))(zod@4.3.6))(@standard-schema/spec@1.0.0)(arktype@2.1.29)(openapi-types@12.1.3)(zod@4.3.6) - '@types/json-schema': 7.0.15 - openapi-types: 12.1.3 - optionalDependencies: - '@hono/standard-validator': 0.2.2(@standard-schema/spec@1.0.0)(hono@4.12.2) - hono: 4.12.2 - hono@4.12.2: {} html-encoding-sniffer@4.0.0: @@ -16014,8 +15852,6 @@ snapshots: regex: 6.0.1 regex-recursion: 6.0.2 - openapi-types@12.1.3: {} - openapi3-ts@4.5.0: dependencies: yaml: 2.8.1 @@ -18199,11 +18035,6 @@ snapshots: dependencies: zod: 3.25.76 - zod-to-json-schema@3.24.6(zod@4.3.6): - dependencies: - zod: 4.3.6 - optional: true - zod-to-ts@1.2.0(typescript@5.9.3)(zod@3.25.76): dependencies: typescript: 5.9.3