Skip to content
23 changes: 2 additions & 21 deletions apps/ensapi/src/handlers/api/explore/name-tokens-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,18 @@ import {
import { createApp } from "@/lib/hono-factory";
import { findRegisteredNameTokensForDomain } from "@/lib/name-tokens/find-name-tokens-for-domain";
import { getIndexedSubregistries } from "@/lib/name-tokens/get-indexed-subregistries";
import { indexingStatusMiddleware } from "@/middleware/indexing-status.middleware";
import { nameTokensApiMiddleware } from "@/middleware/name-tokens.middleware";

import { getNameTokensRoute } from "./name-tokens-api.routes";

const app = createApp();
const app = createApp({ middlewares: [indexingStatusMiddleware, nameTokensApiMiddleware] });

const indexedSubregistries = getIndexedSubregistries(
config.namespace,
config.ensIndexerPublicConfig.plugins as PluginName[],
);

// Middleware managing access to Name Tokens API route.
// It makes the route available if all prerequisites are met,
// and if not returns the appropriate HTTP 503 (Service Unavailable) error.
app.use(nameTokensApiMiddleware);

/**
* Factory function for creating a 404 Name Tokens Not Indexed error response
*/
Expand All @@ -48,21 +44,6 @@ const makeNameTokensNotIndexedResponse = (
});

