@kubb/plugin-axios 5.4.0-canary.20260910T110004 → 5.4.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/package.json +9 -5
- package/templates/axios.ts +76 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kubb/plugin-axios",
|
|
3
|
-
"version": "5.4.0
|
|
3
|
+
"version": "5.4.0",
|
|
4
4
|
"description": "Generate a slim, type-safe HTTP client with Kubb based on axios.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"api-client",
|
|
@@ -29,6 +29,10 @@
|
|
|
29
29
|
{
|
|
30
30
|
"type": "opencollective",
|
|
31
31
|
"url": "https://opencollective.com/kubb"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"type": "custom",
|
|
35
|
+
"url": "https://kubb.dev/sponsors"
|
|
32
36
|
}
|
|
33
37
|
],
|
|
34
38
|
"files": [
|
|
@@ -61,12 +65,12 @@
|
|
|
61
65
|
"registry": "https://registry.npmjs.org/"
|
|
62
66
|
},
|
|
63
67
|
"dependencies": {
|
|
64
|
-
"@kubb/plugin-ts": "^5.
|
|
65
|
-
"@kubb/plugin-zod": "^5.
|
|
68
|
+
"@kubb/plugin-ts": "^5.0.2",
|
|
69
|
+
"@kubb/plugin-zod": "^5.1.5"
|
|
66
70
|
},
|
|
67
71
|
"devDependencies": {
|
|
68
|
-
"@internals/client": "0.
|
|
69
|
-
"@internals/shared": "0.
|
|
72
|
+
"@internals/client": "0.0.0",
|
|
73
|
+
"@internals/shared": "0.0.0",
|
|
70
74
|
"axios": "^1.20.0",
|
|
71
75
|
"kubb": "^5.2.0",
|
|
72
76
|
"typescript": "^6.0.3"
|
package/templates/axios.ts
CHANGED
|
@@ -2,7 +2,7 @@ import axios from 'axios'
|
|
|
2
2
|
import type { AxiosError, AxiosInstance, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from 'axios'
|
|
3
3
|
import { applyHeaderStyles, defaultBodySerializer, defaultPathSerializer, defaultQuerySerializer, isDefaultJsonBody, serializeCookies } from './serializers'
|
|
4
4
|
import type { HeadersInit, PathParamStyle, PathSerializer, Serializers, Styles } from './serializers'
|
|
5
|
-
import { type StandardSchemaValidator, validateStandardSchema } from './standardSchema'
|
|
5
|
+
import { ParseError, type StandardSchemaValidator, validateStandardSchema } from './standardSchema'
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* HTTP status codes treated as a success, everything else is an error.
|
|
@@ -174,6 +174,25 @@ export type ContentType = string | { request?: string; response?: string }
|
|
|
174
174
|
*/
|
|
175
175
|
export type Validator<T = unknown> = StandardSchemaValidator<T>
|
|
176
176
|
|
|
177
|
+
/**
|
|
178
|
+
* The failing body and the call it came from, handed to `onValidationError` alongside the `ParseError`.
|
|
179
|
+
* `direction` says which slot rejected it: the request body, the success body, or the error body.
|
|
180
|
+
*/
|
|
181
|
+
export type ValidationErrorContext = {
|
|
182
|
+
value: unknown
|
|
183
|
+
direction: 'request' | 'response' | 'error'
|
|
184
|
+
method?: string
|
|
185
|
+
url?: string
|
|
186
|
+
status?: number
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Decides what a failed validation does. Returning nothing rethrows the `ParseError`; returning
|
|
191
|
+
* `{ value }` resolves the call with that value instead, so a drifted body can be reported and still
|
|
192
|
+
* delivered. The box keeps an explicit `{ value: undefined }` substitution distinct from declining.
|
|
193
|
+
*/
|
|
194
|
+
export type ValidationErrorHandler = (error: ParseError, context: ValidationErrorContext) => { value: unknown } | void | Promise<{ value: unknown } | void>
|
|
195
|
+
|
|
177
196
|
/**
|
|
178
197
|
* A resolved security scheme carried on each generated call's `security` array and passed to the `auth` resolver.
|
|
179
198
|
*/
|
|
@@ -224,6 +243,7 @@ export type RequestConfig<TBody = unknown, TRequest = AxiosRequestConfig, TRespo
|
|
|
224
243
|
serializer?: Serializers
|
|
225
244
|
codecs?: Record<string, Codec>
|
|
226
245
|
validator?: { request?: Validator; response?: Validator; error?: Validator }
|
|
246
|
+
onValidationError?: ValidationErrorHandler
|
|
227
247
|
security?: Array<Auth>
|
|
228
248
|
auth?: AuthResolver
|
|
229
249
|
}
|
|
@@ -253,6 +273,7 @@ export type ClientConfig = {
|
|
|
253
273
|
transport?: AxiosInstance
|
|
254
274
|
serializer?: Serializers
|
|
255
275
|
codecs?: Record<string, Codec>
|
|
276
|
+
onValidationError?: ValidationErrorHandler
|
|
256
277
|
auth?: AuthResolver
|
|
257
278
|
}
|
|
258
279
|
|
|
@@ -431,9 +452,26 @@ export async function resolveAuth(params: {
|
|
|
431
452
|
}
|
|
432
453
|
}
|
|
433
454
|
|
|
434
|
-
async function runValidator<T>(
|
|
455
|
+
async function runValidator<T>({
|
|
456
|
+
validator,
|
|
457
|
+
value,
|
|
458
|
+
context,
|
|
459
|
+
onValidationError,
|
|
460
|
+
}: {
|
|
461
|
+
validator: Validator<T> | undefined
|
|
462
|
+
value: T
|
|
463
|
+
context: Omit<ValidationErrorContext, 'value'>
|
|
464
|
+
onValidationError: ValidationErrorHandler | undefined
|
|
465
|
+
}): Promise<T> {
|
|
435
466
|
if (!validator) return value
|
|
436
|
-
|
|
467
|
+
try {
|
|
468
|
+
return await validateStandardSchema(validator, value)
|
|
469
|
+
} catch (error) {
|
|
470
|
+
if (!onValidationError || !(error instanceof ParseError)) throw error
|
|
471
|
+
const handled = await onValidationError(error, { ...context, value })
|
|
472
|
+
if (!handled) throw error
|
|
473
|
+
return handled.value as T
|
|
474
|
+
}
|
|
437
475
|
}
|
|
438
476
|
|
|
439
477
|
/**
|
|
@@ -509,7 +547,12 @@ async function resolveRequest<TBody, TRequest, TResponse>({
|
|
|
509
547
|
if (cookie) headers['Cookie'] = [headers['Cookie'], cookie].filter(Boolean).join('; ')
|
|
510
548
|
}
|
|
511
549
|
|
|
512
|
-
const validatedBody = await runValidator(
|
|
550
|
+
const validatedBody = await runValidator({
|
|
551
|
+
validator: requestConfig.validator?.request,
|
|
552
|
+
value: requestConfig.body,
|
|
553
|
+
context: { direction: 'request', method: requestConfig.method, url: requestConfig.url },
|
|
554
|
+
onValidationError: requestConfig.onValidationError ?? config.onValidationError,
|
|
555
|
+
})
|
|
513
556
|
const requestContentTypeBase = baseContentType(requestContentType)
|
|
514
557
|
const contentCodec = requestContentTypeBase ? codecs[requestContentTypeBase] : undefined
|
|
515
558
|
const usesDefaultBodySerializer = !contentCodec?.serialize && bodySerializer === defaultBodySerializer
|
|
@@ -571,10 +614,12 @@ async function settleResponse<TRequest, TResponse>({
|
|
|
571
614
|
response,
|
|
572
615
|
codecs,
|
|
573
616
|
validator,
|
|
617
|
+
onValidationError,
|
|
574
618
|
}: {
|
|
575
619
|
response: AxiosResponse
|
|
576
620
|
codecs: Record<string, Codec>
|
|
577
621
|
validator: { response?: Validator; error?: Validator } | undefined
|
|
622
|
+
onValidationError: ValidationErrorHandler | undefined
|
|
578
623
|
}): Promise<CallResult<TRequest, TResponse>> {
|
|
579
624
|
const isSuccess = response.status >= 200 && response.status < 300
|
|
580
625
|
const contentType = getResponseContentType(response.headers as Record<string, unknown>)
|
|
@@ -583,8 +628,27 @@ async function settleResponse<TRequest, TResponse>({
|
|
|
583
628
|
const codec = codecs[contentType]
|
|
584
629
|
if (codec?.deserialize) decoded = await codec.deserialize(response.data, contentType)
|
|
585
630
|
}
|
|
586
|
-
const
|
|
587
|
-
|
|
631
|
+
const validationContext = {
|
|
632
|
+
method: response.config?.method?.toUpperCase(),
|
|
633
|
+
url: response.config?.url,
|
|
634
|
+
status: response.status,
|
|
635
|
+
}
|
|
636
|
+
const data = isSuccess
|
|
637
|
+
? await runValidator({
|
|
638
|
+
validator: validator?.response,
|
|
639
|
+
value: decoded,
|
|
640
|
+
context: { direction: 'response', ...validationContext },
|
|
641
|
+
onValidationError,
|
|
642
|
+
})
|
|
643
|
+
: undefined
|
|
644
|
+
const error = isSuccess
|
|
645
|
+
? undefined
|
|
646
|
+
: await runValidator({
|
|
647
|
+
validator: validator?.error,
|
|
648
|
+
value: decoded,
|
|
649
|
+
context: { direction: 'error', ...validationContext },
|
|
650
|
+
onValidationError,
|
|
651
|
+
})
|
|
588
652
|
return {
|
|
589
653
|
status: response.status,
|
|
590
654
|
data,
|
|
@@ -629,7 +693,12 @@ export function createClientCore<TRequest = AxiosRequestConfig, TResponse = Axio
|
|
|
629
693
|
|
|
630
694
|
try {
|
|
631
695
|
const response = await activeInstance.request<unknown, AxiosResponse>(axiosConfig)
|
|
632
|
-
return await settleResponse({
|
|
696
|
+
return await settleResponse({
|
|
697
|
+
response,
|
|
698
|
+
codecs,
|
|
699
|
+
validator: requestConfig.validator,
|
|
700
|
+
onValidationError: requestConfig.onValidationError ?? config.onValidationError,
|
|
701
|
+
})
|
|
633
702
|
} catch (error) {
|
|
634
703
|
const axiosError = error as AxiosError
|
|
635
704
|
if (throwOnError && axiosError.response) {
|