@kubb/core 5.0.0-alpha.69 → 5.0.0-alpha.70

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import { t as __name } from "./chunk--u3MIqq1.js";
2
- import { FileNode, HttpMethod, ImportNode, InputNode, Node, OperationNode, SchemaNode, Visitor } from "@kubb/ast";
2
+ import { FileNode, HttpMethod, ImportNode, InputNode, Node, OperationNode, SchemaNode, UserFileNode, Visitor } from "@kubb/ast";
3
3
 
4
4
  //#region ../../internals/utils/src/asyncEventEmitter.d.ts
5
5
  /**
@@ -853,28 +853,10 @@ declare global {
853
853
  //#endregion
854
854
  //#region src/defineMiddleware.d.ts
855
855
  /**
856
- * A middleware observes and post-processes the build output produced by plugins.
857
- * It attaches listeners to the shared `hooks` emitter before the plugin execution loop
858
- * begins and reacts to lifecycle events (e.g. `kubb:plugin:end`, `kubb:build:end`) to
859
- * inject barrel files or perform other cross-cutting concerns.
860
- *
861
- * Middleware listeners are always registered **after** all plugin listeners, because
862
- * `createKubb` installs middleware only after the `PluginDriver` has registered every
863
- * plugin's hooks. This means middleware hooks for any event always fire last.
864
- *
865
- * @example
866
- * ```ts
867
- * import { defineMiddleware } from '@kubb/core'
868
- *
869
- * export const myMiddleware = defineMiddleware({
870
- * name: 'my-middleware',
871
- * install(hooks) {
872
- * hooks.on('kubb:build:end', ({ files }) => {
873
- * console.log(`Build complete with ${files.length} files`)
874
- * })
875
- * },
876
- * })
877
- * ```
856
+ * A middleware instance produced by calling a factory created with `defineMiddleware`.
857
+ * It declares event handlers under a `hooks` object which are registered on the
858
+ * shared emitter after all plugin hooks, so middleware handlers for any event
859
+ * always fire last.
878
860
  */
879
861
  type Middleware = {
880
862
  /**
@@ -882,29 +864,51 @@ type Middleware = {
882
864
  */
883
865
  name: string;
884
866
  /**
885
- * Called during `createKubb` after `setup()` but before the plugin
886
- * execution loop starts. Attach listeners to `hooks` here.
867
+ * Lifecycle event handlers for this middleware.
868
+ * Any event from the global `KubbHooks` map can be subscribed to here.
869
+ * Handlers are registered after all plugin handlers, so they always fire last.
887
870
  */
888
- install(hooks: AsyncEventEmitter<KubbHooks>): void;
871
+ hooks: { [K in keyof KubbHooks]?: (...args: KubbHooks[K]) => void | Promise<void> };
889
872
  };
890
873
  /**
891
- * Identity factory for middleware.
892
- * Returns the middleware object unchanged but provides a typed entry-point
893
- * to define middleware with proper inference.
874
+ * Creates a middleware factory using the hook-style (`hooks:`) API.
875
+ *
876
+ * Mirrors `definePlugin`: the factory is called with optional options and returns a
877
+ * fresh `Middleware` instance. Placing per-build state (e.g. accumulators) inside the
878
+ * factory closure ensures each `createKubb` invocation gets its own isolated instance.
894
879
  *
895
880
  * @example
896
881
  * ```ts
897
- * export const myMiddleware = defineMiddleware({
898
- * name: 'my-middleware',
899
- * install(hooks) {
900
- * hooks.on('kubb:build:end', ({ files }) => {
882
+ * // Stateless middleware
883
+ * export const logMiddleware = defineMiddleware(() => ({
884
+ * name: 'log-middleware',
885
+ * hooks: {
886
+ * 'kubb:build:end'({ files }) {
901
887
  * console.log(`Build complete with ${files.length} files`)
902
- * })
888
+ * },
903
889
  * },
890
+ * }))
891
+ *
892
+ * // Middleware with options and per-build state
893
+ * export const myMiddleware = defineMiddleware((options: { prefix: string } = { prefix: '' }) => {
894
+ * const seen = new Set<string>()
895
+ * return {
896
+ * name: 'my-middleware',
897
+ * hooks: {
898
+ * 'kubb:plugin:end'({ plugin }) {
899
+ * seen.add(`${options.prefix}${plugin.name}`)
900
+ * },
901
+ * },
902
+ * }
903
+ * })
904
+ *
905
+ * // Usage in kubb.config.ts:
906
+ * export default defineConfig({
907
+ * middleware: [logMiddleware(), myMiddleware({ prefix: 'pfx:' })],
904
908
  * })
905
909
  * ```
906
910
  */
