@kubb/plugin-client 5.0.0-beta.25 → 5.0.0-beta.27

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,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  //#region src/templates/clients/axios.source.ts
3
- const source = "import type { AxiosError, AxiosRequestConfig, AxiosResponse } from 'axios'\nimport axios from 'axios'\n\ndeclare const AXIOS_BASE: string\ndeclare const AXIOS_HEADERS: string\n\n/**\n * Subset of AxiosRequestConfig\n */\nexport type RequestConfig<TData = unknown> = {\n baseURL?: string\n url?: string\n method?: 'GET' | 'PUT' | 'PATCH' | 'POST' | 'DELETE' | 'OPTIONS' | 'HEAD'\n params?: unknown\n data?: TData | FormData\n responseType?: 'arraybuffer' | 'blob' | 'document' | 'json' | 'text' | 'stream'\n signal?: AbortSignal\n validateStatus?: (status: number) => boolean\n headers?: AxiosRequestConfig['headers']\n contentType?: string\n}\n\n/**\n * Subset of AxiosResponse\n */\nexport type ResponseConfig<TData = unknown> = {\n data: TData\n status: number\n statusText: string\n headers: AxiosResponse['headers']\n}\n\nexport type ResponseErrorConfig<TError = unknown> = AxiosError<TError>\n\nexport type Client = <TData, _TError = unknown, TVariables = unknown>(config: RequestConfig<TVariables>, request?: unknown) => Promise<ResponseConfig<TData>>\n\nlet _config: Partial<RequestConfig> = {\n baseURL: typeof AXIOS_BASE !== 'undefined' ? AXIOS_BASE : undefined,\n headers: typeof AXIOS_HEADERS !== 'undefined' ? JSON.parse(AXIOS_HEADERS) : undefined,\n}\n\nexport const getConfig = () => _config\n\nexport const setConfig = (config: RequestConfig) => {\n _config = config\n return getConfig()\n}\n\nexport const mergeConfig = <T extends RequestConfig>(...configs: Array<Partial<T>>): Partial<T> => {\n return configs.reduce<Partial<T>>((merged, config) => {\n return {\n ...merged,\n ...config,\n headers: {\n ...merged.headers,\n ...config.headers,\n },\n }\n }, {})\n}\n\nexport const axiosInstance = axios.create(getConfig())\n\nexport const fetch = async <TData, TError = unknown, TVariables = unknown>(\n config: RequestConfig<TVariables>,\n _request?: unknown,\n): Promise<ResponseConfig<TData>> => {\n const requestConfig = mergeConfig(getConfig(), config)\n const { contentType, headers, ...axiosConfig } = requestConfig\n return axiosInstance\n .request<TData, ResponseConfig<TData>>({\n ...axiosConfig,\n headers: {\n ...(contentType && contentType !== 'multipart/form-data' ? { 'Content-Type': contentType } : {}),\n ...headers,\n },\n })\n .catch((e: AxiosError<TError>) => {\n throw e\n })\n}\n\nfetch.getConfig = getConfig\nfetch.setConfig = setConfig\n";
3
+ const source = "import type { AxiosError, AxiosRequestConfig, AxiosResponse } from 'axios'\nimport axios from 'axios'\n\ndeclare const AXIOS_BASE: string\ndeclare const AXIOS_HEADERS: string\n\n/**\n * Header values may be objects (e.g. JSON-encoded headers like `X-Filter` in the Linode API).\n * Non-string values are JSON-serialized before the request is sent.\n */\nexport type HeaderValue = string | number | boolean | null | undefined | object\nexport type HeadersInit = Array<[string, HeaderValue]> | Record<string, HeaderValue>\n\n/**\n * Subset of AxiosRequestConfig\n */\nexport type RequestConfig<TData = unknown> = {\n baseURL?: string\n url?: string\n method?: 'GET' | 'PUT' | 'PATCH' | 'POST' | 'DELETE' | 'OPTIONS' | 'HEAD'\n params?: unknown\n data?: TData | FormData\n responseType?: 'arraybuffer' | 'blob' | 'document' | 'json' | 'text' | 'stream'\n signal?: AbortSignal\n validateStatus?: (status: number) => boolean\n headers?: HeadersInit\n contentType?: string\n}\n\n/**\n * Subset of AxiosResponse\n */\nexport type ResponseConfig<TData = unknown> = {\n data: TData\n status: number\n statusText: string\n headers: AxiosResponse['headers']\n}\n\nexport type ResponseErrorConfig<TError = unknown> = AxiosError<TError>\n\nexport type Client = <TData, _TError = unknown, TVariables = unknown>(config: RequestConfig<TVariables>, request?: unknown) => Promise<ResponseConfig<TData>>\n\nlet _config: Partial<RequestConfig> = {\n baseURL: typeof AXIOS_BASE !== 'undefined' ? AXIOS_BASE : undefined,\n headers: typeof AXIOS_HEADERS !== 'undefined' ? JSON.parse(AXIOS_HEADERS) : undefined,\n}\n\nexport const getConfig = () => _config\n\nexport const setConfig = (config: RequestConfig) => {\n _config = config\n return getConfig()\n}\n\nexport const mergeConfig = <T extends RequestConfig>(...configs: Array<Partial<T>>): Partial<T> => {\n return configs.reduce<Partial<T>>((merged, config) => {\n return {\n ...merged,\n ...config,\n headers: {\n ...(Array.isArray(merged.headers) ? Object.fromEntries(merged.headers) : merged.headers),\n ...(Array.isArray(config.headers) ? Object.fromEntries(config.headers) : config.headers),\n },\n }\n }, {})\n}\n\n/**\n * Serializes header values into the string form `axios` ultimately puts on the wire.\n * Objects (including arrays) are JSON-stringified so spec-defined object headers like `X-Filter`\n * are sent in their canonical JSON-string form rather than `[object Object]`.\n */\nfunction serializeHeaders(headers: HeadersInit | undefined): Record<string, string> {\n if (!headers) return {}\n const entries = Array.isArray(headers) ? headers : Object.entries(headers)\n const result: Record<string, string> = {}\n for (const [key, value] of entries) {\n if (value === undefined || value === null) continue\n result[key] = typeof value === 'string' ? value : typeof value === 'object' ? JSON.stringify(value) : String(value)\n }\n return result\n}\n\nexport const axiosInstance = axios.create(getConfig() as AxiosRequestConfig)\n\nexport const fetch = async <TData, TError = unknown, TVariables = unknown>(\n config: RequestConfig<TVariables>,\n _request?: unknown,\n): Promise<ResponseConfig<TData>> => {\n const requestConfig = mergeConfig(getConfig(), config)\n const { contentType, headers, ...axiosConfig } = requestConfig\n return axiosInstance\n .request<TData, ResponseConfig<TData>>({\n ...axiosConfig,\n headers: {\n ...(contentType && contentType !== 'multipart/form-data' ? { 'Content-Type': contentType } : {}),\n ...serializeHeaders(headers),\n },\n })\n .catch((e: AxiosError<TError>) => {\n throw e\n })\n}\n\nfetch.getConfig = getConfig\nfetch.setConfig = setConfig\n";
4
4
  //#endregion