app.openapi(getNameTokensRoute, async (c) => {
// Invariant: context must be set by the required middleware
if (c.var.indexingStatus === undefined) {
return c.json(
serializeNameTokensResponse({
responseCode: NameTokensResponseCodes.Error,
errorCode: NameTokensResponseErrorCodes.IndexingStatusUnsupported,
error: {
message: "Name Tokens API is not available yet",
details: "Indexing status middleware is required but not initialized.",
},
}),
503,
);
}

// Check if Indexing Status resolution failed.
if (c.var.indexingStatus instanceof Error) {
return c.json(
Expand Down
13 changes: 4 additions & 9 deletions apps/ensapi/src/handlers/api/explore/registrar-actions-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
import { createApp } from "@/lib/hono-factory";
import { makeLogger } from "@/lib/logger";
import { findRegistrarActions } from "@/lib/registrar-actions/find-registrar-actions";
import { indexingStatusMiddleware } from "@/middleware/indexing-status.middleware";
import { registrarActionsApiMiddleware } from "@/middleware/registrar-actions.middleware";

import {
Expand All @@ -20,14 +21,10 @@ import {
type RegistrarActionsQuery,
} from "./registrar-actions-api.routes";

const app = createApp();
const app = createApp({ middlewares: [indexingStatusMiddleware, registrarActionsApiMiddleware] });

const logger = makeLogger("registrar-actions-api");

// Middleware managing access to Registrar Actions API routes.
// It makes the routes available if all prerequisites are met.
app.use(registrarActionsApiMiddleware);

// Shared business logic for fetching registrar actions
async function fetchRegistrarActions(parentNode: Node | undefined, query: RegistrarActionsQuery) {
const {
Expand Down Expand Up @@ -150,10 +147,8 @@ app.openapi(getRegistrarActionsRoute, async (c) => {
*/
app.openapi(getRegistrarActionsByParentNodeRoute, async (c) => {
try {
// Middleware ensures indexingStatus is available and not an Error
// This check is for TypeScript type safety
if (!c.var.indexingStatus || c.var.indexingStatus instanceof Error) {
throw new Error("Invariant violation: indexingStatus should be validated by middleware");
if (c.var.indexingStatus instanceof Error) {
throw new Error("Indexing status has not been loaded yet");
}

const { parentNode } = c.req.valid("param");
Expand Down
4 changes: 2 additions & 2 deletions apps/ensapi/src/handlers/api/graphql/ensnode-graphql-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import config from "@/config";

import { hasGraphqlApiConfigSupport } from "@ensnode/ensnode-sdk";

import { factory } from "@/lib/hono-factory";
import { createApp } from "@/lib/hono-factory";

const app = factory.createApp();
const app = createApp();

// 503 if ensv2 plugin not available
app.use(async (c, next) => {
Expand Down
8 changes: 2 additions & 6 deletions apps/ensapi/src/handlers/api/meta/realtime-api.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
import { errorResponse } from "@/lib/handlers/error-response";
import { createApp } from "@/lib/hono-factory";
import { indexingStatusMiddleware } from "@/middleware/indexing-status.middleware";

import { realtimeGetMeta } from "./realtime-api.routes";

const app = createApp();
const app = createApp({ middlewares: [indexingStatusMiddleware] });

// allow performance monitoring clients to read HTTP Status for the provided
// `maxWorstCaseDistance` param
app.openapi(realtimeGetMeta, async (c) => {
// context must be set by the required middleware
if (c.var.indexingStatus === undefined) {
throw new Error(`Invariant(realtime-api): indexingStatusMiddleware required.`);
}

// return 503 response error with details on prerequisite being unavailable
if (c.var.indexingStatus instanceof Error) {
return errorResponse(
Expand Down
8 changes: 2 additions & 6 deletions apps/ensapi/src/handlers/api/meta/status-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,18 @@ import {

import { buildEnsApiPublicConfig } from "@/config/config.schema";
import { createApp } from "@/lib/hono-factory";
import { indexingStatusMiddleware } from "@/middleware/indexing-status.middleware";

import { getConfigRoute, getIndexingStatusRoute } from "./status-api.routes";

const app = createApp();
const app = createApp({ middlewares: [indexingStatusMiddleware] });

app.openapi(getConfigRoute, async (c) => {
const ensApiPublicConfig = buildEnsApiPublicConfig(config);
return c.json(serializeENSApiPublicConfig(ensApiPublicConfig));
});
Comment thread
sevenzing marked this conversation as resolved.

app.openapi(getIndexingStatusRoute, async (c) => {
// context must be set by the required middleware
if (c.var.indexingStatus === undefined) {
throw new Error(`Invariant(indexing-status): indexingStatusMiddleware required`);
}

if (c.var.indexingStatus instanceof Error) {
return c.json(
serializeEnsApiIndexingStatusResponse({
Expand Down
29 changes: 8 additions & 21 deletions apps/ensapi/src/handlers/api/resolution/resolution-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { resolvePrimaryNames } from "@/lib/resolution/multichain-primary-name-re
import { resolveReverse } from "@/lib/resolution/reverse-resolution";
import { runWithTrace } from "@/lib/tracing/tracing-api";
import { canAccelerateMiddleware } from "@/middleware/can-accelerate.middleware";
import { indexingStatusMiddleware } from "@/middleware/indexing-status.middleware";
import { makeIsRealtimeMiddleware } from "@/middleware/is-realtime.middleware";

import {
Expand All @@ -25,12 +26,13 @@ import {
*/
const MAX_REALTIME_DISTANCE_TO_ACCELERATE: Duration = 60; // 1 minute in seconds

const app = createApp();

// inject c.var.isRealtime derived from MAX_REALTIME_DISTANCE_TO_ACCELERATE
app.use(makeIsRealtimeMiddleware("resolution-api", MAX_REALTIME_DISTANCE_TO_ACCELERATE));
// inject c.var.canAccelerate derived from that c.var.isRealtime
app.use(canAccelerateMiddleware);
const app = createApp({
middlewares: [
indexingStatusMiddleware,
makeIsRealtimeMiddleware("resolution-api", MAX_REALTIME_DISTANCE_TO_ACCELERATE),
canAccelerateMiddleware,
],
});

/**
* Example queries for /records:
Expand All @@ -45,11 +47,6 @@ app.use(canAccelerateMiddleware);
* GET /records/example.eth&name=true&addresses=60,0&texts=avatar,com.twitter
*/
app.openapi(resolveRecordsRoute, async (c) => {
// context must be set by the required middleware
if (c.var.canAccelerate === undefined) {
throw new Error(`Invariant(resolution-api): canAccelerateMiddleware required`);
}

const { name } = c.req.valid("param");
const { selection, trace: showTrace, accelerate } = c.req.valid("query");
const canAccelerate = c.var.canAccelerate;
Expand Down Expand Up @@ -82,11 +79,6 @@ app.openapi(resolveRecordsRoute, async (c) => {
* GET /primary-name/0x1234...abcd/0
*/
app.openapi(resolvePrimaryNameRoute, async (c) => {
// context must be set by the required middleware
if (c.var.canAccelerate === undefined) {
throw new Error(`Invariant(resolution-api): canAccelerateMiddleware required`);
}

const { address, chainId } = c.req.valid("param");
const { trace: showTrace, accelerate } = c.req.valid("query");
const canAccelerate = c.var.canAccelerate;
Expand Down Expand Up @@ -116,11 +108,6 @@ app.openapi(resolvePrimaryNameRoute, async (c) => {
* GET /primary-names/0x1234...abcd?chainIds=1,10,8453
*/
app.openapi(resolvePrimaryNamesRoute, async (c) => {
// context must be set by the required middleware
if (c.var.canAccelerate === undefined) {
throw new Error(`Invariant(resolution-api): canAccelerateMiddleware required`);
}

const { address } = c.req.valid("param");
const { chainIds, trace: showTrace, accelerate } = c.req.valid("query");
const canAccelerate = c.var.canAccelerate;
Expand Down
40 changes: 6 additions & 34 deletions apps/ensapi/src/handlers/ensanalytics/ensanalytics-api-v1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,23 +29,15 @@ import {

const logger = makeLogger("ensanalytics-api-v1");

const app = createApp();

// Apply referral program edition config set middleware
app.use(referralProgramEditionConfigSetMiddleware);

// Apply referrer leaderboard cache middleware (depends on edition config set middleware)
app.use(referralLeaderboardEditionsCachesMiddleware);
const app = createApp({
middlewares: [
referralProgramEditionConfigSetMiddleware,
referralLeaderboardEditionsCachesMiddleware,
],
});

// Get a page from the referrer leaderboard for a specific edition
app.openapi(getReferralLeaderboardRoute, async (c) => {
// context must be set by the required middleware
if (c.var.referralLeaderboardEditionsCaches === undefined) {
throw new Error(
`Invariant(ensanalytics-api-v1): referralLeaderboardEditionsCachesMiddleware required`,
);
}

try {
const { edition, page, recordsPerPage } = c.req.valid("query");

Expand Down Expand Up @@ -122,13 +114,6 @@ app.openapi(getReferralLeaderboardRoute, async (c) => {

// Get referrer detail for a specific address for requested editions
app.openapi(getReferrerDetailRoute, async (c) => {
// context must be set by the required middleware
if (c.var.referralLeaderboardEditionsCaches === undefined) {
throw new Error(
`Invariant(ensanalytics-api-v1): referralLeaderboardEditionsCachesMiddleware required`,
);
}

try {
const { referrer } = c.req.valid("param");
const { editions } = c.req.valid("query");
Expand Down Expand Up @@ -238,19 +223,6 @@ app.openapi(getReferrerDetailRoute, async (c) => {

// Get edition summaries
app.openapi(getEditionsRoute, async (c) => {
// context must be set by the required middleware
if (c.var.referralProgramEditionConfigSet === undefined) {
throw new Error(
`Invariant(ensanalytics-api-v1): referralProgramEditionConfigSetMiddleware required`,
);
}

if (c.var.referralLeaderboardEditionsCaches === undefined) {
throw new Error(
`Invariant(ensanalytics-api-v1): referralLeaderboardEditionsCachesMiddleware required`,
);
}

try {
// Check if edition config set failed to load
if (c.var.referralProgramEditionConfigSet instanceof Error) {
Expand Down
15 changes: 1 addition & 14 deletions apps/ensapi/src/handlers/ensanalytics/ensanalytics-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,10 @@ import { getReferrerDetailRoute, getReferrerLeaderboardRoute } from "./ensanalyt

const logger = makeLogger("ensanalytics-api");

const app = createApp();

// Apply referrer leaderboard cache middleware to all routes in this handler
app.use(referrerLeaderboardMiddleware);
const app = createApp({ middlewares: [referrerLeaderboardMiddleware] });

// Get a page from the referrer leaderboard
app.openapi(getReferrerLeaderboardRoute, async (c) => {
// context must be set by the required middleware
if (c.var.referrerLeaderboard === undefined) {
throw new Error(`Invariant(ensanalytics-api): referrerLeaderboardMiddleware required`);
}

try {
if (c.var.referrerLeaderboard instanceof Error) {
return c.json(
Expand Down Expand Up @@ -72,11 +64,6 @@ app.openapi(getReferrerLeaderboardRoute, async (c) => {

// Get referrer detail for a specific address
app.openapi(getReferrerDetailRoute, async (c) => {
// context must be set by the required middleware
if (c.var.referrerLeaderboard === undefined) {
throw new Error(`Invariant(ensanalytics-api): referrerLeaderboardMiddleware required`);
}

try {
// Check if leaderboard failed to load
if (c.var.referrerLeaderboard instanceof Error) {
Expand Down
8 changes: 6 additions & 2 deletions apps/ensapi/src/handlers/subgraph/subgraph-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ import * as schema from "@ensnode/ensdb-sdk";
import { type Duration, hasSubgraphApiConfigSupport } from "@ensnode/ensnode-sdk";
import { subgraphGraphQLMiddleware } from "@ensnode/ponder-subgraph";

import { factory } from "@/lib/hono-factory";
import { createApp } from "@/lib/hono-factory";
import { makeSubgraphApiDocumentation } from "@/lib/subgraph/api-documentation";
import { filterSchemaByPrefix } from "@/lib/subgraph/filter-schema-by-prefix";
import { fixContentLengthMiddleware } from "@/middleware/fix-content-length.middleware";
import { indexingStatusMiddleware } from "@/middleware/indexing-status.middleware";
import { makeIsRealtimeMiddleware } from "@/middleware/is-realtime.middleware";
import { subgraphMetaMiddleware } from "@/middleware/subgraph-meta.middleware";
import { thegraphFallbackMiddleware } from "@/middleware/thegraph-fallback.middleware";
Expand All @@ -19,7 +20,7 @@ const MAX_REALTIME_DISTANCE_TO_RESOLVE: Duration = 10 * 60; // 10 minutes in sec
// generate a subgraph-specific subset of the schema
const subgraphSchema = filterSchemaByPrefix("subgraph_", schema);

const app = factory.createApp();
const app = createApp();

// 503 if subgraph plugin not available
app.use(async (c, next) => {
Expand All @@ -31,6 +32,9 @@ app.use(async (c, next) => {
await next();
});

// inject c.var.indexingStatus
app.use(indexingStatusMiddleware);
Comment thread
sevenzing marked this conversation as resolved.

// inject c.var.isRealtime derived from MAX_REALTIME_DISTANCE_TO_RESOLVE
app.use(makeIsRealtimeMiddleware("subgraph-api", MAX_REALTIME_DISTANCE_TO_RESOLVE));
Comment thread
sevenzing marked this conversation as resolved.

Expand Down
8 changes: 2 additions & 6 deletions apps/ensapi/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,9 @@ import { referralProgramEditionConfigSetCache } from "@/cache/referral-program-e
import { referrerLeaderboardCache } from "@/cache/referrer-leaderboard.cache";
import { redactEnsApiConfig } from "@/config/redact";
import { errorResponse } from "@/lib/handlers/error-response";
import { factory } from "@/lib/hono-factory";
import { createApp } from "@/lib/hono-factory";
import { sdk } from "@/lib/instrumentation";
import logger from "@/lib/logger";
import { indexingStatusMiddleware } from "@/middleware/indexing-status.middleware";
import { generateOpenApi31Document } from "@/openapi-document";

import realtimeApi from "./handlers/api/meta/realtime-api";
Expand All @@ -24,7 +23,7 @@ import ensanalyticsApi from "./handlers/ensanalytics/ensanalytics-api";
import ensanalyticsApiV1 from "./handlers/ensanalytics/ensanalytics-api-v1";
import subgraphApi from "./handlers/subgraph/subgraph-api";

const app = factory.createApp();
const app = createApp();

// set the X-ENSNode-Version header to the current version
app.use(async (ctx, next) => {
Expand All @@ -38,9 +37,6 @@ app.use(cors({ origin: "*" }));
// include automatic OpenTelemetry instrumentation for incoming requests
app.use(otel());

// add ENSIndexer Indexing Status Middleware to all routes for convenience
app.use(indexingStatusMiddleware);

// host welcome page
app.get("/", (c) =>
c.html(html`
Expand Down
Loading
Loading