@kubb/plugin-client 6.1.0-canary.20261109T175349 → 6.1.0-canary.20261109T175913
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-D0IfSe5q.d.ts → client-DaI8VaEz.d.ts} +2 -3
- package/dist/index.cjs +43 -36
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +43 -36
- package/dist/index.js.map +1 -1
- package/dist/templates/client.d.ts +1 -1
- package/dist/templates/core.d.ts +1 -1
- package/dist/templates/sse.d.ts +1 -1
- package/docs/guides/validate-requests-and-responses.md +7 -4
- package/package.json +5 -5
- package/templates/core.ts +9 -9
|
@@ -203,7 +203,7 @@ type RequestConfig<TBody = unknown, TRequest = NativeRequest, TResponse = Native
|
|
|
203
203
|
transport?: Transport<TRequest, TResponse>;
|
|
204
204
|
serializer?: Serializers;
|
|
205
205
|
codecs?: Record<string, Codec>;
|
|
206
|
-
/** `
|
|
206
|
+
/** `error` takes one validator for every non-2xx body, or a map by status such as `{ 404: schema, '5XX': schema, default: schema }`. */
|
|
207
207
|
validator?: {
|
|
208
208
|
request?: Validator;
|
|
209
209
|
path?: Validator;
|
|
@@ -211,8 +211,7 @@ type RequestConfig<TBody = unknown, TRequest = NativeRequest, TResponse = Native
|
|
|
211
211
|
headers?: Validator;
|
|
212
212
|
cookies?: Validator;
|
|
213
213
|
response?: Validator;
|
|
214
|
-
error?: Validator
|
|
215
|
-
errorStatus?: Array<number | string>;
|
|
214
|
+
error?: Validator | Record<string, Validator>;
|
|
216
215
|
};
|
|
217
216
|
onValidationError?: ValidationErrorHandler;
|
|
218
217
|
validate?: ValidateOption;
|
package/dist/index.cjs
CHANGED
|
@@ -547,7 +547,7 @@ var compatibility = {
|
|
|
547
547
|
"node": ">=22.22"
|
|
548
548
|
};
|
|
549
549
|
// package.json
|
|
550
|
-
var version = "6.1.0-canary.
|
|
550
|
+
var version = "6.1.0-canary.20261109T175913";
|
|
551
551
|
// ../../internals/client/src/builders/validatorOptions.ts
|
|
552
552
|
/**
|
|
553
553
|
* Returns `true` when any direction of the validator uses zod (used for dependency checks).
|
|
@@ -583,22 +583,19 @@ function resolveResponseValidator(validator) {
|
|
|
583
583
|
return validator.response ?? null;
|
|
584
584
|
}
|
|
585
585
|
/**
|
|
586
|
-
*
|
|
587
|
-
*
|
|
588
|
-
* operation documents no error responses with a schema.
|
|
586
|
+
* Builds the `validator.error` map of a call, one plugin-zod `<operation>StatusNNNSchema` per non-2xx response with a
|
|
587
|
+
* schema, such as `{ 404: getPetStatus404Schema, '5XX': getPetStatus5XXSchema }`. Returns `null` without one.
|
|
589
588
|
*/
|
|
590
589
|
function buildZodErrorParse(node, zodResolver) {
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
}
|
|
600
|
-
function getErrorStatusCodes(node) {
|
|
601
|
-
return node.responses.filter((res) => !isSuccessStatusCode(res.statusCode) && res.content?.some((entry) => entry.schema)).map((res) => String(res.statusCode));
|
|
590
|
+
const entries = node.responses.filter((res) => !isSuccessStatusCode(res.statusCode) && res.content?.some((entry) => entry.schema)).map((res) => ({
|
|
591
|
+
key: String(res.statusCode),
|
|
592
|
+
name: zodResolver.response.status(node, res.statusCode)
|
|
593
|
+
}));
|
|
594
|
+
if (!entries.length) return null;
|
|
595
|
+
return {
|
|
596
|
+
literal: `{ ${entries.map(({ key, name }) => `${/^\d+$/.test(key) ? key : stringify(key)}: ${name}`).join(", ")} }`,
|
|
597
|
+
names: entries.map(({ name }) => name)
|
|
598
|
+
};
|
|
602
599
|
}
|
|
603
600
|
// ../../internals/client/src/builders/generics.ts
|
|
604
601
|
/**
|
|
@@ -803,8 +800,7 @@ function buildValidatorHooks({ node, validator, zodResolver }) {
|
|
|
803
800
|
const hasRequestBody = Boolean(node.requestBody?.content?.[0]?.schema);
|
|
804
801
|
const parsesResponse = zodResolver && resolveResponseValidator(validator) === "zod";
|
|
805
802
|
const response = parsesResponse ? zodResolver.response.response(node) || null : null;
|
|
806
|
-
const
|
|
807
|
-
const errorStatus = error ? buildErrorStatusLiteral(node) : null;
|
|
803
|
+
const errorParse = parsesResponse ? buildZodErrorParse(node, zodResolver) : null;
|
|
808
804
|
const request = zodResolver && resolveRequestValidator(validator) === "zod" && hasRequestBody ? zodResolver.response.body(node) || null : null;
|
|
809
805
|
const paramGroups = getOperationParameters(node);
|
|
810
806
|
const resolveParamsName = (kind, params) => zodResolver && resolveParamsValidator(validator) === "zod" && params.length > 0 ? zodResolver.param[kind](node, params[0]) : null;
|
|
@@ -814,7 +810,7 @@ function buildValidatorHooks({ node, validator, zodResolver }) {
|
|
|
814
810
|
const cookies = resolveParamsName("cookies", paramGroups.cookie);
|
|
815
811
|
const importedZodNames = [
|
|
816
812
|
response,
|
|
817
|
-
|
|
813
|
+
...errorParse?.names ?? [],
|
|
818
814
|
request,
|
|
819
815
|
path,
|
|
820
816
|
query,
|
|
@@ -828,17 +824,17 @@ function buildValidatorHooks({ node, validator, zodResolver }) {
|
|
|
828
824
|
headers: headers ? `toHeadersStandardSchema(${headers}, ${headers}.shape)` : null,
|
|
829
825
|
cookies,
|
|
830
826
|
response,
|
|
831
|
-
error,
|
|
832
|
-
errorStatus,
|
|
827
|
+
error: errorParse?.literal ?? null,
|
|
833
828
|
importedZodNames
|
|
834
829
|
};
|
|
835
830
|
}
|
|
836
831
|
/**
|
|
837
832
|
* Prints the `validator: { … }` entry of a call config from the hooks named in `keys`, or `null` when none is set.
|
|
833
|
+
* The entry spreads `config.validator` last, so a per-call hook overrides the generated one for its key only.
|
|
838
834
|
*/
|
|
839
835
|
function buildValidatorLiteral(hooks, keys) {
|
|
840
836
|
const entries = keys.flatMap((key) => hooks?.[key] ? [`${key}: ${hooks[key]}`] : []);
|
|
841
|
-
return entries.length ? `validator: { ${entries.join(", ")} }` : null;
|
|
837
|
+
return entries.length ? `validator: { ${entries.join(", ")}, ...config.validator }` : null;
|
|
842
838
|
}
|
|
843
839
|
// ../../internals/client/src/builders/contentType.ts
|
|
844
840
|
/**
|
|
@@ -891,13 +887,13 @@ function serializeParameter(parameter) {
|
|
|
891
887
|
return parts.length > 0 ? `{ ${parts.join(", ")} }` : null;
|
|
892
888
|
}
|
|
893
889
|
/**
|
|
894
|
-
* Serializes the `encoding` of the request body's default content type into
|
|
895
|
-
*
|
|
890
|
+
* Serializes the `encoding` of the request body's default content type into `property: { ... }`
|
|
891
|
+
* entries, empty when it carries none. Only an operation with a single request content type
|
|
896
892
|
* emits it, because the runtime applies `styles.body` to whichever type the caller selects.
|
|
897
893
|
*/
|
|
898
894
|
function serializeBodyEncoding(node) {
|
|
899
895
|
const content = node.requestBody?.content;
|
|
900
|
-
|
|
896
|
+
return Object.entries(content?.length === 1 ? content[0]?.encoding ?? {} : {}).map(([property, { contentType, style, explode, allowReserved }]) => {
|
|
901
897
|
const parts = [
|
|
902
898
|
style && `style: ${JSON.stringify(style)}`,
|
|
903
899
|
explode !== void 0 && `explode: ${explode}`,
|
|
@@ -906,7 +902,6 @@ function serializeBodyEncoding(node) {
|
|
|
906
902
|
].filter(Boolean);
|
|
907
903
|
return `${isValidVarName(property) ? property : JSON.stringify(property)}: { ${parts.join(", ")} }`;
|
|
908
904
|
});
|
|
909
|
-
return entries.length > 0 ? `body: { ${entries.join(", ")} }` : null;
|
|
910
905
|
}
|
|
911
906
|
/**
|
|
912
907
|
* Builds the per-operation `styles` literal from the operation's parameters, grouped by location.
|
|
@@ -916,26 +911,31 @@ function serializeBodyEncoding(node) {
|
|
|
916
911
|
* is unchanged. A form request body adds a `body` group keyed by property name from its `encoding`.
|
|
917
912
|
* Returns `null` when nothing carries metadata.
|
|
918
913
|
*
|
|
914
|
+
* With `merge`, the literal spreads `config.styles` per parameter, so a per-call entry overrides the generated one for
|
|
915
|
+
* that parameter and leaves the others in place.
|
|
916
|
+
*
|
|
919
917
|
* @example
|
|
920
918
|
* ```ts
|
|
921
919
|
* // a path param with { style: 'matrix', explode: true } and a query param with { explode: false }
|
|
922
920
|
* buildStyles({ node }) // "{ path: { id: { style: 'matrix', explode: true } }, query: { tags: { explode: false } } }"
|
|
923
921
|
* ```
|
|
924
922
|
*/
|
|
925
|
-
function buildStyles({ node }) {
|
|
923
|
+
function buildStyles({ node, merge }) {
|
|
926
924
|
if (!_kubb_kit.ast.isHttpOperationNode(node)) return null;
|
|
927
925
|
const groups = {
|
|
928
926
|
path: [],
|
|
929
927
|
query: [],
|
|
930
928
|
header: [],
|
|
931
|
-
cookie: []
|
|
929
|
+
cookie: [],
|
|
930
|
+
body: serializeBodyEncoding(node)
|
|
932
931
|
};
|
|
933
932
|
for (const [location, parameters] of Object.entries(getOperationParameters(node))) for (const parameter of parameters) {
|
|
934
933
|
const literal = serializeParameter(parameter);
|
|
935
934
|
if (literal) groups[location].push(`${toKey(parameter.name)}: ${literal}`);
|
|
936
935
|
}
|
|
937
|
-
const entries =
|
|
938
|
-
|
|
936
|
+
const entries = Object.entries(groups).filter(([, items]) => items.length > 0).map(([location, items]) => `${location}: { ${(merge ? [...items, `...config.styles?.${location}`] : items).join(", ")} }`);
|
|
937
|
+
if (entries.length === 0) return null;
|
|
938
|
+
return `{ ${(merge ? ["...config.styles", ...entries] : entries).join(", ")} }`;
|
|
939
939
|
}
|
|
940
940
|
// ../../internals/client/src/builders/callConfig.ts
|
|
941
941
|
/**
|
|
@@ -951,7 +951,9 @@ function buildResponseTypeLiteral(node) {
|
|
|
951
951
|
}
|
|
952
952
|
/**
|
|
953
953
|
* Builds the call config literal a generated operation forwards to the client, shared by the standalone
|
|
954
|
-
* functions and the SDK methods. The `throwOnError`
|
|
954
|
+
* functions and the SDK methods. The `validator` and `throwOnError` entries come after the `...config` spread, so a
|
|
955
|
+
* per-call `validator` is merged per key with the generated one instead of replacing it. `styles` is merged the same
|
|
956
|
+
* way, per parameter, unless `returnType` is `'plain'`.
|
|
955
957
|
*
|
|
956
958
|
* `mergeContentType` is `true` when the caller must destructure `contentType` from `options`, and
|
|
957
959
|
* `eventStream` is `true` when the operation streams `text/event-stream` or JSON Lines. Unless `returnType` is `'plain'`, a
|
|
@@ -960,16 +962,20 @@ function buildResponseTypeLiteral(node) {
|
|
|
960
962
|
function buildCallConfig({ node, validatorHooks, security, throwOnErrorDefault, returnType }) {
|
|
961
963
|
const eventStream = isEventStream(node);
|
|
962
964
|
const securityLiteral = buildSecurityMetadata({ security });
|
|
963
|
-
const
|
|
965
|
+
const ownRuntime = returnType !== "plain";
|
|
966
|
+
const stylesLiteral = buildStyles({
|
|
967
|
+
node,
|
|
968
|
+
merge: ownRuntime
|
|
969
|
+
});
|
|
970
|
+
const styles = stylesLiteral ? `styles: ${stylesLiteral}` : null;
|
|
964
971
|
const validatorLiteral = buildValidatorLiteral(validatorHooks, [
|
|
965
972
|
"request",
|
|
966
973
|
"path",
|
|
967
974
|
"query",
|
|
968
975
|
"headers",
|
|
969
976
|
"cookies",
|
|
970
|
-
...eventStream &&
|
|
971
|
-
"error"
|
|
972
|
-
"errorStatus"
|
|
977
|
+
...eventStream && ownRuntime ? [] : ["response"],
|
|
978
|
+
"error"
|
|
973
979
|
]);
|
|
974
980
|
const { literal: contentTypeLiteral, merge: mergeContentType } = buildContentType({ node });
|
|
975
981
|
return {
|
|
@@ -977,11 +983,12 @@ function buildCallConfig({ node, validatorHooks, security, throwOnErrorDefault,
|
|
|
977
983
|
`method: '${node.method.toUpperCase()}'`,
|
|
978
984
|
`url: '${node.path}'`,
|
|
979
985
|
securityLiteral ? `security: ${securityLiteral}` : null,
|
|
980
|
-
|
|
981
|
-
validatorLiteral,
|
|
986
|
+
ownRuntime ? null : styles,
|
|
982
987
|
contentTypeLiteral,
|
|
983
988
|
buildResponseTypeLiteral(node),
|
|
984
989
|
"...config",
|
|
990
|
+
ownRuntime ? styles : null,
|
|
991
|
+
validatorLiteral,
|
|
985
992
|
`throwOnError: config.throwOnError ?? ${throwOnErrorDefault}`
|
|
986
993
|
].filter(Boolean).join(", ")} }`,
|
|
987
994
|
mergeContentType,
|