@kubb/plugin-client 6.1.0-canary.20261109T175349 → 6.1.0-canary.20261109T175913

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,2 @@
1
- import { M as SuccessOf, m as DataShape, n as NativeRequest, r as NativeResponse, t as NativeOptions, w as RequestResult, x as Options } from "../client-D0IfSe5q.js";
1
+ import { M as SuccessOf, m as DataShape, n as NativeRequest, r as NativeResponse, t as NativeOptions, w as RequestResult, x as Options } from "../client-DaI8VaEz.js";
2
2
  export { type DataShape, NativeOptions, NativeRequest, NativeResponse, type Options, type RequestResult, type SuccessOf };
@@ -1,3 +1,3 @@
1
1
  import { a as ValidateOption, o as ValidationErrorContext, s as ValidationErrorHandler } from "../standardSchema-B2AxHwZB.js";
2
- import { $ as unwrapResult, A as ResultByStatus, B as UnwrappedResult, C as RequestCredentials, D as ResponseErrorConfig, E as ResponseError, F as SuccessVariant, G as getHeader, H as Validator, I as ToStatusNumber, J as parseJsonOrText, K as getResponseContentType, L as Transport, M as SuccessOf, N as SuccessResultUnion, O as ResponseType, P as SuccessStatusCode, Q as toRequestInit, R as TransportResult, S as RequestConfig, T as ResolvedRequest, U as createClientCore, V as UrlConfig, W as createInterceptorStack, X as resolveAuth, Y as readResponse, Z as resolveResponseType, _ as ErrorOf, a as AuthResolver, b as Interceptors, c as ClientConfig, d as ContentBodySerializer, et as withUnwrap, f as ContentType, g as EmptyErrorBody, h as Deserializer, i as Auth, j as ResultUnion, k as ResponseTypeMap, l as ClientInstance, m as DataShape, o as AuthToken, p as DataOf, q as isStreamed, s as CallResult, u as Codec, v as InterceptorFn, w as RequestResult, x as Options, y as InterceptorStack, z as Unwrappable } from "../client-D0IfSe5q.js";
2
+ import { $ as unwrapResult, A as ResultByStatus, B as UnwrappedResult, C as RequestCredentials, D as ResponseErrorConfig, E as ResponseError, F as SuccessVariant, G as getHeader, H as Validator, I as ToStatusNumber, J as parseJsonOrText, K as getResponseContentType, L as Transport, M as SuccessOf, N as SuccessResultUnion, O as ResponseType, P as SuccessStatusCode, Q as toRequestInit, R as TransportResult, S as RequestConfig, T as ResolvedRequest, U as createClientCore, V as UrlConfig, W as createInterceptorStack, X as resolveAuth, Y as readResponse, Z as resolveResponseType, _ as ErrorOf, a as AuthResolver, b as Interceptors, c as ClientConfig, d as ContentBodySerializer, et as withUnwrap, f as ContentType, g as EmptyErrorBody, h as Deserializer, i as Auth, j as ResultUnion, k as ResponseTypeMap, l as ClientInstance, m as DataShape, o as AuthToken, p as DataOf, q as isStreamed, s as CallResult, u as Codec, v as InterceptorFn, w as RequestResult, x as Options, y as InterceptorStack, z as Unwrappable } from "../client-DaI8VaEz.js";
3
3
  export { Auth, AuthResolver, AuthToken, CallResult, ClientConfig, ClientInstance, Codec, ContentBodySerializer, ContentType, DataOf, DataShape, Deserializer, EmptyErrorBody, ErrorOf, InterceptorFn, InterceptorStack, Interceptors, Options, RequestConfig, RequestCredentials, RequestResult, ResolvedRequest, ResponseError, ResponseErrorConfig, ResponseType, ResponseTypeMap, ResultByStatus, ResultUnion, SuccessOf, SuccessResultUnion, SuccessStatusCode, SuccessVariant, ToStatusNumber, Transport, TransportResult, Unwrappable, UnwrappedResult, UrlConfig, type ValidateOption, type ValidationErrorContext, type ValidationErrorHandler, Validator, createClientCore, createInterceptorStack, getHeader, getResponseContentType, isStreamed, parseJsonOrText, readResponse, resolveAuth, resolveResponseType, toRequestInit, unwrapResult, withUnwrap };
