@kubb/plugin-fetch 5.0.0-beta.81 → 5.0.0-beta.84

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kubb/plugin-fetch",
3
- "version": "5.0.0-beta.81",
3
+ "version": "5.0.0-beta.84",
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",
@@ -49,20 +49,18 @@
49
49
  "registry": "https://registry.npmjs.org/"
50
50
  },
51
51
  "dependencies": {
52
- "@kubb/ast": "5.0.0-beta.80",
53
- "@kubb/core": "5.0.0-beta.80",
54
- "@kubb/renderer-jsx": "5.0.0-beta.80",
55
- "@kubb/plugin-ts": "5.0.0-beta.81",
56
- "@kubb/plugin-zod": "5.0.0-beta.81"
52
+ "@kubb/plugin-ts": "5.0.0-beta.84",
53
+ "@kubb/plugin-zod": "5.0.0-beta.84"
57
54
  },
58
55
  "devDependencies": {
56
+ "kubb": "5.0.0-beta.84",
59
57
  "typescript": "^6.0.3",
60
58
  "@internals/client": "0.0.0",
61
59
  "@internals/shared": "0.0.0",
62
60
  "@internals/utils": "0.0.0"
63
61
  },
64
62
  "peerDependencies": {
65
- "@kubb/renderer-jsx": "5.0.0-beta.80"
63
+ "kubb": "5.0.0-beta.84"
66
64
  },