5
5
  exports.source = source;
6
6
 
@@ -1,5 +1,5 @@
1
1
  //#region src/templates/clients/axios.source.ts
2
- const source = "import type { AxiosError, AxiosRequestConfig, AxiosResponse } from 'axios'\nimport axios from 'axios'\n\ndeclare const AXIOS_BASE: string\ndeclare const AXIOS_HEADERS: string\n\n/**\n * Subset of AxiosRequestConfig\n */\nexport type RequestConfig<TData = unknown> = {\n baseURL?: string\n url?: string\n method?: 'GET' | 'PUT' | 'PATCH' | 'POST' | 'DELETE' | 'OPTIONS' | 'HEAD'\n params?: unknown\n data?: TData | FormData\n responseType?: 'arraybuffer' | 'blob' | 'document' | 'json' | 'text' | 'stream'\n signal?: AbortSignal\n validateStatus?: (status: number) => boolean\n headers?: AxiosRequestConfig['headers']\n contentType?: string\n}\n\n/**\n * Subset of AxiosResponse\n */\nexport type ResponseConfig<TData = unknown> = {\n data: TData\n status: number\n statusText: string\n headers: AxiosResponse['headers']\n}\n\nexport type ResponseErrorConfig<TError = unknown> = AxiosError<TError>\n\nexport type Client = <TData, _TError = unknown, TVariables = unknown>(config: RequestConfig<TVariables>, request?: unknown) => Promise<ResponseConfig<TData>>\n\nlet _config: Partial<RequestConfig> = {\n baseURL: typeof AXIOS_BASE !== 'undefined' ? AXIOS_BASE : undefined,\n headers: typeof AXIOS_HEADERS !== 'undefined' ? JSON.parse(AXIOS_HEADERS) : undefined,\n}\n\nexport const getConfig = () => _config\n\nexport const setConfig = (config: RequestConfig) => {\n _config = config\n return getConfig()\n}\n\nexport const mergeConfig = <T extends RequestConfig>(...configs: Array<Partial<T>>): Partial<T> => {\n return configs.reduce<Partial<T>>((merged, config) => {\n return {\n ...merged,\n ...config,\n headers: {\n ...merged.headers,\n ...config.headers,\n },\n }\n }, {})\n}\n\nexport const axiosInstance = axios.create(getConfig())\n\nexport const fetch = async <TData, TError = unknown, TVariables = unknown>(\n config: RequestConfig<TVariables>,\n _request?: unknown,\n): Promise<ResponseConfig<TData>> => {\n const requestConfig = mergeConfig(getConfig(), config)\n const { contentType, headers, ...axiosConfig } = requestConfig\n return axiosInstance\n .request<TData, ResponseConfig<TData>>({\n ...axiosConfig,\n headers: {\n ...(contentType && contentType !== 'multipart/form-data' ? { 'Content-Type': contentType } : {}),\n ...headers,\n },\n })\n .catch((e: AxiosError<TError>) => {\n throw e\n })\n}\n\nfetch.getConfig = getConfig\nfetch.setConfig = setConfig\n";
2
+ const source = "import type { AxiosError, AxiosRequestConfig, AxiosResponse } from 'axios'\nimport axios from 'axios'\n\ndeclare const AXIOS_BASE: string\ndeclare const AXIOS_HEADERS: string\n\n/**\n * Header values may be objects (e.g. JSON-encoded headers like `X-Filter` in the Linode API).\n * Non-string values are JSON-serialized before the request is sent.\n */\nexport type HeaderValue = string | number | boolean | null | undefined | object\nexport type HeadersInit = Array<[string, HeaderValue]> | Record<string, HeaderValue>\n\n/**\n * Subset of AxiosRequestConfig\n */\nexport type RequestConfig<TData = unknown> = {\n baseURL?: string\n url?: string\n method?: 'GET' | 'PUT' | 'PATCH' | 'POST' | 'DELETE' | 'OPTIONS' | 'HEAD'\n params?: unknown\n data?: TData | FormData\n responseType?: 'arraybuffer' | 'blob' | 'document' | 'json' | 'text' | 'stream'\n signal?: AbortSignal\n validateStatus?: (status: number) => boolean\n headers?: HeadersInit\n contentType?: string\n}\n\n/**\n * Subset of AxiosResponse\n */\nexport type ResponseConfig<TData = unknown> = {\n data: TData\n status: number\n statusText: string\n headers: AxiosResponse['headers']\n}\n\nexport type ResponseErrorConfig<TError = unknown> = AxiosError<TError>\n\nexport type Client = <TData, _TError = unknown, TVariables = unknown>(config: RequestConfig<TVariables>, request?: unknown) => Promise<ResponseConfig<TData>>\n\nlet _config: Partial<RequestConfig> = {\n baseURL: typeof AXIOS_BASE !== 'undefined' ? AXIOS_BASE : undefined,\n headers: typeof AXIOS_HEADERS !== 'undefined' ? JSON.parse(AXIOS_HEADERS) : undefined,\n}\n\nexport const getConfig = () => _config\n\nexport const setConfig = (config: RequestConfig) => {\n _config = config\n return getConfig()\n}\n\nexport const mergeConfig = <T extends RequestConfig>(...configs: Array<Partial<T>>): Partial<T> => {\n return configs.reduce<Partial<T>>((merged, config) => {\n return {\n ...merged,\n ...config,\n headers: {\n ...(Array.isArray(merged.headers) ? Object.fromEntries(merged.headers) : merged.headers),\n ...(Array.isArray(config.headers) ? Object.fromEntries(config.headers) : config.headers),\n },\n }\n }, {})\n}\n\n/**\n * Serializes header values into the string form `axios` ultimately puts on the wire.\n * Objects (including arrays) are JSON-stringified so spec-defined object headers like `X-Filter`\n * are sent in their canonical JSON-string form rather than `[object Object]`.\n */\nfunction serializeHeaders(headers: HeadersInit | undefined): Record<string, string> {\n if (!headers) return {}\n const entries = Array.isArray(headers) ? headers : Object.entries(headers)\n const result: Record<string, string> = {}\n for (const [key, value] of entries) {\n if (value === undefined || value === null) continue\n result[key] = typeof value === 'string' ? value : typeof value === 'object' ? JSON.stringify(value) : String(value)\n }\n return result\n}\n\nexport const axiosInstance = axios.create(getConfig() as AxiosRequestConfig)\n\nexport const fetch = async <TData, TError = unknown, TVariables = unknown>(\n config: RequestConfig<TVariables>,\n _request?: unknown,\n): Promise<ResponseConfig<TData>> => {\n const requestConfig = mergeConfig(getConfig(), config)\n const { contentType, headers, ...axiosConfig } = requestConfig\n return axiosInstance\n .request<TData, ResponseConfig<TData>>({\n ...axiosConfig,\n headers: {\n ...(contentType && contentType !== 'multipart/form-data' ? { 'Content-Type': contentType } : {}),\n ...serializeHeaders(headers),\n },\n })\n .catch((e: AxiosError<TError>) => {\n throw e\n })\n}\n\nfetch.getConfig = getConfig\nfetch.setConfig = setConfig\n";
3
3
  //#endregion
