zod-nest 3.1.0 → 3.2.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.
@@ -103,15 +103,18 @@ var sizeCheck = /* @__PURE__ */ __name((readSize, options) => {
103
103
  // src/multipart/file-marker.ts
104
104
  var fileSchemas = /* @__PURE__ */ new WeakSet();
105
105
  var isZodType = /* @__PURE__ */ __name((value) => value !== null && typeof value === "object" && "_zod" in value, "isZodType");
106
- var unwrapOnce = /* @__PURE__ */ __name((schema) => {
107
- const def = schema._zod.def;
106
+ var innerOf = /* @__PURE__ */ __name((def) => {
108
107
  if ("innerType" in def) {
109
- return isZodType(def.innerType) ? def.innerType : void 0;
108
+ return def.innerType;
110
109
  }
111
110
  if ("element" in def) {
112
- return isZodType(def.element) ? def.element : void 0;
111
+ return def.element;
113
112
  }
114
113
  return void 0;
114
+ }, "innerOf");
115
+ var unwrapOnce = /* @__PURE__ */ __name((schema) => {
116
+ const inner = innerOf(schema._zod.def);
117
+ return isZodType(inner) ? inner : void 0;
115
118
  }, "unwrapOnce");
116
119
  var markFileSchema = /* @__PURE__ */ __name((schema) => {
117
120
  fileSchemas.add(schema);
@@ -787,12 +790,172 @@ var toOpenApi = /* @__PURE__ */ __name((schema, opts) => {
787
790
  return result;
788
791
  }, "toOpenApi");
789
792
 
793
+ // src/schema/anon-id.ts
794
+ var ANON_BODY_PREFIX = "_AnonBodySchema_";
795
+ var anonIdCache = /* @__PURE__ */ new WeakMap();
796
+ var counter = 0;
797
+ var resolveAnonId = /* @__PURE__ */ __name((schema, prefix) => {
798
+ const cached = anonIdCache.get(schema);
799
+ if (cached !== void 0) {
800
+ return cached;
801
+ }
802
+ counter += 1;
803
+ const id = `${prefix}${counter}`;
804
+ anonIdCache.set(schema, id);
805
+ return id;
806
+ }, "resolveAnonId");
807
+
808
+ // src/decorators/internal/zod-schema-ref.ts
809
+ function resolveSchemaRef(schema, options) {
810
+ const registry = options?.registry ?? defaultRegistry;
811
+ const id = registerSchema(schema, registry, {
812
+ id: options?.id
813
+ });
814
+ if (id !== void 0) {
815
+ return {
816
+ kind: "ref",
817
+ ref: {
818
+ $ref: `${COMPONENTS_SCHEMAS_PREFIX}${id}`
819
+ }
820
+ };
821
+ }
822
+ if (options?.deferAnonInline === true) {
823
+ const anonId = resolveAnonId(schema, ANON_BODY_PREFIX);
824
+ registerSchema(schema, registry, {
825
+ id: anonId,
826
+ anonymous: true
827
+ });
828
+ return {
829
+ kind: "ref",
830
+ ref: {
831
+ $ref: `${COMPONENTS_SCHEMAS_PREFIX}${anonId}`
832
+ }
833
+ };
834
+ }
835
+ for (const [child, childId] of discoverDependents(schema)) {
836
+ registry.register(child, childId);
837
+ }
838
+ const { schema: body } = toOpenApi(schema, {
839
+ io: "input",
840
+ registry
841
+ });
842
+ return {
843
+ kind: "inline",
844
+ schema: body
845
+ };
846
+ }
847
+ __name(resolveSchemaRef, "resolveSchemaRef");
848
+
849
+ // src/decorators/internal/zod-param-expand.ts
850
+ var isZodObject = /* @__PURE__ */ __name((schema) => schema._zod.def.type === "object", "isZodObject");
851
+
852
+ // src/decorators/internal/flatten-intersection.ts
853
+ var intersectionArms = /* @__PURE__ */ __name((schema) => {
854
+ if (schema._zod.def.type !== "intersection") {
855
+ return null;
856
+ }
857
+ const def = schema._zod.def;
858
+ return {
859
+ left: def.left,
860
+ right: def.right
861
+ };
862
+ }, "intersectionArms");
863
+ var unionOptions = /* @__PURE__ */ __name((schema) => {
864
+ if (schema._zod.def.type !== "union") {
865
+ return null;
866
+ }
867
+ const def = schema._zod.def;
868
+ return def.options;
869
+ }, "unionOptions");
870
+ var collectObjectShapes = /* @__PURE__ */ __name((schema) => {
871
+ if (isZodObject(schema)) {
872
+ return {
873
+ shapes: [
874
+ schema.shape
875
+ ],
876
+ unionCrossed: false
877
+ };
878
+ }
879
+ const options = unionOptions(schema);
880
+ if (options !== null) {
881
+ const allShapes = [];
882
+ for (const variant of options) {
883
+ const variantResult = collectObjectShapes(variant);
884
+ if (variantResult === null) {
885
+ return null;
886
+ }
887
+ allShapes.push(...variantResult.shapes);
888
+ }
889
+ return {
890
+ shapes: allShapes,
891
+ unionCrossed: true
892
+ };
893
+ }
894
+ const arms = intersectionArms(schema);
895
+ if (arms === null) {
896
+ return null;
897
+ }
898
+ const left = collectObjectShapes(arms.left);
899
+ if (left === null) {
900
+ return null;
901
+ }
902
+ const right = collectObjectShapes(arms.right);
903
+ if (right === null) {
904
+ return null;
905
+ }
906
+ return {
907
+ shapes: [
908
+ ...left.shapes,
909
+ ...right.shapes
910
+ ],
911
+ unionCrossed: left.unionCrossed || right.unionCrossed
912
+ };
913
+ }, "collectObjectShapes");
914
+ var flattenObjectIntersection = /* @__PURE__ */ __name((schema, registry, decoratorName) => {
915
+ const collected = collectObjectShapes(schema);
916
+ if (collected === null) {
917
+ throw new ZodNestError(`${decoratorName} \`flatten: true\` requires every leaf of the schema to be a \`z.object({...})\` \u2014 intersections and unions of objects are supported, but primitives, tuples, transforms, and other non-object leaves are not. Drop \`flatten: true\` to emit the original schema with its composition intact.`);
918
+ }
919
+ const mergedShape = {};
920
+ for (const shape of collected.shapes) {
921
+ Object.assign(mergedShape, shape);
922
+ }
923
+ if (collected.unionCrossed) {
924
+ for (const key of Object.keys(mergedShape)) {
925
+ const value = mergedShape[key];
926
+ if (value !== void 0) {
927
+ mergedShape[key] = value.optional();
928
+ }
929
+ }
930
+ }
931
+ const merged = z.object(mergedShape);
932
+ registerSchema(schema, registry);
933
+ for (const [child, childId] of discoverDependents(schema)) {
934
+ registry.register(child, childId);
935
+ }
936
+ const { schema: body } = toOpenApi(merged, {
937
+ io: "input",
938
+ registry
939
+ });
940
+ return body;
941
+ }, "flattenObjectIntersection");
942
+ var isZodSchema = /* @__PURE__ */ __name((value) => value instanceof z.ZodType, "isZodSchema");
943
+
790
944
  // src/multipart/zod-multipart.decorator.ts
791
945
  var MULTIPART_CONTENT_TYPE = "multipart/form-data";
946
+ var toSchema = /* @__PURE__ */ __name((body) => isZodSchema(body) ? body : z.object({
947
+ ...body
948
+ }), "toSchema");
949
+ var toShape = /* @__PURE__ */ __name((body) => {
950
+ if (!isZodSchema(body)) {
951
+ return body;
952
+ }
953
+ return isZodObject(body) ? body.shape : void 0;
954
+ }, "toShape");
792
955
  var partitionKeys = /* @__PURE__ */ __name((shape) => {
793
956
  const fileKeys = [];
794
957
  const textKeys = [];
795
- for (const [key, schema] of Object.entries(shape)) {
958
+ for (const [key, schema] of Object.entries(shape ?? {})) {
796
959
  if (isFileSchema(schema)) {
797
960
  fileKeys.push(key);
798
961
  continue;
@@ -804,30 +967,28 @@ var partitionKeys = /* @__PURE__ */ __name((shape) => {
804
967
  textKeys
805
968
  };
806
969
  }, "partitionKeys");
807
- var emitInlineBody = /* @__PURE__ */ __name((shape, registry) => {
808
- const object = z.object({
809
- ...shape
810
- });
811
- for (const [child, childId] of discoverDependents(object)) {
812
- registry.register(child, childId);
970
+ var resolveBody = /* @__PURE__ */ __name((schema, options, registry) => {
971
+ if (options?.flatten === true) {
972
+ return flattenObjectIntersection(schema, registry, "@ZodMultipart");
813
973
  }
814
- const { schema } = toOpenApi(object, {
815
- io: "input",
974
+ const resolved = resolveSchemaRef(schema, {
975
+ ...options?.id !== void 0 ? {
976
+ id: options.id
977
+ } : {},
816
978
  registry
817
979
  });
818
- return schema;
819
- }, "emitInlineBody");
980
+ return resolved.kind === "ref" ? resolved.ref : resolved.schema;
981
+ }, "resolveBody");
820
982
  var createZodMultipart = /* @__PURE__ */ __name((defaultFilesIn) => {
821
- return (shape, options) => {
983
+ return (body, options) => {
822
984
  const registry = options?.registry ?? defaultRegistry;
823
- const { fileKeys, textKeys } = partitionKeys(shape);
985
+ const shape = toShape(body);
824
986
  const metadata = {
825
987
  shape,
826
- fileKeys,
827
- textKeys,
988
+ ...partitionKeys(shape),
828
989
  filesIn: options?.filesIn ?? defaultFilesIn
829
990
  };
830
- const body = emitInlineBody(shape, registry);
991
+ const schema = resolveBody(toSchema(body), options, registry);
831
992
  return (target, propertyKey, descriptor) => {
832
993
  const handler = descriptor.value;
833
994
  if (typeof handler !== "function") {
@@ -837,7 +998,7 @@ var createZodMultipart = /* @__PURE__ */ __name((defaultFilesIn) => {
837
998
  const swaggerDescriptor = descriptor;
838
999
  ApiConsumes(MULTIPART_CONTENT_TYPE)(target, propertyKey, swaggerDescriptor);
839
1000
  ApiBody({
840
- schema: body,
1001
+ schema,
841
1002
  ...options?.description !== void 0 ? {
842
1003
  description: options.description
843
1004
  } : {},
@@ -874,10 +1035,17 @@ var readMetadata = /* @__PURE__ */ __name((ctx, decorator) => {
874
1035
  return metadata;
875
1036
  }, "readMetadata");
876
1037
  var isMultipartMetadata = /* @__PURE__ */ __name((value) => value !== null && typeof value === "object" && "shape" in value && "filesIn" in value, "isMultipartMetadata");
1038
+ var requireShape = /* @__PURE__ */ __name((metadata, decorator) => {
1039
+ if (metadata.shape !== void 0) {
1040
+ return metadata.shape;
1041
+ }
1042
+ throw new Error(`[zod-nest] ${decorator} needs a flat body shape, but @ZodMultipart was given a composite schema (an intersection or union). Validate it with @Body(new ZodValidationPipe(schema)) instead.`);
1043
+ }, "requireShape");
877
1044
  var schemaFor = /* @__PURE__ */ __name((metadata, name, decorator) => {
878
- const schema = metadata.shape[name];
1045
+ const shape = requireShape(metadata, decorator);
1046
+ const schema = shape[name];
879
1047
  if (schema === void 0) {
880
- throw new Error(`[zod-nest] ${decorator}('${name}') has no matching property in the @ZodMultipart shape. Declared: ${Object.keys(metadata.shape).join(", ")}.`);
1048
+ throw new Error(`[zod-nest] ${decorator}('${name}') has no matching property in the @ZodMultipart shape. Declared: ${Object.keys(shape).join(", ")}.`);
881
1049
  }
882
1050
  return schema;
883
1051
  }, "schemaFor");
@@ -918,14 +1086,15 @@ var resolveUploadedFiles = /* @__PURE__ */ __name(async (name, ctx) => {
918
1086
  const metadata = readMetadata(ctx, "@ZodUploadedFiles");
919
1087
  assertFilesOnRequest(metadata, "@ZodUploadedFiles");
920
1088
  const request = ctx.switchToHttp().getRequest();
921
- const schema = name === void 0 ? pick(metadata.shape, metadata.fileKeys) : schemaFor(metadata, name, "@ZodUploadedFiles");
1089
+ const schema = name === void 0 ? pick(requireShape(metadata, "@ZodUploadedFiles"), metadata.fileKeys) : schemaFor(metadata, name, "@ZodUploadedFiles");
922
1090
  return validate(schema, request.files, "custom");
923
1091
  }, "resolveUploadedFiles");
924
1092
  var resolveMultipartBody = /* @__PURE__ */ __name(async (_data, ctx) => {
925
1093
  const metadata = readMetadata(ctx, "@ZodMultipartBody");
1094
+ const shape = requireShape(metadata, "@ZodMultipartBody");
926
1095
  const request = ctx.switchToHttp().getRequest();
927
- const keys = metadata.filesIn === MultipartFilesIn.Body ? Object.keys(metadata.shape) : metadata.textKeys;
928
- return validate(pick(metadata.shape, keys), request.body, "body");
1096
+ const keys = metadata.filesIn === MultipartFilesIn.Body ? Object.keys(shape) : metadata.textKeys;
1097
+ return validate(pick(shape, keys), request.body, "body");
929
1098
  }, "resolveMultipartBody");
930
1099
  var ZodUploadedFile = createParamDecorator(resolveUploadedFile);
931
1100
  var ZodUploadedFiles = createParamDecorator(resolveUploadedFiles);