67
65
  "engines": {
68
66
  "node": ">=22"
@@ -8,10 +8,10 @@ import {
8
8
  type SecurityDocument,
9
9
  } from '@internals/client'
10
10
  import { isEventStream, operationFileEntry } from '@internals/shared'
11
- import { ast, defineGenerator } from '@kubb/core'
11
+ import { ast, defineGenerator } from 'kubb/kit'
12
12
  import { pluginTsName } from '@kubb/plugin-ts'
13
13
  import { pluginZodName } from '@kubb/plugin-zod'
14
- import { File, jsxRenderer } from '@kubb/renderer-jsx'
14
+ import { File, jsxRenderer } from 'kubb/jsx'
15
15
  import type { PluginFetch } from '../types.ts'
16
16
 
17
17
  /**
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 { definePlugin } from '@kubb/core'
4
+ import { definePlugin } from 'kubb/kit'
5
5
  import { pluginTsName } from '@kubb/plugin-ts'
6
6
  import { pluginZodName } from '@kubb/plugin-zod'
7
7
  import { clientGenerator } from './generators/clientGenerator.tsx'
@@ -22,7 +22,7 @@ export const pluginFetchName = 'plugin-fetch' satisfies PluginFetch['name']
22
22
  *
23
23
  * @example
24
24
  * ```ts
25
- * import { defineConfig } from 'kubb'
25
+ * import { defineConfig } from 'kubb/config'
26
26
  * import { pluginTs } from '@kubb/plugin-ts'
27
27
  * import { pluginFetch } from '@kubb/plugin-fetch'
28
28
  *
package/src/types.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { PluginFactoryOptions } from '@kubb/core'
1
+ import type { PluginFactoryOptions } from 'kubb/kit'
2
2
  import type { Options, ResolvedOptions, ResolverClient } from '@internals/client'
3
3
 
4
4
  export type { Options, ResolvedOptions, ResolverClient } from '@internals/client'
@@ -1,4 +1,4 @@
1
- import { applyHeaderStyles, defaultBodySerializer, defaultPathSerializer, defaultQuerySerializer, serializeCookies } from './serializers'
1
+ import { applyHeaderStyles, defaultBodySerializer, defaultPathSerializer, defaultQuerySerializer, isDefaultJsonBody, serializeCookies } from './serializers'
2
2
  import type { HeadersInit, PathParamStyle, PathSerializer, Serializers, Styles } from './serializers'
3
3
  import { type StandardSchemaValidator, validateStandardSchema } from './standardSchema.ts'
4
4
 
@@ -323,6 +323,15 @@ function mergeHeaders(...sources: Array<HeadersInit | undefined>): Record<string
323
323
  return Object.assign({}, ...sources.map(serializeHeaders))
324
324
  }
325
325
 
326
+ function getHeader(headers: Record<string, string>, name: string): string | undefined {
327
+ const key = Object.keys(headers).find((k) => k.toLowerCase() === name.toLowerCase())
328
+ return key ? headers[key] : undefined
329
+ }
330
+
331
+ function hasHeader(headers: Record<string, string>, name: string): boolean {
332
+ return Object.keys(headers).some((k) => k.toLowerCase() === name.toLowerCase())
333
+ }
334
+
326
335
  /**
327
336
  * Joins the URL parts, interpolates URL-encoded `{param}` segments, and appends the serialized query, shared by the send path and `getUrl`.
328
337
  */
@@ -387,9 +396,6 @@ export async function resolveAuth(params: {
387
396
  const { security, auth, headers, query } = params
388
397
  if (!security?.length || auth === undefined) return
389
398
 
390
- // An explicit caller-set header wins over the resolved token.
391
- const hasHeader = (name: string) => Object.keys(headers).some((key) => key.toLowerCase() === name.toLowerCase())
392
-
393
399
  for (const scheme of security) {
394
400
  const token = typeof auth === 'function' ? await auth(scheme) : auth
395
401
  if (token === undefined) continue
@@ -400,10 +406,10 @@ export async function resolveAuth(params: {
400
406
  if (query[name] === undefined) query[name] = token
401
407
  } else if (scheme.in === 'cookie') {
402
408
  headers.Cookie = [headers.Cookie, `${name}=${token}`].filter(Boolean).join('; ')
403
- } else if (!hasHeader(name)) {
409
+ } else if (!hasHeader(headers, name)) {
404
410
  headers[name] = token
405
411
  }
406
- } else if (!hasHeader('Authorization')) {
412
+ } else if (!hasHeader(headers, 'Authorization')) {
407
413
  headers.Authorization = scheme.scheme === 'basic' ? `Basic ${btoa(token)}` : `Bearer ${token}`
408
414
  }
409
415
  return
@@ -469,8 +475,8 @@ async function resolveRequest<TBody, TRequest, TResponse>({
469
475
 
470
476
  const headers = mergeHeaders(config.headers, applyHeaderStyles(requestConfig.headers, requestConfig.styles?.header))
471
477
  const { request: requestContentTypeOption, response: responseContentType } = resolveContentType(requestConfig.contentType)
472
- const requestContentType = requestContentTypeOption ?? headers['Content-Type'] ?? headers['content-type']
473
- if (responseContentType && headers['Accept'] === undefined && headers['accept'] === undefined) {
478
+ const requestContentType = requestContentTypeOption ?? getHeader(headers, 'content-type')
479
+ if (responseContentType && !hasHeader(headers, 'accept')) {
474
480
  headers['Accept'] = responseContentType
475
481
  }
476
482
 
@@ -491,15 +497,19 @@ async function resolveRequest<TBody, TRequest, TResponse>({
491
497
  const validatedBody = await runValidator(requestConfig.validator?.request, requestConfig.body)
492
498
  const requestContentTypeBase = baseContentType(requestContentType)
493
499
  const contentCodec = requestContentTypeBase ? codecs[requestContentTypeBase] : undefined
500
+ const usesDefaultBodySerializer = !contentCodec?.serialize && bodySerializer === defaultBodySerializer
494
501
  const body = contentCodec?.serialize
495
502
  ? contentCodec.serialize(validatedBody, requestContentType)
496
503
  : bodySerializer({ body: validatedBody, contentType: requestContentType, encoding: requestConfig.styles?.body })
497
504
  // A FormData body must keep its Content-Type unset so the runtime appends the multipart boundary.
498
505
  if (body instanceof FormData) {
499
- delete headers['Content-Type']
500
- delete headers['content-type']
506
+ for (const key of Object.keys(headers)) {
507
+ if (key.toLowerCase() === 'content-type') delete headers[key]
508
+ }
501
509
  } else if (requestContentTypeOption) {
502
510
  headers['Content-Type'] = requestContentTypeOption
511
+ } else if (usesDefaultBodySerializer && isDefaultJsonBody(validatedBody) && !hasHeader(headers, 'content-type')) {
512
+ headers['Content-Type'] = 'application/json'
503
513
  }
504
514
 
505
515
  const url = serializeUrl({
@@ -122,6 +122,10 @@ function isFormBody(body: unknown): body is BodyInit {
122
122
  )
123
123
  }
124
124
 
125
+ export function isDefaultJsonBody(body: unknown): boolean {
126
+ return body !== undefined && body !== null && !isFormBody(body)
127
+ }
128
+
125
129
  function appendFormDataValue({ formData, key, value, contentType }: { formData: FormData; key: string; value: unknown; contentType?: string }): void {
126
130
  if (value === undefined || value === null) return
127
131
  if (value instanceof Blob) formData.append(key, value)