Releases: Julien-R44/tuyau
@tuyau/core@1.2.2
Patch Changes
-
8ce6877: Fix
TuyauPromisenot being assignable toPromise<T>, which broke TanStack Query type inference.TuyauPromiseimplementedPromiseLike<T>but was missing[Symbol.toStringTag], so TypeScript did not consider it structurally compatible withPromise<T>. When users passed a tuyau call directly to TanStack Query'squeryFn, thedatatype was inferred asTuyauPromise<Response>instead ofResponse:// Before: data was typed as TuyauPromise<User[]> instead of User[] const { data } = useQuery({ queryKey: ["users"], queryFn: () => tuyau.request("users.index", {}), });
TuyauPromisenow implements the fullPromise<T>interface, so it works seamlessly with TanStack Query and any other library expectingPromise<T>. -
8a29325: Fix body type not being recognized when using
vine.groupwith.merge()in validators.Previously, validators like this would cause tuyau to lose the
bodytype, resulting in'body' does not exist in type 'BaseRequestOptions':const createSessionValidator = vine.create( vine .object({}) .merge( vine.group([ vine.group.if((data) => data.password, { password: vine.string() }), vine.group.if((data) => data.assertion, { assertion: webauthnAssertion, }), ]), ), );
The tuyau client now correctly accepts both variants of the union:
// Both calls are now properly typed await client.session.store({ body: { password: "secret" } }); await client.session.store({ body: { assertion: { id: "...", rawId: "..." } }, });
@tuyau/core@1.2.0
Minor Changes
-
d6fcd0f: Support wildcard
*route params in generated typesWildcard route parameters (e.g.
/downloads/*) are now included in the generated params type as'*': ParamValue[], matching AdonisJS's runtime behavior where the wildcard captures all remaining URL segments as an array.Previously, the codegen only extracted named
:paramtokens and ignored wildcard tokens, which meanturlFor()andrequest()calls with*params would fail type checking despite working at runtime.// AdonisJS route router.get("/docs/:category/*", [DocsController, "show"]).as("docs.show"); // Generated params type now includes '*' // params: { category: ParamValue; '*': ParamValue[] } // Client usage const tuyau = createTuyau({ baseUrl: "http://localhost:3333", registry }); tuyau.request("docs.show", { params: { category: "guides", "*": ["sql", "orm", "query-builder"] }, }); tuyau.urlFor.get("docs.show", { category: "guides", "*": ["sql", "orm", "query-builder"], });
@tuyau/core@1.1.0
Minor Changes
-
077085b: Add
responseTypeoption to override content-type based response parsing -
a2e531f: Add typed non-throwing error handling with
.safe()andTuyauError- Add
TuyauPromise, a thenable wrapper returned by client requests that preservesawait,.catch(), and.finally()while adding.safe() - Add
.safe()to return[data, null]on success or[null, error]on failure without throwing - Add
TuyauErroras the shared base class for client errors, with:kindto distinguish'http'and'network'failuresstatus,response,rawResponse, andrawRequestisStatus()to narrow typed HTTP error payloads withoutinstanceofchecks
- Make
TuyauHTTPErrorandTuyauNetworkErrorextendTuyauError - Extract non-2xx response payloads into generated route metadata so client errors can be typed from controller return unions
- Add
ExtractErrorResponseandErrorResponseOftype utilities - Update
Route.Error,Path.Error,RouteWithRegistry.Error, andPathWithRegistry.Errorto expose the unifiedTuyauErrorcontract - Keep thrown errors specific in
try/catch: HTTP failures still throwTuyauHTTPError, and transport failures still throwTuyauNetworkError
Basic usage
// .safe() returns [data, null] on success, [null, error] on failure const [data, error] = await tuyau.api.auth .login({ body: { email: "foo@bar.com", password: "secret" } }) .safe(); if (error) { console.log(error.message); // "Request failed with status code 400: POST /auth/login" console.log(error.status); // 400 return; } // data is fully typed here console.log(data.token);
Narrowing errors with
isStatus()const [data, error] = await tuyau.api.users..safe({ body: { name: 'John' } }) if (error.isStatus(422)) { // error.response is narrowed to the 422 payload type console.log(error.response.errors) } if (error.isStatus(403)) { // error.response is narrowed to the 403 payload type console.log(error.response.message) }
Network vs HTTP errors
const [data, error] = await tuyau.api.users.index.safe(); if (error.kind === "network") { // Server unreachable or client offline // error.status and error.response are undefined console.log("Network error:", error.message); } if (error.kind === "http") { // Server responded with a non-2xx status console.log(error.status, error.response); }
- Add
-
3fcacf0: Add
has()andcurrent()methods for route introspectiontuyau.has('users.show')— checks if a route name exists in the registrytuyau.current()— returns the current route name based onwindow.locationtuyau.current('users.show')— returnstrueif the current URL matches that routetuyau.current('users.*')— supports*wildcards to match multiple routestuyau.current('users.show', { params: { id: 42 }, query: { foo: 'bar' } })— additionally checks params and query
-
6bbd80f: Auto-add typed 422 validation error response for routes using a validator. The generated error type uses
SimpleErrorfrom@vinejs/vine/types. Can be customized viavalidationErrorTypeoption or disabled withvalidationErrorType: false.Also adds
isValidationError()as an alias forisStatus(422).const { data, error } = await tuyau.api.users.store.$post.safe({ body: { email: "foo@bar.com", password: "secret" }, }); if (error.isValidationError()) { // error.response is typed as { errors: SimpleError[] } for (const err of error.response.errors) { console.log(err.field, err.message); } }
Patch Changes
- 077085b: Handle objects in arrays and Date values in buildSearchParams