@kubb/core 4.35.1 → 4.36.1

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.
@@ -23,6 +23,75 @@ declare var AsyncEventEmitter: {
23
23
  removeAll(): void;
24
24
  };
25
25
  };
26
+ /**
27
+ * Parses and transforms an OpenAPI/Swagger path string into various URL formats.
28
+ *
29
+ * @example
30
+ * const p = new URLPath('/pet/{petId}')
31
+ * p.URL // '/pet/:petId'
32
+ * p.template // '`/pet/${petId}`'
33
+ */
34
+ declare var URLPath: {
35
+ new (path: any, options?: {}): {
36
+ /** The raw OpenAPI/Swagger path string, e.g. `/pet/{petId}`. */path: any;
37
+ "__#private@#options": {}; /** Converts the OpenAPI path to Express-style colon syntax, e.g. `/pet/{petId}` → `/pet/:petId`. */
38
+ get URL(): any; /** Returns `true` when `path` is a fully-qualified URL (e.g. starts with `https://`). */
39
+ get isURL(): boolean;
40
+ /**
41
+ * Converts the OpenAPI path to a TypeScript template literal string.
42
+ *
43
+ * @example
44
+ * new URLPath('/pet/{petId}').template // '`/pet/${petId}`'
45
+ * new URLPath('/account/monetary-accountID').template // '`/account/${monetaryAccountId}`'
46
+ */
47
+ get template(): string; /** Returns the path and its extracted params as a structured `URLObject`, or as a stringified expression when `stringify` is set. */
48
+ get object(): string | {
49
+ url: any;
50
+ params: {} | undefined;
51
+ }; /** Returns a map of path parameter names, or `undefined` when the path has no parameters. */
52
+ get params(): {} | undefined;
53
+ "__#private@#transformParam"(raw: any): any; /** Iterates over every `{param}` token in `path`, calling `fn` with the raw token and transformed name. */
54
+ "__#private@#eachParam"(fn: any): void;
55
+ toObject({
56
+ type,
57
+ replacer,
58
+ stringify
59
+ }?: {
60
+ type?: string | undefined;
61
+ }): string | {
62
+ url: any;
63
+ params: {} | undefined;
64
+ };
65
+ /**
66
+ * Converts the OpenAPI path to a TypeScript template literal string.
67
+ * An optional `replacer` can transform each extracted parameter name before interpolation.
68
+ *
69
+ * @example
70
+ * new URLPath('/pet/{petId}').toTemplateString() // '`/pet/${petId}`'
71
+ */
72
+ toTemplateString({
73
+ prefix,
74
+ replacer
75
+ }?: {
76
+ prefix?: string | undefined;
77
+ }): string;
78
+ /**
79
+ * Extracts all `{param}` segments from the path and returns them as a key-value map.
80
+ * An optional `replacer` transforms each parameter name in both key and value positions.
81
+ * Returns `undefined` when no path parameters are found.
82
+ */
83
+ getParams(replacer: any): {} | undefined; /** Converts the OpenAPI path to Express-style colon syntax, e.g. `/pet/{petId}` → `/pet/:petId`. */
84
+ toURLPath(): any;
85
+ };
86
+ };
87
+ /**
88
+ * Serializes a primitive value to a JSON string literal, stripping any surrounding quote characters first.
89
+ *
90
+ * @example
91
+ * stringify('hello') // '"hello"'
92
+ * stringify('"hello"') // '"hello"'
93
+ */
94
+ declare function stringify(value: any): string;
26
95
  //#endregion
27
96
  //#region src/constants.d.ts
28
97
  declare const DEFAULT_STUDIO_URL: "https://studio.kubb.dev";
@@ -69,6 +138,61 @@ declare const formatters: {
69
138
  };
70
139
  };
71
140
  //#endregion