4
4
  export { source };
5
5
 
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  //#region src/templates/clients/fetch.source.ts
3
- const source = "/**\n * RequestCredentials\n */\nexport type RequestCredentials = 'omit' | 'same-origin' | 'include'\n\n/**\n * Subset of FetchRequestConfig\n */\nexport type RequestConfig<TData = unknown> = {\n baseURL?: string\n url?: string\n method?: 'GET' | 'PUT' | 'PATCH' | 'POST' | 'DELETE' | 'OPTIONS' | 'HEAD'\n params?: unknown\n data?: TData | FormData\n responseType?: 'arraybuffer' | 'blob' | 'document' | 'json' | 'text' | 'stream'\n signal?: AbortSignal\n headers?: Array<[string, string]> | Record<string, string>\n credentials?: RequestCredentials\n contentType?: string\n}\n\n/**\n * Subset of FetchResponse\n */\nexport type ResponseConfig<TData = unknown> = {\n data: TData\n status: number\n statusText: string\n headers: Headers\n}\n\nlet _config: Partial<RequestConfig> = {}\n\nexport const getConfig = () => _config\n\nexport const setConfig = (config: Partial<RequestConfig>) => {\n _config = config\n return getConfig()\n}\n\nexport const mergeConfig = <T extends RequestConfig>(...configs: Array<Partial<T>>): Partial<T> => {\n return configs.reduce<Partial<T>>((merged, config) => {\n return {\n ...merged,\n ...config,\n headers: {\n ...(Array.isArray(merged.headers) ? Object.fromEntries(merged.headers) : merged.headers),\n ...(Array.isArray(config.headers) ? Object.fromEntries(config.headers) : config.headers),\n },\n }\n }, {})\n}\n\nexport type ResponseErrorConfig<TError = unknown> = TError\n\nexport type Client = <TData, _TError = unknown, TVariables = unknown>(config: RequestConfig<TVariables>, request?: unknown) => Promise<ResponseConfig<TData>>\n\nexport const fetch = async <TData, _TError = unknown, TVariables = unknown>(\n paramsConfig: RequestConfig<TVariables>,\n _request?: unknown,\n): Promise<ResponseConfig<TData>> => {\n const normalizedParams = new URLSearchParams()\n\n const config = mergeConfig(getConfig(), paramsConfig)\n\n Object.entries(config.params || {}).forEach(([key, value]) => {\n if (value !== undefined) {\n normalizedParams.append(key, value === null ? 'null' : value.toString())\n }\n })\n\n let targetUrl = [config.baseURL, config.url].filter(Boolean).join('')\n\n if (config.params) {\n targetUrl += `?${normalizedParams}`\n }\n\n const response = await globalThis.fetch(targetUrl, {\n credentials: config.credentials || 'same-origin',\n method: config.method?.toUpperCase(),\n body: config.data instanceof FormData ? config.data : JSON.stringify(config.data),\n signal: config.signal,\n headers: {\n ...(config.contentType && config.contentType !== 'multipart/form-data' ? { 'Content-Type': config.contentType } : {}),\n ...(Array.isArray(config.headers) ? Object.fromEntries(config.headers) : config.headers),\n },\n })\n\n const data = [204, 205, 304].includes(response.status) || !response.body ? {} : await response.json()\n\n return {\n data: data as TData,\n status: response.status,\n statusText: response.statusText,\n headers: response.headers as Headers,\n }\n}\n\nfetch.getConfig = getConfig\nfetch.setConfig = setConfig\n";
3
+ const source = "/**\n * RequestCredentials\n */\nexport type RequestCredentials = 'omit' | 'same-origin' | 'include'\n\n/**\n * Header values may be objects (e.g. JSON-encoded headers like `X-Filter` in the Linode API).\n * Non-string values are JSON-serialized before the request is sent.\n */\nexport type HeaderValue = string | number | boolean | null | undefined | object\nexport type HeadersInit = Array<[string, HeaderValue]> | Record<string, HeaderValue>\n\n/**\n * Subset of FetchRequestConfig\n */\nexport type RequestConfig<TData = unknown> = {\n baseURL?: string\n url?: string\n method?: 'GET' | 'PUT' | 'PATCH' | 'POST' | 'DELETE' | 'OPTIONS' | 'HEAD'\n params?: unknown\n data?: TData | FormData\n responseType?: 'arraybuffer' | 'blob' | 'document' | 'json' | 'text' | 'stream'\n signal?: AbortSignal\n headers?: HeadersInit\n credentials?: RequestCredentials\n contentType?: string\n}\n\n/**\n * Subset of FetchResponse\n */\nexport type ResponseConfig<TData = unknown> = {\n data: TData\n status: number\n statusText: string\n headers: Headers\n}\n\nlet _config: Partial<RequestConfig> = {}\n\nexport const getConfig = () => _config\n\nexport const setConfig = (config: Partial<RequestConfig>) => {\n _config = config\n return getConfig()\n}\n\nexport const mergeConfig = <T extends RequestConfig>(...configs: Array<Partial<T>>): Partial<T> => {\n return configs.reduce<Partial<T>>((merged, config) => {\n return {\n ...merged,\n ...config,\n headers: {\n ...(Array.isArray(merged.headers) ? Object.fromEntries(merged.headers) : merged.headers),\n ...(Array.isArray(config.headers) ? Object.fromEntries(config.headers) : config.headers),\n },\n }\n }, {})\n}\n\n/**\n * Serializes header values into the string form `fetch` expects.\n * Objects (including arrays) are JSON-stringified so spec-defined object headers like `X-Filter`\n * are sent in their canonical JSON-string form rather than `[object Object]`.\n */\nfunction serializeHeaders(headers: HeadersInit | undefined): Record<string, string> {\n if (!headers) return {}\n const entries = Array.isArray(headers) ? headers : Object.entries(headers)\n const result: Record<string, string> = {}\n for (const [key, value] of entries) {\n if (value === undefined || value === null) continue\n result[key] = typeof value === 'string' ? value : typeof value === 'object' ? JSON.stringify(value) : String(value)\n }\n return result\n}\n\nexport type ResponseErrorConfig<TError = unknown> = TError\n\nexport type Client = <TData, _TError = unknown, TVariables = unknown>(config: RequestConfig<TVariables>, request?: unknown) => Promise<ResponseConfig<TData>>\n\nexport const fetch = async <TData, _TError = unknown, TVariables = unknown>(\n paramsConfig: RequestConfig<TVariables>,\n _request?: unknown,\n): Promise<ResponseConfig<TData>> => {\n const normalizedParams = new URLSearchParams()\n\n const config = mergeConfig(getConfig(), paramsConfig)\n\n Object.entries(config.params || {}).forEach(([key, value]) => {\n if (value !== undefined) {\n normalizedParams.append(key, value === null ? 'null' : value.toString())\n }\n })\n\n let targetUrl = [config.baseURL, config.url].filter(Boolean).join('')\n\n if (config.params) {\n targetUrl += `?${normalizedParams}`\n }\n\n const response = await globalThis.fetch(targetUrl, {\n credentials: config.credentials || 'same-origin',\n method: config.method?.toUpperCase(),\n body: config.data instanceof FormData ? config.data : JSON.stringify(config.data),\n signal: config.signal,\n headers: {\n ...(config.contentType && config.contentType !== 'multipart/form-data' ? { 'Content-Type': config.contentType } : {}),\n ...serializeHeaders(config.headers),\n },\n })\n\n const data = [204, 205, 304].includes(response.status) || !response.body ? {} : await response.json()\n\n return {\n data: data as TData,\n status: response.status,\n statusText: response.statusText,\n headers: response.headers as Headers,\n }\n}\n\nfetch.getConfig = getConfig\nfetch.setConfig = setConfig\n";
4
4
  //#endregion
