@kubb/plugin-fetch 5.4.1 → 5.4.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 +45 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +45 -2
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/src/plugin.ts +33 -3
- package/templates/fetch.ts +25 -22
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kubb/plugin-fetch",
|
|
3
|
-
"version": "5.4.
|
|
3
|
+
"version": "5.4.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",
|
|
@@ -66,16 +66,16 @@
|
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
68
|
"@kubb/plugin-ts": "^5.0.2",
|
|
69
|
-
"@kubb/plugin-zod": "^5.1
|
|
69
|
+
"@kubb/plugin-zod": "^5.2.1"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"@internals/client": "0.0.0",
|
|
73
73
|
"@internals/shared": "0.0.0",
|
|
74
|
-
"kubb": "^5.
|
|
74
|
+
"kubb": "^5.3.13",
|
|
75
75
|
"typescript": "^6.0.3"
|
|
76
76
|
},
|
|
77
77
|
"peerDependencies": {
|
|
78
|
-
"kubb": "^5.
|
|
78
|
+
"kubb": "^5.3.13"
|
|
79
79
|
},
|
|
80
80
|
"engines": {
|
|
81
81
|
"node": ">=22"
|
package/src/plugin.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs'
|
|
1
2
|
import path from 'node:path'
|
|
2
3
|
import { createSdkGenerator, defaultMacros, resolverClient } from '@internals/client'
|
|
3
4
|
import { createGroupConfig } from '@internals/shared'
|
|
4
|
-
import { definePlugin, Resolver } from 'kubb/kit'
|
|
5
|
+
import { ast, definePlugin, Resolver } from 'kubb/kit'
|
|
5
6
|
import { pluginTsName } from '@kubb/plugin-ts'
|
|
6
7
|
import { pluginZodName } from '@kubb/plugin-zod'
|
|
7
8
|
import { clientGenerator } from './generators/clientGenerator.tsx'
|
|
@@ -90,10 +91,39 @@ export const pluginFetch = definePlugin<PluginFetch>((options) => {
|
|
|
90
91
|
copy: fetchSerializersTemplatePath,
|
|
91
92
|
})
|
|
92
93
|
|
|
94
|
+
const clientPath = path.resolve(root, '.kubb/client.ts')
|
|
95
|
+
const clientSource = readFileSync(fetchClientTemplatePath, 'utf8')
|
|
96
|
+
const clientBody = clientSource.slice(clientSource.indexOf('\n\n') + 2)
|
|
97
|
+
const runtimeRoot = path.dirname(clientPath)
|
|
98
|
+
|
|
93
99
|
ctx.injectFile({
|
|
94
100
|
baseName: 'client.ts',
|
|
95
|
-
path:
|
|
96
|
-
|
|
101
|
+
path: clientPath,
|
|
102
|
+
imports: [
|
|
103
|
+
ast.factory.createImport({
|
|
104
|
+
name: ['applyHeaderStyles', 'defaultBodySerializer', 'defaultPathSerializer', 'defaultQuerySerializer', 'isDefaultJsonBody', 'serializeCookies'],
|
|
105
|
+
path: path.resolve(root, '.kubb/serializers.ts'),
|
|
106
|
+
root: runtimeRoot,
|
|
107
|
+
}),
|
|
108
|
+
ast.factory.createImport({
|
|
109
|
+
name: ['HeadersInit', 'PathParamStyle', 'PathSerializer', 'RequestBody', 'Serializers', 'Styles'],
|
|
110
|
+
path: path.resolve(root, '.kubb/serializers.ts'),
|
|
111
|
+
root: runtimeRoot,
|
|
112
|
+
isTypeOnly: true,
|
|
113
|
+
}),
|
|
114
|
+
ast.factory.createImport({
|
|
115
|
+
name: ['ParseError', 'validateStandardSchema'],
|
|
116
|
+
path: path.resolve(root, '.kubb/standardSchema.ts'),
|
|
117
|
+
root: runtimeRoot,
|
|
118
|
+
}),
|
|
119
|
+
ast.factory.createImport({
|
|
120
|
+
name: ['StandardSchemaValidator'],
|
|
121
|
+
path: path.resolve(root, '.kubb/standardSchema.ts'),
|
|
122
|
+
root: runtimeRoot,
|
|
123
|
+
isTypeOnly: true,
|
|
124
|
+
}),
|
|
125
|
+
],
|
|
126
|
+
sources: [ast.factory.createSource({ nodes: [ast.factory.createText(clientBody)] })],
|
|
97
127
|
footer: baseURLExpression ? `client.setConfig({ baseURL: ${baseURLExpression} })` : undefined,
|
|
98
128
|
})
|
|
99
129
|
|
package/templates/fetch.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { applyHeaderStyles, defaultBodySerializer, defaultPathSerializer, defaultQuerySerializer, isDefaultJsonBody, serializeCookies } from './serializers'
|
|
2
|
-
import type { HeadersInit, PathParamStyle, PathSerializer, RequestBody, Serializers, Styles } from './serializers'
|
|
3
|
-
import { ParseError, type StandardSchemaValidator, validateStandardSchema } from './standardSchema'
|
|
1
|
+
import { applyHeaderStyles, defaultBodySerializer, defaultPathSerializer, defaultQuerySerializer, isDefaultJsonBody, serializeCookies } from './serializers.ts'
|
|
2
|
+
import type { HeadersInit, PathParamStyle, PathSerializer, RequestBody, Serializers, Styles } from './serializers.ts'
|
|
3
|
+
import { ParseError, type StandardSchemaValidator, validateStandardSchema } from './standardSchema.ts'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* HTTP status codes treated as a success, everything else is an error.
|
|
@@ -317,25 +317,25 @@ export type CallResult<TRequest = Request, TResponse = Response> = {
|
|
|
317
317
|
response: TResponse
|
|
318
318
|
}
|
|
319
319
|
|
|
320
|
-
export type InterceptorFn<T> = (value: T) => T | Promise<T>
|
|
320
|
+
export type InterceptorFn<T, TContext = never> = (value: T, context?: TContext) => T | Promise<T>
|
|
321
321
|
|
|
322
322
|
/**
|
|
323
323
|
* A single interceptor channel with a transport-agnostic `use` / `eject` / `update` API.
|
|
324
324
|
*/
|
|
325
|
-
export type InterceptorStack<T> = {
|
|
326
|
-
use: (fn: InterceptorFn<T>) => number
|
|
325
|
+
export type InterceptorStack<T, TContext = never> = {
|
|
326
|
+
use: (fn: InterceptorFn<T, TContext>) => number
|
|
327
327
|
eject: (id: number) => void
|
|
328
|
-
update: (id: number, fn: InterceptorFn<T>) => void
|
|
329
|
-
run: (value: T) => Promise<T>
|
|
328
|
+
update: (id: number, fn: InterceptorFn<T, TContext>) => void
|
|
329
|
+
run: (value: T, context?: TContext) => Promise<T>
|
|
330
330
|
}
|
|
331
331
|
|
|
332
332
|
/**
|
|
333
333
|
* The three interceptor channels every client instance exposes.
|
|
334
334
|
*/
|
|
335
335
|
export type Interceptors<TRequest = Request, TResponse = Response> = {
|
|
336
|
-
request: InterceptorStack<ResolvedRequest
|
|
337
|
-
response: InterceptorStack<TransportResult<unknown, TRequest, TResponse>>
|
|
338
|
-
error: InterceptorStack<ResponseError<unknown, TRequest, TResponse>>
|
|
336
|
+
request: InterceptorStack<ResolvedRequest, RequestConfig<unknown, TRequest, TResponse>>
|
|
337
|
+
response: InterceptorStack<TransportResult<unknown, TRequest, TResponse>, RequestConfig<unknown, TRequest, TResponse>>
|
|
338
|
+
error: InterceptorStack<ResponseError<unknown, TRequest, TResponse>, RequestConfig<unknown, TRequest, TResponse>>
|
|
339
339
|
}
|
|
340
340
|
|
|
341
341
|
/**
|
|
@@ -426,8 +426,8 @@ function serializeUrl({
|
|
|
426
426
|
/**
|
|
427
427
|
* Creates a transport-agnostic interceptor channel that runs interceptors in registration order.
|
|
428
428
|
*/
|
|
429
|
-
export function createInterceptorStack<T>(): InterceptorStack<T> {
|
|
430
|
-
let entries: Array<{ id: number; fn: InterceptorFn<T> }> = []
|
|
429
|
+
export function createInterceptorStack<T, TContext = never>(): InterceptorStack<T, TContext> {
|
|
430
|
+
let entries: Array<{ id: number; fn: InterceptorFn<T, TContext> }> = []
|
|
431
431
|
let counter = 0
|
|
432
432
|
return {
|
|
433
433
|
use(fn) {
|
|
@@ -442,10 +442,10 @@ export function createInterceptorStack<T>(): InterceptorStack<T> {
|
|
|
442
442
|
const entry = entries.find((item) => item.id === id)
|
|
443
443
|
if (entry) entry.fn = fn
|
|
444
444
|
},
|
|
445
|
-
async run(value) {
|
|
445
|
+
async run(value, context) {
|
|
446
446
|
let result = value
|
|
447
447
|
for (const entry of entries) {
|
|
448
|
-
result = await entry.fn(result)
|
|
448
|
+
result = await entry.fn(result, context)
|
|
449
449
|
}
|
|
450
450
|
return result
|
|
451
451
|
},
|
|
@@ -640,6 +640,7 @@ async function settleResult<TRequest, TResponse>({
|
|
|
640
640
|
validator,
|
|
641
641
|
onValidationError,
|
|
642
642
|
errorInterceptors,
|
|
643
|
+
requestConfig,
|
|
643
644
|
}: {
|
|
644
645
|
result: TransportResult<unknown, TRequest, TResponse>
|
|
645
646
|
request: ResolvedRequest
|
|
@@ -647,7 +648,8 @@ async function settleResult<TRequest, TResponse>({
|
|
|
647
648
|
throwOnError: boolean
|
|
648
649
|
validator: { response?: Validator; error?: Validator } | undefined
|
|
649
650
|
onValidationError: ValidationErrorHandler | undefined
|
|
650
|
-
errorInterceptors: InterceptorStack<ResponseError<unknown, TRequest, TResponse>>
|
|
651
|
+
errorInterceptors: InterceptorStack<ResponseError<unknown, TRequest, TResponse>, RequestConfig<unknown, TRequest, TResponse>>
|
|
652
|
+
requestConfig: RequestConfig<unknown, TRequest, TResponse>
|
|
651
653
|
}): Promise<CallResult<TRequest, TResponse>> {
|
|
652
654
|
const isSuccess = result.status >= 200 && result.status < 300
|
|
653
655
|
const contentType = result.contentType ?? getResponseContentType(result.headers)
|
|
@@ -684,7 +686,7 @@ async function settleResult<TRequest, TResponse>({
|
|
|
684
686
|
request: result.request,
|
|
685
687
|
response: result.response,
|
|
686
688
|
})
|
|
687
|
-
await errorInterceptors.run(responseError)
|
|
689
|
+
await errorInterceptors.run(responseError, requestConfig)
|
|
688
690
|
throw responseError
|
|
689
691
|
}
|
|
690
692
|
return { status: result.status, data: undefined, error, contentType, request: result.request, response: result.response }
|
|
@@ -700,17 +702,17 @@ export function createClientCore<TRequest = Request, TResponse = Response>(
|
|
|
700
702
|
let config: ClientConfig<TRequest, TResponse> = { ...initialConfig }
|
|
701
703
|
|
|
702
704
|
const interceptors: Interceptors<TRequest, TResponse> = {
|
|
703
|
-
request: createInterceptorStack<ResolvedRequest
|
|
704
|
-
response: createInterceptorStack<TransportResult<unknown, TRequest, TResponse>>(),
|
|
705
|
-
error: createInterceptorStack<ResponseError<unknown, TRequest, TResponse>>(),
|
|
705
|
+
request: createInterceptorStack<ResolvedRequest, RequestConfig<unknown, TRequest, TResponse>>(),
|
|
706
|
+
response: createInterceptorStack<TransportResult<unknown, TRequest, TResponse>, RequestConfig<unknown, TRequest, TResponse>>(),
|
|
707
|
+
error: createInterceptorStack<ResponseError<unknown, TRequest, TResponse>, RequestConfig<unknown, TRequest, TResponse>>(),
|
|
706
708
|
}
|
|
707
709
|
|
|
708
710
|
const client = (async <TBody = unknown>(requestConfig: RequestConfig<TBody, TRequest, TResponse>): Promise<CallResult<TRequest, TResponse>> => {
|
|
709
711
|
const transport = requestConfig.transport ?? config.transport ?? defaultTransport
|
|
710
712
|
const { request, codecs } = await resolveRequest({ config, requestConfig })
|
|
711
713
|
|
|
712
|
-
const resolvedRequest = await interceptors.request.run(request)
|
|
713
|
-
const result = await interceptors.response.run(await transport(resolvedRequest))
|
|
714
|
+
const resolvedRequest = await interceptors.request.run(request, requestConfig)
|
|
715
|
+
const result = await interceptors.response.run(await transport(resolvedRequest), requestConfig)
|
|
714
716
|
|
|
715
717
|
return settleResult({
|
|
716
718
|
result,
|
|
@@ -720,6 +722,7 @@ export function createClientCore<TRequest = Request, TResponse = Response>(
|
|
|
720
722
|
validator: requestConfig.validator,
|
|
721
723
|
onValidationError: requestConfig.onValidationError ?? config.onValidationError,
|
|
722
724
|
errorInterceptors: interceptors.error,
|
|
725
|
+
requestConfig,
|
|
723
726
|
})
|
|
724
727
|
}) as ClientInstance<TRequest, TResponse>
|
|
725
728
|
|