Summary
When a non-GET endpoint uses a validator body field named query, the generated Tuyau registry becomes incompatible with AdonisEndpoint, and createTuyau({ registry }) falls back to TransformApiDefinition<unknown>.
This ends up breaking unrelated route tree typing like tuyau.api.spaces.index and tuyau.api.documents.index.
This looks like a typing bug / design hole around reserved transport keys (query, possibly also params, headers, cookies) in generated registry types.
Environment
@tuyau/core: 1.2.2
- AdonisJS app using generated registry via
generateRegistry()
- TypeScript project consuming
createTuyau({ registry })
Minimal Reproduction
Validator
import vine from '@vinejs/vine'
export const ragSearchValidator = vine.create({
query: vine.string().trim().minLength(1),
})
Controller
import type { HttpContext } from '@adonisjs/core/http'
export default class RagController {
async search({ request }: HttpContext) {
const payload = await request.validateUsing(ragSearchValidator)
return {
data: {
query: payload.query,
hits: [],
},
}
}
}
Route
router.post('/api/rag/search', [RagController, 'search'])
Client
import { registry } from '@my-api/registry'
import { createTuyau } from '@tuyau/core/client'
export const tuyau = createTuyau({
registry,
baseUrl: '/',
})
Then unrelated usages start failing:
tuyau.api.spaces.index({})
tuyau.api.documents.index({})
Actual Behavior
Generated registry contains something like:
types: {
body: ExtractBody<InferInput<typeof ragSearchValidator>>
paramsTuple: []
params: {}
query: ExtractQuery<InferInput<typeof ragSearchValidator>>
response: ...
}
Because the validator has a field named query, ExtractQuery<...> resolves to string instead of an object shape.
But Tuyau's endpoint type requires:
query: Record<string, any>
So the generated route no longer satisfies AdonisEndpoint, and the registry becomes invalid.
This eventually causes createTuyau({ registry }) to infer unknown, so the whole typed route tree collapses.
TypeScript error looks like:
Property 'spaces' does not exist on type 'TransformApiDefinition<unknown>'
and/or:
Type '{ ... }' is not assignable to type 'AdonisEndpoint'
Types of property 'query' are incompatible.
Type 'string' is not assignable to type 'Record<string, any>'
Expected Behavior
One of these should happen:
- A body field named
query should remain a body field for non-GET endpoints, and not poison the generated registry.
- If
query is intentionally reserved by Tuyau, the generator should emit a clear, local error explaining that this key is reserved.
- In any case, a single route naming conflict should not cause the entire
createTuyau({ registry }) API tree to collapse to unknown.
Why this seems like a bug
I understand Tuyau treats query as transport metadata, but the current failure mode is too broad:
- the route-level conflict is not surfaced clearly
- unrelated routes lose typing
- the consumer only sees downstream errors like
TransformApiDefinition<unknown>
This makes the issue hard to diagnose.
Workaround
Renaming the field from query to something like searchText fixes the issue immediately.
export const ragSearchValidator = vine.create({
searchText: vine.string().trim().minLength(1),
})
Related Context
This may be related to non-GET query extraction behavior discussed here:
Suggested Fix Direction
Possible fixes:
- reserve
query/params/headers/cookies explicitly and fail generation with a clear message
- improve
ExtractQuery / registry generation so body fields on non-GET routes don't invalidate endpoint typing
- avoid collapsing the full route tree to
unknown when one route is malformed
Summary
When a non-GET endpoint uses a validator body field named
query, the generated Tuyau registry becomes incompatible withAdonisEndpoint, andcreateTuyau({ registry })falls back toTransformApiDefinition<unknown>.This ends up breaking unrelated route tree typing like
tuyau.api.spaces.indexandtuyau.api.documents.index.This looks like a typing bug / design hole around reserved transport keys (
query, possibly alsoparams,headers,cookies) in generated registry types.Environment
@tuyau/core:1.2.2generateRegistry()createTuyau({ registry })Minimal Reproduction
Validator
Controller
Route
Client
Then unrelated usages start failing:
Actual Behavior
Generated registry contains something like:
Because the validator has a field named
query,ExtractQuery<...>resolves tostringinstead of an object shape.But Tuyau's endpoint type requires:
So the generated route no longer satisfies
AdonisEndpoint, and the registry becomes invalid.This eventually causes
createTuyau({ registry })to inferunknown, so the whole typed route tree collapses.TypeScript error looks like:
and/or:
Expected Behavior
One of these should happen:
queryshould remain a body field for non-GET endpoints, and not poison the generated registry.queryis intentionally reserved by Tuyau, the generator should emit a clear, local error explaining that this key is reserved.createTuyau({ registry })API tree to collapse tounknown.Why this seems like a bug
I understand Tuyau treats
queryas transport metadata, but the current failure mode is too broad:TransformApiDefinition<unknown>This makes the issue hard to diagnose.
Workaround
Renaming the field from
queryto something likesearchTextfixes the issue immediately.Related Context
This may be related to non-GET query extraction behavior discussed here:
Suggested Fix Direction
Possible fixes:
query/params/headers/cookiesexplicitly and fail generation with a clear messageExtractQuery/ registry generation so body fields on non-GET routes don't invalidate endpoint typingunknownwhen one route is malformed