@kubb/plugin-fetch 5.9.0-canary.20261024T190549 → 5.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -1,17 +1,19 @@
1
1
  import { Exclude, Group, Include, Output, OutputOptions, Override, PluginType, Resolver, ResolverPatch, ast } from "kubb/kit";
2
2
  import "@kubb/plugin-zod";
3
+ import "@kubb/plugin-ts";
3
4
  //#region ../../internals/client/src/types.d.ts
4
5
  /**
5
- * Validator applied to request and response bodies using schemas from `@kubb/plugin-zod`.
6
+ * Validator applied to the request and response using schemas from `@kubb/plugin-zod`.
6
7
  * - `false`: no validation.
7
8
  * - `'zod'`: validates the success (2xx) response body, and the error body when a non-2xx call does
8
9
  * not throw (`throwOnError: false`).
9
- * - `{ request?: 'zod'; response?: 'zod' }`: opt in per direction. `request` validates the request
10
- * body before the call; `response` validates the success response body and,
11
- * on the non-throw path, the error body.
10
+ * - `{ request?: 'zod'; params?: 'zod'; response?: 'zod' }`: opt in per slot. `request` encodes the
11
+ * request body before the call; `params` validate the path, query, and header params;
12
+ * `response` validates the success response body and, on the non-throw path, the error body.
12
13
  */
13
14
  type ValidatorOptions = false | 'zod' | {
14
15
  request?: 'zod';
16
+ params?: 'zod';
15
17
  response?: 'zod';
16
18
  };
17
19
  /**
@@ -86,7 +88,7 @@ type Options = OutputOptions & {
86
88
  */
87
89
  throwOnErrorDefault?: boolean;
88
90
  /**
89
- * Validate request and response bodies with schemas from `@kubb/plugin-zod`.
91
+ * Validate the request body, the request params, and the response with schemas from `@kubb/plugin-zod`.
90
92
  *
91
93
  * @default false
92
94
  */
package/dist/index.d.ts CHANGED
@@ -1,17 +1,19 @@
1
1
  import { Exclude, Group, Include, Output, OutputOptions, Override, PluginType, Resolver, ResolverPatch, ast } from "kubb/kit";
2
2
  import "@kubb/plugin-zod";
3
+ import "@kubb/plugin-ts";
3
4
  //#region ../../internals/client/src/types.d.ts
4
5
  /**
5
- * Validator applied to request and response bodies using schemas from `@kubb/plugin-zod`.
6
+ * Validator applied to the request and response using schemas from `@kubb/plugin-zod`.
6
7
  * - `false`: no validation.
7
8
  * - `'zod'`: validates the success (2xx) response body, and the error body when a non-2xx call does
8
9
  * not throw (`throwOnError: false`).
9
- * - `{ request?: 'zod'; response?: 'zod' }`: opt in per direction. `request` validates the request
10
- * body before the call; `response` validates the success response body and,
11
- * on the non-throw path, the error body.
10
+ * - `{ request?: 'zod'; params?: 'zod'; response?: 'zod' }`: opt in per slot. `request` encodes the
11
+ * request body before the call; `params` validate the path, query, and header params;
12
+ * `response` validates the success response body and, on the non-throw path, the error body.
12
13
  */
13
14
  type ValidatorOptions = false | 'zod' | {
14
15
  request?: 'zod';
16
+ params?: 'zod';
15
17
  response?: 'zod';
16
18
  };
17
19
  /**
@@ -86,7 +88,7 @@ type Options = OutputOptions & {
86
88
  */
87
89
  throwOnErrorDefault?: boolean;
88
90
  /**
89
- * Validate request and response bodies with schemas from `@kubb/plugin-zod`.
91
+ * Validate the request body, the request params, and the response with schemas from `@kubb/plugin-zod`.
90
92
  *
91
93
  * @default false
92
94
  */
