@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.
- package/dist/{client-CiHb_Cfg.d.ts → client-BxO6Dygu.d.ts} +13 -3
- package/dist/index.cjs +68 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +68 -14
- package/dist/index.js.map +1 -1
- package/dist/templates/client.d.ts +1 -1
- package/dist/templates/core.d.ts +2 -2
- package/dist/templates/sse.d.ts +1 -1
- package/docs/guides/write-your-client.md +3 -0
- package/package.json +5 -5
- package/templates/core.ts +30 -3
- package/templates/sse.ts +2 -1
package/dist/templates/core.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { a as ValidateOption, o as ValidationErrorContext, s as ValidationErrorHandler } from "../standardSchema-BShJWz2i.js";
|
|
2
|
-
import { A as
|
|
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 };
|
package/dist/templates/sse.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as ValidateOption, i as StandardSchemaValidator, s as ValidationErrorHandler } from "../standardSchema-BShJWz2i.js";
|
|
2
|
-
import {
|
|
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
|
|
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.
|
|
66
|
-
"@kubb/plugin-zod": "^5.
|
|
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.
|
|
71
|
-
"@internals/shared": "0.
|
|
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
|
-
|
|
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
|
}
|