@kubb/plugin-client 5.11.0-canary.20261106T171559 → 5.11.0

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,3 +1,3 @@
1
1
  import { a as ValidateOption, o as ValidationErrorContext, s as ValidationErrorHandler } from "../standardSchema-BShJWz2i.js";
2
- import { A as SuccessResultUnion, B as createClientCore, C as ResolvedRequest, D as ResultByStatus, E as ResponseType, F as TransportResult, G as unwrapResult, H as getResponseContentType, I as Unwrappable, K as withUnwrap, L as UnwrappedResult, M as SuccessVariant, N as ToStatusNumber, O as ResultUnion, P as Transport, R as UrlConfig, S as RequestResult, T as ResponseErrorConfig, U as isStreamed, V as createInterceptorStack, W as resolveAuth, _ as InterceptorStack, a as AuthToken, b as RequestConfig, c as ClientInstance, d as ContentType, f as DataOf, g as InterceptorFn, h as ErrorOf, i as AuthResolver, j as SuccessStatusCode, k as SuccessOf, l as Codec, m as Deserializer, o as CallResult, p as DataShape, r as Auth, s as ClientConfig, u as ContentBodySerializer, v as Interceptors, w as ResponseError, x as RequestCredentials, y as Options, z as Validator } from "../client-CiHb_Cfg.js";
3
- export { Auth, AuthResolver, AuthToken, CallResult, ClientConfig, ClientInstance, Codec, ContentBodySerializer, ContentType, DataOf, DataShape, Deserializer, ErrorOf, InterceptorFn, InterceptorStack, Interceptors, Options, RequestConfig, RequestCredentials, RequestResult, ResolvedRequest, ResponseError, ResponseErrorConfig, ResponseType, ResultByStatus, ResultUnion, SuccessOf, SuccessResultUnion, SuccessStatusCode, SuccessVariant, ToStatusNumber, Transport, TransportResult, Unwrappable, UnwrappedResult, UrlConfig, type ValidateOption, type ValidationErrorContext, type ValidationErrorHandler, Validator, createClientCore, createInterceptorStack, getResponseContentType, isStreamed, resolveAuth, unwrapResult, withUnwrap };
2
+ import { A as SuccessOf, B as Validator, C as ResolvedRequest, D as ResponseTypeMap, E as ResponseType, F as Transport, G as resolveAuth, H as createInterceptorStack, I as TransportResult, J as withUnwrap, K as resolveResponseType, L as Unwrappable, M as SuccessStatusCode, N as SuccessVariant, O as ResultByStatus, P as ToStatusNumber, R as UnwrappedResult, S as RequestResult, T as ResponseErrorConfig, U as getResponseContentType, V as createClientCore, W as isStreamed, _ as InterceptorStack, a as AuthToken, b as RequestConfig, c as ClientInstance, d as ContentType, f as DataOf, g as InterceptorFn, h as ErrorOf, i as AuthResolver, j as SuccessResultUnion, k as ResultUnion, l as Codec, m as Deserializer, o as CallResult, p as DataShape, q as unwrapResult, r as Auth, s as ClientConfig, u as ContentBodySerializer, v as Interceptors, w as ResponseError, x as RequestCredentials, y as Options, z as UrlConfig } from "../client-BxO6Dygu.js";
3
+ export { Auth, AuthResolver, AuthToken, CallResult, ClientConfig, ClientInstance, Codec, ContentBodySerializer, ContentType, DataOf, DataShape, Deserializer, 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, getResponseContentType, isStreamed, resolveAuth, resolveResponseType, unwrapResult, withUnwrap };
@@ -1,5 +1,5 @@
1
1
  import { a as ValidateOption, i as StandardSchemaValidator, s as ValidationErrorHandler } from "../standardSchema-BShJWz2i.js";