5
5
  exports.source = source;
6
6
 
@@ -1,5 +1,5 @@
1
1
  //#region src/templates/clients/fetch.source.ts
2
- const source = "/**\n * RequestCredentials\n */\nexport type RequestCredentials = 'omit' | 'same-origin' | 'include'\n\n/**\n * Subset of FetchRequestConfig\n */\nexport type RequestConfig<TData = unknown> = {\n baseURL?: string\n url?: string\n method?: 'GET' | 'PUT' | 'PATCH' | 'POST' | 'DELETE' | 'OPTIONS' | 'HEAD'\n params?: unknown\n data?: TData | FormData\n responseType?: 'arraybuffer' | 'blob' | 'document' | 'json' | 'text' | 'stream'\n signal?: AbortSignal\n headers?: Array<[string, string]> | Record<string, string>\n credentials?: RequestCredentials\n contentType?: string\n}\n\n/**\n * Subset of FetchResponse\n */\nexport type ResponseConfig<TData = unknown> = {\n data: TData\n status: number\n statusText: string\n headers: Headers\n}\n\nlet _config: Partial<RequestConfig> = {}\n\nexport const getConfig = () => _config\n\nexport const setConfig = (config: Partial<RequestConfig>) => {\n _config = config\n return getConfig()\n}\n\nexport const mergeConfig = <T extends RequestConfig>(...configs: Array<Partial<T>>): Partial<T> => {\n return configs.reduce<Partial<T>>((merged, config) => {\n return {\n ...merged,\n ...config,\n headers: {\n ...(Array.isArray(merged.headers) ? Object.fromEntries(merged.headers) : merged.headers),\n ...(Array.isArray(config.headers) ? Object.fromEntries(config.headers) : config.headers),\n },\n }\n }, {})\n}\n\nexport type ResponseErrorConfig<TError = unknown> = TError\n\nexport type Client = <TData, _TError = unknown, TVariables = unknown>(config: RequestConfig<TVariables>, request?: unknown) => Promise<ResponseConfig<TData>>\n\nexport const fetch = async <TData, _TError = unknown, TVariables = unknown>(\n paramsConfig: RequestConfig<TVariables>,\n _request?: unknown,\n): Promise<ResponseConfig<TData>> => {\n const normalizedParams = new URLSearchParams()\n\n const config = mergeConfig(getConfig(), paramsConfig)\n\n Object.entries(config.params || {}).forEach(([key, value]) => {\n if (value !== undefined) {\n normalizedParams.append(key, value === null ? 'null' : value.toString())\n }\n })\n\n let targetUrl = [config.baseURL, config.url].filter(Boolean).join('')\n\n if (config.params) {\n targetUrl += `?${normalizedParams}`\n }\n\n const response = await globalThis.fetch(targetUrl, {\n credentials: config.credentials || 'same-origin',\n method: config.method?.toUpperCase(),\n body: config.data instanceof FormData ? config.data : JSON.stringify(config.data),\n signal: config.signal,\n headers: {\n ...(config.contentType && config.contentType !== 'multipart/form-data' ? { 'Content-Type': config.contentType } : {}),\n ...(Array.isArray(config.headers) ? Object.fromEntries(config.headers) : config.headers),\n },\n })\n\n const data = [204, 205, 304].includes(response.status) || !response.body ? {} : await response.json()\n\n return {\n data: data as TData,\n status: response.status,\n statusText: response.statusText,\n headers: response.headers as Headers,\n }\n}\n\nfetch.getConfig = getConfig\nfetch.setConfig = setConfig\n";
2
+ const source = "/**\n * RequestCredentials\n */\nexport type RequestCredentials = 'omit' | 'same-origin' | 'include'\n\n/**\n * Header values may be objects (e.g. JSON-encoded headers like `X-Filter` in the Linode API).\n * Non-string values are JSON-serialized before the request is sent.\n */\nexport type HeaderValue = string | number | boolean | null | undefined | object\nexport type HeadersInit = Array<[string, HeaderValue]> | Record<string, HeaderValue>\n\n/**\n * Subset of FetchRequestConfig\n */\nexport type RequestConfig<TData = unknown> = {\n baseURL?: string\n url?: string\n method?: 'GET' | 'PUT' | 'PATCH' | 'POST' | 'DELETE' | 'OPTIONS' | 'HEAD'\n params?: unknown\n data?: TData | FormData\n responseType?: 'arraybuffer' | 'blob' | 'document' | 'json' | 'text' | 'stream'\n signal?: AbortSignal\n headers?: HeadersInit\n credentials?: RequestCredentials\n contentType?: string\n}\n\n/**\n * Subset of FetchResponse\n */\nexport type ResponseConfig<TData = unknown> = {\n data: TData\n status: number\n statusText: string\n headers: Headers\n}\n\nlet _config: Partial<RequestConfig> = {}\n\nexport const getConfig = () => _config\n\nexport const setConfig = (config: Partial<RequestConfig>) => {\n _config = config\n return getConfig()\n}\n\nexport const mergeConfig = <T extends RequestConfig>(...configs: Array<Partial<T>>): Partial<T> => {\n return configs.reduce<Partial<T>>((merged, config) => {\n return {\n ...merged,\n ...config,\n headers: {\n ...(Array.isArray(merged.headers) ? Object.fromEntries(merged.headers) : merged.headers),\n ...(Array.isArray(config.headers) ? Object.fromEntries(config.headers) : config.headers),\n },\n }\n }, {})\n}\n\n/**\n * Serializes header values into the string form `fetch` expects.\n * Objects (including arrays) are JSON-stringified so spec-defined object headers like `X-Filter`\n * are sent in their canonical JSON-string form rather than `[object Object]`.\n */\nfunction serializeHeaders(headers: HeadersInit | undefined): Record<string, string> {\n if (!headers) return {}\n const entries = Array.isArray(headers) ? headers : Object.entries(headers)\n const result: Record<string, string> = {}\n for (const [key, value] of entries) {\n if (value === undefined || value === null) continue\n result[key] = typeof value === 'string' ? value : typeof value === 'object' ? JSON.stringify(value) : String(value)\n }\n return result\n}\n\nexport type ResponseErrorConfig<TError = unknown> = TError\n\nexport type Client = <TData, _TError = unknown, TVariables = unknown>(config: RequestConfig<TVariables>, request?: unknown) => Promise<ResponseConfig<TData>>\n\nexport const fetch = async <TData, _TError = unknown, TVariables = unknown>(\n paramsConfig: RequestConfig<TVariables>,\n _request?: unknown,\n): Promise<ResponseConfig<TData>> => {\n const normalizedParams = new URLSearchParams()\n\n const config = mergeConfig(getConfig(), paramsConfig)\n\n Object.entries(config.params || {}).forEach(([key, value]) => {\n if (value !== undefined) {\n normalizedParams.append(key, value === null ? 'null' : value.toString())\n }\n })\n\n let targetUrl = [config.baseURL, config.url].filter(Boolean).join('')\n\n if (config.params) {\n targetUrl += `?${normalizedParams}`\n }\n\n const response = await globalThis.fetch(targetUrl, {\n credentials: config.credentials || 'same-origin',\n method: config.method?.toUpperCase(),\n body: config.data instanceof FormData ? config.data : JSON.stringify(config.data),\n signal: config.signal,\n headers: {\n ...(config.contentType && config.contentType !== 'multipart/form-data' ? { 'Content-Type': config.contentType } : {}),\n ...serializeHeaders(config.headers),\n },\n })\n\n const data = [204, 205, 304].includes(response.status) || !response.body ? {} : await response.json()\n\n return {\n data: data as TData,\n status: response.status,\n statusText: response.statusText,\n headers: response.headers as Headers,\n }\n}\n\nfetch.getConfig = getConfig\nfetch.setConfig = setConfig\n";
3
3
  //#endregion
