@kubb/plugin-fetch 5.9.0-canary.20261024T172532 → 5.9.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/dist/index.d.cts CHANGED
@@ -2,16 +2,17 @@ import { Exclude, Group, Include, Output, OutputOptions, Override, PluginType, R
2
2
  import "@kubb/plugin-zod";
3
3
  //#region ../../internals/client/src/types.d.ts
4
4
  /**
5
- * Validator applied to request and response bodies using schemas from `@kubb/plugin-zod`.
5
+ * Validator applied to the request and response using schemas from `@kubb/plugin-zod`.
6
6
  * - `false`: no validation.
7
7
  * - `'zod'`: validates the success (2xx) response body, and the error body when a non-2xx call does
8
8
  * 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.
9
+ * - `{ request?: 'zod'; params?: 'zod'; response?: 'zod' }`: opt in per slot. `request` encodes the
10
+ * request body before the call; `params` validate the path, query, and header params;
11
+ * `response` validates the success response body and, on the non-throw path, the error body.
12
12
  */
13
13
  type ValidatorOptions = false | 'zod' | {
14
14
  request?: 'zod';
15
+ params?: 'zod';
15
16
  response?: 'zod';
16
17
  };
17
18
  /**
@@ -86,7 +87,7 @@ type Options = OutputOptions & {
86
87
  */
87
88
  throwOnErrorDefault?: boolean;
88
89
  /**
89
- * Validate request and response bodies with schemas from `@kubb/plugin-zod`.
90
+ * Validate the request body, the request params, and the response with schemas from `@kubb/plugin-zod`.
90
91
  *
91
92
  * @default false
92
93
  */
package/dist/index.d.ts CHANGED
@@ -2,16 +2,17 @@ import { Exclude, Group, Include, Output, OutputOptions, Override, PluginType, R
2
2
  import "@kubb/plugin-zod";
3
3
  //#region ../../internals/client/src/types.d.ts
4
4
  /**
5
- * Validator applied to request and response bodies using schemas from `@kubb/plugin-zod`.
5
+ * Validator applied to the request and response using schemas from `@kubb/plugin-zod`.
6
6
  * - `false`: no validation.
7
7
  * - `'zod'`: validates the success (2xx) response body, and the error body when a non-2xx call does
8
8
  * 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.
9
+ * - `{ request?: 'zod'; params?: 'zod'; response?: 'zod' }`: opt in per slot. `request` encodes the
10
+ * request body before the call; `params` validate the path, query, and header params;
11
+ * `response` validates the success response body and, on the non-throw path, the error body.
12
12
  */
13
13
  type ValidatorOptions = false | 'zod' | {
14
14
  request?: 'zod';
15
+ params?: 'zod';
15
16
  response?: 'zod';
16
17
  };
17
18
  /**
@@ -86,7 +87,7 @@ type Options = OutputOptions & {
86
87
  */
87
88
  throwOnErrorDefault?: boolean;
88
89
  /**
89
- * Validate request and response bodies with schemas from `@kubb/plugin-zod`.
90
+ * Validate the request body, the request params, and the response with schemas from `@kubb/plugin-zod`.
90
91
  *
91
92
  * @default false
92
93
  */
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,36 +483,13 @@ 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}'`];
505
489
  if (auth.scheme) parts.push(`scheme: '${auth.scheme}'`);
506
490
  if (auth.name) parts.push(`name: '${auth.name}'`);
507
491
  if (auth.in) parts.push(`in: '${auth.in}'`);
492
+ if (auth.scopes?.length) parts.push(`scopes: [${auth.scopes.map((scope) => `'${scope}'`).join(", ")}]`);
508
493
  return `{ ${parts.join(", ")} }`;
509
494
  }
510
495
  /**
@@ -547,11 +532,14 @@ function getOperationSecurity({ document, method, path }) {
547
532
  const definitions = document.components?.securitySchemes ?? {};
548
533
  const security = [];
549
534
  const seen = /* @__PURE__ */ new Set();
550
- for (const requirement of requirements) for (const schemeName of Object.keys(requirement)) {
535
+ for (const requirement of requirements) for (const [schemeName, scopes] of Object.entries(requirement)) {
551
536
  if (seen.has(schemeName)) continue;
552
537
  seen.add(schemeName);
553
538
  const auth = resolveSecurityScheme(definitions[schemeName]);
554
- if (auth) security.push(auth);
539
+ if (auth) security.push(scopes.length ? {
540
+ ...auth,
541
+ scopes
542
+ } : auth);
555
543
  }
556
544
  return security.length ? security : void 0;
557
545
  }
@@ -567,6 +555,49 @@ function buildSecurityMetadata({ security }) {
567
555
  return `[${security.map(serializeAuth).join(", ")}]`;
568
556
  }
569
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
570
601
  //#region ../../internals/client/src/builders/contentType.ts
