zod-nest 0.10.1 → 0.12.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/README.md CHANGED
@@ -39,7 +39,7 @@ For the long-form motivation, see [`docs/why-this-exists.md`](docs/why-this-exis
39
39
  A short list of behavioural differences you'll hit on day one. Full migration table is in [`MIGRATION.md`](MIGRATION.md).
40
40
 
41
41
  - **Multi-status `@ZodResponse`** — stack the decorator per status code. In `nestjs-zod`, multi-status required mixing `@ZodSerializerDto` with hand-rolled `@ApiResponse({ status: ... })` calls.
42
- - **No internal `@HttpCode`** — `@ZodResponse` does **not** call `@HttpCode` under the hood. Status resolution precedence: `@ZodResponse({ status })` → `@HttpCode(...)` on the handler → method default (`POST → 201`, others → `200`). The caller controls `201` vs `200` vs `204` via standard NestJS decorators.
42
+ - **No internal `@HttpCode`** — `@ZodResponse` does **not** call `@HttpCode` under the hood. Status resolution precedence: `@ZodResponse({ status })` → `@HttpCode(...)` on the handler → method default (`POST → 201`, others → `200`). The caller controls `201` vs `200` vs `204` via standard NestJS decorators. `status` accepts numeric codes plus the OpenAPI 3.1 range keys (`'1XX'`…`'5XX'`) and `'default'` (sugar for the resolved method default).
43
43
  - **I/O suffix only when needed** — `<Id>Output` is only emitted when the input and output JSON Schemas actually differ. `nestjs-zod` always emitted `_Output`.
44
44
  - **OpenAPI 3.1 only** — no `3.0` fallback. `$ref`s emit to the final location; `cleanupOpenApiDoc` is unnecessary.
45
45
  - **Validation-failure logging out of the box** — `nestjs-zod` has none.
@@ -52,7 +52,6 @@ A short list of behavioural differences you'll hit on day one. Full migration ta
52
52
 
53
53
  - **Zod v3 support** — Zod v4 only. Migrate first.
54
54
  - **`class-validator` / `class-transformer` coexistence** — `zod-nest` is Zod-native. Mixing class-validator decorators on a `createZodDto` result is not supported.
55
- - **Status wildcards** in `@ZodResponse` (`'2XX'`, `'default'`) — deferred to v1.
56
55
  - **Hybrid DTO projects** — mixing `createZodDto` DTOs with plain `@ApiProperty` classes in the same controller is not tested.
57
56
  - **Non-HTTP contexts** — WebSocket gateways, GraphQL resolvers, microservice handlers are out of scope.
58
57
 
@@ -423,7 +422,7 @@ A compact, link-out index. Type signatures and detailed semantics live in the co
423
422
  - `ZodValidationPipe`, `ZodValidationException`, `ZodValidationPipeOptions`, `CreateValidationException`
424
423
 
425
424
  **Response** — [`docs/responses.md`](docs/responses.md)
426
- - `@ZodResponse({ status?, type, description?, passthroughOnError? })`, `ZodSerializerInterceptor`, `ZodSerializationException`, `defaultStatusFor`, `resolveEffectiveStatus`, `ResponseVariant`, `ZOD_RESPONSES_METADATA_KEY`
425
+ - `@ZodResponse({ status?, type, description?, passthroughOnError? })`, `ZodSerializerInterceptor`, `ZodSerializationException`, `defaultStatusFor`, `resolveEffectiveStatus`, `ResponseStatusInput`, `ResponseStatusWildcard`, `ResponseVariant`, `ZOD_RESPONSES_METADATA_KEY`
427
426
 
428
427
  **Document** — [`docs/swagger-integration.md`](docs/swagger-integration.md)
429
428
  - `applyZodNest(rawDoc, options)`, `ApplyZodNestOptions`, `ZodNestDocumentError`
@@ -449,6 +448,19 @@ A compact, link-out index. Type signatures and detailed semantics live in the co
449
448
  | Exception classes | [`docs/exceptions.md`](docs/exceptions.md) |
450
449
  | Recipes | [`docs/recipes/`](docs/recipes/) |
451
450
 
451
+ ## Compatibility matrix
452
+
453
+ `zod-nest` declares broad peer-dep ranges in `package.json`: `zod >= 4.4.0`, `@nestjs/common >= 10`, `@nestjs/core >= 10`, `@nestjs/swagger >= 8`, `rxjs >= 7`, Node `>= 22`. CI validates those claims by running the full test suite against the cells below; a red cell is a real blocker.
454
+
455
+ | Cell | `zod` | `@nestjs/common` | `@nestjs/core` | `@nestjs/swagger` |
456
+ |---|---|---|---|---|
457
+ | `floor` | 4.4.0 | 10.0.0 | 10.0.0 | 8.0.0 |
458
+ | `zod-latest` | latest | 10.0.0 | 10.0.0 | 8.0.0 |
459
+ | `nest-latest` | 4.4.0 | latest | latest | latest |
460
+ | `all-latest` | latest | latest | latest | latest |
461
+
462
+ Cell definitions live in [`.github/compat-matrix.json`](.github/compat-matrix.json). The CI workflow ([`.github/workflows/compat-matrix.yml`](.github/workflows/compat-matrix.yml)) runs on every push to `main` and weekly on Monday — when a cell fails, the workflow opens (or comments on) a GitHub issue labelled `compat-matrix-failure` so the regression is tracked outside the Actions UI. Editing the JSON is the formal way to extend or shrink supported ranges — Node + rxjs are not currently matrixed (Node floor `22` is enforced by `engines`; rxjs has been stable enough not to need cells yet).
463
+
452
464
  ## Migration from `nestjs-zod`
453
465
 
454
466
  If you're coming from `nestjs-zod`, the headline changes are:
@@ -457,7 +469,6 @@ If you're coming from `nestjs-zod`, the headline changes are:
457
469
  - Replace `@ApiOkResponse({ type: Dto }) + @ZodSerializerDto(Dto)` pairs with `@ZodResponse({ type: Dto })`.
458
470
  - Drop `class-validator` / `class-transformer` if they were installed only for `nestjs-zod` interop.
459
471
  - Check any `MyDto.isZodDto` reflection — the discriminator is now `Symbol.for('zod-nest.dto') in MyDto`.
460
- - Status wildcards (`'2XX'`, `'default'`) aren't supported in v0 — use explicit statuses.
461
472
 
462
473
  Full guide with side-by-side diffs and a 19-row breaking-changes table in [`MIGRATION.md`](MIGRATION.md).
463
474
 
package/dist/index.d.mts CHANGED
@@ -321,6 +321,12 @@ declare class ZodValidationPipe implements PipeTransform {
321
321
  */
322
322
  declare const ZOD_RESPONSES_METADATA_KEY: unique symbol;
323
323
  type ResponseVariantKind = 'single' | 'array' | 'tuple';
324
+ /**
325
+ * OpenAPI 3.1 range keys accepted by `@ZodResponse({ status })`. Matched
326
+ * by `ZodSerializerInterceptor` after exact numeric matches fail —
327
+ * `'2XX'` covers 200–299, `'4XX'` covers 400–499, and so on.
328
+ */
329
+ type ResponseStatusWildcard = '1XX' | '2XX' | '3XX' | '4XX' | '5XX';
324
330
  /**
325
331
  * Description payload accepted by `@ZodResponse(...)` and passed through to
326
332
  * `applyZodNest`'s `@ApiResponse(...)` emitter. String form is shorthand for
@@ -337,14 +343,20 @@ type ZodResponseDescription = string | {
337
343
  * `validationSchema` so `applyZodNest` can emit `@ApiResponse({ type })`
338
344
  * without unwrapping the runtime-only `z.array(...)` / `z.tuple([...])` wrapper.
339
345
  *
340
- * `status` is `undefined` when the user didn't pass one explicitly the
341
- * effective status is resolved lazily by `resolveEffectiveStatus(variant,
342
- * handler)` because `@ZodResponse` runs *before* NestJS' route decorators
343
- * (`@Get`, `@Post`, ...) under TypeScript's bottom-up application order,
344
- * so `METHOD_METADATA` is not yet set when the decorator evaluates.
346
+ * `status` is `undefined` when the user didn't pass one explicitly OR when
347
+ * the user wrote `'default'` (the decorator collapses both to `undefined` —
348
+ * they mean the same thing: "resolve to the method's default status at
349
+ * request time"). The effective status is resolved lazily by
350
+ * `resolveEffectiveStatus(variant, handler)` because `@ZodResponse` runs
351
+ * *before* NestJS' route decorators (`@Get`, `@Post`, ...) under
352
+ * TypeScript's bottom-up application order, so `METHOD_METADATA` is not
353
+ * yet set when the decorator evaluates.
354
+ *
355
+ * A wildcard string (`'2XX'` / `'4XX'` / ...) is kept verbatim — the
356
+ * matcher in `ZodSerializerInterceptor` handles range comparison.
345
357
  */
346
358
  interface ResponseVariant {
347
- status: number | undefined;
359
+ status: number | ResponseStatusWildcard | undefined;
348
360
  kind: ResponseVariantKind;
349
361
  dto: ZodDto | readonly ZodDto[];
350
362
  validationSchema: z.ZodType;
@@ -365,8 +377,22 @@ interface ResponseVariant {
365
377
  * so typos surface at module load, not the first request.
366
378
  */
367
379
  type ZodResponseType = ZodDto | readonly [ZodDto, ...ZodDto[]];
380
+ /**
381
+ * Accepted shapes for `@ZodResponse({ status })`:
382
+ * - `number` — exact match against `response.statusCode` (most common case).
383
+ * - `'1XX'` / `'2XX'` / `'3XX'` / `'4XX'` / `'5XX'` — OpenAPI 3.1 range key;
384
+ * `'2XX'` matches 200–299, etc. Considered only after no exact numeric
385
+ * variant matches the observed status.
386
+ * - `'default'` — sugar for the handler's method default status. Collapsed
387
+ * to `undefined` when the variant is built, so `resolveEffectiveStatus`
388
+ * walks the same `@HttpCode → method-default` chain as an omitted `status`.
389
+ * This deliberately does NOT implement a catch-all-fallback semantic; it
390
+ * names the canonical-success card explicitly, matching what consumers
391
+ * already write in `@ApiResponse({ status: 'default' })`.
392
+ */
393
+ type ResponseStatusInput = number | ResponseStatusWildcard | 'default';
368
394
  interface ZodResponseOptions {
369
- status?: number;
395
+ status?: ResponseStatusInput;
370
396
  type: ZodResponseType;
371
397
  description?: ZodResponseDescription;
372
398
  passthroughOnError?: boolean;
@@ -374,7 +400,8 @@ interface ZodResponseOptions {
374
400
  /**
375
401
  * Method-only decorator. Declares a typed response variant for the handler.
376
402
  * Stack multiple decorations to declare per-status types; lookup at runtime
377
- * is by `response.statusCode === variant.status`.
403
+ * is by `ZodSerializerInterceptor`'s two-pass matcher (exact numeric, then
404
+ * `'NXX'` wildcard).
378
405
  *
379
406
  * The wrapped Zod schema (array / tuple) is built once at decoration time
380
407
  * and stored on the variant record — no per-request schema construction.
@@ -404,17 +431,19 @@ declare class ZodSerializerInterceptor implements NestInterceptor {
404
431
  */
405
432
  declare const defaultStatusFor: (handler: object) => number;
406
433
  /**
407
- * Resolve the effective status code for a variant. Precedence chain:
434
+ * Resolve the effective status for a variant. Precedence chain:
408
435
  *
409
- * 1. Explicit `@ZodResponse({ status })` on the decorator call — `variant.status`.
410
- * 2. `@HttpCode(n)` on the handlerread via `defaultStatusFor()` at runtime.
411
- * 3. HTTP method default (POST → 201, others → 200) — also via `defaultStatusFor()`.
436
+ * 1. Explicit numeric `@ZodResponse({ status })` returned verbatim.
437
+ * 2. Wildcard `@ZodResponse({ status: 'NXX' })`returned verbatim; the
438
+ * interceptor matcher handles range comparison against `response.statusCode`.
439
+ * 3. Omitted status (or `'default'` collapsed at decoration time) —
440
+ * `@HttpCode(n)` then HTTP-method default via `defaultStatusFor()`.
412
441
  *
413
442
  * Resolution is deferred to request time because `@ZodResponse` runs before
414
443
  * NestJS' route + `@HttpCode` decorators — none of their metadata is set
415
444
  * when the decorator evaluates.
416
445
  */
417
- declare const resolveEffectiveStatus: (variant: ResponseVariant, handler: object) => number;
446
+ declare const resolveEffectiveStatus: (variant: ResponseVariant, handler: object) => number | ResponseStatusWildcard;
418
447
 
419
448
  /**
420
449
  * Central wiring for the zod-nest pipe + interceptor. Call
@@ -498,4 +527,4 @@ declare class ZodNestDocumentError extends ZodNestError {
498
527
  constructor(code: ZodNestDocumentErrorCode, message: string, details?: Record<string, unknown>);
499
528
  }
500
529
 
501
- export { type ApplyZodNestOptions, COMPONENTS_SCHEMAS_PREFIX, type CreateSerializationException, type CreateValidationException, type CreateZodDtoOptions, DEFAULT_MAX_LOGGED_VALUE_BYTES, DEFAULT_REDACT_KEYS, type Io, type LineageEntry, type NormalizedZodNestOptions, type Override, type OverrideContext, type ResponseVariant, type ResponseVariantKind, type SchemaObject, type ToOpenApiOptions, type ToOpenApiResult, ZOD_DTO_SYMBOL, ZOD_NEST_DTO_EXTENSION, ZOD_NEST_ERROR_DUPLICATE_ID, ZOD_NEST_ERROR_EXTENSION, ZOD_NEST_OPTIONS, ZOD_RESPONSES_METADATA_KEY, type ZodDto, type ZodDtoMarker, ZodNestDocumentError, type ZodNestDocumentErrorCode, ZodNestError, ZodNestModule, type ZodNestModuleOptions, type ZodNestRegistry, ZodNestUnrepresentableError, ZodResponse, type ZodResponseDescription, type ZodResponseOptions, type ZodResponseType, ZodSerializationException, ZodSerializerInterceptor, ZodValidationException, ZodValidationPipe, type ZodValidationPipeArg, type ZodValidationPipeOptions, applyZodNest, createRegistry, createZodDto, defaultRegistry, defaultStatusFor, extend, getLineage, isZodDto, isZodDtoMarker, makeZodDtoMarker, resolveEffectiveStatus, toOpenApi };
530
+ export { type ApplyZodNestOptions, COMPONENTS_SCHEMAS_PREFIX, type CreateSerializationException, type CreateValidationException, type CreateZodDtoOptions, DEFAULT_MAX_LOGGED_VALUE_BYTES, DEFAULT_REDACT_KEYS, type Io, type LineageEntry, type NormalizedZodNestOptions, type Override, type OverrideContext, type ResponseStatusInput, type ResponseStatusWildcard, type ResponseVariant, type ResponseVariantKind, type SchemaObject, type ToOpenApiOptions, type ToOpenApiResult, ZOD_DTO_SYMBOL, ZOD_NEST_DTO_EXTENSION, ZOD_NEST_ERROR_DUPLICATE_ID, ZOD_NEST_ERROR_EXTENSION, ZOD_NEST_OPTIONS, ZOD_RESPONSES_METADATA_KEY, type ZodDto, type ZodDtoMarker, ZodNestDocumentError, type ZodNestDocumentErrorCode, ZodNestError, ZodNestModule, type ZodNestModuleOptions, type ZodNestRegistry, ZodNestUnrepresentableError, ZodResponse, type ZodResponseDescription, type ZodResponseOptions, type ZodResponseType, ZodSerializationException, ZodSerializerInterceptor, ZodValidationException, ZodValidationPipe, type ZodValidationPipeArg, type ZodValidationPipeOptions, applyZodNest, createRegistry, createZodDto, defaultRegistry, defaultStatusFor, extend, getLineage, isZodDto, isZodDtoMarker, makeZodDtoMarker, resolveEffectiveStatus, toOpenApi };
package/dist/index.d.ts CHANGED
@@ -321,6 +321,12 @@ declare class ZodValidationPipe implements PipeTransform {
321
321
  */
322
322
  declare const ZOD_RESPONSES_METADATA_KEY: unique symbol;
323
323
  type ResponseVariantKind = 'single' | 'array' | 'tuple';
324
+ /**
325
+ * OpenAPI 3.1 range keys accepted by `@ZodResponse({ status })`. Matched
326
+ * by `ZodSerializerInterceptor` after exact numeric matches fail —
327
+ * `'2XX'` covers 200–299, `'4XX'` covers 400–499, and so on.
328
+ */
329
+ type ResponseStatusWildcard = '1XX' | '2XX' | '3XX' | '4XX' | '5XX';
324
330
  /**
325
331
  * Description payload accepted by `@ZodResponse(...)` and passed through to
326
332
  * `applyZodNest`'s `@ApiResponse(...)` emitter. String form is shorthand for
@@ -337,14 +343,20 @@ type ZodResponseDescription = string | {
337
343
  * `validationSchema` so `applyZodNest` can emit `@ApiResponse({ type })`
338
344
  * without unwrapping the runtime-only `z.array(...)` / `z.tuple([...])` wrapper.
339
345
  *
340
- * `status` is `undefined` when the user didn't pass one explicitly the
341
- * effective status is resolved lazily by `resolveEffectiveStatus(variant,
342
- * handler)` because `@ZodResponse` runs *before* NestJS' route decorators
343
- * (`@Get`, `@Post`, ...) under TypeScript's bottom-up application order,
344
- * so `METHOD_METADATA` is not yet set when the decorator evaluates.
346
+ * `status` is `undefined` when the user didn't pass one explicitly OR when
347
+ * the user wrote `'default'` (the decorator collapses both to `undefined` —
348
+ * they mean the same thing: "resolve to the method's default status at
349
+ * request time"). The effective status is resolved lazily by
350
+ * `resolveEffectiveStatus(variant, handler)` because `@ZodResponse` runs
351
+ * *before* NestJS' route decorators (`@Get`, `@Post`, ...) under
352
+ * TypeScript's bottom-up application order, so `METHOD_METADATA` is not
353
+ * yet set when the decorator evaluates.
354
+ *
355
+ * A wildcard string (`'2XX'` / `'4XX'` / ...) is kept verbatim — the
356
+ * matcher in `ZodSerializerInterceptor` handles range comparison.
345
357
  */
346
358
  interface ResponseVariant {
347
- status: number | undefined;
359
+ status: number | ResponseStatusWildcard | undefined;
348
360
  kind: ResponseVariantKind;
349
361
  dto: ZodDto | readonly ZodDto[];
350
362
  validationSchema: z.ZodType;
@@ -365,8 +377,22 @@ interface ResponseVariant {
365
377
  * so typos surface at module load, not the first request.
366
378
  */
367
379
  type ZodResponseType = ZodDto | readonly [ZodDto, ...ZodDto[]];
380
+ /**
381
+ * Accepted shapes for `@ZodResponse({ status })`:
382
+ * - `number` — exact match against `response.statusCode` (most common case).
383
+ * - `'1XX'` / `'2XX'` / `'3XX'` / `'4XX'` / `'5XX'` — OpenAPI 3.1 range key;
384
+ * `'2XX'` matches 200–299, etc. Considered only after no exact numeric
385
+ * variant matches the observed status.
386
+ * - `'default'` — sugar for the handler's method default status. Collapsed
387
+ * to `undefined` when the variant is built, so `resolveEffectiveStatus`
388
+ * walks the same `@HttpCode → method-default` chain as an omitted `status`.
389
+ * This deliberately does NOT implement a catch-all-fallback semantic; it
390
+ * names the canonical-success card explicitly, matching what consumers
391
+ * already write in `@ApiResponse({ status: 'default' })`.
392
+ */
393
+ type ResponseStatusInput = number | ResponseStatusWildcard | 'default';
368
394
  interface ZodResponseOptions {
369
- status?: number;
395
+ status?: ResponseStatusInput;
370
396
  type: ZodResponseType;
371
397
  description?: ZodResponseDescription;
372
398
  passthroughOnError?: boolean;
@@ -374,7 +400,8 @@ interface ZodResponseOptions {
374
400
  /**
375
401
  * Method-only decorator. Declares a typed response variant for the handler.
376
402
  * Stack multiple decorations to declare per-status types; lookup at runtime
377
- * is by `response.statusCode === variant.status`.
403
+ * is by `ZodSerializerInterceptor`'s two-pass matcher (exact numeric, then
404
+ * `'NXX'` wildcard).
378
405
  *
379
406
  * The wrapped Zod schema (array / tuple) is built once at decoration time
380
407
  * and stored on the variant record — no per-request schema construction.
@@ -404,17 +431,19 @@ declare class ZodSerializerInterceptor implements NestInterceptor {
404
431
  */
405
432
  declare const defaultStatusFor: (handler: object) => number;
406
433
  /**
407
- * Resolve the effective status code for a variant. Precedence chain:
434
+ * Resolve the effective status for a variant. Precedence chain:
408
435
  *
409
- * 1. Explicit `@ZodResponse({ status })` on the decorator call — `variant.status`.
410
- * 2. `@HttpCode(n)` on the handlerread via `defaultStatusFor()` at runtime.
411
- * 3. HTTP method default (POST → 201, others → 200) — also via `defaultStatusFor()`.
436
+ * 1. Explicit numeric `@ZodResponse({ status })` returned verbatim.
437
+ * 2. Wildcard `@ZodResponse({ status: 'NXX' })`returned verbatim; the
438
+ * interceptor matcher handles range comparison against `response.statusCode`.
439
+ * 3. Omitted status (or `'default'` collapsed at decoration time) —
440
+ * `@HttpCode(n)` then HTTP-method default via `defaultStatusFor()`.
412
441
  *
413
442
  * Resolution is deferred to request time because `@ZodResponse` runs before
414
443
  * NestJS' route + `@HttpCode` decorators — none of their metadata is set
415
444
  * when the decorator evaluates.
416
445
  */
417
- declare const resolveEffectiveStatus: (variant: ResponseVariant, handler: object) => number;
446
+ declare const resolveEffectiveStatus: (variant: ResponseVariant, handler: object) => number | ResponseStatusWildcard;
418
447
 
419
448
  /**
420
449
  * Central wiring for the zod-nest pipe + interceptor. Call
@@ -498,4 +527,4 @@ declare class ZodNestDocumentError extends ZodNestError {
498
527
  constructor(code: ZodNestDocumentErrorCode, message: string, details?: Record<string, unknown>);
499
528
  }
500
529
 
501
- export { type ApplyZodNestOptions, COMPONENTS_SCHEMAS_PREFIX, type CreateSerializationException, type CreateValidationException, type CreateZodDtoOptions, DEFAULT_MAX_LOGGED_VALUE_BYTES, DEFAULT_REDACT_KEYS, type Io, type LineageEntry, type NormalizedZodNestOptions, type Override, type OverrideContext, type ResponseVariant, type ResponseVariantKind, type SchemaObject, type ToOpenApiOptions, type ToOpenApiResult, ZOD_DTO_SYMBOL, ZOD_NEST_DTO_EXTENSION, ZOD_NEST_ERROR_DUPLICATE_ID, ZOD_NEST_ERROR_EXTENSION, ZOD_NEST_OPTIONS, ZOD_RESPONSES_METADATA_KEY, type ZodDto, type ZodDtoMarker, ZodNestDocumentError, type ZodNestDocumentErrorCode, ZodNestError, ZodNestModule, type ZodNestModuleOptions, type ZodNestRegistry, ZodNestUnrepresentableError, ZodResponse, type ZodResponseDescription, type ZodResponseOptions, type ZodResponseType, ZodSerializationException, ZodSerializerInterceptor, ZodValidationException, ZodValidationPipe, type ZodValidationPipeArg, type ZodValidationPipeOptions, applyZodNest, createRegistry, createZodDto, defaultRegistry, defaultStatusFor, extend, getLineage, isZodDto, isZodDtoMarker, makeZodDtoMarker, resolveEffectiveStatus, toOpenApi };
530
+ export { type ApplyZodNestOptions, COMPONENTS_SCHEMAS_PREFIX, type CreateSerializationException, type CreateValidationException, type CreateZodDtoOptions, DEFAULT_MAX_LOGGED_VALUE_BYTES, DEFAULT_REDACT_KEYS, type Io, type LineageEntry, type NormalizedZodNestOptions, type Override, type OverrideContext, type ResponseStatusInput, type ResponseStatusWildcard, type ResponseVariant, type ResponseVariantKind, type SchemaObject, type ToOpenApiOptions, type ToOpenApiResult, ZOD_DTO_SYMBOL, ZOD_NEST_DTO_EXTENSION, ZOD_NEST_ERROR_DUPLICATE_ID, ZOD_NEST_ERROR_EXTENSION, ZOD_NEST_OPTIONS, ZOD_RESPONSES_METADATA_KEY, type ZodDto, type ZodDtoMarker, ZodNestDocumentError, type ZodNestDocumentErrorCode, ZodNestError, ZodNestModule, type ZodNestModuleOptions, type ZodNestRegistry, ZodNestUnrepresentableError, ZodResponse, type ZodResponseDescription, type ZodResponseOptions, type ZodResponseType, ZodSerializationException, ZodSerializerInterceptor, ZodValidationException, ZodValidationPipe, type ZodValidationPipeArg, type ZodValidationPipeOptions, applyZodNest, createRegistry, createZodDto, defaultRegistry, defaultStatusFor, extend, getLineage, isZodDto, isZodDtoMarker, makeZodDtoMarker, resolveEffectiveStatus, toOpenApi };
package/dist/index.js CHANGED
@@ -801,15 +801,22 @@ var buildKind = /* @__PURE__ */ __name((type) => {
801
801
  validationSchema: type.schema
802
802
  };
803
803
  }, "buildKind");
804
+ var normaliseStatus = /* @__PURE__ */ __name((status) => {
805
+ if (status === "default") {
806
+ return void 0;
807
+ }
808
+ return status;
809
+ }, "normaliseStatus");
804
810
  var ZodResponse = /* @__PURE__ */ __name((opts) => {
805
811
  const built = buildKind(opts.type);
812
+ const status = normaliseStatus(opts.status);
806
813
  return (_target, _propertyKey, descriptor) => {
807
814
  const handler = descriptor.value;
808
815
  if (typeof handler !== "function") {
809
816
  throw new TypeError("[zod-nest] @ZodResponse can only be applied to methods.");
810
817
  }
811
818
  const variant = {
812
- status: opts.status,
819
+ status,
813
820
  kind: built.kind,
814
821
  dto: built.dto,
815
822
  validationSchema: built.validationSchema,
@@ -866,6 +873,22 @@ var formatDtoLabel = /* @__PURE__ */ __name((variant) => {
866
873
  return `[${dtos.map((d) => d.name).join(", ")}]`;
867
874
  }, "formatDtoLabel");
868
875
  var formatHandlerLabel = /* @__PURE__ */ __name((context) => `${context.getClass().name}.${context.getHandler().name}`, "formatHandlerLabel");
876
+ var matchesWildcard = /* @__PURE__ */ __name((wildcard, status) => wildcard.charCodeAt(0) - 48 === Math.floor(status / 100), "matchesWildcard");
877
+ var selectVariant = /* @__PURE__ */ __name((variants, status, handler) => {
878
+ for (const variant of variants) {
879
+ const effective = resolveEffectiveStatus(variant, handler);
880
+ if (typeof effective === "number" && effective === status) {
881
+ return variant;
882
+ }
883
+ }
884
+ for (const variant of variants) {
885
+ const effective = resolveEffectiveStatus(variant, handler);
886
+ if (typeof effective === "string" && matchesWildcard(effective, status)) {
887
+ return variant;
888
+ }
889
+ }
890
+ return void 0;
891
+ }, "selectVariant");
869
892
  exports.ZodSerializerInterceptor = class ZodSerializerInterceptor {
870
893
  static {
871
894
  __name(this, "ZodSerializerInterceptor");
@@ -895,7 +918,7 @@ exports.ZodSerializerInterceptor = class ZodSerializerInterceptor {
895
918
  if (status === void 0) {
896
919
  return value;
897
920
  }
898
- const variant = variants.find((v) => resolveEffectiveStatus(v, handler) === status);
921
+ const variant = selectVariant(variants, status, handler);
899
922
  if (variant === void 0) {
900
923
  return value;
901
924
  }