@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.cjs CHANGED
@@ -472,7 +472,7 @@ function createGroupConfig(group) {
472
472
  function isValidatorEnabled(validator) {
473
473
  if (!validator) return false;
474
474
  if (validator === "zod") return true;
475
- return Boolean(validator.request || validator.response);
475
+ return Boolean(validator.request || validator.params || validator.response);
476
476
  }
477
477
  /**
478
478
  * Returns `'zod'` when request body parsing is enabled, `null` otherwise. The string shorthand
@@ -483,6 +483,14 @@ function resolveRequestValidator(validator) {
483
483
  return validator.request ?? null;
484
484
  }
485
485
  /**
486
+ * Returns `'zod'` when path, query, and header params parsing is enabled, `null` otherwise. Only the
487
+ * object form `{ params: 'zod' }` enables it.
488
+ */
489
+ function resolveParamsValidator(validator) {
490
+ if (!validator || validator === "zod") return null;
491
+ return validator.params ?? null;
492
+ }
493
+ /**
486
494
  * Returns `'zod'` when response parsing is enabled, `null` otherwise. The string shorthand `'zod'`
487
495
  * maps to response parsing.
488
496
  */
@@ -501,30 +509,6 @@ function buildZodErrorParse(node, zodResolver) {
501
509
  return zodResolver.response.error?.(node) || null;
502
510
  }
503
511
  //#endregion
504
- //#region ../../internals/client/src/builders/validator.ts
505
- /**
506
- * Builds the validator-hook references for one operation. Request validation runs before the send;
507
- * response validation runs on the success body only. Returns `null` references when the matching
508
- * direction is disabled or the schema is absent.
509
- */
510
- function buildValidatorHooks({ node, validator, zodResolver }) {
511
- const hasRequestBody = Boolean(node.requestBody?.content?.[0]?.schema);
512
- const parsesResponse = zodResolver && resolveResponseValidator(validator) === "zod";
513
- const response = parsesResponse ? zodResolver.response.response(node) || null : null;
514
- const error = parsesResponse ? buildZodErrorParse(node, zodResolver) : null;
515
- const request = zodResolver && resolveRequestValidator(validator) === "zod" && hasRequestBody ? zodResolver.response.body(node) || null : null;
516
- return {
517
- request,
518
- response,
519
- error,
520
- importedZodNames: [
521
- response,
522
- error,
523
- request
524
- ].filter((name) => Boolean(name))
525
- };
526
- }
527
- //#endregion
528
512
  //#region ../../internals/client/src/builders/security.ts
529
513
  function serializeAuth(auth) {
530
514
  const parts = [`type: '${auth.type}'`];
@@ -597,6 +581,49 @@ function buildSecurityMetadata({ security }) {
597
581
  return `[${security.map(serializeAuth).join(", ")}]`;
598
582
  }
599
583
  //#endregion
584
+ //#region ../../internals/client/src/builders/validator.ts
585
+ /**
586
+ * Builds the validator-hook references for one operation. Request body and params validation run before the send.
587
+ * Response validation runs on the success body only. Returns `null` references when the matching
588
+ * direction is disabled or the schema is absent.
589
+ */
590
+ function buildValidatorHooks({ node, validator, zodResolver }) {
591
+ const hasRequestBody = Boolean(node.requestBody?.content?.[0]?.schema);
592
+ const parsesResponse = zodResolver && resolveResponseValidator(validator) === "zod";
593
+ const response = parsesResponse ? zodResolver.response.response(node) || null : null;
594
+ const error = parsesResponse ? buildZodErrorParse(node, zodResolver) : null;
595
+ const request = zodResolver && resolveRequestValidator(validator) === "zod" && hasRequestBody ? zodResolver.response.body(node) || null : null;
596
+ const paramGroups = getOperationParameters(node);
597
+ const resolveParamsName = (kind, params) => zodResolver && resolveParamsValidator(validator) === "zod" && params.length > 0 ? zodResolver.param[kind](node, params[0]) : null;
598
+ const path = resolveParamsName("path", paramGroups.path);
599
+ const query = resolveParamsName("query", paramGroups.query);
600
+ const headers = resolveParamsName("headers", paramGroups.header);
601
+ const importedZodNames = [
602
+ response,
603
+ error,
604
+ request,
605
+ path,
606
+ query,
607
+ headers
608
+ ].filter((name) => Boolean(name));
609
+ return {
610
+ request,
611
+ path,
612
+ query,
613
+ headers: headers ? `toHeadersStandardSchema(${headers}, ${headers}.shape)` : null,
614
+ response,
615
+ error,
616
+ importedZodNames
617
+ };
618
+ }
619
+ /**
620
+ * Prints the `validator: { … }` entry of a call config from the hooks named in `keys`, or `null` when none is set.
621
+ */
622
+ function buildValidatorLiteral(hooks, keys) {
623
+ const entries = keys.flatMap((key) => hooks?.[key] ? [`${key}: ${hooks[key]}`] : []);
624
+ return entries.length ? `validator: { ${entries.join(", ")} }` : null;
625
+ }
626
+ //#endregion
600
627
  //#region ../../internals/client/src/builders/contentType.ts
601
628
  /**
602
629
  * Builds the `contentType` entry baked into the call config, or `null` for the JSON default.
@@ -801,12 +828,14 @@ function Operation({ name, node, types, zodResolver, validator, returnType, thro
801
828
  const eventStream = isEventStream(node);
802
829
  const responseType = getResponseType(node);
803
830
  const responseTypeLiteral = responseType ? `responseType: '${responseType}'` : null;
804
- const validatorEntries = [
805
- validators.request ? `request: ${validators.request}` : null,
806
- validators.response ? `response: ${validators.response}` : null,
807
- validators.error ? `error: ${validators.error}` : null
808
- ].filter(Boolean);
809
- const validatorLiteral = validatorEntries.length ? `validator: { ${validatorEntries.join(", ")} }` : null;
831
+ const validatorLiteral = buildValidatorLiteral(validators, [
832
+ "request",
833
+ "path",
834
+ "query",
835
+ "headers",
836
+ "response",
837
+ "error"
838
+ ]);
810
839
  const callConfig = `{ ${[
811
840
  `method: '${node.method.toUpperCase()}'`,
812
841
  `url: '${node.path}'`,
@@ -853,14 +882,35 @@ function Operation({ name, node, types, zodResolver, validator, returnType, thro
853
882
  //#endregion
854
883
  //#region ../../internals/client/src/resolveOperationTypes.ts
855
884
  /**
856
- * Picks the plugin a generated client takes its `Options` and `Responses` types from.
885
+ * A `plugin-ts` shaped resolver whose operation type names point at the types `pluginZod({ inferred })`
886
+ * exports next to each schema, so code written against `plugin-ts` names picks up the zod types.
887
+ */
888
+ function toZodTypeResolver(resolver) {
889
+ const type = (name) => resolver.schema.type(name);
890
+ return {
891
+ ...resolver,
892
+ file: resolver.file.bind(resolver),
893
+ param: {
894
+ name: (node, p) => type(resolver.param.name(node, p)),
895
+ path: (node, p) => type(resolver.param.path(node, p)),
896
+ query: (node, p) => type(resolver.param.query(node, p)),
897
+ headers: (node, p) => type(resolver.param.headers(node, p))
898
+ },
899
+ response: {
900
+ body: (node) => type(resolver.response.body(node)),
901
+ status: (node, statusCode) => type(resolver.response.status(node, statusCode)),
902
+ response: (node) => type(resolver.response.response(node)),
903
+ responses: (node) => type(resolver.response.responses(node)),
904
+ options: (node) => resolver.response.options(node)
905
+ }
906
+ };
907
+ }
908
+ /**
909
+ * Picks the plugin generated clients, query hooks, and MCP handlers take their operation types from.
857
910
  *
858
- * `plugin-ts` wins whenever it is in the pipeline, so existing configs keep the types they generate
859
- * today. Without it, `pluginZod({ inferred: true })` takes over: its inferred options and responses
860
- * types are built from the same shared schemas as the `plugin-ts` ones, so a client typed off
861
- * `z.infer` carries what the codecs decode to (a `Temporal` instance, a `Date`) rather than the raw
862
- * wire type. Throws `KUBB_MISSING_DEPENDENCY` for `pluginName` when neither is available, since the
863
- * client has nothing to type against.
911
+ * `pluginZod({ inferred: 'codec' })` wins, so a codec param takes its domain value. Otherwise `plugin-ts`
912
+ * wins when it is in the pipeline, and without it any `pluginZod({ inferred })`. Throws
913
+ * `KUBB_MISSING_DEPENDENCY` for `pluginName` when neither is available.
864
914
  *
865
915
  * @example
866
916
  * ```ts
@@ -870,16 +920,16 @@ function Operation({ name, node, types, zodResolver, validator, returnType, thro
870
920
  */
871
921
  function resolveOperationTypes(driver, pluginName) {
872
922
  const pluginTs = driver.getPlugin(_kubb_plugin_ts.pluginTsName);
873
- if (pluginTs) {
923
+ const pluginZod = driver.getPlugin(_kubb_plugin_zod.pluginZodName);
924
+ if (pluginTs && pluginZod?.options?.inferred !== "codec") {
874
925
  const resolver = driver.getResolver(_kubb_plugin_ts.pluginTsName);
875
926
  return {
876
927
  response: resolver.response,
877
928
  resolver,
878
929
  output: pluginTs.options?.output,
879
- group: pluginTs.options?.group
930
+ group: pluginTs.options?.group ?? void 0
880
931
  };
881
932
  }
882
- const pluginZod = driver.getPlugin(_kubb_plugin_zod.pluginZodName);
883
933
  if (!pluginZod?.options?.inferred) throw new kubb_kit.Diagnostics.Error({
884
934
  code: kubb_kit.Diagnostics.code.missingDependency,
885
935
  severity: "error",
@@ -888,15 +938,12 @@ function resolveOperationTypes(driver, pluginName) {
888
938
  location: { kind: "config" },
889
939
  plugin: pluginName
890
940
  });
891
- const resolver = driver.getResolver(_kubb_plugin_zod.pluginZodName);
941
+ const resolver = toZodTypeResolver(driver.getResolver(_kubb_plugin_zod.pluginZodName));
892
942
  return {
893
- response: {
894
- options: resolver.response.options,
895
- responses: (node) => resolver.schema.type(resolver.response.responses(node))
896
- },
943
+ response: resolver.response,
897
944
  resolver,
898
945
  output: pluginZod.options.output,
899
- group: pluginZod.options.group
946
+ group: pluginZod.options.group ?? void 0
900
947
  };
901
948
  }
902
949
  //#endregion
@@ -918,14 +965,15 @@ function createClientGenerator(name, resolveClientPath) {
918
965
  const { config, driver, resolver, root } = ctx;
919
966
  const { output, validator, returnType, throwOnErrorDefault, group } = ctx.options;
920
967
  const types = resolveOperationTypes(driver, ctx.plugin.name);
921
- const pluginZod = resolveResponseValidator(validator) === "zod" || resolveRequestValidator(validator) === "zod" ? driver.getPlugin(_kubb_plugin_zod.pluginZodName) : null;
968
+ const pluginZod = isValidatorEnabled(validator) ? driver.getPlugin(_kubb_plugin_zod.pluginZodName) : null;
922
969
  const zodResolver = pluginZod ? driver.getResolver(_kubb_plugin_zod.pluginZodName) : null;
923
970
  const importedTypeNames = [types.response.options(node), types.response.responses(node)];
924
- const importedZodNames = buildValidatorHooks({
971
+ const validatorHooks = buildValidatorHooks({
925
972
  node,
926
973
  validator,
927
974
  zodResolver
928
- }).importedZodNames;
975
+ });
976
+ const importedZodNames = validatorHooks.importedZodNames;
929
977
  const meta = {
930
978
  name: resolver.name(node.operationId),
931
979
  file: resolver.file({
@@ -957,6 +1005,7 @@ function createClientGenerator(name, resolveClientPath) {
957
1005
  const customClientPath = resolveClientPath?.(ctx.options, root);
958
1006
  const clientPath = customClientPath ?? node_path.default.resolve(root, ".kubb/client.ts");
959
1007
  const clientRoot = customClientPath === void 0 ? meta.file.path : void 0;
1008
+ const standardSchemaPath = customClientPath ?? node_path.default.resolve(root, ".kubb/standardSchema.ts");
960
1009
  const eventStream = isEventStream(node);
961
1010
  const clientValueImports = (() => {
962
1011
  if (eventStream) return ["client", "toEventStream"];
@@ -1021,6 +1070,11 @@ function createClientGenerator(name, resolveClientPath) {
1021
1070
  root: meta.file.path,
1022
1071
  path: meta.fileZod.path
1023
1072
  }),
1073
+ validatorHooks.headers && /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Import, {
1074
+ name: ["toHeadersStandardSchema"],
1075
+ root: clientRoot,
1076
+ path: standardSchemaPath
1077
+ }),
1024
1078
  /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(Operation, {
1025
1079
  name: meta.name,
1026
1080
  node,
@@ -1041,14 +1095,14 @@ function createClientGenerator(name, resolveClientPath) {
1041
1095
  /**
1042
1096
  * Builds the call config literal forwarded to the contract client; the `throwOnError` fallback is applied after the `...config` spread.
1043
1097
  */
1044
- function buildCallConfig({ node, validator, zodResolver, security, throwOnErrorDefault }) {
1045
- const validators = buildValidatorHooks({
1046
- node,
1047
- validator,
1048
- zodResolver
1049
- });
1050
- const validatorEntries = [validators.request ? `request: ${validators.request}` : null, validators.response ? `response: ${validators.response}` : null].filter(Boolean);
1051
- const validatorLiteral = validatorEntries.length ? `validator: { ${validatorEntries.join(", ")} }` : null;
1098
+ function buildCallConfig({ node, validatorHooks, security, throwOnErrorDefault }) {
1099
+ const validatorLiteral = buildValidatorLiteral(validatorHooks, [
1100
+ "request",
1101
+ "path",
1102
+ "query",
1103
+ "headers",
1104
+ "response"
1105
+ ]);
1052
1106
  const securityLiteral = buildSecurityMetadata({ security });
1053
1107
  const { literal: contentTypeLiteral } = buildContentType({ node });
1054
1108
  return `{ ${[
@@ -1064,7 +1118,7 @@ function buildCallConfig({ node, validator, zodResolver, security, throwOnErrorD
1064
1118
  /**
1065
1119
  * Builds one instance method of a generated SDK class; a per-call `options.client` overrides `this.client`.
1066
1120
  */
1067
- function buildSdkMethod({ node, name, types, zodResolver, validator, security, returnType, throwOnErrorDefault }) {
1121
+ function buildSdkMethod({ node, name, types, validatorHooks, security, returnType, throwOnErrorDefault }) {
1068
1122
  if (!kubb_kit.ast.isHttpOperationNode(node)) return "";
1069
1123
  const signature = buildGroupedOptionsSignature({
1070
1124
  node,
@@ -1077,8 +1131,7 @@ function buildSdkMethod({ node, name, types, zodResolver, validator, security, r
1077
1131
  types,
1078
1132
  callConfig: buildCallConfig({
1079
1133
  node,
1080
- validator,
1081
- zodResolver,
1134
+ validatorHooks,
1082
1135
  security,
1083
1136
  throwOnErrorDefault
1084
1137
  }),
@@ -1104,13 +1157,12 @@ function buildSdkMethod({ node, name, types, zodResolver, validator, security, r
1104
1157
  * instance: `const api = new PetClient({ baseURL }); api.getPetById(...)`. A per-call `client` option
1105
1158
  * still overrides the instance client for a one-off call.
1106
1159
  */
1107
- function SdkClient({ name, operations, validator, returnType, throwOnErrorDefault }) {
1108
- const methods = operations.map(({ node, name: methodName, types, zodResolver, security }) => buildSdkMethod({
1160
+ function SdkClient({ name, operations, returnType, throwOnErrorDefault }) {
1161
+ const methods = operations.map(({ node, name: methodName, types, validatorHooks, security }) => buildSdkMethod({
1109
1162
  node,
1110
1163
  name: methodName,
1111
1164
  types,
1112
- zodResolver,
1113
- validator,
1165
+ validatorHooks,
1114
1166
  security,
1115
1167
  returnType,
1116
1168
  throwOnErrorDefault
@@ -1158,9 +1210,6 @@ function SdkFacade({ name, members }) {
1158
1210
  function resolveTypeImportNames(node, types) {
1159
1211
  return [types.response.options(node), types.response.responses(node)];
1160
1212
  }
1161
- function resolveZodImportNames(node, zodResolver, validator) {
1162
- 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));
1163
- }
1164
1213
  /**
1165
1214
  * Groups operations into one controller per tag. Operations without a tag fall back to a single
1166
1215
  * `Client`/`ApiClient` controller, matching the resolver's default naming.
@@ -1189,13 +1238,18 @@ function buildControllers(nodes, ctx, types) {
1189
1238
  method: node.method,
1190
1239
  path: node.path
1191
1240
  }) : void 0;
1241
+ const validatorHooks = zodResolver ? buildValidatorHooks({
1242
+ node,
1243
+ validator,
1244
+ zodResolver
1245
+ }) : null;
1192
1246
  return {
1193
1247
  node,
1194
1248
  name: resolver.name(node.operationId),
1195
1249
  types,
1196
- zodResolver,
1197
1250
  typeFile,
1198
1251
  zodFile,
1252
+ validatorHooks,
1199
1253
  security
1200
1254
  };
1201
1255
  }
@@ -1268,6 +1322,7 @@ function createSdkGenerator() {
1268
1322
  });
1269
1323
  const controllers = buildControllers(nodes, ctx, resolveOperationTypes(ctx.driver, ctx.plugin.name));
1270
1324
  const clientPath = node_path.default.resolve(root, ".kubb/client.ts");
1325
+ const standardSchemaPath = node_path.default.resolve(root, ".kubb/standardSchema.ts");
1271
1326
  const banner = (file) => resolver.default.banner(ctx.meta, {
1272
1327
  output,
1273
1328
  config,
@@ -1291,7 +1346,7 @@ function createSdkGenerator() {
1291
1346
  }));
1292
1347
  const { namesByPath: zodNamesByPath, filesByPath: zodFilesByPath } = isValidatorEnabled(validator) ? collectImportsByFile(ops, (op) => ({
1293
1348
  file: op.zodFile,
1294
- names: op.zodResolver ? resolveZodImportNames(op.node, op.zodResolver, validator) : []
1349
+ names: op.validatorHooks?.importedZodNames.filter((name) => name !== op.validatorHooks?.error) ?? []
1295
1350
  })) : {
1296
1351
  namesByPath: /* @__PURE__ */ new Map(),
1297
1352
  filesByPath: /* @__PURE__ */ new Map()
@@ -1341,10 +1396,14 @@ function createSdkGenerator() {
1341
1396
  root: file.path,
1342
1397
  path: zodFilesByPath.get(filePath).path
1343
1398
  }, filePath)),
1399
+ ops.some((op) => op.validatorHooks?.headers) && /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Import, {
1400
+ name: ["toHeadersStandardSchema"],
1401
+ root: file.path,
1402
+ path: standardSchemaPath
1403
+ }),
1344
1404
  /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(SdkClient, {
1345
1405
  name: className,
1346
1406
  operations: ops,
1347
- validator,
1348
1407
  returnType,
1349
1408
  throwOnErrorDefault
1350
1409
  })
@@ -1447,7 +1506,7 @@ var compatibility = {
1447
1506
  };
1448
1507
  //#endregion
1449
1508
  //#region package.json
1450
- var version = "5.9.0-canary.20261024T190549";
1509
+ var version = "5.9.1";
1451
1510
  //#endregion
1452
1511
  //#region src/templates.ts
1453
1512
  /** Absolute path to the fetch client template, copied into `.kubb/client.ts`. */