4
4
  export { source };
5
5
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kubb/plugin-client",
3
- "version": "5.0.0-beta.25",
3
+ "version": "5.0.0-beta.27",
4
4
  "description": "Generate type-safe HTTP clients from your OpenAPI specification. Supports Axios, Fetch, and custom client adapters with full TypeScript inference and zero boilerplate.",
5
5
  "keywords": [
6
6
  "api-client",
@@ -87,10 +87,10 @@
87
87
  "registry": "https://registry.npmjs.org/"
88
88
  },
89
89
  "dependencies": {
90
- "@kubb/core": "5.0.0-beta.25",
91
- "@kubb/renderer-jsx": "5.0.0-beta.25",
92
- "@kubb/plugin-ts": "5.0.0-beta.25",
93
- "@kubb/plugin-zod": "5.0.0-beta.25"
90
+ "@kubb/core": "5.0.0-beta.27",
91
+ "@kubb/renderer-jsx": "5.0.0-beta.27",
92
+ "@kubb/plugin-ts": "5.0.0-beta.27",
93
+ "@kubb/plugin-zod": "5.0.0-beta.27"
94
94
  },
95
95
  "devDependencies": {
96
96
  "axios": "^1.16.1",
@@ -98,7 +98,7 @@
98
98
  "@internals/utils": "0.0.0"
99
99
  },
