@kubb/plugin-fetch 5.7.1 → 5.7.2
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/index.cjs +10 -34
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +11 -35
- package/dist/index.js.map +1 -1
- package/dist/templates/serializers.d.ts +7 -3
- package/package.json +5 -5
- package/src/plugin.ts +1 -22
- package/templates/serializers.ts +31 -5
|
@@ -22,10 +22,14 @@ export type SerializationStyle<TStyle = string> = {
|
|
|
22
22
|
explode?: boolean;
|
|
23
23
|
allowReserved?: boolean;
|
|
24
24
|
};
|
|
25
|
+
/** The media type of a parameter described with `content`; JSON sends one JSON-encoded value. */
|
|
26
|
+
export type ParamContentType = {
|
|
27
|
+
contentType?: string;
|
|
28
|
+
};
|
|
25
29
|
/**
|
|
26
30
|
* The per-parameter query serialization metadata carried by the generated request.
|
|
27
31
|
*/
|
|
28
|
-
export type QueryParamStyle = SerializationStyle<QueryStyle
|
|
32
|
+
export type QueryParamStyle = SerializationStyle<QueryStyle> & ParamContentType;
|
|
29
33
|
/**
|
|
30
34
|
* Serializes the query object into a search string. The optional second argument carries the
|
|
31
35
|
* per-parameter OpenAPI `style` / `explode` / `allowReserved` metadata; without it arrays explode
|
|
@@ -36,7 +40,7 @@ export type QuerySerializer = (params: Record<string, unknown>, options?: Record
|
|
|
36
40
|
* The per-parameter cookie serialization metadata carried by the generated request. Cookies use the
|
|
37
41
|
* OpenAPI `form` style, so only `explode` is configurable.
|
|
38
42
|
*/
|
|
39
|
-
export type CookieParamStyle = {
|
|
43
|
+
export type CookieParamStyle = ParamContentType & {
|
|
40
44
|
explode?: boolean;
|
|
41
45
|
};
|
|
42
46
|
/**
|
|
@@ -49,7 +53,7 @@ export type CookieParamStyle = {
|
|
|
49
53
|
* // styles.header: { 'X-Filter': { explode: true } }, header { role: 'admin' } -> 'X-Filter: role=admin'
|
|
50
54
|
* ```
|
|
51
55
|
*/
|
|
52
|
-
export type HeaderParamStyle = {
|
|
56
|
+
export type HeaderParamStyle = ParamContentType & {
|
|
53
57
|
explode?: boolean;
|
|
54
58
|
};
|
|
55
59
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kubb/plugin-fetch",
|
|
3
|
-
"version": "5.7.
|
|
3
|
+
"version": "5.7.2",
|
|
4
4
|
"description": "Generate a slim, type-safe HTTP client with Kubb based on the native Fetch api.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"api-client",
|
|
@@ -80,17 +80,17 @@
|
|
|
80
80
|
"registry": "https://registry.npmjs.org/"
|
|
81
81
|
},
|
|
82
82
|
"dependencies": {
|
|
83
|
-
"@kubb/plugin-ts": "^5.0.
|
|
84
|
-
"@kubb/plugin-zod": "^5.
|
|
83
|
+
"@kubb/plugin-ts": "^5.0.16",
|
|
84
|
+
"@kubb/plugin-zod": "^5.5.0"
|
|
85
85
|
},
|
|
86
86
|
"devDependencies": {
|
|
87
87
|
"@internals/client": "0.0.0",
|
|
88
88
|
"@internals/shared": "0.0.0",
|
|
89
|
-
"kubb": "^5.12.
|
|
89
|
+
"kubb": "^5.12.8",
|
|
90
90
|
"typescript": "^7.0.2"
|
|
91
91
|
},
|
|
92
92
|
"peerDependencies": {
|
|
93
|
-
"kubb": "^5.12.
|
|
93
|
+
"kubb": "^5.12.8"
|
|
94
94
|
},
|
|
95
95
|
"engines": {
|
|
96
96
|
"node": ">=22.12"
|
package/src/plugin.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import path from 'node:path'
|
|
2
2
|
import { createSdkGenerator, defaultMacros, isValidatorEnabled, resolverClient } from '@internals/client'
|
|
3
3
|
import { createGroupConfig } from '@internals/shared'
|
|
4
|
-
import { addGenerator,
|
|
4
|
+
import { addGenerator, defineExtension, injectFile, Resolver, setMacros, setResolver, useConfig } from 'kubb/kit'
|
|
5
5
|
import { compatibility } from '../kubb-extension.json'
|
|
6
6
|
import { version } from '../package.json'
|
|
7
7
|
import { pluginTsName } from '@kubb/plugin-ts'
|
|
@@ -74,27 +74,6 @@ export const pluginFetch = defineExtension<PluginFetch>({
|
|
|
74
74
|
resolver: userResolver ? Resolver.merge<ResolverClient>(resolverClient, userResolver) : resolverClient,
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
const allowedReturnTypes = ['full', 'data', 'plain'] satisfies Array<ResolvedOptions['returnType']>
|
|
78
|
-
assertPluginOption({ plugin: pluginFetchName, option: 'returnType', value: returnType, allowed: allowedReturnTypes })
|
|
79
|
-
// An override replaces `returnType` per operation, so its values are checked too.
|
|
80
|
-
for (const [index, entry] of override.entries()) {
|
|
81
|
-
if (entry.options.returnType === undefined) continue
|
|
82
|
-
assertPluginOption({
|
|
83
|
-
plugin: pluginFetchName,
|
|
84
|
-
option: `override[${index}].options.returnType`,
|
|
85
|
-
value: entry.options.returnType,
|
|
86
|
-
allowed: allowedReturnTypes,
|
|
87
|
-
})
|
|
88
|
-
}
|
|
89
|
-
if (resolved.sdk) {
|
|
90
|
-
assertPluginOption({
|
|
91
|
-
plugin: pluginFetchName,
|
|
92
|
-
option: 'sdk.mode',
|
|
93
|
-
value: resolved.sdk.mode,
|
|
94
|
-
allowed: ['tag', 'flat'] satisfies Array<NonNullable<ResolvedOptions['sdk']>['mode']>,
|
|
95
|
-
})
|
|
96
|
-
}
|
|
97
|
-
|
|
98
77
|
setResolver(resolved.resolver)
|
|
99
78
|
setMacros([...defaultMacros, ...(options.macros ?? [])])
|
|
100
79
|
|
package/templates/serializers.ts
CHANGED
|
@@ -25,10 +25,15 @@ export type SerializationStyle<TStyle = string> = {
|
|
|
25
25
|
allowReserved?: boolean
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
/** The media type of a parameter described with `content`; JSON sends one JSON-encoded value. */
|
|
29
|
+
export type ParamContentType = {
|
|
30
|
+
contentType?: string
|
|
31
|
+
}
|
|
32
|
+
|
|
28
33
|
/**
|
|
29
34
|
* The per-parameter query serialization metadata carried by the generated request.
|
|
30
35
|
*/
|
|
31
|
-
export type QueryParamStyle = SerializationStyle<QueryStyle>
|
|
36
|
+
export type QueryParamStyle = SerializationStyle<QueryStyle> & ParamContentType
|
|
32
37
|
|
|
33
38
|
/**
|
|
34
39
|
* Serializes the query object into a search string. The optional second argument carries the
|
|
@@ -41,7 +46,7 @@ export type QuerySerializer = (params: Record<string, unknown>, options?: Record
|
|
|
41
46
|
* The per-parameter cookie serialization metadata carried by the generated request. Cookies use the
|
|
42
47
|
* OpenAPI `form` style, so only `explode` is configurable.
|
|
43
48
|
*/
|
|
44
|
-
export type CookieParamStyle = {
|
|
49
|
+
export type CookieParamStyle = ParamContentType & {
|
|
45
50
|
explode?: boolean
|
|
46
51
|
}
|
|
47
52
|
|
|
@@ -55,7 +60,7 @@ export type CookieParamStyle = {
|
|
|
55
60
|
* // styles.header: { 'X-Filter': { explode: true } }, header { role: 'admin' } -> 'X-Filter: role=admin'
|
|
56
61
|
* ```
|
|
57
62
|
*/
|
|
58
|
-
export type HeaderParamStyle = {
|
|
63
|
+
export type HeaderParamStyle = ParamContentType & {
|
|
59
64
|
explode?: boolean
|
|
60
65
|
}
|
|
61
66
|
|
|
@@ -195,6 +200,11 @@ function serializeUrlencodedBody(body: Record<string, unknown>, encoding: Record
|
|
|
195
200
|
return parts.join('&')
|
|
196
201
|
}
|
|
197
202
|
|
|
203
|
+
function isJsonMediaType(contentType: string | undefined): boolean {
|
|
204
|
+
const type = contentType?.split(';')[0]?.trim().toLowerCase()
|
|
205
|
+
return type === 'application/json' || !!type?.endsWith('+json')
|
|
206
|
+
}
|
|
207
|
+
|
|
198
208
|
function serializeCookie({ name, value, explode }: { name: string; value: unknown; explode: boolean }): string {
|
|
199
209
|
if (Array.isArray(value)) {
|
|
200
210
|
const items = value.filter(notNullish).map((item) => encodeURIComponent(toValue(item)))
|
|
@@ -225,7 +235,12 @@ export function serializeCookies(cookies: Record<string, unknown>, styles?: Reco
|
|
|
225
235
|
const parts: Array<string> = []
|
|
226
236
|
for (const [name, value] of Object.entries(cookies)) {
|
|
227
237
|
if (value === undefined || value === null) continue
|
|
228
|
-
|
|
238
|
+
const style = styles?.[name]
|
|
239
|
+
if (isJsonMediaType(style?.contentType)) {
|
|
240
|
+
parts.push(`${name}=${encodeURIComponent(JSON.stringify(value, jsonReplacer))}`)
|
|
241
|
+
continue
|
|
242
|
+
}
|
|
243
|
+
parts.push(serializeCookie({ name, value, explode: style?.explode ?? false }))
|
|
229
244
|
}
|
|
230
245
|
return parts.join('; ')
|
|
231
246
|
}
|
|
@@ -368,6 +383,10 @@ export const defaultQuerySerializer: QuerySerializer = (params, options) => {
|
|
|
368
383
|
const parts: Array<string> = []
|
|
369
384
|
for (const [key, value] of Object.entries(params)) {
|
|
370
385
|
const paramOptions = options?.[key]
|
|
386
|
+
if (notNullish(value) && isJsonMediaType(paramOptions?.contentType)) {
|
|
387
|
+
parts.push(`${encodeComponent(key)}=${encodeComponent(JSON.stringify(value, jsonReplacer))}`)
|
|
388
|
+
continue
|
|
389
|
+
}
|
|
371
390
|
parts.push(...(paramOptions ? serializeStyledQueryParam({ key, value, options: paramOptions }) : serializeDefaultQueryParam(key, value)))
|
|
372
391
|
}
|
|
373
392
|
return parts.join('&')
|
|
@@ -429,6 +448,11 @@ function serializeHeaderValue(value: unknown, explode: boolean): string {
|
|
|
429
448
|
.join(',')
|
|
430
449
|
}
|
|
431
450
|
|
|
451
|
+
/** Header values must be Latin-1, so non-ASCII characters become JSON `\uXXXX` escapes. */
|
|
452
|
+
function toAsciiJson(value: unknown): string {
|
|
453
|
+
return JSON.stringify(value, jsonReplacer).replace(/[\u007f-\uffff]/g, (char) => `\\u${char.charCodeAt(0).toString(16).padStart(4, '0')}`)
|
|
454
|
+
}
|
|
455
|
+
|
|
432
456
|
/**
|
|
433
457
|
* Serializes array and object header parameters with the OpenAPI `simple` style before they are
|
|
434
458
|
* merged. Header values are not URL-encoded. Primitive values and headers without metadata pass
|
|
@@ -439,7 +463,9 @@ export function applyHeaderStyles(headers: HeadersInit | undefined, styles: Reco
|
|
|
439
463
|
const entries = Array.isArray(headers) ? headers : Object.entries(headers)
|
|
440
464
|
return entries.map(([key, value]) => {
|
|
441
465
|
const style = styles[key]
|
|
442
|
-
if (!style || value === undefined || value === null
|
|
466
|
+
if (!style || value === undefined || value === null) return [key, value] as [string, HeaderValue]
|
|
467
|
+
if (isJsonMediaType(style.contentType)) return [key, toAsciiJson(value)] as [string, HeaderValue]
|
|
468
|
+
if (typeof value !== 'object') return [key, value] as [string, HeaderValue]
|
|
443
469
|
return [key, serializeHeaderValue(value, style.explode ?? false)] as [string, HeaderValue]
|
|
444
470
|
})
|
|
445
471
|
}
|