@kubb/plugin-react-query 5.10.0-canary.20261109T201601 → 5.10.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.
package/dist/index.cjs CHANGED
@@ -26,12 +26,295 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
26
26
  let _kubb_kit = require("@kubb/kit");
27
27
  let node_path = require("node:path");
28
28
  node_path = __toESM(node_path, 1);
29
- let _kubb_plugin_zod = require("@kubb/plugin-zod");
30
- let _kubb_renderer_jsx = require("@kubb/renderer-jsx");
31
29
  let _kubb_plugin_ts = require("@kubb/plugin-ts");
30
+ let _kubb_renderer_jsx = require("@kubb/renderer-jsx");
32
31
  let _kubb_renderer_jsx_jsx_runtime = require("@kubb/renderer-jsx/jsx-runtime");
33
32
  let node_fs = require("node:fs");
34
33
  node_fs = __toESM(node_fs, 1);
34
+ // kubb-extension.json
35
+ var compatibility = {
36
+ "kubb": ">=5.18.4",
37
+ "node": ">=22.22"
38
+ };
39
+ // package.json
40
+ var version = "5.10.1";
41
+ // ../../internals/client/src/resolveClient.ts
42
+ /**
43
+ * Resolves which client plugin a consumer (react-query, vue-query, swr, mcp) should call for an
44
+ * operation, shared so the selection rules and diagnostics stay in one place.
45
+ *
46
+ * Every client runtime lives in a dedicated client plugin, so a consumer always calls a registered
47
+ * contract client plugin (plugin-fetch, plugin-axios, or plugin-client) and never emits its own
48
+ * inline client:
49
+ *
50
+ * - `contract` — a registered contract client plugin owns the `<op>` functions and the consumer
51
+ * imports and calls them.
52
+ * - `error` — no client plugin is registered, several are registered without a selector, the
53
+ * requested one is missing, or `client` is not a known selector.
54
+ *
55
+ * The `client` string selects explicitly (`'fetch'` / `'axios'` / `'client'`); when it is unset a
56
+ * lone registered contract client plugin is picked up automatically.
57
+ */
58
+ const pluginFetchName = "plugin-fetch";
59
+ const pluginAxiosName = "plugin-axios";
60
+ const pluginClientName = "plugin-client";
61
+ const selectorToPlugin = {
62
+ fetch: pluginFetchName,
63
+ axios: pluginAxiosName,
64
+ client: pluginClientName
65
+ };
66
+ const contractPlugins = [
67
+ pluginFetchName,
68
+ pluginAxiosName,
69
+ pluginClientName
70
+ ];
71
+ /**
72
+ * Applies the `client` resolution rules. See the module comment for the strategy shape.
73
+ *
74
+ * @example
75
+ * ```ts
76
+ * resolveClient({ client: 'fetch', pluginNames: ['plugin-ts', 'plugin-fetch'] })
77
+ * // { kind: 'contract', pluginName: 'plugin-fetch' }
78
+ * ```
79
+ *
80
+ * @example
81
+ * ```ts
82
+ * resolveClient({ client: undefined, pluginNames: ['plugin-ts'] })
83
+ * // { kind: 'error', code: 'KUBB_MISSING_DEPENDENCY', message: 'No client plugin is registered.', help: 'Add …' }
84
+ * ```
85
+ */
86
+ function resolveClient(options) {
87
+ const { client, pluginNames } = options;
88
+ const has = (name) => pluginNames.includes(name);
89
+ if (client === "fetch" || client === "axios" || client === "client") {
90
+ const pluginName = selectorToPlugin[client];
91
+ if (!has(pluginName)) return {
92
+ kind: "error",
93
+ code: _kubb_kit.Diagnostics.code.missingDependency,
94
+ message: `\`client: '${client}'\` is set but \`@kubb/plugin-${client}\` is not registered in \`plugins\`.`,
95
+ help: `Add \`@kubb/plugin-${client}\` to \`plugins\`, or drop \`client\` to use a different client plugin.`
96
+ };
97
+ return {
98
+ kind: "contract",
99
+ pluginName
100
+ };
101
+ }
102
+ if (client !== void 0) return {
103
+ kind: "error",
104
+ code: _kubb_kit.Diagnostics.code.invalidPluginOptions,
105
+ message: `Option \`client\` is ${typeof client === "string" ? `'${client}'` : String(client)}, but it must be one of 'fetch', 'axios', 'client'.`,
106
+ help: "Set `client` to one of those values, or drop it to use the registered client plugin."
107
+ };
108
+ const registered = contractPlugins.filter(has);
109
+ if (registered.length === 1) return {
110
+ kind: "contract",
111
+ pluginName: registered[0]
112
+ };
113
+ if (registered.length > 1) return {
114
+ kind: "error",
115
+ code: _kubb_kit.Diagnostics.code.invalidPluginOptions,
116
+ message: `Multiple client plugins are registered (${registered.map((name) => `\`@kubb/${name}\``).join(", ")}) and \`client\` is not set.`,
117
+ help: "Set `client: 'fetch' | 'axios' | 'client'` to choose which client the hooks call, or register a single client plugin."
118
+ };
119
+ return {
120
+ kind: "error",
121
+ code: _kubb_kit.Diagnostics.code.missingDependency,
122
+ message: "No client plugin is registered.",
123
+ help: "Add `@kubb/plugin-fetch`, `@kubb/plugin-axios`, or `@kubb/plugin-client` to `plugins` so the generated code has an HTTP client to call."
124
+ };
125
+ }
126
+ /**
127
+ * Resolves the contract client during a consumer plugin's setup hook.
128
+ * It extracts the plugin names from the raw `plugins` config and applies {@link resolveClient}.
129
+ * On a misconfiguration it throws a config diagnostic tagged with `plugin`, so every consumer
130
+ * fails fast with the same message.
131
+ */
132
+ function resolveContractClient(options) {
133
+ const { plugin, client, plugins = [] } = options;
134
+ const resolved = resolveClient({
135
+ client,
136
+ pluginNames: plugins.map((plugin) => plugin.name).filter((name) => Boolean(name))
137
+ });
138
+ if (resolved.kind === "error") {
139
+ const { code, message, help } = resolved;
140
+ throw new _kubb_kit.Diagnostics.Error({
141
+ code,
142
+ severity: "error",
143
+ message,
144
+ help,
145
+ location: { kind: "config" },
146
+ plugin
147
+ });
148
+ }
149
+ return resolved;
150
+ }
151
+ // ../../internals/utils/src/reserved.ts
152
+ /**
153
+ * JavaScript and Java reserved words.
154
+ * @link https://github.com/jonschlinkert/reserved/blob/master/index.js
155
+ */
156
+ const reservedWords = /* @__PURE__ */ new Set([
157
+ "abstract",
158
+ "arguments",
159
+ "await",
160
+ "boolean",
161
+ "break",
162
+ "byte",
163
+ "case",
164
+ "catch",
165
+ "char",
166
+ "class",
167
+ "const",
168
+ "continue",
169
+ "debugger",
170
+ "default",
171
+ "delete",
172
+ "do",
173
+ "double",
174
+ "else",
175
+ "enum",
176
+ "eval",
177
+ "export",
178
+ "extends",
179
+ "false",
180
+ "final",
181
+ "finally",
182
+ "float",
183
+ "for",
184
+ "function",
185
+ "goto",
186
+ "if",
187
+ "implements",
188
+ "import",
189
+ "in",
190
+ "instanceof",
191
+ "int",
192
+ "interface",
193
+ "let",
194
+ "long",
195
+ "native",
196
+ "new",
197
+ "null",
198
+ "package",
199
+ "private",
200
+ "protected",
201
+ "public",
202
+ "return",
203
+ "short",
204
+ "static",
205
+ "super",
206
+ "switch",
207
+ "synchronized",
208
+ "this",
209
+ "throw",
210
+ "throws",
211
+ "transient",
212
+ "true",
213
+ "try",
214
+ "typeof",
215
+ "var",
216
+ "void",
217
+ "volatile",
218
+ "while",
219
+ "with",
220
+ "yield",
221
+ "Array",
222
+ "Date",
223
+ "hasOwnProperty",
224
+ "Infinity",
225
+ "isFinite",
226
+ "isNaN",
227
+ "isPrototypeOf",
228
+ "length",
229
+ "Math",
230
+ "name",
231
+ "NaN",
232
+ "Number",
233
+ "Object",
234
+ "prototype",
235
+ "String",
236
+ "toString",
237
+ "undefined",
238
+ "valueOf"
239
+ ]);
240
+ /**
241
+ * Returns `true` when `name` is a syntactically valid JavaScript variable name.
242
+ *
243
+ * @example
244
+ * ```ts
245
+ * isValidVarName('status') // true
246
+ * isValidVarName('class') // false (reserved word)
247
+ * isValidVarName('42foo') // false (starts with digit)
248
+ * ```
249
+ */
250
+ function isValidVarName(name) {
251
+ if (!name || reservedWords.has(name)) return false;
252
+ return isIdentifier(name);
253
+ }
254
+ /**
255
+ * Returns `name` when it's a syntactically valid JavaScript variable name,
256
+ * otherwise prefixes it with `_` so the result is a valid identifier.
257
+ *
258
+ * Useful for sanitizing OpenAPI schema names or operation IDs that start with
259
+ * a digit (e.g. `409`, `504AccountCancel`) before using them as exported
260
+ * variable, type, or function names.
261
+ *
262
+ * @example
263
+ * ```ts
264
+ * ensureValidVarName('409') // '_409'
265
+ * ensureValidVarName('504AccountCancel') // '_504AccountCancel'
266
+ * ensureValidVarName('Pet') // 'Pet'
267
+ * ensureValidVarName('class') // '_class'
268
+ * ```
269
+ */
270
+ function ensureValidVarName(name) {
271
+ if (!name || isValidVarName(name)) return name;
272
+ return `_${name}`;
273
+ }
274
+ /**
275
+ * Returns `true` when `name` is syntactically a valid identifier, ignoring reserved words.
276
+ *
277
+ * Reserved words and globals (`class`, `name`, `Date`, …) are valid as bare object-literal keys
278
+ * even though they are not valid variable names, so use this (not {@link isValidVarName}) when
279
+ * deciding whether an object key needs quoting.
280
+ *
281
+ * @example
282
+ * ```ts
283
+ * isIdentifier('name') // true
284
+ * isIdentifier('x-total')// false
285
+ * ```
286
+ */
287
+ function isIdentifier(name) {
288
+ return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
289
+ }
290
+ // ../../internals/utils/src/strings.ts
291
+ /**
292
+ * Renders a dotted path or string array as an optional-chaining accessor expression rooted at
293
+ * `accessor`. Returns `null` for an empty path.
294
+ *
295
+ * @example
296
+ * ```ts
297
+ * getNestedAccessor('pagination.next.id', 'lastPage')
298
+ * // "lastPage?.['pagination']?.['next']?.['id']"
299
+ * ```
300
+ */
301
+ function getNestedAccessor(param, accessor) {
302
+ const parts = Array.isArray(param) ? param : param.split(".");
303
+ if (parts.length === 0 || parts.length === 1 && parts[0] === "") return null;
304
+ return `${accessor}?.['${`${parts.join("']?.['")}']`}`;
305
+ }
306
+ /**
307
+ * Escapes an `@` at the start of a line, so a multi-line description can't start a new JSDoc tag.
308
+ * Editors render `\@` as `@` in hovers.
309
+ *
310
+ * @example
311
+ * ```ts
312
+ * jsDocEscape('intro\n@example value') // 'intro\n\\@example value'
313
+ * ```
314
+ */
315
+ function jsDocEscape(input) {
316
+ return `${input}`.replace(/^(\s*)@/gm, "$1\\@");
317
+ }
35
318
  // ../../internals/shared/src/operation.ts