141
+ //#region src/defineStorage.d.ts
142
+ /**
143
+ * Storage interface for persisting Kubb output.
144
+ *
145
+ * Keys are root-relative forward-slash paths (e.g. `src/gen/api/getPets.ts`).
146
+ * Implement this interface to route generated files to any backend — filesystem,
147
+ * S3, Redis, in-memory, etc.
148
+ *
149
+ * Use `defineStorage` to create a typed storage driver.
150
+ */
151
+ interface DefineStorage {
152
+ /** Identifier used for logging and debugging (e.g. `'fs'`, `'s3'`). */
153
+ readonly name: string;
154
+ /** Returns `true` when an entry for `key` exists in storage. */
155
+ hasItem(key: string): Promise<boolean>;
156
+ /** Returns the stored string value, or `null` when `key` does not exist. */
157
+ getItem(key: string): Promise<string | null>;
158
+ /** Persists `value` under `key`, creating any required structure. */
159
+ setItem(key: string, value: string): Promise<void>;
160
+ /** Removes the entry for `key`. No-ops when the key does not exist. */
161
+ removeItem(key: string): Promise<void>;
162
+ /** Returns all keys, optionally filtered to those starting with `base`. */
163
+ getKeys(base?: string): Promise<Array<string>>;
164
+ /** Removes all entries, optionally scoped to those starting with `base`. */
165
+ clear(base?: string): Promise<void>;
166
+ /** Optional teardown hook called after the build completes. */
167
+ dispose?(): Promise<void>;
168
+ }
169
+ /**
170
+ * Wraps a storage builder so the `options` argument is optional, following the
171
+ * same factory pattern as `definePlugin`, `defineLogger`, and `defineAdapter`.
172
+ *
173
+ * The builder receives the resolved options object and must return a
174
+ * `DefineStorage`-compatible object that includes a `name` string.
175
+ *
176
+ * @example
177
+ * ```ts
178
+ * import { defineStorage } from '@kubb/core'
179
+ *
180
+ * export const memoryStorage = defineStorage((_options) => {
181
+ * const store = new Map<string, string>()
182
+ * return {
183
+ * name: 'memory',
184
+ * async hasItem(key) { return store.has(key) },
185
+ * async getItem(key) { return store.get(key) ?? null },
186
+ * async setItem(key, value) { store.set(key, value) },
187
+ * async removeItem(key) { store.delete(key) },
188
+ * async getKeys() { return [...store.keys()] },
189
+ * async clear() { store.clear() },
190
+ * }
191
+ * })
192
+ * ```
193
+ */
194
+ declare function defineStorage<TOptions = Record<string, never>>(build: (options: TOptions) => DefineStorage): (options?: TOptions) => DefineStorage;
195
+ //#endregion
72
196
  //#region src/PluginManager.d.ts
73
197
  type RequiredPluginLifecycle = Required<PluginLifecycle>;
74
198
  type Strategy = 'hookFirst' | 'hookForPlugin' | 'hookParallel' | 'hookSeq';
