@kubb/plugin-fetch 5.14.0-canary.20261109T125041 → 6.0.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
@@ -2,1734 +2,16 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- // \0rolldown/runtime.js
6
- var __create = Object.create;
7
- var __defProp = Object.defineProperty;
8
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
9
- var __getOwnPropNames = Object.getOwnPropertyNames;
10
- var __getProtoOf = Object.getPrototypeOf;
11
- var __hasOwnProp = Object.prototype.hasOwnProperty;
12
- var __copyProps = (to, from, except, desc) => {
13
- if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
14
- key = keys[i];
15
- if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
16
- get: ((k) => from[k]).bind(null, key),
17
- enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
18
- });
19
- }
20
- return to;
21
- };
22
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
23
- value: mod,
24
- enumerable: true
25
- }) : target, mod));
26
- let _kubb_kit = require("@kubb/kit");
27
- let node_path = require("node:path");
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
- let _kubb_plugin_ts = require("@kubb/plugin-ts");
32
- let _kubb_renderer_jsx_jsx_runtime = require("@kubb/renderer-jsx/jsx-runtime");
33
- let node_module = require("node:module");
34
5
  let node_url = require("node:url");
35
- // ../../internals/shared/src/operation.ts
36
- /**
37
- * Builds the `ResolverFileParams` every operation generator passes to
38
- * `resolver.file`: a file named `name`, tagged by the operation's first
39
- * tag (or `'default'`), at the operation's path. Centralizes the entry object
40
- * that was repeated at dozens of call sites across the client and query plugins.
41
- *
42
- * @example
43
- * ```ts
44
- * resolver.file(operationFileEntry(node, node.operationId), { root, output, group })
45
- * ```
46
- */
47
- function operationFileEntry(node, name, extname = ".ts") {
48
- return {
49
- name,
50
- extname,
51
- tag: node.tags[0] ?? "default",
52
- path: node.path
53
- };
54
- }
55
- /**
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.
60
- *
61
- * @example Cache `plugin-ts`'s file for the current operation
62
- * ```ts
63
- * const fileTs = resolveDependencyOperationFile({ memo: ctx.memo, node, resolver: tsResolver, root, output })
64
- * ```
65
- */
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),
70
- root,
71
- output,
72
- group: group ?? void 0
73
- }));
74
- }
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;
79
- }
80
- /**
81
- * Derives the shared `ContentTypeInfo` shape from a list of content types, tracking whether several
82
- * are present and the union, default, and form-data flags the client uses to pick one.
83
- */
84
- function buildContentTypeInfo(contentTypes) {
85
- const isMultipleContentTypes = contentTypes.length > 1;
86
- return {
87
- contentTypes,
88
- isMultipleContentTypes,
89
- contentTypeUnion: isMultipleContentTypes ? contentTypes.map((ct) => JSON.stringify(ct)).join(" | ") : "",
90
- defaultContentType: contentTypes[0] ?? "application/json",
91
- hasFormData: contentTypes.some((ct) => ct === "multipart/form-data")
92
- };
93
- }
94
- function getContentTypeInfo(node) {
95
- return buildContentTypeInfo(node.requestBody?.content?.map((e) => e.contentType) ?? []);
96
- }
97
- /**
98
- * The request-body counterpart for the primary success response: the content types it documents and
99
- * whether several are present, so the client can let a caller pick which one to accept.
100
- */
101
- function getResponseContentTypeInfo(node) {
102
- return buildContentTypeInfo(getPrimarySuccessResponse(node)?.content?.map((e) => e.contentType) ?? []);
103
- }
104
- /**
105
- * Reads the single base content type of an operation's primary success response, lowercased and
106
- * stripped of any `; charset=...` suffix. Returns `undefined` when the response declares zero or
107
- * more than one content type, since neither case has a single type to act on.
108
- */
109
- function getPrimarySuccessContentType(node) {
110
- const contentTypes = getPrimarySuccessResponse(node)?.content?.map((entry) => entry.contentType) ?? [];
111
- if (contentTypes.length !== 1) return void 0;
112
- return contentTypes[0].split(";")[0].trim().toLowerCase();
113
- }
114
- /**
115
- * The `text/event-stream` content of the primary success response, when it is the only content type. A response that also
116
- * declares another type stays a normal call with its query hooks.
117
- */
118
- function getEventStreamContent(node) {
119
- return getPrimarySuccessContentType(node) === "text/event-stream" ? getPrimarySuccessResponse(node)?.content?.[0] : void 0;
120
- }
121
- /**
122
- * Whether an operation streams its primary success response as Server-Sent Events (`text/event-stream`). The client
123
- * generator uses this to return a typed event stream instead of a one-shot `RequestResult`.
124
- */
125
- function isEventStream(node) {
126
- return getEventStreamContent(node) !== void 0;
127
- }
128
- /**
129
- * How the document types a `text/event-stream` response, as the adapter read it from `itemSchema`: `event` when each item is
130
- * the parsed event with its own `event` and `data`, `data` when it is only the payload. Returns `null` without an event stream.
131
- */
132
- function getEventStream(node) {
133
- const content = getEventStreamContent(node);
134
- return content ? content.stream?.shape ?? "data" : null;
135
- }
136
- function baseContentType(contentType) {
137
- return contentType.split(";")[0].trim().toLowerCase();
138
- }
139
- function isJsonContentType(baseType) {
140
- return baseType === "application/json" || baseType.endsWith("+json") || baseType === "text/json";
141
- }
142
- /**
143
- * Parser for one response content entry.
144
- *
145
- * JSON stays unset so the runtime detects it. `text/event-stream` is a stream. A binary schema
146
- * (`format: binary` / `contentMediaType`) is a blob even when the media type is not a well-known
147
- * binary type. Other `text/*` is text, and `application/octet-stream`, `application/pdf`,
148
- * `image/*`, `audio/*`, and `video/*` are blobs.
149
- */
150
- function responseTypeForContent(contentType, schema) {
151
- const baseType = baseContentType(contentType);
152
- if (!baseType) return void 0;
153
- if (isJsonContentType(baseType)) return void 0;
154
- if (baseType === "text/event-stream") return "stream";
155
- if (schema?.type === "blob") return "blob";
156
- if (baseType.startsWith("text/")) return "text";
157
- if (baseType === "application/octet-stream" || baseType === "application/pdf" || /^(image|audio|video)\//.test(baseType)) return "blob";
158
- }
159
- /**
160
- * Derives the default `responseType` string for an operation from its primary success response.
161
- *
162
- * One content type uses {@link responseTypeForContent}. Several content types that all use the same
163
- * parser collapse to that string, so a call can keep `responseType: 'blob'`. Mixed parsers return
164
- * `undefined`; {@link getResponseTypeMap} carries the per-type choice.
165
- */
166
- function getResponseType(node) {
167
- const entries = getPrimarySuccessResponse(node)?.content ?? [];
168
- if (entries.length === 0) return void 0;
169
- const responseTypes = entries.map((entry) => responseTypeForContent(entry.contentType, entry.schema));
170
- const first = responseTypes[0];
171
- if (!first) return void 0;
172
- if (responseTypes.every((responseType) => responseType === first)) return first;
173
- }
174
- /**
175
- * Maps each base content type of a primary success response to its parser when those parsers differ.
176
- *
177
- * Keys are lowercased and stripped of parameters. JSON entries are kept as `'json'` so a catch-all
178
- * entry cannot claim a JSON response. Returns `undefined` when {@link getResponseType} already
179
- * covers the response with one string, or when no content type needs a parser other than JSON.
180
- * The runtime matches the response `Content-Type` against this map instead of guessing from the media type.
181
- */
182
- function getResponseTypeMap(node) {
183
- if (getResponseType(node)) return void 0;
184
- const entries = getPrimarySuccessResponse(node)?.content ?? [];
185
- if (entries.length <= 1) return void 0;
186
- const map = {};
187
- for (const entry of entries) {
188
- const baseType = baseContentType(entry.contentType);
189
- const responseType = responseTypeForContent(entry.contentType, entry.schema) ?? (isJsonContentType(baseType) ? "json" : void 0);
190
- if (baseType && responseType) map[baseType] = responseType;
191
- }
192
- return Object.values(map).some((responseType) => responseType !== "json") ? map : void 0;
193
- }
194
- /**
195
- * Which of the grouped request options an operation carries.
196
- */
197
- function getRequestGroups(node) {
198
- const { path, query, header } = getOperationParameters(node);
199
- return {
200
- path: path.length > 0,
201
- query: query.length > 0,
202
- body: Boolean(node.requestBody?.content?.[0]?.schema),
203
- headers: header.length > 0
204
- };
205
- }
206
- /**
207
- * Resolves which grouped request options an operation carries together with whether each group
208
- * holds a required member. The grouped parameter stays optional only when nothing inside it is
209
- * required, matching the generated `RequestConfig` type.
210
- */
211
- function getRequestGroupOptionality(node) {
212
- const groups = getRequestGroups(node);
213
- const { path, query, header } = getOperationParameters(node);
214
- const hasRequiredPath = path.some((param) => param.required);
215
- const hasRequiredQuery = query.some((param) => param.required);
216
- const hasRequiredHeader = header.some((param) => param.required);
217
- return {
218
- groups,
219
- hasRequiredPath,
220
- hasRequiredQuery,
221
- hasRequiredHeader,
222
- isOptional: !hasRequiredPath && !hasRequiredQuery && !hasRequiredHeader && !groups.body
223
- };
224
- }
225
- function buildOperationComments(node, options = {}) {
226
- const { link = "pathTemplate", linkPosition = "afterDeprecated", splitLines = false } = options;
227
- const linkComment = getOperationLink(node, link);
228
- const filteredComments = (linkPosition === "beforeDeprecated" ? [
229
- node.description && `@description ${node.description}`,
230
- node.summary && `@summary ${node.summary}`,
231
- linkComment,
232
- node.deprecated && "@deprecated"
233
- ] : [
234
- node.description && `@description ${node.description}`,
235
- node.summary && `@summary ${node.summary}`,
236
- node.deprecated && "@deprecated",
237
- linkComment
238
- ]).filter((comment) => Boolean(comment));
239
- if (!splitLines) return filteredComments;
240
- return filteredComments.flatMap((text) => text.split(/\r?\n/).map((line) => line.trim())).filter((comment) => Boolean(comment));
241
- }
242
- const operationParameterGroupsByNode = /* @__PURE__ */ new WeakMap();
243
- /**
244
- * An OpenAPI 3.2 `querystring` parameter is the whole query string, so a form-encoded object becomes one query parameter
245
- * per property, typed and serialized like any other.
246
- * Another content type, such as JSON, stays one parameter named after it, and the runtime sends its value as the whole query string.
247
- */
248
- function spreadQuerystring(param) {
249
- const schema = param.schema.type === "ref" ? param.schema.schema : param.schema;
250
- const formEncoded = !param.contentType || param.contentType.split(";")[0].trim().toLowerCase() === "application/x-www-form-urlencoded";
251
- if (schema?.type !== "object" || !formEncoded) return [param];
252
- return schema.properties.map((property) => _kubb_kit.ast.factory.createParameter({
253
- name: property.name,
254
- in: "query",
255
- schema: property.schema,
256
- required: param.required && property.required
257
- }));
258
- }
259
- /**
260
- * Groups an operation's parameters by location (`path`/`query`/`header`/`cookie`), deduping each
261
- * group by name. Every plugin generator visiting the same `OperationNode` shares one AST instance
262
- * (see `KubbDriver`), so the result is cached per node to avoid re-filtering and re-deduping the
263
- * same parameters once per plugin.
264
- */
265
- function getOperationParameters(node) {
266
- const cached = operationParameterGroupsByNode.get(node);
267
- if (cached) return cached;
268
- const dedupe = (params) => {
269
- const seen = /* @__PURE__ */ new Set();
270
- return params.filter((param) => {
271
- if (seen.has(param.name)) return false;
272
- seen.add(param.name);
273
- return true;
274
- });
275
- };
276
- const group = (location) => dedupe(node.parameters.filter((param) => param.in === location));
277
- const groups = {
278
- path: group("path"),
279
- query: dedupe([...group("query"), ...group("querystring").flatMap(spreadQuerystring)]),
280
- header: group("header"),
281
- cookie: group("cookie")
282
- };
283
- operationParameterGroupsByNode.set(node, groups);
284
- return groups;
285
- }
286
- /**
287
- * Builds the combined `{ body, path, query, headers }` options object schema for an operation,
288
- * referencing the already-resolved body and grouped param names. Shared by `@kubb/plugin-ts`'s
289
- * `Options` type and `@kubb/plugin-zod`'s inferred options schema, so both printers emit the same
290
- * shape from the same inputs. `primitive: 'object'` is a no-op for the TS printer and tells the Zod
291
- * printer to emit `z.object(…)` rather than a record.
292
- */
293
- function hasRequestContentTypeChoice(node) {
294
- return (node.requestBody?.content ?? []).filter((entry) => entry.schema).length > 1;
295
- }
296
- function getStatusCodeNumber(statusCode) {
297
- const code = Number(statusCode);
298
- return Number.isNaN(code) ? null : code;
299
- }
300
- function isSuccessStatusCode(statusCode) {
301
- const code = getStatusCodeNumber(statusCode);
302
- return code !== null && code >= 200 && code < 300;
303
- }
304
- function getSuccessResponses(responses) {
305
- return responses.filter((response) => isSuccessStatusCode(response.statusCode));
306
- }
307
- function getOperationSuccessResponses(node) {
308
- return getSuccessResponses(node.responses);
309
- }
310
- function getPrimarySuccessResponse(node) {
311
- return getOperationSuccessResponses(node)[0] ?? null;
312
- }
313
- // ../../internals/utils/src/reserved.ts
314
- /**
315
- * JavaScript and Java reserved words.
316
- * @link https://github.com/jonschlinkert/reserved/blob/master/index.js
317
- */
318
- const reservedWords = /* @__PURE__ */ new Set([
319
- "abstract",
320
- "arguments",
321
- "await",
322
- "boolean",
323
- "break",
324
- "byte",
325
- "case",
326
- "catch",
327
- "char",
328
- "class",
329
- "const",
330
- "continue",
331
- "debugger",
332
- "default",
333
- "delete",
334
- "do",
335
- "double",
336
- "else",
337
- "enum",
338
- "eval",
339
- "export",
340
- "extends",
341
- "false",
342
- "final",
343
- "finally",
344
- "float",
345
- "for",
346
- "function",
347
- "goto",
348
- "if",
349
- "implements",
350
- "import",
351
- "in",
352
- "instanceof",
353
- "int",
354
- "interface",
355
- "let",
356
- "long",
357
- "native",
358
- "new",
359
- "null",
360
- "package",
361
- "private",
362
- "protected",
363
- "public",
364
- "return",
365
- "short",
366
- "static",
367
- "super",
368
- "switch",
369
- "synchronized",
370
- "this",
371
- "throw",
372
- "throws",
373
- "transient",
374
- "true",
375
- "try",
376
- "typeof",
377
- "var",
378
- "void",
379
- "volatile",
380
- "while",
381
- "with",
382
- "yield",
383
- "Array",
384
- "Date",
385
- "hasOwnProperty",
386
- "Infinity",
387
- "isFinite",
388
- "isNaN",
389
- "isPrototypeOf",
390
- "length",
391
- "Math",
392
- "name",
393
- "NaN",
394
- "Number",
395
- "Object",
396
- "prototype",
397
- "String",
398
- "toString",
399
- "undefined",
400
- "valueOf"
401
- ]);
402
- /**
403
- * Returns `true` when `name` is a syntactically valid JavaScript variable name.
404
- *
405
- * @example
406
- * ```ts
407
- * isValidVarName('status') // true
408
- * isValidVarName('class') // false (reserved word)
409
- * isValidVarName('42foo') // false (starts with digit)
410
- * ```
411
- */
412
- function isValidVarName(name) {
413
- if (!name || reservedWords.has(name)) return false;
414
- return isIdentifier(name);
415
- }
416
- /**
417
- * Returns `name` when it's a syntactically valid JavaScript variable name,
418
- * otherwise prefixes it with `_` so the result is a valid identifier.
419
- *
420
- * Useful for sanitizing OpenAPI schema names or operation IDs that start with
421
- * a digit (e.g. `409`, `504AccountCancel`) before using them as exported
422
- * variable, type, or function names.
423
- *
424
- * @example
425
- * ```ts
426
- * ensureValidVarName('409') // '_409'
427
- * ensureValidVarName('504AccountCancel') // '_504AccountCancel'
428
- * ensureValidVarName('Pet') // 'Pet'
429
- * ensureValidVarName('class') // '_class'
430
- * ```
431
- */
432
- function ensureValidVarName(name) {
433
- if (!name || isValidVarName(name)) return name;
434
- return `_${name}`;
435
- }
436
- /**
437
- * Returns `true` when `name` is syntactically a valid identifier, ignoring reserved words.
438
- *
439
- * Reserved words and globals (`class`, `name`, `Date`, …) are valid as bare object-literal keys
440
- * even though they are not valid variable names, so use this (not {@link isValidVarName}) when
441
- * deciding whether an object key needs quoting.
442
- *
443
- * @example
444
- * ```ts
445
- * isIdentifier('name') // true
446
- * isIdentifier('x-total')// false
447
- * ```
448
- */
449
- function isIdentifier(name) {
450
- return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
451
- }
452
- // ../../internals/utils/src/codegen.ts
453
- /**
454
- * Builds a JSDoc comment block from an array of lines. Returns `fallback` when there are no
455
- * comments.
456
- *
457
- * @example
458
- * ```ts
459
- * buildJSDoc(['@type string', '@example hello'])
460
- * // '/**\n * @type string\n * @example hello\n *\/\n '
461
- * ```
462
- */
463
- function buildJSDoc(comments, options = {}) {
464
- const { indent = " * ", suffix = "\n ", fallback = " " } = options;
465
- if (comments.length === 0) return fallback;
466
- return `/**\n${comments.map((c) => `${indent}${c}`).join("\n")}\n */${suffix}`;
467
- }
468
- // ../../internals/shared/src/resolver.ts
469
- /**
470
- * The shared top-level `name` of the operation plugins, computed once per operation name and build.
471
- */
472
- function resolveOperationName(name) {
473
- return this.memo(`operation:${name}`, () => ensureValidVarName((0, _kubb_kit.camelCase)(name)));
474
- }
475
- /**
476
- * Builds the allocation key for a declaration an operation owns. `scope` names which declaration
477
- * it is, so two of them never share an allocation even when a custom resolver gives both the same
478
- * name. Leave `scope` empty for the operation's own declaration.
479
- *
480
- * @example
481
- * ```ts
482
- * resolver.resolveName({ key: operationKey(node, 'response', 'status', 404), name })
483
- * ```
484
- */
485
- function operationKey(node, ...scope) {
486
- return [
487
- "operation",
488
- node.method,
489
- node.path,
490
- ...scope.map(String)
491
- ];
492
- }
493
- // ../../internals/shared/src/group.ts
494
- /**
495
- * Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the
496
- * shared default naming so every plugin groups output consistently:
497
- *
498
- * - `path` groups use the second path segment (`/pet/findByStatus` → `pet`).
499
- * - other groups use the camelCased group (`pet store` → `petStore`).
500
- *
501
- * A user-provided `group.name` always wins over the default namer, so callers stay in
502
- * control of their output folders. Returns `null` when grouping is disabled, matching the
503
- * per-plugin convention.
504
- *
505
- * @param group - The user-supplied group option, or `undefined` to disable grouping.
506
- *
507
- * @example
508
- * ```ts
509
- * createGroupConfig(group) // shared across every plugin
510
- * ```
511
- */
512
- function createGroupConfig(group) {
513
- if (!group) return null;
514
- const defaultName = (ctx) => {
515
- if (group.type === "path") return `${ctx.group.split("/")[1]}`;
516
- return (0, _kubb_kit.camelCase)(ctx.group);
517
- };
518
- return {
519
- ...group,
520
- name: group.name ? group.name : defaultName
521
- };
522
- }
523
- // ../../internals/client/src/builders/validatorOptions.ts
524
- /**
525
- * Returns `true` when any direction of the validator uses zod (used for dependency checks).
526
- */
527
- function isValidatorEnabled(validator) {
528
- if (!validator) return false;
529
- if (validator === "zod") return true;
530
- return Boolean(validator.request || validator.params || validator.response);
531
- }
532
- /**
533
- * Returns `'zod'` when request body parsing is enabled, `null` otherwise. The string shorthand
534
- * `'zod'` validates the response only, so it does not enable request parsing.
535
- */
536
- function resolveRequestValidator(validator) {
537
- if (!validator || validator === "zod") return null;
538
- return validator.request ?? null;
539
- }
540
- /**
541
- * Returns `'zod'` when path, query, and header params parsing is enabled, `null` otherwise. Only the
542
- * object form `{ params: 'zod' }` enables it.
543
- */
544
- function resolveParamsValidator(validator) {
545
- if (!validator || validator === "zod") return null;
546
- return validator.params ?? null;
547
- }
548
- /**
549
- * Returns `'zod'` when response parsing is enabled, `null` otherwise. The string shorthand `'zod'`
550
- * maps to response parsing.
551
- */
552
- function resolveResponseValidator(validator) {
553
- if (!validator) return null;
554
- if (validator === "zod") return "zod";
555
- return validator.response ?? null;
556
- }
557
- /**
558
- * Resolves the zod schema name a generated client validates an error body with on the non-throw path.
559
- * Uses the error-only `<operation>ErrorSchema` (the union of non-2xx statuses); returns `null` when the
560
- * operation documents no error responses with a schema.
561
- */
562
- function buildZodErrorParse(node, zodResolver) {
563
- if (!node.responses.some((res) => !isSuccessStatusCode(res.statusCode) && res.content?.some((entry) => entry.schema))) return null;
564
- return zodResolver.response.error?.(node) || null;
565
- }
566
- // ../../internals/client/src/builders/generics.ts
567
- /**
568
- * Builds the `RequestResult` generic arguments for one operation: the per-status responses record
569
- * plus the per-call `ThrowOnError` flag. `SuccessOf` / `ErrorOf` split the record inside the
570
- * runtime, so this only names the record and threads `ThrowOnError`.
571
- *
572
- * @example
573
- * `buildRequestResultGenerics({ node, types }) // 'AddPetResponses, ThrowOnError'`
574
- */
575
- function buildRequestResultGenerics({ node, types }) {
576
- return `${types.response.responses(node)}, ThrowOnError`;
577
- }
578
- /**
579
- * Builds the full return type an operation's function signature uses: `Unwrappable<RequestResult>`
580
- * for the default `returnType: 'full'`, already a promise so no further wrapping is needed, a plain
581
- * `Promise<RequestResult>` for the internal `'plain'` shape, or a
582
- * `Promise` of the runtime's `UnwrappedResult` when `returnType: 'data'` narrows a resolved call
583
- * down to the bare success body.
584
- *
585
- * @example
586
- * `buildResultType({ node, types, returnType: 'data' }) // 'Promise<UnwrappedResult<AddPetResponses, ThrowOnError>>'`
587
- */
588
- function buildResultType({ node, types, returnType }) {
589
- const generics = buildRequestResultGenerics({
590
- node,
591
- types
592
- });
593
- if (returnType === "data") return `Promise<UnwrappedResult<${generics}>>`;
594
- if (returnType === "plain") return `Promise<RequestResult<${generics}>>`;
595
- return `Unwrappable<RequestResult<${generics}>>`;
596
- }
597
- // ../../internals/client/src/builders/returnStatement.ts
598
- /**
599
- * Builds the return statement of a generated operation function. With the default
600
- * `returnType: 'full'` the runtime call already resolves to `{ data, error, request, response }`.
601
- * The generated code casts that result to the operation's `RequestResult`, then wraps it with
602
- * `withUnwrap`, so the caller can `await` it directly or call `.unwrap()` for the bare success
603
- * body. With `returnType: 'data'` it instead routes the call through the runtime's `unwrapResult`,
604
- * which narrows the resolved value down to the bare success body the same way `RequestResult`
605
- * already does, using the plugin default when the call leaves `throwOnError` unset.
606
- * With `returnType: 'plain'` it returns the runtime call as is, cast to `RequestResult`, with no helper.
607
- *
608
- * Cast first, wrap second, for the `'full'` path. That order keeps `withUnwrap`'s generic inferred
609
- * as `RequestResult` instead of the runtime's own internal result type. Casting an `Unwrappable<A>`
610
- * straight to `Unwrappable<B>` does not work: the `.then` overload stays pinned to `A`, and `as`
611
- * rejects that two-generic swap even where `A` and `B` on their own would satisfy it.
612
- *
613
- * @example
614
- * `return withUnwrap(request({ method: 'POST', url: '/pet', ...config }) as Promise<RequestResult<AddPetResponses, ThrowOnError>>)`
615
- * @example
616
- * `return unwrapResult(request({ method: 'POST', url: '/pet', ...config }), config.throwOnError ?? false) as Promise<UnwrappedResult<AddPetResponses, ThrowOnError>>`
617
- * @example
618
- * `return request({ method: 'POST', url: '/pet', ...config }) as Promise<RequestResult<AddPetResponses, ThrowOnError>>`
619
- */
620
- function buildReturnStatement({ node, types, callConfig, returnType, throwOnErrorDefault }) {
621
- const request = returnType !== "plain" && hasRequestContentTypeChoice(node) ? `request<${types.response.options(node)}['body']>` : "request";
622
- if (returnType === "data") return `return unwrapResult(${request}(${callConfig}), config.throwOnError ?? ${throwOnErrorDefault}) as ${buildResultType({
623
- node,
624
- types,
625
- returnType
626
- })}`;
627
- if (returnType === "plain") return `return ${request}(${callConfig}) as Promise<RequestResult<${buildRequestResultGenerics({
628
- node,
629
- types
630
- })}>>`;
631
- return `return withUnwrap(${request}(${callConfig}) as Promise<RequestResult<${buildRequestResultGenerics({
632
- node,
633
- types
634
- })}>>)`;
635
- }
636
- /**
637
- * Builds the return type and statement of a `text/event-stream` operation. The item type is `TypedEvent<...>` when each item
638
- * declares its own `event` and `data`, and otherwise the payload type, which `EventStreamResult` wraps in `ServerSentEvent`. The call's
639
- * promise goes through `toEventStream` with the `client` for its defaults, the call's `config`, the shape and the per-event
640
- * validator. A `returnType: 'plain'` client receives only the promise,
641
- * `toEventStream(request(config))`, and keeps its response validator in the call config.
642
- */
643
- function buildEventStreamReturn({ node, types, callConfig, returnType, validatorHooks, throwOnErrorDefault }) {
644
- const shape = getEventStream(node) ?? "data";
645
- const responses = types.response.responses(node);
646
- const success = `SuccessOf<${responses}>`;
647
- const eventType = shape === "event" ? `TypedEvent<${success}>` : success;
648
- if (returnType === "plain") return {
649
- returnType: `Promise<EventStreamResult<${eventType}>>`,
650
- statement: `return toEventStream<${eventType}>(request(${callConfig}))`
651
- };
652
- const generics = `${responses}, ThrowOnError${shape === "event" ? `, ${eventType}` : ""}`;
653
- const call = `toEventStream<${eventType}>(request(${callConfig}), { client: request, config, ${[`shape: '${shape}'`, validatorHooks?.response ? `validator: ${validatorHooks.response}` : null].filter(Boolean).join(", ")} })`;
654
- if (returnType === "data") {
655
- const result = `Promise<UnwrappedStreamResult<${generics}>>`;
656
- return {
657
- returnType: result,
658
- statement: `return unwrapResult(${call}, config.throwOnError ?? ${throwOnErrorDefault}) as ${result}`
659
- };
660
- }
661
- return {
662
- returnType: `Unwrappable<StreamResult<${generics}>>`,
663
- statement: `return withUnwrap(${call} as Promise<StreamResult<${generics}>>)`
664
- };
665
- }
666
- /** The stream types an operation file imports: `StreamResult` and `StreamOptions`, `EventStreamResult` for a plain client, and `TypedEvent` for named events. */
667
- function buildEventStreamImports({ returnType, typed }) {
668
- return [...{
669
- plain: ["EventStreamResult"],
670
- full: ["StreamResult", "StreamOptions"],
671
- data: ["UnwrappedStreamResult", "StreamOptions"]
672
- }[returnType], ...typed ? ["TypedEvent"] : []];
673
- }
674
- // ../../internals/client/src/builders/security.ts
675
- function serializeAuth(auth) {
676
- const parts = [`type: '${auth.type}'`];
677
- if (auth.scheme) parts.push(`scheme: '${auth.scheme}'`);
678
- if (auth.name) parts.push(`name: '${auth.name}'`);
679
- if (auth.in) parts.push(`in: '${auth.in}'`);
680
- if (auth.scopes?.length) parts.push(`scopes: [${auth.scopes.map((scope) => `'${scope}'`).join(", ")}]`);
681
- return `{ ${parts.join(", ")} }`;
682
- }
683
- /**
684
- * Maps an OpenAPI security scheme to the inline `Auth` object, or `null` when the runtime cannot
685
- * place it (an unresolved `$ref`, or an `apiKey` without a name or outside `header` / `query` /
686
- * `cookie`). `http` schemes other than `basic` are treated as bearer.
687
- */
688
- function resolveSecurityScheme(scheme) {
689
- if (!scheme || "$ref" in scheme) return null;
690
- if (scheme.type === "apiKey") {
691
- if (!scheme.name || scheme.in !== "header" && scheme.in !== "query" && scheme.in !== "cookie") return null;
692
- return {
693
- type: "apiKey",
694
- name: scheme.name,
695
- in: scheme.in
696
- };
697
- }
698
- if (scheme.type === "http") return {
699
- type: "http",
700
- scheme: scheme.scheme?.toLowerCase() === "basic" ? "basic" : "bearer"
701
- };
702
- if (scheme.type === "oauth2") return { type: "oauth2" };
703
- if (scheme.type === "openIdConnect") return { type: "openIdConnect" };
704
- return null;
705
- }
706
- /**
707
- * Derives the per-operation security metadata from the OpenAPI document. The operation's own
708
- * `security` overrides the global `security` (an explicit empty array disables auth), and every
709
- * referenced scheme is resolved from `components.securitySchemes` into a flat, de-duplicated list of
710
- * `Auth` objects the runtime walks in order.
711
- *
712
- * @example
713
- * `getOperationSecurity({ document, method: 'POST', path: '/pet' })`
714
- * `// [{ type: 'http', scheme: 'bearer' }]`
715
- */
716
- function getOperationSecurity({ document, method, path }) {
717
- if (!document) return void 0;
718
- const requirements = (document.paths?.[path]?.[method.toLowerCase()])?.security ?? document.security;
719
- if (!requirements?.length) return void 0;
720
- const definitions = document.components?.securitySchemes ?? {};
721
- const security = [];
722
- const seen = /* @__PURE__ */ new Set();
723
- for (const requirement of requirements) for (const [schemeName, scopes] of Object.entries(requirement)) {
724
- if (seen.has(schemeName)) continue;
725
- seen.add(schemeName);
726
- const auth = resolveSecurityScheme(definitions[schemeName]);
727
- if (auth) security.push(scopes.length ? {
728
- ...auth,
729
- scopes
730
- } : auth);
731
- }
732
- return security.length ? security : void 0;
733
- }
734
- /**
735
- * Serializes the per-operation security into the literal emitted on each generated call's `security`
736
- * field. The runtime `resolveAuth` helper walks it, calling the configured `auth` resolver per entry.
737
- *
738
- * @example
739
- * `buildSecurityMetadata({ security: [{ type: 'http', scheme: 'bearer' }] }) // "[{ type: 'http', scheme: 'bearer' }]"`
740
- */
741
- function buildSecurityMetadata({ security }) {
742
- if (!security?.length) return null;
743
- return `[${security.map(serializeAuth).join(", ")}]`;
744
- }
745
- // ../../internals/client/src/builders/validator.ts
746
- /**
747
- * Builds the validator-hook references for one operation. Request body and params validation run before the send.
748
- * Response validation runs on the success body only. Returns `null` references when the matching
749
- * direction is disabled or the schema is absent.
750
- */
751
- function buildValidatorHooks({ node, validator, zodResolver }) {
752
- const hasRequestBody = Boolean(node.requestBody?.content?.[0]?.schema);
753
- const parsesResponse = zodResolver && resolveResponseValidator(validator) === "zod";
754
- const response = parsesResponse ? zodResolver.response.response(node) || null : null;
755
- const error = parsesResponse ? buildZodErrorParse(node, zodResolver) : null;
756
- const request = zodResolver && resolveRequestValidator(validator) === "zod" && hasRequestBody ? zodResolver.response.body(node) || null : null;
757
- const paramGroups = getOperationParameters(node);
758
- const resolveParamsName = (kind, params) => zodResolver && resolveParamsValidator(validator) === "zod" && params.length > 0 ? zodResolver.param[kind](node, params[0]) : null;
759
- const path = resolveParamsName("path", paramGroups.path);
760
- const query = resolveParamsName("query", paramGroups.query);
761
- const headers = resolveParamsName("headers", paramGroups.header);
762
- const importedZodNames = [
763
- response,
764
- error,
765
- request,
766
- path,
767
- query,
768
- headers
769
- ].filter((name) => Boolean(name));
770
- return {
771
- request,
772
- path,
773
- query,
774
- headers: headers ? `toHeadersStandardSchema(${headers}, ${headers}.shape)` : null,
775
- response,
776
- error,
777
- importedZodNames
778
- };
779
- }
780
- /**
781
- * Prints the `validator: { … }` entry of a call config from the hooks named in `keys`, or `null` when none is set.
782
- */
783
- function buildValidatorLiteral(hooks, keys) {
784
- const entries = keys.flatMap((key) => hooks?.[key] ? [`${key}: ${hooks[key]}`] : []);
785
- return entries.length ? `validator: { ${entries.join(", ")} }` : null;
786
- }
787
- // ../../internals/client/src/builders/contentType.ts
788
- /**
789
- * Builds the `contentType` entry baked into the call config, or `null` without a request body.
790
- *
791
- * `merge` is `true` when the generated function must destructure `contentType` from `options` and
792
- * merge it over the baked request default, because the caller can also pick a response content type.
793
- */
794
- function buildContentType({ node }) {
795
- const { defaultContentType } = getContentTypeInfo(node);
796
- const requestContentType = Boolean(node.requestBody?.content?.[0]?.schema) ? defaultContentType : null;
797
- if (!requestContentType) return {
798
- literal: null,
799
- merge: false
800
- };
801
- const merge = getResponseContentTypeInfo(node).isMultipleContentTypes;
802
- return {
803
- merge,
804
- literal: merge ? `contentType: { request: '${requestContentType}', ...(typeof contentType === 'string' ? { request: contentType } : contentType) }` : `contentType: { request: '${requestContentType}' }`
805
- };
806
- }
807
- // ../../internals/client/src/builders/styles.ts
808
- /**
809
- * Renders a parameter name as an object-literal key, quoted when it is not a bare identifier. Every
810
- * location keeps the spec name: the runtime looks path styles up by the `{name}` placeholder in the
811
- * URL, and the other locations by the key it serializes.
812
- */
813
- function toKey(name) {
814
- return isValidVarName(name) ? name : JSON.stringify(name);
815
- }
816
- /**
817
- * Serializes one parameter's metadata into a `{ style, explode, allowReserved, contentType }`
818
- * literal, or `null` when the parameter carries none. Path and query carry the serialization
819
- * `style`; header and cookie use a fixed style (`simple` and `form`), so only `explode` is emitted
820
- * for them. `allowReserved` only applies to query parameters, and `contentType` to every location
821
- * except path.
822
- */
823
- function serializeParameter(parameter) {
824
- const parts = [];
825
- if ((parameter.in === "path" || parameter.in === "query") && parameter.style) parts.push(`style: '${parameter.style}'`);
826
- if (parameter.explode !== void 0) parts.push(`explode: ${parameter.explode}`);
827
- if (parameter.in === "query" && parameter.allowReserved !== void 0) parts.push(`allowReserved: ${parameter.allowReserved}`);
828
- if (parameter.in !== "path" && parameter.contentType) parts.push(`contentType: '${parameter.contentType}'`);
829
- if (parameter.in === "querystring") parts.push("querystring: true");
830
- return parts.length > 0 ? `{ ${parts.join(", ")} }` : null;
831
- }
832
- /**
833
- * Serializes the `encoding` of the request body's default content type into a `{ property: { ... } }`
834
- * literal, or `null` when it carries none. Only an operation with a single request content type
835
- * emits it, because the runtime applies `styles.body` to whichever type the caller selects.
836
- */
837
- function serializeBodyEncoding(node) {
838
- const content = node.requestBody?.content;
839
- const entries = Object.entries(content?.length === 1 ? content[0]?.encoding ?? {} : {}).map(([property, { contentType, style, explode, allowReserved }]) => {
840
- const parts = [
841
- style && `style: ${JSON.stringify(style)}`,
842
- explode !== void 0 && `explode: ${explode}`,
843
- allowReserved !== void 0 && `allowReserved: ${allowReserved}`,
844
- contentType && `contentType: ${JSON.stringify(contentType)}`
845
- ].filter(Boolean);
846
- return `${isValidVarName(property) ? property : JSON.stringify(property)}: { ${parts.join(", ")} }`;
847
- });
848
- return entries.length > 0 ? `body: { ${entries.join(", ")} }` : null;
849
- }
850
- /**
851
- * Builds the per-operation `styles` literal from the operation's parameters, grouped by location.
852
- * Entries are keyed by the spec name of the parameter.
853
- * Only parameters whose source defines `style`, `explode`, `allowReserved`, or `contentType` are
854
- * emitted, so calls without serialization metadata keep the runtime defaults and existing output
855
- * is unchanged. A form request body adds a `body` group keyed by property name from its `encoding`.
856
- * Returns `null` when nothing carries metadata.
857
- *
858
- * @example
859
- * ```ts
860
- * // a path param with { style: 'matrix', explode: true } and a query param with { explode: false }
861
- * buildStyles({ node }) // "{ path: { id: { style: 'matrix', explode: true } }, query: { tags: { explode: false } } }"
862
- * ```
863
- */
864
- function buildStyles({ node }) {
865
- if (!_kubb_kit.ast.isHttpOperationNode(node)) return null;
866
- const groups = {
867
- path: [],
868
- query: [],
869
- header: [],
870
- cookie: []
871
- };
872
- for (const [location, parameters] of Object.entries(getOperationParameters(node))) for (const parameter of parameters) {
873
- const literal = serializeParameter(parameter);
874
- if (literal) groups[location].push(`${toKey(parameter.name)}: ${literal}`);
875
- }
876
- const entries = [...Object.keys(groups).filter((location) => groups[location].length > 0).map((location) => `${location}: { ${groups[location].join(", ")} }`), serializeBodyEncoding(node)].filter(Boolean);
877
- return entries.length > 0 ? `{ ${entries.join(", ")} }` : null;
878
- }
879
- // ../../internals/client/src/builders/callConfig.ts
880
- /**
881
- * `responseType` baked into a call. One parser is a string. Several parsers become a map from content
882
- * type to parser so the runtime can choose from the response `Content-Type`.
883
- */
884
- function buildResponseTypeLiteral(node) {
885
- const responseType = getResponseType(node);
886
- if (responseType) return `responseType: '${responseType}'`;
887
- const responseTypes = getResponseTypeMap(node);
888
- if (!responseTypes) return null;
889
- return `responseType: { ${Object.entries(responseTypes).map(([contentType, type]) => `${JSON.stringify(contentType)}: '${type}'`).join(", ")} }`;
890
- }
891
- /**
892
- * Builds the call config literal a generated operation forwards to the client, shared by the standalone
893
- * functions and the SDK methods. The `throwOnError` fallback is applied after the `...config` spread.
894
- *
895
- * `mergeContentType` is `true` when the caller must destructure `contentType` from `options`, and
896
- * `eventStream` is `true` when the operation returns `text/event-stream`. Unless `returnType` is `'plain'`, a
897
- * stream's literal leaves the `response` validator to `toEventStream`, which runs it per event.
898
- */
899
- function buildCallConfig({ node, validatorHooks, security, throwOnErrorDefault, returnType }) {
900
- const eventStream = isEventStream(node);
901
- const securityLiteral = buildSecurityMetadata({ security });
902
- const stylesLiteral = buildStyles({ node });
903
- const validatorLiteral = buildValidatorLiteral(validatorHooks, eventStream && returnType !== "plain" ? [
904
- "request",
905
- "path",
906
- "query",
907
- "headers",
908
- "error"
909
- ] : [
910
- "request",
911
- "path",
912
- "query",
913
- "headers",
914
- "response",
915
- "error"
916
- ]);
917
- const { literal: contentTypeLiteral, merge: mergeContentType } = buildContentType({ node });
918
- return {
919
- callConfig: `{ ${[
920
- `method: '${node.method.toUpperCase()}'`,
921
- `url: '${node.path}'`,
922
- securityLiteral ? `security: ${securityLiteral}` : null,
923
- stylesLiteral ? `styles: ${stylesLiteral}` : null,
924
- validatorLiteral,
925
- contentTypeLiteral,
926
- buildResponseTypeLiteral(node),
927
- "...config",
928
- `throwOnError: config.throwOnError ?? ${throwOnErrorDefault}`
929
- ].filter(Boolean).join(", ")} }`,
930
- mergeContentType,
931
- eventStream
932
- };
933
- }
934
- // ../../internals/client/src/builders/signature.ts
935
- const declarationPrinter = (0, _kubb_plugin_ts.functionPrinter)({ mode: "declaration" });
936
- /**
937
- * Builds the grouped-options signature for one operation: a single `options` object whose `TData`
938
- * is the `<Name>Options` type, and a `RequestResult` return type keyed to the per-status responses
939
- * record. There are no positional arguments.
940
- *
941
- * The generated file imports `<Name>Options` and `<Name>Responses` and uses them directly, so no
942
- * per-operation input type has to be emitted. Both names come from `types`, which is `plugin-ts` or
943
- * `plugin-zod`'s inferred types (see `resolveOperationTypes`).
944
- */
945
- function buildGroupedOptionsSignature({ node, types, returnType, throwOnErrorDefault, eventStream = false }) {
946
- const optionsName = types.response.options(node);
947
- const optionsType = `${eventStream && returnType !== "plain" ? "StreamOptions" : "Options"}<${optionsName}, ThrowOnError>`;
948
- const { isOptional } = getRequestGroupOptionality(node);
949
- return {
950
- paramsSignature: declarationPrinter.print((0, _kubb_plugin_ts.createFunctionParameters)({ params: [(0, _kubb_plugin_ts.createFunctionParameter)({
951
- name: "options",
952
- type: optionsType,
953
- ...isOptional ? { default: "{}" } : {}
954
- })] })) ?? "",
955
- returnType: buildResultType({
956
- node,
957
- types,
958
- returnType
959
- }),
960
- generics: [`ThrowOnError extends boolean = ${throwOnErrorDefault}`]
961
- };
962
- }
963
- // ../../internals/client/src/builders/operationBody.ts
964
- /**
965
- * The pieces of a generated operation: its generics, `options` parameter, return type, return statement, and whether the
966
- * body destructures `contentType` from `options`. Shared by the standalone functions and the SDK methods, so a
967
- * `text/event-stream` operation is wired to `toEventStream` in one place.
968
- */
969
- function buildOperationBody({ node, types, validatorHooks, security, returnType, throwOnErrorDefault }) {
970
- const { callConfig, mergeContentType, eventStream } = buildCallConfig({
971
- node,
972
- validatorHooks,
973
- security,
974
- throwOnErrorDefault,
975
- returnType
976
- });
977
- const signature = buildGroupedOptionsSignature({
978
- node,
979
- types,
980
- returnType,
981
- throwOnErrorDefault,
982
- eventStream
983
- });
984
- const stream = eventStream ? buildEventStreamReturn({
985
- node,
986
- types,
987
- callConfig,
988
- returnType,
989
- validatorHooks,
990
- throwOnErrorDefault
991
- }) : null;
992
- return {
993
- generics: signature.generics,
994
- paramsSignature: signature.paramsSignature,
995
- returnType: stream?.returnType ?? signature.returnType,
996
- statement: stream?.statement ?? buildReturnStatement({
997
- node,
998
- types,
999
- callConfig,
1000
- returnType,
1001
- throwOnErrorDefault
1002
- }),
1003
- mergeContentType
1004
- };
1005
- }
1006
- // ../../internals/client/src/components/Operation.tsx
1007
- /**
1008
- * Renders one client operation: the grouped `<Name>Request` type and the function that forwards a
1009
- * single `options` object to the resolved client and returns the `Unwrappable<RequestResult>`. The
1010
- * type, signature, and call config are built with the AST factory, and only the jsx-renderer emits
1011
- * the source.
1012
- */
1013
- function Operation({ name, node, types, validatorHooks, returnType, throwOnErrorDefault, security }) {
1014
- if (!_kubb_kit.ast.isHttpOperationNode(node)) return null;
1015
- const body = buildOperationBody({
1016
- node,
1017
- types,
1018
- validatorHooks,
1019
- security,
1020
- returnType,
1021
- throwOnErrorDefault
1022
- });
1023
- return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
1024
- name,
1025
- isExportable: true,
1026
- isIndexable: true,
1027
- children: /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx.Function, {
1028
- name,
1029
- export: true,
1030
- generics: body.generics,
1031
- params: body.paramsSignature,
1032
- returnType: body.returnType,
1033
- JSDoc: { comments: buildOperationComments(node, {
1034
- link: "urlPath",
1035
- linkPosition: "beforeDeprecated",
1036
- splitLines: true
1037
- }) },
1038
- children: [
1039
- body.mergeContentType ? "const { client: request = client, contentType, ...config } = options" : "const { client: request = client, ...config } = options",
1040
- /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)("br", {}),
1041
- body.statement
1042
- ]
1043
- })
1044
- });
1045
- }
1046
- // ../../internals/client/src/components/StreamRuntime.tsx
1047
- /**
1048
- * The `footer` of `.kubb/client.ts`: the `baseURL` set at generation time, and the `sse.ts` re-export when the document
1049
- * streams events, so `ServerSentEvent` and `toEventStream` stay importable from the client as in earlier releases.
1050
- */
1051
- function buildClientFooter({ baseURL, sse }) {
1052
- const baseURLExpression = baseURL ? baseURL.includes("${") ? `\`${baseURL.replaceAll("`", "\\`")}\`` : JSON.stringify(baseURL) : void 0;
1053
- return [baseURLExpression ? `client.setConfig({ baseURL: ${baseURLExpression} })` : null, sse ? `export * from './sse.ts'` : null].filter(Boolean).join("\n") || void 0;
1054
- }
1055
- /**
1056
- * Writes the footer of the `.kubb/client.ts` the plugin injected, the one place it is built, and copies `sse.ts` into
1057
- * `.kubb/` only for a document with a `text/event-stream` operation, so a document without streams ships no stream runtime.
1058
- * `sse` is set by the plugins that ship the runtime, so a custom client from `@kubb/plugin-client` gets neither file.
1059
- */
1060
- function StreamRuntime({ nodes, root, sse, baseURL }) {
1061
- if (!sse) return null;
1062
- const streams = nodes.some(isEventStream);
1063
- const footer = buildClientFooter({
1064
- baseURL,
1065
- sse: streams
1066
- });
1067
- return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [streams && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File, {
1068
- baseName: "sse.ts",
1069
- path: node_path.default.resolve(root, ".kubb/sse.ts"),
1070
- copy: sse
1071
- }), footer && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File, {
1072
- baseName: "client.ts",
1073
- path: node_path.default.resolve(root, ".kubb/client.ts"),
1074
- footer
1075
- })] });
1076
- }
1077
- // ../../internals/client/src/resolveOperationTypes.ts
1078
- /**
1079
- * A `plugin-ts` shaped resolver whose operation type names point at the types `pluginZod({ inferred })`
1080
- * exports next to each schema, so code written against `plugin-ts` names picks up the zod types.
1081
- */
1082
- function toZodTypeResolver(resolver) {
1083
- const type = (name) => resolver.schema.type(name);
1084
- return {
1085
- ...resolver,
1086
- file: resolver.file.bind(resolver),
1087
- memo: (key, compute) => resolver.memo(`zodTypes:${key}`, compute),
1088
- param: {
1089
- name: (node, p) => type(resolver.param.name(node, p)),
1090
- path: (node, p) => type(resolver.param.path(node, p)),
1091
- query: (node, p) => type(resolver.param.query(node, p)),
1092
- headers: (node, p) => type(resolver.param.headers(node, p))
1093
- },
1094
- response: {
1095
- body: (node) => type(resolver.response.body(node)),
1096
- status: (node, statusCode) => type(resolver.response.status(node, statusCode)),
1097
- response: (node) => type(resolver.response.response(node)),
1098
- responses: (node) => type(resolver.response.responses(node)),
1099
- options: (node) => resolver.response.options(node)
1100
- }
1101
- };
1102
- }
1103
- /**
1104
- * Picks the plugin generated clients, query hooks, and MCP handlers take their operation types from.
1105
- *
1106
- * `pluginZod({ inferred: 'codec' })` wins, so a codec param takes its domain value. Otherwise `plugin-ts`
1107
- * wins when it is in the pipeline, and without it any `pluginZod({ inferred })`. Throws
1108
- * `KUBB_MISSING_DEPENDENCY` for `pluginName` when neither is available.
1109
- *
1110
- * @example
1111
- * ```ts
1112
- * const types = resolveOperationTypes(ctx.driver, ctx.plugin.name)
1113
- * types.response.options(node) // 'GetPetByIdOptions', or 'GetPetByIdOptionsSchemaType' from zod
1114
- * ```
1115
- */
1116
- function resolveOperationTypes(driver, pluginName) {
1117
- return driver.memo(`operationTypes:${pluginName}`, () => {
1118
- const pluginTs = driver.getPlugin(_kubb_plugin_ts.pluginTsName);
1119
- const pluginZod = driver.getPlugin(_kubb_plugin_zod.pluginZodName);
1120
- if (pluginTs && pluginZod?.options?.inferred !== "codec") {
1121
- const resolver = driver.getResolver(_kubb_plugin_ts.pluginTsName);
1122
- return {
1123
- response: resolver.response,
1124
- resolver,
1125
- output: pluginTs.options?.output,
1126
- group: pluginTs.options?.group ?? void 0
1127
- };
1128
- }
1129
- if (!pluginZod?.options?.inferred) throw new _kubb_kit.Diagnostics.Error({
1130
- code: _kubb_kit.Diagnostics.code.missingDependency,
1131
- severity: "error",
1132
- message: `Plugin "${pluginName}" has no source for operation types.`,
1133
- help: `Add \`pluginTs()\` before "${pluginName}", or add \`pluginZod({ inferred: true })\`.`,
1134
- location: { kind: "config" },
1135
- plugin: pluginName
1136
- });
1137
- const resolver = toZodTypeResolver(driver.getResolver(_kubb_plugin_zod.pluginZodName));
1138
- return {
1139
- response: resolver.response,
1140
- resolver,
1141
- output: pluginZod.options.output,
1142
- group: pluginZod.options.group ?? void 0
1143
- };
1144
- });
1145
- }
1146
- // ../../internals/client/src/generators/clientGenerator.tsx
1147
- /**
1148
- * Builds the built-in per-operation generator shared by the client plugins (`@kubb/plugin-fetch`,
1149
- * `@kubb/plugin-axios`). Emits one async function per OpenAPI operation using the shared
1150
- * `Operation` component: a grouped `<Name>Request` type and a function that forwards a single
1151
- * `options` object to the bundled `client` and returns the `Unwrappable<RequestResult>`. Only the
1152
- * generator `name` and the runtime templates differ between plugins. Every other resolution, import,
1153
- * and rendering step is identical.
1154
- *
1155
- * `sse` is the Server-Sent Events runtime template, copied into `.kubb/sse.ts` only for a document with a
1156
- * `text/event-stream` operation.
1157
- */
1158
- function createClientGenerator(name, { sse } = {}) {
1159
- return (0, _kubb_kit.defineGenerator)({
1160
- name,
1161
- renderer: _kubb_renderer_jsx.jsxRenderer,
1162
- operations(nodes, ctx) {
1163
- return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(StreamRuntime, {
1164
- nodes,
1165
- root: ctx.root,
1166
- sse,
1167
- baseURL: ctx.options.baseURL
1168
- });
1169
- },
1170
- operation(node, ctx) {
1171
- if (!_kubb_kit.ast.isHttpOperationNode(node)) return null;
1172
- const { config, driver, resolver, root } = ctx;
1173
- const { output, validator, returnType, throwOnErrorDefault, group, importPath } = ctx.options;
1174
- const types = resolveOperationTypes(driver, ctx.plugin.name);
1175
- const pluginZod = isValidatorEnabled(validator) ? driver.getPlugin(_kubb_plugin_zod.pluginZodName) : null;
1176
- const zodResolver = pluginZod ? driver.getResolver(_kubb_plugin_zod.pluginZodName) : null;
1177
- const importedTypeNames = [types.response.options(node), types.response.responses(node)];
1178
- const validatorHooks = buildValidatorHooks({
1179
- node,
1180
- validator,
1181
- zodResolver
1182
- });
1183
- const importedZodNames = validatorHooks.importedZodNames;
1184
- const operationName = resolver.name(node.operationId);
1185
- const meta = {
1186
- name: resolver.resolveName({
1187
- key: operationKey(node),
1188
- name: operationName
1189
- }),
1190
- file: resolver.file({
1191
- ...operationFileEntry(node, node.operationId),
1192
- root,
1193
- output,
1194
- group: group ?? void 0
1195
- }),
1196
- fileTypes: resolveDependencyOperationFile({
1197
- memo: ctx.memo,
1198
- node,
1199
- resolver: types.resolver,
1200
- root,
1201
- output: types.output ?? output,
1202
- group: types.group
1203
- }),
1204
- fileZod: zodResolver && pluginZod?.options ? zodResolver.file({
1205
- ...operationFileEntry(node, node.operationId),
1206
- root,
1207
- output: pluginZod.options.output ?? output,
1208
- group: pluginZod.options?.group ?? void 0
1209
- }) : null
1210
- };
1211
- const security = getOperationSecurity({
1212
- document: ctx.adapter.document,
1213
- method: node.method,
1214
- path: node.path
1215
- });
1216
- const clientPath = importPath ?? node_path.default.resolve(root, ".kubb/client.ts");
1217
- const clientRoot = importPath === void 0 ? meta.file.path : void 0;
1218
- const standardSchemaPath = importPath ?? node_path.default.resolve(root, ".kubb/standardSchema.ts");
1219
- const ssePath = importPath ?? node_path.default.resolve(root, ".kubb/sse.ts");
1220
- const stream = getEventStream(node);
1221
- const clientValueImports = (() => {
1222
- if (returnType === "plain") return ["client"];
1223
- if (returnType === "data") return ["client", "unwrapResult"];
1224
- return ["client", "withUnwrap"];
1225
- })();
1226
- const clientTypeImports = (() => {
1227
- if (stream) return {
1228
- plain: ["Options", "SuccessOf"],
1229
- data: ["SuccessOf"],
1230
- full: ["SuccessOf", "Unwrappable"]
1231
- }[returnType];
1232
- if (returnType === "plain") return ["Options", "RequestResult"];
1233
- if (returnType === "data") return ["Options", "UnwrappedResult"];
1234
- return [
1235
- "Options",
1236
- "Unwrappable",
1237
- "RequestResult"
1238
- ];
1239
- })();
1240
- return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx.File, {
1241
- baseName: meta.file.baseName,
1242
- path: meta.file.path,
1243
- meta: meta.file.meta,
1244
- banner: resolver.default.banner(ctx.meta, {
1245
- output,
1246
- config,
1247
- file: {
1248
- path: meta.file.path,
1249
- baseName: meta.file.baseName
1250
- }
1251
- }),
1252
- footer: resolver.default.footer(ctx.meta, {
1253
- output,
1254
- config,
1255
- file: {
1256
- path: meta.file.path,
1257
- baseName: meta.file.baseName
1258
- }
1259
- }),
1260
- children: [
1261
- /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
1262
- name: clientValueImports,
1263
- root: clientRoot,
1264
- path: clientPath
1265
- }),
1266
- /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
1267
- name: clientTypeImports,
1268
- root: clientRoot,
1269
- path: clientPath,
1270
- isTypeOnly: true
1271
- }),
1272
- stream && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
1273
- name: ["toEventStream"],
1274
- root: clientRoot,
1275
- path: ssePath
1276
- }),
1277
- stream && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
1278
- name: buildEventStreamImports({
1279
- returnType,
1280
- typed: stream === "event"
1281
- }),
1282
- root: clientRoot,
1283
- path: ssePath,
1284
- isTypeOnly: true
1285
- }),
1286
- meta.fileTypes && importedTypeNames.length > 0 && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
1287
- name: Array.from(new Set(importedTypeNames)),
1288
- root: meta.file.path,
1289
- path: meta.fileTypes.path,
1290
- isTypeOnly: true
1291
- }),
1292
- meta.fileZod && importedZodNames.length > 0 && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
1293
- name: importedZodNames,
1294
- root: meta.file.path,
1295
- path: meta.fileZod.path
1296
- }),
1297
- validatorHooks.headers && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
1298
- name: ["toHeadersStandardSchema"],
1299
- root: clientRoot,
1300
- path: standardSchemaPath
1301
- }),
1302
- /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(Operation, {
1303
- name: meta.name,
1304
- node,
1305
- types,
1306
- validatorHooks,
1307
- returnType,
1308
- throwOnErrorDefault,
1309
- security
1310
- })
1311
- ]
1312
- });
1313
- }
1314
- });
1315
- }
1316
- // ../../internals/client/src/components/SdkClient.tsx
1317
- /**
1318
- * Builds one instance method of a generated SDK class; a per-call `options.client` overrides `this.client`.
1319
- */
1320
- function buildSdkMethod({ node, name, types, validatorHooks, security, returnType, throwOnErrorDefault }) {
1321
- if (!_kubb_kit.ast.isHttpOperationNode(node)) return "";
1322
- const body = buildOperationBody({
1323
- node,
1324
- types,
1325
- validatorHooks,
1326
- security,
1327
- returnType,
1328
- throwOnErrorDefault
1329
- });
1330
- const generics = body.generics.length ? `<${body.generics.join(", ")}>` : "";
1331
- const jsdoc = buildJSDoc(buildOperationComments(node, {
1332
- link: "urlPath",
1333
- linkPosition: "beforeDeprecated",
1334
- splitLines: true
1335
- }));
1336
- const methodBody = [
1337
- body.mergeContentType ? "const { client: request = this.client, contentType, ...config } = options" : "const { client: request = this.client, ...config } = options",
1338
- "",
1339
- body.statement
1340
- ].map((line) => line ? ` ${line}` : "").join("\n");
1341
- return `${jsdoc} public ${name}${generics}(${body.paramsSignature}): ${body.returnType} {\n${methodBody}\n }`;
1342
- }
1343
- /**
1344
- * Renders one instance class per tag with one method per operation. The constructor takes a client
1345
- * config object and builds its own client through `createClient`, so each environment is a separate
1346
- * instance: `const api = new PetClient({ baseURL }); api.getPetById(...)`. A per-call `client` option
1347
- * still overrides the instance client for a one-off call.
1348
- */
1349
- function SdkClient({ name, operations, returnType, throwOnErrorDefault }) {
1350
- const methods = operations.map(({ node, name: methodName, types, validatorHooks, security }) => buildSdkMethod({
1351
- node,
1352
- name: methodName,
1353
- types,
1354
- validatorHooks,
1355
- security,
1356
- returnType,
1357
- throwOnErrorDefault
1358
- }));
1359
- const classCode = `export class ${name} {\n${[
1360
- " private readonly client: ClientInstance",
1361
- "",
1362
- " constructor(config: ClientConfig = {}) {",
1363
- " this.client = createClient(config)",
1364
- " }"
1365
- ].join("\n")}\n\n${methods.join("\n\n")}\n}`;
1366
- return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
1367
- name,
1368
- isExportable: true,
1369
- isIndexable: true,
1370
- children: classCode
1371
- });
1372
- }
1373
- // ../../internals/client/src/components/SdkFacade.tsx
1374
- /**
1375
- * Renders a composed root SDK class that instantiates every tag client from one shared config, so
1376
- * `new PetStore({ baseURL }).petClient.getPetById(...)` reaches an operation through a single entry
1377
- * point bound to one environment. The per-tag clients are read-only fields built in the constructor.
1378
- */
1379
- function SdkFacade({ name, members }) {
1380
- const fields = members.map((member) => ` readonly ${member.propName}: ${member.className}`);
1381
- const assignments = members.map((member) => ` this.${member.propName} = new ${member.className}(config)`);
1382
- const classCode = `export class ${name} {\n${[
1383
- ...fields,
1384
- "",
1385
- " constructor(config: ClientConfig = {}) {",
1386
- ...assignments,
1387
- " }"
1388
- ].join("\n")}\n}`;
1389
- return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
1390
- name,
1391
- isExportable: true,
1392
- isIndexable: true,
1393
- children: classCode
1394
- });
1395
- }
1396
- // ../../internals/client/src/generators/sdkGenerator.tsx
1397
- function resolveTypeImportNames(node, types) {
1398
- return [types.response.options(node), types.response.responses(node)];
1399
- }
1400
- /**
1401
- * Groups operations into one controller per tag. Operations without a tag fall back to a single
1402
- * `Client`/`ApiClient` controller, matching the resolver's default naming.
1403
- */
1404
- function buildControllers(nodes, ctx, types, validatorEnabled) {
1405
- const { driver, resolver, root } = ctx;
1406
- const { output, group, validator } = ctx.options;
1407
- const pluginZod = validatorEnabled ? driver.getPlugin(_kubb_plugin_zod.pluginZodName) : null;
1408
- const zodResolver = pluginZod ? driver.getResolver(_kubb_plugin_zod.pluginZodName) : null;
1409
- const document = ctx.adapter.document;
1410
- function buildOperationData(node) {
1411
- const typeFile = types.resolver.file({
1412
- ...operationFileEntry(node, node.operationId),
1413
- root,
1414
- output: types.output ?? output,
1415
- group: types.group
1416
- });
1417
- const zodFile = zodResolver && pluginZod?.options ? zodResolver.file({
1418
- ...operationFileEntry(node, node.operationId),
1419
- root,
1420
- output: pluginZod.options?.output ?? output,
1421
- group: pluginZod.options?.group ?? void 0
1422
- }) : null;
1423
- const security = _kubb_kit.ast.isHttpOperationNode(node) ? getOperationSecurity({
1424
- document,
1425
- method: node.method,
1426
- path: node.path
1427
- }) : void 0;
1428
- const validatorHooks = zodResolver ? buildValidatorHooks({
1429
- node,
1430
- validator,
1431
- zodResolver
1432
- }) : null;
1433
- const name = resolver.name(node.operationId);
1434
- return {
1435
- node,
1436
- name: resolver.resolveName({
1437
- key: operationKey(node),
1438
- name
1439
- }),
1440
- types,
1441
- typeFile,
1442
- zodFile,
1443
- validatorHooks,
1444
- security
1445
- };
1446
- }
1447
- return nodes.reduce((acc, operationNode) => {
1448
- if (!_kubb_kit.ast.isHttpOperationNode(operationNode)) return acc;
1449
- const tag = operationNode.tags[0];
1450
- const name = tag ? ensureValidVarName(group?.name?.({ group: (0, _kubb_kit.camelCase)(tag) }) ?? resolver.groupName(tag)) : resolver.className("ApiClient");
1451
- const file = resolver.file({
1452
- name,
1453
- extname: ".ts",
1454
- tag,
1455
- root,
1456
- output,
1457
- group: group ?? void 0
1458
- });
1459
- const operationData = buildOperationData(operationNode);
1460
- const previous = acc.find((item) => item.file.path === file.path);
1461
- if (previous) previous.operations.push(operationData);
1462
- else acc.push({
1463
- name,
1464
- tag,
1465
- file,
1466
- operations: [operationData]
1467
- });
1468
- return acc;
1469
- }, []);
1470
- }
1471
- function collectImportsByFile(ops, pick) {
1472
- const namesByPath = /* @__PURE__ */ new Map();
1473
- const filesByPath = /* @__PURE__ */ new Map();
1474
- ops.forEach((op) => {
1475
- const { file, names } = pick(op);
1476
- if (!file || names.length === 0) return;
1477
- if (!namesByPath.has(file.path)) namesByPath.set(file.path, /* @__PURE__ */ new Set());
1478
- const set = namesByPath.get(file.path);
1479
- names.forEach((n) => set.add(n));
1480
- filesByPath.set(file.path, file);
1481
- });
1482
- return {
1483
- namesByPath,
1484
- filesByPath
1485
- };
1486
- }
1487
- /**
1488
- * Builds the class-based SDK generator for a client plugin (`@kubb/plugin-fetch`,
1489
- * `@kubb/plugin-axios`). Only registered when `sdk` is set; otherwise the plugin keeps its
1490
- * standalone per-operation functions.
1491
- *
1492
- * Every tag client is an instance class whose constructor takes a client config and builds its own
1493
- * client, so each environment is a separate instance. With `sdk.mode: 'tag'` (the default) it
1494
- * emits one class per tag and, when `sdk.name` is set, a composed root that instantiates every tag
1495
- * client. With `sdk.mode: 'flat'` it emits one class named by `sdk.name`, with every operation as a
1496
- * direct method.
1497
- *
1498
- * `sse` is the Server-Sent Events runtime template, copied into `.kubb/sse.ts` only for a document with a
1499
- * `text/event-stream` operation.
1500
- */
1501
- function createSdkGenerator({ sse } = {}) {
1502
- return (0, _kubb_kit.defineGenerator)({
1503
- name: "sdk",
1504
- renderer: _kubb_renderer_jsx.jsxRenderer,
1505
- operations(nodes, ctx) {
1506
- const { config, resolver, root } = ctx;
1507
- const { output, group, validator, returnType, throwOnErrorDefault, sdk } = ctx.options;
1508
- if (!sdk) return null;
1509
- if (sdk.mode === "tag" && output.mode === "file") throw new _kubb_kit.Diagnostics.Error({
1510
- code: _kubb_kit.Diagnostics.code.invalidPluginOptions,
1511
- severity: "error",
1512
- message: `Plugin "${ctx.plugin.name}" resolves \`output.mode\` to 'file' but also configures \`sdk.mode: 'tag'\`.`,
1513
- help: "A single-file output has nothing to split tag classes into. Set `sdk.mode: 'flat'` to emit one class into that file, or give `output.path` an extensionless directory name (or set `output.mode: 'directory'` explicitly) so each tag gets its own file.",
1514
- location: { kind: "config" },
1515
- plugin: ctx.plugin.name
1516
- });
1517
- const types = resolveOperationTypes(ctx.driver, ctx.plugin.name);
1518
- const validatorEnabled = isValidatorEnabled(validator);
1519
- const controllers = buildControllers(nodes, ctx, types, validatorEnabled);
1520
- const clientPath = node_path.default.resolve(root, ".kubb/client.ts");
1521
- const standardSchemaPath = node_path.default.resolve(root, ".kubb/standardSchema.ts");
1522
- const ssePath = node_path.default.resolve(root, ".kubb/sse.ts");
1523
- const banner = (file) => resolver.default.banner(ctx.meta, {
1524
- output,
1525
- config,
1526
- file: {
1527
- path: file.path,
1528
- baseName: file.baseName
1529
- }
1530
- });
1531
- const footer = (file) => resolver.default.footer(ctx.meta, {
1532
- output,
1533
- config,
1534
- file: {
1535
- path: file.path,
1536
- baseName: file.baseName
1537
- }
1538
- });
1539
- const renderClassFile = (className, file, ops) => {
1540
- const { namesByPath: typeNamesByPath, filesByPath: typeFilesByPath } = collectImportsByFile(ops, (op) => ({
1541
- file: op.typeFile,
1542
- names: resolveTypeImportNames(op.node, op.types)
1543
- }));
1544
- const { namesByPath: zodNamesByPath, filesByPath: zodFilesByPath } = validatorEnabled ? collectImportsByFile(ops, (op) => ({
1545
- file: op.zodFile,
1546
- names: op.validatorHooks?.importedZodNames ?? []
1547
- })) : {
1548
- namesByPath: /* @__PURE__ */ new Map(),
1549
- filesByPath: /* @__PURE__ */ new Map()
1550
- };
1551
- const shapes = new Set(ops.map((op) => getEventStream(op.node)).filter(Boolean));
1552
- const hasEventStream = shapes.size > 0;
1553
- const hasResult = ops.some((op) => !isEventStream(op.node));
1554
- return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx.File, {
1555
- baseName: file.baseName,
1556
- path: file.path,
1557
- meta: file.meta,
1558
- banner: banner(file),
1559
- footer: footer(file),
1560
- children: [
1561
- /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
1562
- name: ["createClient", returnType === "data" ? "unwrapResult" : "withUnwrap"],
1563
- root: file.path,
1564
- path: clientPath
1565
- }),
1566
- /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
1567
- name: [
1568
- "ClientConfig",
1569
- "ClientInstance",
1570
- "Options",
1571
- ...returnType === "data" ? [] : ["Unwrappable"],
1572
- ...hasResult ? [returnType === "data" ? "UnwrappedResult" : "RequestResult"] : [],
1573
- ...hasEventStream ? ["SuccessOf"] : []
1574
- ],
1575
- root: file.path,
1576
- path: clientPath,
1577
- isTypeOnly: true
1578
- }),
1579
- hasEventStream && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
1580
- name: ["toEventStream"],
1581
- root: file.path,
1582
- path: ssePath
1583
- }),
1584
- hasEventStream && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
1585
- name: buildEventStreamImports({
1586
- returnType,
1587
- typed: shapes.has("event")
1588
- }),
1589
- root: file.path,
1590
- path: ssePath,
1591
- isTypeOnly: true
1592
- }),
1593
- validator === "zod" && ops.some((op) => op.node.requestBody?.content?.[0]?.schema != null) && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
1594
- name: ["z"],
1595
- path: "zod",
1596
- isTypeOnly: true
1597
- }),
1598
- Array.from(typeNamesByPath.entries()).map(([filePath, set]) => /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
1599
- name: Array.from(set),
1600
- root: file.path,
1601
- path: typeFilesByPath.get(filePath).path,
1602
- isTypeOnly: true
1603
- }, filePath)),
1604
- validatorEnabled && Array.from(zodNamesByPath.entries()).map(([filePath, set]) => /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
1605
- name: Array.from(set),
1606
- root: file.path,
1607
- path: zodFilesByPath.get(filePath).path
1608
- }, filePath)),
1609
- ops.some((op) => op.validatorHooks?.headers) && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
1610
- name: ["toHeadersStandardSchema"],
1611
- root: file.path,
1612
- path: standardSchemaPath
1613
- }),
1614
- /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(SdkClient, {
1615
- name: className,
1616
- operations: ops,
1617
- returnType,
1618
- throwOnErrorDefault
1619
- })
1620
- ]
1621
- }, file.path);
1622
- };
1623
- const renderFacadeFile = (name) => {
1624
- const sdkFile = resolver.file({
1625
- name,
1626
- extname: ".ts",
1627
- root,
1628
- output,
1629
- group: group ?? void 0
1630
- });
1631
- const members = controllers.map(({ name, tag }) => ({
1632
- className: name,
1633
- propName: resolver.propertyName(tag ?? name)
1634
- }));
1635
- return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx.File, {
1636
- baseName: sdkFile.baseName,
1637
- path: sdkFile.path,
1638
- meta: sdkFile.meta,
1639
- banner: banner(sdkFile),
1640
- footer: footer(sdkFile),
1641
- children: [
1642
- /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
1643
- name: ["ClientConfig"],
1644
- root: sdkFile.path,
1645
- path: clientPath,
1646
- isTypeOnly: true
1647
- }),
1648
- controllers.map(({ name, file }) => /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
1649
- name: [name],
1650
- root: sdkFile.path,
1651
- path: file.path
1652
- }, name)),
1653
- /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(SdkFacade, {
1654
- name: resolver.className(name),
1655
- members
1656
- })
1657
- ]
1658
- }, sdkFile.path);
1659
- };
1660
- const files = sdk.mode === "flat" ? renderClassFile(resolver.className(sdk.name ?? "sdk"), resolver.file({
1661
- name: sdk.name ?? "sdk",
1662
- extname: ".ts",
1663
- root,
1664
- output,
1665
- group: group ?? void 0
1666
- }), controllers.flatMap((controller) => controller.operations)) : [...controllers.map(({ name, file, operations: ops }) => renderClassFile(name, file, ops)), sdk.name && renderFacadeFile(sdk.name)];
1667
- return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(StreamRuntime, {
1668
- nodes,
1669
- root,
1670
- sse,
1671
- baseURL: ctx.options.baseURL
1672
- }), files] });
1673
- }
1674
- });
1675
- }
1676
- // ../../internals/client/src/macros.ts
1677
- /**
1678
- * Macros the client plugins apply by default, ahead of any user macros. `macroDedupeUnion`
1679
- * drops repeated union members, keeping the generated response and error
1680
- * unions tidy. A plugin wires them with `ctx.setMacros([...defaultMacros, ...userMacros])`.
1681
- */
1682
- const defaultMacros = [_kubb_kit.macroDedupeUnion];
1683
- // ../../internals/client/src/resolver.ts
1684
- /**
1685
- * Default resolver shared by the client plugins. Functions use safe camelCase identifiers and
1686
- * files inherit the built-in casing; classes and tag groups use PascalCase.
1687
- *
1688
- * @example
1689
- * ```ts
1690
- * resolverClient.name('show pet by id') // 'showPetById'
1691
- * resolverClient.groupName('pet') // 'PetClient'
1692
- * ```
1693
- */
1694
- const resolverClient = (0, _kubb_kit.createResolver)({
1695
- pluginName: "plugin-contract-client",
1696
- name: resolveOperationName,
1697
- className(name) {
1698
- return ensureValidVarName((0, _kubb_kit.pascalCase)(name));
1699
- },
1700
- groupName(name) {
1701
- return ensureValidVarName((0, _kubb_kit.pascalCase)(`${name} Client`));
1702
- },
1703
- propertyName(name) {
1704
- return ensureValidVarName((0, _kubb_kit.camelCase)(name));
1705
- }
1706
- });
1707
- // src/templates.ts
1708
- const require$1 = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href);
1709
- /** Absolute path to the fetch client template, copied into `.kubb/client.ts`. */
1710
- const fetchClientTemplatePath = (0, node_url.fileURLToPath)(new URL("../templates/client.ts", require("url").pathToFileURL(__filename).href));
1711
- /**
1712
- * Absolute paths to the runtime templates `@kubb/plugin-client` ships for every client plugin, copied into `.kubb/core.ts`,
1713
- * `.kubb/serializers.ts`, `.kubb/standardSchema.ts`, and `.kubb/sse.ts`.
1714
- */
1715
- const coreTemplatePath = require$1.resolve("@kubb/plugin-client/templates/core.ts");
1716
- const serializersTemplatePath = require$1.resolve("@kubb/plugin-client/templates/serializers.ts");
1717
- const standardSchemaTemplatePath = require$1.resolve("@kubb/plugin-client/templates/standardSchema.ts");
1718
- const sseTemplatePath = require$1.resolve("@kubb/plugin-client/templates/sse.ts");
1719
- // src/generators/clientGenerator.tsx
1720
- /**
1721
- * Built-in operation generator for `@kubb/plugin-fetch`. Emits one async function per OpenAPI
1722
- * operation using the shared `Operation` component: a grouped `<Name>Request` type and a function
1723
- * that forwards a single `options` object to the bundled `client` and returns the `RequestResult`.
1724
- */
1725
- const clientGenerator = createClientGenerator("fetch", { sse: sseTemplatePath });
6
+ let _kubb_kit = require("@kubb/kit");
7
+ let _kubb_plugin_client = require("@kubb/plugin-client");
1726
8
  // kubb-extension.json
