@kubb/plugin-client 5.0.0-beta.4 → 5.0.0-beta.42

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.
Files changed (48) hide show
  1. package/README.md +39 -24
  2. package/dist/clients/axios.cjs +26 -4
  3. package/dist/clients/axios.cjs.map +1 -1
  4. package/dist/clients/axios.d.ts +11 -5
  5. package/dist/clients/axios.js +26 -4
  6. package/dist/clients/axios.js.map +1 -1
  7. package/dist/clients/fetch.cjs +77 -9
  8. package/dist/clients/fetch.cjs.map +1 -1
  9. package/dist/clients/fetch.d.ts +10 -3
  10. package/dist/clients/fetch.js +77 -9
  11. package/dist/clients/fetch.js.map +1 -1
  12. package/dist/index.cjs +625 -354
  13. package/dist/index.cjs.map +1 -1
  14. package/dist/index.d.ts +160 -94
  15. package/dist/index.js +626 -355
  16. package/dist/index.js.map +1 -1
  17. package/dist/templates/clients/axios.source.cjs +1 -1
  18. package/dist/templates/clients/axios.source.d.ts +1 -1
  19. package/dist/templates/clients/axios.source.js +1 -1
  20. package/dist/templates/clients/fetch.source.cjs +1 -1
  21. package/dist/templates/clients/fetch.source.d.ts +1 -1
  22. package/dist/templates/clients/fetch.source.js +1 -1
  23. package/dist/templates/config.source.d.ts +1 -1
  24. package/extension.yaml +792 -301
  25. package/package.json +11 -16
  26. package/src/clients/axios.ts +41 -7
  27. package/src/clients/fetch.ts +106 -6
  28. package/src/components/ClassClient.tsx +19 -20
  29. package/src/components/Client.tsx +74 -53
  30. package/src/components/Operations.tsx +2 -1
  31. package/src/components/StaticClassClient.tsx +19 -20
  32. package/src/components/Url.tsx +8 -9
  33. package/src/components/WrapperClient.tsx +9 -5
  34. package/src/functionParams.ts +8 -8
  35. package/src/generators/classClientGenerator.tsx +51 -47
  36. package/src/generators/clientGenerator.tsx +37 -48
  37. package/src/generators/groupedClientGenerator.tsx +14 -8
  38. package/src/generators/operationsGenerator.tsx +14 -8
  39. package/src/generators/staticClassClientGenerator.tsx +45 -41
  40. package/src/plugin.ts +27 -26
  41. package/src/resolvers/resolverClient.ts +31 -8
  42. package/src/types.ts +93 -55
  43. package/src/utils.ts +35 -56
  44. package/templates/clients/axios.ts +0 -73
  45. package/templates/clients/fetch.ts +0 -96
  46. package/templates/config.ts +0 -43
  47. /package/dist/{chunk-ByKO4r7w.cjs → chunk-Bx3C2hgW.cjs} +0 -0
  48. /package/dist/{chunk--u3MIqq1.js → chunk-C0LytTxp.js} +0 -0
package/extension.yaml CHANGED
@@ -2,18 +2,18 @@ $schema: https://kubb.dev/schemas/extension.json
2
2
  kind: plugin
3
3
  id: plugin-client
4
4
  name: Client
5
- description: Generate type-safe HTTP clients (Axios, Fetch) from OpenAPI specifications for making API requests.
5
+ description: Generate type-safe HTTP clients (axios or fetch) from OpenAPI one async function per operation, fully typed end to end.
6
6
  category: client
7
7
  type: official
8
- npmPackage: "@kubb/plugin-client"
8
+ npmPackage: '@kubb/plugin-client'
9
9
  docsPath: /plugins/plugin-client
10
10
  repo: https://github.com/kubb-labs/plugins
11
11
  maintainers:
12
12
  - name: Stijn Van Hulle
13
13
  github: stijnvanhulle
14
14
  compatibility:
15
- kubb: ">=5.0.0"
16
- node: ">=22"
15
+ kubb: '>=5.0.0'
16
+ node: '>=22'
17
17
  tags:
18
18
  - api-client
19
19
  - axios
@@ -35,156 +35,391 @@ icon:
35
35
  intro: |
36
36
  # @kubb/plugin-client
37
37
 
38
- Generate API client code for handling API requests.
38
+ Generate HTTP client functions for every operation in your OpenAPI spec. Each generated function has typed path params, query params, body, and response — call the API like any other typed function.
39
39
 