907
- declare function defineMiddleware(middleware: Middleware): Middleware;
911
+ declare function defineMiddleware<TOptions extends object = object>(factory: (options: TOptions) => Middleware): (options?: TOptions) => Middleware;
908
912
  //#endregion
909
913
  //#region src/defineParser.d.ts
910
914
  type PrintOptions = {
@@ -1125,19 +1129,6 @@ type Config<TInput = Input> = {
1125
1129
  * @deprecated Use `storage` to control where files are written.
1126
1130
  */
1127
1131
  write?: boolean;
1128
- /**
1129
- * Storage backend for generated files.
1130
- * Defaults to `fsStorage()` — the built-in filesystem driver.
1131
- * Accepts any object implementing the {@link Storage} interface.
1132
- * Keys are root-relative paths (e.g. `src/gen/api/getPets.ts`).
1133
- * @default fsStorage()
1134
- * @example
1135
- * ```ts
1136
- * import { memoryStorage } from '@kubb/core'
1137
- * storage: memoryStorage()
1138
- * ```
1139
- */
1140
- storage?: Storage;
1141
1132
  /**
1142
1133
  * Specifies the formatting tool to be used.
1143
1134
  * - 'auto' automatically detects and uses oxfmt, biome, or prettier (in that order of preference).
@@ -1179,6 +1170,19 @@ type Config<TInput = Input> = {
1179
1170
  */
1180
1171
  override?: boolean;
1181
1172
  } & ExtractRegistryKey<Kubb.ConfigOptionsRegistry, 'output'>;
1173
+ /**
1174
+ * Storage backend for generated files.
1175
+ * Defaults to `fsStorage()` — the built-in filesystem driver.
1176
+ * Accepts any object implementing the {@link Storage} interface.
1177
+ * Keys are root-relative paths (e.g. `src/gen/api/getPets.ts`).
1178
+ * @default fsStorage()
1179
+ * @example
1180
+ * ```ts
1181
+ * import { memoryStorage } from '@kubb/core'
1182
+ * storage: memoryStorage()
1183
+ * ```
1184
+ */
1185
+ storage?: Storage;
1182
1186
  /**
1183
1187
  * An array of Kubb plugins used for code generation.
1184
1188
  * Each plugin may declare additional configurable options.
@@ -1562,9 +1566,7 @@ type KubbPluginSetupContext<TFactory extends PluginFactoryOptions = PluginFactor
1562
1566
  /**
1563
1567
  * Inject a raw file into the build output, bypassing the normal generation pipeline.
1564
1568
  */
1565
- injectFile(file: Pick<FileNode, 'baseName' | 'path'> & {
1566
- sources?: FileNode['sources'];
1567
- }): void;
1569
+ injectFile(userFileNode: UserFileNode): void;
1568
1570
  /**
1569
1571
  * Merge a partial config update into the current build configuration.
1570
1572
  */
@@ -1724,6 +1726,16 @@ type KubbPluginEndContext = {
1724
1726
  duration: number;
1725
1727
  success: boolean;
1726
1728
  error?: Error;
1729
+ config: Config;
1730
+ /**
1731
+ * Returns all files currently in the file manager (lazy snapshot).
1732
+ * Includes files added by plugins that have already run.
1733
+ */
1734
+ readonly files: ReadonlyArray<FileNode>;
1735
+ /**
1736
+ * Upsert one or more files into the file manager.
1737
+ */
1738
+ upsertFile: (...files: Array<FileNode>) => void;
1727
1739
  };
1728
1740
  type KubbHookStartContext = {
1729
1741
  id?: string;
@@ -1900,4 +1912,4 @@ type CLIOptions = {
1900
1912
  type PossibleConfig<TCliOptions = undefined> = PossiblePromise<Config | Config[]> | ((...args: [TCliOptions] extends [undefined] ? [] : [TCliOptions]) => PossiblePromise<Config | Config[]>);
1901
1913
  //#endregion
1902
1914
  export { defineParser as $, KubbPluginStartContext as A, Override as B, KubbGenerationSummaryContext as C, KubbLifecycleStartContext as D, KubbInfoContext as E, Logger as F, ResolveOptionsContext as G, PossibleConfig as H, LoggerContext as I, ResolverFileParams as J, Resolver as K, LoggerOptions as L, KubbSuccessContext as M, KubbVersionNewContext as N, KubbPluginEndContext as O, KubbWarnContext as P, Parser as Q, NormalizedPlugin as R, KubbGenerationStartContext as S, KubbHookStartContext as T, ResolveBannerContext as U, PluginFactoryOptions as V, ResolveNameParams as W, UserConfig as X, ResolverPathParams as Y, UserLogger as Z, KubbErrorContext as _, logLevel as _t, Config as a, createKubb as at, KubbFilesProcessingStartContext as b, GeneratorContext as c, Plugin as ct, InputData as d, defineGenerator as dt, Middleware as et, InputPath as f, Storage as ft, KubbDebugContext as g, createRenderer as gt, KubbConfigEndContext as h, RendererFactory as ht, CLIOptions as i, BuildOutput as it, KubbPluginsEndContext as j, KubbPluginSetupContext as k, Group as l, definePlugin as lt, KubbBuildStartContext as m, Renderer as mt, AdapterFactoryOptions as n, Kubb$1 as nt, DevtoolsOptions as o, PluginDriver as ot, KubbBuildEndContext as p, createStorage as pt, ResolverContext as q, AdapterSource as r, KubbHooks as rt, Exclude$1 as s, FileManager as st, Adapter as t, defineMiddleware as tt, Include as u, Generator as ut, KubbFileProcessingUpdateContext as v, AsyncEventEmitter as vt, KubbHookEndContext as w, KubbGenerationEndContext as x, KubbFilesProcessingEndContext as y, Output as z };
1903
- //# sourceMappingURL=types-mW3-Ihuf.d.ts.map
1915
+ //# sourceMappingURL=types-DWtkW2RX.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kubb/core",
3
- "version": "5.0.0-alpha.69",
3
+ "version": "5.0.0-alpha.70",
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
  "ast",
@@ -65,15 +65,15 @@
65
65
  "dependencies": {
66
66
  "fflate": "^0.8.2",
67
67
  "tinyexec": "^1.1.1",
68
- "@kubb/ast": "5.0.0-alpha.69"
68
+ "@kubb/ast": "5.0.0-alpha.70"
69
69
  },
70
70
  "devDependencies": {
71
71
  "p-limit": "^7.3.0",
72
72
  "@internals/utils": "0.0.0",
73
- "@kubb/renderer-jsx": "5.0.0-alpha.69"
73
+ "@kubb/renderer-jsx": "5.0.0-alpha.70"
74
74
  },
75
75
  "peerDependencies": {
76
- "@kubb/renderer-jsx": "5.0.0-alpha.69"
76
+ "@kubb/renderer-jsx": "5.0.0-alpha.70"
77
77
  },
78
78
  "size-limit": [
79
79
  {
@@ -4,6 +4,11 @@ import { createFile } from '@kubb/ast'
4
4
  function mergeFile<TMeta extends object = object>(a: FileNode<TMeta>, b: FileNode<TMeta>): FileNode<TMeta> {
5
5
  return {
6
6
  ...a,
7
+ // Incoming file (b) takes precedence for banner/footer so that barrel files,
8
+ // which never carry a banner, can clear banners set by plugin-generated files
9
+ // at the same path.
10
+ banner: b.banner,
11
+ footer: b.footer,
7
12
  sources: [...(a.sources || []), ...(b.sources || [])],
8
13
  imports: [...(a.imports || []), ...(b.imports || [])],
9
14
  exports: [...(a.exports || []), ...(b.exports || [])],
@@ -161,8 +161,8 @@ export class PluginDriver {
161
161
  setOptions: (opts) => {
162
162
  normalizedPlugin.options = { ...normalizedPlugin.options, ...opts }
163
163
  },
164
- injectFile: ({ sources = [], ...rest }) => {
165
- this.fileManager.add(createFile({ imports: [], exports: [], sources, ...rest }))
164
+ injectFile: (userFileNode) => {
165
+ this.fileManager.add(createFile(userFileNode))
166
166
  },
167
167
  }
168
168
  return hooks['kubb:plugin:setup']!(pluginCtx)
package/src/createKubb.ts CHANGED
@@ -12,7 +12,7 @@ import type { Kubb } from './Kubb.ts'
12
12
  import { PluginDriver } from './PluginDriver.ts'
13
13
  import { applyHookResult } from './renderNode.ts'
14
14
  import { fsStorage } from './storages/fsStorage.ts'
15
- import type { AdapterSource, Config, GeneratorContext, KubbHooks, NormalizedPlugin, Storage, UserConfig } from './types.ts'
15
+ import type { AdapterSource, Config, GeneratorContext, KubbHooks, Middleware, NormalizedPlugin, Storage, UserConfig } from './types.ts'
16
16
  import { getDiagnosticInfo } from './utils/diagnostics.ts'
17
17
  import { isInputPath } from './utils/isInputPath.ts'
18
18
 
@@ -68,7 +68,7 @@ async function setup(userConfig: UserConfig, options: SetupOptions = {}): Promis
68
68
  ` • Output: ${userConfig.output?.path || 'not specified'}`,
69
69
  ` • Plugins: ${userConfig.plugins?.length || 0}`,
70
70
  'Output Settings:',
71
- ` • Storage: ${userConfig.output?.storage ? `custom(${userConfig.output.storage.name})` : userConfig.output?.write === false ? 'disabled' : 'filesystem (default)'}`,
71
+ ` • Storage: ${userConfig.storage ? `custom(${userConfig.storage.name})` : userConfig.output?.write === false ? 'disabled' : 'filesystem (default)'}`,
72
72
  ` • Formatter: ${userConfig.output?.format || 'none'}`,
73
73
  ` • Linter: ${userConfig.output?.lint || 'none'}`,
74
74
  'Environment:',
@@ -124,7 +124,7 @@ async function setup(userConfig: UserConfig, options: SetupOptions = {}): Promis
124
124
  plugins: userConfig.plugins as unknown as Config['plugins'],
125
125
  }
126
126
 
127
- const storage: Storage | null = config.output.write === false ? null : (config.output.storage ?? fsStorage())
127
+ const storage: Storage | null = config.output.write === false ? null : (config.storage ?? fsStorage())
128
128
 
129
129
  if (config.output.clean) {
130
130
  await hooks.emit('kubb:debug', {
@@ -138,11 +138,20 @@ async function setup(userConfig: UserConfig, options: SetupOptions = {}): Promis
138
138
  hooks,
139
139
  })
140
140
 
141
- // Install middleware listeners after all plugin hooks are registered.
141
+ // Register middleware hooks after all plugin hooks are registered.
142
142
  // Because AsyncEventEmitter calls listeners in registration order,
143
143
  // middleware hooks for any event fire after all plugin hooks for that event.
144
+ function registerMiddlewareHook<K extends keyof KubbHooks & string>(event: K, middlewareHooks: Middleware['hooks']) {
145
+ const handler = middlewareHooks[event]
146
+ if (handler) {
147
+ hooks.on(event, handler)
148
+ }
149
+ }
150
+
144
151
  for (const middleware of config.middleware ?? []) {
145
- middleware.install(hooks)
152
+ for (const event of Object.keys(middleware.hooks) as Array<keyof KubbHooks & string>) {
153
+ registerMiddlewareHook(event, middleware.hooks)
154
+ }
146
155
  }
147
156
 
148
157
  const adapter = config.adapter
@@ -308,6 +317,11 @@ async function safeBuild(setupResult: SetupResult): Promise<BuildOutput> {
308
317
  plugin,
309
318
  duration,
310
319
  success: true,
320
+ config,
321
+ get files() {
322
+ return driver.fileManager.files
323
+ },
324
+ upsertFile: (...files) => driver.fileManager.upsert(...files),
311
325
  })
312
326
 
313
327
  await hooks.emit('kubb:debug', {
@@ -324,6 +338,11 @@ async function safeBuild(setupResult: SetupResult): Promise<BuildOutput> {
324
338
  duration,
325
339
  success: false,
326
340
  error,
341
+ config,
342
+ get files() {
343
+ return driver.fileManager.files
344
+ },
345
+ upsertFile: (...files) => driver.fileManager.upsert(...files),
327
346
  })
328
347
 
329
348
  await hooks.emit('kubb:debug', {
@@ -1,29 +1,10 @@
1
- import type { AsyncEventEmitter } from '@internals/utils'
2
1
  import type { KubbHooks } from './Kubb.ts'
3
2
 
4
3
  /**
5
- * A middleware observes and post-processes the build output produced by plugins.
6
- * It attaches listeners to the shared `hooks` emitter before the plugin execution loop
7
- * begins and reacts to lifecycle events (e.g. `kubb:plugin:end`, `kubb:build:end`) to
8
- * inject barrel files or perform other cross-cutting concerns.
9
- *
10
- * Middleware listeners are always registered **after** all plugin listeners, because
11
- * `createKubb` installs middleware only after the `PluginDriver` has registered every
12
- * plugin's hooks. This means middleware hooks for any event always fire last.
13
- *
14
- * @example
15
- * ```ts
16
- * import { defineMiddleware } from '@kubb/core'
17
- *
18
- * export const myMiddleware = defineMiddleware({
19
- * name: 'my-middleware',
20
- * install(hooks) {
21
- * hooks.on('kubb:build:end', ({ files }) => {
22
- * console.log(`Build complete with ${files.length} files`)
23
- * })
24
- * },
25
- * })
26
- * ```
4
+ * A middleware instance produced by calling a factory created with `defineMiddleware`.
5
+ * It declares event handlers under a `hooks` object which are registered on the
6
+ * shared emitter after all plugin hooks, so middleware handlers for any event
7
+ * always fire last.
27
8
  */
28
9
  export type Middleware = {
29
10
  /**
@@ -31,29 +12,53 @@ export type Middleware = {
31
12
  */
32
13
  name: string
33
14
  /**
34
- * Called during `createKubb` after `setup()` but before the plugin
35
- * execution loop starts. Attach listeners to `hooks` here.
15
+ * Lifecycle event handlers for this middleware.
16
+ * Any event from the global `KubbHooks` map can be subscribed to here.
17
+ * Handlers are registered after all plugin handlers, so they always fire last.
36
18
  */
37
- install(hooks: AsyncEventEmitter<KubbHooks>): void
19
+ hooks: {
20
+ [K in keyof KubbHooks]?: (...args: KubbHooks[K]) => void | Promise<void>
21
+ }
38
22
  }
39
23
 
40
24
  /**
41
- * Identity factory for middleware.
42
- * Returns the middleware object unchanged but provides a typed entry-point
43
- * to define middleware with proper inference.
25
+ * Creates a middleware factory using the hook-style (`hooks:`) API.
26
+ *
27
+ * Mirrors `definePlugin`: the factory is called with optional options and returns a
28
+ * fresh `Middleware` instance. Placing per-build state (e.g. accumulators) inside the
29
+ * factory closure ensures each `createKubb` invocation gets its own isolated instance.
44
30
  *
45
31
  * @example
46
32
  * ```ts
47
- * export const myMiddleware = defineMiddleware({
48
- * name: 'my-middleware',
49
- * install(hooks) {
50
- * hooks.on('kubb:build:end', ({ files }) => {
33
+ * // Stateless middleware
34
+ * export const logMiddleware = defineMiddleware(() => ({
35
+ * name: 'log-middleware',
36
+ * hooks: {
37
+ * 'kubb:build:end'({ files }) {
51
38
  * console.log(`Build complete with ${files.length} files`)
52
- * })
39
+ * },
53
40
  * },
41
+ * }))
42
+ *
43
+ * // Middleware with options and per-build state
44
+ * export const myMiddleware = defineMiddleware((options: { prefix: string } = { prefix: '' }) => {
45
+ * const seen = new Set<string>()
46
+ * return {
47
+ * name: 'my-middleware',
48
+ * hooks: {
49
+ * 'kubb:plugin:end'({ plugin }) {
50
+ * seen.add(`${options.prefix}${plugin.name}`)
51
+ * },
52
+ * },
53
+ * }
54
+ * })
55
+ *
56
+ * // Usage in kubb.config.ts:
57
+ * export default defineConfig({
58
+ * middleware: [logMiddleware(), myMiddleware({ prefix: 'pfx:' })],
54
59
  * })
55
60
  * ```
56
61
  */
57
- export function defineMiddleware(middleware: Middleware): Middleware {
58
- return middleware
62
+ export function defineMiddleware<TOptions extends object = object>(factory: (options: TOptions) => Middleware): (options?: TOptions) => Middleware {
63
+ return (options) => factory(options ?? ({} as TOptions))
59
64
  }
@@ -14,7 +14,7 @@ function isMissingPathError(error: unknown): error is NodeJS.ErrnoException {
14
14
  /**
15
15
  * Built-in filesystem storage driver.
16
16
  *
17
- * This is the default storage when no `storage` option is configured in `output`.
17
+ * This is the default storage when no `storage` option is configured in the root config.
18
18
  * Keys are resolved against `process.cwd()`, so root-relative paths such as
19
19
  * `src/gen/api/getPets.ts` are written to the correct location without extra configuration.
20
20
  *
@@ -31,7 +31,8 @@ function isMissingPathError(error: unknown): error is NodeJS.ErrnoException {
31
31
  *
32
32
  * export default defineConfig({
33
33
  * input: { path: './petStore.yaml' },
34
- * output: { path: './src/gen', storage: fsStorage() },
34
+ * output: { path: './src/gen' },
35
+ * storage: fsStorage(),
35
36
  * })
36
37
  * ```
37
38
  */
@@ -14,7 +14,8 @@ import { createStorage } from '../createStorage.ts'
14
14
  *
15
15
  * export default defineConfig({
16
16
  * input: { path: './petStore.yaml' },
17
- * output: { path: './src/gen', storage: memoryStorage() },
17
+ * output: { path: './src/gen' },
18
+ * storage: memoryStorage(),
18
19
  * })
19
20
  * ```
20
21
  */
package/src/types.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { AsyncEventEmitter, PossiblePromise } from '@internals/utils'
2
- import type { FileNode, HttpMethod, ImportNode, InputNode, Node, SchemaNode, Visitor } from '@kubb/ast'
2
+ import type { FileNode, HttpMethod, ImportNode, InputNode, Node, SchemaNode, UserFileNode, Visitor } from '@kubb/ast'
3
3
  import type { DEFAULT_STUDIO_URL, logLevel } from './constants.ts'
4
4
  import type { RendererFactory } from './createRenderer.ts'
5
5
  import type { Storage } from './createStorage.ts'
@@ -190,19 +190,6 @@ export type Config<TInput = Input> = {
190
190
  * @deprecated Use `storage` to control where files are written.
191
191
  */
192
192
  write?: boolean
193
- /**
194
- * Storage backend for generated files.
195
- * Defaults to `fsStorage()` — the built-in filesystem driver.
196
- * Accepts any object implementing the {@link Storage} interface.
197
- * Keys are root-relative paths (e.g. `src/gen/api/getPets.ts`).
198
- * @default fsStorage()
199
- * @example
200
- * ```ts
201
- * import { memoryStorage } from '@kubb/core'
202
- * storage: memoryStorage()
203
- * ```
204
- */
205
- storage?: Storage
206
193
  /**
207
194
  * Specifies the formatting tool to be used.
208
195
  * - 'auto' automatically detects and uses oxfmt, biome, or prettier (in that order of preference).
@@ -244,6 +231,19 @@ export type Config<TInput = Input> = {
244
231
  */
245
232
  override?: boolean
246
233
  } & ExtractRegistryKey<Kubb.ConfigOptionsRegistry, 'output'>
234
+ /**
235
+ * Storage backend for generated files.
236
+ * Defaults to `fsStorage()` — the built-in filesystem driver.
237
+ * Accepts any object implementing the {@link Storage} interface.
238
+ * Keys are root-relative paths (e.g. `src/gen/api/getPets.ts`).
239
+ * @default fsStorage()
240
+ * @example
241
+ * ```ts
242
+ * import { memoryStorage } from '@kubb/core'
243
+ * storage: memoryStorage()
244
+ * ```
245
+ */
246
+ storage?: Storage
247
247
  /**
248
248
  * An array of Kubb plugins used for code generation.
249
249
  * Each plugin may declare additional configurable options.
@@ -648,11 +648,7 @@ export type KubbPluginSetupContext<TFactory extends PluginFactoryOptions = Plugi
648
648
  /**
649
649
  * Inject a raw file into the build output, bypassing the normal generation pipeline.
650
650
  */
651
- injectFile(
652
- file: Pick<FileNode, 'baseName' | 'path'> & {
653
- sources?: FileNode['sources']
654
- },
655
- ): void
651
+ injectFile(userFileNode: UserFileNode): void
656
652
  /**
657
653
  * Merge a partial config update into the current build configuration.
658
654
  */
@@ -828,6 +824,16 @@ export type KubbPluginEndContext = {
828
824
  duration: number
829
825
  success: boolean
830
826
  error?: Error
827
+ config: Config
828
+ /**
829
+ * Returns all files currently in the file manager (lazy snapshot).
830
+ * Includes files added by plugins that have already run.
831
+ */
832
+ readonly files: ReadonlyArray<FileNode>
833
+ /**
834
+ * Upsert one or more files into the file manager.
835
+ */
836
+ upsertFile: (...files: Array<FileNode>) => void
831
837
  }
832
838
 
833
839
  export type KubbHookStartContext = {