@kubb/plugin-client 5.10.0-canary.20261105T164114 → 5.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/client-CiHb_Cfg.d.ts +345 -0
- package/dist/index.cjs +288 -143
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +290 -145
- package/dist/index.js.map +1 -1
- package/dist/serializers-Ds8zZwOO.d.ts +190 -0
- package/dist/standardSchema-BShJWz2i.d.ts +104 -0
- package/dist/templates/client.d.ts +2 -0
- package/dist/templates/core.d.ts +3 -0
- package/dist/templates/serializers.d.ts +2 -0
- package/dist/templates/sse.d.ts +124 -0
- package/dist/templates/standardSchema.d.ts +2 -0
- package/docs/guides/write-your-client.md +1 -1
- package/docs/overview.md +1 -1
- package/kubb-extension.json +1 -1
- package/package.json +17 -8
- package/templates/client.ts +5 -0
- package/templates/core.ts +694 -0
- package/templates/serializers.ts +493 -0
- package/templates/sse.ts +274 -0
- package/templates/standardSchema.ts +162 -0
package/dist/index.cjs
CHANGED
|
@@ -110,20 +110,33 @@ function getPrimarySuccessContentType(node) {
|
|
|
110
110
|
return contentTypes[0].split(";")[0].trim().toLowerCase();
|
|
111
111
|
}
|
|
112
112
|
/**
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
|
|
113
|
+
* The `text/event-stream` content of the primary success response, when it is the only content type. A response that also
|
|
114
|
+
* declares another type stays a normal call with its query hooks.
|
|
115
|
+
*/
|
|
116
|
+
function getEventStreamContent(node) {
|
|
117
|
+
return getPrimarySuccessContentType(node) === "text/event-stream" ? getPrimarySuccessResponse(node)?.content?.[0] : void 0;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Whether an operation streams its primary success response as Server-Sent Events (`text/event-stream`). The client
|
|
121
|
+
* generator uses this to return a typed event stream instead of a one-shot `RequestResult`.
|
|
116
122
|
*/
|
|
117
123
|
function isEventStream(node) {
|
|
118
|
-
return
|
|
124
|
+
return getEventStreamContent(node) !== void 0;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* How the document types a `text/event-stream` response, as the adapter read it from `itemSchema`: `event` when each item is
|
|
128
|
+
* the parsed event with its own `event` and `data`, `data` when it is only the payload. Returns `null` without an event stream.
|
|
129
|
+
*/
|
|
130
|
+
function getEventStream(node) {
|
|
131
|
+
const content = getEventStreamContent(node);
|
|
132
|
+
return content ? content.stream?.shape ?? "data" : null;
|
|
119
133
|
}
|
|
120
134
|
/**
|
|
121
135
|
* Derives the default `responseType` for an operation from its primary success response.
|
|
122
136
|
*
|
|
123
|
-
* Returns a value only when that response declares a single non-JSON content type. `text/event-stream`
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
* leaving the runtime client's `Content-Type` auto-detection in charge.
|
|
137
|
+
* Returns a value only when that response declares a single non-JSON content type. `text/event-stream` maps to
|
|
138
|
+
* `'stream'`, `application/octet-stream`, `application/pdf`, `image/*`, `audio/*` and `video/*` map to `'blob'`, and
|
|
139
|
+
* other `text/*` to `'text'`. Otherwise `undefined`, leaving the runtime client's `Content-Type` auto-detection in charge.
|
|
127
140
|
*/
|
|
128
141
|
function getResponseType(node) {
|
|
129
142
|
const baseType = getPrimarySuccessContentType(node);
|
|
@@ -183,6 +196,22 @@ function buildOperationComments(node, options = {}) {
|
|
|
183
196
|
}
|
|
184
197
|
const operationParameterGroupsByNode = /* @__PURE__ */ new WeakMap();
|
|
185
198
|
/**
|
|
199
|
+
* An OpenAPI 3.2 `querystring` parameter is the whole query string, so a form-encoded object becomes one query parameter
|
|
200
|
+
* per property, typed and serialized like any other.
|
|
201
|
+
* Another content type, such as JSON, stays one parameter named after it, and the runtime sends its value as the whole query string.
|
|
202
|
+
*/
|
|
203
|
+
function spreadQuerystring(param) {
|
|
204
|
+
const schema = param.schema.type === "ref" ? param.schema.schema : param.schema;
|
|
205
|
+
const formEncoded = !param.contentType || param.contentType.split(";")[0].trim().toLowerCase() === "application/x-www-form-urlencoded";
|
|
206
|
+
if (schema?.type !== "object" || !formEncoded) return [param];
|
|
207
|
+
return schema.properties.map((property) => _kubb_kit.ast.factory.createParameter({
|
|
208
|
+
name: property.name,
|
|
209
|
+
in: "query",
|
|
210
|
+
schema: property.schema,
|
|
211
|
+
required: param.required && property.required
|
|
212
|
+
}));
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
186
215
|
* Groups an operation's parameters by location (`path`/`query`/`header`/`cookie`), deduping each
|
|
187
216
|
* group by name. Every plugin generator visiting the same `OperationNode` shares one AST instance
|
|
188
217
|
* (see `KubbDriver`), so the result is cached per node to avoid re-filtering and re-deduping the
|
|
@@ -191,17 +220,18 @@ const operationParameterGroupsByNode = /* @__PURE__ */ new WeakMap();
|
|
|
191
220
|
function getOperationParameters(node) {
|
|
192
221
|
const cached = operationParameterGroupsByNode.get(node);
|
|
193
222
|
if (cached) return cached;
|
|
194
|
-
const
|
|
223
|
+
const dedupe = (params) => {
|
|
195
224
|
const seen = /* @__PURE__ */ new Set();
|
|
196
|
-
return
|
|
197
|
-
if (
|
|
225
|
+
return params.filter((param) => {
|
|
226
|
+
if (seen.has(param.name)) return false;
|
|
198
227
|
seen.add(param.name);
|
|
199
228
|
return true;
|
|
200
229
|
});
|
|
201
230
|
};
|
|
231
|
+
const group = (location) => dedupe(node.parameters.filter((param) => param.in === location));
|
|
202
232
|
const groups = {
|
|
203
233
|
path: group("path"),
|
|
204
|
-
query: group("query"),
|
|
234
|
+
query: dedupe([...group("query"), ...group("querystring").flatMap(spreadQuerystring)]),
|
|
205
235
|
header: group("header"),
|
|
206
236
|
cookie: group("cookie")
|
|
207
237
|
};
|
|
@@ -431,11 +461,11 @@ function createGroupConfig(group) {
|
|
|
431
461
|
}
|
|
432
462
|
// kubb-extension.json
|
|
433
463
|
var compatibility = {
|
|
434
|
-
"kubb": ">=5.
|
|
464
|
+
"kubb": ">=5.16.0",
|
|
435
465
|
"node": ">=22.22"
|
|
436
466
|
};
|
|
437
467
|
// package.json
|
|
438
|
-
var version = "5.10.0
|
|
468
|
+
var version = "5.10.0";
|
|
439
469
|
// ../../internals/client/src/builders/validatorOptions.ts
|
|
440
470
|
/**
|
|
441
471
|
* Returns `true` when any direction of the validator uses zod (used for dependency checks).
|
|
@@ -479,6 +509,114 @@ function buildZodErrorParse(node, zodResolver) {
|
|
|
479
509
|
if (!node.responses.some((res) => !isSuccessStatusCode(res.statusCode) && res.content?.some((entry) => entry.schema))) return null;
|
|
480
510
|
return zodResolver.response.error?.(node) || null;
|
|
481
511
|
}
|
|
512
|
+
// ../../internals/client/src/builders/generics.ts
|
|
513
|
+
/**
|
|
514
|
+
* Builds the `RequestResult` generic arguments for one operation: the per-status responses record
|
|
515
|
+
* plus the per-call `ThrowOnError` flag. `SuccessOf` / `ErrorOf` split the record inside the
|
|
516
|
+
* runtime, so this only names the record and threads `ThrowOnError`.
|
|
517
|
+
*
|
|
518
|
+
* @example
|
|
519
|
+
* `buildRequestResultGenerics({ node, types }) // 'AddPetResponses, ThrowOnError'`
|
|
520
|
+
*/
|
|
521
|
+
function buildRequestResultGenerics({ node, types }) {
|
|
522
|
+
return `${types.response.responses(node)}, ThrowOnError`;
|
|
523
|
+
}
|
|
524
|
+
/**
|
|
525
|
+
* Builds the full return type an operation's function signature uses: `Unwrappable<RequestResult>`
|
|
526
|
+
* for the default `returnType: 'full'`, already a promise so no further wrapping is needed, a plain
|
|
527
|
+
* `Promise<RequestResult>` for the internal `'plain'` shape, or a
|
|
528
|
+
* `Promise` of the runtime's `UnwrappedResult` when `returnType: 'data'` narrows a resolved call
|
|
529
|
+
* down to the bare success body.
|
|
530
|
+
*
|
|
531
|
+
* @example
|
|
532
|
+
* `buildResultType({ node, types, returnType: 'data' }) // 'Promise<UnwrappedResult<AddPetResponses, ThrowOnError>>'`
|
|
533
|
+
*/
|
|
534
|
+
function buildResultType({ node, types, returnType }) {
|
|
535
|
+
const generics = buildRequestResultGenerics({
|
|
536
|
+
node,
|
|
537
|
+
types
|
|
538
|
+
});
|
|
539
|
+
if (returnType === "data") return `Promise<UnwrappedResult<${generics}>>`;
|
|
540
|
+
if (returnType === "plain") return `Promise<RequestResult<${generics}>>`;
|
|
541
|
+
return `Unwrappable<RequestResult<${generics}>>`;
|
|
542
|
+
}
|
|
543
|
+
// ../../internals/client/src/builders/returnStatement.ts
|
|
544
|
+
/**
|
|
545
|
+
* Builds the return statement of a generated operation function. With the default
|
|
546
|
+
* `returnType: 'full'` the runtime call already resolves to `{ data, error, request, response }`.
|
|
547
|
+
* The generated code casts that result to the operation's `RequestResult`, then wraps it with
|
|
548
|
+
* `withUnwrap`, so the caller can `await` it directly or call `.unwrap()` for the bare success
|
|
549
|
+
* body. With `returnType: 'data'` it instead routes the call through the runtime's `unwrapResult`,
|
|
550
|
+
* which narrows the resolved value down to the bare success body the same way `RequestResult`
|
|
551
|
+
* already does, using the plugin default when the call leaves `throwOnError` unset.
|
|
552
|
+
* With `returnType: 'plain'` it returns the runtime call as is, cast to `RequestResult`, with no helper.
|
|
553
|
+
*
|
|
554
|
+
* Cast first, wrap second, for the `'full'` path. That order keeps `withUnwrap`'s generic inferred
|
|
555
|
+
* as `RequestResult` instead of the runtime's own internal result type. Casting an `Unwrappable<A>`
|
|
556
|
+
* straight to `Unwrappable<B>` does not work: the `.then` overload stays pinned to `A`, and `as`
|
|
557
|
+
* rejects that two-generic swap even where `A` and `B` on their own would satisfy it.
|
|
558
|
+
*
|
|
559
|
+
* @example
|
|
560
|
+
* `return withUnwrap(request({ method: 'POST', url: '/pet', ...config }) as Promise<RequestResult<AddPetResponses, ThrowOnError>>)`
|
|
561
|
+
* @example
|
|
562
|
+
* `return unwrapResult(request({ method: 'POST', url: '/pet', ...config }), config.throwOnError ?? false) as Promise<UnwrappedResult<AddPetResponses, ThrowOnError>>`
|
|
563
|
+
* @example
|
|
564
|
+
* `return request({ method: 'POST', url: '/pet', ...config }) as Promise<RequestResult<AddPetResponses, ThrowOnError>>`
|
|
565
|
+
*/
|
|
566
|
+
function buildReturnStatement({ node, types, callConfig, returnType, throwOnErrorDefault }) {
|
|
567
|
+
const request = returnType !== "plain" && hasRequestContentTypeChoice(node) ? `request<${types.response.options(node)}['body']>` : "request";
|
|
568
|
+
if (returnType === "data") return `return unwrapResult(${request}(${callConfig}), config.throwOnError ?? ${throwOnErrorDefault}) as ${buildResultType({
|
|
569
|
+
node,
|
|
570
|
+
types,
|
|
571
|
+
returnType
|
|
572
|
+
})}`;
|
|
573
|
+
if (returnType === "plain") return `return ${request}(${callConfig}) as Promise<RequestResult<${buildRequestResultGenerics({
|
|
574
|
+
node,
|
|
575
|
+
types
|
|
576
|
+
})}>>`;
|
|
577
|
+
return `return withUnwrap(${request}(${callConfig}) as Promise<RequestResult<${buildRequestResultGenerics({
|
|
578
|
+
node,
|
|
579
|
+
types
|
|
580
|
+
})}>>)`;
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* Builds the return type and statement of a `text/event-stream` operation. The item type is `TypedEvent<...>` when each item
|
|
584
|
+
* declares its own `event` and `data`, and otherwise the payload type, which `EventStreamResult` wraps in `ServerSentEvent`. The call's
|
|
585
|
+
* promise goes through `toEventStream` with the `client` for its defaults, the call's `config`, the shape and the per-event
|
|
586
|
+
* validator. A `returnType: 'plain'` client receives only the promise,
|
|
587
|
+
* `toEventStream(request(config))`, and keeps its response validator in the call config.
|
|
588
|
+
*/
|
|
589
|
+
function buildEventStreamReturn({ node, types, callConfig, returnType, validatorHooks, throwOnErrorDefault }) {
|
|
590
|
+
const shape = getEventStream(node) ?? "data";
|
|
591
|
+
const responses = types.response.responses(node);
|
|
592
|
+
const success = `SuccessOf<${responses}>`;
|
|
593
|
+
const eventType = shape === "event" ? `TypedEvent<${success}>` : success;
|
|
594
|
+
if (returnType === "plain") return {
|
|
595
|
+
returnType: `Promise<EventStreamResult<${eventType}>>`,
|
|
596
|
+
statement: `return toEventStream<${eventType}>(request(${callConfig}))`
|
|
597
|
+
};
|
|
598
|
+
const generics = `${responses}, ThrowOnError${shape === "event" ? `, ${eventType}` : ""}`;
|
|
599
|
+
const call = `toEventStream<${eventType}>(request(${callConfig}), { client: request, config, ${[`shape: '${shape}'`, validatorHooks?.response ? `validator: ${validatorHooks.response}` : null].filter(Boolean).join(", ")} })`;
|
|
600
|
+
if (returnType === "data") {
|
|
601
|
+
const result = `Promise<UnwrappedStreamResult<${generics}>>`;
|
|
602
|
+
return {
|
|
603
|
+
returnType: result,
|
|
604
|
+
statement: `return unwrapResult(${call}, config.throwOnError ?? ${throwOnErrorDefault}) as ${result}`
|
|
605
|
+
};
|
|
606
|
+
}
|
|
607
|
+
return {
|
|
608
|
+
returnType: `Unwrappable<StreamResult<${generics}>>`,
|
|
609
|
+
statement: `return withUnwrap(${call} as Promise<StreamResult<${generics}>>)`
|
|
610
|
+
};
|
|
611
|
+
}
|
|
612
|
+
/** The stream types an operation file imports: `StreamResult` and `StreamOptions`, `EventStreamResult` for a plain client, and `TypedEvent` for named events. */
|
|
613
|
+
function buildEventStreamImports({ returnType, typed }) {
|
|
614
|
+
return [...{
|
|
615
|
+
plain: ["EventStreamResult"],
|
|
616
|
+
full: ["StreamResult", "StreamOptions"],
|
|
617
|
+
data: ["UnwrappedStreamResult", "StreamOptions"]
|
|
618
|
+
}[returnType], ...typed ? ["TypedEvent"] : []];
|
|
619
|
+
}
|
|
482
620
|
// ../../internals/client/src/builders/security.ts
|
|
483
621
|
function serializeAuth(auth) {
|
|
484
622
|
const parts = [`type: '${auth.type}'`];
|
|
@@ -634,6 +772,7 @@ function serializeParameter(parameter) {
|
|
|
634
772
|
if (parameter.explode !== void 0) parts.push(`explode: ${parameter.explode}`);
|
|
635
773
|
if (parameter.in === "query" && parameter.allowReserved !== void 0) parts.push(`allowReserved: ${parameter.allowReserved}`);
|
|
636
774
|
if (parameter.in !== "path" && parameter.contentType) parts.push(`contentType: '${parameter.contentType}'`);
|
|
775
|
+
if (parameter.in === "querystring") parts.push("querystring: true");
|
|
637
776
|
return parts.length > 0 ? `{ ${parts.join(", ")} }` : null;
|
|
638
777
|
}
|
|
639
778
|
/**
|
|
@@ -676,10 +815,9 @@ function buildStyles({ node }) {
|
|
|
676
815
|
header: [],
|
|
677
816
|
cookie: []
|
|
678
817
|
};
|
|
679
|
-
for (const parameter of
|
|
818
|
+
for (const [location, parameters] of Object.entries(getOperationParameters(node))) for (const parameter of parameters) {
|
|
680
819
|
const literal = serializeParameter(parameter);
|
|
681
|
-
if (
|
|
682
|
-
groups[parameter.in].push(`${toKey(parameter.name)}: ${literal}`);
|
|
820
|
+
if (literal) groups[location].push(`${toKey(parameter.name)}: ${literal}`);
|
|
683
821
|
}
|
|
684
822
|
const entries = [...Object.keys(groups).filter((location) => groups[location].length > 0).map((location) => `${location}: { ${groups[location].join(", ")} }`), serializeBodyEncoding(node)].filter(Boolean);
|
|
685
823
|
return entries.length > 0 ? `{ ${entries.join(", ")} }` : null;
|
|
@@ -690,12 +828,20 @@ function buildStyles({ node }) {
|
|
|
690
828
|
* functions and the SDK methods. The `throwOnError` fallback is applied after the `...config` spread.
|
|
691
829
|
*
|
|
692
830
|
* `mergeContentType` is `true` when the caller must destructure `contentType` from `options`, and
|
|
693
|
-
* `eventStream` is `true` when the operation returns `text/event-stream`.
|
|
831
|
+
* `eventStream` is `true` when the operation returns `text/event-stream`. Unless `returnType` is `'plain'`, a
|
|
832
|
+
* stream's literal leaves the `response` validator to `toEventStream`, which runs it per event.
|
|
694
833
|
*/
|
|
695
|
-
function buildCallConfig({ node, validatorHooks, security, throwOnErrorDefault }) {
|
|
834
|
+
function buildCallConfig({ node, validatorHooks, security, throwOnErrorDefault, returnType }) {
|
|
835
|
+
const eventStream = isEventStream(node);
|
|
696
836
|
const securityLiteral = buildSecurityMetadata({ security });
|
|
697
837
|
const stylesLiteral = buildStyles({ node });
|
|
698
|
-
const validatorLiteral = buildValidatorLiteral(validatorHooks, [
|
|
838
|
+
const validatorLiteral = buildValidatorLiteral(validatorHooks, eventStream && returnType !== "plain" ? [
|
|
839
|
+
"request",
|
|
840
|
+
"path",
|
|
841
|
+
"query",
|
|
842
|
+
"headers",
|
|
843
|
+
"error"
|
|
844
|
+
] : [
|
|
699
845
|
"request",
|
|
700
846
|
"path",
|
|
701
847
|
"query",
|
|
@@ -718,90 +864,7 @@ function buildCallConfig({ node, validatorHooks, security, throwOnErrorDefault }
|
|
|
718
864
|
`throwOnError: config.throwOnError ?? ${throwOnErrorDefault}`
|
|
719
865
|
].filter(Boolean).join(", ")} }`,
|
|
720
866
|
mergeContentType,
|
|
721
|
-
eventStream
|
|
722
|
-
};
|
|
723
|
-
}
|
|
724
|
-
// ../../internals/client/src/builders/generics.ts
|
|
725
|
-
/**
|
|
726
|
-
* Builds the `RequestResult` generic arguments for one operation: the per-status responses record
|
|
727
|
-
* plus the per-call `ThrowOnError` flag. `SuccessOf` / `ErrorOf` split the record inside the
|
|
728
|
-
* runtime, so this only names the record and threads `ThrowOnError`.
|
|
729
|
-
*
|
|
730
|
-
* @example
|
|
731
|
-
* `buildRequestResultGenerics({ node, types }) // 'AddPetResponses, ThrowOnError'`
|
|
732
|
-
*/
|
|
733
|
-
function buildRequestResultGenerics({ node, types }) {
|
|
734
|
-
return `${types.response.responses(node)}, ThrowOnError`;
|
|
735
|
-
}
|
|
736
|
-
/**
|
|
737
|
-
* Builds the full return type an operation's function signature uses: `Unwrappable<RequestResult>`
|
|
738
|
-
* for the default `returnType: 'full'`, already a promise so no further wrapping is needed, a plain
|
|
739
|
-
* `Promise<RequestResult>` for the internal `'plain'` shape, or a
|
|
740
|
-
* `Promise` of the runtime's `UnwrappedResult` when `returnType: 'data'` narrows a resolved call
|
|
741
|
-
* down to the bare success body.
|
|
742
|
-
*
|
|
743
|
-
* @example
|
|
744
|
-
* `buildResultType({ node, types, returnType: 'data' }) // 'Promise<UnwrappedResult<AddPetResponses, ThrowOnError>>'`
|
|
745
|
-
*/
|
|
746
|
-
function buildResultType({ node, types, returnType }) {
|
|
747
|
-
const generics = buildRequestResultGenerics({
|
|
748
|
-
node,
|
|
749
|
-
types
|
|
750
|
-
});
|
|
751
|
-
if (returnType === "data") return `Promise<UnwrappedResult<${generics}>>`;
|
|
752
|
-
if (returnType === "plain") return `Promise<RequestResult<${generics}>>`;
|
|
753
|
-
return `Unwrappable<RequestResult<${generics}>>`;
|
|
754
|
-
}
|
|
755
|
-
// ../../internals/client/src/builders/returnStatement.ts
|
|
756
|
-
/**
|
|
757
|
-
* Builds the return statement of a generated operation function. With the default
|
|
758
|
-
* `returnType: 'full'` the runtime call already resolves to `{ data, error, request, response }`.
|
|
759
|
-
* The generated code casts that result to the operation's `RequestResult`, then wraps it with
|
|
760
|
-
* `withUnwrap`, so the caller can `await` it directly or call `.unwrap()` for the bare success
|
|
761
|
-
* body. With `returnType: 'data'` it instead routes the call through the runtime's `unwrapResult`,
|
|
762
|
-
* which narrows the resolved value down to the bare success body the same way `RequestResult`
|
|
763
|
-
* already does, using the plugin default when the call leaves `throwOnError` unset.
|
|
764
|
-
* With `returnType: 'plain'` it returns the runtime call as is, cast to `RequestResult`, with no helper.
|
|
765
|
-
*
|
|
766
|
-
* Cast first, wrap second, for the `'full'` path. That order keeps `withUnwrap`'s generic inferred
|
|
767
|
-
* as `RequestResult` instead of the runtime's own internal result type. Casting an `Unwrappable<A>`
|
|
768
|
-
* straight to `Unwrappable<B>` does not work: the `.then` overload stays pinned to `A`, and `as`
|
|
769
|
-
* rejects that two-generic swap even where `A` and `B` on their own would satisfy it.
|
|
770
|
-
*
|
|
771
|
-
* @example
|
|
772
|
-
* `return withUnwrap(request({ method: 'POST', url: '/pet', ...config }) as Promise<RequestResult<AddPetResponses, ThrowOnError>>)`
|
|
773
|
-
* @example
|
|
774
|
-
* `return unwrapResult(request({ method: 'POST', url: '/pet', ...config }), config.throwOnError ?? false) as Promise<UnwrappedResult<AddPetResponses, ThrowOnError>>`
|
|
775
|
-
* @example
|
|
776
|
-
* `return request({ method: 'POST', url: '/pet', ...config }) as Promise<RequestResult<AddPetResponses, ThrowOnError>>`
|
|
777
|
-
*/
|
|
778
|
-
function buildReturnStatement({ node, types, callConfig, returnType, throwOnErrorDefault }) {
|
|
779
|
-
const request = returnType !== "plain" && hasRequestContentTypeChoice(node) ? `request<${types.response.options(node)}['body']>` : "request";
|
|
780
|
-
if (returnType === "data") return `return unwrapResult(${request}(${callConfig}), config.throwOnError ?? ${throwOnErrorDefault}) as ${buildResultType({
|
|
781
|
-
node,
|
|
782
|
-
types,
|
|
783
|
-
returnType
|
|
784
|
-
})}`;
|
|
785
|
-
if (returnType === "plain") return `return ${request}(${callConfig}) as Promise<RequestResult<${buildRequestResultGenerics({
|
|
786
|
-
node,
|
|
787
|
-
types
|
|
788
|
-
})}>>`;
|
|
789
|
-
return `return withUnwrap(${request}(${callConfig}) as Promise<RequestResult<${buildRequestResultGenerics({
|
|
790
|
-
node,
|
|
791
|
-
types
|
|
792
|
-
})}>>)`;
|
|
793
|
-
}
|
|
794
|
-
/**
|
|
795
|
-
* Builds the return type and statement of an operation that returns `text/event-stream`: the call
|
|
796
|
-
* is wrapped in `toEventStream`, so the caller iterates the typed success events. Except with
|
|
797
|
-
* `returnType: 'plain'`, `toEventStream` also receives `config`, so a per-call `maxEventSize` reaches the parser.
|
|
798
|
-
*/
|
|
799
|
-
function buildEventStreamReturn({ node, types, callConfig, returnType }) {
|
|
800
|
-
const eventType = `SuccessOf<${types.response.responses(node)}>`;
|
|
801
|
-
const args = returnType === "plain" ? `request(${callConfig})` : `request(${callConfig}), config`;
|
|
802
|
-
return {
|
|
803
|
-
returnType: `Promise<EventStreamResult<${eventType}>>`,
|
|
804
|
-
statement: `return toEventStream<${eventType}>(${args})`
|
|
867
|
+
eventStream
|
|
805
868
|
};
|
|
806
869
|
}
|
|
807
870
|
// ../../internals/client/src/builders/signature.ts
|
|
@@ -815,13 +878,14 @@ const declarationPrinter = (0, _kubb_plugin_ts.functionPrinter)({ mode: "declara
|
|
|
815
878
|
* per-operation input type has to be emitted. Both names come from `types`, which is `plugin-ts` or
|
|
816
879
|
* `plugin-zod`'s inferred types (see `resolveOperationTypes`).
|
|
817
880
|
*/
|
|
818
|
-
function buildGroupedOptionsSignature({ node, types, returnType, throwOnErrorDefault }) {
|
|
881
|
+
function buildGroupedOptionsSignature({ node, types, returnType, throwOnErrorDefault, eventStream = false }) {
|
|
819
882
|
const optionsName = types.response.options(node);
|
|
883
|
+
const optionsType = `${eventStream && returnType !== "plain" ? "StreamOptions" : "Options"}<${optionsName}, ThrowOnError>`;
|
|
820
884
|
const { isOptional } = getRequestGroupOptionality(node);
|
|
821
885
|
return {
|
|
822
886
|
paramsSignature: declarationPrinter.print((0, _kubb_plugin_ts.createFunctionParameters)({ params: [(0, _kubb_plugin_ts.createFunctionParameter)({
|
|
823
887
|
name: "options",
|
|
824
|
-
type:
|
|
888
|
+
type: optionsType,
|
|
825
889
|
...isOptional ? { default: "{}" } : {}
|
|
826
890
|
})] })) ?? "",
|
|
827
891
|
returnType: buildResultType({
|
|
@@ -832,38 +896,63 @@ function buildGroupedOptionsSignature({ node, types, returnType, throwOnErrorDef
|
|
|
832
896
|
generics: [`ThrowOnError extends boolean = ${throwOnErrorDefault}`]
|
|
833
897
|
};
|
|
834
898
|
}
|
|
835
|
-
// ../../internals/client/src/
|
|
899
|
+
// ../../internals/client/src/builders/operationBody.ts
|
|
836
900
|
/**
|
|
837
|
-
*
|
|
838
|
-
*
|
|
839
|
-
*
|
|
840
|
-
* the source.
|
|
901
|
+
* The pieces of a generated operation: its generics, `options` parameter, return type, return statement, and whether the
|
|
902
|
+
* body destructures `contentType` from `options`. Shared by the standalone functions and the SDK methods, so a
|
|
903
|
+
* `text/event-stream` operation is wired to `toEventStream` in one place.
|
|
841
904
|
*/
|
|
842
|
-
function
|
|
843
|
-
if (!_kubb_kit.ast.isHttpOperationNode(node)) return null;
|
|
844
|
-
const signature = buildGroupedOptionsSignature({
|
|
845
|
-
node,
|
|
846
|
-
types,
|
|
847
|
-
returnType,
|
|
848
|
-
throwOnErrorDefault
|
|
849
|
-
});
|
|
905
|
+
function buildOperationBody({ node, types, validatorHooks, security, returnType, throwOnErrorDefault }) {
|
|
850
906
|
const { callConfig, mergeContentType, eventStream } = buildCallConfig({
|
|
851
907
|
node,
|
|
852
908
|
validatorHooks,
|
|
853
909
|
security,
|
|
854
|
-
throwOnErrorDefault
|
|
910
|
+
throwOnErrorDefault,
|
|
911
|
+
returnType
|
|
855
912
|
});
|
|
856
|
-
const
|
|
913
|
+
const signature = buildGroupedOptionsSignature({
|
|
914
|
+
node,
|
|
915
|
+
types,
|
|
916
|
+
returnType,
|
|
917
|
+
throwOnErrorDefault,
|
|
918
|
+
eventStream
|
|
919
|
+
});
|
|
920
|
+
const stream = eventStream ? buildEventStreamReturn({
|
|
857
921
|
node,
|
|
858
922
|
types,
|
|
859
923
|
callConfig,
|
|
860
|
-
returnType
|
|
924
|
+
returnType,
|
|
925
|
+
validatorHooks,
|
|
926
|
+
throwOnErrorDefault
|
|
861
927
|
}) : null;
|
|
862
|
-
|
|
863
|
-
|
|
928
|
+
return {
|
|
929
|
+
generics: signature.generics,
|
|
930
|
+
paramsSignature: signature.paramsSignature,
|
|
931
|
+
returnType: stream?.returnType ?? signature.returnType,
|
|
932
|
+
statement: stream?.statement ?? buildReturnStatement({
|
|
933
|
+
node,
|
|
934
|
+
types,
|
|
935
|
+
callConfig,
|
|
936
|
+
returnType,
|
|
937
|
+
throwOnErrorDefault
|
|
938
|
+
}),
|
|
939
|
+
mergeContentType
|
|
940
|
+
};
|
|
941
|
+
}
|
|
942
|
+
// ../../internals/client/src/components/Operation.tsx
|
|
943
|
+
/**
|
|
944
|
+
* Renders one client operation: the grouped `<Name>Request` type and the function that forwards a
|
|
945
|
+
* single `options` object to the resolved client and returns the `Unwrappable<RequestResult>`. The
|
|
946
|
+
* type, signature, and call config are built with the AST factory, and only the jsx-renderer emits
|
|
947
|
+
* the source.
|
|
948
|
+
*/
|
|
949
|
+
function Operation({ name, node, types, validatorHooks, returnType, throwOnErrorDefault, security }) {
|
|
950
|
+
if (!_kubb_kit.ast.isHttpOperationNode(node)) return null;
|
|
951
|
+
const body = buildOperationBody({
|
|
864
952
|
node,
|
|
865
953
|
types,
|
|
866
|
-
|
|
954
|
+
validatorHooks,
|
|
955
|
+
security,
|
|
867
956
|
returnType,
|
|
868
957
|
throwOnErrorDefault
|
|
869
958
|
});
|
|
@@ -874,22 +963,53 @@ function Operation({ name, node, types, validatorHooks, returnType, throwOnError
|
|
|
874
963
|
children: /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx.Function, {
|
|
875
964
|
name,
|
|
876
965
|
export: true,
|
|
877
|
-
generics:
|
|
878
|
-
params:
|
|
879
|
-
returnType:
|
|
966
|
+
generics: body.generics,
|
|
967
|
+
params: body.paramsSignature,
|
|
968
|
+
returnType: body.returnType,
|
|
880
969
|
JSDoc: { comments: buildOperationComments(node, {
|
|
881
970
|
link: "urlPath",
|
|
882
971
|
linkPosition: "beforeDeprecated",
|
|
883
972
|
splitLines: true
|
|
884
973
|
}) },
|
|
885
974
|
children: [
|
|
886
|
-
mergeContentType ? "const { client: request = client, contentType, ...config } = options" : "const { client: request = client, ...config } = options",
|
|
975
|
+
body.mergeContentType ? "const { client: request = client, contentType, ...config } = options" : "const { client: request = client, ...config } = options",
|
|
887
976
|
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)("br", {}),
|
|
888
|
-
|
|
977
|
+
body.statement
|
|
889
978
|
]
|
|
890
979
|
})
|
|
891
980
|
});
|
|
892
981
|
}
|
|
982
|
+
// ../../internals/client/src/components/StreamRuntime.tsx
|
|
983
|
+
/**
|
|
984
|
+
* The `footer` of `.kubb/client.ts`: the `baseURL` set at generation time, and the `sse.ts` re-export when the document
|
|
985
|
+
* streams events, so `ServerSentEvent` and `toEventStream` stay importable from the client as in earlier releases.
|
|
986
|
+
*/
|
|
987
|
+
function buildClientFooter({ baseURL, sse }) {
|
|
988
|
+
const baseURLExpression = baseURL ? baseURL.includes("${") ? `\`${baseURL.replaceAll("`", "\\`")}\`` : JSON.stringify(baseURL) : void 0;
|
|
989
|
+
return [baseURLExpression ? `client.setConfig({ baseURL: ${baseURLExpression} })` : null, sse ? `export * from './sse.ts'` : null].filter(Boolean).join("\n") || void 0;
|
|
990
|
+
}
|
|
991
|
+
/**
|
|
992
|
+
* Writes the footer of the `.kubb/client.ts` the plugin injected, the one place it is built, and copies `sse.ts` into
|
|
993
|
+
* `.kubb/` only for a document with a `text/event-stream` operation, so a document without streams ships no stream runtime.
|
|
994
|
+
* `sse` is set by the plugins that ship the runtime, so a custom client from `@kubb/plugin-client` gets neither file.
|
|
995
|
+
*/
|
|
996
|
+
function StreamRuntime({ nodes, root, sse, baseURL }) {
|
|
997
|
+
if (!sse) return null;
|
|
998
|
+
const streams = nodes.some(isEventStream);
|
|
999
|
+
const footer = buildClientFooter({
|
|
1000
|
+
baseURL,
|
|
1001
|
+
sse: streams
|
|
1002
|
+
});
|
|
1003
|
+
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, {
|
|
1004
|
+
baseName: "sse.ts",
|
|
1005
|
+
path: node_path.default.resolve(root, ".kubb/sse.ts"),
|
|
1006
|
+
copy: sse
|
|
1007
|
+
}), footer && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File, {
|
|
1008
|
+
baseName: "client.ts",
|
|
1009
|
+
path: node_path.default.resolve(root, ".kubb/client.ts"),
|
|
1010
|
+
footer
|
|
1011
|
+
})] });
|
|
1012
|
+
}
|
|
893
1013
|
// ../../internals/client/src/resolveOperationTypes.ts
|
|
894
1014
|
/**
|
|
895
1015
|
* A `plugin-ts` shaped resolver whose operation type names point at the types `pluginZod({ inferred })`
|
|
@@ -965,13 +1085,24 @@ function resolveOperationTypes(driver, pluginName) {
|
|
|
965
1085
|
* `@kubb/plugin-axios`). Emits one async function per OpenAPI operation using the shared
|
|
966
1086
|
* `Operation` component: a grouped `<Name>Request` type and a function that forwards a single
|
|
967
1087
|
* `options` object to the bundled `client` and returns the `Unwrappable<RequestResult>`. Only the
|
|
968
|
-
* generator `name`
|
|
969
|
-
* identical.
|
|
1088
|
+
* generator `name` and the runtime templates differ between plugins. Every other resolution, import,
|
|
1089
|
+
* and rendering step is identical.
|
|
1090
|
+
*
|
|
1091
|
+
* `sse` is the Server-Sent Events runtime template, copied into `.kubb/sse.ts` only for a document with a
|
|
1092
|
+
* `text/event-stream` operation.
|
|
970
1093
|
*/
|
|
971
|
-
function createClientGenerator(name) {
|
|
1094
|
+
function createClientGenerator(name, { sse } = {}) {
|
|
972
1095
|
return (0, _kubb_kit.defineGenerator)({
|
|
973
1096
|
name,
|
|
974
1097
|
renderer: _kubb_renderer_jsx.jsxRenderer,
|
|
1098
|
+
operations(nodes, ctx) {
|
|
1099
|
+
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(StreamRuntime, {
|
|
1100
|
+
nodes,
|
|
1101
|
+
root: ctx.root,
|
|
1102
|
+
sse,
|
|
1103
|
+
baseURL: ctx.options.baseURL
|
|
1104
|
+
});
|
|
1105
|
+
},
|
|
975
1106
|
operation(node, ctx) {
|
|
976
1107
|
if (!_kubb_kit.ast.isHttpOperationNode(node)) return null;
|
|
977
1108
|
const { config, driver, resolver, root } = ctx;
|
|
@@ -1021,19 +1152,19 @@ function createClientGenerator(name) {
|
|
|
1021
1152
|
const clientPath = importPath ?? node_path.default.resolve(root, ".kubb/client.ts");
|
|
1022
1153
|
const clientRoot = importPath === void 0 ? meta.file.path : void 0;
|
|
1023
1154
|
const standardSchemaPath = importPath ?? node_path.default.resolve(root, ".kubb/standardSchema.ts");
|
|
1024
|
-
const
|
|
1155
|
+
const ssePath = importPath ?? node_path.default.resolve(root, ".kubb/sse.ts");
|
|
1156
|
+
const stream = getEventStream(node);
|
|
1025
1157
|
const clientValueImports = (() => {
|
|
1026
|
-
if (eventStream) return ["client", "toEventStream"];
|
|
1027
1158
|
if (returnType === "plain") return ["client"];
|
|
1028
1159
|
if (returnType === "data") return ["client", "unwrapResult"];
|
|
1029
1160
|
return ["client", "withUnwrap"];
|
|
1030
1161
|
})();
|
|
1031
1162
|
const clientTypeImports = (() => {
|
|
1032
|
-
if (
|
|
1033
|
-
"Options",
|
|
1034
|
-
"
|
|
1035
|
-
"SuccessOf"
|
|
1036
|
-
];
|
|
1163
|
+
if (stream) return {
|
|
1164
|
+
plain: ["Options", "SuccessOf"],
|
|
1165
|
+
data: ["SuccessOf"],
|
|
1166
|
+
full: ["SuccessOf", "Unwrappable"]
|
|
1167
|
+
}[returnType];
|
|
1037
1168
|
if (returnType === "plain") return ["Options", "RequestResult"];
|
|
1038
1169
|
if (returnType === "data") return ["Options", "UnwrappedResult"];
|
|
1039
1170
|
return [
|
|
@@ -1074,6 +1205,20 @@ function createClientGenerator(name) {
|
|
|
1074
1205
|
path: clientPath,
|
|
1075
1206
|
isTypeOnly: true
|
|
1076
1207
|
}),
|
|
1208
|
+
stream && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1209
|
+
name: ["toEventStream"],
|
|
1210
|
+
root: clientRoot,
|
|
1211
|
+
path: ssePath
|
|
1212
|
+
}),
|
|
1213
|
+
stream && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1214
|
+
name: buildEventStreamImports({
|
|
1215
|
+
returnType,
|
|
1216
|
+
typed: stream === "event"
|
|
1217
|
+
}),
|
|
1218
|
+
root: clientRoot,
|
|
1219
|
+
path: ssePath,
|
|
1220
|
+
isTypeOnly: true
|
|
1221
|
+
}),
|
|
1077
1222
|
meta.fileTypes && importedTypeNames.length > 0 && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1078
1223
|
name: Array.from(new Set(importedTypeNames)),
|
|
1079
1224
|
root: meta.file.path,
|
|
@@ -1106,11 +1251,11 @@ function createClientGenerator(name) {
|
|
|
1106
1251
|
}
|
|
1107
1252
|
// ../../internals/client/src/macros.ts
|
|
1108
1253
|
/**
|
|
1109
|
-
* Macros the client plugins apply by default, ahead of any user macros. `
|
|
1110
|
-
* drops union members
|
|
1254
|
+
* Macros the client plugins apply by default, ahead of any user macros. `macroDedupeUnion`
|
|
1255
|
+
* drops repeated union members, keeping the generated response and error
|
|
1111
1256
|
* unions tidy. A plugin wires them with `ctx.setMacros([...defaultMacros, ...userMacros])`.
|
|
1112
1257
|
*/
|
|
1113
|
-
const defaultMacros = [_kubb_kit.
|
|
1258
|
+
const defaultMacros = [_kubb_kit.macroDedupeUnion];
|
|
1114
1259
|
// ../../internals/client/src/resolver.ts
|
|
1115
1260
|
/**
|
|
1116
1261
|
* Default resolver shared by the client plugins. Functions use safe camelCase identifiers and
|