100
100
  "peerDependencies": {
101
- "@kubb/renderer-jsx": "5.0.0-beta.25",
101
+ "@kubb/renderer-jsx": "5.0.0-beta.27",
102
102
  "axios": "^1.7.2"
103
103
  },
104
104
  "peerDependenciesMeta": {
@@ -4,6 +4,13 @@ import axios from 'axios'
4
4
  declare const AXIOS_BASE: string
5
5
  declare const AXIOS_HEADERS: string
6
6
 
7
+ /**
8
+ * Header values may be objects (e.g. JSON-encoded headers like `X-Filter` in the Linode API).
9
+ * Non-string values are JSON-serialized before the request is sent.
10
+ */
11
+ export type HeaderValue = string | number | boolean | null | undefined | object
12
+ export type HeadersInit = Array<[string, HeaderValue]> | Record<string, HeaderValue>
13
+
7
14
  /**
8
15
  * Subset of AxiosRequestConfig
9
16
  */
@@ -16,7 +23,7 @@ export type RequestConfig<TData = unknown> = {
16
23
  responseType?: 'arraybuffer' | 'blob' | 'document' | 'json' | 'text' | 'stream'
17
24
  signal?: AbortSignal
18
25
  validateStatus?: (status: number) => boolean
19
- headers?: AxiosRequestConfig['headers']
26
+ headers?: HeadersInit
20
27
  paramsSerializer?: AxiosRequestConfig['paramsSerializer']
21
28
  contentType?: string
22
29
  }
@@ -56,14 +63,30 @@ export const mergeConfig = <T extends RequestConfig>(...configs: Array<Partial<T
56
63
  ...merged,
57
64
  ...config,
58
65
  headers: {
59
- ...merged.headers,
60
- ...config.headers,
66
+ ...(Array.isArray(merged.headers) ? Object.fromEntries(merged.headers) : merged.headers),
67
+ ...(Array.isArray(config.headers) ? Object.fromEntries(config.headers) : config.headers),
61
68
  },
62
69
  }
63
70
  }, {})
