@kubb/plugin-fetch 5.13.0-canary.20261105T105941 → 5.13.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/client-Dn80AjdR.d.ts +39 -0
- package/dist/core-D6FAGTsL.d.ts +2 -0
- package/dist/index.cjs +384 -226
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +385 -227
- package/dist/index.js.map +1 -1
- package/dist/templates/client.d.ts +3 -0
- package/dist/templates/core.d.ts +2 -0
- package/dist/templates/fetch.d.ts +5 -405
- package/dist/templates/serializers.d.ts +1 -179
- package/dist/templates/standardSchema.d.ts +1 -63
- package/docs/guides/server-sent-events.md +281 -45
- package/kubb-extension.json +1 -1
- package/package.json +8 -7
- package/src/generators/clientGenerator.tsx +2 -1
- package/src/plugin.ts +9 -5
- package/src/templates.ts +10 -7
- package/templates/client.ts +111 -0
- package/templates/core.ts +2 -0
- package/templates/fetch.ts +2 -913
- package/templates/serializers.ts +2 -481
- package/templates/standardSchema.ts +2 -109
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import { Diagnostics, Resolver, Url, addGenerator, ast, camelCase, createResolver, defineExtension, defineGenerator, injectFile, macroDedupeUnion, pascalCase, setMacros, setResolver, useConfig } from "@kubb/kit";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import { pluginZodName } from "@kubb/plugin-zod";
|
|
4
5
|
import { File, Function, jsxRenderer } from "@kubb/renderer-jsx";
|
|
@@ -85,20 +86,33 @@ function getPrimarySuccessContentType(node) {
|
|
|
85
86
|
return contentTypes[0].split(";")[0].trim().toLowerCase();
|
|
86
87
|
}
|
|
87
88
|
/**
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
|
|
89
|
+
* The `text/event-stream` content of the primary success response, when it is the only content type. A response that also
|
|
90
|
+
* declares another type stays a normal call with its query hooks.
|
|
91
|
+
*/
|
|
92
|
+
function getEventStreamContent(node) {
|
|
93
|
+
return getPrimarySuccessContentType(node) === "text/event-stream" ? getPrimarySuccessResponse(node)?.content?.[0] : void 0;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Whether an operation streams its primary success response as Server-Sent Events (`text/event-stream`). The client
|
|
97
|
+
* generator uses this to return a typed event stream instead of a one-shot `RequestResult`.
|
|
91
98
|
*/
|
|
92
99
|
function isEventStream(node) {
|
|
93
|
-
return
|
|
100
|
+
return getEventStreamContent(node) !== void 0;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* How the document types a `text/event-stream` response, as the adapter read it from `itemSchema`: `event` when each item is
|
|
104
|
+
* the parsed event with its own `event` and `data`, `data` when it is only the payload. Returns `null` without an event stream.
|
|
105
|
+
*/
|
|
106
|
+
function getEventStream(node) {
|
|
107
|
+
const content = getEventStreamContent(node);
|
|
108
|
+
return content ? content.stream?.shape ?? "data" : null;
|
|
94
109
|
}
|
|
95
110
|
/**
|
|
96
111
|
* Derives the default `responseType` for an operation from its primary success response.
|
|
97
112
|
*
|
|
98
|
-
* Returns a value only when that response declares a single non-JSON content type. `text/event-stream`
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
* leaving the runtime client's `Content-Type` auto-detection in charge.
|
|
113
|
+
* Returns a value only when that response declares a single non-JSON content type. `text/event-stream` maps to
|
|
114
|
+
* `'stream'`, `application/octet-stream`, `application/pdf`, `image/*`, `audio/*` and `video/*` map to `'blob'`, and
|
|
115
|
+
* other `text/*` to `'text'`. Otherwise `undefined`, leaving the runtime client's `Content-Type` auto-detection in charge.
|
|
102
116
|
*/
|
|
103
117
|
function getResponseType(node) {
|
|
104
118
|
const baseType = getPrimarySuccessContentType(node);
|
|
@@ -158,6 +172,22 @@ function buildOperationComments(node, options = {}) {
|
|
|
158
172
|
}
|
|
159
173
|
const operationParameterGroupsByNode = /* @__PURE__ */ new WeakMap();
|
|
160
174
|
/**
|
|
175
|
+
* An OpenAPI 3.2 `querystring` parameter is the whole query string, so a form-encoded object becomes one query parameter
|
|
176
|
+
* per property, typed and serialized like any other.
|
|
177
|
+
* Another content type, such as JSON, stays one parameter named after it, and the runtime sends its value as the whole query string.
|
|
178
|
+
*/
|
|
179
|
+
function spreadQuerystring(param) {
|
|
180
|
+
const schema = param.schema.type === "ref" ? param.schema.schema : param.schema;
|
|
181
|
+
const formEncoded = !param.contentType || param.contentType.split(";")[0].trim().toLowerCase() === "application/x-www-form-urlencoded";
|
|
182
|
+
if (schema?.type !== "object" || !formEncoded) return [param];
|
|
183
|
+
return schema.properties.map((property) => ast.factory.createParameter({
|
|
184
|
+
name: property.name,
|
|
185
|
+
in: "query",
|
|
186
|
+
schema: property.schema,
|
|
187
|
+
required: param.required && property.required
|
|
188
|
+
}));
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
161
191
|
* Groups an operation's parameters by location (`path`/`query`/`header`/`cookie`), deduping each
|
|
162
192
|
* group by name. Every plugin generator visiting the same `OperationNode` shares one AST instance
|
|
163
193
|
* (see `KubbDriver`), so the result is cached per node to avoid re-filtering and re-deduping the
|
|
@@ -166,17 +196,18 @@ const operationParameterGroupsByNode = /* @__PURE__ */ new WeakMap();
|
|
|
166
196
|
function getOperationParameters(node) {
|
|
167
197
|
const cached = operationParameterGroupsByNode.get(node);
|
|
168
198
|
if (cached) return cached;
|
|
169
|
-
const
|
|
199
|
+
const dedupe = (params) => {
|
|
170
200
|
const seen = /* @__PURE__ */ new Set();
|
|
171
|
-
return
|
|
172
|
-
if (
|
|
201
|
+
return params.filter((param) => {
|
|
202
|
+
if (seen.has(param.name)) return false;
|
|
173
203
|
seen.add(param.name);
|
|
174
204
|
return true;
|
|
175
205
|
});
|
|
176
206
|
};
|
|
207
|
+
const group = (location) => dedupe(node.parameters.filter((param) => param.in === location));
|
|
177
208
|
const groups = {
|
|
178
209
|
path: group("path"),
|
|
179
|
-
query: group("query"),
|
|
210
|
+
query: dedupe([...group("query"), ...group("querystring").flatMap(spreadQuerystring)]),
|
|
180
211
|
header: group("header"),
|
|
181
212
|
cookie: group("cookie")
|
|
182
213
|
};
|
|
@@ -463,6 +494,114 @@ function buildZodErrorParse(node, zodResolver) {
|
|
|
463
494
|
if (!node.responses.some((res) => !isSuccessStatusCode(res.statusCode) && res.content?.some((entry) => entry.schema))) return null;
|
|
464
495
|
return zodResolver.response.error?.(node) || null;
|
|
465
496
|
}
|
|
497
|
+
// ../../internals/client/src/builders/generics.ts
|
|
498
|
+
/**
|
|
499
|
+
* Builds the `RequestResult` generic arguments for one operation: the per-status responses record
|
|
500
|
+
* plus the per-call `ThrowOnError` flag. `SuccessOf` / `ErrorOf` split the record inside the
|
|
501
|
+
* runtime, so this only names the record and threads `ThrowOnError`.
|
|
502
|
+
*
|
|
503
|
+
* @example
|
|
504
|
+
* `buildRequestResultGenerics({ node, types }) // 'AddPetResponses, ThrowOnError'`
|
|
505
|
+
*/
|
|
506
|
+
function buildRequestResultGenerics({ node, types }) {
|
|
507
|
+
return `${types.response.responses(node)}, ThrowOnError`;
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* Builds the full return type an operation's function signature uses: `Unwrappable<RequestResult>`
|
|
511
|
+
* for the default `returnType: 'full'`, already a promise so no further wrapping is needed, a plain
|
|
512
|
+
* `Promise<RequestResult>` for the internal `'plain'` shape, or a
|
|
513
|
+
* `Promise` of the runtime's `UnwrappedResult` when `returnType: 'data'` narrows a resolved call
|
|
514
|
+
* down to the bare success body.
|
|
515
|
+
*
|
|
516
|
+
* @example
|
|
517
|
+
* `buildResultType({ node, types, returnType: 'data' }) // 'Promise<UnwrappedResult<AddPetResponses, ThrowOnError>>'`
|
|
518
|
+
*/
|
|
519
|
+
function buildResultType({ node, types, returnType }) {
|
|
520
|
+
const generics = buildRequestResultGenerics({
|
|
521
|
+
node,
|
|
522
|
+
types
|
|
523
|
+
});
|
|
524
|
+
if (returnType === "data") return `Promise<UnwrappedResult<${generics}>>`;
|
|
525
|
+
if (returnType === "plain") return `Promise<RequestResult<${generics}>>`;
|
|
526
|
+
return `Unwrappable<RequestResult<${generics}>>`;
|
|
527
|
+
}
|
|
528
|
+
// ../../internals/client/src/builders/returnStatement.ts
|
|
529
|
+
/**
|
|
530
|
+
* Builds the return statement of a generated operation function. With the default
|
|
531
|
+
* `returnType: 'full'` the runtime call already resolves to `{ data, error, request, response }`.
|
|
532
|
+
* The generated code casts that result to the operation's `RequestResult`, then wraps it with
|
|
533
|
+
* `withUnwrap`, so the caller can `await` it directly or call `.unwrap()` for the bare success
|
|
534
|
+
* body. With `returnType: 'data'` it instead routes the call through the runtime's `unwrapResult`,
|
|
535
|
+
* which narrows the resolved value down to the bare success body the same way `RequestResult`
|
|
536
|
+
* already does, using the plugin default when the call leaves `throwOnError` unset.
|
|
537
|
+
* With `returnType: 'plain'` it returns the runtime call as is, cast to `RequestResult`, with no helper.
|
|
538
|
+
*
|
|
539
|
+
* Cast first, wrap second, for the `'full'` path. That order keeps `withUnwrap`'s generic inferred
|
|
540
|
+
* as `RequestResult` instead of the runtime's own internal result type. Casting an `Unwrappable<A>`
|
|
541
|
+
* straight to `Unwrappable<B>` does not work: the `.then` overload stays pinned to `A`, and `as`
|
|
542
|
+
* rejects that two-generic swap even where `A` and `B` on their own would satisfy it.
|
|
543
|
+
*
|
|
544
|
+
* @example
|
|
545
|
+
* `return withUnwrap(request({ method: 'POST', url: '/pet', ...config }) as Promise<RequestResult<AddPetResponses, ThrowOnError>>)`
|
|
546
|
+
* @example
|
|
547
|
+
* `return unwrapResult(request({ method: 'POST', url: '/pet', ...config }), config.throwOnError ?? false) as Promise<UnwrappedResult<AddPetResponses, ThrowOnError>>`
|
|
548
|
+
* @example
|
|
549
|
+
* `return request({ method: 'POST', url: '/pet', ...config }) as Promise<RequestResult<AddPetResponses, ThrowOnError>>`
|
|
550
|
+
*/
|
|
551
|
+
function buildReturnStatement({ node, types, callConfig, returnType, throwOnErrorDefault }) {
|
|
552
|
+
const request = returnType !== "plain" && hasRequestContentTypeChoice(node) ? `request<${types.response.options(node)}['body']>` : "request";
|
|
553
|
+
if (returnType === "data") return `return unwrapResult(${request}(${callConfig}), config.throwOnError ?? ${throwOnErrorDefault}) as ${buildResultType({
|
|
554
|
+
node,
|
|
555
|
+
types,
|
|
556
|
+
returnType
|
|
557
|
+
})}`;
|
|
558
|
+
if (returnType === "plain") return `return ${request}(${callConfig}) as Promise<RequestResult<${buildRequestResultGenerics({
|
|
559
|
+
node,
|
|
560
|
+
types
|
|
561
|
+
})}>>`;
|
|
562
|
+
return `return withUnwrap(${request}(${callConfig}) as Promise<RequestResult<${buildRequestResultGenerics({
|
|
563
|
+
node,
|
|
564
|
+
types
|
|
565
|
+
})}>>)`;
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* Builds the return type and statement of a `text/event-stream` operation. The item type is `TypedEvent<...>` when each item
|
|
569
|
+
* declares its own `event` and `data`, and otherwise the payload type, which `EventStreamResult` wraps in `ServerSentEvent`. The call's
|
|
570
|
+
* promise goes through `toEventStream` with the `client` for its defaults, the call's `config`, the shape and the per-event
|
|
571
|
+
* validator. A `returnType: 'plain'` client receives only the promise,
|
|
572
|
+
* `toEventStream(request(config))`, and keeps its response validator in the call config.
|
|
573
|
+
*/
|
|
574
|
+
function buildEventStreamReturn({ node, types, callConfig, returnType, validatorHooks, throwOnErrorDefault }) {
|
|
575
|
+
const shape = getEventStream(node) ?? "data";
|
|
576
|
+
const responses = types.response.responses(node);
|
|
577
|
+
const success = `SuccessOf<${responses}>`;
|
|
578
|
+
const eventType = shape === "event" ? `TypedEvent<${success}>` : success;
|
|
579
|
+
if (returnType === "plain") return {
|
|
580
|
+
returnType: `Promise<EventStreamResult<${eventType}>>`,
|
|
581
|
+
statement: `return toEventStream<${eventType}>(request(${callConfig}))`
|
|
582
|
+
};
|
|
583
|
+
const generics = `${responses}, ThrowOnError${shape === "event" ? `, ${eventType}` : ""}`;
|
|
584
|
+
const call = `toEventStream<${eventType}>(request(${callConfig}), { client: request, config, ${[`shape: '${shape}'`, validatorHooks?.response ? `validator: ${validatorHooks.response}` : null].filter(Boolean).join(", ")} })`;
|
|
585
|
+
if (returnType === "data") {
|
|
586
|
+
const result = `Promise<UnwrappedStreamResult<${generics}>>`;
|
|
587
|
+
return {
|
|
588
|
+
returnType: result,
|
|
589
|
+
statement: `return unwrapResult(${call}, config.throwOnError ?? ${throwOnErrorDefault}) as ${result}`
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
return {
|
|
593
|
+
returnType: `Unwrappable<StreamResult<${generics}>>`,
|
|
594
|
+
statement: `return withUnwrap(${call} as Promise<StreamResult<${generics}>>)`
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
/** The stream types an operation file imports: `StreamResult` and `StreamOptions`, `EventStreamResult` for a plain client, and `TypedEvent` for named events. */
|
|
598
|
+
function buildEventStreamImports({ returnType, typed }) {
|
|
599
|
+
return [...{
|
|
600
|
+
plain: ["EventStreamResult"],
|
|
601
|
+
full: ["StreamResult", "StreamOptions"],
|
|
602
|
+
data: ["UnwrappedStreamResult", "StreamOptions"]
|
|
603
|
+
}[returnType], ...typed ? ["TypedEvent"] : []];
|
|
604
|
+
}
|
|
466
605
|
// ../../internals/client/src/builders/security.ts
|
|
467
606
|
function serializeAuth(auth) {
|
|
468
607
|
const parts = [`type: '${auth.type}'`];
|
|
@@ -618,6 +757,7 @@ function serializeParameter(parameter) {
|
|
|
618
757
|
if (parameter.explode !== void 0) parts.push(`explode: ${parameter.explode}`);
|
|
619
758
|
if (parameter.in === "query" && parameter.allowReserved !== void 0) parts.push(`allowReserved: ${parameter.allowReserved}`);
|
|
620
759
|
if (parameter.in !== "path" && parameter.contentType) parts.push(`contentType: '${parameter.contentType}'`);
|
|
760
|
+
if (parameter.in === "querystring") parts.push("querystring: true");
|
|
621
761
|
return parts.length > 0 ? `{ ${parts.join(", ")} }` : null;
|
|
622
762
|
}
|
|
623
763
|
/**
|
|
@@ -660,10 +800,9 @@ function buildStyles({ node }) {
|
|
|
660
800
|
header: [],
|
|
661
801
|
cookie: []
|
|
662
802
|
};
|
|
663
|
-
for (const parameter of
|
|
803
|
+
for (const [location, parameters] of Object.entries(getOperationParameters(node))) for (const parameter of parameters) {
|
|
664
804
|
const literal = serializeParameter(parameter);
|
|
665
|
-
if (
|
|
666
|
-
groups[parameter.in].push(`${toKey(parameter.name)}: ${literal}`);
|
|
805
|
+
if (literal) groups[location].push(`${toKey(parameter.name)}: ${literal}`);
|
|
667
806
|
}
|
|
668
807
|
const entries = [...Object.keys(groups).filter((location) => groups[location].length > 0).map((location) => `${location}: { ${groups[location].join(", ")} }`), serializeBodyEncoding(node)].filter(Boolean);
|
|
669
808
|
return entries.length > 0 ? `{ ${entries.join(", ")} }` : null;
|
|
@@ -674,12 +813,20 @@ function buildStyles({ node }) {
|
|
|
674
813
|
* functions and the SDK methods. The `throwOnError` fallback is applied after the `...config` spread.
|
|
675
814
|
*
|
|
676
815
|
* `mergeContentType` is `true` when the caller must destructure `contentType` from `options`, and
|
|
677
|
-
* `eventStream` is `true` when the operation returns `text/event-stream`.
|
|
816
|
+
* `eventStream` is `true` when the operation returns `text/event-stream`. Unless `returnType` is `'plain'`, a
|
|
817
|
+
* stream's literal leaves the `response` validator to `toEventStream`, which runs it per event.
|
|
678
818
|
*/
|
|
679
|
-
function buildCallConfig({ node, validatorHooks, security, throwOnErrorDefault }) {
|
|
819
|
+
function buildCallConfig({ node, validatorHooks, security, throwOnErrorDefault, returnType }) {
|
|
820
|
+
const eventStream = isEventStream(node);
|
|
680
821
|
const securityLiteral = buildSecurityMetadata({ security });
|
|
681
822
|
const stylesLiteral = buildStyles({ node });
|
|
682
|
-
const validatorLiteral = buildValidatorLiteral(validatorHooks, [
|
|
823
|
+
const validatorLiteral = buildValidatorLiteral(validatorHooks, eventStream && returnType !== "plain" ? [
|
|
824
|
+
"request",
|
|
825
|
+
"path",
|
|
826
|
+
"query",
|
|
827
|
+
"headers",
|
|
828
|
+
"error"
|
|
829
|
+
] : [
|
|
683
830
|
"request",
|
|
684
831
|
"path",
|
|
685
832
|
"query",
|
|
@@ -702,88 +849,7 @@ function buildCallConfig({ node, validatorHooks, security, throwOnErrorDefault }
|
|
|
702
849
|
`throwOnError: config.throwOnError ?? ${throwOnErrorDefault}`
|
|
703
850
|
].filter(Boolean).join(", ")} }`,
|
|
704
851
|
mergeContentType,
|
|
705
|
-
eventStream
|
|
706
|
-
};
|
|
707
|
-
}
|
|
708
|
-
// ../../internals/client/src/builders/generics.ts
|
|
709
|
-
/**
|
|
710
|
-
* Builds the `RequestResult` generic arguments for one operation: the per-status responses record
|
|
711
|
-
* plus the per-call `ThrowOnError` flag. `SuccessOf` / `ErrorOf` split the record inside the
|
|
712
|
-
* runtime, so this only names the record and threads `ThrowOnError`.
|
|
713
|
-
*
|
|
714
|
-
* @example
|
|
715
|
-
* `buildRequestResultGenerics({ node, types }) // 'AddPetResponses, ThrowOnError'`
|
|
716
|
-
*/
|
|
717
|
-
function buildRequestResultGenerics({ node, types }) {
|
|
718
|
-
return `${types.response.responses(node)}, ThrowOnError`;
|
|
719
|
-
}
|
|
720
|
-
/**
|
|
721
|
-
* Builds the full return type an operation's function signature uses: `Unwrappable<RequestResult>`
|
|
722
|
-
* for the default `returnType: 'full'`, already a promise so no further wrapping is needed, a plain
|
|
723
|
-
* `Promise<RequestResult>` for the internal `'plain'` shape, or a
|
|
724
|
-
* `Promise` of the runtime's `UnwrappedResult` when `returnType: 'data'` narrows a resolved call
|
|
725
|
-
* down to the bare success body.
|
|
726
|
-
*
|
|
727
|
-
* @example
|
|
728
|
-
* `buildResultType({ node, types, returnType: 'data' }) // 'Promise<UnwrappedResult<AddPetResponses, ThrowOnError>>'`
|
|
729
|
-
*/
|
|
730
|
-
function buildResultType({ node, types, returnType }) {
|
|
731
|
-
const generics = buildRequestResultGenerics({
|
|
732
|
-
node,
|
|
733
|
-
types
|
|
734
|
-
});
|
|
735
|
-
if (returnType === "data") return `Promise<UnwrappedResult<${generics}>>`;
|
|
736
|
-
if (returnType === "plain") return `Promise<RequestResult<${generics}>>`;
|
|
737
|
-
return `Unwrappable<RequestResult<${generics}>>`;
|
|
738
|
-
}
|
|
739
|
-
// ../../internals/client/src/builders/returnStatement.ts
|
|
740
|
-
/**
|
|
741
|
-
* Builds the return statement of a generated operation function. With the default
|
|
742
|
-
* `returnType: 'full'` the runtime call already resolves to `{ data, error, request, response }`.
|
|
743
|
-
* The generated code casts that result to the operation's `RequestResult`, then wraps it with
|
|
744
|
-
* `withUnwrap`, so the caller can `await` it directly or call `.unwrap()` for the bare success
|
|
745
|
-
* body. With `returnType: 'data'` it instead routes the call through the runtime's `unwrapResult`,
|
|
746
|
-
* which narrows the resolved value down to the bare success body the same way `RequestResult`
|
|
747
|
-
* already does, using the plugin default when the call leaves `throwOnError` unset.
|
|
748
|
-
* With `returnType: 'plain'` it returns the runtime call as is, cast to `RequestResult`, with no helper.
|
|
749
|
-
*
|
|
750
|
-
* Cast first, wrap second, for the `'full'` path. That order keeps `withUnwrap`'s generic inferred
|
|
751
|
-
* as `RequestResult` instead of the runtime's own internal result type. Casting an `Unwrappable<A>`
|
|
752
|
-
* straight to `Unwrappable<B>` does not work: the `.then` overload stays pinned to `A`, and `as`
|
|
753
|
-
* rejects that two-generic swap even where `A` and `B` on their own would satisfy it.
|
|
754
|
-
*
|
|
755
|
-
* @example
|
|
756
|
-
* `return withUnwrap(request({ method: 'POST', url: '/pet', ...config }) as Promise<RequestResult<AddPetResponses, ThrowOnError>>)`
|
|
757
|
-
* @example
|
|
758
|
-
* `return unwrapResult(request({ method: 'POST', url: '/pet', ...config }), config.throwOnError ?? false) as Promise<UnwrappedResult<AddPetResponses, ThrowOnError>>`
|
|
759
|
-
* @example
|
|
760
|
-
* `return request({ method: 'POST', url: '/pet', ...config }) as Promise<RequestResult<AddPetResponses, ThrowOnError>>`
|
|
761
|
-
*/
|
|
762
|
-
function buildReturnStatement({ node, types, callConfig, returnType, throwOnErrorDefault }) {
|
|
763
|
-
const request = returnType !== "plain" && hasRequestContentTypeChoice(node) ? `request<${types.response.options(node)}['body']>` : "request";
|
|
764
|
-
if (returnType === "data") return `return unwrapResult(${request}(${callConfig}), config.throwOnError ?? ${throwOnErrorDefault}) as ${buildResultType({
|
|
765
|
-
node,
|
|
766
|
-
types,
|
|
767
|
-
returnType
|
|
768
|
-
})}`;
|
|
769
|
-
if (returnType === "plain") return `return ${request}(${callConfig}) as Promise<RequestResult<${buildRequestResultGenerics({
|
|
770
|
-
node,
|
|
771
|
-
types
|
|
772
|
-
})}>>`;
|
|
773
|
-
return `return withUnwrap(${request}(${callConfig}) as Promise<RequestResult<${buildRequestResultGenerics({
|
|
774
|
-
node,
|
|
775
|
-
types
|
|
776
|
-
})}>>)`;
|
|
777
|
-
}
|
|
778
|
-
/**
|
|
779
|
-
* Builds the return type and statement of an operation that returns `text/event-stream`: the call
|
|
780
|
-
* is wrapped in `toEventStream`, so the caller iterates the typed success events.
|
|
781
|
-
*/
|
|
782
|
-
function buildEventStreamReturn({ node, types, callConfig }) {
|
|
783
|
-
const eventType = `SuccessOf<${types.response.responses(node)}>`;
|
|
784
|
-
return {
|
|
785
|
-
returnType: `Promise<EventStreamResult<${eventType}>>`,
|
|
786
|
-
statement: `return toEventStream<${eventType}>(request(${callConfig}))`
|
|
852
|
+
eventStream
|
|
787
853
|
};
|
|
788
854
|
}
|
|
789
855
|
// ../../internals/client/src/builders/signature.ts
|
|
@@ -797,13 +863,14 @@ const declarationPrinter = functionPrinter({ mode: "declaration" });
|
|
|
797
863
|
* per-operation input type has to be emitted. Both names come from `types`, which is `plugin-ts` or
|
|
798
864
|
* `plugin-zod`'s inferred types (see `resolveOperationTypes`).
|
|
799
865
|
*/
|
|
800
|
-
function buildGroupedOptionsSignature({ node, types, returnType, throwOnErrorDefault }) {
|
|
866
|
+
function buildGroupedOptionsSignature({ node, types, returnType, throwOnErrorDefault, eventStream = false }) {
|
|
801
867
|
const optionsName = types.response.options(node);
|
|
868
|
+
const optionsType = `${eventStream && returnType !== "plain" ? "StreamOptions" : "Options"}<${optionsName}, ThrowOnError>`;
|
|
802
869
|
const { isOptional } = getRequestGroupOptionality(node);
|
|
803
870
|
return {
|
|
804
871
|
paramsSignature: declarationPrinter.print(createFunctionParameters({ params: [createFunctionParameter({
|
|
805
872
|
name: "options",
|
|
806
|
-
type:
|
|
873
|
+
type: optionsType,
|
|
807
874
|
...isOptional ? { default: "{}" } : {}
|
|
808
875
|
})] })) ?? "",
|
|
809
876
|
returnType: buildResultType({
|
|
@@ -814,37 +881,63 @@ function buildGroupedOptionsSignature({ node, types, returnType, throwOnErrorDef
|
|
|
814
881
|
generics: [`ThrowOnError extends boolean = ${throwOnErrorDefault}`]
|
|
815
882
|
};
|
|
816
883
|
}
|
|
817
|
-
// ../../internals/client/src/
|
|
884
|
+
// ../../internals/client/src/builders/operationBody.ts
|
|
818
885
|
/**
|
|
819
|
-
*
|
|
820
|
-
*
|
|
821
|
-
*
|
|
822
|
-
* the source.
|
|
886
|
+
* The pieces of a generated operation: its generics, `options` parameter, return type, return statement, and whether the
|
|
887
|
+
* body destructures `contentType` from `options`. Shared by the standalone functions and the SDK methods, so a
|
|
888
|
+
* `text/event-stream` operation is wired to `toEventStream` in one place.
|
|
823
889
|
*/
|
|
824
|
-
function
|
|
825
|
-
|
|
890
|
+
function buildOperationBody({ node, types, validatorHooks, security, returnType, throwOnErrorDefault }) {
|
|
891
|
+
const { callConfig, mergeContentType, eventStream } = buildCallConfig({
|
|
892
|
+
node,
|
|
893
|
+
validatorHooks,
|
|
894
|
+
security,
|
|
895
|
+
throwOnErrorDefault,
|
|
896
|
+
returnType
|
|
897
|
+
});
|
|
826
898
|
const signature = buildGroupedOptionsSignature({
|
|
827
899
|
node,
|
|
828
900
|
types,
|
|
829
901
|
returnType,
|
|
830
|
-
throwOnErrorDefault
|
|
902
|
+
throwOnErrorDefault,
|
|
903
|
+
eventStream
|
|
831
904
|
});
|
|
832
|
-
const
|
|
905
|
+
const stream = eventStream ? buildEventStreamReturn({
|
|
833
906
|
node,
|
|
907
|
+
types,
|
|
908
|
+
callConfig,
|
|
909
|
+
returnType,
|
|
834
910
|
validatorHooks,
|
|
835
|
-
security,
|
|
836
911
|
throwOnErrorDefault
|
|
837
|
-
});
|
|
838
|
-
const eventStreamReturn = eventStream ? buildEventStreamReturn({
|
|
839
|
-
node,
|
|
840
|
-
types,
|
|
841
|
-
callConfig
|
|
842
912
|
}) : null;
|
|
843
|
-
|
|
844
|
-
|
|
913
|
+
return {
|
|
914
|
+
generics: signature.generics,
|
|
915
|
+
paramsSignature: signature.paramsSignature,
|
|
916
|
+
returnType: stream?.returnType ?? signature.returnType,
|
|
917
|
+
statement: stream?.statement ?? buildReturnStatement({
|
|
918
|
+
node,
|
|
919
|
+
types,
|
|
920
|
+
callConfig,
|
|
921
|
+
returnType,
|
|
922
|
+
throwOnErrorDefault
|
|
923
|
+
}),
|
|
924
|
+
mergeContentType
|
|
925
|
+
};
|
|
926
|
+
}
|
|
927
|
+
// ../../internals/client/src/components/Operation.tsx
|
|
928
|
+
/**
|
|
929
|
+
* Renders one client operation: the grouped `<Name>Request` type and the function that forwards a
|
|
930
|
+
* single `options` object to the resolved client and returns the `Unwrappable<RequestResult>`. The
|
|
931
|
+
* type, signature, and call config are built with the AST factory, and only the jsx-renderer emits
|
|
932
|
+
* the source.
|
|
933
|
+
*/
|
|
934
|
+
function Operation({ name, node, types, validatorHooks, returnType, throwOnErrorDefault, security }) {
|
|
935
|
+
if (!ast.isHttpOperationNode(node)) return null;
|
|
936
|
+
const body = buildOperationBody({
|
|
845
937
|
node,
|
|
846
938
|
types,
|
|
847
|
-
|
|
939
|
+
validatorHooks,
|
|
940
|
+
security,
|
|
848
941
|
returnType,
|
|
849
942
|
throwOnErrorDefault
|
|
850
943
|
});
|
|
@@ -855,22 +948,53 @@ function Operation({ name, node, types, validatorHooks, returnType, throwOnError
|
|
|
855
948
|
children: /* @__PURE__ */ jsxs(Function, {
|
|
856
949
|
name,
|
|
857
950
|
export: true,
|
|
858
|
-
generics:
|
|
859
|
-
params:
|
|
860
|
-
returnType:
|
|
951
|
+
generics: body.generics,
|
|
952
|
+
params: body.paramsSignature,
|
|
953
|
+
returnType: body.returnType,
|
|
861
954
|
JSDoc: { comments: buildOperationComments(node, {
|
|
862
955
|
link: "urlPath",
|
|
863
956
|
linkPosition: "beforeDeprecated",
|
|
864
957
|
splitLines: true
|
|
865
958
|
}) },
|
|
866
959
|
children: [
|
|
867
|
-
mergeContentType ? "const { client: request = client, contentType, ...config } = options" : "const { client: request = client, ...config } = options",
|
|
960
|
+
body.mergeContentType ? "const { client: request = client, contentType, ...config } = options" : "const { client: request = client, ...config } = options",
|
|
868
961
|
/* @__PURE__ */ jsx("br", {}),
|
|
869
|
-
|
|
962
|
+
body.statement
|
|
870
963
|
]
|
|
871
964
|
})
|
|
872
965
|
});
|
|
873
966
|
}
|
|
967
|
+
// ../../internals/client/src/components/StreamRuntime.tsx
|
|
968
|
+
/**
|
|
969
|
+
* The `footer` of `.kubb/client.ts`: the `baseURL` set at generation time, and the `sse.ts` re-export when the document
|
|
970
|
+
* streams events, so `ServerSentEvent` and `toEventStream` stay importable from the client as in earlier releases.
|
|
971
|
+
*/
|
|
972
|
+
function buildClientFooter({ baseURL, sse }) {
|
|
973
|
+
const baseURLExpression = baseURL ? baseURL.includes("${") ? `\`${baseURL.replaceAll("`", "\\`")}\`` : JSON.stringify(baseURL) : void 0;
|
|
974
|
+
return [baseURLExpression ? `client.setConfig({ baseURL: ${baseURLExpression} })` : null, sse ? `export * from './sse.ts'` : null].filter(Boolean).join("\n") || void 0;
|
|
975
|
+
}
|
|
976
|
+
/**
|
|
977
|
+
* Writes the footer of the `.kubb/client.ts` the plugin injected, the one place it is built, and copies `sse.ts` into
|
|
978
|
+
* `.kubb/` only for a document with a `text/event-stream` operation, so a document without streams ships no stream runtime.
|
|
979
|
+
* `sse` is set by the plugins that ship the runtime, so a custom client from `@kubb/plugin-client` gets neither file.
|
|
980
|
+
*/
|
|
981
|
+
function StreamRuntime({ nodes, root, sse, baseURL }) {
|
|
982
|
+
if (!sse) return null;
|
|
983
|
+
const streams = nodes.some(isEventStream);
|
|
984
|
+
const footer = buildClientFooter({
|
|
985
|
+
baseURL,
|
|
986
|
+
sse: streams
|
|
987
|
+
});
|
|
988
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [streams && /* @__PURE__ */ jsx(File, {
|
|
989
|
+
baseName: "sse.ts",
|
|
990
|
+
path: path.resolve(root, ".kubb/sse.ts"),
|
|
991
|
+
copy: sse
|
|
992
|
+
}), footer && /* @__PURE__ */ jsx(File, {
|
|
993
|
+
baseName: "client.ts",
|
|
994
|
+
path: path.resolve(root, ".kubb/client.ts"),
|
|
995
|
+
footer
|
|
996
|
+
})] });
|
|
997
|
+
}
|
|
874
998
|
// ../../internals/client/src/resolveOperationTypes.ts
|
|
875
999
|
/**
|
|
876
1000
|
* A `plugin-ts` shaped resolver whose operation type names point at the types `pluginZod({ inferred })`
|
|
@@ -946,13 +1070,24 @@ function resolveOperationTypes(driver, pluginName) {
|
|
|
946
1070
|
* `@kubb/plugin-axios`). Emits one async function per OpenAPI operation using the shared
|
|
947
1071
|
* `Operation` component: a grouped `<Name>Request` type and a function that forwards a single
|
|
948
1072
|
* `options` object to the bundled `client` and returns the `Unwrappable<RequestResult>`. Only the
|
|
949
|
-
* generator `name`
|
|
950
|
-
* identical.
|
|
1073
|
+
* generator `name` and the runtime templates differ between plugins. Every other resolution, import,
|
|
1074
|
+
* and rendering step is identical.
|
|
1075
|
+
*
|
|
1076
|
+
* `sse` is the Server-Sent Events runtime template, copied into `.kubb/sse.ts` only for a document with a
|
|
1077
|
+
* `text/event-stream` operation.
|
|
951
1078
|
*/
|
|
952
|
-
function createClientGenerator(name) {
|
|
1079
|
+
function createClientGenerator(name, { sse } = {}) {
|
|
953
1080
|
return defineGenerator({
|
|
954
1081
|
name,
|
|
955
1082
|
renderer: jsxRenderer,
|
|
1083
|
+
operations(nodes, ctx) {
|
|
1084
|
+
return /* @__PURE__ */ jsx(StreamRuntime, {
|
|
1085
|
+
nodes,
|
|
1086
|
+
root: ctx.root,
|
|
1087
|
+
sse,
|
|
1088
|
+
baseURL: ctx.options.baseURL
|
|
1089
|
+
});
|
|
1090
|
+
},
|
|
956
1091
|
operation(node, ctx) {
|
|
957
1092
|
if (!ast.isHttpOperationNode(node)) return null;
|
|
958
1093
|
const { config, driver, resolver, root } = ctx;
|
|
@@ -1002,19 +1137,19 @@ function createClientGenerator(name) {
|
|
|
1002
1137
|
const clientPath = importPath ?? path.resolve(root, ".kubb/client.ts");
|
|
1003
1138
|
const clientRoot = importPath === void 0 ? meta.file.path : void 0;
|
|
1004
1139
|
const standardSchemaPath = importPath ?? path.resolve(root, ".kubb/standardSchema.ts");
|
|
1005
|
-
const
|
|
1140
|
+
const ssePath = importPath ?? path.resolve(root, ".kubb/sse.ts");
|
|
1141
|
+
const stream = getEventStream(node);
|
|
1006
1142
|
const clientValueImports = (() => {
|
|
1007
|
-
if (eventStream) return ["client", "toEventStream"];
|
|
1008
1143
|
if (returnType === "plain") return ["client"];
|
|
1009
1144
|
if (returnType === "data") return ["client", "unwrapResult"];
|
|
1010
1145
|
return ["client", "withUnwrap"];
|
|
1011
1146
|
})();
|
|
1012
1147
|
const clientTypeImports = (() => {
|
|
1013
|
-
if (
|
|
1014
|
-
"Options",
|
|
1015
|
-
"
|
|
1016
|
-
"SuccessOf"
|
|
1017
|
-
];
|
|
1148
|
+
if (stream) return {
|
|
1149
|
+
plain: ["Options", "SuccessOf"],
|
|
1150
|
+
data: ["SuccessOf"],
|
|
1151
|
+
full: ["SuccessOf", "Unwrappable"]
|
|
1152
|
+
}[returnType];
|
|
1018
1153
|
if (returnType === "plain") return ["Options", "RequestResult"];
|
|
1019
1154
|
if (returnType === "data") return ["Options", "UnwrappedResult"];
|
|
1020
1155
|
return [
|
|
@@ -1055,6 +1190,20 @@ function createClientGenerator(name) {
|
|
|
1055
1190
|
path: clientPath,
|
|
1056
1191
|
isTypeOnly: true
|
|
1057
1192
|
}),
|
|
1193
|
+
stream && /* @__PURE__ */ jsx(File.Import, {
|
|
1194
|
+
name: ["toEventStream"],
|
|
1195
|
+
root: clientRoot,
|
|
1196
|
+
path: ssePath
|
|
1197
|
+
}),
|
|
1198
|
+
stream && /* @__PURE__ */ jsx(File.Import, {
|
|
1199
|
+
name: buildEventStreamImports({
|
|
1200
|
+
returnType,
|
|
1201
|
+
typed: stream === "event"
|
|
1202
|
+
}),
|
|
1203
|
+
root: clientRoot,
|
|
1204
|
+
path: ssePath,
|
|
1205
|
+
isTypeOnly: true
|
|
1206
|
+
}),
|
|
1058
1207
|
meta.fileTypes && importedTypeNames.length > 0 && /* @__PURE__ */ jsx(File.Import, {
|
|
1059
1208
|
name: Array.from(new Set(importedTypeNames)),
|
|
1060
1209
|
root: meta.file.path,
|
|
@@ -1091,43 +1240,26 @@ function createClientGenerator(name) {
|
|
|
1091
1240
|
*/
|
|
1092
1241
|
function buildSdkMethod({ node, name, types, validatorHooks, security, returnType, throwOnErrorDefault }) {
|
|
1093
1242
|
if (!ast.isHttpOperationNode(node)) return "";
|
|
1094
|
-
const
|
|
1243
|
+
const body = buildOperationBody({
|
|
1095
1244
|
node,
|
|
1096
1245
|
types,
|
|
1097
|
-
returnType,
|
|
1098
|
-
throwOnErrorDefault
|
|
1099
|
-
});
|
|
1100
|
-
const { callConfig, mergeContentType, eventStream } = buildCallConfig({
|
|
1101
|
-
node,
|
|
1102
1246
|
validatorHooks,
|
|
1103
1247
|
security,
|
|
1104
|
-
throwOnErrorDefault
|
|
1105
|
-
});
|
|
1106
|
-
const eventStreamReturn = eventStream ? buildEventStreamReturn({
|
|
1107
|
-
node,
|
|
1108
|
-
types,
|
|
1109
|
-
callConfig
|
|
1110
|
-
}) : null;
|
|
1111
|
-
const methodReturnType = eventStreamReturn?.returnType ?? signature.returnType;
|
|
1112
|
-
const returnStatement = eventStreamReturn?.statement ?? buildReturnStatement({
|
|
1113
|
-
node,
|
|
1114
|
-
types,
|
|
1115
|
-
callConfig,
|
|
1116
1248
|
returnType,
|
|
1117
1249
|
throwOnErrorDefault
|
|
1118
1250
|
});
|
|
1119
|
-
const generics =
|
|
1251
|
+
const generics = body.generics.length ? `<${body.generics.join(", ")}>` : "";
|
|
1120
1252
|
const jsdoc = buildJSDoc(buildOperationComments(node, {
|
|
1121
1253
|
link: "urlPath",
|
|
1122
1254
|
linkPosition: "beforeDeprecated",
|
|
1123
1255
|
splitLines: true
|
|
1124
1256
|
}));
|
|
1125
1257
|
const methodBody = [
|
|
1126
|
-
mergeContentType ? "const { client: request = this.client, contentType, ...config } = options" : "const { client: request = this.client, ...config } = options",
|
|
1258
|
+
body.mergeContentType ? "const { client: request = this.client, contentType, ...config } = options" : "const { client: request = this.client, ...config } = options",
|
|
1127
1259
|
"",
|
|
1128
|
-
|
|
1260
|
+
body.statement
|
|
1129
1261
|
].map((line) => line ? ` ${line}` : "").join("\n");
|
|
1130
|
-
return `${jsdoc} public ${name}${generics}(${
|
|
1262
|
+
return `${jsdoc} public ${name}${generics}(${body.paramsSignature}): ${body.returnType} {\n${methodBody}\n }`;
|
|
1131
1263
|
}
|
|
1132
1264
|
/**
|
|
1133
1265
|
* Renders one instance class per tag with one method per operation. The constructor takes a client
|
|
@@ -1283,8 +1415,11 @@ function collectImportsByFile(ops, pick) {
|
|
|
1283
1415
|
* emits one class per tag and, when `sdk.name` is set, a composed root that instantiates every tag
|
|
1284
1416
|
* client. With `sdk.mode: 'flat'` it emits one class named by `sdk.name`, with every operation as a
|
|
1285
1417
|
* direct method.
|
|
1418
|
+
*
|
|
1419
|
+
* `sse` is the Server-Sent Events runtime template, copied into `.kubb/sse.ts` only for a document with a
|
|
1420
|
+
* `text/event-stream` operation.
|
|
1286
1421
|
*/
|
|
1287
|
-
function createSdkGenerator() {
|
|
1422
|
+
function createSdkGenerator({ sse } = {}) {
|
|
1288
1423
|
return defineGenerator({
|
|
1289
1424
|
name: "sdk",
|
|
1290
1425
|
renderer: jsxRenderer,
|
|
@@ -1305,6 +1440,7 @@ function createSdkGenerator() {
|
|
|
1305
1440
|
const controllers = buildControllers(nodes, ctx, types, validatorEnabled);
|
|
1306
1441
|
const clientPath = path.resolve(root, ".kubb/client.ts");
|
|
1307
1442
|
const standardSchemaPath = path.resolve(root, ".kubb/standardSchema.ts");
|
|
1443
|
+
const ssePath = path.resolve(root, ".kubb/sse.ts");
|
|
1308
1444
|
const banner = (file) => resolver.default.banner(ctx.meta, {
|
|
1309
1445
|
output,
|
|
1310
1446
|
config,
|
|
@@ -1333,7 +1469,8 @@ function createSdkGenerator() {
|
|
|
1333
1469
|
namesByPath: /* @__PURE__ */ new Map(),
|
|
1334
1470
|
filesByPath: /* @__PURE__ */ new Map()
|
|
1335
1471
|
};
|
|
1336
|
-
const
|
|
1472
|
+
const shapes = new Set(ops.map((op) => getEventStream(op.node)).filter(Boolean));
|
|
1473
|
+
const hasEventStream = shapes.size > 0;
|
|
1337
1474
|
const hasResult = ops.some((op) => !isEventStream(op.node));
|
|
1338
1475
|
return /* @__PURE__ */ jsxs(File, {
|
|
1339
1476
|
baseName: file.baseName,
|
|
@@ -1343,11 +1480,7 @@ function createSdkGenerator() {
|
|
|
1343
1480
|
footer: footer(file),
|
|
1344
1481
|
children: [
|
|
1345
1482
|
/* @__PURE__ */ jsx(File.Import, {
|
|
1346
|
-
name: [
|
|
1347
|
-
"createClient",
|
|
1348
|
-
...hasResult ? [returnType === "data" ? "unwrapResult" : "withUnwrap"] : [],
|
|
1349
|
-
...hasEventStream ? ["toEventStream"] : []
|
|
1350
|
-
],
|
|
1483
|
+
name: ["createClient", returnType === "data" ? "unwrapResult" : "withUnwrap"],
|
|
1351
1484
|
root: file.path,
|
|
1352
1485
|
path: clientPath
|
|
1353
1486
|
}),
|
|
@@ -1356,13 +1489,28 @@ function createSdkGenerator() {
|
|
|
1356
1489
|
"ClientConfig",
|
|
1357
1490
|
"ClientInstance",
|
|
1358
1491
|
"Options",
|
|
1359
|
-
...
|
|
1360
|
-
...
|
|
1492
|
+
...returnType === "data" ? [] : ["Unwrappable"],
|
|
1493
|
+
...hasResult ? [returnType === "data" ? "UnwrappedResult" : "RequestResult"] : [],
|
|
1494
|
+
...hasEventStream ? ["SuccessOf"] : []
|
|
1361
1495
|
],
|
|
1362
1496
|
root: file.path,
|
|
1363
1497
|
path: clientPath,
|
|
1364
1498
|
isTypeOnly: true
|
|
1365
1499
|
}),
|
|
1500
|
+
hasEventStream && /* @__PURE__ */ jsx(File.Import, {
|
|
1501
|
+
name: ["toEventStream"],
|
|
1502
|
+
root: file.path,
|
|
1503
|
+
path: ssePath
|
|
1504
|
+
}),
|
|
1505
|
+
hasEventStream && /* @__PURE__ */ jsx(File.Import, {
|
|
1506
|
+
name: buildEventStreamImports({
|
|
1507
|
+
returnType,
|
|
1508
|
+
typed: shapes.has("event")
|
|
1509
|
+
}),
|
|
1510
|
+
root: file.path,
|
|
1511
|
+
path: ssePath,
|
|
1512
|
+
isTypeOnly: true
|
|
1513
|
+
}),
|
|
1366
1514
|
validator === "zod" && ops.some((op) => op.node.requestBody?.content?.[0]?.schema != null) && /* @__PURE__ */ jsx(File.Import, {
|
|
1367
1515
|
name: ["z"],
|
|
1368
1516
|
path: "zod",
|
|
@@ -1393,61 +1541,66 @@ function createSdkGenerator() {
|
|
|
1393
1541
|
]
|
|
1394
1542
|
}, file.path);
|
|
1395
1543
|
};
|
|
1396
|
-
|
|
1544
|
+
const renderFacadeFile = (name) => {
|
|
1545
|
+
const sdkFile = resolver.file({
|
|
1546
|
+
name,
|
|
1547
|
+
extname: ".ts",
|
|
1548
|
+
root,
|
|
1549
|
+
output,
|
|
1550
|
+
group: group ?? void 0
|
|
1551
|
+
});
|
|
1552
|
+
const members = controllers.map(({ name, tag }) => ({
|
|
1553
|
+
className: name,
|
|
1554
|
+
propName: resolver.propertyName(tag ?? name)
|
|
1555
|
+
}));
|
|
1556
|
+
return /* @__PURE__ */ jsxs(File, {
|
|
1557
|
+
baseName: sdkFile.baseName,
|
|
1558
|
+
path: sdkFile.path,
|
|
1559
|
+
meta: sdkFile.meta,
|
|
1560
|
+
banner: banner(sdkFile),
|
|
1561
|
+
footer: footer(sdkFile),
|
|
1562
|
+
children: [
|
|
1563
|
+
/* @__PURE__ */ jsx(File.Import, {
|
|
1564
|
+
name: ["ClientConfig"],
|
|
1565
|
+
root: sdkFile.path,
|
|
1566
|
+
path: clientPath,
|
|
1567
|
+
isTypeOnly: true
|
|
1568
|
+
}),
|
|
1569
|
+
controllers.map(({ name, file }) => /* @__PURE__ */ jsx(File.Import, {
|
|
1570
|
+
name: [name],
|
|
1571
|
+
root: sdkFile.path,
|
|
1572
|
+
path: file.path
|
|
1573
|
+
}, name)),
|
|
1574
|
+
/* @__PURE__ */ jsx(SdkFacade, {
|
|
1575
|
+
name: resolver.className(name),
|
|
1576
|
+
members
|
|
1577
|
+
})
|
|
1578
|
+
]
|
|
1579
|
+
}, sdkFile.path);
|
|
1580
|
+
};
|
|
1581
|
+
const files = sdk.mode === "flat" ? renderClassFile(resolver.className(sdk.name ?? "sdk"), resolver.file({
|
|
1397
1582
|
name: sdk.name ?? "sdk",
|
|
1398
1583
|
extname: ".ts",
|
|
1399
1584
|
root,
|
|
1400
1585
|
output,
|
|
1401
1586
|
group: group ?? void 0
|
|
1402
|
-
}), controllers.flatMap((controller) => controller.operations));
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
const sdkFile = resolver.file({
|
|
1406
|
-
name: sdk.name,
|
|
1407
|
-
extname: ".ts",
|
|
1587
|
+
}), controllers.flatMap((controller) => controller.operations)) : [...controllers.map(({ name, file, operations: ops }) => renderClassFile(name, file, ops)), sdk.name && renderFacadeFile(sdk.name)];
|
|
1588
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(StreamRuntime, {
|
|
1589
|
+
nodes,
|
|
1408
1590
|
root,
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
});
|
|
1412
|
-
const facadeName = resolver.className(sdk.name);
|
|
1413
|
-
const members = controllers.map(({ name, tag }) => ({
|
|
1414
|
-
className: name,
|
|
1415
|
-
propName: resolver.propertyName(tag ?? name)
|
|
1416
|
-
}));
|
|
1417
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [classFiles, /* @__PURE__ */ jsxs(File, {
|
|
1418
|
-
baseName: sdkFile.baseName,
|
|
1419
|
-
path: sdkFile.path,
|
|
1420
|
-
meta: sdkFile.meta,
|
|
1421
|
-
banner: banner(sdkFile),
|
|
1422
|
-
footer: footer(sdkFile),
|
|
1423
|
-
children: [
|
|
1424
|
-
/* @__PURE__ */ jsx(File.Import, {
|
|
1425
|
-
name: ["ClientConfig"],
|
|
1426
|
-
root: sdkFile.path,
|
|
1427
|
-
path: clientPath,
|
|
1428
|
-
isTypeOnly: true
|
|
1429
|
-
}),
|
|
1430
|
-
controllers.map(({ name, file }) => /* @__PURE__ */ jsx(File.Import, {
|
|
1431
|
-
name: [name],
|
|
1432
|
-
root: sdkFile.path,
|
|
1433
|
-
path: file.path
|
|
1434
|
-
}, name)),
|
|
1435
|
-
/* @__PURE__ */ jsx(SdkFacade, {
|
|
1436
|
-
name: facadeName,
|
|
1437
|
-
members
|
|
1438
|
-
})
|
|
1439
|
-
]
|
|
1440
|
-
}, sdkFile.path)] });
|
|
1591
|
+
sse,
|
|
1592
|
+
baseURL: ctx.options.baseURL
|
|
1593
|
+
}), files] });
|
|
1441
1594
|
}
|
|
1442
1595
|
});
|
|
1443
1596
|
}
|
|
1444
1597
|
// ../../internals/client/src/macros.ts
|
|
1445
1598
|
/**
|
|
1446
|
-
* Macros the client plugins apply by default, ahead of any user macros. `
|
|
1447
|
-
* drops union members
|
|
1599
|
+
* Macros the client plugins apply by default, ahead of any user macros. `macroDedupeUnion`
|
|
1600
|
+
* drops repeated union members, keeping the generated response and error
|
|
1448
1601
|
* unions tidy. A plugin wires them with `ctx.setMacros([...defaultMacros, ...userMacros])`.
|
|
1449
1602
|
*/
|
|
1450
|
-
const defaultMacros = [
|
|
1603
|
+
const defaultMacros = [macroDedupeUnion];
|
|
1451
1604
|
// ../../internals/client/src/resolver.ts
|
|
1452
1605
|
/**
|
|
1453
1606
|
* Default resolver shared by the client plugins. Functions use safe camelCase identifiers and
|
|
@@ -1472,30 +1625,32 @@ const resolverClient = createResolver({
|
|
|
1472
1625
|
return ensureValidVarName(camelCase(name));
|
|
1473
1626
|
}
|
|
1474
1627
|
});
|
|
1628
|
+
// src/templates.ts
|
|
1629
|
+
const require = createRequire(import.meta.url);
|
|
1630
|
+
/** Absolute path to the fetch client template, copied into `.kubb/client.ts`. */
|
|
1631
|
+
const fetchClientTemplatePath = fileURLToPath(new URL("../templates/client.ts", import.meta.url));
|
|
1632
|
+
/**
|
|
1633
|
+
* Absolute paths to the runtime templates `@kubb/plugin-client` ships for every client plugin, copied into `.kubb/core.ts`,
|
|
1634
|
+
* `.kubb/serializers.ts`, `.kubb/standardSchema.ts`, and `.kubb/sse.ts`.
|
|
1635
|
+
*/
|
|
1636
|
+
const coreTemplatePath = require.resolve("@kubb/plugin-client/templates/core.ts");
|
|
1637
|
+
const serializersTemplatePath = require.resolve("@kubb/plugin-client/templates/serializers.ts");
|
|
1638
|
+
const standardSchemaTemplatePath = require.resolve("@kubb/plugin-client/templates/standardSchema.ts");
|
|
1639
|
+
const sseTemplatePath = require.resolve("@kubb/plugin-client/templates/sse.ts");
|
|
1475
1640
|
// src/generators/clientGenerator.tsx
|
|
1476
1641
|
/**
|
|
1477
1642
|
* Built-in operation generator for `@kubb/plugin-fetch`. Emits one async function per OpenAPI
|
|
1478
1643
|
* operation using the shared `Operation` component: a grouped `<Name>Request` type and a function
|
|
1479
1644
|
* that forwards a single `options` object to the bundled `client` and returns the `RequestResult`.
|
|
1480
1645
|
*/
|
|
1481
|
-
const clientGenerator = createClientGenerator("fetch");
|
|
1646
|
+
const clientGenerator = createClientGenerator("fetch", { sse: sseTemplatePath });
|
|
1482
1647
|
// kubb-extension.json
|
|
1483
1648
|
var compatibility = {
|
|
1484
|
-
"kubb": ">=5.
|
|
1649
|
+
"kubb": ">=5.16.0",
|
|
1485
1650
|
"node": ">=22.22"
|
|
1486
1651
|
};
|
|
1487
1652
|
// package.json
|
|
1488
|
-
var version = "5.13.0
|
|
1489
|
-
// src/templates.ts
|
|
1490
|
-
/** Absolute path to the fetch client template, copied into `.kubb/client.ts`. */
|
|
1491
|
-
const fetchClientTemplatePath = fileURLToPath(new URL("../templates/fetch.ts", import.meta.url));
|
|
1492
|
-
/** Absolute path to the fetch serializers template, copied into `.kubb/serializers.ts`. */
|
|
1493
|
-
const fetchSerializersTemplatePath = fileURLToPath(new URL("../templates/serializers.ts", import.meta.url));
|
|
1494
|
-
/**
|
|
1495
|
-
* Absolute path to the Standard Schema runtime template. Pass it to a file node's `copy` field to
|
|
1496
|
-
* emit the helper into the generated `.kubb/standardSchema.ts` verbatim.
|
|
1497
|
-
*/
|
|
1498
|
-
const standardSchemaTemplatePath = fileURLToPath(new URL("../templates/standardSchema.ts", import.meta.url));
|
|
1653
|
+
var version = "5.13.0";
|
|
1499
1654
|
// src/plugin.ts
|
|
1500
1655
|
/**
|
|
1501
1656
|
* Canonical plugin name for `@kubb/plugin-fetch`. Used for driver lookups and cross-plugin
|
|
@@ -1559,19 +1714,22 @@ const pluginFetch = defineExtension({
|
|
|
1559
1714
|
};
|
|
1560
1715
|
setResolver(resolved.resolver);
|
|
1561
1716
|
setMacros([...defaultMacros, ...options.macros ?? []]);
|
|
1562
|
-
addGenerator(resolved.sdk ? createSdkGenerator() : clientGenerator);
|
|
1717
|
+
addGenerator(resolved.sdk ? createSdkGenerator({ sse: sseTemplatePath }) : clientGenerator);
|
|
1563
1718
|
const root = path.resolve(config.root, config.output.path);
|
|
1564
|
-
const baseURLExpression = baseURL ? baseURL.includes("${") ? `\`${baseURL.replaceAll("`", "\\`")}\`` : JSON.stringify(baseURL) : void 0;
|
|
1565
1719
|
injectFile({
|
|
1566
1720
|
baseName: "serializers.ts",
|
|
1567
1721
|
path: path.resolve(root, ".kubb/serializers.ts"),
|
|
1568
|
-
copy:
|
|
1722
|
+
copy: serializersTemplatePath
|
|
1723
|
+
});
|
|
1724
|
+
injectFile({
|
|
1725
|
+
baseName: "core.ts",
|
|
1726
|
+
path: path.resolve(root, ".kubb/core.ts"),
|
|
1727
|
+
copy: coreTemplatePath
|
|
1569
1728
|
});
|
|
1570
1729
|
injectFile({
|
|
1571
1730
|
baseName: "client.ts",
|
|
1572
1731
|
path: path.resolve(root, ".kubb/client.ts"),
|
|
1573
|
-
copy: fetchClientTemplatePath
|
|
1574
|
-
footer: baseURLExpression ? `client.setConfig({ baseURL: ${baseURLExpression} })` : void 0
|
|
1732
|
+
copy: fetchClientTemplatePath
|
|
1575
1733
|
});
|
|
1576
1734
|
injectFile({
|
|
1577
1735
|
baseName: "standardSchema.ts",
|