@@ -551,8 +675,22 @@ type Config<TInput = Input> = {
551
675
  /**
552
676
  * Save files to the file system.
553
677
  * @default true
678
+ * @deprecated Use `storage` to control where files are written.
554
679
  */
555
680
  write?: boolean;
681
+ /**
682
+ * Storage backend for generated files.
683
+ * Defaults to `fsStorage()` — the built-in filesystem driver.
684
+ * Accepts any object implementing the {@link DefineStorage} interface.
685
+ * Keys are root-relative paths (e.g. `src/gen/api/getPets.ts`).
686
+ * @default fsStorage()
687
+ * @example
688
+ * ```ts
689
+ * import { defineStorage, fsStorage } from '@kubb/core'
690
+ * storage: defineStorage(fsStorage())
691
+ * ```
692
+ */
693
+ storage?: DefineStorage;
556
694
  /**
557
695
  * Specifies the formatting tool to be used.
558
696
  * - 'auto' automatically detects and uses biome or prettier (in that order of preference).
@@ -849,5 +987,5 @@ type Logger<TOptions extends LoggerOptions = LoggerOptions> = {
849
987
  };
850
988
  type UserLogger<TOptions extends LoggerOptions = LoggerOptions> = Omit<Logger<TOptions>, 'logLevel'>;
851
989
  //#endregion
852
- export { UserPlugin as A, Printer as C, UnknownUserPlugin as D, ResolvePathParams as E, formatters as F, linters as I, logLevel as L, KubbEvents as M, PluginManager as N, UserConfig as O, getMode as P, AsyncEventEmitter as R, PluginWithLifeCycle as S, ResolveNameParams as T, PluginFactoryOptions as _, Config as a, PluginLifecycleHooks as b, Group as c, Logger as d, LoggerContext as f, PluginContext as g, Plugin as h, BarrelType as i, UserPluginWithLifeCycle as j, UserLogger as k, InputData as l, Output as m, AdapterFactoryOptions as n, DevtoolsOptions as o, LoggerOptions as p, AdapterSource as r, GetPluginFactoryOptions as s, Adapter as t, InputPath as u, PluginKey as v, PrinterFactoryOptions as w, PluginParameter as x, PluginLifecycle as y };
853
- //# sourceMappingURL=types-BPb8k77q.d.ts.map
990
+ export { UserPlugin as A, AsyncEventEmitter as B, Printer as C, UnknownUserPlugin as D, ResolvePathParams as E, DefineStorage as F, defineStorage as I, formatters as L, KubbEvents as M, PluginManager as N, UserConfig as O, getMode as P, linters as R, PluginWithLifeCycle as S, ResolveNameParams as T, URLPath as V, PluginFactoryOptions as _, Config as a, PluginLifecycleHooks as b, Group as c, Logger as d, LoggerContext as f, PluginContext as g, Plugin as h, BarrelType as i, UserPluginWithLifeCycle as j, UserLogger as k, InputData as l, Output as m, AdapterFactoryOptions as n, DevtoolsOptions as o, LoggerOptions as p, AdapterSource as r, GetPluginFactoryOptions as s, Adapter as t, InputPath as u, PluginKey as v, PrinterFactoryOptions as w, PluginParameter as x, PluginLifecycle as y, logLevel as z };
991
+ //# sourceMappingURL=types-D30QAz2y.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kubb/core",
3
- "version": "4.35.1",
3
+ "version": "4.36.1",
4
4
  "description": "Core functionality for Kubb's plugin-based code generation system, providing the foundation for transforming OpenAPI specifications.",
5
5
  "keywords": [
6
6
  "typescript",
@@ -71,7 +71,7 @@
71
71
  "remeda": "^2.33.6",
72
72
  "semver": "^7.7.4",
73
73
  "tinyexec": "^1.0.4",
74
- "@kubb/ast": "4.35.1"
74
+ "@kubb/ast": "4.36.1"
75
75
  },
76
76
  "devDependencies": {
77
77
  "@types/semver": "^7.7.1",
package/src/build.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { dirname, resolve } from 'node:path'
2
- import { AsyncEventEmitter, clean, exists, formatMs, getElapsedMs, getRelativePath, URLPath, write } from '@internals/utils'
1
+ import { dirname, relative, resolve } from 'node:path'
2
+ import { AsyncEventEmitter, exists, formatMs, getElapsedMs, getRelativePath, URLPath } from '@internals/utils'
3
3
  import type { KubbFile } from '@kubb/fabric-core/types'
4
4
  import type { Fabric } from '@kubb/react-fabric'
5
5
  import { createFabric } from '@kubb/react-fabric'
@@ -9,7 +9,8 @@ import { isInputPath } from './config.ts'
9
9
  import { BARREL_FILENAME, DEFAULT_BANNER, DEFAULT_CONCURRENCY, DEFAULT_EXTENSION, DEFAULT_STUDIO_URL } from './constants.ts'
10
10
  import { BuildError } from './errors.ts'
11
11
  import { PluginManager } from './PluginManager.ts'
12
- import type { AdapterSource, Config, KubbEvents, Output, Plugin, UserConfig } from './types.ts'
12
+ import { fsStorage } from './storages/fsStorage.ts'
13
+ import type { AdapterSource, Config, DefineStorage, KubbEvents, Output, Plugin, UserConfig } from './types.ts'
13
14
  import { getDiagnosticInfo } from './utils/diagnostics.ts'
14
15
  import type { FileMetaBase } from './utils/getBarrelFiles.ts'
15
16
 
@@ -54,7 +55,7 @@ export async function setup(options: BuildOptions): Promise<SetupResult> {
54
55
  ` • Output: ${userConfig.output?.path || 'not specified'}`,
55
56
  ` • Plugins: ${userConfig.plugins?.length || 0}`,
56
57
  'Output Settings:',
57
- ` • Write: ${userConfig.output?.write !== false ? 'enabled' : 'disabled'}`,
58
+ ` • Storage: ${userConfig.output?.storage ? `custom(${userConfig.output.storage.name})` : userConfig.output?.write === false ? 'disabled' : 'filesystem (default)'}`,
58
59
  ` • Formatter: ${userConfig.output?.format || 'none'}`,
59
60
  ` • Linter: ${userConfig.output?.lint || 'none'}`,
60
61
  'Environment:',
@@ -105,12 +106,18 @@ export async function setup(options: BuildOptions): Promise<SetupResult> {
105
106
  plugins: userConfig.plugins as Config['plugins'],
106
107
  }
107
108
 
109
+ // write: false is the explicit dry-run opt-out; otherwise use the provided
110
+ // storage or fall back to fsStorage (backwards-compatible default).
111
+ // Keys are root-relative (e.g. `src/gen/api/getPets.ts`) so fsStorage()
112
+ // needs no configuration — it resolves them against process.cwd().
113
+ const storage: DefineStorage | null = definedConfig.output.write === false ? null : (definedConfig.output.storage ?? fsStorage())
114
+
108
115
  if (definedConfig.output.clean) {
109
116
  await events.emit('debug', {
110
117
  date: new Date(),
111
118
  logs: ['Cleaning output directories', ` • Output: ${definedConfig.output.path}`],
112
119
  })
113
- await clean(definedConfig.output.path)
120
+ await storage?.clear(resolve(definedConfig.root, definedConfig.output.path))
114
121
  }
115
122
 
116
123
  const fabric = createFabric()
@@ -134,10 +141,9 @@ export async function setup(options: BuildOptions): Promise<SetupResult> {
134
141
  })
135
142
 
136
143
  if (source) {
137
- if (definedConfig.output.write) {
138
- await write(file.path, source, { sanity: false })
139
- }
140
-
144
+ // Key is root-relative so it's meaningful for any backend (fs, S3, Redis…)
145
+ const key = relative(resolve(definedConfig.root), file.path)
146
+ await storage?.setItem(key, source)
141
147
  sources.set(file.path, source)
142
148
  }
143
149
  })
@@ -154,7 +160,7 @@ export async function setup(options: BuildOptions): Promise<SetupResult> {
154
160
  date: new Date(),
155
161
  logs: [
156
162
  '✓ Fabric initialized',
157
- ` • File writing: ${definedConfig.output.write ? 'enabled' : 'disabled (dry-run)'}`,
163
+ ` • Storage: ${storage ? storage.name : 'disabled (dry-run)'}`,
158
164
  ` • Barrel type: ${definedConfig.output.barrelType || 'none'}`,
159
165
  ],
160
166
  })
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Storage interface for persisting Kubb output.
3
+ *
4
+ * Keys are root-relative forward-slash paths (e.g. `src/gen/api/getPets.ts`).
5
+ * Implement this interface to route generated files to any backend — filesystem,
6
+ * S3, Redis, in-memory, etc.
7
+ *
8
+ * Use `defineStorage` to create a typed storage driver.
9
+ */
10
+ export interface DefineStorage {
11
+ /** Identifier used for logging and debugging (e.g. `'fs'`, `'s3'`). */
12
+ readonly name: string
13
+ /** Returns `true` when an entry for `key` exists in storage. */
14
+ hasItem(key: string): Promise<boolean>
15
+ /** Returns the stored string value, or `null` when `key` does not exist. */
16
+ getItem(key: string): Promise<string | null>
17
+ /** Persists `value` under `key`, creating any required structure. */
18
+ setItem(key: string, value: string): Promise<void>
19
+ /** Removes the entry for `key`. No-ops when the key does not exist. */
20
+ removeItem(key: string): Promise<void>
21
+ /** Returns all keys, optionally filtered to those starting with `base`. */
22
+ getKeys(base?: string): Promise<Array<string>>
23
+ /** Removes all entries, optionally scoped to those starting with `base`. */
24
+ clear(base?: string): Promise<void>
25
+ /** Optional teardown hook called after the build completes. */
26
+ dispose?(): Promise<void>
27
+ }
28
+
29
+ /**
30
+ * Wraps a storage builder so the `options` argument is optional, following the
31
+ * same factory pattern as `definePlugin`, `defineLogger`, and `defineAdapter`.
32
+ *
33
+ * The builder receives the resolved options object and must return a
34
+ * `DefineStorage`-compatible object that includes a `name` string.
35
+ *
36
+ * @example
37
+ * ```ts
38
+ * import { defineStorage } from '@kubb/core'
39
+ *
40
+ * export const memoryStorage = defineStorage((_options) => {
41
+ * const store = new Map<string, string>()
42
+ * return {
43
+ * name: 'memory',
44
+ * async hasItem(key) { return store.has(key) },
45
+ * async getItem(key) { return store.get(key) ?? null },
46
+ * async setItem(key, value) { store.set(key, value) },
47
+ * async removeItem(key) { store.delete(key) },
48
+ * async getKeys() { return [...store.keys()] },
49
+ * async clear() { store.clear() },
50
+ * }
51
+ * })
52
+ * ```
53
+ */
54
+ export function defineStorage<TOptions = Record<string, never>>(build: (options: TOptions) => DefineStorage): (options?: TOptions) => DefineStorage {
55
+ return (options) => build(options ?? ({} as TOptions))
56
+ }
package/src/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { AsyncEventEmitter } from '@internals/utils'
1
+ export { AsyncEventEmitter, URLPath } from '@internals/utils'
2
2
  export { definePrinter } from '@kubb/ast'
3
3
  export { build, build as default, safeBuild, setup } from './build.ts'
4
4
  export { type CLIOptions, type ConfigInput, defineConfig, isInputPath } from './config.ts'
@@ -6,9 +6,12 @@ export { formatters, linters, logLevel } from './constants.ts'
6
6
  export { defineAdapter } from './defineAdapter.ts'
7
7
  export { defineLogger } from './defineLogger.ts'
8
8
  export { definePlugin } from './definePlugin.ts'
9
+ export { defineStorage } from './defineStorage.ts'
9
10
  export { PackageManager } from './PackageManager.ts'
10
11
  export { getMode, PluginManager } from './PluginManager.ts'
11
12
  export { PromiseManager } from './PromiseManager.ts'
13
+ export { fsStorage } from './storages/fsStorage.ts'
14
+ export { memoryStorage } from './storages/memoryStorage.ts'
12
15
  export * from './types.ts'
13
16
  export type { FunctionParamsAST } from './utils/FunctionParams.ts'
14
17
  export { FunctionParams } from './utils/FunctionParams.ts'
@@ -0,0 +1,84 @@
1
+ import type { Dirent } from 'node:fs'
2
+ import { access, readdir, readFile, rm } from 'node:fs/promises'
3
+ import { join, resolve } from 'node:path'
4
+ import { clean, write } from '@internals/utils'
5
+ import { defineStorage } from '../defineStorage.ts'
6
+
7
+ /**
8
+ * Built-in filesystem storage driver.
9
+ *
10
+ * This is the default storage when no `storage` option is configured in `output`.
11
+ * Keys are resolved against `process.cwd()`, so root-relative paths such as
12
+ * `src/gen/api/getPets.ts` are written to the correct location without extra configuration.
13
+ *
14
+ * Internally uses the `write` utility from `@internals/utils`, which:
15
+ * - trims leading/trailing whitespace before writing
16
+ * - skips the write when file content is already identical (deduplication)
17
+ * - creates missing parent directories automatically
18
+ * - supports Bun's native file API when running under Bun
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * import { defineConfig, fsStorage } from '@kubb/core'
23
+ *
24
+ * export default defineConfig({
25
+ * input: { path: './petStore.yaml' },
26
+ * output: { path: './src/gen', storage: fsStorage() },
27
+ * })
28
+ * ```
29
+ */
30
+ export const fsStorage = defineStorage(() => ({
31
+ name: 'fs',
32
+ async hasItem(key: string) {
33
+ try {
34
+ await access(resolve(key))
35
+ return true
36
+ } catch {
37
+ return false
38
+ }
39
+ },
40
+ async getItem(key: string) {
41
+ try {
42
+ return await readFile(resolve(key), 'utf8')
43
+ } catch {
44
+ return null
45
+ }
46
+ },
47
+ async setItem(key: string, value: string) {
48
+ await write(resolve(key), value, { sanity: false })
49
+ },
50
+ async removeItem(key: string) {
51
+ await rm(resolve(key), { force: true })
52
+ },
53
+ async getKeys(base?: string) {
54
+ const keys: Array<string> = []
55
+
56
+ async function walk(dir: string, prefix: string): Promise<void> {
57
+ let entries: Array<Dirent>
58
+ try {
59
+ entries = (await readdir(dir, { withFileTypes: true })) as Array<Dirent>
60
+ } catch {
61
+ return
62
+ }
63
+ for (const entry of entries) {
64
+ const rel = prefix ? `${prefix}/${entry.name}` : entry.name
65
+ if (entry.isDirectory()) {
66
+ await walk(join(dir, entry.name), rel)
67
+ } else {
68
+ keys.push(rel)
69
+ }
70
+ }
71
+ }
72
+
73
+ await walk(resolve(base ?? process.cwd()), '')
74
+
75
+ return keys
76
+ },
77
+ async clear(base?: string) {
78
+ if (!base) {
79
+ return
80
+ }
81
+
82
+ await clean(resolve(base))
83
+ },
84
+ }))
@@ -0,0 +1,53 @@
1
+ import { defineStorage } from '../defineStorage.ts'
2
+
3
+ /**
4
+ * In-memory storage driver. Useful for testing and dry-run scenarios where
5
+ * generated output should be captured without touching the filesystem.
6
+ *
7
+ * All data lives in a `Map` scoped to the storage instance and is discarded
8
+ * when the instance is garbage-collected.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * import { defineConfig, memoryStorage } from '@kubb/core'
13
+ *
14
+ * export default defineConfig({
15
+ * input: { path: './petStore.yaml' },
16
+ * output: { path: './src/gen', storage: memoryStorage() },
17
+ * })
18
+ * ```
19
+ */
20
+ export const memoryStorage = defineStorage(() => {
21
+ const store = new Map<string, string>()
22
+
23
+ return {
24
+ name: 'memory',
25
+ async hasItem(key: string) {
26
+ return store.has(key)
27
+ },
28
+ async getItem(key: string) {
29
+ return store.get(key) ?? null
30
+ },
31
+ async setItem(key: string, value: string) {
32
+ store.set(key, value)
33
+ },
34
+ async removeItem(key: string) {
35
+ store.delete(key)
36
+ },
37
+ async getKeys(base?: string) {
38
+ const keys = [...store.keys()]
39
+ return base ? keys.filter((k) => k.startsWith(base)) : keys
40
+ },
41
+ async clear(base?: string) {
42
+ if (!base) {
43
+ store.clear()
44
+ return
45
+ }
46
+ for (const key of store.keys()) {
47
+ if (key.startsWith(base)) {
48
+ store.delete(key)
49
+ }
50
+ }
51
+ },
52
+ }
53
+ })
package/src/types.ts CHANGED
@@ -3,6 +3,7 @@ import type { RootNode } from '@kubb/ast/types'
3
3
  import type { KubbFile } from '@kubb/fabric-core/types'
4
4
  import type { Fabric } from '@kubb/react-fabric'
5
5
  import type { DEFAULT_STUDIO_URL, logLevel } from './constants.ts'
6
+ import type { DefineStorage } from './defineStorage.ts'
6
7
  import type { KubbEvents } from './Kubb.ts'
7
8
  import type { PluginManager } from './PluginManager.ts'
8
9
 
@@ -158,8 +159,22 @@ export type Config<TInput = Input> = {
158
159
  /**
159
160
  * Save files to the file system.
160
161
  * @default true
162
+ * @deprecated Use `storage` to control where files are written.
161
163
  */
162
164
  write?: boolean
165
+ /**
166
+ * Storage backend for generated files.
167
+ * Defaults to `fsStorage()` — the built-in filesystem driver.
168
+ * Accepts any object implementing the {@link DefineStorage} interface.
169
+ * Keys are root-relative paths (e.g. `src/gen/api/getPets.ts`).
170
+ * @default fsStorage()
171
+ * @example
172
+ * ```ts
173
+ * import { defineStorage, fsStorage } from '@kubb/core'
174
+ * storage: defineStorage(fsStorage())
175
+ * ```
176
+ */
177
+ storage?: DefineStorage
163
178
  /**
164
179
  * Specifies the formatting tool to be used.
165
180
  * - 'auto' automatically detects and uses biome or prettier (in that order of preference).
@@ -483,4 +498,5 @@ export type Logger<TOptions extends LoggerOptions = LoggerOptions> = {
483
498
 
484
499
  export type UserLogger<TOptions extends LoggerOptions = LoggerOptions> = Omit<Logger<TOptions>, 'logLevel'>
485
500
 
501
+ export type { DefineStorage } from './defineStorage.ts'
486
502
  export type { KubbEvents } from './Kubb.ts'