64
71
  }
65
72
 
66
- export const axiosInstance = axios.create(getConfig())
73
+ /**
74
+ * Serializes header values into the string form axios ultimately puts on the wire.
75
+ * Objects (including arrays) are JSON-stringified so spec-defined object headers like `X-Filter`
76
+ * are sent in their canonical JSON-string form rather than `[object Object]`.
77
+ */
78
+ function serializeHeaders(headers: HeadersInit | undefined): Record<string, string> {
79
+ if (!headers) return {}
80
+ const entries = Array.isArray(headers) ? headers : Object.entries(headers)
81
+ const result: Record<string, string> = {}
82
+ for (const [key, value] of entries) {
83
+ if (value === undefined || value === null) continue
84
+ result[key] = typeof value === 'string' ? value : typeof value === 'object' ? JSON.stringify(value) : String(value)
85
+ }
86
+ return result
87
+ }
88
+
89
+ export const axiosInstance = axios.create(getConfig() as AxiosRequestConfig)
67
90
 
68
91
  export const client = async <TResponseData, TError = unknown, TRequestData = unknown>(
69
92
  config: RequestConfig<TRequestData>,
@@ -76,7 +99,7 @@ export const client = async <TResponseData, TError = unknown, TRequestData = unk
76
99
  ...axiosConfig,
77
100
  headers: {
78
101
  ...(contentType && contentType !== 'multipart/form-data' ? { 'Content-Type': contentType } : {}),
79
- ...headers,
102
+ ...serializeHeaders(headers),
80
103
  },
81
104
  })
82
105
  .catch((e: AxiosError<TError>) => {
@@ -3,6 +3,13 @@
3
3
  */
4
4
  export type RequestCredentials = 'omit' | 'same-origin' | 'include'
5
5
 
6
+ /**
7
+ * Header values may be objects (e.g. JSON-encoded filter headers like `X-Filter`).
8
+ * Non-string values are JSON-serialized before the request is sent.
9
+ */
10
+ export type HeaderValue = string | number | boolean | null | undefined | object
11
+ export type HeadersInit = Array<[string, HeaderValue]> | Record<string, HeaderValue>
12
+
6
13
  /**
7
14
  * Subset of FetchRequestConfig
8
15
  */
@@ -14,7 +21,7 @@ export type RequestConfig<TData = unknown> = {
14
21
  data?: TData | FormData
15
22
  responseType?: 'arraybuffer' | 'blob' | 'document' | 'json' | 'text' | 'stream'
16
23
  signal?: AbortSignal
17
- headers?: Array<[string, string]> | Record<string, string>
24
+ headers?: HeadersInit
18
25
  credentials?: RequestCredentials
19
26
  contentType?: string
20
27
  }
@@ -51,6 +58,22 @@ export const mergeConfig = <T extends RequestConfig>(...configs: Array<Partial<T
51
58
  }, {})
52
59
  }
53
60
 
61
+ /**
62
+ * Serializes header values into the string form `fetch` expects.
63
+ * Objects (including arrays) are JSON-stringified so spec-defined object
64
+ * headers like `X-Filter` are sent in their canonical JSON-string form.
65
+ */
66
+ function serializeHeaders(headers: HeadersInit | undefined): Record<string, string> {
67
+ if (!headers) return {}
68
+ const entries = Array.isArray(headers) ? headers : Object.entries(headers)
69
+ const result: Record<string, string> = {}
70
+ for (const [key, value] of entries) {
71
+ if (value === undefined || value === null) continue
72
+ result[key] = typeof value === 'string' ? value : typeof value === 'object' ? JSON.stringify(value) : String(value)
73
+ }
74
+ return result
75
+ }
76
+
54
77
  export type ResponseErrorConfig<TError = unknown> = TError