@@ -1,5 +1,5 @@
1
1
  import { a as ValidateOption, i as StandardSchemaValidator, s as ValidationErrorHandler } from "../standardSchema-B2AxHwZB.js";
2
- import { M as SuccessOf, m as DataShape, n as NativeRequest, r as NativeResponse, w as RequestResult, x as Options } from "../client-D0IfSe5q.js";
2
+ import { M as SuccessOf, m as DataShape, n as NativeRequest, r as NativeResponse, w as RequestResult, x as Options } from "../client-DaI8VaEz.js";
3
3
  /**
4
4
  * One decoded Server-Sent Event. `data` is parsed as JSON when valid and kept as the raw string otherwise,
5
5
  * `event` is `message` when the server sent no `event` field, and `id` is the last event ID the stream has set.
@@ -29,11 +29,13 @@ Each generated call now includes the schemas:
29
29
  request({
30
30
  method: 'POST',
31
31
  url: '/pet',
32
- validator: { response: addPetResponseSchema, error: addPetErrorSchema, errorStatus: [405] },
33
32
  ...config,
33
+ validator: { response: addPetResponseSchema, error: { 405: addPetStatus405Schema }, ...config.validator },
34
34
  })
35
35
  ```
36
36
 
37
+ A `validator` passed on one call is merged per key, so `validator: { request }` adds a request schema and keeps the generated response schema. A per-call `error` replaces the generated error map as a whole.
38
+
37
39
  Add a `validator` field to your `RequestConfig`, then run the schemas in `client`. Zod schemas follow [Standard Schema](https://standardschema.dev), so `~standard.validate` works with any compatible library:
38
40
 
39
41
  ```typescript [src/client.ts]
@@ -42,7 +44,7 @@ type Schema = { '~standard': { validate: (value: unknown) => Result | Promise<Re
42
44
 
43
45
  export type RequestConfig = {
44
46
  // ...
45
- validator?: { request?: Schema; response?: Schema; error?: Schema; errorStatus?: Array<number | string> }
47
+ validator?: { request?: Schema; response?: Schema; error?: Schema | Record<string, Schema> }
46
48
  }
47
49
 
48
50
  // inside client(), after reading the body
@@ -53,7 +55,7 @@ const validatedBody = result && 'value' in result ? result.value : body
53
55
 
54
56
  Return `validatedBody` as `data`, so a schema that transforms the value takes effect. Without a response schema, `validatedBody` is the original `body`.
55
57
 
56
- `errorStatus` lists the statuses `error` covers. Skip `error` for any other status.
58
+ `error` is keyed by status, such as `{ 404: schema, '5XX': schema, default: schema }`. Pick the exact status, then its range, then `default`, and skip validation when none matches.
57
59
 
58
60
  Set `validator: { request: 'zod' }` or `{ response: 'zod' }` to pass one direction only. Without `pluginZod()` in the plugins list, generation stops with an error.
59
61
 
@@ -65,12 +67,13 @@ With `validator: { params: 'zod' }`, each call also passes the schemas for its p
65
67
  request({
66
68
  method: 'PUT',
67
69
  url: '/events/{day}',
70
+ ...config,
68
71
  validator: {
69
72
  path: putEventPathSchema,
70
73
  query: putEventQuerySchema,
71
74
  headers: toHeadersStandardSchema(putEventHeadersSchema, putEventHeadersSchema.shape),
75
+ ...config.validator,
72
76
  },
73
- ...config,
74
77
  })
75
78
  ```
76
79
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kubb/plugin-client",
3
- "version": "6.1.0-canary.20261109T175349",
3
+ "version": "6.1.0-canary.20261109T175913",
4
4
  "description": "Generate typed API operations against your own client module.",
5
5
  "keywords": [
6
6
  "api-client",
@@ -62,13 +62,13 @@
62
62
  },
63
63
  "dependencies": {
64
64
  "@kubb/kit": "^5.16.1",
65
- "@kubb/plugin-ts": "^5.5.0-canary.20261109T175348",
66
- "@kubb/plugin-zod": "^5.9.0-canary.20261109T175348",
65
+ "@kubb/plugin-ts": "^5.5.0-canary.20261109T175913",
66
+ "@kubb/plugin-zod": "^5.9.0-canary.20261109T175913",
67
67
  "@kubb/renderer-jsx": "^5.16.1"
68
68
  },
69
69
  "devDependencies": {
70
- "@internals/client": "0.1.0-canary.20261109T175348",
71
- "@internals/shared": "0.1.0-canary.20261109T175348",
70
+ "@internals/client": "0.1.0-canary.20261109T175913",
71
+ "@internals/shared": "0.1.0-canary.20261109T175913",
72
72
  "typescript": "^7.0.2"
73
73
  },
74
74
  "peerDependencies": {},
package/templates/core.ts CHANGED
@@ -226,7 +226,7 @@ export type RequestConfig<TBody = unknown, TRequest = NativeRequest, TResponse =
226
226
  transport?: Transport<TRequest, TResponse>
227
227
  serializer?: Serializers
228
228
  codecs?: Record<string, Codec>
229
- /** `errorStatus` lists the statuses `error` covers, such as `[404, '5XX']`. Without it, `error` checks every non-2xx body. */
229
+ /** `error` takes one validator for every non-2xx body, or a map by status such as `{ 404: schema, '5XX': schema, default: schema }`. */
230
230
  validator?: {
231
231
  request?: Validator
232
232
  path?: Validator
@@ -234,8 +234,7 @@ export type RequestConfig<TBody = unknown, TRequest = NativeRequest, TResponse =
234
234
  headers?: Validator
235
235
  cookies?: Validator
236
236
  response?: Validator
237
- error?: Validator
238
- errorStatus?: Array<number | string>
237
+ error?: Validator | Record<string, Validator>
239
238
  }
