@kubb/plugin-react-query 5.10.0-canary.20261109T201601 → 5.10.0

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.0";
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.
343
+ *
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.
60
348
  *
61
- * @example Cache `plugin-ts`'s file for the current operation
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 }) {
@@ -1645,7 +1654,7 @@ const hookOptionsGenerator = (0, _kubb_kit.defineGenerator)({
1645
1654
  const imports = [];
1646
1655
  const hookOptions = {};
1647
1656
  for (const node of nodes) {
1648
- if (!_kubb_kit.ast.isHttpOperationNode(node)) continue;
1657
+ if (!_kubb_kit.ast.http.isOperation(node)) continue;
1649
1658
  const opOverrides = resolveOperationOverrides(node, override);
1650
1659
  const nodeQuery = "query" in opOverrides ? opOverrides.query : query;
1651
1660
  const nodeMutation = "mutation" in opOverrides ? opOverrides.mutation : mutation;
@@ -1768,8 +1777,11 @@ function buildHookTypes({ node, tsResolver, infinite, suspense, TData, TError, q
1768
1777
  resultType: `${resultTypeName}<TData, ${TError}> & { queryKey: TQueryKey }`
1769
1778
  };
1770
1779
  }
1771
- function Query({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, tsResolver, customOptions, suspense, infinite, returnType }) {
1772
- const { TData, TError } = buildResponseTypes(node, tsResolver, { returnType });
1780
+ function Query({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, tsResolver, customOptions, suspense, infinite, returnType, typedHeaders }) {
1781
+ const { TData, TError } = buildResponseTypes(node, tsResolver, {
1782
+ returnType,
1783
+ typedHeaders
1784
+ });
1773
1785
  const prefix = suspense ? "UseSuspense" : "Use";
1774
1786
  const hookName = `${suspense ? "useSuspense" : "use"}${infinite ? "InfiniteQuery" : "Query"}`;
1775
1787
  const observerOptionsName = OBSERVER_OPTIONS_NAMES[infinite ? "infinite" : "plain"][suspense ? "suspense" : "standard"];
@@ -1793,7 +1805,7 @@ function Query({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, t
1793
1805
  memberTypeWrapper: maybeValueOrGetter,
1794
1806
  optionsType: `{
1795
1807
  query?: Partial<${observerOptionsType}> & { client?: QueryClient },
1796
- client?: ${buildClientOptionType(node)}
1808
+ client?: ${buildClientOptionType()}
1797
1809
  }`
1798
1810
  });
1799
1811
  const paramsSignature = declarationPrinter$3.print(paramsNode) ?? "";
@@ -1829,8 +1841,11 @@ function Query({ name, queryKeyTypeName, queryOptionsName, queryKeyName, node, t
1829
1841
  // src/components/QueryOptions.tsx
1830
1842
  const declarationPrinter$2 = (0, _kubb_plugin_ts.functionPrinter)({ mode: "declaration" });
1831
1843
  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 });
1844
+ function QueryOptions({ name, clientName, node, tsResolver, queryKeyName, clientReturnType, returnType, typedHeaders }) {
1845
+ const { TData, TError } = buildResponseTypes(node, tsResolver, {
1846
+ returnType,
1847
+ typedHeaders
1848
+ });
1834
1849
  const queryKeyParamsNode = buildQueryKeyParams(node, { resolver: tsResolver });
1835
1850
  const queryKeyParamsCall = callPrinter$2.print(queryKeyParamsNode) ?? "";
1836
1851
  const paramsNode = buildQueryOptionsParams(node, { resolver: tsResolver });
@@ -1883,7 +1898,7 @@ function createQueryGenerator({ name, variant }) {
1883
1898
  renderer: _kubb_renderer_jsx.jsxRenderer,
1884
1899
  match(node, ctx) {
1885
1900
  const operationNode = node;
1886
- if (!_kubb_kit.ast.isHttpOperationNode(operationNode)) return false;
1901
+ if (!_kubb_kit.ast.http.isOperation(operationNode)) return false;
1887
1902
  const { query, mutation, infinite: infiniteConfig, suspense: suspenseConfig, hooks } = ctx.options;
1888
1903
  const { isQuery, isMutation } = classifyOperation(operationNode, {
1889
1904
  query,
@@ -1898,7 +1913,7 @@ function createQueryGenerator({ name, variant }) {
1898
1913
  return !!infiniteOptions && matchesInfinite(operationNode, infiniteOptions);
1899
1914
  },
1900
1915
  operation(node, ctx) {
1901
- if (!_kubb_kit.ast.isHttpOperationNode(node)) return null;
1916
+ if (!_kubb_kit.ast.http.isOperation(node)) return null;
1902
1917
  const { driver, resolver, root } = ctx;
1903
1918
  const { output, query, infinite: infiniteConfig, client, group, customOptions, hooks } = ctx.options;
1904
1919
  const infiniteOptions = infinite && infiniteConfig && typeof infiniteConfig === "object" ? infiniteConfig : null;
@@ -1976,7 +1991,8 @@ function createQueryGenerator({ name, variant }) {
1976
1991
  hasExplicitInitialPageParam: infiniteOptions.hasExplicitInitialPageParam,
1977
1992
  queryParam: infiniteOptions.queryParam,
1978
1993
  clientReturnType: contractOp.returnType,
1979
- returnType: hook.returnType
1994
+ returnType: hook.returnType,
1995
+ typedHeaders: hook.contractOp.typedHeaders
1980
1996
  })
1981
1997
  ] }) : /* @__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
1998
  name: ["queryOptions"],
@@ -1988,7 +2004,8 @@ function createQueryGenerator({ name, variant }) {
1988
2004
  node,
1989
2005
  tsResolver: hook.tsResolver,
1990
2006
  clientReturnType: contractOp.returnType,
1991
- returnType: hook.returnType
2007
+ returnType: hook.returnType,
2008
+ typedHeaders: hook.contractOp.typedHeaders
1992
2009
  })] }),
1993
2010
  (variant !== "query" || query && hooks) && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [
1994
2011
  /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
@@ -2013,6 +2030,7 @@ function createQueryGenerator({ name, variant }) {
2013
2030
  tsResolver: hook.tsResolver,
2014
2031
  customOptions,
2015
2032
  returnType: hook.returnType,
2033
+ typedHeaders: hook.contractOp.typedHeaders,
2016
2034
  suspense,
2017
2035
  infinite: infiniteOptions ? {
2018
2036
  initialPageParam: infiniteOptions.initialPageParam,
@@ -2047,8 +2065,11 @@ function buildMutationConfigParamsNode(node) {
2047
2065
  default: "{}"
2048
2066
  })] });
2049
2067
  }
2050
- function MutationOptions({ name, clientName, node, tsResolver, mutationKeyName, clientReturnType, returnType }) {
2051
- const { TData, TError } = buildResponseTypes(node, tsResolver, { returnType });
2068
+ function MutationOptions({ name, clientName, node, tsResolver, mutationKeyName, clientReturnType, returnType, typedHeaders }) {
2069
+ const { TData, TError } = buildResponseTypes(node, tsResolver, {
2070
+ returnType,
2071
+ typedHeaders
2072
+ });
2052
2073
  const configParamsNode = buildMutationConfigParamsNode(node);
2053
2074
  const paramsSignature = declarationPrinter$1.print(configParamsNode) ?? "";
2054
2075
  const groupedParam = buildGroupedRequestParam(node, {
@@ -2057,13 +2078,12 @@ function MutationOptions({ name, clientName, node, tsResolver, mutationKeyName,
2057
2078
  });
2058
2079
  const hasMutationParams = groupedParam !== null;
2059
2080
  const groupedParamsNode = (0, _kubb_plugin_ts.createFunctionParameters)({ params: groupedParam ? [groupedParam] : [] });
2060
- const TRequest = hasMutationParams ? tsResolver.response.options(node) : "undefined";
2081
+ const TRequest = resolveMutationRequestType(node, tsResolver);
2061
2082
  const argBindingStr = hasMutationParams ? callPrinter$1.print(groupedParamsNode) ?? "" : "_";
2062
2083
  const mutationFnBody = buildCallResultBody(buildClientCall(node, {
2063
2084
  clientName,
2064
2085
  signal: false,
2065
- withContentType: true,
2066
- returnType: clientReturnType
2086
+ withContentType: true
2067
2087
  }), {
2068
2088
  clientReturnType,
2069
2089
  returnType
@@ -2093,8 +2113,11 @@ function MutationOptions({ name, clientName, node, tsResolver, mutationKeyName,
2093
2113
  const declarationPrinter = (0, _kubb_plugin_ts.functionPrinter)({ mode: "declaration" });
2094
2114
  const callPrinter = (0, _kubb_plugin_ts.functionPrinter)({ mode: "call" });
2095
2115
  function buildMutationParamsNode(node, options) {
2096
- const { resolver, returnType } = options;
2097
- const { TData, TError } = buildResponseTypes(node, resolver, { returnType });
2116
+ const { resolver, returnType, typedHeaders } = options;
2117
+ const { TData, TError } = buildResponseTypes(node, resolver, {
2118
+ returnType,
2119
+ typedHeaders
2120
+ });
2098
2121
  return buildHookParams(node, {
2099
2122
  resolver,
2100
2123
  withRequest: false,
@@ -2109,8 +2132,11 @@ function buildMutationParamsNode(node, options) {
2109
2132
  }`
2110
2133
  });
2111
2134
  }
2112
- function Mutation({ name, mutationOptionsName, node, tsResolver, mutationKeyName, customOptions, returnType }) {
2113
- const { TData, TError } = buildResponseTypes(node, tsResolver, { returnType });
2135
+ function Mutation({ name, mutationOptionsName, node, tsResolver, mutationKeyName, customOptions, returnType, typedHeaders }) {
2136
+ const { TData, TError } = buildResponseTypes(node, tsResolver, {
2137
+ returnType,
2138
+ typedHeaders
2139
+ });
2114
2140
  const generics = [
2115
2141
  TData,
2116
2142
  TError,
@@ -2122,7 +2148,8 @@ function Mutation({ name, mutationOptionsName, node, tsResolver, mutationKeyName
2122
2148
  const mutationOptionsParamsCall = callPrinter.print(mutationOptionsConfigNode) ?? "";
2123
2149
  const paramsNode = buildMutationParamsNode(node, {
2124
2150
  resolver: tsResolver,
2125
- returnType
2151
+ returnType,
2152
+ typedHeaders
2126
2153
  });
2127
2154
  const paramsSignature = declarationPrinter.print(paramsNode) ?? "";
2128
2155
  return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
@@ -2162,7 +2189,7 @@ const mutationGenerator = (0, _kubb_kit.defineGenerator)({
2162
2189
  renderer: _kubb_renderer_jsx.jsxRenderer,
2163
2190
  match(node, ctx) {
2164
2191
  const operationNode = node;
2165
- if (!_kubb_kit.ast.isHttpOperationNode(operationNode)) return false;
2192
+ if (!_kubb_kit.ast.http.isOperation(operationNode)) return false;
2166
2193
  const { query, mutation } = ctx.options;
2167
2194
  return classifyOperation(operationNode, {
2168
2195
  query,
@@ -2170,7 +2197,7 @@ const mutationGenerator = (0, _kubb_kit.defineGenerator)({
2170
2197
  }).isMutation;
2171
2198
  },
2172
2199
  operation(node, ctx) {
2173
- if (!_kubb_kit.ast.isHttpOperationNode(node)) return null;
2200
+ if (!_kubb_kit.ast.http.isOperation(node)) return null;
2174
2201
  const { driver, resolver, root } = ctx;
2175
2202
  const { output, mutation, client, group, customOptions, hooks } = ctx.options;
2176
2203
  const importPath = mutation ? mutation.importPath : "@tanstack/react-query";
@@ -2217,7 +2244,8 @@ const mutationGenerator = (0, _kubb_kit.defineGenerator)({
2217
2244
  node,
2218
2245
  tsResolver,
2219
2246
  clientReturnType: contractOp.returnType,
2220
- returnType: hook.returnType
2247
+ returnType: hook.returnType,
2248
+ typedHeaders: hook.contractOp.typedHeaders
2221
2249
  }),
2222
2250
  mutation && hooks && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [
2223
2251
  /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
@@ -2240,7 +2268,8 @@ const mutationGenerator = (0, _kubb_kit.defineGenerator)({
2240
2268
  node,
2241
2269
  tsResolver,
2242
2270
  customOptions,
2243
- returnType: hook.returnType
2271
+ returnType: hook.returnType,
2272
+ typedHeaders: hook.contractOp.typedHeaders
2244
2273
  })
2245
2274
  ] })
2246
2275
  ]
@@ -2399,7 +2428,7 @@ const pluginReactQuery = (0, _kubb_kit.defineExtension)({
2399
2428
  ...customOptions
2400
2429
  } : null,
2401
2430
  hooks,
2402
- group: createGroupConfig(group),
2431
+ group: group ?? null,
2403
2432
  exclude,
2404
2433
  include,
2405
2434
  override,