11import config from "@/config" ;
22
3- import { describeRoute , resolver as validationResolver } from "hono-openapi" ;
43import { namehash } from "viem" ;
5- import { z } from "zod/v4" ;
64
75import {
86 ENS_ROOT ,
@@ -15,20 +13,15 @@ import {
1513 type PluginName ,
1614 serializeNameTokensResponse ,
1715} from "@ensnode/ensnode-sdk" ;
18- import {
19- ErrorResponseSchema ,
20- makeNameTokensResponseSchema ,
21- makeNodeSchema ,
22- } from "@ensnode/ensnode-sdk/internal" ;
23-
24- import { params } from "@/lib/handlers/params.schema" ;
25- import { validate } from "@/lib/handlers/validate" ;
26- import { factory } from "@/lib/hono-factory" ;
16+
17+ import { createApp } from "@/lib/hono-factory" ;
2718import { findRegisteredNameTokensForDomain } from "@/lib/name-tokens/find-name-tokens-for-domain" ;
2819import { getIndexedSubregistries } from "@/lib/name-tokens/get-indexed-subregistries" ;
2920import { nameTokensApiMiddleware } from "@/middleware/name-tokens.middleware" ;
3021
31- const app = factory . createApp ( ) ;
22+ import { getNameTokensRoute } from "./name-tokens-api.routes" ;
23+
24+ const app = createApp ( ) ;
3225
3326const indexedSubregistries = getIndexedSubregistries (
3427 config . namespace ,
@@ -40,21 +33,6 @@ const indexedSubregistries = getIndexedSubregistries(
4033// and if not returns the appropriate HTTP 503 (Service Unavailable) error.
4134app . use ( nameTokensApiMiddleware ) ;
4235
43- /**
44- * Request Query Schema
45- *
46- * Name Tokens API can be requested by either `name` or `domainId`, and
47- * can never be requested by both, or neither.
48- */
49- const nameTokensQuerySchema = z
50- . object ( {
51- domainId : makeNodeSchema ( "request.domainId" ) . optional ( ) . describe ( "Domain node hash identifier" ) ,
52- name : params . name . optional ( ) . describe ( "ENS name to look up tokens for" ) ,
53- } )
54- . refine ( ( data ) => ( data . domainId !== undefined ) !== ( data . name !== undefined ) , {
55- message : "Exactly one of 'domainId' or 'name' must be provided" ,
56- } ) ;
57-
5836/**
5937 * Factory function for creating a 404 Name Tokens Not Indexed error response
6038 */
@@ -69,163 +47,109 @@ const makeNameTokensNotIndexedResponse = (
6947 } ,
7048} ) ;
7149
72- app . get (
73- "/" ,
74- describeRoute ( {
75- tags : [ "Explore" ] ,
76- summary : "Get Name Tokens" ,
77- description : "Returns name tokens for the requested identifier (domainId or name)" ,
78- responses : {
79- 200 : {
80- description : "Name tokens known" ,
81- content : {
82- "application/json" : {
83- schema : validationResolver ( makeNameTokensResponseSchema ( "Name Tokens Response" , true ) ) ,
84- } ,
85- } ,
86- } ,
87- 400 : {
88- description : "Invalid input" ,
89- content : {
90- "application/json" : {
91- schema : validationResolver ( ErrorResponseSchema ) ,
92- } ,
93- } ,
94- } ,
95- 404 : {
96- description : "Name tokens not indexed" ,
97- content : {
98- "application/json" : {
99- schema : validationResolver ( makeNameTokensResponseSchema ( "Name Tokens Response" , true ) ) ,
100- } ,
101- } ,
102- } ,
103- 500 : {
104- description : "Internal server error" ,
105- content : {
106- "application/json" : {
107- schema : validationResolver ( ErrorResponseSchema ) ,
108- } ,
109- } ,
110- } ,
111- 503 : {
112- description :
113- "Service unavailable - Name Tokens API prerequisites not met (indexing status not ready or required plugins not activated)" ,
114- content : {
115- "application/json" : {
116- schema : validationResolver ( makeNameTokensResponseSchema ( "Name Tokens Response" , true ) ) ,
117- } ,
50+ app . openapi ( getNameTokensRoute , async ( c ) => {
51+ // Invariant: context must be set by the required middleware
52+ if ( c . var . indexingStatus === undefined ) {
53+ return c . json (
54+ serializeNameTokensResponse ( {
55+ responseCode : NameTokensResponseCodes . Error ,
56+ errorCode : NameTokensResponseErrorCodes . IndexingStatusUnsupported ,
57+ error : {
58+ message : "Name Tokens API is not available yet" ,
59+ details : "Indexing status middleware is required but not initialized." ,
11860 } ,
119- } ,
120- } ,
121- } ) ,
122- validate ( "query" , nameTokensQuerySchema ) ,
123- async ( c ) => {
124- // Invariant: context must be set by the required middleware
125- if ( c . var . indexingStatus === undefined ) {
126- return c . json (
127- serializeNameTokensResponse ( {
128- responseCode : NameTokensResponseCodes . Error ,
129- errorCode : NameTokensResponseErrorCodes . IndexingStatusUnsupported ,
130- error : {
131- message : "Name Tokens API is not available yet" ,
132- details : "Indexing status middleware is required but not initialized." ,
133- } ,
134- } ) ,
135- 503 ,
136- ) ;
137- }
61+ } ) ,
62+ 503 ,
63+ ) ;
64+ }
13865
139- // Check if Indexing Status resolution failed.
140- if ( c . var . indexingStatus instanceof Error ) {
141- return c . json (
142- serializeNameTokensResponse ( {
143- responseCode : NameTokensResponseCodes . Error ,
144- errorCode : NameTokensResponseErrorCodes . IndexingStatusUnsupported ,
145- error : {
146- message : "Name Tokens API is not available yet" ,
147- details :
148- "Indexing status has not yet reached the required state to enable the Name Tokens API." ,
149- } ,
150- } ) ,
151- 503 ,
152- ) ;
153- }
66+ // Check if Indexing Status resolution failed.
67+ if ( c . var . indexingStatus instanceof Error ) {
68+ return c . json (
69+ serializeNameTokensResponse ( {
70+ responseCode : NameTokensResponseCodes . Error ,
71+ errorCode : NameTokensResponseErrorCodes . IndexingStatusUnsupported ,
72+ error : {
73+ message : "Name Tokens API is not available yet" ,
74+ details :
75+ "Indexing status has not yet reached the required state to enable the Name Tokens API." ,
76+ } ,
77+ } ) ,
78+ 503 ,
79+ ) ;
80+ }
15481
155- const request = c . req . valid ( "query" ) satisfies NameTokensRequest ;
156- let domainId : Node ;
82+ const request = c . req . valid ( "query" ) satisfies NameTokensRequest ;
83+ let domainId : Node ;
15784
158- if ( request . name !== undefined ) {
159- const { name } = request ;
85+ if ( request . name !== undefined ) {
86+ const { name } = request ;
16087
161- // return 404 when the requested name was the ENS Root
162- if ( name === ENS_ROOT ) {
163- return c . json (
164- serializeNameTokensResponse (
165- makeNameTokensNotIndexedResponse (
166- `The 'name' param must not be ENS Root, no tokens exist for it.` ,
167- ) ,
88+ // return 404 when the requested name was the ENS Root
89+ if ( name === ENS_ROOT ) {
90+ return c . json (
91+ serializeNameTokensResponse (
92+ makeNameTokensNotIndexedResponse (
93+ `The 'name' param must not be ENS Root, no tokens exist for it.` ,
16894 ) ,
169- 404 ,
170- ) ;
171- }
172-
173- const parentNode = namehash ( getParentNameFQDN ( name ) ) ;
174- const subregistry = indexedSubregistries . find (
175- ( subregistry ) => subregistry . node === parentNode ,
95+ ) ,
96+ 404 ,
17697 ) ;
177-
178- // Return 404 response with error code for Name Tokens Not Indexed when
179- // the parent name of the requested name does not match any of the
180- // actively indexed subregistries.
181- if ( ! subregistry ) {
182- return c . json (
183- serializeNameTokensResponse (
184- makeNameTokensNotIndexedResponse (
185- `This ENSNode instance has not been configured to index tokens for the requested name: '${ name } ` ,
186- ) ,
187- ) ,
188- 404 ,
189- ) ;
190- }
191-
192- domainId = namehash ( name ) ;
193- } else if ( request . domainId !== undefined ) {
194- domainId = request . domainId ;
195- } else {
196- // This should never happen due to Zod validation, but TypeScript needs this
197- throw new Error ( "Invariant(name-tokens-api): Either name or domainId must be provided" ) ;
19898 }
19999
200- const { omnichainSnapshot } = c . var . indexingStatus . snapshot ;
201- const accurateAsOf = omnichainSnapshot . omnichainIndexingCursor ;
202-
203- const registeredNameTokens = await findRegisteredNameTokensForDomain ( domainId , accurateAsOf ) ;
100+ const parentNode = namehash ( getParentNameFQDN ( name ) ) ;
101+ const subregistry = indexedSubregistries . find ( ( subregistry ) => subregistry . node === parentNode ) ;
204102
205103 // Return 404 response with error code for Name Tokens Not Indexed when
206- // no name tokens were found for the domain ID associated with
207- // the requested name.
208- if ( ! registeredNameTokens ) {
209- const errorMessageSubject =
210- request . name !== undefined ? `name: '${ request . name } '` : `domain ID: '${ request . domainId } '` ;
211-
104+ // the parent name of the requested name does not match any of the
105+ // actively indexed subregistries.
106+ if ( ! subregistry ) {
212107 return c . json (
213108 serializeNameTokensResponse (
214109 makeNameTokensNotIndexedResponse (
215- `No Name Tokens were indexed by this ENSNode instance for the requested ${ errorMessageSubject } . ` ,
110+ `This ENSNode instance has not been configured to index tokens for the requested name: ' ${ name } ` ,
216111 ) ,
217112 ) ,
218113 404 ,
219114 ) ;
220115 }
221116
117+ domainId = namehash ( name ) ;
118+ } else if ( request . domainId !== undefined ) {
119+ domainId = request . domainId ;
120+ } else {
121+ // This should never happen due to Zod validation, but TypeScript needs this
122+ throw new Error ( "Invariant(name-tokens-api): Either name or domainId must be provided" ) ;
123+ }
124+
125+ const { omnichainSnapshot } = c . var . indexingStatus . snapshot ;
126+ const accurateAsOf = omnichainSnapshot . omnichainIndexingCursor ;
127+
128+ const registeredNameTokens = await findRegisteredNameTokensForDomain ( domainId , accurateAsOf ) ;
129+
130+ // Return 404 response with error code for Name Tokens Not Indexed when
131+ // no name tokens were found for the domain ID associated with
132+ // the requested name.
133+ if ( ! registeredNameTokens ) {
134+ const errorMessageSubject =
135+ request . name !== undefined ? `name: '${ request . name } '` : `domain ID: '${ request . domainId } '` ;
136+
222137 return c . json (
223- serializeNameTokensResponse ( {
224- responseCode : NameTokensResponseCodes . Ok ,
225- registeredNameTokens,
226- } ) ,
138+ serializeNameTokensResponse (
139+ makeNameTokensNotIndexedResponse (
140+ `No Name Tokens were indexed by this ENSNode instance for the requested ${ errorMessageSubject } .` ,
141+ ) ,
142+ ) ,
143+ 404 ,
227144 ) ;
228- } ,
229- ) ;
145+ }
146+
147+ return c . json (
148+ serializeNameTokensResponse ( {
149+ responseCode : NameTokensResponseCodes . Ok ,
150+ registeredNameTokens,
151+ } ) ,
152+ ) ;
153+ } ) ;
230154
231155export default app ;
0 commit comments