@kubb/plugin-fetch 5.1.0-canary.20260824T161549 → 5.1.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.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import { t as __name } from "./rolldown-runtime-C0LytTxp.js";
2
2
  import { Exclude, Group, Include, Output, OutputOptions, Override, PluginFactoryOptions, Resolver, ResolverPatch, ast } from "kubb/kit";
3
- import "@kubb/plugin-ts";
4
3
  import "kubb/jsx";
5
4
  import "@kubb/plugin-zod";
6
5
  //#region ../../internals/client/src/types.d.ts
package/dist/index.js CHANGED
@@ -440,15 +440,15 @@ function createGroupConfig(group) {
440
440
  //#endregion
441
441
  //#region ../../internals/client/src/builders/generics.ts
442
442
  /**
443
- * Builds the `RequestResult` generic arguments for one operation: the plugin-ts per-status responses
444
- * record plus the per-call `ThrowOnError` flag. `SuccessOf` / `ErrorOf` split the record inside the
443
+ * Builds the `RequestResult` generic arguments for one operation: the per-status responses record
444
+ * plus the per-call `ThrowOnError` flag. `SuccessOf` / `ErrorOf` split the record inside the
445
445
  * runtime, so this only names the record and threads `ThrowOnError`.
446
446
  *
447
447
  * @example
448
- * `buildRequestResultGenerics({ node, tsResolver }) // 'AddPetResponses, ThrowOnError'`
448
+ * `buildRequestResultGenerics({ node, types }) // 'AddPetResponses, ThrowOnError'`
449
449
  */
450
- function buildRequestResultGenerics({ node, tsResolver }) {
451
- return `${tsResolver.response.responses(node)}, ThrowOnError`;
450
+ function buildRequestResultGenerics({ node, types }) {
451
+ return `${types.response.responses(node)}, ThrowOnError`;
452
452
  }
453
453
  //#endregion
454
454
  //#region ../../internals/client/src/builders/returnStatement.ts
@@ -460,10 +460,10 @@ function buildRequestResultGenerics({ node, tsResolver }) {
460
460
  * @example
461
461
  * `return request({ method: 'POST', url: '/pet', ...config }) as Promise<RequestResult<AddPetResponses, ThrowOnError>>`
462
462
  */
463
- function buildReturnStatement({ node, tsResolver, callConfig }) {
463
+ function buildReturnStatement({ node, types, callConfig }) {
464
464
  return `return request(${callConfig}) as Promise<RequestResult<${buildRequestResultGenerics({
465
465
  node,
466
- tsResolver
466
+ types
467
467
  })}>>`;
468
468
  }
469
469
  //#endregion
@@ -539,30 +539,28 @@ function buildSecurityMetadata({ security }) {
539
539
  const declarationPrinter = functionPrinter({ mode: "declaration" });
540
540
  /**
541
541
  * Builds the grouped-options signature for one operation: a single `options` object whose `TData`
542
- * is the plugin-ts `<Name>Options` (carrying a literal `url`), and a `RequestResult` return type
543
- * keyed to the plugin-ts per-status responses record. There are no positional arguments.
542
+ * is the `<Name>Options` type, and a `RequestResult` return type keyed to the per-status responses
543
+ * record. There are no positional arguments.
544
544
  *
545
545
  * The generated file imports `<Name>Options` and `<Name>Responses` and uses them directly, so no
546
- * per-operation input type has to be emitted.
546
+ * per-operation input type has to be emitted. Both names come from `types`, which is `plugin-ts` or
547
+ * `plugin-zod`'s inferred types (see `resolveOperationTypes`).
547
548
  */
548
- function buildGroupedOptionsSignature({ node, tsResolver }) {
549
- const optionsName = tsResolver.response.options(node);
550
- const responsesName = tsResolver.response.responses(node);
549
+ function buildGroupedOptionsSignature({ node, types }) {
550
+ const optionsName = types.response.options(node);
551
551
  const resultGenerics = buildRequestResultGenerics({
552
552
  node,
553
- tsResolver
553
+ types
554
554
  });
555
555
  const { isOptional } = getRequestGroupOptionality(node);
556
556
  return {
557
- dataTypeName: optionsName,
558
557
  paramsSignature: declarationPrinter.print(createFunctionParameters({ params: [createFunctionParameter({
559
558
  name: "options",
560
559
  type: `Options<${optionsName}, ThrowOnError>`,
561
560
  ...isOptional ? { default: "{}" } : {}
562
561
  })] })) ?? "",
563
562
  returnType: `Promise<RequestResult<${resultGenerics}>>`,
564
- generics: ["ThrowOnError extends boolean = true"],
565
- importedTypeNames: [optionsName, responsesName]
563
+ generics: ["ThrowOnError extends boolean = true"]
566
564
  };
567
565
  }
568
566
  //#endregion
@@ -681,15 +679,15 @@ function buildCallConfig({ node, validator, zodResolver, security }) {
681
679
  * returns the `RequestResult`. A per-call `options.client` still overrides the instance client, so
682
680
  * one operation can be routed to a different environment without a new instance.
683
681
  */
684
- function buildSdkMethod({ node, name, tsResolver, zodResolver, validator, security }) {
682
+ function buildSdkMethod({ node, name, types, zodResolver, validator, security }) {
685
683
  if (!ast.isHttpOperationNode(node)) return "";
686
684
  const signature = buildGroupedOptionsSignature({
687
685
  node,
688
- tsResolver
686
+ types
689
687
  });
690
688
  const returnStatement = buildReturnStatement({
691
689
  node,
692
- tsResolver,
690
+ types,
693
691
  callConfig: buildCallConfig({
694
692
  node,
695
693
  validator,
@@ -770,11 +768,11 @@ function buildStyles({ node }) {
770
768
  * single `options` object to the resolved client and returns the `RequestResult`. The type, signature,
771
769
  * and call config are built with the AST factory, and only the jsx-renderer emits the source.
772
770
  */
773
- function Operation({ name, node, tsResolver, zodResolver, validator, security, isExportable = true, isIndexable = true }) {
771
+ function Operation({ name, node, types, zodResolver, validator, security, isExportable = true, isIndexable = true }) {
774
772
  if (!ast.isHttpOperationNode(node)) return null;
775
773
  const signature = buildGroupedOptionsSignature({
776
774
  node,
777
- tsResolver
775
+ types
778
776
  });
779
777
  const validators = buildValidatorHooks({
780
778
  node,
@@ -806,11 +804,11 @@ function Operation({ name, node, tsResolver, zodResolver, validator, security, i
806
804
  responseTypeLiteral,
807
805
  "...config"
808
806
  ].filter(Boolean).join(", ")} }`;
809
- const eventType = `SuccessOf<${tsResolver.response.responses(node)}>`;
807
+ const eventType = `SuccessOf<${types.response.responses(node)}>`;
810
808
  const returnType = eventStream ? `Promise<EventStreamResult<${eventType}>>` : signature.returnType;
811
809
  const returnStatement = eventStream ? `return toEventStream<${eventType}>(request(${callConfig}))` : buildReturnStatement({
812
810
  node,
813
- tsResolver,
811
+ types,
814
812
  callConfig
815
813
  });
816
814
  return /* @__PURE__ */ jsx(File.Source, {
@@ -845,10 +843,10 @@ function Operation({ name, node, tsResolver, zodResolver, validator, security, i
845
843
  * still overrides the instance client for a one-off call.
846
844
  */
847
845
  function SdkClient({ name, isExportable = true, isIndexable = true, operations, validator, children }) {
848
- const methods = operations.map(({ node, name: methodName, tsResolver, zodResolver, security }) => buildSdkMethod({
846
+ const methods = operations.map(({ node, name: methodName, types, zodResolver, security }) => buildSdkMethod({
849
847
  node,
850
848
  name: methodName,
851
- tsResolver,
849
+ types,
852
850
  zodResolver,
853
851
  validator,
854
852
  security
@@ -868,6 +866,53 @@ function SdkClient({ name, isExportable = true, isIndexable = true, operations,
868
866
  });
869
867
  }
870
868
  //#endregion
869
+ //#region ../../internals/client/src/resolveOperationTypes.ts
870
+ /**
871
+ * Warning a client generator reports when neither plugin can supply the operation types, so the
872
+ * pipeline says why nothing was generated instead of silently emitting no files.
873
+ */
874
+ const MISSING_OPERATION_TYPES_WARNING = "Skipped: no operation types available. Add `pluginTs()`, or `pluginZod({ inferred: true })` to type the client from its zod schemas.";
875
+ /**
876
+ * Picks the plugin a generated client takes its `Options` and `Responses` types from.
877
+ *
878
+ * `plugin-ts` wins whenever it is in the pipeline, so existing configs keep the types they generate
879
+ * today. Without it, `pluginZod({ inferred: true })` takes over: its inferred options and responses
880
+ * types are built from the same shared schemas as the `plugin-ts` ones, so a client typed off
881
+ * `z.infer` carries what the codecs decode to (a `Temporal` instance, a `Date`) rather than the raw
882
+ * wire type. Returns `null` when neither is available, leaving the caller nothing to type against.
883
+ *
884
+ * @example
885
+ * ```ts
886
+ * const types = resolveOperationTypes(ctx.driver)
887
+ * if (!types) return null
888
+ * types.response.options(node) // 'GetPetByIdOptions', or 'GetPetByIdOptionsSchemaType' from zod
889
+ * ```
890
+ */
891
+ function resolveOperationTypes(driver) {
892
+ const pluginTs = driver.getPlugin(pluginTsName);
893
+ if (pluginTs) {
894
+ const resolver = driver.getResolver(pluginTsName);
895
+ return {
896
+ response: resolver.response,
897
+ resolver,
898
+ output: pluginTs.options?.output,
899
+ group: pluginTs.options?.group
900
+ };
901
+ }
902
+ const pluginZod = driver.getPlugin(pluginZodName);
903
+ if (!pluginZod?.options?.inferred) return null;
904
+ const resolver = driver.getResolver(pluginZodName);
905
+ return {
906
+ response: {
907
+ options: resolver.response.options,
908
+ responses: (node) => resolver.schema.type(resolver.response.responses(node))
909
+ },
910
+ resolver,
911
+ output: pluginZod.options.output,
912
+ group: pluginZod.options.group
913
+ };
914
+ }
915
+ //#endregion
871
916
  //#region ../../internals/client/src/generators/clientGenerator.tsx
872
917
  /**
873
918
  * Builds the built-in per-operation generator shared by the client plugins (`@kubb/plugin-fetch`,
@@ -884,13 +929,15 @@ function createClientGenerator(name) {
884
929
  if (!ast.isHttpOperationNode(node)) return null;
885
930
  const { config, driver, resolver, root } = ctx;
886
931
  const { output, validator, group } = ctx.options;
887
- const pluginTs = driver.getPlugin(pluginTsName);
888
- if (!pluginTs) return null;
889
- const tsResolver = driver.getResolver(pluginTsName);
932
+ const types = resolveOperationTypes(driver);
933
+ if (!types) {
934
+ ctx.warn(MISSING_OPERATION_TYPES_WARNING);
935
+ return null;
936
+ }
890
937
  const pluginZod = resolveResponseValidator(validator) === "zod" || resolveRequestValidator(validator) === "zod" ? driver.getPlugin(pluginZodName) : null;
891
938
  const zodResolver = pluginZod ? driver.getResolver(pluginZodName) : null;
892
939
  const hasRequestBody = Boolean(node.requestBody?.content?.[0]?.schema);
893
- const importedTypeNames = [tsResolver.response.options(node), tsResolver.response.responses(node)];
940
+ const importedTypeNames = [types.response.options(node), types.response.responses(node)];
894
941
  const importedZodNames = zodResolver ? [
895
942
  resolveResponseValidator(validator) === "zod" ? zodResolver.response.response?.(node) : null,
896
943
  resolveResponseValidator(validator) === "zod" ? buildZodErrorParse(node, zodResolver)?.expression ?? null : null,
@@ -904,13 +951,13 @@ function createClientGenerator(name) {
904
951
  output,
905
952
  group: group ?? void 0
906
953
  }),
907
- fileTs: resolveDependencyOperationFile({
954
+ fileTypes: resolveDependencyOperationFile({
908
955
  cache: ctx.cache,
909
956
  node,
910
- resolver: tsResolver,
957
+ resolver: types.resolver,
911
958
  root,
912
- output: pluginTs.options?.output ?? output,
913
- group: pluginTs.options?.group
959
+ output: types.output ?? output,
960
+ group: types.group
914
961
  }),
915
962
  fileZod: zodResolver && pluginZod?.options ? zodResolver.file({
916
963
  ...operationFileEntry(node, node.operationId),
@@ -962,10 +1009,10 @@ function createClientGenerator(name) {
962
1009
  path: clientPath,
963
1010
  isTypeOnly: true
964
1011
  }),
965
- meta.fileTs && importedTypeNames.length > 0 && /* @__PURE__ */ jsx(File.Import, {
1012
+ meta.fileTypes && importedTypeNames.length > 0 && /* @__PURE__ */ jsx(File.Import, {
966
1013
  name: Array.from(new Set(importedTypeNames)),
967
1014
  root: meta.file.path,
968
- path: meta.fileTs.path,
1015
+ path: meta.fileTypes.path,
969
1016
  isTypeOnly: true
970
1017
  }),
971
1018
  meta.fileZod && importedZodNames.length > 0 && /* @__PURE__ */ jsx(File.Import, {
@@ -976,7 +1023,7 @@ function createClientGenerator(name) {
976
1023
  /* @__PURE__ */ jsx(Operation, {
977
1024
  name: meta.name,
978
1025
  node,
979
- tsResolver,
1026
+ types,
980
1027
  zodResolver,
981
1028
  validator,
982
1029
  security
@@ -1012,8 +1059,8 @@ function SdkFacade({ name, isExportable = true, isIndexable = true, members, chi
1012
1059
  }
1013
1060
  //#endregion
1014
1061
  //#region ../../internals/client/src/generators/sdkGenerator.tsx
1015
- function resolveTypeImportNames(node, tsResolver) {
1016
- return [tsResolver.response.options(node), tsResolver.response.responses(node)];
1062
+ function resolveTypeImportNames(node, types) {
1063
+ return [types.response.options(node), types.response.responses(node)];
1017
1064
  }
1018
1065
  function resolveZodImportNames(node, zodResolver, validator) {
1019
1066
  const { query: queryParams } = getOperationParameters(node);
@@ -1028,21 +1075,18 @@ function resolveZodImportNames(node, zodResolver, validator) {
1028
1075
  * Groups operations into one controller per tag. Operations without a tag fall back to a single
1029
1076
  * `Client`/`ApiClient` controller, matching the resolver's default naming.
1030
1077
  */
1031
- function buildControllers(nodes, ctx) {
1078
+ function buildControllers(nodes, ctx, types) {
1032
1079
  const { driver, resolver, root } = ctx;
1033
1080
  const { output, group, validator } = ctx.options;
1034
- const pluginTs = driver.getPlugin(pluginTsName);
1035
- const tsResolver = driver.getResolver(pluginTsName);
1036
- const tsPluginOptions = pluginTs.options;
1037
1081
  const pluginZod = isValidatorEnabled(validator) ? driver.getPlugin(pluginZodName) : null;
1038
1082
  const zodResolver = pluginZod ? driver.getResolver(pluginZodName) : null;
1039
1083
  const document = ctx.adapter.document;
1040
1084
  function buildOperationData(node) {
1041
- const typeFile = tsResolver.file({
1085
+ const typeFile = types.resolver.file({
1042
1086
  ...operationFileEntry(node, node.operationId),
1043
1087
  root,
1044
- output: tsPluginOptions?.output ?? output,
1045
- group: tsPluginOptions?.group
1088
+ output: types.output ?? output,
1089
+ group: types.group
1046
1090
  });
1047
1091
  const zodFile = zodResolver && pluginZod?.options ? zodResolver.file({
1048
1092
  ...operationFileEntry(node, node.operationId),
@@ -1058,7 +1102,7 @@ function buildControllers(nodes, ctx) {
1058
1102
  return {
1059
1103
  node,
1060
1104
  name: resolver.name(node.operationId),
1061
- tsResolver,
1105
+ types,
1062
1106
  zodResolver,
1063
1107
  typeFile,
1064
1108
  zodFile,
@@ -1123,8 +1167,13 @@ function createSdkGenerator() {
1123
1167
  operations(nodes, ctx) {
1124
1168
  const { config, resolver, root } = ctx;
1125
1169
  const { output, group, validator, sdk } = ctx.options;
1126
- if (!ctx.driver.getPlugin(pluginTsName) || !sdk) return null;
1127
- const controllers = buildControllers(nodes, ctx);
1170
+ if (!sdk) return null;
1171
+ const types = resolveOperationTypes(ctx.driver);
1172
+ if (!types) {
1173
+ ctx.warn(MISSING_OPERATION_TYPES_WARNING);
1174
+ return null;
1175
+ }
1176
+ const controllers = buildControllers(nodes, ctx, types);
1128
1177
  const clientPath = path.resolve(root, ".kubb/client.ts");
1129
1178
  const banner = (file) => resolver.default.banner(ctx.meta, {
1130
1179
  output,
@@ -1145,7 +1194,7 @@ function createSdkGenerator() {
1145
1194
  const renderClassFile = (className, file, ops) => {
1146
1195
  const { namesByPath: typeNamesByPath, filesByPath: typeFilesByPath } = collectImportsByFile(ops, (op) => ({
1147
1196
  file: op.typeFile,
1148
- names: resolveTypeImportNames(op.node, op.tsResolver)
1197
+ names: resolveTypeImportNames(op.node, op.types)
1149
1198
  }));
1150
1199
  const { namesByPath: zodNamesByPath, filesByPath: zodFilesByPath } = isValidatorEnabled(validator) ? collectImportsByFile(ops, (op) => ({
1151
1200
  file: op.zodFile,
@@ -1352,7 +1401,7 @@ const pluginFetch = definePlugin((options) => {
1352
1401
  return {
1353
1402
  name: pluginFetchName,
1354
1403
  options,
1355
- dependencies: [pluginTsName, isValidatorEnabled(resolved.validator) ? pluginZodName : null].filter((dependency) => Boolean(dependency)),
1404
+ dependencies: [pluginTsName, pluginZodName],
1356
1405
  hooks: { "kubb:plugin:setup"(ctx) {
1357
1406
  ctx.setOptions(resolved);
1358
1407
  ctx.setResolver(resolved.resolver);