package/dist/index.js CHANGED
@@ -446,7 +446,7 @@ function createGroupConfig(group) {
446
446
  function isValidatorEnabled(validator) {
447
447
  if (!validator) return false;
448
448
  if (validator === "zod") return true;
449
- return Boolean(validator.request || validator.response);
449
+ return Boolean(validator.request || validator.params || validator.response);
450
450
  }
451
451
  /**
452
452
  * Returns `'zod'` when request body parsing is enabled, `null` otherwise. The string shorthand
@@ -457,6 +457,14 @@ function resolveRequestValidator(validator) {
457
457
  return validator.request ?? null;
458
458
  }
459
459
  /**
460
+ * Returns `'zod'` when path, query, and header params parsing is enabled, `null` otherwise. Only the
461
+ * object form `{ params: 'zod' }` enables it.
462
+ */
463
+ function resolveParamsValidator(validator) {
464
+ if (!validator || validator === "zod") return null;
465
+ return validator.params ?? null;
466
+ }
467
+ /**
460
468
  * Returns `'zod'` when response parsing is enabled, `null` otherwise. The string shorthand `'zod'`
461
469
  * maps to response parsing.
462
470
  */
@@ -475,30 +483,6 @@ function buildZodErrorParse(node, zodResolver) {
475
483
  return zodResolver.response.error?.(node) || null;
476
484
  }
477
485
  //#endregion
478
- //#region ../../internals/client/src/builders/validator.ts
479
- /**
480
- * Builds the validator-hook references for one operation. Request validation runs before the send;
481
- * response validation runs on the success body only. Returns `null` references when the matching
482
- * direction is disabled or the schema is absent.
483
- */
484
- function buildValidatorHooks({ node, validator, zodResolver }) {
485
- const hasRequestBody = Boolean(node.requestBody?.content?.[0]?.schema);
486
- const parsesResponse = zodResolver && resolveResponseValidator(validator) === "zod";
487
- const response = parsesResponse ? zodResolver.response.response(node) || null : null;
488
- const error = parsesResponse ? buildZodErrorParse(node, zodResolver) : null;
489
- const request = zodResolver && resolveRequestValidator(validator) === "zod" && hasRequestBody ? zodResolver.response.body(node) || null : null;
490
- return {
491
- request,
492
- response,
493
- error,
494
- importedZodNames: [
495
- response,
496
- error,
497
- request
498
- ].filter((name) => Boolean(name))
499
- };
500
- }
501
- //#endregion
502
486
  //#region ../../internals/client/src/builders/security.ts
503
487
  function serializeAuth(auth) {
504
488
  const parts = [`type: '${auth.type}'`];
@@ -571,6 +555,49 @@ function buildSecurityMetadata({ security }) {
571
555
  return `[${security.map(serializeAuth).join(", ")}]`;
572
556
  }
573
557
  //#endregion
558
+ //#region ../../internals/client/src/builders/validator.ts
559
+ /**
560
+ * Builds the validator-hook references for one operation. Request body and params validation run before the send.
561
+ * Response validation runs on the success body only. Returns `null` references when the matching
562
+ * direction is disabled or the schema is absent.
563
+ */
564
+ function buildValidatorHooks({ node, validator, zodResolver }) {
565
+ const hasRequestBody = Boolean(node.requestBody?.content?.[0]?.schema);
566
+ const parsesResponse = zodResolver && resolveResponseValidator(validator) === "zod";
567
+ const response = parsesResponse ? zodResolver.response.response(node) || null : null;
568
+ const error = parsesResponse ? buildZodErrorParse(node, zodResolver) : null;
569
+ const request = zodResolver && resolveRequestValidator(validator) === "zod" && hasRequestBody ? zodResolver.response.body(node) || null : null;
570
+ const paramGroups = getOperationParameters(node);
571
+ const resolveParamsName = (kind, params) => zodResolver && resolveParamsValidator(validator) === "zod" && params.length > 0 ? zodResolver.param[kind](node, params[0]) : null;
572
+ const path = resolveParamsName("path", paramGroups.path);
573
+ const query = resolveParamsName("query", paramGroups.query);
574
+ const headers = resolveParamsName("headers", paramGroups.header);
575
+ const importedZodNames = [
576
+ response,
577
+ error,
578
+ request,
579
+ path,
580
+ query,
581
+ headers
582
+ ].filter((name) => Boolean(name));
583
+ return {
584
+ request,
585
+ path,
586
+ query,
587
+ headers: headers ? `toHeadersStandardSchema(${headers}, ${headers}.shape)` : null,
588
+ response,
589
+ error,
590
+ importedZodNames
591
+ };
592
+ }
593
+ /**
594
+ * Prints the `validator: { … }` entry of a call config from the hooks named in `keys`, or `null` when none is set.
595
+ */
596
+ function buildValidatorLiteral(hooks, keys) {
597
+ const entries = keys.flatMap((key) => hooks?.[key] ? [`${key}: ${hooks[key]}`] : []);
598
+ return entries.length ? `validator: { ${entries.join(", ")} }` : null;
599
+ }
600
+ //#endregion
574
601
  //#region ../../internals/client/src/builders/contentType.ts
575
602
  /**
576
603
  * Builds the `contentType` entry baked into the call config, or `null` for the JSON default.
@@ -775,12 +802,14 @@ function Operation({ name, node, types, zodResolver, validator, returnType, thro
775
802
  const eventStream = isEventStream(node);
776
803
  const responseType = getResponseType(node);
777
804
  const responseTypeLiteral = responseType ? `responseType: '${responseType}'` : null;
778
- const validatorEntries = [
779
- validators.request ? `request: ${validators.request}` : null,
780
- validators.response ? `response: ${validators.response}` : null,
781
- validators.error ? `error: ${validators.error}` : null
782
- ].filter(Boolean);
783
- const validatorLiteral = validatorEntries.length ? `validator: { ${validatorEntries.join(", ")} }` : null;
805
+ const validatorLiteral = buildValidatorLiteral(validators, [
806
+ "request",
807
+ "path",
808
+ "query",
809
+ "headers",
810
+ "response",
811
+ "error"
812
+ ]);
784
813
  const callConfig = `{ ${[
785
814
  `method: '${node.method.toUpperCase()}'`,
786
815
  `url: '${node.path}'`,
@@ -827,14 +856,35 @@ function Operation({ name, node, types, zodResolver, validator, returnType, thro
827
856
  //#endregion
828
857
  //#region ../../internals/client/src/resolveOperationTypes.ts
829
858
  /**
830
- * Picks the plugin a generated client takes its `Options` and `Responses` types from.
859
+ * A `plugin-ts` shaped resolver whose operation type names point at the types `pluginZod({ inferred })`
860
+ * exports next to each schema, so code written against `plugin-ts` names picks up the zod types.
861
+ */
862
+ function toZodTypeResolver(resolver) {
863
+ const type = (name) => resolver.schema.type(name);
864
+ return {
865
+ ...resolver,
866
+ file: resolver.file.bind(resolver),
867
+ param: {
868
+ name: (node, p) => type(resolver.param.name(node, p)),
869
+ path: (node, p) => type(resolver.param.path(node, p)),
870
+ query: (node, p) => type(resolver.param.query(node, p)),
871
+ headers: (node, p) => type(resolver.param.headers(node, p))
872
+ },
873
+ response: {
874
+ body: (node) => type(resolver.response.body(node)),
875
+ status: (node, statusCode) => type(resolver.response.status(node, statusCode)),
876
+ response: (node) => type(resolver.response.response(node)),
877
+ responses: (node) => type(resolver.response.responses(node)),
878
+ options: (node) => resolver.response.options(node)
879
+ }
880
+ };
881
+ }
882
+ /**
883
+ * Picks the plugin generated clients, query hooks, and MCP handlers take their operation types from.
831
884
  *
832
- * `plugin-ts` wins whenever it is in the pipeline, so existing configs keep the types they generate
833
- * today. Without it, `pluginZod({ inferred: true })` takes over: its inferred options and responses
834
- * types are built from the same shared schemas as the `plugin-ts` ones, so a client typed off
835
- * `z.infer` carries what the codecs decode to (a `Temporal` instance, a `Date`) rather than the raw
836
- * wire type. Throws `KUBB_MISSING_DEPENDENCY` for `pluginName` when neither is available, since the
837
- * client has nothing to type against.
885
+ * `pluginZod({ inferred: 'codec' })` wins, so a codec param takes its domain value. Otherwise `plugin-ts`
886
+ * wins when it is in the pipeline, and without it any `pluginZod({ inferred })`. Throws
887
+ * `KUBB_MISSING_DEPENDENCY` for `pluginName` when neither is available.
838
888
  *
839
889
  * @example
840
890
  * ```ts
@@ -844,16 +894,16 @@ function Operation({ name, node, types, zodResolver, validator, returnType, thro
844
894
  */
845
895
  function resolveOperationTypes(driver, pluginName) {
846
896
  const pluginTs = driver.getPlugin(pluginTsName);
847
- if (pluginTs) {
897
+ const pluginZod = driver.getPlugin(pluginZodName);
898
+ if (pluginTs && pluginZod?.options?.inferred !== "codec") {
848
899
  const resolver = driver.getResolver(pluginTsName);
849
900
  return {
850
901
  response: resolver.response,
851
902
  resolver,
852
903
  output: pluginTs.options?.output,
853
- group: pluginTs.options?.group
904
+ group: pluginTs.options?.group ?? void 0
854
905
  };
855
906
  }
856
- const pluginZod = driver.getPlugin(pluginZodName);
857
907
  if (!pluginZod?.options?.inferred) throw new Diagnostics.Error({
858
908
  code: Diagnostics.code.missingDependency,
859
909
  severity: "error",
@@ -862,15 +912,12 @@ function resolveOperationTypes(driver, pluginName) {
862
912
  location: { kind: "config" },
863
913
  plugin: pluginName
864
914
  });
865
- const resolver = driver.getResolver(pluginZodName);
915
+ const resolver = toZodTypeResolver(driver.getResolver(pluginZodName));
866
916
  return {
867
- response: {
868
- options: resolver.response.options,
869
- responses: (node) => resolver.schema.type(resolver.response.responses(node))
870
- },
917
+ response: resolver.response,
871
918
  resolver,
872
919
  output: pluginZod.options.output,
873
- group: pluginZod.options.group
920
+ group: pluginZod.options.group ?? void 0
874
921
  };
875
922
  }
876
923
  //#endregion
@@ -892,14 +939,15 @@ function createClientGenerator(name, resolveClientPath) {
892
939
  const { config, driver, resolver, root } = ctx;
893
940
  const { output, validator, returnType, throwOnErrorDefault, group } = ctx.options;
894
941
  const types = resolveOperationTypes(driver, ctx.plugin.name);
895
- const pluginZod = resolveResponseValidator(validator) === "zod" || resolveRequestValidator(validator) === "zod" ? driver.getPlugin(pluginZodName) : null;
942
+ const pluginZod = isValidatorEnabled(validator) ? driver.getPlugin(pluginZodName) : null;
896
943
  const zodResolver = pluginZod ? driver.getResolver(pluginZodName) : null;
897
944
  const importedTypeNames = [types.response.options(node), types.response.responses(node)];
898
- const importedZodNames = buildValidatorHooks({
945
+ const validatorHooks = buildValidatorHooks({
899
946
  node,
900
947
  validator,
901
948
  zodResolver
902
- }).importedZodNames;
949
+ });
950
+ const importedZodNames = validatorHooks.importedZodNames;
903
951
  const meta = {
904
952
  name: resolver.name(node.operationId),
905
953
  file: resolver.file({
@@ -931,6 +979,7 @@ function createClientGenerator(name, resolveClientPath) {
931
979
  const customClientPath = resolveClientPath?.(ctx.options, root);
932
980
  const clientPath = customClientPath ?? path.resolve(root, ".kubb/client.ts");
933
981
  const clientRoot = customClientPath === void 0 ? meta.file.path : void 0;
982
+ const standardSchemaPath = customClientPath ?? path.resolve(root, ".kubb/standardSchema.ts");
934
983
  const eventStream = isEventStream(node);
935
984
  const clientValueImports = (() => {
936
985
  if (eventStream) return ["client", "toEventStream"];
@@ -995,6 +1044,11 @@ function createClientGenerator(name, resolveClientPath) {
995
1044
  root: meta.file.path,
996
1045
  path: meta.fileZod.path
997
1046
  }),
1047
+ validatorHooks.headers && /* @__PURE__ */ jsx(File.Import, {
1048
+ name: ["toHeadersStandardSchema"],
1049
+ root: clientRoot,
1050
+ path: standardSchemaPath
1051
+ }),
998
1052
  /* @__PURE__ */ jsx(Operation, {
999
1053
  name: meta.name,
1000
1054
  node,
@@ -1015,14 +1069,14 @@ function createClientGenerator(name, resolveClientPath) {
1015
1069
  /**
1016
1070
  * Builds the call config literal forwarded to the contract client; the `throwOnError` fallback is applied after the `...config` spread.
1017
1071
  */
1018
- function buildCallConfig({ node, validator, zodResolver, security, throwOnErrorDefault }) {
1019
- const validators = buildValidatorHooks({
1020
- node,
1021
- validator,
1022
- zodResolver
1023
- });
1024
- const validatorEntries = [validators.request ? `request: ${validators.request}` : null, validators.response ? `response: ${validators.response}` : null].filter(Boolean);
1025
- const validatorLiteral = validatorEntries.length ? `validator: { ${validatorEntries.join(", ")} }` : null;
1072
+ function buildCallConfig({ node, validatorHooks, security, throwOnErrorDefault }) {
1073
+ const validatorLiteral = buildValidatorLiteral(validatorHooks, [
1074
+ "request",
1075
+ "path",
1076
+ "query",
1077
+ "headers",
1078
+ "response"
1079
+ ]);
1026
1080
  const securityLiteral = buildSecurityMetadata({ security });
1027
1081
  const { literal: contentTypeLiteral } = buildContentType({ node });
1028
1082
  return `{ ${[
@@ -1038,7 +1092,7 @@ function buildCallConfig({ node, validator, zodResolver, security, throwOnErrorD
1038
1092
  /**
1039
1093
  * Builds one instance method of a generated SDK class; a per-call `options.client` overrides `this.client`.
1040
1094
  */
1041
- function buildSdkMethod({ node, name, types, zodResolver, validator, security, returnType, throwOnErrorDefault }) {
1095
+ function buildSdkMethod({ node, name, types, validatorHooks, security, returnType, throwOnErrorDefault }) {
1042
1096
  if (!ast.isHttpOperationNode(node)) return "";
1043
1097
  const signature = buildGroupedOptionsSignature({
1044
1098
  node,
@@ -1051,8 +1105,7 @@ function buildSdkMethod({ node, name, types, zodResolver, validator, security, r
1051
1105
  types,
1052
1106
  callConfig: buildCallConfig({
1053
1107
  node,
1054
- validator,
1055
- zodResolver,
1108
+ validatorHooks,
1056
1109
  security,
1057
1110
  throwOnErrorDefault
1058
1111
  }),
@@ -1078,13 +1131,12 @@ function buildSdkMethod({ node, name, types, zodResolver, validator, security, r
1078
1131
  * instance: `const api = new PetClient({ baseURL }); api.getPetById(...)`. A per-call `client` option
1079
1132
  * still overrides the instance client for a one-off call.
1080
1133
  */
1081
- function SdkClient({ name, operations, validator, returnType, throwOnErrorDefault }) {
1082
- const methods = operations.map(({ node, name: methodName, types, zodResolver, security }) => buildSdkMethod({
1134
+ function SdkClient({ name, operations, returnType, throwOnErrorDefault }) {
1135
+ const methods = operations.map(({ node, name: methodName, types, validatorHooks, security }) => buildSdkMethod({
1083
1136
  node,
1084
1137
  name: methodName,
1085
1138
  types,
1086
- zodResolver,
1087
- validator,
1139
+ validatorHooks,
1088
1140
  security,
1089
1141
  returnType,
1090
1142
  throwOnErrorDefault
@@ -1132,9 +1184,6 @@ function SdkFacade({ name, members }) {
1132
1184
  function resolveTypeImportNames(node, types) {
1133
1185
  return [types.response.options(node), types.response.responses(node)];
1134
1186
  }
1135
- function resolveZodImportNames(node, zodResolver, validator) {
1136
- return [resolveResponseValidator(validator) === "zod" ? zodResolver.response.response(node) : null, resolveRequestValidator(validator) === "zod" && node.requestBody?.content?.[0]?.schema ? zodResolver.response.body(node) : null].filter((n) => Boolean(n));
1137
- }
1138
1187
  /**
1139
1188
  * Groups operations into one controller per tag. Operations without a tag fall back to a single
1140
1189
  * `Client`/`ApiClient` controller, matching the resolver's default naming.
@@ -1163,13 +1212,18 @@ function buildControllers(nodes, ctx, types) {
1163
1212
  method: node.method,
1164
1213
  path: node.path
1165
1214
  }) : void 0;
1215
+ const validatorHooks = zodResolver ? buildValidatorHooks({
1216
+ node,
1217
+ validator,
1218
+ zodResolver
1219
+ }) : null;
1166
1220
  return {
1167
1221
  node,
1168
1222
  name: resolver.name(node.operationId),
1169
1223
  types,
1170
- zodResolver,
1171
1224
  typeFile,
1172
1225
  zodFile,
1226
+ validatorHooks,
1173
1227
  security
1174
1228
  };
1175
1229
  }
@@ -1242,6 +1296,7 @@ function createSdkGenerator() {
1242
1296
  });
1243
1297
  const controllers = buildControllers(nodes, ctx, resolveOperationTypes(ctx.driver, ctx.plugin.name));
1244
1298
  const clientPath = path.resolve(root, ".kubb/client.ts");
1299
+ const standardSchemaPath = path.resolve(root, ".kubb/standardSchema.ts");
1245
1300
  const banner = (file) => resolver.default.banner(ctx.meta, {
1246
1301
  output,
1247
1302
  config,
@@ -1265,7 +1320,7 @@ function createSdkGenerator() {
1265
1320
  }));
1266
1321
  const { namesByPath: zodNamesByPath, filesByPath: zodFilesByPath } = isValidatorEnabled(validator) ? collectImportsByFile(ops, (op) => ({
1267
1322
  file: op.zodFile,
1268
- names: op.zodResolver ? resolveZodImportNames(op.node, op.zodResolver, validator) : []
1323
+ names: op.validatorHooks?.importedZodNames.filter((name) => name !== op.validatorHooks?.error) ?? []
1269
1324
  })) : {
1270
1325
  namesByPath: /* @__PURE__ */ new Map(),
1271
1326
  filesByPath: /* @__PURE__ */ new Map()
@@ -1315,10 +1370,14 @@ function createSdkGenerator() {
1315
1370
  root: file.path,
1316
1371
  path: zodFilesByPath.get(filePath).path
1317
1372
  }, filePath)),
1373
+ ops.some((op) => op.validatorHooks?.headers) && /* @__PURE__ */ jsx(File.Import, {
1374
+ name: ["toHeadersStandardSchema"],
1375
+ root: file.path,
1376
+ path: standardSchemaPath
1377
+ }),
1318
1378
  /* @__PURE__ */ jsx(SdkClient, {
1319
1379
  name: className,
1320
1380
  operations: ops,
1321
- validator,
1322
1381
  returnType,
1323
1382
  throwOnErrorDefault
1324
1383
  })
@@ -1421,7 +1480,7 @@ var compatibility = {
1421
1480
  };
1422
1481
  //#endregion
1423
1482
  //#region package.json
1424
- var version = "5.9.0-canary.20261024T190549";
1483
+ var version = "5.9.1";
1425
1484
  //#endregion
1426
1485
  //#region src/templates.ts
1427
1486
  /** Absolute path to the fetch client template, copied into `.kubb/client.ts`. */