240
239
  onValidationError?: ValidationErrorHandler
241
240
  validate?: ValidateOption
@@ -627,9 +626,11 @@ export async function readResponse<TRequest, TResponse extends Response>(
627
626
  }
628
627
  }
629
628
 
630
- /** Returns `true` when `statuses` is unset or lists `status`, directly or by a range key such as `'5XX'`. */
631
- function coversStatus(statuses: ReadonlyArray<number | string> | undefined, status: number): boolean {
632
- return !statuses || statuses.some((code) => [String(status), `${String(status)[0]}XX`].includes(String(code).toUpperCase()))
629
+ /** Picks the error validator for `status`: the exact status, then its range such as `5XX`, then `default`. */
630
+ function pickErrorValidator(error: Validator | Record<string, Validator> | undefined, status: number): Validator | undefined {
631
+ if (!error || '~standard' in error) return error as Validator | undefined
632
+ const range = Object.keys(error).find((key) => key.toUpperCase() === `${String(status)[0]}XX`)
633
+ return error[String(status)] ?? (range ? error[range] : undefined) ?? error.default
633
634
  }
634
635
 
635
636
  /**
@@ -828,10 +829,9 @@ export function createClientCore<TRequest = NativeRequest, TResponse = NativeRes
828
829
  // A streamed success body is validated event by event in `toEventStream`, not as a whole. A JSON answer to a streamed call is a whole body.
829
830
  const streaming = isSuccess && resolveResponseType(resolvedRequest.responseType, contentType) === 'stream' && isStreamed(decoded)
830
831
  // An error body is validated only when the call returns it. A call that throws keeps its `ResponseError`.
831
- const declared = isSuccess || coversStatus(validator?.errorStatus, result.status)
832
- const validatesBody = isValidationEnabled(validate, direction) && !streaming && declared && (isSuccess || !throwOnError)
832
+ const validatesBody = isValidationEnabled(validate, direction) && !streaming && (isSuccess || !throwOnError)
833
833
  const data = await runValidator({
834
- validator: validatesBody ? validator?.[direction] : undefined,
834
+ validator: validatesBody ? (isSuccess ? validator?.response : pickErrorValidator(validator?.error, result.status)) : undefined,
835
835
  value: decoded,
836
836
  context: { direction, source: 'body', method: resolvedRequest.method, url: resolvedRequest.url, status: result.status },
837
837
  onValidationError,