@kubb/plugin-client 6.1.0-canary.20261109T175349 → 6.1.0-canary.20261109T191216
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 +69 -40
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +69 -40
- 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.20261109T191216";
|
|
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
|
/**
|
|
@@ -793,6 +790,18 @@ function buildSecurityMetadata({ security }) {
|
|
|
793
790
|
if (!security?.length) return null;
|
|
794
791
|
return `[${security.map(serializeAuth).join(", ")}]`;
|
|
795
792
|
}
|
|
793
|
+
// ../../internals/client/src/builders/server.ts
|
|
794
|
+
/**
|
|
795
|
+
* Returns the URL of the operation's own `servers`, else its path item's, picked with `server.index` and falling back to the
|
|
796
|
+
* first entry. Returns `undefined` without `servers`, for a relative URL such as `/v2`, which would drop the client's host, or
|
|
797
|
+
* for a URL with `{variable}` placeholders, which are not supported, so the client's `baseURL` applies.
|
|
798
|
+
*/
|
|
799
|
+
function getOperationBaseURL({ document, method, path, server: { index = 0 } = {} }) {
|
|
800
|
+
const pathItem = document?.paths?.[path];
|
|
801
|
+
const servers = [(pathItem?.[method.toLowerCase()])?.servers, pathItem?.servers].find((list) => list?.length);
|
|
802
|
+
const url = (servers?.[index] ?? servers?.[0])?.url;
|
|
803
|
+
return url && /^[a-z][a-z\d+.-]*:\/\/[^{}]*$/i.test(url) ? url : void 0;
|
|
804
|
+
}
|
|
796
805
|
// ../../internals/client/src/builders/validator.ts
|
|
797
806
|
/**
|
|
798
807
|
* Builds the validator-hook references for one operation. Request body and params validation run before the send.
|
|
@@ -803,8 +812,7 @@ function buildValidatorHooks({ node, validator, zodResolver }) {
|
|
|
803
812
|
const hasRequestBody = Boolean(node.requestBody?.content?.[0]?.schema);
|
|
804
813
|
const parsesResponse = zodResolver && resolveResponseValidator(validator) === "zod";
|
|
805
814
|
const response = parsesResponse ? zodResolver.response.response(node) || null : null;
|
|
806
|
-
const
|
|
807
|
-
const errorStatus = error ? buildErrorStatusLiteral(node) : null;
|
|
815
|
+
const errorParse = parsesResponse ? buildZodErrorParse(node, zodResolver) : null;
|
|
808
816
|
const request = zodResolver && resolveRequestValidator(validator) === "zod" && hasRequestBody ? zodResolver.response.body(node) || null : null;
|
|
809
817
|
const paramGroups = getOperationParameters(node);
|
|
810
818
|
const resolveParamsName = (kind, params) => zodResolver && resolveParamsValidator(validator) === "zod" && params.length > 0 ? zodResolver.param[kind](node, params[0]) : null;
|
|
@@ -814,7 +822,7 @@ function buildValidatorHooks({ node, validator, zodResolver }) {
|
|
|
814
822
|
const cookies = resolveParamsName("cookies", paramGroups.cookie);
|
|
815
823
|
const importedZodNames = [
|
|
816
824
|
response,
|
|
817
|
-
|
|
825
|
+
...errorParse?.names ?? [],
|
|
818
826
|
request,
|
|
819
827
|
path,
|
|
820
828
|
query,
|
|
@@ -828,17 +836,17 @@ function buildValidatorHooks({ node, validator, zodResolver }) {
|
|
|
828
836
|
headers: headers ? `toHeadersStandardSchema(${headers}, ${headers}.shape)` : null,
|
|
829
837
|
cookies,
|
|
830
838
|
response,
|
|
831
|
-
error,
|
|
832
|
-
errorStatus,
|
|
839
|
+
error: errorParse?.literal ?? null,
|
|
833
840
|
importedZodNames
|
|
834
841
|
};
|
|
835
842
|
}
|
|
836
843
|
/**
|
|
837
844
|
* Prints the `validator: { … }` entry of a call config from the hooks named in `keys`, or `null` when none is set.
|
|
845
|
+
* The entry spreads `config.validator` last, so a per-call hook overrides the generated one for its key only.
|
|
838
846
|
*/
|
|
839
847
|
function buildValidatorLiteral(hooks, keys) {
|
|
840
848
|
const entries = keys.flatMap((key) => hooks?.[key] ? [`${key}: ${hooks[key]}`] : []);
|
|
841
|
-
return entries.length ? `validator: { ${entries.join(", ")} }` : null;
|
|
849
|
+
return entries.length ? `validator: { ${entries.join(", ")}, ...config.validator }` : null;
|
|
842
850
|
}
|
|
843
851
|
// ../../internals/client/src/builders/contentType.ts
|
|
844
852
|
/**
|
|
@@ -891,13 +899,13 @@ function serializeParameter(parameter) {
|
|
|
891
899
|
return parts.length > 0 ? `{ ${parts.join(", ")} }` : null;
|
|
892
900
|
}
|
|
893
901
|
/**
|
|
894
|
-
* Serializes the `encoding` of the request body's default content type into
|
|
895
|
-
*
|
|
902
|
+
* Serializes the `encoding` of the request body's default content type into `property: { ... }`
|
|
903
|
+
* entries, empty when it carries none. Only an operation with a single request content type
|
|
896
904
|
* emits it, because the runtime applies `styles.body` to whichever type the caller selects.
|
|
897
905
|
*/
|
|
898
906
|
function serializeBodyEncoding(node) {
|
|
899
907
|
const content = node.requestBody?.content;
|
|
900
|
-
|
|
908
|
+
return Object.entries(content?.length === 1 ? content[0]?.encoding ?? {} : {}).map(([property, { contentType, style, explode, allowReserved }]) => {
|
|
901
909
|
const parts = [
|
|
902
910
|
style && `style: ${JSON.stringify(style)}`,
|
|
903
911
|
explode !== void 0 && `explode: ${explode}`,
|
|
@@ -906,7 +914,6 @@ function serializeBodyEncoding(node) {
|
|
|
906
914
|
].filter(Boolean);
|
|
907
915
|
return `${isValidVarName(property) ? property : JSON.stringify(property)}: { ${parts.join(", ")} }`;
|
|
908
916
|
});
|
|
909
|
-
return entries.length > 0 ? `body: { ${entries.join(", ")} }` : null;
|
|
910
917
|
}
|
|
911
918
|
/**
|
|
912
919
|
* Builds the per-operation `styles` literal from the operation's parameters, grouped by location.
|
|
@@ -916,26 +923,31 @@ function serializeBodyEncoding(node) {
|
|
|
916
923
|
* is unchanged. A form request body adds a `body` group keyed by property name from its `encoding`.
|
|
917
924
|
* Returns `null` when nothing carries metadata.
|
|
918
925
|
*
|
|
926
|
+
* With `merge`, the literal spreads `config.styles` per parameter, so a per-call entry overrides the generated one for
|
|
927
|
+
* that parameter and leaves the others in place.
|
|
928
|
+
*
|
|
919
929
|
* @example
|
|
920
930
|
* ```ts
|
|
921
931
|
* // a path param with { style: 'matrix', explode: true } and a query param with { explode: false }
|
|
922
932
|
* buildStyles({ node }) // "{ path: { id: { style: 'matrix', explode: true } }, query: { tags: { explode: false } } }"
|
|
923
933
|
* ```
|
|
924
934
|
*/
|
|
925
|
-
function buildStyles({ node }) {
|
|
935
|
+
function buildStyles({ node, merge }) {
|
|
926
936
|
if (!_kubb_kit.ast.isHttpOperationNode(node)) return null;
|
|
927
937
|
const groups = {
|
|
928
938
|
path: [],
|
|
929
939
|
query: [],
|
|
930
940
|
header: [],
|
|
931
|
-
cookie: []
|
|
941
|
+
cookie: [],
|
|
942
|
+
body: serializeBodyEncoding(node)
|
|
932
943
|
};
|
|
933
944
|
for (const [location, parameters] of Object.entries(getOperationParameters(node))) for (const parameter of parameters) {
|
|
934
945
|
const literal = serializeParameter(parameter);
|
|
935
946
|
if (literal) groups[location].push(`${toKey(parameter.name)}: ${literal}`);
|
|
936
947
|
}
|
|
937
|
-
const entries =
|
|
938
|
-
|
|
948
|
+
const entries = Object.entries(groups).filter(([, items]) => items.length > 0).map(([location, items]) => `${location}: { ${(merge ? [...items, `...config.styles?.${location}`] : items).join(", ")} }`);
|
|
949
|
+
if (entries.length === 0) return null;
|
|
950
|
+
return `{ ${(merge ? ["...config.styles", ...entries] : entries).join(", ")} }`;
|
|
939
951
|
}
|
|
940
952
|
// ../../internals/client/src/builders/callConfig.ts
|
|
941
953
|
/**
|
|
@@ -951,37 +963,45 @@ function buildResponseTypeLiteral(node) {
|
|
|
951
963
|
}
|
|
952
964
|
/**
|
|
953
965
|
* Builds the call config literal a generated operation forwards to the client, shared by the standalone
|
|
954
|
-
* functions and the SDK methods. The `
|
|
966
|
+
* functions and the SDK methods. The operation's own `baseURL` comes before the `...config` spread, so a per-call one wins. The
|
|
967
|
+
* `validator` and `throwOnError` entries come after it, so a per-call `validator` is merged per key with the generated one instead
|
|
968
|
+
* of replacing it. `styles` is merged the same way, per parameter, unless `returnType` is `'plain'`.
|
|
955
969
|
*
|
|
956
970
|
* `mergeContentType` is `true` when the caller must destructure `contentType` from `options`, and
|
|
957
971
|
* `eventStream` is `true` when the operation streams `text/event-stream` or JSON Lines. Unless `returnType` is `'plain'`, a
|
|
958
972
|
* stream's literal leaves the `response` validator to `toEventStream`, which runs it per item.
|
|
959
973
|
*/
|
|
960
|
-
function buildCallConfig({ node, validatorHooks, security, throwOnErrorDefault, returnType }) {
|
|
974
|
+
function buildCallConfig({ node, validatorHooks, security, baseURL, throwOnErrorDefault, returnType }) {
|
|
961
975
|
const eventStream = isEventStream(node);
|
|
962
976
|
const securityLiteral = buildSecurityMetadata({ security });
|
|
963
|
-
const
|
|
977
|
+
const ownRuntime = returnType !== "plain";
|
|
978
|
+
const stylesLiteral = buildStyles({
|
|
979
|
+
node,
|
|
980
|
+
merge: ownRuntime
|
|
981
|
+
});
|
|
982
|
+
const styles = stylesLiteral ? `styles: ${stylesLiteral}` : null;
|
|
964
983
|
const validatorLiteral = buildValidatorLiteral(validatorHooks, [
|
|
965
984
|
"request",
|
|
966
985
|
"path",
|
|
967
986
|
"query",
|
|
968
987
|
"headers",
|
|
969
988
|
"cookies",
|
|
970
|
-
...eventStream &&
|
|
971
|
-
"error"
|
|
972
|
-
"errorStatus"
|
|
989
|
+
...eventStream && ownRuntime ? [] : ["response"],
|
|
990
|
+
"error"
|
|
973
991
|
]);
|
|
974
992
|
const { literal: contentTypeLiteral, merge: mergeContentType } = buildContentType({ node });
|
|
975
993
|
return {
|
|
976
994
|
callConfig: `{ ${[
|
|
977
995
|
`method: '${node.method.toUpperCase()}'`,
|
|
978
996
|
`url: '${node.path}'`,
|
|
997
|
+
baseURL ? `baseURL: ${JSON.stringify(baseURL)}` : null,
|
|
979
998
|
securityLiteral ? `security: ${securityLiteral}` : null,
|
|
980
|
-
|
|
981
|
-
validatorLiteral,
|
|
999
|
+
ownRuntime ? null : styles,
|
|
982
1000
|
contentTypeLiteral,
|
|
983
1001
|
buildResponseTypeLiteral(node),
|
|
984
1002
|
"...config",
|
|
1003
|
+
ownRuntime ? styles : null,
|
|
1004
|
+
validatorLiteral,
|
|
985
1005
|
`throwOnError: config.throwOnError ?? ${throwOnErrorDefault}`
|
|
986
1006
|
].filter(Boolean).join(", ")} }`,
|
|
987
1007
|
mergeContentType,
|
|
@@ -1023,11 +1043,12 @@ function buildGroupedOptionsSignature({ node, types, returnType, throwOnErrorDef
|
|
|
1023
1043
|
* body destructures `contentType` from `options`. Shared by the standalone functions and the SDK methods, so a
|
|
1024
1044
|
* `text/event-stream` operation is wired to `toEventStream` in one place.
|
|
1025
1045
|
*/
|
|
1026
|
-
function buildOperationBody({ node, types, validatorHooks, security, returnType, throwOnErrorDefault }) {
|
|
1046
|
+
function buildOperationBody({ node, types, validatorHooks, security, baseURL, returnType, throwOnErrorDefault }) {
|
|
1027
1047
|
const { callConfig, mergeContentType, eventStream } = buildCallConfig({
|
|
1028
1048
|
node,
|
|
1029
1049
|
validatorHooks,
|
|
1030
1050
|
security,
|
|
1051
|
+
baseURL,
|
|
1031
1052
|
throwOnErrorDefault,
|
|
1032
1053
|
returnType
|
|
1033
1054
|
});
|
|
@@ -1067,13 +1088,14 @@ function buildOperationBody({ node, types, validatorHooks, security, returnType,
|
|
|
1067
1088
|
* type, signature, and call config are built with the AST factory, and only the jsx-renderer emits
|
|
1068
1089
|
* the source.
|
|
1069
1090
|
*/
|
|
1070
|
-
function Operation({ name, node, types, validatorHooks, returnType, throwOnErrorDefault, security }) {
|
|
1091
|
+
function Operation({ name, node, types, validatorHooks, returnType, throwOnErrorDefault, security, baseURL }) {
|
|
1071
1092
|
if (!_kubb_kit.ast.isHttpOperationNode(node)) return null;
|
|
1072
1093
|
const body = buildOperationBody({
|
|
1073
1094
|
node,
|
|
1074
1095
|
types,
|
|
1075
1096
|
validatorHooks,
|
|
1076
1097
|
security,
|
|
1098
|
+
baseURL,
|
|
1077
1099
|
returnType,
|
|
1078
1100
|
throwOnErrorDefault
|
|
1079
1101
|
});
|
|
@@ -1272,6 +1294,12 @@ function createClientGenerator(name, { sse } = {}) {
|
|
|
1272
1294
|
method: node.method,
|
|
1273
1295
|
path: node.path
|
|
1274
1296
|
});
|
|
1297
|
+
const baseURL = getOperationBaseURL({
|
|
1298
|
+
document: ctx.adapter.document,
|
|
1299
|
+
method: node.method,
|
|
1300
|
+
path: node.path,
|
|
1301
|
+
server: ctx.adapter.options?.server
|
|
1302
|
+
});
|
|
1275
1303
|
const clientPath = importPath ?? node_path.default.resolve(root, ".kubb/client.ts");
|
|
1276
1304
|
const clientRoot = importPath === void 0 ? meta.file.path : void 0;
|
|
1277
1305
|
const standardSchemaPath = importPath ?? node_path.default.resolve(root, ".kubb/standardSchema.ts");
|
|
@@ -1366,7 +1394,8 @@ function createClientGenerator(name, { sse } = {}) {
|
|
|
1366
1394
|
validatorHooks,
|
|
1367
1395
|
returnType,
|
|
1368
1396
|
throwOnErrorDefault,
|
|
1369
|
-
security
|
|
1397
|
+
security,
|
|
1398
|
+
baseURL
|
|
1370
1399
|
})
|
|
1371
1400
|
]
|
|
1372
1401
|
});
|