36
319
  /**
37
320
  * Builds the `ResolverFileParams` every operation generator passes to
@@ -53,29 +336,55 @@ function operationFileEntry(node, name, extname = ".ts") {
53
336
  };
54
337
  }
55
338
  /**
56
- * Resolves a dependency plugin's generated file for `node.operationId`, cached in `memo` (the
57
- * build's `ctx.memo`) under the resolver's own plugin name and the operation. Several dependents reading the
58
- * same dependency for the same operation in one pass (a query plugin's several hook generators, the
59
- * MCP handler, ...) share one computed name and path instead of each calling `resolver.file` again.
339
+ * Resolves the file a schema-emitting plugin (`plugin-ts`, `plugin-zod`, `plugin-faker`) writes
340
+ * `node` to, cached in `ctx.memo` under the resolver's plugin name and the
341
+ * operation. The plugin itself and every plugin that imports from it call this, so they all get
342
+ * the same path.
60
343
  *
61
- * @example Cache `plugin-ts`'s file for the current operation
344
+ * When that path matches the file of a component schema in `ctx.driver.inputNode`, ignoring case, the file name
345
+ * gets an `Operation` suffix: operation `point` goes to `PointOperation.ts` next to schema `Point.ts`.
346
+ * Otherwise the two merge into one file, or overwrite each other on a case-insensitive file system.
347
+ * Only the file name changes. The declarations keep their names.
348
+ *
349
+ * @example Resolve `plugin-ts`'s file for the current operation
62
350
  * ```ts
63
- * const fileTs = resolveDependencyOperationFile({ memo: ctx.memo, node, resolver: tsResolver, root, output })
351
+ * const fileTs = resolveOperationFile({ ctx, node, resolver: tsResolver, root, output })
64
352
  * ```
65
353
  */