55
78
 
56
79
  export type Client = <TResponseData, _TError = unknown, TRequestData = unknown>(
@@ -85,7 +108,7 @@ export const client = async <TResponseData, _TError = unknown, RequestData = unk
85
108
  signal: config.signal,
86
109
  headers: {
87
110
  ...(config.contentType && config.contentType !== 'multipart/form-data' ? { 'Content-Type': config.contentType } : {}),
88
- ...(Array.isArray(config.headers) ? Object.fromEntries(config.headers) : config.headers),
111
+ ...serializeHeaders(config.headers),
89
112
  },
90
113
  })
91
114
 
@@ -1,4 +1,11 @@
1
- import { buildOperationComments, buildParamsMapping, buildRequestConfigType, getContentTypeInfo, getOperationParameters } from '@internals/shared'
1
+ import {
2
+ buildOperationComments,
3
+ buildParamsMapping,
4
+ buildRequestConfigType,
5
+ getContentTypeInfo,
6
+ getOperationParameters,
7
+ resolveSuccessNames,
8
+ } from '@internals/shared'
2
9
  import { isValidVarName, URLPath } from '@internals/utils'
3
10
  import { ast } from '@kubb/core'
4
11
  import type { ResolverTs } from '@kubb/plugin-ts'
@@ -101,7 +108,8 @@ export function Client({
101
108
  const headerParamsMapping = paramsCasing ? buildParamsMapping(originalHeaderParams, casedHeaderParams) : null
102
109
 
103
110
  const requestName = node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : null
104
- const responseName = tsResolver.resolveResponseName(node)
111
+ const successNames = resolveSuccessNames(node, tsResolver)
112
+ const responseName = successNames.length > 0 ? successNames.join(' | ') : tsResolver.resolveResponseName(node)
105
113
  const queryParamsName = originalQueryParams.length > 0 ? tsResolver.resolveQueryParamsName(node, originalQueryParams[0]!) : null
106
114
  const headerParamsName = originalHeaderParams.length > 0 ? tsResolver.resolveHeaderParamsName(node, originalHeaderParams[0]!) : null
107
115
 
@@ -1,4 +1,4 @@
1
- import { camelCase, pascalCase } from '@internals/utils'
1
+ import { camelCase, ensureValidVarName, pascalCase } from '@internals/utils'
2
2
  import { defineResolver } from '@kubb/core'
3
3
  import type { PluginClient } from '../types.ts'
4
4
 
@@ -20,7 +20,8 @@ export const resolverClient = defineResolver<PluginClient>(() => ({
20
20
  name: 'default',
21
21
  pluginName: 'plugin-client',
22
22
  default(name, type) {
23
- return camelCase(name, { isFile: type === 'file' })
23
+ const resolved = camelCase(name, { isFile: type === 'file' })
24
+ return type === 'file' ? resolved : ensureValidVarName(resolved)
24
25
  },
25
26
  resolveName(name) {
26
27
  return this.default(name, 'function')
@@ -29,13 +30,13 @@ export const resolverClient = defineResolver<PluginClient>(() => ({
29
30
  return this.default(name, type)
30
31
  },
31
32
  resolveClassName(name) {
32
- return pascalCase(name)
33
+ return ensureValidVarName(pascalCase(name))
33
34
  },
34
35
  resolveGroupName(name) {
35
- return pascalCase(name)
36
+ return ensureValidVarName(pascalCase(name))
36
37
  },
37
38
  resolveClientPropertyName(name) {
38
- return camelCase(name)
39
+ return ensureValidVarName(camelCase(name))
39
40
  },
40
41
  resolveUrlName(node) {
41
42
  const name = this.resolveName(node.operationId)
package/src/utils.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { getOperationParameters } from '@internals/shared'
1
+ import { getOperationParameters, resolveSuccessNames } from '@internals/shared'
2
2
  import type { URLPath } from '@internals/utils'
3
3
  import type { ast } from '@kubb/core'
4
4
  import type { ResolverTs } from '@kubb/plugin-ts'
@@ -22,7 +22,8 @@ export function buildHeaders(contentType: string, hasHeaderParams: boolean): Arr
22
22
  * Includes response type, error type, and optional request type.
23
23
  */
24
24
  export function buildGenerics(node: ast.OperationNode, tsResolver: ResolverTs): Array<string> {
25
- const responseName = tsResolver.resolveResponseName(node)
25
+ const successNames = resolveSuccessNames(node, tsResolver)
26
+ const responseName = successNames.length > 0 ? successNames.join(' | ') : tsResolver.resolveResponseName(node)
26
27
  const requestName = node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : null
27
28
  const errorNames = node.responses.filter((r) => Number.parseInt(r.statusCode, 10) >= 400).map((r) => tsResolver.resolveResponseStatusName(node, r.statusCode))
28
29
  const TError = `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(' | ') : 'Error'}>`