40
- By default, this plugin uses [Axios](https://axios-http.com/docs/intro), but you can add your own client. See [Use of Fetch](https://kubb.dev/plugins/plugin-client#importpath) for an example.
40
+ Ships with `axios` and `fetch` runtimes out of the box. Bring your own client (auth, retries, custom base URL) by pointing `importPath` at your module.
41
41
  options:
42
42
  - name: output
43
43
  type: Output
44
44
  required: false
45
- default: "{ path: 'clients', barrelType: 'named' }"
46
- description: Specify the export location for the files and define the behavior of the output.
45
+ default: "{ path: 'clients', barrel: { type: 'named' } }"
46
+ description: Where the generated client files are written and how they are exported.
47
47
  properties:
48
48
  - name: path
49
49
  type: string
50
50
  required: true
51
- description: Output directory or file for the generated code, relative to the global `output.path`.
51
+ description: |
52
+ Folder (or single file) where the plugin writes its generated code. The path is resolved against the global `output.path` set on `defineConfig`.
53
+
54
+ Use a folder to keep each generator's output isolated (`'types'`, `'clients'`, `'hooks'`). Use a single file when you want everything in one place, for example `'api.ts'`.
52
55
  tip: |
53
- if `output.path` is a file, `group` cannot be used.
56
+ When `output.path` points to a single file, the `group` option cannot be used because every operation ends up in the same file.
57
+ examples:
58
+ - name: kubb.config.ts
59
+ files:
60
+ - lang: typescript
61
+ twoslash: false
62
+ code: |
63
+ import { defineConfig } from 'kubb'
64
+ import { pluginTs } from '@kubb/plugin-ts'
65
+
66
+ export default defineConfig({
67
+ input: { path: './petStore.yaml' },
68
+ output: { path: './src/gen' },
69
+ plugins: [
70
+ pluginTs({
71
+ output: { path: './types' },
72
+ }),
73
+ ],
74
+ })
75
+ - name: Resulting tree
76
+ files:
77
+ - lang: text
78
+ twoslash: false
79
+ code: |
80
+ src/
81
+ └── gen/
82
+ └── types/
83
+ ├── Pet.ts
84
+ └── Store.ts
54
85
  default: "'clients'"
55
- - name: barrelType
56
- type: "'all' | 'named' | 'propagate' | false"
86
+ - name: barrel
87
+ type: "{ type: 'named' | 'all', nested?: boolean } | false"
57
88
  required: false
58
- default: "'named'"
59
- description: Specify what to export and optionally disable barrel-file generation.
89
+ default: "{ type: 'named' }"
90
+ description: |
91
+ Controls how the generated `index.ts` (barrel) file re-exports the plugin's output.
92
+
93
+ - `{ type: 'named' }` re-exports each symbol by name. Best for tree-shaking and explicit imports.
94
+ - `{ type: 'all' }` uses `export *`. Smaller barrel file, but exports everything.
95
+ - `{ nested: true }` creates a barrel in every subdirectory, so callers can import from any depth.
96
+ - `false` skips the barrel entirely. The plugin's files are also excluded from the root `index.ts`.
60
97
  tip: |
61
- Using `propagate` will prevent a plugin from creating a barrel file, but it will still propagate, allowing [`output.barrelType`](https://kubb.dev/docs/5.x/configuration#output-barreltype) to export the specific function or type.
98
+ Pick `'named'` when consumers care about which symbols they import (better tree-shaking, friendlier auto-import). Pick `'all'` when the file count is small and you want a one-line barrel.
62
99
  examples:
63
- - name: all
100
+ - name: "'named' (default)"
64
101
  files:
65
- - lang: typescript
102
+ - name: kubb.config.ts
103
+ lang: typescript
104
+ twoslash: false
66
105
  code: |
67
- export * from './gen/petService.ts'
106
+ import { defineConfig } from 'kubb'
107
+ import { pluginTs } from '@kubb/plugin-ts'
108
+
109
+ export default defineConfig({
110
+ input: { path: './petStore.yaml' },
111
+ output: { path: './src/gen' },
112
+ plugins: [
113
+ pluginTs({
114
+ output: { barrel: { type: 'named' } },
115
+ }),
116
+ ],
117
+ })
118
+ - name: src/gen/types/index.ts
119
+ lang: typescript
68
120
  twoslash: false
69
- - name: named
121
+ code: |
122
+ export { Pet, PetStatus } from './Pet'
123
+ export { Store } from './Store'
124
+ - name: "'all'"
70
125
  files:
71
- - lang: typescript
126
+ - name: kubb.config.ts
127
+ lang: typescript
128
+ twoslash: false
72
129
  code: |
73
- export { PetService } from './gen/petService.ts'
130
+ import { defineConfig } from 'kubb'
131
+ import { pluginTs } from '@kubb/plugin-ts'
132
+
133
+ export default defineConfig({
134
+ input: { path: './petStore.yaml' },
135
+ output: { path: './src/gen' },
136
+ plugins: [
137
+ pluginTs({
138
+ output: { barrel: { type: 'all' } },
139
+ }),
140
+ ],
141
+ })
142
+ - name: src/gen/types/index.ts
143
+ lang: typescript
74
144
  twoslash: false
75
- - name: propagate
145
+ code: |
146
+ export * from './Pet'
147
+ export * from './Store'
148
+ - name: nested
76
149
  files:
77
- - lang: typescript
78
- code: ""
150
+ - name: kubb.config.ts
151
+ lang: typescript
152
+ twoslash: false
153
+ code: |
154
+ import { defineConfig } from 'kubb'
155
+ import { pluginTs } from '@kubb/plugin-ts'
156
+
157
+ export default defineConfig({
158
+ input: { path: './petStore.yaml' },
159
+ output: { path: './src/gen' },
160
+ plugins: [
161
+ pluginTs({
162
+ output: { barrel: { type: 'named', nested: true } },
163
+ }),
164
+ ],
165
+ })
166
+ - name: Generated tree
167
+ lang: text
79
168
  twoslash: false
80
- - name: "false"
169
+ code: |
170
+ src/gen/types/
171
+ ├── index.ts # re-exports ./petController and ./storeController
172
+ ├── petController/
173
+ │ ├── index.ts # re-exports Pet, Store, ...
174
+ │ └── Pet.ts
175
+ └── storeController/
176
+ ├── index.ts
177
+ └── Store.ts
178
+ - name: 'false'
81
179
  files:
82
- - lang: typescript
83
- code: ""
180
+ - name: kubb.config.ts
181
+ lang: typescript
84
182
  twoslash: false
183
+ code: |
184
+ import { defineConfig } from 'kubb'
185
+ import { pluginTs } from '@kubb/plugin-ts'
186
+
187
+ export default defineConfig({
188
+ input: { path: './petStore.yaml' },
189
+ output: { path: './src/gen' },
190
+ plugins: [
191
+ pluginTs({
192
+ output: { barrel: false },
193
+ }),
194
+ ],
195
+ })
196
+ - name: Result
197
+ lang: text
198
+ twoslash: false
199
+ code: |
200
+ # No index.ts is generated for this plugin.
201
+ # Its files are also excluded from the root index.ts.
85
202
  - name: banner
86
- type: "string | ((node: RootNode) => string)"
203
+ type: 'string | ((node: RootNode) => string)'
87
204
  required: false
88
- description: Add a banner comment at the top of every generated file. Accepts a static string or a function that receives the `RootNode` and returns a string.
205
+ description: |
206
+ Text prepended to every generated file. Useful for license headers, lint disables, or `@ts-nocheck` directives.
207
+
208
+ Pass a string for a static banner. Pass a function to compute the banner from each file's `RootNode` (the AST root containing path, schema, and operation context).
209
+ examples:
210
+ - name: Static banner
211
+ files:
212
+ - name: kubb.config.ts
213
+ lang: typescript
214
+ twoslash: false
215
+ code: |
216
+ import { defineConfig } from 'kubb'
217
+ import { pluginTs } from '@kubb/plugin-ts'
218
+
219
+ export default defineConfig({
220
+ input: { path: './petStore.yaml' },
221
+ output: { path: './src/gen' },
222
+ plugins: [
223
+ pluginTs({
224
+ output: {
225
+ banner: '/* eslint-disable */\n// @ts-nocheck',
226
+ },
227
+ }),
228
+ ],
229
+ })
230
+ - name: Generated file
231
+ lang: typescript
232
+ twoslash: false
233
+ code: |
234
+ /* eslint-disable */
235
+ // @ts-nocheck
236
+ export type Pet = {
237
+ id: number
238
+ name: string
239
+ }
240
+ - name: Dynamic banner
241
+ files:
242
+ - name: kubb.config.ts
243
+ lang: typescript
244
+ twoslash: false
245
+ code: |
246
+ import { defineConfig } from 'kubb'
247
+ import { pluginTs } from '@kubb/plugin-ts'
248
+
249
+ export default defineConfig({
250
+ input: { path: './petStore.yaml' },
251
+ output: { path: './src/gen' },
252
+ plugins: [
253
+ pluginTs({
254
+ output: {
255
+ banner: (node) => `// Source: ${node.path}\n// Generated at ${new Date().toISOString()}`,
256
+ },
257
+ }),
258
+ ],
259
+ })
89
260
  - name: footer
90
- type: "string | ((node: RootNode) => string)"
261
+ type: 'string | ((node: RootNode) => string)'
91
262
  required: false
92
- description: Add a footer comment at the end of every generated file. Accepts a static string or a function that receives the `RootNode` and returns a string.
263
+ description: |
264
+ Text appended at the end of every generated file. The mirror of `banner` — use it for closing comments, re-enabling lint rules, or marker lines.
265
+
266
+ Pass a string for a static footer, or a function that receives the file's `RootNode` and returns the footer text.
267
+ examples:
268
+ - name: Re-enable lint after a banner disable
269
+ files:
270
+ - name: kubb.config.ts
271
+ lang: typescript
272
+ twoslash: false
273
+ code: |
274
+ import { defineConfig } from 'kubb'
275
+ import { pluginTs } from '@kubb/plugin-ts'
276
+
277
+ export default defineConfig({
278
+ input: { path: './petStore.yaml' },
279
+ output: { path: './src/gen' },
280
+ plugins: [
281
+ pluginTs({
282
+ output: {
283
+ banner: '/* eslint-disable */',
284
+ footer: '/* eslint-enable */',
285
+ },
286
+ }),
287
+ ],
288
+ })
93
289
  - name: override
94
290
  type: boolean
95
291
  required: false
96
- default: "false"
97
- description: Whether Kubb overrides existing external files that can be generated if they already exist.
98
- - name: contentType
99
- type: "'application/json' | (string & {})"
100
- required: false
101
- description: |
102
- Define which content type to use.
292
+ default: 'false'
293
+ description: |
294
+ Allows the plugin to overwrite hand-written files that share a name with a generated file.
103
295
 
104
- By default, Kubb uses the first JSON-valid media type.
296
+ - `false` (default): Kubb skips a file if it already exists and is not marked as generated. This protects manual edits.
297
+ - `true`: Kubb overwrites any file at the target path, including hand-written ones.
298
+ warning: |
299
+ Enable this only when you are sure the target folder contains nothing you need to keep. Local edits are lost on the next generation.
300
+ examples:
301
+ - name: kubb.config.ts
302
+ files:
303
+ - lang: typescript
304
+ twoslash: false
305
+ code: |
306
+ import { defineConfig } from 'kubb'
307
+ import { pluginTs } from '@kubb/plugin-ts'
308
+
309
+ export default defineConfig({
310
+ input: { path: './petStore.yaml' },
311
+ output: { path: './src/gen' },
312
+ plugins: [
313
+ pluginTs({
314
+ output: { override: true },
315
+ }),
316
+ ],
317
+ })
105
318
  - name: group
106
319
  type: Group
107
320
  required: false
108
321
  description: |
109
- Grouping combines files in a folder based on a specific `type`.
322
+ Splits generated files into subfolders based on the operation's tag, so each tag in your OpenAPI spec gets its own directory.
323
+
324
+ Without `group`, every file lands in the plugin's `output.path` folder. With `group`, files are bucketed under `{output.path}/{groupName}/`, where `groupName` is derived from the operation's first tag.
325
+ tip: |
326
+ Use `group` to mirror your API's domain structure (pet, store, user) in the generated code. Combine it with `output.barrel: { type: 'named', nested: true }` to get per-tag barrel files.
110
327
  examples:
111
328
  - name: kubb.config.ts
112
329
  files:
113
330
  - lang: typescript
114
- code: |
115
- group: {
116
- type: 'tag',
117
- name({ group }) {
118
- return `${group}Controller`
119
- }
120
- }
121
331
  twoslash: false
332
+ code: |
333
+ import { defineConfig } from 'kubb'
334
+ import { pluginTs } from '@kubb/plugin-ts'
335
+
336
+ export default defineConfig({
337
+ input: { path: './petStore.yaml' },
338
+ output: { path: './src/gen' },
339
+ plugins: [
340
+ pluginTs({
341
+ group: {
342
+ type: 'tag',
343
+ name: ({ group }) => `${group}Controller`,
344
+ },
345
+ }),
346
+ ],
347
+ })
122
348
  body: |
123
349
  With the configuration above, the generator emits:
124
350
 
125
351
  ```text
126
- .
127
- ├── src/
128
- └── petController/
129
- │ ├── addPet.ts
130
- │ │ └── getPet.ts
131
- │ └── storeController/
132
- │ ├── createStore.ts
133
- │ └── getStoreById.ts
134
- ├── petStore.yaml
135
- ├── kubb.config.ts
136
- └── package.json
352
+ src/gen/
353
+ ├── petController/
354
+ ├── AddPet.ts
355
+ └── GetPet.ts
356
+ └── storeController/
357
+ ├── CreateStore.ts
358
+ └── GetStoreById.ts
137
359
  ```
138
360
  properties:
139
361
  - name: type
140
362
  type: "'tag'"
141
363
  required: true
142
- description: Specify the property to group files by. Required when `group` is defined.
364
+ description: |
365
+ Property used to assign each operation to a group. Required whenever `group` is set.
366
+
367
+ Today only `'tag'` is supported: Kubb reads the first tag on the operation (`operation.getTags().at(0)?.name`) and uses it as the group key. Operations without a tag are placed in a default group.
143
368
  note: |
144
- `Required: true*` means this is required only when the `group` option is used. The `group` option itself is optional.
145
- body: |
146
- - `'tag'`: Uses the first tag from `operation.getTags().at(0)?.name`
369
+ `Required: true*` is conditional only required when the parent `group` option is used. `group` itself stays optional.
147
370
  - name: name
148
- type: "(context: GroupContext) => string"
371
+ type: '(context: GroupContext) => string'
149
372
  required: false
150
373
  default: (ctx) => `${ctx.group}Controller`
151
- description: Return the name of a group based on the group name. Used for the file and identifier generation.
374
+ description: Function that builds the folder/identifier name from a group key (the operation's first tag).
152
375
  - name: importPath
153
376
  type: string
154
377
  required: false
155
- description: Path to the client used for API calls. Supports both relative and absolute paths.
378
+ description: |
379
+ Path or module specifier of a custom client module. Generated code imports its HTTP runtime from here instead of `@kubb/plugin-client/clients/{client}`.
380
+
381
+ Use this when you need to inject auth headers, add interceptors, change the base URL at runtime, or wrap a different HTTP library (ky, ofetch, ...). Both relative paths (`./src/client.ts`) and bare specifiers (`@my-org/api-client`) work.
156
382
  details:
157
383
  - title: When to use `importPath`
158
384
  body: |
159
- Use `importPath` when you want to:
385
+ Reach for a custom client when you need to:
160
386
 
161
- - **Customize the HTTP client**: Provide your own client implementation with custom configurations (e.g., baseURL, headers, interceptors)
162
- - **Add authentication**: Include authentication tokens or other security mechanisms in your client
163
- - **Override default behavior**: Replace the default Kubb client with your own implementation
387
+ - Add an auth token to every request.
388
+ - Plug in interceptors, retries, or logging.
389
+ - Configure `baseURL` and headers from environment variables.
390
+ - Wrap a library other than `axios`/`fetch`.
164
391
  - title: Default behavior
165
392
  body: |
166
- When `importPath` is not specified:
393
+ Without `importPath`:
394
+
395
+ - `bundle: false` (default) — generated code imports from `@kubb/plugin-client/clients/{axios|fetch}`.
396
+ - `bundle: true` — Kubb writes `.kubb/client.ts` and generated code imports from there.
397
+ - title: Required exports
398
+ body: |
399
+ The module pointed to by `importPath` must satisfy the same shape as the built-in client. At minimum:
400
+
401
+ - A default export of the `client` function.
402
+ - A `RequestConfig` type.
403
+ - A `ResponseErrorConfig` type.
167
404
 
168
- - If `bundle: false` (default): Uses `@kubb/plugin-client/clients/${client}` where client is either `axios` or `fetch`.
169
- - If `bundle: true`: Bundles the client into `.kubb/fetch.ts`.
170
- - title: Import structure
171
- body: "Generated code imports the client as a default import and the runtime types as named type imports:"
405
+ When used together with a query plugin (`@kubb/plugin-react-query`, `@kubb/plugin-vue-query`), it must also export a `Client` type alias.
406
+ - title: How generated files import it
407
+ body: |
408
+ Generated code imports the client as a default import (bound to the local name `client`) and the runtime types as named type imports:
172
409
  codeBlock:
173
410
  lang: typescript
174
- code: |-
175
- /**
176
- * Generated by Kubb (https://kubb.dev/).
177
- * Do not edit manually.
178
- */
411
+ code: |
179
412
  import client from '${client.importPath}'
180
413
  import type { RequestConfig, ResponseErrorConfig } from '${client.importPath}'
181
- // ... rest of generated file
414
+ // ... rest of the generated file
182
415
  important: |
183
- When using `importPath` with query plugins such as `@kubb/plugin-react-query` or `@kubb/plugin-vue-query`, the generated hooks also import a `Client` type alongside `RequestConfig` and `ResponseErrorConfig` from the custom module. Your custom client module **must** export all three typesif any is missing, TypeScript will report an unresolvable import error.
416
+ When used with query plugins (`@kubb/plugin-react-query`, `@kubb/plugin-vue-query`), generated hooks also import a `Client` type alias. Your module **must** export `Client`, `RequestConfig`, and `ResponseErrorConfig` — TypeScript will fail the import otherwise.
184
417
  codeBlock:
185
418
  lang: typescript
186
- title: client.ts
419
+ title: src/client.ts
187
420
  code: |
421
+ import axios from 'axios'
422
+
188
423
  export type RequestConfig<TData = unknown> = {
189
424
  url?: string
190
425
  method: 'GET' | 'PUT' | 'PATCH' | 'POST' | 'DELETE'
@@ -203,77 +438,109 @@ options:
203
438
 
204
439
  export type ResponseErrorConfig<TError = unknown> = TError
205
440
 
206
- // The Client type alias is required when using query plugins
441
+ // Required when used with @kubb/plugin-react-query or @kubb/plugin-vue-query
207
442
  export type Client = <TData, _TError = unknown, TVariables = unknown>(
208
- config: RequestConfig<TVariables>
443
+ config: RequestConfig<TVariables>,
209
444
  ) => Promise<ResponseConfig<TData>>
210
445
 
211
- export const client: Client = async (config) => { /* ... */ }
446
+ const client: Client = async (config) => {
447
+ const response = await axios.request<TData>({
448
+ ...config,
449
+ headers: {
450
+ Authorization: `Bearer ${process.env.API_TOKEN}`,
451
+ ...config.headers,
452
+ },
453
+ })
454
+
455
+ return response
456
+ }
457
+
212
458
  export default client
213
459
  examples:
214
- - name: kubb.config.ts
460
+ - name: Wire up a custom client
215
461
  files:
216
- - lang: typescript
462
+ - name: kubb.config.ts
463
+ lang: typescript
464
+ twoslash: false
217
465
  code: |
218
466
  import { defineConfig } from 'kubb'
219
467
  import { pluginClient } from '@kubb/plugin-client'
220
468
 
221
469
  export default defineConfig({
222
- // ...
470
+ input: { path: './petStore.yaml' },
471
+ output: { path: './src/gen' },
223
472
  plugins: [
224
473
  pluginClient({
225
- importPath: './src/client.ts', // Path to your custom client
474
+ importPath: './src/client.ts',
226
475
  }),
227
476
  ],
228
477
  })
229
- twoslash: false
230
478
  tip: |
231
- Learn more about defining a custom client [here](https://kubb.dev/plugins/plugin-client#importpath).
479
+ See the [custom client guide](https://kubb.dev/plugins/plugin-client#importpath) for a worked example.
232
480
  - name: operations
233
481
  type: boolean
234
482
  required: false
235
- default: "false"
236
- description: Create an `operations.ts` file with all operations grouped by methods.
483
+ default: 'false'
484
+ description: |
485
+ Emits an `operations.ts` file that re-exports every generated function grouped by HTTP method. Useful for building meta-tooling (route registries, API explorers) on top of the generated code.
237
486
  - name: dataReturnType
238
487
  type: "'data' | 'full'"
239
488
  required: false
240
489
  default: "'data'"
241
490
  description: |
242
- Return type used when calling the client.
491
+ Shape of the value returned from each generated client function.
243
492
 
244
- - `'data'` returns `ResponseConfig['data']`.
245
- - `'full'` returns the full `ResponseConfig`.
493
+ - `'data'` returns only the response body (`response.data`). Concise and matches what most apps need.
494
+ - `'full'` returns the full response config — body, status code, headers, and the original request. Use this when callers need to inspect headers or status.
246
495
  examples:
247
- - name: data
496
+ - name: "'data' (default)"
248
497
  files:
249
- - lang: typescript
498
+ - name: getPetById.ts
499
+ lang: typescript
500
+ twoslash: false
250
501
  code: |
251
502
  export async function getPetById<TData>(
252
503
  petId: GetPetByIdPathParams,
253
504
  ): Promise<ResponseConfig<TData>['data']> {
254
- ...
505
+ // ...
255
506
  }
507
+ - name: usage.ts
508
+ lang: typescript
256
509
  twoslash: false
257
- - name: full
510
+ code: |
511
+ const pet = await getPetById(1)
512
+ // ^? Pet
513
+ - name: "'full'"
258
514
  files:
259
- - lang: typescript
515
+ - name: getPetById.ts
516
+ lang: typescript
517
+ twoslash: false
260
518
  code: |
261
519
  export async function getPetById<TData>(
262
520
  petId: GetPetByIdPathParams,
263
521
  ): Promise<ResponseConfig<TData>> {
264
- ...
522
+ // ...
265
523
  }
524
+ - name: usage.ts
525
+ lang: typescript
266
526
  twoslash: false
527
+ code: |
528
+ const response = await getPetById(1)
529
+ // ^? ResponseConfig<Pet>
530
+ console.log(response.status, response.headers)
531
+ const pet = response.data
267
532
  - name: urlType
268
533
  type: "'export' | false"
269
534
  required: false
270
- default: "false"
271
- description: Export URLs that are used by every operation.
272
- body: |
273
- - `'export'` will make them part of your barrel file.
274
- - `false` will not make them exportable.
535
+ default: 'false'
536
+ description: |
537
+ Controls whether the URL builder helpers (`get<Operation>Url`) are exported alongside each client function.
538
+
539
+ - `'export'` expose them via the barrel. Useful when you call the API through a different transport (`navigator.sendBeacon`, server actions, etc.).
540
+ - `false` (default) — keep them private to the generated module.
275
541
  codeBlock:
276
542
  lang: typescript
543
+ title: Generated URL helper
277
544
  code: |
278
545
  export function getGetPetByIdUrl(petId: GetPetByIdPathParams['petId']) {
279
546
  return `/pet/${petId}` as const
@@ -282,16 +549,37 @@ options:
282
549
  type: "'object' | 'inline'"
283
550
  required: false
284
551
  default: "'inline'"
285
- description: Defines how parameters are passed to generated functions. Switch between object-style parameters and inline parameters.
552
+ description: |
553
+ How operation parameters (path, query, headers) are exposed in the generated function signature.
554
+
555
+ - `'inline'` (default) — each parameter is a separate positional argument. Compact for operations with one or two params.
556
+ - `'object'` — every parameter is wrapped in a single object argument. Easier to read for operations with many params and named at the call site.
286
557
  tip: |
287
- When `paramsType` is set to `'object'`, `pathParams` will also be set to `'object'`.
288
- body: |
289
- - `'object'` returns params and pathParams as an object.
290
- - `'inline'` returns params as comma-separated params.
558
+ Setting `paramsType: 'object'` implicitly sets `pathParamsType: 'object'` as well, so call sites are consistent.
291
559
  examples:
292
- - name: object
560
+ - name: "'inline' (default)"
293
561
  files:
294
- - lang: typescript
562
+ - name: Generated client
563
+ lang: typescript
564
+ twoslash: false
565
+ code: |
566
+ export async function deletePet(
567
+ petId: DeletePetPathParams['petId'],
568
+ headers?: DeletePetHeaderParams,
569
+ config: Partial<RequestConfig> = {},
570
+ ) {
571
+ // ...
572
+ }
573
+ - name: Caller
574
+ lang: typescript
575
+ twoslash: false
576
+ code: |
577
+ await deletePet(42)
578
+ - name: "'object'"
579
+ files:
580
+ - name: Generated client
581
+ lang: typescript
582
+ twoslash: false
295
583
  code: |
296
584
  export async function deletePet(
297
585
  {
@@ -303,131 +591,179 @@ options:
303
591
  },
304
592
  config: Partial<RequestConfig> = {},
305
593
  ) {
306
- ...
594
+ // ...
307
595
  }
596
+ - name: Caller
597
+ lang: typescript
308
598
  twoslash: false
309
- - name: inline
310
- files:
311
- - lang: typescript
312
599
  code: |
313
- export async function deletePet(
314
- petId: DeletePetPathParams['petId'],
315
- headers?: DeletePetHeaderParams,
316
- config: Partial<RequestConfig> = {}
317
- ){
318
- ...
319
- }
320
- twoslash: false
600
+ await deletePet({ petId: 42, headers: { 'X-Api-Key': 'secret' } })
321
601
  - name: paramsCasing
322
602
  type: "'camelcase'"
323
603
  required: false
324
- description: Transform parameter names to a specific casing format for path, query, and header parameters in generated client code.
604
+ description: |
605
+ Renames path, query, and header parameters in the generated client to the chosen casing. The HTTP request still uses the original names from the OpenAPI spec — Kubb writes the mapping for you.
606
+
607
+ - `'camelcase'` — turn `pet_id` and `X-Api-Key` into `petId` and `xApiKey` in your TypeScript code. The runtime URL still uses `/pet/{pet_id}` and the header is still sent as `X-Api-Key`.
325
608
  important: |
326
- When using `paramsCasing`, ensure that `@kubb/plugin-ts` also has the same `paramsCasing` setting. This option automatically maps transformed parameter names back to their original API names in HTTP requests.
327
- body: |
328
- - `'camelcase'` transforms parameter names to camelCase.
609
+ Set the same `paramsCasing` on every plugin that touches operation parameters (`@kubb/plugin-ts`, `@kubb/plugin-client`, `@kubb/plugin-react-query`, `@kubb/plugin-faker`, `@kubb/plugin-mcp`). Mismatched casing causes type errors between generated layers.
329
610
  examples:
330
- - name: With paramsCasing camelcase
611
+ - name: "With paramsCasing: 'camelcase'"
331
612
  files:
332
- - lang: typescript
613
+ - name: Generated client
614
+ lang: typescript
615
+ twoslash: false
333
616
  code: |
334
- // Function parameters use camelCase
617
+ // Function takes camelCase parameters
335
618
  export async function deletePet(
336
- petId: DeletePetPathParams['petId'], // ✓ camelCase
619
+ petId: DeletePetPathParams['petId'],
337
620
  headers?: DeletePetHeaderParams,
338
- config: Partial<RequestConfig> = {}
621
+ config: Partial<RequestConfig> = {},
339
622
  ) {
340
- // Automatically maps back to original name for the API
623
+ // ...mapped back to the original API name internally
341
624
  const pet_id = petId
342
625
 
343
- return fetch({
626
+ return client({
344
627
  method: 'DELETE',
345
- url: `/pet/${pet_id}`, // Uses original API parameter name
346
- ...
628
+ url: `/pet/${pet_id}`,
629
+ ...config,
347
630
  })
348
631
  }
632
+ - name: Caller
633
+ lang: typescript
349
634
  twoslash: false
635
+ code: |
636
+ await deletePet(42)
350
637
  - name: Without paramsCasing
351
638
  files:
352
- - lang: typescript
639
+ - name: Generated client
640
+ lang: typescript
641
+ twoslash: false
353
642
  code: |
354
- // Parameters use original API naming
643
+ // Function parameters mirror the OpenAPI spec
355
644
  export async function deletePet(
356
- pet_id: DeletePetPathParams['pet_id'], // Original naming
645
+ pet_id: DeletePetPathParams['pet_id'],
357
646
  headers?: DeletePetHeaderParams,
358
- config: Partial<RequestConfig> = {}
647
+ config: Partial<RequestConfig> = {},
359
648
  ) {
360
- return fetch({
649
+ return client({
361
650
  method: 'DELETE',
362
651
  url: `/pet/${pet_id}`,
363
- ...
652
+ ...config,
364
653
  })
365
654
  }
366
- twoslash: false
367
655
  tip: |
368
- The client automatically generates mapping code to convert camelCase parameter names back to the original API format. You write code with developer-friendly camelCase names, but HTTP requests use the exact parameter names from your OpenAPI specification.
656
+ Callers write friendly camelCase names. The generated client maps them back to whatever the API expects (snake_case path params, kebab-case headers, ...).
369
657
  - name: pathParamsType
370
658
  type: "'object' | 'inline'"
371
659
  required: false
372
660
  default: "'inline'"
373
- description: Defines how pathParams are passed to generated functions.
374
- body: |
375
- - `'object'` returns pathParams as an object.
376
- - `'inline'` returns pathParams as comma-separated params.
661
+ description: |
662
+ How URL path parameters appear in the generated function signature. Affects only path params; query/header params follow `paramsType`.
663
+
664
+ - `'inline'` (default) each path param is a positional argument: `getPetById(petId)`.
665
+ - `'object'` — path params are wrapped in a single object: `getPetById({ petId })`.
377
666
  examples:
378
- - name: object
667
+ - name: "'inline' (default)"
379
668
  files:
380
669
  - lang: typescript
670
+ twoslash: false
381
671
  code: |
382
672
  export async function getPetById(
383
- { petId }: GetPetByIdPathParams,
673
+ petId: GetPetByIdPathParams,
384
674
  ) {
385
- ...
675
+ // ...
386
676
  }
387
- twoslash: false
388
- - name: inline
677
+ - name: "'object'"
389
678
  files:
390
679
  - lang: typescript
680
+ twoslash: false
391
681
  code: |
392
682
  export async function getPetById(
393
- petId: GetPetByIdPathParams,
683
+ { petId }: GetPetByIdPathParams,
394
684
  ) {
395
- ...
685
+ // ...
396
686
  }
397
- twoslash: false
398
687
  - name: parser
399
- type: "'client' | 'zod'"
688
+ type: false | 'zod'
400
689
  required: false
401
- default: "'client'"
402
- description: Parser used before returning data.
403
- body: |
404
- - `'zod'` uses `@kubb/plugin-zod` to parse data.
405
- - `'client'` returns data without parsing.
690
+ default: 'false'
691
+ description: |
692
+ Runtime validator applied to the response body before it is returned to the caller.
693
+
694
+ - `false` (default) no validation. The client has no runtime parser; the response is cast to the generated TypeScript type and returned as-is. Fastest path, trusts the API.
695
+ - `'zod'` — pipes the response through the Zod schema produced by `@kubb/plugin-zod`. Catches mismatches between spec and API at runtime, at the cost of a parse on every call.
696
+
697
+ Use `'zod'` when you want a defensive boundary against drift between your OpenAPI spec and the live API. Requires `@kubb/plugin-zod` in the plugins list.
698
+ examples:
699
+ - name: Validate responses with Zod
700
+ files:
701
+ - lang: typescript
702
+ twoslash: false
703
+ code: |
704
+ import { defineConfig } from 'kubb'
705
+ import { pluginClient } from '@kubb/plugin-client'
706
+ import { pluginTs } from '@kubb/plugin-ts'
707
+ import { pluginZod } from '@kubb/plugin-zod'
708
+
709
+ export default defineConfig({
710
+ input: { path: './petStore.yaml' },
711
+ output: { path: './src/gen' },
712
+ plugins: [
713
+ pluginTs(),
714
+ pluginZod(),
715
+ pluginClient({
716
+ parser: 'zod',
717
+ }),
718
+ ],
719
+ })
406
720
  - name: client
407
721
  type: "'axios' | 'fetch'"
408
722
  required: false
409
723
  default: "'axios'"
410
- description: Client used for HTTP calls.
411
- body: |
412
- - `'axios'` uses `@kubb/plugin-client/templates/axios` to fetch data.
413
- - `'fetch'` uses `@kubb/plugin-client/templates/fetch` to fetch data.
724
+ description: |
725
+ HTTP client used by the generated code.
726
+
727
+ - `'axios'` generated functions call into `@kubb/plugin-client/clients/axios`. Requires `axios` as a runtime dependency.
728
+ - `'fetch'` — generated functions call into `@kubb/plugin-client/clients/fetch`. Uses the global `fetch`, no extra runtime dependency.
729
+
730
+ To plug in your own client, use [`importPath`](#importpath) instead.
731
+ examples:
732
+ - name: Use fetch
733
+ files:
734
+ - lang: typescript
735
+ twoslash: false
736
+ code: |
737
+ import { defineConfig } from 'kubb'
738
+ import { pluginClient } from '@kubb/plugin-client'
739
+
740
+ export default defineConfig({
741
+ input: { path: './petStore.yaml' },
742
+ output: { path: './src/gen' },
743
+ plugins: [
744
+ pluginClient({
745
+ client: 'fetch',
746
+ }),
747
+ ],
748
+ })
414
749
  - name: clientType
415
750
  type: "'function' | 'class' | 'staticClass'"
416
751
  required: false
417
752
  default: "'function'"
418
753
  description: |
419
- Defines the client code generation style.
754
+ Shape of the generated client code.
420
755
 
421
- - `'function'` generates standalone functions for each operation.
422
- - `'class'` generates a class with instance methods for each operation.
423
- - `'staticClass'` generates a class with static methods for each operation. Use this style to call methods like `Pet.getPetById(...)` without instantiating the class.
756
+ - `'function'` (default) — one standalone async function per operation. Tree-shakes cleanly and works with every query plugin.
757
+ - `'class'` one class per group/tag with an instance method per operation. Use this to share configuration (auth, headers) through the constructor.
758
+ - `'staticClass'` one class per group/tag with static methods. Call as `Pet.getPetById(...)` without instantiating. Good for app-wide singleton clients.
424
759
  warning: |
425
- When using `clientType: 'class'` or `clientType: 'staticClass'`, these are not compatible with query plugins like `@kubb/plugin-react-query` or `@kubb/plugin-vue-query`. These plugins are designed to work with function-based clients. If you need to use both class-based or static-class clients and query hooks, configure separate `pluginClient` instances: one with `clientType: 'class'` or `clientType: 'staticClass'` for your needs, and another with `clientType: 'function'` (or omit it for the default) that the query plugins will reference.
760
+ Only `'function'` is compatible with query plugins (`@kubb/plugin-react-query`, `@kubb/plugin-vue-query`). To use both classes and query hooks, register two `pluginClient` instances one with `clientType: 'function'` for the query plugins to consume, and a second with `clientType: 'class'` or `'staticClass'` for your direct usage.
426
761
  examples:
427
- - name: staticClass
762
+ - name: "'staticClass'"
428
763
  files:
429
764
  - name: kubb.config.ts
430
765
  lang: typescript
766
+ twoslash: false
431
767
  code: |
432
768
  import { defineConfig } from 'kubb'
433
769
  import { pluginClient } from '@kubb/plugin-client'
@@ -445,30 +781,23 @@ options:
445
781
  }),
446
782
  ],
447
783
  })
448
- twoslash: false
449
- - name: Pet.ts
784
+ - name: Generated Pet.ts (excerpt)
450
785
  lang: typescript
786
+ twoslash: false
451
787
  code: |
452
- import fetch from '@kubb/plugin-client/clients/fetch'
453
- import type { GetPetByIdQueryResponse, GetPetByIdPathParams, GetPetById400, GetPetById404 } from '../../../models/ts/petController/GetPetById.js'
454
- import type { AddPetMutationRequest, AddPetMutationResponse, AddPet405 } from '../../../models/ts/petController/AddPet.js'
455
- import type { RequestConfig, ResponseErrorConfig } from '@kubb/plugin-client/clients/fetch'
788
+ import client from '@kubb/plugin-client/clients/fetch'
789
+ import type { GetPetByIdPathParams, GetPetByIdQueryResponse } from '../../models/ts/petController/GetPetById'
790
+ import type { RequestConfig } from '@kubb/plugin-client/clients/fetch'
456
791
 
457
792
  export class Pet {
458
- static #client: typeof fetch = fetch
793
+ static #client: typeof client = client
459
794
 
460
- /**
461
- * @description Returns a single pet
462
- * @summary Find pet by ID
463
- * {@link /pet/:petId}
464
- */
465
795
  static async getPetById(
466
796
  { petId }: { petId: GetPetByIdPathParams['petId'] },
467
- config: Partial<RequestConfig> & { client?: typeof fetch } = {}
797
+ config: Partial<RequestConfig> & { client?: typeof client } = {},
468
798
  ) {
469
- const request = this.#client || fetch
470
- const { client: _request = this.#client, ...requestConfig } = config
471
- const res = await request<GetPetByIdQueryResponse, ResponseErrorConfig<GetPetById400 | GetPetById404>, unknown>({
799
+ const { client: request = this.#client, ...requestConfig } = config
800
+ const res = await request<GetPetByIdQueryResponse>({
472
801
  method: 'GET',
473
802
  url: `/pet/${petId}`,
474
803
  ...requestConfig,
@@ -476,18 +805,18 @@ options:
476
805
  return res.data
477
806
  }
478
807
  }
479
- twoslash: false
480
808
  - name: usage.ts
481
809
  lang: typescript
810
+ twoslash: false
482
811
  code: |
483
812
  import { Pet } from './gen/clients/Pet'
484
813
 
485
814
  const pet = await Pet.getPetById({ petId: 1 })
486
- twoslash: false
487
- - name: class
815
+ - name: "'class'"
488
816
  files:
489
817
  - name: kubb.config.ts
490
818
  lang: typescript
819
+ twoslash: false
491
820
  code: |
492
821
  import { defineConfig } from 'kubb'
493
822
  import { pluginClient } from '@kubb/plugin-client'
@@ -505,27 +834,27 @@ options:
505
834
  }),
506
835
  ],
507
836
  })
508
- twoslash: false
509
- - name: Pet.ts
837
+ - name: Generated Pet.ts (excerpt)
510
838
  lang: typescript
839
+ twoslash: false
511
840
  code: |
512
- import fetch from '@kubb/plugin-client/clients/fetch'
513
- import type { GetPetByIdQueryResponse, GetPetByIdPathParams, GetPetById400, GetPetById404 } from '../../../models/ts/petController/GetPetById.js'
514
- import type { RequestConfig, ResponseErrorConfig } from '@kubb/plugin-client/clients/fetch'
841
+ import client from '@kubb/plugin-client/clients/fetch'
842
+ import type { GetPetByIdPathParams, GetPetByIdQueryResponse } from '../../models/ts/petController/GetPetById'
843
+ import type { RequestConfig } from '@kubb/plugin-client/clients/fetch'
515
844
 
516
845
  export class Pet {
517
- #client: typeof fetch
846
+ #client: typeof client
518
847
 
519
- constructor(config: Partial<RequestConfig> & { client?: typeof fetch } = {}) {
520
- this.#client = config.client || fetch
848
+ constructor(config: Partial<RequestConfig> & { client?: typeof client } = {}) {
849
+ this.#client = config.client || client
521
850
  }
522
851
 
523
852
  async getPetById(
524
853
  { petId }: { petId: GetPetByIdPathParams['petId'] },
525
- config: Partial<RequestConfig> & { client?: typeof fetch } = {}
854
+ config: Partial<RequestConfig> & { client?: typeof client } = {},
526
855
  ) {
527
856
  const { client: request = this.#client, ...requestConfig } = config
528
- const res = await request<GetPetByIdQueryResponse, ResponseErrorConfig<GetPetById400 | GetPetById404>, unknown>({
857
+ const res = await request<GetPetByIdQueryResponse>({
529
858
  method: 'GET',
530
859
  url: `/pet/${petId}`,
531
860
  ...requestConfig,
@@ -533,29 +862,32 @@ options:
533
862
  return res.data
534
863
  }
535
864
  }
536
- twoslash: false
537
865
  - name: usage.ts
538
866
  lang: typescript
867
+ twoslash: false
539
868
  code: |
540
869
  import { Pet } from './gen/clients/Pet'
541
870
 
542
871
  const petClient = new Pet()
543
872
  const pet = await petClient.getPetById({ petId: 1 })
544
- twoslash: false
545
- - name: wrapper
546
- type: "{ className: string }"
873
+ - name: sdk
874
+ type: '{ className: string }'
547
875
  required: false
548
- description: Generate a wrapper class that composes all tag-based client classes into a single entry point.
876
+ description: |
877
+ Generates a single SDK class that composes the per-tag client classes into one entry point. Setting `sdk` automatically enables `clientType: 'class'`, so you only need to add `group: { type: 'tag' }` to split the clients per tag.
878
+
879
+ Use this when you want a single object to hand around your app (`api.petController.findById`, `api.userController.login`) instead of importing each tag client separately.
549
880
  properties:
550
881
  - name: className
551
882
  type: string
552
883
  required: true
553
- description: Name of the generated wrapper class.
884
+ description: Name of the generated SDK class — used as the export name and file name.
554
885
  examples:
555
- - name: wrapper.className
886
+ - name: A composed PetStoreClient
556
887
  files:
557
888
  - name: kubb.config.ts
558
889
  lang: typescript
890
+ twoslash: false
559
891
  code: |
560
892
  import { defineConfig } from 'kubb'
561
893
  import { pluginClient } from '@kubb/plugin-client'
@@ -568,176 +900,337 @@ options:
568
900
  pluginTs(),
569
901
  pluginClient({
570
902
  output: { path: './clients' },
571
- clientType: 'class',
572
903
  group: { type: 'tag' },
573
- wrapper: { className: 'PetStoreClient' },
904
+ sdk: { className: 'PetStoreClient' },
574
905
  }),
575
906
  ],
576
907
  })
577
- twoslash: false
578
- - name: PetStoreClient.ts
908
+ - name: Generated PetStoreClient.ts
579
909
  lang: typescript
910
+ twoslash: false
580
911
  code: |
581
- import type { Client, RequestConfig } from './.kubb/fetch.js'
582
- import { Pet } from './petController/Pet.js'
583
- import { Store } from './storeController/Store.js'
584
- import { User } from './userController/User.js'
912
+ import type { Client, RequestConfig } from './.kubb/client'
913
+ import { petController } from './petController/petController'
914
+ import { storeController } from './storeController/storeController'
915
+ import { userController } from './userController/userController'
585
916
 
586
917
  export class PetStoreClient {
587
- readonly pet: Pet
588
- readonly store: Store
589
- readonly user: User
918
+ readonly petController: petController
919
+ readonly storeController: storeController
920
+ readonly userController: userController
590
921
 
591
922
  constructor(config: Partial<RequestConfig> & { client?: Client } = {}) {
592
- this.pet = new Pet(config)
593
- this.store = new Store(config)
594
- this.user = new User(config)
923
+ this.petController = new petController(config)
924
+ this.storeController = new storeController(config)
925
+ this.userController = new userController(config)
595
926
  }
596
927
  }
597
- twoslash: false
598
928
  - name: usage.ts
599
929
  lang: typescript
930
+ twoslash: false
600
931
  code: |
601
932
  import { PetStoreClient } from './gen/clients/PetStoreClient'
602
933
 
603
- const client = new PetStoreClient({ baseURL: 'https://petstore.swagger.io/v2' })
934
+ const api = new PetStoreClient({ baseURL: 'https://petstore.swagger.io/v2' })
604
935
 
605
- const pets = await client.pet.findPetsByTags({ tags: ['available'] })
606
- const user = await client.user.getUserByName({ username: 'john' })
607
- twoslash: false
936
+ const pets = await api.petController.findPetsByTags({ tags: ['available'] })
937
+ const user = await api.userController.getUserByName({ username: 'john' })
608
938
  - name: bundle
609
939
  type: boolean
610
940
  required: false
611
- default: "false"
612
- description: Controls whether the HTTP client runtime is copied into the generated `.kubb` directory.
613
- body: |
614
- - `true` adds a `.kubb/fetch.ts` file containing the selected client template (fetch or axios). Generated clients remain self-contained.
615
- - `false` keeps generated clients slim by importing the shared runtime from `@kubb/plugin-client/clients/{client}`.
616
- - Override this behavior by providing a custom `client.importPath`.
941
+ default: 'false'
942
+ description: |
943
+ Copies the HTTP client runtime into the generated output, so the consuming app does not need `@kubb/plugin-client` installed at runtime.
944
+
945
+ - `false` (default) generated files import from `@kubb/plugin-client/clients/{client}`. Smaller diff, but the package must be a runtime dependency.
946
+ - `true` Kubb writes a `.kubb/client.ts` file with the client implementation. Generated code imports from that local file and the project no longer pulls `@kubb/plugin-client` at runtime.
947
+ - Setting `client.importPath` overrides both behaviors and uses your custom client instead.
948
+ examples:
949
+ - name: Bundle the runtime
950
+ files:
951
+ - lang: typescript
952
+ twoslash: false
953
+ code: |
954
+ import { defineConfig } from 'kubb'
955
+ import { pluginClient } from '@kubb/plugin-client'
956
+
957
+ export default defineConfig({
958
+ input: { path: './petStore.yaml' },
959
+ output: { path: './src/gen' },
960
+ plugins: [
961
+ pluginClient({
962
+ client: 'fetch',
963
+ bundle: true,
964
+ }),
965
+ ],
966
+ })
617
967
  - name: baseURL
618
968
  type: string
619
969
  required: false
620
- description: Sets a custom base URL for all generated calls. When not set, the base URL is automatically taken from the OAS spec via the adapter (e.g. the `servers[0].url` field).
970
+ description: |
971
+ Base URL prepended to every request URL in the generated client. When omitted, the URL comes from the OpenAPI spec's `servers[0].url` (or whichever index the adapter is configured to read).
972
+
973
+ Set this when the generated client should point at a different environment (staging, production) than the one written in the spec.
974
+ examples:
975
+ - name: Override the spec's server URL
976
+ files:
977
+ - lang: typescript
978
+ twoslash: false
979
+ code: |
980
+ import { defineConfig } from 'kubb'
981
+ import { pluginClient } from '@kubb/plugin-client'
982
+
983
+ export default defineConfig({
984
+ input: { path: './petStore.yaml' },
985
+ output: { path: './src/gen' },
986
+ plugins: [
987
+ pluginClient({
988
+ baseURL: 'https://petstore.swagger.io/v2',
989
+ }),
990
+ ],
991
+ })
621
992
  - name: include
622
993
  type: Array<Include>
623
994
  required: false
624
- description: Array containing include parameters to include tags, operations, methods, paths, or content types.
995
+ description: |
996
+ Restricts generation to operations that match at least one entry in the list. Anything not matched is skipped.
997
+
998
+ Each entry filters by one of:
999
+
1000
+ - `tag` — the operation's first tag in the OpenAPI spec.
1001
+ - `operationId` — the operation's `operationId`.
1002
+ - `path` — the URL pattern (`'/pet/{petId}'`).
1003
+ - `method` — HTTP method (`'get'`, `'post'`, ...).
1004
+ - `contentType` — the media type of the request body.
1005
+
1006
+ `pattern` accepts either a string (exact match) or a `RegExp` for fuzzy matches.
625
1007
  codeBlock:
626
1008
  lang: typescript
627
- title: Include
1009
+ title: Type definition
628
1010
  code: |
629
1011
  export type Include = {
630
1012
  type: 'tag' | 'operationId' | 'path' | 'method' | 'contentType'
631
1013
  pattern: string | RegExp
632
1014
  }
1015
+ examples:
1016
+ - name: Only the pet tag
1017
+ files:
1018
+ - name: kubb.config.ts
1019
+ lang: typescript
1020
+ twoslash: false
1021
+ code: |
1022
+ import { defineConfig } from 'kubb'
1023
+ import { pluginTs } from '@kubb/plugin-ts'
1024
+
1025
+ export default defineConfig({
1026
+ input: { path: './petStore.yaml' },
1027
+ output: { path: './src/gen' },
1028
+ plugins: [
1029
+ pluginTs({
1030
+ include: [
1031
+ { type: 'tag', pattern: 'pet' },
1032
+ ],
1033
+ }),
1034
+ ],
1035
+ })
1036
+ - name: Only GET operations under /pet
1037
+ files:
1038
+ - name: kubb.config.ts
1039
+ lang: typescript
1040
+ twoslash: false
1041
+ code: |
1042
+ import { defineConfig } from 'kubb'
1043
+ import { pluginTs } from '@kubb/plugin-ts'
1044
+
1045
+ export default defineConfig({
1046
+ input: { path: './petStore.yaml' },
1047
+ output: { path: './src/gen' },
1048
+ plugins: [
1049
+ pluginTs({
1050
+ include: [
1051
+ { type: 'method', pattern: 'get' },
1052
+ { type: 'path', pattern: /^\/pet/ },
1053
+ ],
1054
+ }),
1055
+ ],
1056
+ })
633
1057
  - name: exclude
634
1058
  type: Array<Exclude>
635
1059
  required: false
636
- description: Array containing exclude parameters to exclude or skip tags, operations, methods, paths, or content types.
1060
+ description: |
1061
+ Skips any operation that matches at least one entry in the list. The opposite of `include`.
1062
+
1063
+ Each entry filters by one of:
1064
+
1065
+ - `tag` — the operation's first tag.
1066
+ - `operationId` — the operation's `operationId`.
1067
+ - `path` — the URL pattern (`'/pet/{petId}'`).
1068
+ - `method` — HTTP method (`'get'`, `'post'`, ...).
1069
+ - `contentType` — the media type of the request body.
1070
+
1071
+ `pattern` accepts a plain string or a `RegExp`. When both `include` and `exclude` are set, `exclude` wins.
637
1072
  codeBlock:
638
1073
  lang: typescript
639
- title: Exclude
1074
+ title: Type definition
640
1075
  code: |
641
1076
  export type Exclude = {
642
1077
  type: 'tag' | 'operationId' | 'path' | 'method' | 'contentType'
643
1078
  pattern: string | RegExp
644
1079
  }
1080
+ examples:
1081
+ - name: Skip everything under the store tag
1082
+ files:
1083
+ - name: kubb.config.ts
1084
+ lang: typescript
1085
+ twoslash: false
1086
+ code: |
1087
+ import { defineConfig } from 'kubb'
1088
+ import { pluginTs } from '@kubb/plugin-ts'
1089
+
1090
+ export default defineConfig({
1091
+ input: { path: './petStore.yaml' },
1092
+ output: { path: './src/gen' },
1093
+ plugins: [
1094
+ pluginTs({
1095
+ exclude: [
1096
+ { type: 'tag', pattern: 'store' },
1097
+ ],
1098
+ }),
1099
+ ],
1100
+ })
1101
+ - name: Skip a specific operation and all delete methods
1102
+ files:
1103
+ - name: kubb.config.ts
1104
+ lang: typescript
1105
+ twoslash: false
1106
+ code: |
1107
+ import { defineConfig } from 'kubb'
1108
+ import { pluginTs } from '@kubb/plugin-ts'
1109
+
1110
+ export default defineConfig({
1111
+ input: { path: './petStore.yaml' },
1112
+ output: { path: './src/gen' },
1113
+ plugins: [
1114
+ pluginTs({
1115
+ exclude: [
1116
+ { type: 'operationId', pattern: 'deletePet' },
1117
+ { type: 'method', pattern: 'delete' },
1118
+ ],
1119
+ }),
1120
+ ],
1121
+ })
645
1122
  - name: override
646
1123
  type: Array<Override>
647
1124
  required: false
648
- description: Array containing override parameters to override `options` based on tags, operations, methods, paths, or content types.
1125
+ description: |
1126
+ Applies a different set of plugin options to operations that match a pattern. Use this when most of your API should follow the global config, but a handful of endpoints need different treatment.
1127
+
1128
+ Each entry has the same `type` and `pattern` shape as `include`/`exclude`, plus an `options` object that overrides the plugin's options for matched operations.
1129
+
1130
+ Entries are evaluated top to bottom. The first matching entry's `options` is merged onto the plugin defaults; later entries do not stack.
649
1131
  codeBlock:
650
1132
  lang: typescript
651
- title: Override
1133
+ title: Type definition
652
1134
  code: |
653
1135
  export type Override = {
654
1136
  type: 'tag' | 'operationId' | 'path' | 'method' | 'contentType'
655
1137
  pattern: string | RegExp
656
1138
  options: PluginOptions
657
1139
  }
658
- - name: generators
659
- type: Array<Generator<PluginClient>>
660
- required: false
661
- experimental: true
662
- description: |
663
- Define additional generators next to the built-in generators.
664
-
665
- See [Generators](https://kubb.dev/docs/5.x/guides/creating-plugins) for more information on how to use generators.
666
- - name: transformers
667
- type: Visitor
668
- required: false
669
- description: |
670
- A single AST visitor applied to every node before code is printed. Each method you provide replaces the corresponding built-in one. When a method returns `null` or `undefined`, the preset transformer's result is used as the fallback — so you only need to supply the methods you want to change.
671
-
672
- Visitor methods receive the node and a context object. Return a modified node to replace it, or return `undefined`/`void` to leave it unchanged.
673
1140
  examples:
674
- - name: Strip descriptions before printing
1141
+ - name: Use a different enum style for the user tag
675
1142
  files:
676
- - lang: typescript
677
- code: |
678
- import { pluginTs } from '@kubb/plugin-ts'
679
-
680
- pluginTs({
681
- transformer: {
682
- schema(node) {
683
- return { ...node, description: undefined }
684
- },
685
- },
686
- })
1143
+ - name: kubb.config.ts
1144
+ lang: typescript
687
1145
  twoslash: false
688
- - name: Prefix every operationId
689
- files:
690
- - lang: typescript
691
1146
  code: |
1147
+ import { defineConfig } from 'kubb'
692
1148
  import { pluginTs } from '@kubb/plugin-ts'
693
1149
 
694
- pluginTs({
695
- transformer: {
696
- operation(node) {
697
- return { ...node, operationId: `api_${node.operationId}` }
698
- },
699
- },
1150
+ export default defineConfig({
1151
+ input: { path: './petStore.yaml' },
1152
+ output: { path: './src/gen' },
1153
+ plugins: [
1154
+ pluginTs({
1155
+ enumType: 'asConst',
1156
+ override: [
1157
+ {
1158
+ type: 'tag',
1159
+ pattern: 'user',
1160
+ options: { enumType: 'literal' },
1161
+ },
1162
+ ],
1163
+ }),
1164
+ ],
700
1165
  })
701
- twoslash: false
702
- tip: |
703
- Use `transformer` to rewrite node properties before printing. For output naming customization, use `resolver` instead.
1166
+ - name: generators
1167
+ type: Array<Generator<PluginClient>>
1168
+ required: false
1169
+ experimental: true
1170
+ description: |
1171
+ Adds custom generators that run alongside the plugin's built-in generators. Each generator can emit additional files or post-process existing ones using the plugin's AST and options.
1172
+
1173
+ Use this when you need output the plugin does not produce out of the box (a custom client wrapper, an extra index, a metadata file). For end-to-end guidance, see [Creating plugins](https://kubb.dev/docs/5.x/guides/creating-plugins).
1174
+ warning: |
1175
+ Generators are an experimental, low-level API. The signature may change between minor releases.
704
1176
  - name: resolver
705
1177
  type: Partial<ResolverClient> & ThisType<ResolverClient>
706
1178
  required: false
707
- description: Override individual resolver methods to customize generated names. Any method you omit falls back to the preset resolver. Use `this.default(...)` to call the preset's implementation.
1179
+ description: |
1180
+ Overrides naming and path resolution for the generated client. Only the methods you supply replace the defaults; everything else falls back to the built-in resolver.
1181
+
1182
+ Inside each method, `this` is bound to the full resolver, so you can call `this.default(name)` to delegate to the original implementation.
708
1183
  codeBlock:
709
1184
  lang: typescript
1185
+ title: Append "Client" to every name
710
1186
  code: |
1187
+ import { defineConfig } from 'kubb'
711
1188
  import { pluginClient } from '@kubb/plugin-client'
712
1189
 
713
- pluginClient({
714
- resolver: {
715
- resolveName(name) {
716
- return `${this.default(name)}Client`
717
- },
718
- },
1190
+ export default defineConfig({
1191
+ input: { path: './petStore.yaml' },
1192
+ output: { path: './src/gen' },
1193
+ plugins: [
1194
+ pluginClient({
1195
+ resolver: {
1196
+ resolveName(name) {
1197
+ return `${this.default(name)}Client`
1198
+ },
1199
+ },
1200
+ }),
1201
+ ],
719
1202
  })
720
1203
  - name: transformer
721
1204
  type: Visitor
722
1205
  required: false
723
1206
  experimental: true
724
- description: Apply an AST `Visitor` to transform operation nodes before they are printed.
1207
+ description: |
1208
+ AST visitor applied to operation nodes before code is printed. Use this to rewrite operation IDs, tags, or descriptions across the entire client.
725
1209
  codeBlock:
726
1210
  lang: typescript
1211
+ title: Prefix every operationId with "api_"
727
1212
  code: |
1213
+ import { defineConfig } from 'kubb'
728
1214
  import { pluginClient } from '@kubb/plugin-client'
729
1215
 
730
- pluginClient({
731
- transformer: {
732
- operation(node) {
733
- return { ...node, operationId: `api_${node.operationId}` }
734
- },
735
- },
1216
+ export default defineConfig({
1217
+ input: { path: './petStore.yaml' },
1218
+ output: { path: './src/gen' },
1219
+ plugins: [
1220
+ pluginClient({
1221
+ transformer: {
1222
+ operation(node) {
1223
+ return { ...node, operationId: `api_${node.operationId}` }
1224
+ },
1225
+ },
1226
+ }),
1227
+ ],
736
1228
  })
737
1229
  examples:
738
1230
  - name: kubb.config.ts
739
1231
  files:
740
1232
  - lang: typescript
1233
+ twoslash: false
741
1234
  code: |
742
1235
  import { defineConfig } from 'kubb'
743
1236
  import { pluginTs } from '@kubb/plugin-ts'
@@ -751,9 +1244,8 @@ examples:
751
1244
  pluginClient({
752
1245
  output: {
753
1246
  path: './clients/axios',
754
- barrelType: 'named',
755
- banner: '/* eslint-disable no-alert, no-console */',
756
- footer: '',
1247
+ barrel: { type: 'named' },
1248
+ banner: '/* eslint-disable */',
757
1249
  },
758
1250
  group: {
759
1251
  type: 'tag',
@@ -765,7 +1257,7 @@ examples:
765
1257
  },
766
1258
  },
767
1259
  operations: true,
768
- parser: 'client',
1260
+ parser: false,
769
1261
  exclude: [{ type: 'tag', pattern: 'store' }],
770
1262
  pathParamsType: 'object',
771
1263
  dataReturnType: 'full',
@@ -773,4 +1265,3 @@ examples:
773
1265
  }),
774
1266
  ],
775
1267
  })
776
- twoslash: false