1727
9
  var compatibility = {
1728
- "kubb": ">=5.16.0",
10
+ "kubb": ">=5.18.4",
1729
11
  "node": ">=22.22"
1730
12
  };
1731
13
  // package.json
1732
- var version = "5.14.0-canary.20261109T125041";
14
+ var version = "6.0.0";
1733
15
  // src/plugin.ts
1734
16
  /**
1735
17
  * Canonical plugin name for `@kubb/plugin-fetch`. Used for driver lookups and cross-plugin
@@ -1765,60 +47,18 @@ const pluginFetch = (0, _kubb_kit.defineExtension)({
1765
47
  version,
1766
48
  compatibility
1767
49
  },
1768
- dependencies: (options) => ({
1769
- [_kubb_plugin_ts.pluginTsName]: { optional: true },
1770
- [_kubb_plugin_zod.pluginZodName]: { optional: !isValidatorEnabled(options.validator) }
1771
- }),
50
+ dependencies: _kubb_plugin_client.clientDependencies,
1772
51
  setup(options) {
1773
- const config = (0, _kubb_kit.useConfig)();
1774
- const { output = {
1775
- path: "clients",
1776
- barrel: { type: "named" }
1777
- }, exclude = [], include, override = [], baseURL, throwOnErrorDefault = true, validator = false, returnType = "full", group, sdk, resolver: userResolver } = options;
1778
- const resolved = {
1779
- output,
1780
- exclude,
1781
- include,
1782
- override,
1783
- group: createGroupConfig(group),
1784
- baseURL,
1785
- throwOnErrorDefault,
1786
- validator,
1787
- returnType,
1788
- sdk: sdk ? {
1789
- mode: sdk.mode ?? "tag",
1790
- name: sdk.name
1791
- } : void 0,
1792
- resolver: userResolver ? _kubb_kit.Resolver.merge(resolverClient, userResolver) : resolverClient
1793
- };
1794
- (0, _kubb_kit.setResolver)(resolved.resolver);
1795
- (0, _kubb_kit.setMacros)([...defaultMacros, ...options.macros ?? []]);
1796
- (0, _kubb_kit.addGenerator)(resolved.sdk ? createSdkGenerator({ sse: sseTemplatePath }) : clientGenerator);
1797
- const root = node_path.default.resolve(config.root, config.output.path);
1798
- (0, _kubb_kit.injectFile)({
1799
- baseName: "serializers.ts",
1800
- path: node_path.default.resolve(root, ".kubb/serializers.ts"),
1801
- copy: serializersTemplatePath
1802
- });
1803
- (0, _kubb_kit.injectFile)({
1804
- baseName: "core.ts",
1805
- path: node_path.default.resolve(root, ".kubb/core.ts"),
1806
- copy: coreTemplatePath
1807
- });
1808
- (0, _kubb_kit.injectFile)({
1809
- baseName: "client.ts",
1810
- path: node_path.default.resolve(root, ".kubb/client.ts"),
1811
- copy: fetchClientTemplatePath
1812
- });
1813
- (0, _kubb_kit.injectFile)({
1814
- baseName: "standardSchema.ts",
1815
- path: node_path.default.resolve(root, ".kubb/standardSchema.ts"),
1816
- copy: standardSchemaTemplatePath
52
+ const resolved = (0, _kubb_plugin_client.resolveClientOptions)(options);
53
+ (0, _kubb_plugin_client.setupClient)({
54
+ name: "fetch",
55
+ resolved,
56
+ macros: options.macros,
57
+ client: (0, node_url.fileURLToPath)(new URL("../templates/client.ts", require("url").pathToFileURL(__filename).href))
1817
58
  });
1818
59
  return resolved;
1819
60
  }
1820
61
  });
1821
- exports.clientGenerator = clientGenerator;
1822
62
  exports.default = pluginFetch;
1823
63
  exports.pluginFetch = pluginFetch;
1824
64
  exports.pluginFetchName = pluginFetchName;