2
- import { S as RequestResult, k as SuccessOf, n as NativeResponse, p as DataShape, t as NativeRequest, y as Options } from "../client-CiHb_Cfg.js";
2
+ import { A as SuccessOf, S as RequestResult, n as NativeResponse, p as DataShape, t as NativeRequest, y as Options } from "../client-BxO6Dygu.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.
@@ -45,6 +45,8 @@ export function getPetById<ThrowOnError extends boolean = true>(
45
45
 
46
46
  Your `client` receives `method`, the `url` template with `{param}` placeholders, `security`, the grouped `path`, `query`, `headers`, and `body`, and `throwOnError`. It returns a promise.
47
47
 
48
+ A non-JSON response also passes `responseType`. It is a string such as `'blob'` when every response content type uses one parser, or a map from content type to parser when they differ, for example `{ 'audio/mpeg': 'blob', 'text/event-stream': 'stream' }`. Read the response `Content-Type`, look it up in the map (exact type, then `type/*`, then `*/*`), and parse the body with that parser.
49
+
48
50
  ## A minimal client
49
51
 
50
52
  The client below uses `fetch`. Replace the transport with the HTTP library you use.
@@ -59,6 +61,7 @@ export type RequestConfig = {
59
61
  query?: object
60
62
  body?: unknown
61
63
  signal?: AbortSignal
64
+ responseType?: string | Record<string, string>
62
65
  throwOnError?: boolean
63
66
  security?: Array<{ type: string; name?: string; in?: string; scopes?: Array<string> }>
64
67
  client?: typeof client
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kubb/plugin-client",
3
- "version": "5.11.0-canary.20261106T171559",
3
+ "version": "5.11.0",
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.0",
65
- "@kubb/plugin-ts": "^5.5.0-canary.20261106T171558",
66
- "@kubb/plugin-zod": "^5.9.0-canary.20261106T171558",
65
+ "@kubb/plugin-ts": "^5.4.1",
66
+ "@kubb/plugin-zod": "^5.8.2",
67
67
  "@kubb/renderer-jsx": "^5.16.0"
68
68
  },
69
69
  "devDependencies": {
70
- "@internals/client": "0.1.0-canary.20261106T171558",
71
- "@internals/shared": "0.1.0-canary.20261106T171558",
70
+ "@internals/client": "0.0.0",
71
+ "@internals/shared": "0.0.0",
72
72
  "typescript": "^7.0.2"
73
73
  },
74
74
  "peerDependencies": {},
package/templates/core.ts CHANGED
@@ -6,6 +6,7 @@ import {
6
6
  defaultPathSerializer,
7
7
  defaultQuerySerializer,
8
8
  isDefaultJsonBody,
9
+ isJsonMediaType,
9
10
  serializeCookies,
10
11
  } from './serializers.ts'
11
12
  import type { HeadersInit, HttpMethod, PathParamStyle, PathSerializer, RequestBody, Serializers, Styles } from './serializers.ts'
@@ -133,6 +134,12 @@ export type DataShape = { body?: unknown; cookies?: unknown; headers?: unknown;
133
134
  export type RequestCredentials = 'omit' | 'same-origin' | 'include'
134
135
  export type ResponseType = 'arraybuffer' | 'blob' | 'document' | 'json' | 'text' | 'stream' | 'formdata'
135
136
 
137
+ /**
138
+ * Parser per response content type. Generated when one success response declares several content
139
+ * types that do not share a single parser. Keys are base media types, such as `audio/mpeg` or `audio/*`.
140
+ */
141
+ export type ResponseTypeMap = Record<string, ResponseType>
142
+
136
143
  /**
137
144
  * Decodes a response body for a codec's media type.
138
145
  */
@@ -200,7 +207,7 @@ export type RequestConfig<TBody = unknown, TRequest = NativeRequest, TResponse =
200
207
  credentials?: RequestCredentials
201
208
  options?: Record<string, unknown>
202
209
  contentType?: ContentType
203
- responseType?: ResponseType
210
+ responseType?: ResponseType | ResponseTypeMap
204
211
  throwOnError?: boolean
205
212
  client?: ClientInstance<TRequest, TResponse>
206
213
  transport?: Transport<TRequest, TResponse>
@@ -253,7 +260,7 @@ export type ResolvedRequest = {
253
260
  signal?: AbortSignal
254
261
  credentials?: RequestCredentials
255
262
  options?: Record<string, unknown>
256
- responseType?: ResponseType
263
+ responseType?: ResponseType | ResponseTypeMap
257
264
  }
258
265
 
259
266
  /**
@@ -493,6 +500,26 @@ export function isStreamed(data: unknown): data is ReadableStream<Uint8Array> |
493
500
  return data instanceof ReadableStream || (!!data && typeof data === 'object' && Symbol.asyncIterator in data)
494
501
  }
495
502
 
503
+ /**
504
+ * Picks the parser for a response. A string `responseType` wins. A map is matched against the media type: the exact
505
+ * type, then a wildcard such as `audio/*`, then a catch-all entry. Otherwise the parser is guessed from the media type.
506
+ */
507
+ export function resolveResponseType(
508
+ responseType: ResponseType | ResponseTypeMap | undefined,
509
+ contentType: string | null | undefined,
510
+ ): ResponseType | undefined {
511
+ if (typeof responseType === 'string') return responseType
512
+ const base = baseContentType(contentType)
513
+ if (!base) return undefined
514
+ const mapped = responseType?.[base] ?? responseType?.[`${base.split('/')[0]}/*`] ?? responseType?.['*/*']
515
+ if (mapped) return mapped
516
+ if (base === 'text/event-stream') return 'stream'
517
+ if (isJsonMediaType(base)) return 'json'
518
+ if (base.startsWith('text/')) return 'text'
519
+ if (base === 'application/octet-stream' || base === 'application/pdf' || /^(image|audio|video)\//.test(base)) return 'blob'
520
+ return undefined
521
+ }
522
+
496
523
  /** The media type of the `Content-Type` response header, without its parameters. */
497
524
  export function getResponseContentType(headers: Headers | Record<string, string> | undefined): string | undefined {
498
525
  if (!headers) return undefined
@@ -640,7 +667,7 @@ export function createClientCore<TRequest = NativeRequest, TResponse = NativeRes
640
667
  const codec = contentType ? codecs[contentType] : undefined
641
668
  const decoded = contentType && codec?.deserialize ? await codec.deserialize(result.data, contentType) : result.data
642
669
  // 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.
643
- const streaming = isSuccess && resolvedRequest.responseType === 'stream' && isStreamed(decoded)
670
+ const streaming = isSuccess && resolveResponseType(resolvedRequest.responseType, contentType) === 'stream' && isStreamed(decoded)
644
671
  const data = await runValidator({
645
672
  validator: isValidationEnabled(validate, direction) && !streaming ? validator?.[direction] : undefined,
646
673
  value: decoded,
package/templates/sse.ts CHANGED
@@ -235,7 +235,8 @@ export async function toEventStream<TData = unknown, TResponse = NativeResponse>
235
235
  const { data: body, error, status, contentType, request, response } = await call
236
236
  const ok = status === undefined || (status >= 200 && status < 300)
237
237
  // A transport decodes a JSON answer, so a success that is not a stream would otherwise end as an empty stream.
238
- if (ok && body !== undefined && !isStreamBody(body)) {
238
+ // A 204 or empty answer has no body, `undefined` or `null`, and still ends as an empty stream.
239
+ if (ok && body != null && !isStreamBody(body)) {
239
240
  // `cause` is assigned, since the constructor option needs the ES2022 library a generated client cannot assume.
240
241
  throw Object.assign(new TypeError(`Expected a text/event-stream body, got ${contentType ?? 'a body without a content type'}`), { cause: body })
241
242
  }