66
- function resolveDependencyOperationFile(options) {
67
- const { memo, node, resolver, root, output, group } = options;
68
- return memo(`${resolver.pluginName}:operationFile:${node.operationId}`, () => resolver.file({
69
- ...operationFileEntry(node, node.operationId),
354
+ function resolveOperationFile(options) {
355
+ const { ctx, node, resolver, root, output } = options;
356
+ const { memo } = ctx;
357
+ const location = {
70
358
  root,
71
359
  output,
72
- group: group ?? void 0
73
- }));
360
+ group: options.group ?? void 0
361
+ };
362
+ return memo(`${resolver.pluginName}:operationFile:${node.operationId}`, () => {
363
+ const schemaPaths = memo(`${resolver.pluginName}:schemaFilePaths`, () => new Set((ctx.driver.inputNode?.schemas ?? []).flatMap((schema) => schema.name ? [resolver.file({
364
+ name: schema.name,
365
+ extname: ".ts",
366
+ ...location
367
+ }).path.toLowerCase()] : [])));
368
+ let file = resolver.file({
369
+ ...operationFileEntry(node, node.operationId),
370
+ ...location
371
+ });
372
+ for (let name = `${node.operationId}Operation`; schemaPaths.has(file.path.toLowerCase()); name += "Operation") {
373
+ const next = resolver.file({
374
+ ...operationFileEntry(node, name),
375
+ ...location
376
+ });
377
+ if (next.path === file.path) break;
378
+ file = next;
379
+ }
380
+ return file;
381
+ });
74
382
  }
75
- function getOperationLink(node, link) {
76
- if (!link) return null;
77
- if (typeof link === "function") return link(node) ?? null;
78
- return node.path ? `{@link ${_kubb_kit.Url.toPath(node.path)}}` : null;
383
+ /**
384
+ * The operation's method and path as plain text, such as `` `GET /pet/{petId}` ``. A path is not a valid `{@link}` target.
385
+ */
386
+ function getOperationRequestLine(node) {
387
+ return _kubb_kit.ast.http.isOperation(node) && node.path ? `\`${node.method.toUpperCase()} ${node.path}\`` : null;
79
388
  }
80
389
  /**
81
390
  * Derives the shared `ContentTypeInfo` shape from a list of content types, tracking whether several
@@ -99,18 +408,7 @@ function getContentTypeInfo(node) {
99
408
  * whether several are present, so the client can let a caller pick which one to accept.
100
409
  */
101
410
  function getResponseContentTypeInfo(node) {
102
- return buildContentTypeInfo(getPrimarySuccessResponse(node)?.content?.map((e) => e.contentType) ?? []);
103
- }
104
- function baseContentType(contentType) {
105
- return contentType.split(";")[0].trim().toLowerCase();
106
- }
107
- /**
108
- * Whether a content entry is a sequence of JSON values the adapter marks as a stream, such as `application/jsonl`,
109
- * `application/x-ndjson`, `application/json-seq`, or any media type with an OpenAPI 3.2 `itemSchema`.
110
- */
111
- function isJsonLines(entry) {
112
- const baseType = baseContentType(entry.contentType);
113
- return Boolean(entry.stream) && baseType !== "text/event-stream" && !baseType.startsWith("multipart/");
411
+ return buildContentTypeInfo(_kubb_kit.ast.http.responses.findPrimary(node)?.content?.map((e) => e.contentType) ?? []);
114
412
  }
115
413
  /**
116
414
  * How an operation streams its primary success response item by item, when that response declares one content type:
@@ -122,11 +420,19 @@ function isJsonLines(entry) {
122
420
  * call with its query hooks.
123
421
  */
124
422
  function getEventStream(node) {
125
- const content = getPrimarySuccessResponse(node)?.content ?? [];
423
+ const content = _kubb_kit.ast.http.responses.findPrimary(node)?.content ?? [];
126
424
  if (content.length !== 1) return null;
127
425
  const entry = content[0];
128
- if (baseContentType(entry.contentType) === "text/event-stream") return entry.stream?.shape ?? "data";
129
- return isJsonLines(entry) ? "line" : null;
426
+ const framing = getStreamFraming(entry);
427
+ if (framing === "events") return entry.stream?.shape ?? "data";
428
+ return framing === "lines" ? "line" : null;
429
+ }
430
+ /**
431
+ * How a content entry is framed as a stream: `'events'` for Server-Sent Events, `'lines'` for JSON Lines.
432
+ */
433
+ function getStreamFraming(entry) {
434
+ if (_kubb_kit.ast.mediaType.getBase(entry) === "text/event-stream") return "events";
435
+ return entry.stream && _kubb_kit.ast.mediaType.isStream(entry) ? "lines" : void 0;
130
436
  }
131
437
  /**
132
438
  * Whether an operation streams its primary success response, as Server-Sent Events or JSON Lines. The client generator uses
@@ -136,20 +442,42 @@ function isEventStream(node) {
136
442
  return getEventStream(node) !== null;
137
443
  }
138
444
  /**
445
+ * Whether a success response offers a stream media type next to other content types. The client returns that variant's
446
+ * body as a `ReadableStream`, so the stream runtime is registered and a hook's data type includes the stream.
447
+ */
448
+ function hasStreamVariant(node) {
449
+ return _kubb_kit.ast.http.responses.filterSuccess(node).some((response) => {
450
+ const variants = (response.content ?? []).filter((entry) => entry.schema);
451
+ return variants.length > 1 && variants.some((entry) => _kubb_kit.ast.mediaType.isStream(entry));
452
+ });
453
+ }
454
+ /**
139
455
  * Builds the `client?:` option type shared by the generated query hooks (`useQuery`,
140
- * `useInfiniteQuery`, `useSWR`, ...). Unlike {@link buildRequestConfigType}, it never adds a
141
- * `contentType?:` member: query hooks wrap GET operations, which carry no request body to select a
142
- * content type for. It drops the data-shape keys to stay assignable to `Options`, which omits them
143
- * from `RequestConfig`. `cookies` is a group only on an operation that declares one.
456
+ * `useInfiniteQuery`, `useSWR`, ...): `RequestConfig` minus what the
457
+ * hook fills in, which is every request group and `throwOnError`. Unlike {@link buildRequestConfigType},
458
+ * it never narrows `contentType`: query hooks wrap GET operations, which carry no request body to select
459
+ * a content type for.
144
460
  */
145
- function buildClientOptionType(node) {
146
- return `Partial<Omit<RequestConfig, 'path' | 'query' | 'body' | 'headers'${getOperationParameters(node).cookie.length > 0 ? ` | 'cookies'` : ""} | 'url'>>`;
461
+ function buildClientOptionType(options = {}) {
462
+ return `Partial<Omit<RequestConfig, ${[
463
+ ...requestGroupOrder,
464
+ "url",
465
+ ...options.omit ?? [],
466
+ "throwOnError"
467
+ ].map((key) => `'${key}'`).join(" | ")}>>`;
147
468
  }
469
+ /**
470
+ * The `client?:` option type of a mutation hook. When the operation has a request content type choice,
471
+ * the mutation variables carry `contentType`, so the config leaves it out. Otherwise the ambiguous side is
472
+ * narrowed to the operation's media types; a single-type side has nothing to pick, so it stays baked in the
473
+ * generated call.
474
+ */
148
475
  function buildRequestConfigType(node) {
476
+ if (hasRequestContentTypeChoice(node)) return buildClientOptionType({ omit: ["contentType"] });
149
477
  const request = getContentTypeInfo(node);
150
478
  const response = getResponseContentTypeInfo(node);
151
479
  const members = [request.isMultipleContentTypes ? `request?: ${request.contentTypeUnion}` : null, response.isMultipleContentTypes ? `response?: ${response.contentTypeUnion}` : null].filter(Boolean);
152
- const base = buildClientOptionType(node);
480
+ const base = buildClientOptionType();
153
481
  return members.length ? `${base} & { contentType?: { ${members.join("; ")} } }` : base;
154
482
  }
155
483
  /** The grouped request options, in the order generated signatures and calls list them. */
@@ -164,11 +492,11 @@ const requestGroupOrder = [
164
492
  * Which of the grouped request options an operation carries.
165
493
  */
166
494
  function getRequestGroups(node) {
167
- const { path, query, header, cookie } = getOperationParameters(node);
495
+ const { path, query, header, cookie } = _kubb_kit.ast.http.groupParameters(node);
168
496
  return {
169
497
  path: path.length > 0,
170
498
  query: query.length > 0,
171
- body: Boolean(node.requestBody?.content?.[0]?.schema),
499
+ body: Boolean(_kubb_kit.ast.http.requestBody.getSchema(node)),
172
500
  headers: header.length > 0,
173
501
  cookies: cookie.length > 0
174
502
  };
@@ -180,7 +508,7 @@ function getRequestGroups(node) {
180
508
  */
181
509
  function getRequestGroupOptionality(node) {
182
510
  const groups = getRequestGroups(node);
183
- const { path, query, header } = getOperationParameters(node);
511
+ const { path, query, header } = _kubb_kit.ast.http.groupParameters(node);
184
512
  const hasRequiredPath = path.some((param) => param.required);
185
513
  const hasRequiredQuery = query.some((param) => param.required);
186
514
  const hasRequiredHeader = header.some((param) => param.required);
@@ -193,104 +521,28 @@ function getRequestGroupOptionality(node) {
193
521
  };
194
522
  }
195
523
  function buildOperationComments(node, options = {}) {
196
- const { link = "pathTemplate", linkPosition = "afterDeprecated", splitLines = false } = options;
197
- const linkComment = getOperationLink(node, link);
198
- const filteredComments = (linkPosition === "beforeDeprecated" ? [
199
- node.description && `@description ${node.description}`,
200
- node.summary && `@summary ${node.summary}`,
201
- linkComment,
202
- node.deprecated && "@deprecated"
203
- ] : [
524
+ const { splitLines = false } = options;
525
+ const filteredComments = [
526
+ getOperationRequestLine(node),
204
527
  node.description && `@description ${node.description}`,
205
528
  node.summary && `@summary ${node.summary}`,
206
529
  node.deprecated && "@deprecated",
207
- linkComment
208
- ]).filter((comment) => Boolean(comment));
530
+ node.externalDocs && `@see ${jsDocEscape([node.externalDocs.url, node.externalDocs.description].filter(Boolean).join(" "))}`
531
+ ].filter((comment) => Boolean(comment));
209
532
  if (!splitLines) return filteredComments;
210
533
  return filteredComments.flatMap((text) => text.split(/\r?\n/).map((line) => line.trim())).filter((comment) => Boolean(comment));
211
534
  }
212
- const operationParameterGroupsByNode = /* @__PURE__ */ new WeakMap();
213
- /**
214
- * An OpenAPI 3.2 `querystring` parameter is the whole query string, so a form-encoded object becomes one query parameter
215
- * per property, typed and serialized like any other.
216
- * Another content type, such as JSON, stays one parameter named after it, and the runtime sends its value as the whole query string.
217
- */
218
- function spreadQuerystring(param) {
219
- const schema = param.schema.type === "ref" ? param.schema.schema : param.schema;
220
- const formEncoded = !param.contentType || param.contentType.split(";")[0].trim().toLowerCase() === "application/x-www-form-urlencoded";
221
- if (schema?.type !== "object" || !formEncoded) return [param];
222
- return schema.properties.map((property) => _kubb_kit.ast.factory.createParameter({
223
- name: property.name,
224
- in: "query",
225
- schema: property.schema,
226
- required: param.required && property.required
227
- }));
228
- }
229
- /**
230
- * Groups an operation's parameters by location (`path`/`query`/`header`/`cookie`), deduping each
231
- * group by name. Every plugin generator visiting the same `OperationNode` shares one AST instance
232
- * (see `KubbDriver`), so the result is cached per node to avoid re-filtering and re-deduping the
233
- * same parameters once per plugin.
234
- */
235
- function getOperationParameters(node) {
236
- const cached = operationParameterGroupsByNode.get(node);
237
- if (cached) return cached;
238
- const dedupe = (params) => {
239
- const seen = /* @__PURE__ */ new Set();
240
- return params.filter((param) => {
241
- if (seen.has(param.name)) return false;
242
- seen.add(param.name);
243
- return true;
244
- });
245
- };
246
- const group = (location) => dedupe(node.parameters.filter((param) => param.in === location));
247
- const groups = {
248
- path: group("path"),
249
- query: dedupe([...group("query"), ...group("querystring").flatMap(spreadQuerystring)]),
250
- header: group("header"),
251
- cookie: group("cookie")
252
- };
253
- operationParameterGroupsByNode.set(node, groups);
254
- return groups;
255
- }
256
535
  /**
257
536
  * Whether the operation declares more than one request media type with a schema, so a caller must pick one on `contentType`.
258
537
  */
259
538
  function hasRequestContentTypeChoice(node) {
260
539
  return (node.requestBody?.content ?? []).filter((entry) => entry.schema).length > 1;
261
540
  }
262
- /**
263
- * Casts a call argument to the client's parameter type; a `'plain'` client is non-generic.
264
- */
265
- function castToClientOptions(callArg, clientName, returnType = "full") {
266
- return `${callArg} as Parameters<typeof ${clientName}${returnType === "plain" ? "" : "<true>"}>[0]`;
267
- }
268
- function getStatusCodeNumber(statusCode) {
269
- const code = Number(statusCode);
270
- return Number.isNaN(code) ? null : code;
271
- }
272
- function isSuccessStatusCode(statusCode) {
273
- const code = getStatusCodeNumber(statusCode);
274
- return code !== null && code >= 200 && code < 300;
275
- }
276
- function isErrorStatusCode(statusCode) {
277
- const code = getStatusCodeNumber(statusCode);
278
- return code !== null && code >= 400;
279
- }
280
- function getSuccessResponses(responses) {
281
- return responses.filter((response) => isSuccessStatusCode(response.statusCode));
282
- }
283
- function getOperationSuccessResponses(node) {
284
- return getSuccessResponses(node.responses);
285
- }
286
- function getPrimarySuccessResponse(node) {
287
- return getOperationSuccessResponses(node)[0] ?? null;
288
- }
289
541
  function resolveErrorNames(node, resolver) {
290
- return node.responses.filter((response) => isErrorStatusCode(response.statusCode)).map((response) => resolver.response.status(node, response.statusCode));
542
+ return _kubb_kit.ast.http.responses.filterError(node).map((response) => resolver.response.status(node, response.statusCode));
291
543
  }
292
544
  function resolveSuccessNames(node, resolver) {
293
- return node.responses.filter((response) => isSuccessStatusCode(response.statusCode)).map((response) => resolver.response.status(node, response.statusCode));
545
+ return _kubb_kit.ast.http.responses.filterSuccess(node).map((response) => resolver.response.status(node, response.statusCode));
294
546
  }
295
547
  function resolveStatusCodeNames(node, resolver) {
296
548
  return node.responses.map((response) => resolver.response.status(node, response.statusCode));
@@ -302,7 +554,7 @@ function resolveStatusCodeNames(node, resolver) {
302
554
  function resolveOperationTypeNames(node, resolver, options = {}) {
303
555
  const key = `${node.operationId}\0${options.order ?? ""}\0${options.responseStatusNames ?? ""}\0${options.includeParams === false ? "noparams" : ""}\0${(options.exclude ?? []).join(",")}`;
304
556
  return resolver.memo(`operationTypeNames:${key}`, () => {
305
- const { path, query, header, cookie } = getOperationParameters(node);
557
+ const { path, query, header, cookie } = _kubb_kit.ast.http.groupParameters(node);
306
558
  const responseStatusNames = options.responseStatusNames === "error" ? resolveErrorNames(node, resolver) : options.responseStatusNames === false ? [] : resolveStatusCodeNames(node, resolver);
307
559
  const exclude = new Set(options.exclude ?? []);
308
560
  const paramNames = options.includeParams === false ? [] : [
@@ -311,7 +563,7 @@ function resolveOperationTypeNames(node, resolver, options = {}) {
311
563
  ...header.map((param) => resolver.param.headers(node, param)),
312
564
  ...cookie.map((param) => resolver.param.cookies(node, param))
313
565
  ];
314
- const bodyAndResponseNames = [node.requestBody?.content?.[0]?.schema ? resolver.response.body(node) : null, resolver.response.response(node)];
566
+ const bodyAndResponseNames = [_kubb_kit.ast.http.requestBody.getSchema(node) ? resolver.response.body(node) : null, resolver.response.response(node)];
315
567
  return (options.order === "body-response-first" ? [
316
568
  ...bodyAndResponseNames,
317
569
  ...paramNames,
@@ -323,235 +575,139 @@ function resolveOperationTypeNames(node, resolver, options = {}) {
323
575
  ]).filter((name) => Boolean(name) && !exclude.has(name));
324
576
  });
325
577
  }
326
- // ../../internals/utils/src/casing.ts
327
- /**
328
- * Uppercases only the first character of `text`, leaving the rest untouched.
329
- * Unlike `pascalCase` it never re-splits word boundaries or strips characters.
330
- *
331
- * @example
332
- * `capitalize('getPetById') // 'GetPetById'`
333
- */
334
- function capitalize(text) {
335
- return `${text.charAt(0).toUpperCase()}${text.slice(1)}`;
336
- }
337
- // ../../internals/utils/src/reserved.ts
338
- /**
339
- * JavaScript and Java reserved words.
340
- * @link https://github.com/jonschlinkert/reserved/blob/master/index.js
341
- */
342
- const reservedWords = /* @__PURE__ */ new Set([
343
- "abstract",
344
- "arguments",
345
- "await",
346
- "boolean",
347
- "break",
348
- "byte",
349
- "case",
350
- "catch",
351
- "char",
352
- "class",
353
- "const",
354
- "continue",
355
- "debugger",
356
- "default",
357
- "delete",
358
- "do",
359
- "double",
360
- "else",
361
- "enum",
362
- "eval",
363
- "export",
364
- "extends",
365
- "false",
366
- "final",
367
- "finally",
368
- "float",
369
- "for",
370
- "function",
371
- "goto",
372
- "if",
373
- "implements",
374
- "import",
375
- "in",
376
- "instanceof",
377
- "int",
378
- "interface",
379
- "let",
380
- "long",
381
- "native",
382
- "new",
383
- "null",
384
- "package",
385
- "private",
386
- "protected",
387
- "public",
388
- "return",
389
- "short",
390
- "static",
391
- "super",
392
- "switch",
393
- "synchronized",
394
- "this",
395
- "throw",
396
- "throws",
397
- "transient",
398
- "true",
399
- "try",
400
- "typeof",
401
- "var",
402
- "void",
403
- "volatile",
404
- "while",
405
- "with",
406
- "yield",
407
- "Array",
408
- "Date",
409
- "hasOwnProperty",
410
- "Infinity",
411
- "isFinite",
412
- "isNaN",
413
- "isPrototypeOf",
414
- "length",
415
- "Math",
416
- "name",
417
- "NaN",
418
- "Number",
419
- "Object",
420
- "prototype",
421
- "String",
422
- "toString",
423
- "undefined",
424
- "valueOf"
425
- ]);
578
+ // ../../internals/shared/src/resolver.ts
426
579
  /**
427
- * Returns `true` when `name` is a syntactically valid JavaScript variable name.
428
- *
429
- * @example
430
- * ```ts
431
- * isValidVarName('status') // true
432
- * isValidVarName('class') // false (reserved word)
433
- * isValidVarName('42foo') // false (starts with digit)
434
- * ```
580
+ * The shared top-level `name` of the operation plugins, computed once per operation name and build.
435
581
  */
436
- function isValidVarName(name) {
437
- if (!name || reservedWords.has(name)) return false;
438
- return isIdentifier(name);
582
+ function resolveOperationName(name) {
583
+ return this.memo(`operation:${name}`, () => ensureValidVarName(_kubb_kit.casing.camel(name)));
439
584
  }
440
585
  /**
441
- * Returns `name` when it's a syntactically valid JavaScript variable name,
442
- * otherwise prefixes it with `_` so the result is a valid identifier.
586
+ * Builds the allocation key for a declaration an operation owns. `scope` names which declaration
587
+ * it is, so two of them never share an allocation even when a custom resolver gives both the same
588
+ * name. Leave `scope` empty for the operation's own declaration.
443
589
  *
444
- * Useful for sanitizing OpenAPI schema names or operation IDs that start with
445
- * a digit (e.g. `409`, `504AccountCancel`) before using them as exported
446
- * variable, type, or function names.
590
+ * The key starts from the operation's input `pointer`, which macros keep, so a plugin whose macro
591
+ * rewrites the method or path still resolves another plugin's names for the same operation.
447
592
  *
448
593
  * @example
449
594
  * ```ts
450
- * ensureValidVarName('409') // '_409'
451
- * ensureValidVarName('504AccountCancel') // '_504AccountCancel'
452
- * ensureValidVarName('Pet') // 'Pet'
453
- * ensureValidVarName('class') // '_class'
595
+ * resolver.resolveName({ key: operationKey(node, 'response', 'status', 404), name })
454
596
  * ```
455
597
  */
456
- function ensureValidVarName(name) {
457
- if (!name || isValidVarName(name)) return name;
458
- return `_${name}`;
598
+ function operationKey(node, ...scope) {
599
+ return [
600
+ "operation",
601
+ ...node.pointer ? [node.pointer] : [node.method, node.path],
602
+ ...scope.map(String)
603
+ ];
604
+ }
605
+ // ../../internals/client/src/resolveClientOperation.ts
606
+ function isRelativeImport(importPath) {
607
+ return importPath.startsWith(".");
608
+ }
609
+ function resolveImportPath(options) {
610
+ const { importPath, operationFile } = options;
611
+ return isRelativeImport(importPath) ? node_path.default.resolve(node_path.default.dirname(operationFile), importPath) : importPath;
459
612
  }
460
613
  /**
461
- * Returns `true` when `name` is syntactically a valid identifier, ignoring reserved words.
614
+ * Resolves the contract client `<op>` a consumer (query hook, MCP handler) imports, by looking up
615
+ * the registered contract client plugin's resolver and output. Works for any contract client plugin
616
+ * (plugin-fetch, plugin-axios, or plugin-client). Returns `null` when no contract plugin is in play (the inline
617
+ * path), or when the client plugin's `exclude` / `include` leaves this operation out, since it then
618
+ * emits no `<op>` to import. plugin-fetch / plugin-axios inject `.kubb/client.ts` at the global
619
+ * output root, the same path consumers read `RequestConfig` / `ResponseErrorConfig` from.
620
+ * With plugin-client they come from the user's `importPath` module instead.
462
621
  *
463
- * Reserved words and globals (`class`, `name`, `Date`, …) are valid as bare object-literal keys
464
- * even though they are not valid variable names, so use this (not {@link isValidVarName}) when
465
- * deciding whether an object key needs quoting.
622
+ * The result is cached in `memo` (the build's `ctx.memo`) under the client plugin's name and the operation,
623
+ * so several dependents reading the same client plugin for one operation in a single pass
624
+ * (react-query's query/mutation/infinite generators, vue-query, swr, the MCP handler, ...) share
625
+ * one computed result instead of each re-deriving the name and path.
466
626
  *
467
- * @example
468
- * ```ts
469
- * isIdentifier('name') // true
470
- * isIdentifier('x-total')// false
471
- * ```
627
+ * `returnType`, `output`, and `group` are the client plugin's options for this operation, after its
628
+ * `override` entries, the same resolution its own generator sees. A dependent's generated call body
629
+ * and import path therefore match the `<op>` actually emitted, even when an `override` changes it.
472
630
  */
473
- function isIdentifier(name) {
474
- return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
631
+ function resolveClientOperation(options) {
632
+ const { clientPlugin, driver, node, root, output, memo } = options;
633
+ if (!clientPlugin) return null;
634
+ return memo(`${clientPlugin.pluginName}:clientOperation:${node.operationId}`, () => {
635
+ const resolver = driver.getResolver(clientPlugin.pluginName);
636
+ const pluginOptions = driver.getPlugin(clientPlugin.pluginName)?.options ?? {};
637
+ const { exclude, include, override } = pluginOptions;
638
+ const operationOptions = Boolean(exclude?.length || include?.length || override?.length) && resolver.default ? resolver.default.options(node, {
639
+ options: pluginOptions,
640
+ exclude,
641
+ include,
642
+ override
643
+ }) : pluginOptions;
644
+ if (!operationOptions) return null;
645
+ const file = resolver.file({
646
+ ...operationFileEntry(node, node.operationId),
647
+ root,
648
+ output: operationOptions.output ?? output,
649
+ group: operationOptions.group ?? void 0
650
+ });
651
+ const { importPath } = operationOptions;
652
+ const name = resolver.name(node.operationId);
653
+ return {
654
+ name: resolver.resolveName({
655
+ key: operationKey(node),
656
+ name
657
+ }),
658
+ path: file.path,
659
+ clientPath: importPath === void 0 ? node_path.default.resolve(root, ".kubb/client.ts") : resolveImportPath({
660
+ importPath,
661
+ operationFile: file.path
662
+ }),
663
+ clientPathIsFile: importPath === void 0 || isRelativeImport(importPath),
664
+ returnType: operationOptions.returnType ?? "full",
665
+ typedHeaders: importPath === void 0
666
+ };
667
+ });
668
+ }
669
+ // ../../internals/client/src/resolveOperationTypes.ts
670
+ const pluginZodName = "plugin-zod";
671
+ function getResponseHeadersEntries({ node, types }) {
672
+ const resolve = types.response.headers;
673
+ if (!resolve) return [];
674
+ return node.responses.filter((response) => response.headers?.length).map((response) => [response.statusCode, resolve.call(types.response, node, response.statusCode)]);
475
675
  }
476
- // ../../internals/utils/src/strings.ts
477
676
  /**
478
- * Renders a dotted path or string array as an optional-chaining accessor expression rooted at
479
- * `accessor`. Returns `null` for an empty path.
480
- *
481
- * @example
482
- * ```ts
483
- * getNestedAccessor('pagination.next.id', 'lastPage')
484
- * // "lastPage?.['pagination']?.['next']?.['id']"
485
- * ```
677
+ * The headers type argument of `RequestResult`, such as `{ '200': LoginUserStatus200Headers }`, or `null` when no response declares headers.
486
678
  */
487
- function getNestedAccessor(param, accessor) {
488
- const parts = Array.isArray(param) ? param : param.split(".");
489
- if (parts.length === 0 || parts.length === 1 && parts[0] === "") return null;
490
- return `${accessor}?.['${`${parts.join("']?.['")}']`}`;
679
+ function buildResponseHeadersType({ node, types }) {
680
+ const entries = getResponseHeadersEntries({
681
+ node,
682
+ types
683
+ }).map(([statusCode, name]) => `'${statusCode}': ${name}`);
684
+ return entries.length ? `{ ${entries.join("; ")} }` : null;
491
685
  }
492
- // ../../internals/shared/src/resolver.ts
493
686
  /**
494
- * The shared top-level `name` of the operation plugins, computed once per operation name and build.
687
+ * A runtime result type, such as `RequestResult`, in its `WithHeaders` form when `headers` is set.
495
688
  */
496
- function resolveOperationName(name) {
497
- return this.memo(`operation:${name}`, () => ensureValidVarName((0, _kubb_kit.camelCase)(name)));
689
+ function resultTypeName(name, headers) {
690
+ return headers ? `${name}WithHeaders` : name;
498
691
  }
499
692
  /**
500
- * Builds the allocation key for a declaration an operation owns. `scope` names which declaration
501
- * it is, so two of them never share an allocation even when a custom resolver gives both the same
502
- * name. Leave `scope` empty for the operation's own declaration.
503
- *
504
- * @example
505
- * ```ts
506
- * resolver.resolveName({ key: operationKey(node, 'response', 'status', 404), name })
507
- * ```
693
+ * A runtime result type with its arguments, such as `RequestResultWithHeaders<Responses, Headers, ThrowOnError>`.
508
694
  */
509
- function operationKey(node, ...scope) {
510
- return [
511
- "operation",
512
- node.method,
513
- node.path,
514
- ...scope.map(String)
515
- ];
695
+ function buildResultTypeRef(name, responses, headers, rest = []) {
696
+ return `${resultTypeName(name, headers !== null)}<${[
697
+ responses,
698
+ headers,
699
+ ...rest
700
+ ].filter(Boolean).join(", ")}>`;
516
701
  }
517
- // ../../internals/shared/src/group.ts
518
702
  /**
519
- * Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the
520
- * shared default naming so every plugin groups output consistently:
521
- *
522
- * - `path` groups use the second path segment (`/pet/findByStatus` → `pet`).
523
- * - other groups use the camelCased group (`pet store` → `petStore`).
524
- *
525
- * A user-provided `group.name` always wins over the default namer, so callers stay in
526
- * control of their output folders. Returns `null` when grouping is disabled, matching the
527
- * per-plugin convention.
528
- *
529
- * @param group - The user-supplied group option, or `undefined` to disable grouping.
530
- *
531
- * @example
532
- * ```ts
533
- * createGroupConfig(group) // shared across every plugin
534
- * ```
703
+ * The names of the headers types `buildResponseHeadersType` references, for the file's imports.
535
704
  */
536
- function createGroupConfig(group) {
537
- if (!group) return null;
538
- const defaultName = (ctx) => {
539
- if (group.type === "path") return `${ctx.group.split("/")[1]}`;
540
- return (0, _kubb_kit.camelCase)(ctx.group);
541
- };
542
- return {
543
- ...group,
544
- name: group.name ? group.name : defaultName
545
- };
705
+ function getResponseHeadersTypeNames({ node, types }) {
706
+ return getResponseHeadersEntries({
707
+ node,
708
+ types
709
+ }).map(([, name]) => name);
546
710
  }
547
- // kubb-extension.json
548
- var compatibility = {
549
- "kubb": ">=5.16.0",
550
- "node": ">=22.22"
551
- };
552
- // package.json
553
- var version = "5.10.0-canary.20261109T201601";
554
- // ../../internals/client/src/resolveOperationTypes.ts
555
711
  /**
556
712
  * A `plugin-ts` shaped resolver whose operation type names point at the types `pluginZod({ inferred })`
557
713
  * exports next to each schema, so code written against `plugin-ts` names picks up the zod types.
@@ -574,6 +730,7 @@ function toZodTypeResolver(resolver) {
574
730
  status: (node, statusCode) => type(resolver.response.status(node, statusCode)),
575
731
  response: (node) => type(resolver.response.response(node)),
576
732
  responses: (node) => type(resolver.response.responses(node)),
733
+ headers: (node, statusCode) => type(resolver.response.headers(node, statusCode)),
577
734
  options: (node) => resolver.response.options(node)
578
735
  }
579
736
  };
@@ -594,7 +751,7 @@ function toZodTypeResolver(resolver) {
594
751
  function resolveOperationTypes(driver, pluginName) {
595
752
  return driver.memo(`operationTypes:${pluginName}`, () => {
596
753
  const pluginTs = driver.getPlugin(_kubb_plugin_ts.pluginTsName);
597
- const pluginZod = driver.getPlugin(_kubb_plugin_zod.pluginZodName);
754
+ const pluginZod = driver.getPlugin(pluginZodName);
598
755
  if (pluginTs && pluginZod?.options?.inferred !== "codec") {
599
756
  const resolver = driver.getResolver(_kubb_plugin_ts.pluginTsName);
600
757
  return {
@@ -612,7 +769,7 @@ function resolveOperationTypes(driver, pluginName) {
612
769
  location: { kind: "config" },
613
770
  plugin: pluginName
614
771
  });
615
- const resolver = toZodTypeResolver(driver.getResolver(_kubb_plugin_zod.pluginZodName));
772
+ const resolver = toZodTypeResolver(driver.getResolver(pluginZodName));
616
773
  return {
617
774
  response: resolver.response,
618
775
  resolver,
@@ -621,179 +778,6 @@ function resolveOperationTypes(driver, pluginName) {
621
778
  };
622
779
  });
623
780
  }
624
- // ../../internals/client/src/resolveClient.ts
625
- /**
626
- * Resolves which client plugin a consumer (react-query, vue-query, swr, mcp) should call for an
627
- * operation, shared so the selection rules and diagnostics stay in one place.
628
- *
629
- * Every client runtime lives in a dedicated client plugin, so a consumer always calls a registered
630
- * contract client plugin (plugin-fetch, plugin-axios, or plugin-client) and never emits its own
631
- * inline client:
632
- *
633
- * - `contract` — a registered contract client plugin owns the `<op>` functions and the consumer
634
- * imports and calls them.
635
- * - `error` — no client plugin is registered, several are registered without a selector, the
636
- * requested one is missing, or `client` is not a known selector.
637
- *
638
- * The `client` string selects explicitly (`'fetch'` / `'axios'` / `'client'`); when it is unset a
639
- * lone registered contract client plugin is picked up automatically.
640
- */
641
- const pluginFetchName = "plugin-fetch";
642
- const pluginAxiosName = "plugin-axios";
643
- const pluginClientName = "plugin-client";
644
- const selectorToPlugin = {
645
- fetch: pluginFetchName,
646
- axios: pluginAxiosName,
647
- client: pluginClientName
648
- };
649
- const contractPlugins = [
650
- pluginFetchName,
651
- pluginAxiosName,
652
- pluginClientName
653
- ];
654
- /**
655
- * Applies the `client` resolution rules. See the module comment for the strategy shape.
656
- *
657
- * @example
658
- * ```ts
659
- * resolveClient({ client: 'fetch', pluginNames: ['plugin-ts', 'plugin-fetch'] })
660
- * // { kind: 'contract', pluginName: 'plugin-fetch' }
661
- * ```
662
- *
663
- * @example
664
- * ```ts
665
- * resolveClient({ client: undefined, pluginNames: ['plugin-ts'] })
666
- * // { kind: 'error', code: 'KUBB_MISSING_DEPENDENCY', message: 'No client plugin is registered.', help: 'Add …' }
667
- * ```
668
- */
669
- function resolveClient(options) {
670
- const { client, pluginNames } = options;
671
- const has = (name) => pluginNames.includes(name);
672
- if (client === "fetch" || client === "axios" || client === "client") {
673
- const pluginName = selectorToPlugin[client];
674
- if (!has(pluginName)) return {
675
- kind: "error",
676
- code: _kubb_kit.Diagnostics.code.missingDependency,
677
- message: `\`client: '${client}'\` is set but \`@kubb/plugin-${client}\` is not registered in \`plugins\`.`,
678
- help: `Add \`@kubb/plugin-${client}\` to \`plugins\`, or drop \`client\` to use a different client plugin.`
679
- };
680
- return {
681
- kind: "contract",
682
- pluginName
683
- };
684
- }
685
- if (client !== void 0) return {
686
- kind: "error",
687
- code: _kubb_kit.Diagnostics.code.invalidPluginOptions,
688
- message: `Option \`client\` is ${typeof client === "string" ? `'${client}'` : String(client)}, but it must be one of 'fetch', 'axios', 'client'.`,
689
- help: "Set `client` to one of those values, or drop it to use the registered client plugin."
690
- };
691
- const registered = contractPlugins.filter(has);
692
- if (registered.length === 1) return {
693
- kind: "contract",
694
- pluginName: registered[0]
695
- };
696
- if (registered.length > 1) return {
697
- kind: "error",
698
- code: _kubb_kit.Diagnostics.code.invalidPluginOptions,
699
- message: `Multiple client plugins are registered (${registered.map((name) => `\`@kubb/${name}\``).join(", ")}) and \`client\` is not set.`,
700
- help: "Set `client: 'fetch' | 'axios' | 'client'` to choose which client the hooks call, or register a single client plugin."
701
- };
702
- return {
703
- kind: "error",
704
- code: _kubb_kit.Diagnostics.code.missingDependency,
705
- message: "No client plugin is registered.",
706
- help: "Add `@kubb/plugin-fetch`, `@kubb/plugin-axios`, or `@kubb/plugin-client` to `plugins` so the generated code has an HTTP client to call."
707
- };
708
- }
709
- /**
710
- * Resolves the contract client during a consumer plugin's setup hook.
711
- * It extracts the plugin names from the raw `plugins` config and applies {@link resolveClient}.
712
- * On a misconfiguration it throws a config diagnostic tagged with `plugin`, so every consumer
713
- * fails fast with the same message.
714
- */
715
- function resolveContractClient(options) {
716
- const { plugin, client, plugins = [] } = options;
717
- const resolved = resolveClient({
718
- client,
719
- pluginNames: plugins.map((plugin) => plugin.name).filter((name) => Boolean(name))
720
- });
721
- if (resolved.kind === "error") {
722
- const { code, message, help } = resolved;
723
- throw new _kubb_kit.Diagnostics.Error({
724
- code,
725
- severity: "error",
726
- message,
727
- help,
728
- location: { kind: "config" },
729
- plugin
730
- });
731
- }
732
- return resolved;
733
- }
734
- // ../../internals/client/src/resolveClientOperation.ts
735
- function isRelativeImport(importPath) {
736
- return importPath.startsWith(".");
737
- }
738
- function resolveImportPath(options) {
739
- const { importPath, operationFile } = options;
740
- return isRelativeImport(importPath) ? node_path.default.resolve(node_path.default.dirname(operationFile), importPath) : importPath;
741
- }
742
- /**
743
- * Resolves the contract client `<op>` a consumer (query hook, MCP handler) imports, by looking up
744
- * the registered contract client plugin's resolver and output. Works for any contract client plugin
745
- * (plugin-fetch, plugin-axios, or plugin-client). Returns `null` when no contract plugin is in play (the inline
746
- * path), or when the client plugin's `exclude` / `include` leaves this operation out, since it then
747
- * emits no `<op>` to import. plugin-fetch / plugin-axios inject `.kubb/client.ts` at the global
748
- * output root, the same path consumers read `RequestConfig` / `ResponseErrorConfig` from.
749
- * With plugin-client they come from the user's `importPath` module instead.
750
- *
751
- * The result is cached in `memo` (the build's `ctx.memo`) under the client plugin's name and the operation,
752
- * so several dependents reading the same client plugin for one operation in a single pass
753
- * (react-query's query/mutation/infinite generators, vue-query, swr, the MCP handler, ...) share
754
- * one computed result instead of each re-deriving the name and path.
755
- *
756
- * `returnType`, `output`, and `group` are the client plugin's options for this operation, after its
757
- * `override` entries, the same resolution its own generator sees. A dependent's generated call body
758
- * and import path therefore match the `<op>` actually emitted, even when an `override` changes it.
759
- */
760
- function resolveClientOperation(options) {
761
- const { clientPlugin, driver, node, root, output, memo } = options;
762
- if (!clientPlugin) return null;
763
- return memo(`${clientPlugin.pluginName}:clientOperation:${node.operationId}`, () => {
764
- const resolver = driver.getResolver(clientPlugin.pluginName);
765
- const pluginOptions = driver.getPlugin(clientPlugin.pluginName)?.options ?? {};
766
- const { exclude, include, override } = pluginOptions;
767
- const operationOptions = Boolean(exclude?.length || include?.length || override?.length) && resolver.default ? resolver.default.options(node, {
768
- options: pluginOptions,
769
- exclude,
770
- include,
771
- override
772
- }) : pluginOptions;
773
- if (!operationOptions) return null;
774
- const file = resolver.file({
775
- ...operationFileEntry(node, node.operationId),
776
- root,
777
- output: operationOptions.output ?? output,
778
- group: operationOptions.group ?? void 0
779
- });
780
- const { importPath } = operationOptions;
781
- const name = resolver.name(node.operationId);
782
- return {
783
- name: resolver.resolveName({
784
- key: operationKey(node),
785
- name
786
- }),
787
- path: file.path,
788
- clientPath: importPath === void 0 ? node_path.default.resolve(root, ".kubb/client.ts") : resolveImportPath({
789
- importPath,
790
- operationFile: file.path
791
- }),
792
- clientPathIsFile: importPath === void 0 || isRelativeImport(importPath),
793
- returnType: operationOptions.returnType ?? "full"
794
- };
795
- });
796
- }
797
781
  // ../../internals/tanstack-query/src/components/HookFile.tsx
798
782
  /**
799
783
  * Resolves what every TanStack hook file shares: its file, the operation types file and names (`@kubb/plugin-ts`, or
@@ -812,14 +796,18 @@ function resolveHookFile(node, ctx, options) {
812
796
  });
813
797
  const types = resolveOperationTypes(ctx.driver, resolver.pluginName);
814
798
  const tsResolver = types.resolver;
799
+ const headerTypeNames = returnType === "data" || !contractOp.typedHeaders ? [] : getResponseHeadersTypeNames({
800
+ node,
801
+ types: tsResolver
802
+ });
815
803
  const file = resolver.file({
816
804
  ...operationFileEntry(node, name),
817
805
  root,
818
806
  output,
819
807
  group: group ?? void 0
820
808
  });
821
- const fileTs = resolveDependencyOperationFile({
822
- memo: ctx.memo,
809
+ const fileTs = resolveOperationFile({
810
+ ctx,
823
811
  node,
824
812
  resolver: tsResolver,
825
813
  root,
@@ -829,6 +817,7 @@ function resolveHookFile(node, ctx, options) {
829
817
  const importedTypeNames = [
830
818
  tsResolver.response.options(node),
831
819
  tsResolver.response.responses(node),
820
+ ...headerTypeNames,
832
821
  ...extraTypeNames,
833
822
  ...resolveOperationTypeNames(node, tsResolver, {
834
823
  exclude: [keyTypeName, returnType !== "data" ? tsResolver.response.response(node) : null].filter((name) => Boolean(name)),
@@ -846,6 +835,7 @@ function resolveHookFile(node, ctx, options) {
846
835
  tsResolver,
847
836
  contractOp,
848
837
  importedTypeNames,
838
+ resultTypeName: headerTypeNames.length ? "RequestResultWithHeaders" : "RequestResult",
849
839
  returnType,
850
840
  banner: resolver.default.banner(ctx.meta, {
851
841
  output,
@@ -863,7 +853,7 @@ function resolveHookFile(node, ctx, options) {
863
853
  * The `<File>` shell shared by the TanStack hook generators; renders `children` after the imports.
864
854
  */
865
855
  function HookFile({ hook, imports, children }) {
866
- const { file, fileTs, contractOp, importedTypeNames, banner, footer } = hook;
856
+ const { file, fileTs, contractOp, importedTypeNames, resultTypeName, banner, footer } = hook;
867
857
  return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx.File, {
868
858
  baseName: file.baseName,
869
859
  path: file.path,
@@ -880,7 +870,7 @@ function HookFile({ hook, imports, children }) {
880
870
  name: [
881
871
  "RequestConfig",
882
872
  "ResponseErrorConfig",
883
- "RequestResult"
873
+ resultTypeName
884
874
  ],
885
875
  root: contractOp.clientPathIsFile ? file.path : void 0,
886
876
  path: contractOp.clientPath,
@@ -956,8 +946,8 @@ function buildGroupedRequestParam(node, options) {
956
946
  /**
957
947
  * Builds the shared `({ path, query, body, headers, cookies }, config = {})` parameter list for a
958
948
  * TanStack query-options function. The leading parameter mirrors the client signature, and the
959
- * trailing `config` is a partial `RequestConfig` minus the grouped data-shape keys, which are passed
960
- * explicitly. Framework plugins wrap the result when needed, for example vue-query applies `MaybeRefOrGetter`.
949
+ * trailing `config` is the client's `Options` minus the request groups and `throwOnError`, which the
950
+ * hook passes itself. Framework plugins wrap the result when needed, for example vue-query applies `MaybeRefOrGetter`.
961
951
  */
962
952
  function buildQueryOptionsParams(node, options) {
963
953
  const { resolver, memberTypeWrapper } = options;
@@ -967,7 +957,7 @@ function buildQueryOptionsParams(node, options) {
967
957
  });
968
958
  const configParam = (0, _kubb_plugin_ts.createFunctionParameter)({
969
959
  name: "config",
970
- type: buildClientOptionType(node),
960
+ type: buildClientOptionType(),
971
961
  default: "{}"
972
962
  });
973
963
  return (0, _kubb_plugin_ts.createFunctionParameters)({ params: [groupedParam, configParam].filter((param) => param !== null) });
@@ -979,26 +969,30 @@ function buildQueryOptionsParams(node, options) {
979
969
  * can't flip the query's error semantics. Queries thread the TanStack `signal`; mutations omit it.
980
970
  *
981
971
  * When `unwrapName` is set, each request group is passed as an explicit member unwrapped through it,
982
- * used by vue-query to resolve refs and getters with `toValue(...)` at call time.
972
+ * used by vue-query to resolve refs and getters with `toValue(...)` at call time. `pageParam` names the
973
+ * query parameter an infinite query sets from TanStack's `pageParam`.
983
974
  *
984
975
  * @example
985
976
  * ```ts
986
977
  * buildClientCall(node, { clientName: 'getPetById', signal: true })
987
- * // getPetById({ path, ...config, signal: config.signal ?? signal, throwOnError: true })
978
+ * // getPetById({ ...config, path, signal: config.signal ?? signal, throwOnError: true })
988
979
  * ```
989
980
  */
990
981
  function buildClientCall(node, options) {
991
- const { clientName, signal = false, unwrapName, withContentType = false, returnType = "full" } = options;
982
+ const { clientName, signal = false, unwrapName, withContentType = false, pageParam } = options;
992
983
  const { groups } = getRequestGroupOptionality(node);
993
984
  const names = requestGroupOrder.filter((key) => groups[key]);
994
- const args = [
985
+ const member = (name) => {
986
+ const value = unwrapName ? unwrapName(name) : name;
987
+ if (name === "query" && pageParam) return `query: { ...${value}, ${JSON.stringify(pageParam)}: pageParam }`;
988
+ return unwrapName ? `${name}: ${value}` : name;
989
+ };
990
+ return `${clientName}({ ${[
995
991
  "...config",
996
- ...withContentType && hasRequestContentTypeChoice(node) ? ["...variables"] : names.map((name) => unwrapName ? `${name}: ${unwrapName(name)}` : name),
992
+ ...withContentType && hasRequestContentTypeChoice(node) ? ["...variables"] : names.map(member),
997
993
  signal ? "signal: config.signal ?? signal" : null,
998
994
  "throwOnError: true"
999
- ].filter((part) => part !== null);
1000
- if (withContentType && hasRequestContentTypeChoice(node)) return `${clientName}(${castToClientOptions(`{ ${args.join(", ")} }`, clientName, returnType)})`;
1001
- return `${clientName}({ ${args.join(", ")} })`;
995
+ ].filter((part) => part !== null).join(", ")} })`;
1002
996
  }
1003
997
  /**
1004
998
  * Builds the query/mutation body that resolves a `buildClientCall` expression down to the bare
@@ -1021,19 +1015,28 @@ function buildCallResultBody(call, options = {}) {
1021
1015
  if (clientReturnType === "plain") return `return (await ${call}).data`;
1022
1016
  return `return ${call}.unwrap()`;
1023
1017
  }
1018
+ function buildResultType(node, resolver, typedHeaders) {
1019
+ const headers = typedHeaders ? buildResponseHeadersType({
1020
+ node,
1021
+ types: resolver
1022
+ }) : null;
1023
+ return buildResultTypeRef("RequestResult", resolver.response.responses(node), headers, ["true"]);
1024
+ }
1024
1025
  /**
1025
1026
  * Builds the `TData` / `TError` type expressions shared by every generated hook, joining the resolved
1026
1027
  * success responses into `TData` and wrapping the error responses in `ResponseErrorConfig<...>`.
1027
- * With `returnType` `'full'`, `TData` is the client's `RequestResult` over the operation's responses record.
1028
+ * With `returnType` `'full'`, `TData` is the client's `RequestResult` over the operation's responses record, with the
1029
+ * response headers the operation declares.
1028
1030
  */
1029
1031
  function buildResponseTypes(node, resolver, options = {}) {
1030
- const { returnType = "data" } = options;
1031
- return resolver.memo(`responseTypes:${returnType}:${node.method}\0${node.path}`, () => {
1032
+ const { returnType = "data", typedHeaders = true } = options;
1033
+ return resolver.memo(`responseTypes:${returnType}:${typedHeaders}:${node.method}\0${node.path}`, () => {
1032
1034
  const successNames = resolveSuccessNames(node, resolver);
1033
- const responseName = successNames.length > 0 ? successNames.join(" | ") : resolver.response.response(node);
1035
+ const bodyName = successNames.length > 0 ? successNames.join(" | ") : resolver.response.response(node);
1036
+ const responseName = hasStreamVariant(node) ? `${bodyName} | ReadableStream<Uint8Array>` : bodyName;
1034
1037
  const errorNames = resolveErrorNames(node, resolver);
1035
1038
  return {
1036
- TData: returnType !== "data" ? `RequestResult<${resolver.response.responses(node)}, true>` : responseName,
1039
+ TData: returnType === "data" ? responseName : buildResultType(node, resolver, typedHeaders),
1037
1040
  TError: `ResponseErrorConfig<${errorNames.length > 0 ? errorNames.join(" | ") : "Error"}>`
1038
1041
  };
1039
1042
  });
@@ -1052,7 +1055,7 @@ function resolveFallbackPageParamType(initialPageParam) {
1052
1055
  * so callers can reuse it when rewriting the paginated request.
1053
1056
  */
1054
1057
  function resolvePageParamType(node, { resolver, initialPageParam, queryParam }) {
1055
- const firstQueryParam = getOperationParameters(node).query[0];
1058
+ const firstQueryParam = _kubb_kit.ast.http.groupParameters(node).query[0];
1056
1059
  const groupName = firstQueryParam ? resolver.param.query(node, firstQueryParam) : null;
1057
1060
  const queryParamsTypeName = groupName !== (firstQueryParam ? resolver.param.name(node, firstQueryParam) : null) ? groupName : null;
1058
1061
  const queryParamType = queryParam && queryParamsTypeName ? `${queryParamsTypeName}['${queryParam}']` : null;
@@ -1155,7 +1158,7 @@ function resolveInfiniteConfig(infinite) {
1155
1158
  */
1156
1159
  function matchesInfinite(node, infinite) {
1157
1160
  if (!infinite.queryParam) return false;
1158
- return getOperationParameters(node).query.some((param) => param.name.replace(/\?$/, "") === infinite.queryParam);
1161
+ return _kubb_kit.ast.http.groupParameters(node).query.some((param) => param.name.replace(/\?$/, "") === infinite.queryParam);
1159
1162
  }
1160
1163
  /**
1161
1164
  * Warning for an infinite hook that falls back to the built-in page params on a response that
@@ -1163,8 +1166,8 @@ function matchesInfinite(node, infinite) {
1163
1166
  */
1164
1167
  function getDefaultPageParamsWarning(node, infinite) {
1165
1168
  if (!(infinite.getNextPageParam == null && infinite.getPreviousPageParam == null && infinite.nextParam == null && infinite.previousParam == null && !infinite.cursorParam)) return null;
1166
- const content = getPrimarySuccessResponse(node)?.content;
1167
- let resolved = (content?.find((item) => item.contentType?.includes("json")) ?? content?.[0])?.schema;
1169
+ const content = _kubb_kit.ast.http.responses.findPrimary(node)?.content;
1170
+ let resolved = (content?.find((item) => _kubb_kit.ast.mediaType.isJson(item)) ?? content?.[0])?.schema;
1168
1171
  while (resolved?.type === "ref" || resolved?.type === "intersection" && resolved.members?.length === 1) resolved = resolved.type === "ref" ? resolved.schema : resolved.members?.[0];
1169
1172
  if (!resolved || resolved.type === "array") return null;
1170
1173
  return `${node.operationId}: the default infinite page params expect an array response and never end for this one. Set \`infinite.getNextPageParam\` (or \`nextParam\`) to read the next page from the response.`;
@@ -1247,9 +1250,15 @@ function buildHookParams(node, options) {
1247
1250
  }
1248
1251
  /**
1249
1252
  * The `TRequest` type argument of a mutation hook: the options type when the operation takes a request, else `undefined`.
1253
+ * When the variables carry the request media type and the response has several, `contentType` can pick the
1254
+ * response one too, as `{ request, response }`.
1250
1255
  */
1251
1256
  function resolveMutationRequestType(node, resolver) {
1252
- return buildGroupedRequestParam(node, { resolver }) ? resolver.response.options(node) : "undefined";
1257
+ if (!buildGroupedRequestParam(node, { resolver })) return "undefined";
1258
+ const optionsName = resolver.response.options(node);
1259
+ const response = getResponseContentTypeInfo(node);
1260
+ if (!hasRequestContentTypeChoice(node) || !response.isMultipleContentTypes) return optionsName;
1261
+ return `${/^[\w$]+$/.test(optionsName) ? optionsName : `(${optionsName})`} & { contentType?: string | { response?: ${response.contentTypeUnion} } }`;
1253
1262
  }
1254
1263
  /**
1255
1264
  * Builds the object literal that unwraps each request group's getter before it reaches `queryKey`/`queryOptions`; `null` without a request group.
@@ -1263,8 +1272,11 @@ function buildResolvedRequestParams(node) {
1263
1272
  // ../../internals/tanstack-query/src/components/InfiniteQueryOptions.tsx
1264
1273
  const declarationPrinter$6 = (0, _kubb_plugin_ts.functionPrinter)({ mode: "declaration" });
1265
1274
  const callPrinter$3 = (0, _kubb_plugin_ts.functionPrinter)({ mode: "call" });
1266
- function InfiniteQueryOptions({ name, clientName, initialPageParam, hasExplicitInitialPageParam, cursorParam, nextParam, previousParam, getNextPageParam, getPreviousPageParam, node, tsResolver, queryParam, queryKeyName, queryKeyType = "typeof queryKey", memberTypeWrapper, unwrapName, clientReturnType, returnType }) {
1267
- const { TData: queryFnDataType, TError: errorType } = buildResponseTypes(node, tsResolver, { returnType });
1275
+ function InfiniteQueryOptions({ name, clientName, initialPageParam, hasExplicitInitialPageParam, cursorParam, nextParam, previousParam, getNextPageParam, getPreviousPageParam, node, tsResolver, queryParam, queryKeyName, queryKeyType = "typeof queryKey", memberTypeWrapper, unwrapName, clientReturnType, returnType, typedHeaders }) {
1276
+ const { TData: queryFnDataType, TError: errorType } = buildResponseTypes(node, tsResolver, {
1277
+ returnType,
1278
+ typedHeaders
1279
+ });
1268
1280
  const dataSuffix = returnType === "data" ? "" : ".data";
1269
1281
  const { queryParamsTypeName, pageParamType } = resolvePageParamType(node, {
1270
1282
  resolver: tsResolver,
@@ -1283,10 +1295,12 @@ function InfiniteQueryOptions({ name, clientName, initialPageParam, hasExplicitI
1283
1295
  memberTypeWrapper
1284
1296
  });
1285
1297
  const paramsSignature = declarationPrinter$6.print(paramsNode) ?? "";
1298
+ const pageParam = queryParam && queryParamsTypeName ? queryParam : void 0;
1286
1299
  const queryFnBody = buildCallResultBody(buildClientCall(node, {
1287
1300
  clientName,
1288
1301
  signal: true,
1289
- unwrapName
1302
+ unwrapName,
1303
+ pageParam
1290
1304
  }), {
1291
1305
  clientReturnType,
1292
1306
  returnType
@@ -1313,12 +1327,7 @@ function InfiniteQueryOptions({ name, clientName, initialPageParam, hasExplicitI
1313
1327
  getNextPageParamExpr,
1314
1328
  getPreviousPageParamExpr
1315
1329
  ].filter(Boolean);
1316
- const infiniteOverrideParams = queryParam && queryParamsTypeName ? `query = {
1317
- ...(query ?? {}),
1318
- ['${queryParam}']: pageParam as unknown as ${queryParamsTypeName}['${queryParam}'],
1319
- } as ${queryParamsTypeName}` : "";
1320
- const queryFnArgs = infiniteOverrideParams ? "{ signal, pageParam }" : "{ signal }";
1321
- const queryFnStatements = infiniteOverrideParams ? `${infiniteOverrideParams}\n ${queryFnBody}` : queryFnBody;
1330
+ const queryFnArgs = pageParam ? "{ signal, pageParam }" : "{ signal }";
1322
1331
  return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
1323
1332
  name,
1324
1333
  isExportable: true,
@@ -1332,7 +1341,7 @@ const queryKey = ${queryKeyName}(${queryKeyParamsCall})
1332
1341
  return infiniteQueryOptions<${queryFnDataType}, ${errorType}, InfiniteData<${queryFnDataType}>, ${queryKeyType}, ${pageParamType}>({
1333
1342
  queryKey,
1334
1343
  queryFn: async (${queryFnArgs}) => {
1335
- ${queryFnStatements}
1344
+ ${queryFnBody}
1336
1345
  },
1337
1346
  ${queryOptionsArr.join(",\n ")}
1338
1347
  })
@@ -1403,7 +1412,7 @@ function MutationKey({ name, node, transformer, typeName }) {
1403
1412
  function createQueryResolver(variant = "") {
1404
1413
  return {
1405
1414
  name(node) {
1406
- const name = `use${capitalize(this.name(node.operationId))}${variant}`;
1415
+ const name = `use${_kubb_kit.casing.capitalize(this.name(node.operationId))}${variant}`;
1407
1416
  return this.resolveName({
1408
1417
  key: operationKey(node, "query", variant, "name"),
1409
1418
  name
@@ -1424,7 +1433,7 @@ function createQueryResolver(variant = "") {
1424
1433
  });
1425
1434
  },
1426
1435
  keyTypeName(node) {
1427
- const name = `${capitalize(this.name(node.operationId))}${variant}QueryKey`;
1436
+ const name = `${_kubb_kit.casing.capitalize(this.name(node.operationId))}${variant}QueryKey`;
1428
1437
  return this.resolveName({
1429
1438
  key: operationKey(node, "query", variant, "keyTypeName"),
1430
1439
  name
@@ -1445,7 +1454,7 @@ function createQueryResolver(variant = "") {
1445
1454
  function createMutationResolver() {
1446
1455
  return {
1447
1456
  name(node) {
1448
- const name = `use${capitalize(this.name(node.operationId))}`;
1457
+ const name = `use${_kubb_kit.casing.capitalize(this.name(node.operationId))}`;
1449
1458
  return this.resolveName({
1450
1459
  key: operationKey(node, "mutation", "name"),
1451
1460
  name
@@ -1474,14 +1483,14 @@ const declarationPrinter$4 = (0, _kubb_plugin_ts.functionPrinter)({ mode: "decla
1474
1483
  */
1475
1484
  const queryKeyTransformer = ({ node, variant }) => {
1476
1485
  if (!node.path) return [];
1477
- const { path, query } = getOperationParameters(node);
1486
+ const { path, query } = _kubb_kit.ast.http.groupParameters(node);
1478
1487
  const isInfinite = variant === "infiniteQuery" || variant === "suspenseInfiniteQuery";
1479
1488
  const urlFields = [`url: '${_kubb_kit.Url.toPath(node.path)}'`];
1480
1489
  if (path.length > 0) urlFields.push("params: path");
1481
1490
  if (isInfinite) urlFields.push("infinite: true");
1482
1491
  const result = [`{ ${urlFields.join(", ")} }`];
1483
1492
  if (query.length > 0) result.push("...(query ? [query] : [])");
1484
- if (node.requestBody?.content?.[0]?.schema) result.push("...(body !== undefined ? [body] : [])");
1493
+ if (_kubb_kit.ast.http.requestBody.getSchema(node)) result.push("...(body !== undefined ? [body] : [])");
1485
1494
  return result;
1486
1495
  };
1487
1496
  function QueryKey({ name, node, tsResolver, typeName, transformer, variant = "query", memberTypeWrapper, exportType }) {
@@ -1565,6 +1574,13 @@ const customHookOptionsFileGenerator = (0, _kubb_kit.defineGenerator)({
1565
1574
  const relativeToOutput = node_path.default.relative(outputDir, file.path);
1566
1575
  if (relativeToOutput === ".." || relativeToOutput.startsWith(`..${node_path.default.sep}`) || node_path.default.isAbsolute(relativeToOutput)) return null;
1567
1576
  if (node_fs.default.existsSync(file.path)) return null;
1577
+ const hookOptionsPath = resolver.file({
1578
+ name: hookOptionsName,
1579
+ extname: ".ts",
1580
+ root,
1581
+ output,
1582
+ group: group ?? void 0
1583
+ }).path.replace(/[^/\\]+\.ts$/, `${hookOptionsName}.ts`);
1568
1584
  return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx.File, {
1569
1585
  baseName: file.baseName,
1570
1586
  path: file.path,
@@ -1581,7 +1597,8 @@ const customHookOptionsFileGenerator = (0, _kubb_kit.defineGenerator)({
1581
1597
  /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
1582
1598
  name: [hookOptionsName],
1583
1599
  root: file.path,
1584
- path: node_path.default.resolve(root, "./index.ts")
1600
+ path: hookOptionsPath,
1601
+ isTypeOnly: true
1585
1602
  }),
1586
1603
  /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx.File.Source, {
1587
1604
  name,
@@ -1645,7 +1662,7 @@ const hookOptionsGenerator = (0, _kubb_kit.defineGenerator)({
1645
1662
  const imports = [];
1646
1663
  const hookOptions = {};
1647
1664
  for (const node of nodes) {
1648
- if (!_kubb_kit.ast.isHttpOperationNode(node)) continue;
1665
+ if (!_kubb_kit.ast.http.isOperation(node)) continue;
1649
1666
  const opOverrides = resolveOperationOverrides(node, override);
1650
1667
  const nodeQuery = "query" in opOverrides ? opOverrides.query : query;
1651
1668
  const nodeMutation = "mutation" in opOverrides ? opOverrides.mutation : mutation;
@@ -1768,8 +1785,11 @@ function buildHookTypes({ node, tsResolver, infinite, suspense, TData, TError, q
1768
1785
  resultType: `${resultTypeName}<TData, ${TError}> & { queryKey: TQueryKey }`
1769
1786
  };
1770
1787
  }
1771
- function Query({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, tsResolver, customOptions, suspense, infinite, returnType }) {
1772
- const { TData, TError } = buildResponseTypes(node, tsResolver, { returnType });
1788
+ function Query({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, tsResolver, customOptions, suspense, infinite, returnType, typedHeaders }) {
1789
+ const { TData, TError } = buildResponseTypes(node, tsResolver, {
1790
+ returnType,
1791
+ typedHeaders
1792
+ });
1773
1793
  const prefix = suspense ? "UseSuspense" : "Use";
1774
1794
  const hookName = `${suspense ? "useSuspense" : "use"}${infinite ? "InfiniteQuery" : "Query"}`;
1775
1795
  const observerOptionsName = OBSERVER_OPTIONS_NAMES[infinite ? "infinite" : "plain"][suspense ? "suspense" : "standard"];
@@ -1793,7 +1813,7 @@ function Query({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, t
1793
1813
  memberTypeWrapper: maybeValueOrGetter,
1794
1814
  optionsType: `{
1795
1815
  query?: Partial<${observerOptionsType}> & { client?: QueryClient },
1796
- client?: ${buildClientOptionType(node)}
1816
+ client?: ${buildClientOptionType()}
1797
1817
  }`
1798
1818
  });
1799
1819
  const paramsSignature = declarationPrinter$3.print(paramsNode) ?? "";
@@ -1829,8 +1849,11 @@ function Query({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, t
1829
1849
  // src/components/QueryOptions.tsx
1830
1850
  const declarationPrinter$2 = (0, _kubb_plugin_ts.functionPrinter)({ mode: "declaration" });
1831
1851
  const callPrinter$2 = (0, _kubb_plugin_ts.functionPrinter)({ mode: "call" });
1832
- function QueryOptions({ name, clientName, node, tsResolver, queryKeyName, clientReturnType, returnType }) {
1833
- const { TData, TError } = buildResponseTypes(node, tsResolver, { returnType });
1852
+ function QueryOptions({ name, clientName, node, tsResolver, queryKeyName, clientReturnType, returnType, typedHeaders }) {
1853
+ const { TData, TError } = buildResponseTypes(node, tsResolver, {
1854
+ returnType,
1855
+ typedHeaders
1856
+ });
1834
1857
  const queryKeyParamsNode = buildQueryKeyParams(node, { resolver: tsResolver });
1835
1858
  const queryKeyParamsCall = callPrinter$2.print(queryKeyParamsNode) ?? "";
1836
1859
  const paramsNode = buildQueryOptionsParams(node, { resolver: tsResolver });
@@ -1883,7 +1906,7 @@ function createQueryGenerator({ name, variant }) {
1883
1906
  renderer: _kubb_renderer_jsx.jsxRenderer,
1884
1907
  match(node, ctx) {
1885
1908
  const operationNode = node;
1886
- if (!_kubb_kit.ast.isHttpOperationNode(operationNode)) return false;
1909
+ if (!_kubb_kit.ast.http.isOperation(operationNode)) return false;
1887
1910
  const { query, mutation, infinite: infiniteConfig, suspense: suspenseConfig, hooks } = ctx.options;
1888
1911
  const { isQuery, isMutation } = classifyOperation(operationNode, {
1889
1912
  query,
@@ -1898,7 +1921,7 @@ function createQueryGenerator({ name, variant }) {
1898
1921
  return !!infiniteOptions && matchesInfinite(operationNode, infiniteOptions);
1899
1922
  },
1900
1923
  operation(node, ctx) {
1901
- if (!_kubb_kit.ast.isHttpOperationNode(node)) return null;
1924
+ if (!_kubb_kit.ast.http.isOperation(node)) return null;
1902
1925
  const { driver, resolver, root } = ctx;
1903
1926
  const { output, query, infinite: infiniteConfig, client, group, customOptions, hooks } = ctx.options;
1904
1927
  const infiniteOptions = infinite && infiniteConfig && typeof infiniteConfig === "object" ? infiniteConfig : null;
@@ -1976,7 +1999,8 @@ function createQueryGenerator({ name, variant }) {
1976
1999
  hasExplicitInitialPageParam: infiniteOptions.hasExplicitInitialPageParam,
1977
2000
  queryParam: infiniteOptions.queryParam,
1978
2001
  clientReturnType: contractOp.returnType,
1979
- returnType: hook.returnType
2002
+ returnType: hook.returnType,
2003
+ typedHeaders: hook.contractOp.typedHeaders
1980
2004
  })
1981
2005
  ] }) : /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
1982
2006
  name: ["queryOptions"],
@@ -1988,7 +2012,8 @@ function createQueryGenerator({ name, variant }) {
1988
2012
  node,
1989
2013
  tsResolver: hook.tsResolver,
1990
2014
  clientReturnType: contractOp.returnType,
1991
- returnType: hook.returnType
2015
+ returnType: hook.returnType,
2016
+ typedHeaders: hook.contractOp.typedHeaders
1992
2017
  })] }),
1993
2018
  (variant !== "query" || query && hooks) && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [
1994
2019
  /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
@@ -2013,6 +2038,7 @@ function createQueryGenerator({ name, variant }) {
2013
2038
  tsResolver: hook.tsResolver,
2014
2039
  customOptions,
2015
2040
  returnType: hook.returnType,
2041
+ typedHeaders: hook.contractOp.typedHeaders,
2016
2042
  suspense,
2017
2043
  infinite: infiniteOptions ? {
2018
2044
  initialPageParam: infiniteOptions.initialPageParam,
@@ -2047,8 +2073,11 @@ function buildMutationConfigParamsNode(node) {
2047
2073
  default: "{}"
2048
2074
  })] });
2049
2075
  }
2050
- function MutationOptions({ name, clientName, node, tsResolver, mutationKeyName, clientReturnType, returnType }) {
2051
- const { TData, TError } = buildResponseTypes(node, tsResolver, { returnType });
2076
+ function MutationOptions({ name, clientName, node, tsResolver, mutationKeyName, clientReturnType, returnType, typedHeaders }) {
2077
+ const { TData, TError } = buildResponseTypes(node, tsResolver, {
2078
+ returnType,
2079
+ typedHeaders
2080
+ });
2052
2081
  const configParamsNode = buildMutationConfigParamsNode(node);
2053
2082
  const paramsSignature = declarationPrinter$1.print(configParamsNode) ?? "";
2054
2083
  const groupedParam = buildGroupedRequestParam(node, {
@@ -2057,13 +2086,12 @@ function MutationOptions({ name, clientName, node, tsResolver, mutationKeyName,
2057
2086
  });
2058
2087
  const hasMutationParams = groupedParam !== null;
2059
2088
  const groupedParamsNode = (0, _kubb_plugin_ts.createFunctionParameters)({ params: groupedParam ? [groupedParam] : [] });
2060
- const TRequest = hasMutationParams ? tsResolver.response.options(node) : "undefined";
2089
+ const TRequest = resolveMutationRequestType(node, tsResolver);
2061
2090
  const argBindingStr = hasMutationParams ? callPrinter$1.print(groupedParamsNode) ?? "" : "_";
2062
2091
  const mutationFnBody = buildCallResultBody(buildClientCall(node, {
2063
2092
  clientName,
2064
2093
  signal: false,
2065
- withContentType: true,
2066
- returnType: clientReturnType
2094
+ withContentType: true
2067
2095
  }), {
2068
2096
  clientReturnType,
2069
2097
  returnType
@@ -2093,8 +2121,11 @@ function MutationOptions({ name, clientName, node, tsResolver, mutationKeyName,
2093
2121
  const declarationPrinter = (0, _kubb_plugin_ts.functionPrinter)({ mode: "declaration" });
2094
2122
  const callPrinter = (0, _kubb_plugin_ts.functionPrinter)({ mode: "call" });
2095
2123
  function buildMutationParamsNode(node, options) {
2096
- const { resolver, returnType } = options;
2097
- const { TData, TError } = buildResponseTypes(node, resolver, { returnType });
2124
+ const { resolver, returnType, typedHeaders } = options;
2125
+ const { TData, TError } = buildResponseTypes(node, resolver, {
2126
+ returnType,
2127
+ typedHeaders
2128
+ });
2098
2129
  return buildHookParams(node, {
2099
2130
  resolver,
2100
2131
  withRequest: false,
@@ -2109,8 +2140,11 @@ function buildMutationParamsNode(node, options) {
2109
2140
  }`
2110
2141
  });
2111
2142
  }
2112
- function Mutation({ name, mutationOptionsName, node, tsResolver, mutationKeyName, customOptions, returnType }) {
2113
- const { TData, TError } = buildResponseTypes(node, tsResolver, { returnType });
2143
+ function Mutation({ name, mutationOptionsName, node, tsResolver, mutationKeyName, customOptions, returnType, typedHeaders }) {
2144
+ const { TData, TError } = buildResponseTypes(node, tsResolver, {
2145
+ returnType,
2146
+ typedHeaders
2147
+ });
2114
2148
  const generics = [
2115
2149
  TData,
2116
2150
  TError,
@@ -2122,7 +2156,8 @@ function Mutation({ name, mutationOptionsName, node, tsResolver, mutationKeyName
2122
2156
  const mutationOptionsParamsCall = callPrinter.print(mutationOptionsConfigNode) ?? "";
2123
2157
  const paramsNode = buildMutationParamsNode(node, {
2124
2158
  resolver: tsResolver,
2125
- returnType
2159
+ returnType,
2160
+ typedHeaders
2126
2161
  });
2127
2162
  const paramsSignature = declarationPrinter.print(paramsNode) ?? "";
2128
2163
  return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
@@ -2162,7 +2197,7 @@ const mutationGenerator = (0, _kubb_kit.defineGenerator)({
2162
2197
  renderer: _kubb_renderer_jsx.jsxRenderer,
2163
2198
  match(node, ctx) {
2164
2199
  const operationNode = node;
2165
- if (!_kubb_kit.ast.isHttpOperationNode(operationNode)) return false;
2200
+ if (!_kubb_kit.ast.http.isOperation(operationNode)) return false;
2166
2201
  const { query, mutation } = ctx.options;
2167
2202
  return classifyOperation(operationNode, {
2168
2203
  query,
@@ -2170,7 +2205,7 @@ const mutationGenerator = (0, _kubb_kit.defineGenerator)({
2170
2205
  }).isMutation;
2171
2206
  },
2172
2207
  operation(node, ctx) {
2173
- if (!_kubb_kit.ast.isHttpOperationNode(node)) return null;
2208
+ if (!_kubb_kit.ast.http.isOperation(node)) return null;
2174
2209
  const { driver, resolver, root } = ctx;
2175
2210
  const { output, mutation, client, group, customOptions, hooks } = ctx.options;
2176
2211
  const importPath = mutation ? mutation.importPath : "@tanstack/react-query";
@@ -2217,7 +2252,8 @@ const mutationGenerator = (0, _kubb_kit.defineGenerator)({
2217
2252
  node,
2218
2253
  tsResolver,
2219
2254
  clientReturnType: contractOp.returnType,
2220
- returnType: hook.returnType
2255
+ returnType: hook.returnType,
2256
+ typedHeaders: hook.contractOp.typedHeaders
2221
2257
  }),
2222
2258
  mutation && hooks && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [
2223
2259
  /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
@@ -2240,7 +2276,8 @@ const mutationGenerator = (0, _kubb_kit.defineGenerator)({
2240
2276
  node,
2241
2277
  tsResolver,
2242
2278
  customOptions,
2243
- returnType: hook.returnType
2279
+ returnType: hook.returnType,
2280
+ typedHeaders: hook.contractOp.typedHeaders
2244
2281
  })
2245
2282
  ] })
2246
2283
  ]
@@ -2399,7 +2436,7 @@ const pluginReactQuery = (0, _kubb_kit.defineExtension)({
2399
2436
  ...customOptions
2400
2437
  } : null,
2401
2438
  hooks,
2402
- group: createGroupConfig(group),
2439
+ group: group ?? null,
2403
2440
  exclude,
2404
2441
  include,
2405
2442
  override,