571
602
  /**
572
603
  * Builds the `contentType` entry baked into the call config, or `null` for the JSON default.
@@ -771,12 +802,14 @@ function Operation({ name, node, types, zodResolver, validator, returnType, thro
771
802
  const eventStream = isEventStream(node);
772
803
  const responseType = getResponseType(node);
773
804
  const responseTypeLiteral = responseType ? `responseType: '${responseType}'` : null;
774
- const validatorEntries = [
775
- validators.request ? `request: ${validators.request}` : null,
776
- validators.response ? `response: ${validators.response}` : null,
777
- validators.error ? `error: ${validators.error}` : null
778
- ].filter(Boolean);
779
- 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
+ ]);
780
813
  const callConfig = `{ ${[
781
814
  `method: '${node.method.toUpperCase()}'`,
782
815
  `url: '${node.path}'`,
@@ -888,14 +921,15 @@ function createClientGenerator(name, resolveClientPath) {
888
921
  const { config, driver, resolver, root } = ctx;
889
922
  const { output, validator, returnType, throwOnErrorDefault, group } = ctx.options;
890
923
  const types = resolveOperationTypes(driver, ctx.plugin.name);
891
- const pluginZod = resolveResponseValidator(validator) === "zod" || resolveRequestValidator(validator) === "zod" ? driver.getPlugin(pluginZodName) : null;
924
+ const pluginZod = isValidatorEnabled(validator) ? driver.getPlugin(pluginZodName) : null;
892
925
  const zodResolver = pluginZod ? driver.getResolver(pluginZodName) : null;
893
926
  const importedTypeNames = [types.response.options(node), types.response.responses(node)];
894
- const importedZodNames = buildValidatorHooks({
927
+ const validatorHooks = buildValidatorHooks({
895
928
  node,
896
929
  validator,
897
930
  zodResolver
898
- }).importedZodNames;
931
+ });
932
+ const importedZodNames = validatorHooks.importedZodNames;
899
933
  const meta = {
900
934
  name: resolver.name(node.operationId),
901
935
  file: resolver.file({
@@ -927,6 +961,7 @@ function createClientGenerator(name, resolveClientPath) {
927
961
  const customClientPath = resolveClientPath?.(ctx.options, root);
928
962
  const clientPath = customClientPath ?? path.resolve(root, ".kubb/client.ts");
929
963
  const clientRoot = customClientPath === void 0 ? meta.file.path : void 0;
964
+ const standardSchemaPath = customClientPath ?? path.resolve(root, ".kubb/standardSchema.ts");
930
965
  const eventStream = isEventStream(node);
931
966
  const clientValueImports = (() => {
932
967
  if (eventStream) return ["client", "toEventStream"];
@@ -991,6 +1026,11 @@ function createClientGenerator(name, resolveClientPath) {
991
1026
  root: meta.file.path,
992
1027
  path: meta.fileZod.path
993
1028
  }),
1029
+ validatorHooks.headers && /* @__PURE__ */ jsx(File.Import, {
1030
+ name: ["toHeadersStandardSchema"],
1031
+ root: clientRoot,
1032
+ path: standardSchemaPath
1033
+ }),
994
1034
  /* @__PURE__ */ jsx(Operation, {
995
1035
  name: meta.name,
996
1036
  node,
@@ -1011,14 +1051,14 @@ function createClientGenerator(name, resolveClientPath) {
1011
1051
  /**
1012
1052
  * Builds the call config literal forwarded to the contract client; the `throwOnError` fallback is applied after the `...config` spread.
1013
1053
  */
1014
- function buildCallConfig({ node, validator, zodResolver, security, throwOnErrorDefault }) {
1015
- const validators = buildValidatorHooks({
1016
- node,
1017
- validator,
1018
- zodResolver
1019
- });
1020
- const validatorEntries = [validators.request ? `request: ${validators.request}` : null, validators.response ? `response: ${validators.response}` : null].filter(Boolean);
1021
- const validatorLiteral = validatorEntries.length ? `validator: { ${validatorEntries.join(", ")} }` : null;
1054
+ function buildCallConfig({ node, validatorHooks, security, throwOnErrorDefault }) {
1055
+ const validatorLiteral = buildValidatorLiteral(validatorHooks, [
1056
+ "request",
1057
+ "path",
1058
+ "query",
1059
+ "headers",
1060
+ "response"
1061
+ ]);
1022
1062
  const securityLiteral = buildSecurityMetadata({ security });
1023
1063
  const { literal: contentTypeLiteral } = buildContentType({ node });
1024
1064
  return `{ ${[
@@ -1034,7 +1074,7 @@ function buildCallConfig({ node, validator, zodResolver, security, throwOnErrorD
1034
1074
  /**
1035
1075
  * Builds one instance method of a generated SDK class; a per-call `options.client` overrides `this.client`.
1036
1076
  */
1037
- function buildSdkMethod({ node, name, types, zodResolver, validator, security, returnType, throwOnErrorDefault }) {
1077
+ function buildSdkMethod({ node, name, types, validatorHooks, security, returnType, throwOnErrorDefault }) {
1038
1078
  if (!ast.isHttpOperationNode(node)) return "";
1039
1079
  const signature = buildGroupedOptionsSignature({
1040
1080
  node,
@@ -1047,8 +1087,7 @@ function buildSdkMethod({ node, name, types, zodResolver, validator, security, r
1047
1087
  types,
1048
1088
  callConfig: buildCallConfig({
1049
1089
  node,
1050
- validator,
1051
- zodResolver,
1090
+ validatorHooks,
1052
1091
  security,
1053
1092
  throwOnErrorDefault
1054
1093
  }),
@@ -1074,13 +1113,12 @@ function buildSdkMethod({ node, name, types, zodResolver, validator, security, r
1074
1113
  * instance: `const api = new PetClient({ baseURL }); api.getPetById(...)`. A per-call `client` option
1075
1114
  * still overrides the instance client for a one-off call.
1076
1115
  */
1077
- function SdkClient({ name, operations, validator, returnType, throwOnErrorDefault }) {
1078
- const methods = operations.map(({ node, name: methodName, types, zodResolver, security }) => buildSdkMethod({
1116
+ function SdkClient({ name, operations, returnType, throwOnErrorDefault }) {
1117
+ const methods = operations.map(({ node, name: methodName, types, validatorHooks, security }) => buildSdkMethod({
1079
1118
  node,
1080
1119
  name: methodName,
1081
1120
  types,
1082
- zodResolver,
1083
- validator,
1121
+ validatorHooks,
1084
1122
  security,
1085
1123
  returnType,
1086
1124
  throwOnErrorDefault
@@ -1128,9 +1166,6 @@ function SdkFacade({ name, members }) {
1128
1166
  function resolveTypeImportNames(node, types) {
1129
1167
  return [types.response.options(node), types.response.responses(node)];
1130
1168
  }
1131
- function resolveZodImportNames(node, zodResolver, validator) {
1132
- 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));
1133
- }
1134
1169
  /**
1135
1170
  * Groups operations into one controller per tag. Operations without a tag fall back to a single
1136
1171
  * `Client`/`ApiClient` controller, matching the resolver's default naming.
@@ -1159,13 +1194,18 @@ function buildControllers(nodes, ctx, types) {
1159
1194
  method: node.method,
1160
1195
  path: node.path
1161
1196
  }) : void 0;
1197
+ const validatorHooks = zodResolver ? buildValidatorHooks({
1198
+ node,
1199
+ validator,
1200
+ zodResolver
1201
+ }) : null;
1162
1202
  return {
1163
1203
  node,
1164
1204
  name: resolver.name(node.operationId),
1165
1205
  types,
1166
- zodResolver,
1167
1206
  typeFile,
1168
1207
  zodFile,
1208
+ validatorHooks,
1169
1209
  security
1170
1210
  };
1171
1211
  }
@@ -1238,6 +1278,7 @@ function createSdkGenerator() {
1238
1278
  });
1239
1279
  const controllers = buildControllers(nodes, ctx, resolveOperationTypes(ctx.driver, ctx.plugin.name));
1240
1280
  const clientPath = path.resolve(root, ".kubb/client.ts");
1281
+ const standardSchemaPath = path.resolve(root, ".kubb/standardSchema.ts");
1241
1282
  const banner = (file) => resolver.default.banner(ctx.meta, {
1242
1283
  output,
1243
1284
  config,
@@ -1261,7 +1302,7 @@ function createSdkGenerator() {
1261
1302
  }));
1262
1303
  const { namesByPath: zodNamesByPath, filesByPath: zodFilesByPath } = isValidatorEnabled(validator) ? collectImportsByFile(ops, (op) => ({
1263
1304
  file: op.zodFile,
1264
- names: op.zodResolver ? resolveZodImportNames(op.node, op.zodResolver, validator) : []
1305
+ names: op.validatorHooks?.importedZodNames.filter((name) => name !== op.validatorHooks?.error) ?? []
1265
1306
  })) : {
1266
1307
  namesByPath: /* @__PURE__ */ new Map(),
1267
1308
  filesByPath: /* @__PURE__ */ new Map()
@@ -1311,10 +1352,14 @@ function createSdkGenerator() {
1311
1352
  root: file.path,
1312
1353
  path: zodFilesByPath.get(filePath).path
1313
1354
  }, filePath)),
1355
+ ops.some((op) => op.validatorHooks?.headers) && /* @__PURE__ */ jsx(File.Import, {
1356
+ name: ["toHeadersStandardSchema"],
1357
+ root: file.path,
1358
+ path: standardSchemaPath
1359
+ }),
1314
1360
  /* @__PURE__ */ jsx(SdkClient, {
1315
1361
  name: className,
1316
1362
  operations: ops,
1317
- validator,
1318
1363
  returnType,
1319
1364
  throwOnErrorDefault
1320
1365
  })
@@ -1417,7 +1462,7 @@ var compatibility = {
1417
1462
  };
1418
1463
  //#endregion
1419
1464
  //#region package.json
1420
- var version = "5.9.0-canary.20261024T172532";
1465
+ var version = "5.9.0";
1421
1466
  //#endregion
1422
1467
  //#region src/templates.ts
1423
1468
  /** Absolute path to the fetch client template, copied into `.kubb/client.ts`. */