zod-nest 1.6.0 → 1.7.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 +35 -0
- package/dist/index.d.mts +87 -1
- package/dist/index.d.ts +87 -1
- package/dist/index.js +162 -15
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +161 -18
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -24,6 +24,7 @@ For the long-form motivation, see [`docs/why-this-exists.md`](docs/why-this-exis
|
|
|
24
24
|
- **`createZodDto`** — class wrapper around a Zod schema with introspectable `schema`, `id`, `io`, and a sibling `Output` class when input/output diverge.
|
|
25
25
|
- **`ZodValidationPipe`** — auto-detects DTO from handler-arg metatype, accepts an explicit DTO or raw Zod schema, customizable exception factory.
|
|
26
26
|
- **`@ZodResponse`** — stackable per status code, accepts a single DTO, an array (`[Dto]`), or a tuple (`[A, B, …]`). No internal `@HttpCode` — caller controls status.
|
|
27
|
+
- **`@ZodBody` / `@ZodQuery` / `@ZodHeaders` / `@ZodCookies`** — method-level decorators that wire OpenAPI docs for schemas whose `z.infer<>` is a union (intersection-of-union, discriminated unions, etc.) — the ones that can't be wrapped in `createZodDto` because TS refuses unions as class bases (TS2509). Schema validation stays via `@Body(new ZodValidationPipe(schema))`; the type at the handler arg stays `z.infer<>`.
|
|
27
28
|
- **`ZodSerializerInterceptor`** — response validation with a `passthroughOnError` escape hatch for untrusted upstream shapes.
|
|
28
29
|
- **`applyZodNest`** — one call after `SwaggerModule.createDocument(...)` replaces the entire `cleanupOpenApiDoc` ritual.
|
|
29
30
|
- **`ZodNestModule.forRoot`** — global pipe + interceptor + logging configuration in one place; optional (everything works standalone).
|
|
@@ -149,6 +150,37 @@ The class returned by `createZodDto(schema)` carries `schema`, `id`, `io: 'input
|
|
|
149
150
|
|
|
150
151
|
See [`docs/dto.md`](docs/dto.md) for the full surface.
|
|
151
152
|
|
|
153
|
+
### Schemas that don't fit a class
|
|
154
|
+
|
|
155
|
+
A schema whose `z.infer<>` is a TypeScript union — `z.union`, `z.discriminatedUnion`, or `z.intersection(obj, union)` — can't be used as a class base because TS rejects unions as constructor return types (TS2509: *Base constructor return type ... is not an object type*). For these, skip `createZodDto` and pair the raw schema with parameter-level decorators that handle OpenAPI emission directly:
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
const IntersectionWithUnion = z
|
|
159
|
+
.intersection(
|
|
160
|
+
z.union([z.object({ a: z.string() }), z.object({ b: z.string() })]),
|
|
161
|
+
z.union([z.object({ c: z.string() }), z.object({ d: z.string() })]),
|
|
162
|
+
)
|
|
163
|
+
.meta({ id: 'IntersectionWithUnion' });
|
|
164
|
+
|
|
165
|
+
type IntersectionWithUnionType = z.infer<typeof IntersectionWithUnion>;
|
|
166
|
+
|
|
167
|
+
@Controller()
|
|
168
|
+
export class Controller {
|
|
169
|
+
@Post()
|
|
170
|
+
@ZodBody(IntersectionWithUnion)
|
|
171
|
+
async post(
|
|
172
|
+
@Body(new ZodValidationPipe(IntersectionWithUnion))
|
|
173
|
+
body: IntersectionWithUnionType,
|
|
174
|
+
): Promise<IntersectionWithUnionType> {
|
|
175
|
+
return body;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
The decorator set: `@ZodBody`, `@ZodQuery`, `@ZodHeaders`, `@ZodCookies`. All are method-level. They register the schema in the registry (so it lands in `components.schemas` when named) and apply the matching OpenAPI parameter metadata — `@ZodBody` writes the request body's `$ref`/inline schema; `@ZodQuery` / `@ZodHeaders` / `@ZodCookies` expand a `z.object` into one OpenAPI parameter per property. Validation stays manual via `@Body(new ZodValidationPipe(schema))` so the handler arg keeps its precise `z.infer<>` type.
|
|
181
|
+
|
|
182
|
+
See [`docs/recipes/intersection-with-union.md`](docs/recipes/intersection-with-union.md) for the full pattern.
|
|
183
|
+
|
|
152
184
|
### I/O suffix rules
|
|
153
185
|
|
|
154
186
|
If a schema's input and output JSON Schemas are byte-equal (the common case), the OpenAPI doc emits a single `components.schemas[Id]`. If they differ (e.g. a `transform`, a `pipe`, an `.optional().default(x)` field), the doc emits two: `Id` for input, `IdOutput` for output. Response refs are rewritten to `IdOutput` automatically.
|
|
@@ -424,6 +456,9 @@ A compact, link-out index. Type signatures and detailed semantics live in the co
|
|
|
424
456
|
**Response** — [`docs/responses.md`](docs/responses.md)
|
|
425
457
|
- `@ZodResponse({ status?, type, description?, passthroughOnError? })`, `ZodSerializerInterceptor`, `ZodSerializationException`, `defaultStatusFor`, `resolveEffectiveStatus`, `ResponseStatusInput`, `ResponseStatusWildcard`, `ResponseVariant`, `ZOD_RESPONSES_METADATA_KEY`
|
|
426
458
|
|
|
459
|
+
**Parameter decorators for raw schemas** — [`docs/recipes/intersection-with-union.md`](docs/recipes/intersection-with-union.md)
|
|
460
|
+
- `@ZodBody(schema, options?)`, `@ZodQuery(schema, options?)`, `@ZodHeaders(schema, options?)`, `@ZodCookies(schema, options?)`, `ZodBodyOptions`, `ZodQueryOptions`, `ZodHeadersOptions`, `ZodCookiesOptions`
|
|
461
|
+
|
|
427
462
|
**Document** — [`docs/swagger-integration.md`](docs/swagger-integration.md)
|
|
428
463
|
- `applyZodNest(rawDoc, options)`, `ApplyZodNestOptions`, `ZodNestDocumentError`
|
|
429
464
|
|
package/dist/index.d.mts
CHANGED
|
@@ -487,6 +487,92 @@ interface ZodResponseOptions {
|
|
|
487
487
|
*/
|
|
488
488
|
declare const ZodResponse: (opts: ZodResponseOptions) => MethodDecorator;
|
|
489
489
|
|
|
490
|
+
interface ZodBodyOptions {
|
|
491
|
+
/** Forces this id, overriding any `.meta({ id })` already on the schema. */
|
|
492
|
+
readonly id?: string;
|
|
493
|
+
/** Registry to register into. Defaults to `defaultRegistry`. */
|
|
494
|
+
readonly registry?: ZodNestRegistry;
|
|
495
|
+
/** OpenAPI `description` for the request body. */
|
|
496
|
+
readonly description?: string;
|
|
497
|
+
/** Whether the body is required. Defaults to `true`. */
|
|
498
|
+
readonly required?: boolean;
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* Method-level decorator that wires the OpenAPI `requestBody` for a handler
|
|
502
|
+
* whose body schema doesn't fit a `createZodDto` class — typically a
|
|
503
|
+
* `z.intersection` that contains a `z.union`, a `z.discriminatedUnion`, or
|
|
504
|
+
* any schema whose `z.infer<>` is a TypeScript union (which TS refuses as a
|
|
505
|
+
* class base with TS2509).
|
|
506
|
+
*
|
|
507
|
+
* Pair with `@Body(new ZodValidationPipe(schema))` at the parameter to keep
|
|
508
|
+
* the handler arg precisely typed as `z.infer<typeof schema>`:
|
|
509
|
+
*
|
|
510
|
+
* ```ts
|
|
511
|
+
* @Post()
|
|
512
|
+
* @ZodBody(IntersectionWithUnion)
|
|
513
|
+
* async post(
|
|
514
|
+
* @Body(new ZodValidationPipe(IntersectionWithUnion))
|
|
515
|
+
* body: z.infer<typeof IntersectionWithUnion>,
|
|
516
|
+
* ) {}
|
|
517
|
+
* ```
|
|
518
|
+
*
|
|
519
|
+
* The schema is registered in the registry when it has an id (via
|
|
520
|
+
* `.meta({ id })` or `options.id`) so its body is emitted into
|
|
521
|
+
* `components.schemas`. Anonymous schemas are inlined into the operation.
|
|
522
|
+
*/
|
|
523
|
+
declare const ZodBody: (schema: z.ZodType, options?: ZodBodyOptions) => MethodDecorator;
|
|
524
|
+
|
|
525
|
+
interface ZodQueryOptions {
|
|
526
|
+
/** Forces this id on the root schema, overriding any `.meta({ id })`. */
|
|
527
|
+
readonly id?: string;
|
|
528
|
+
/** Registry to register into. Defaults to `defaultRegistry`. */
|
|
529
|
+
readonly registry?: ZodNestRegistry;
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* Method-level decorator that expands a `z.object` schema into one
|
|
533
|
+
* `@ApiQuery` entry per property. Each property's schema is independently
|
|
534
|
+
* resolved — named properties (`.meta({ id })`) become `$ref`s,
|
|
535
|
+
* anonymous properties inline.
|
|
536
|
+
*
|
|
537
|
+
* The user remains responsible for binding the actual query values to the
|
|
538
|
+
* handler, typically via `@Query(new ZodValidationPipe(schema)) q: z.infer<typeof schema>`.
|
|
539
|
+
*/
|
|
540
|
+
declare const ZodQuery: (schema: z.ZodType, options?: ZodQueryOptions) => MethodDecorator;
|
|
541
|
+
|
|
542
|
+
interface ZodHeadersOptions {
|
|
543
|
+
/** Forces this id on the root schema, overriding any `.meta({ id })`. */
|
|
544
|
+
readonly id?: string;
|
|
545
|
+
/** Registry to register into. Defaults to `defaultRegistry`. */
|
|
546
|
+
readonly registry?: ZodNestRegistry;
|
|
547
|
+
}
|
|
548
|
+
/**
|
|
549
|
+
* Method-level decorator that expands a `z.object` schema into one
|
|
550
|
+
* header-parameter entry per property. Required-ness derives from each
|
|
551
|
+
* property's Zod optionality.
|
|
552
|
+
*
|
|
553
|
+
* Writes directly to the `swagger/apiParameters` metadata key the explorer
|
|
554
|
+
* reads. We bypass `@ApiHeader` because it injects a default `type: 'string'`
|
|
555
|
+
* onto the schema (`api-header.decorator.js`), which pollutes our `$ref`
|
|
556
|
+
* objects and inline JSON Schemas. The raw-metadata path keeps our schema
|
|
557
|
+
* bodies intact.
|
|
558
|
+
*/
|
|
559
|
+
declare const ZodHeaders: (schema: z.ZodType, options?: ZodHeadersOptions) => MethodDecorator;
|
|
560
|
+
|
|
561
|
+
interface ZodCookiesOptions {
|
|
562
|
+
/** Forces this id on the root schema, overriding any `.meta({ id })`. */
|
|
563
|
+
readonly id?: string;
|
|
564
|
+
/** Registry to register into. Defaults to `defaultRegistry`. */
|
|
565
|
+
readonly registry?: ZodNestRegistry;
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* Method-level decorator that expands a `z.object` schema into one
|
|
569
|
+
* cookie-parameter entry per property in the OpenAPI operation. There is no
|
|
570
|
+
* `@ApiCookie` decorator in `@nestjs/swagger`, so we write directly to the
|
|
571
|
+
* `swagger/apiParameters` metadata key the explorer reads — the same key
|
|
572
|
+
* `@ApiQuery` / `@ApiParam` / `@ApiHeader` populate via their helper.
|
|
573
|
+
*/
|
|
574
|
+
declare const ZodCookies: (schema: z.ZodType, options?: ZodCookiesOptions) => MethodDecorator;
|
|
575
|
+
|
|
490
576
|
declare class ZodSerializerInterceptor implements NestInterceptor {
|
|
491
577
|
private readonly reflector;
|
|
492
578
|
private readonly logOutputFailure;
|
|
@@ -619,4 +705,4 @@ declare class ZodNestDocumentError extends ZodNestError {
|
|
|
619
705
|
constructor(code: ZodNestDocumentErrorCode, message: string, details?: Record<string, unknown>);
|
|
620
706
|
}
|
|
621
707
|
|
|
622
|
-
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 OverrideJSONSchemaArg, type RegisterSchemaOptions, type ResponseStatusInput, type ResponseStatusWildcard, type ResponseVariant, type ResponseVariantKind, 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, overrideJSONSchema, registerSchema, resolveEffectiveStatus, toOpenApi };
|
|
708
|
+
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 OverrideJSONSchemaArg, type RegisterSchemaOptions, type ResponseStatusInput, type ResponseStatusWildcard, type ResponseVariant, type ResponseVariantKind, 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, ZodBody, type ZodBodyOptions, ZodCookies, type ZodCookiesOptions, type ZodDto, type ZodDtoMarker, ZodHeaders, type ZodHeadersOptions, ZodNestDocumentError, type ZodNestDocumentErrorCode, ZodNestError, ZodNestModule, type ZodNestModuleOptions, type ZodNestRegistry, ZodNestUnrepresentableError, ZodQuery, type ZodQueryOptions, 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, overrideJSONSchema, registerSchema, resolveEffectiveStatus, toOpenApi };
|
package/dist/index.d.ts
CHANGED
|
@@ -487,6 +487,92 @@ interface ZodResponseOptions {
|
|
|
487
487
|
*/
|
|
488
488
|
declare const ZodResponse: (opts: ZodResponseOptions) => MethodDecorator;
|
|
489
489
|
|
|
490
|
+
interface ZodBodyOptions {
|
|
491
|
+
/** Forces this id, overriding any `.meta({ id })` already on the schema. */
|
|
492
|
+
readonly id?: string;
|
|
493
|
+
/** Registry to register into. Defaults to `defaultRegistry`. */
|
|
494
|
+
readonly registry?: ZodNestRegistry;
|
|
495
|
+
/** OpenAPI `description` for the request body. */
|
|
496
|
+
readonly description?: string;
|
|
497
|
+
/** Whether the body is required. Defaults to `true`. */
|
|
498
|
+
readonly required?: boolean;
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* Method-level decorator that wires the OpenAPI `requestBody` for a handler
|
|
502
|
+
* whose body schema doesn't fit a `createZodDto` class — typically a
|
|
503
|
+
* `z.intersection` that contains a `z.union`, a `z.discriminatedUnion`, or
|
|
504
|
+
* any schema whose `z.infer<>` is a TypeScript union (which TS refuses as a
|
|
505
|
+
* class base with TS2509).
|
|
506
|
+
*
|
|
507
|
+
* Pair with `@Body(new ZodValidationPipe(schema))` at the parameter to keep
|
|
508
|
+
* the handler arg precisely typed as `z.infer<typeof schema>`:
|
|
509
|
+
*
|
|
510
|
+
* ```ts
|
|
511
|
+
* @Post()
|
|
512
|
+
* @ZodBody(IntersectionWithUnion)
|
|
513
|
+
* async post(
|
|
514
|
+
* @Body(new ZodValidationPipe(IntersectionWithUnion))
|
|
515
|
+
* body: z.infer<typeof IntersectionWithUnion>,
|
|
516
|
+
* ) {}
|
|
517
|
+
* ```
|
|
518
|
+
*
|
|
519
|
+
* The schema is registered in the registry when it has an id (via
|
|
520
|
+
* `.meta({ id })` or `options.id`) so its body is emitted into
|
|
521
|
+
* `components.schemas`. Anonymous schemas are inlined into the operation.
|
|
522
|
+
*/
|
|
523
|
+
declare const ZodBody: (schema: z.ZodType, options?: ZodBodyOptions) => MethodDecorator;
|
|
524
|
+
|
|
525
|
+
interface ZodQueryOptions {
|
|
526
|
+
/** Forces this id on the root schema, overriding any `.meta({ id })`. */
|
|
527
|
+
readonly id?: string;
|
|
528
|
+
/** Registry to register into. Defaults to `defaultRegistry`. */
|
|
529
|
+
readonly registry?: ZodNestRegistry;
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* Method-level decorator that expands a `z.object` schema into one
|
|
533
|
+
* `@ApiQuery` entry per property. Each property's schema is independently
|
|
534
|
+
* resolved — named properties (`.meta({ id })`) become `$ref`s,
|
|
535
|
+
* anonymous properties inline.
|
|
536
|
+
*
|
|
537
|
+
* The user remains responsible for binding the actual query values to the
|
|
538
|
+
* handler, typically via `@Query(new ZodValidationPipe(schema)) q: z.infer<typeof schema>`.
|
|
539
|
+
*/
|
|
540
|
+
declare const ZodQuery: (schema: z.ZodType, options?: ZodQueryOptions) => MethodDecorator;
|
|
541
|
+
|
|
542
|
+
interface ZodHeadersOptions {
|
|
543
|
+
/** Forces this id on the root schema, overriding any `.meta({ id })`. */
|
|
544
|
+
readonly id?: string;
|
|
545
|
+
/** Registry to register into. Defaults to `defaultRegistry`. */
|
|
546
|
+
readonly registry?: ZodNestRegistry;
|
|
547
|
+
}
|
|
548
|
+
/**
|
|
549
|
+
* Method-level decorator that expands a `z.object` schema into one
|
|
550
|
+
* header-parameter entry per property. Required-ness derives from each
|
|
551
|
+
* property's Zod optionality.
|
|
552
|
+
*
|
|
553
|
+
* Writes directly to the `swagger/apiParameters` metadata key the explorer
|
|
554
|
+
* reads. We bypass `@ApiHeader` because it injects a default `type: 'string'`
|
|
555
|
+
* onto the schema (`api-header.decorator.js`), which pollutes our `$ref`
|
|
556
|
+
* objects and inline JSON Schemas. The raw-metadata path keeps our schema
|
|
557
|
+
* bodies intact.
|
|
558
|
+
*/
|
|
559
|
+
declare const ZodHeaders: (schema: z.ZodType, options?: ZodHeadersOptions) => MethodDecorator;
|
|
560
|
+
|
|
561
|
+
interface ZodCookiesOptions {
|
|
562
|
+
/** Forces this id on the root schema, overriding any `.meta({ id })`. */
|
|
563
|
+
readonly id?: string;
|
|
564
|
+
/** Registry to register into. Defaults to `defaultRegistry`. */
|
|
565
|
+
readonly registry?: ZodNestRegistry;
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* Method-level decorator that expands a `z.object` schema into one
|
|
569
|
+
* cookie-parameter entry per property in the OpenAPI operation. There is no
|
|
570
|
+
* `@ApiCookie` decorator in `@nestjs/swagger`, so we write directly to the
|
|
571
|
+
* `swagger/apiParameters` metadata key the explorer reads — the same key
|
|
572
|
+
* `@ApiQuery` / `@ApiParam` / `@ApiHeader` populate via their helper.
|
|
573
|
+
*/
|
|
574
|
+
declare const ZodCookies: (schema: z.ZodType, options?: ZodCookiesOptions) => MethodDecorator;
|
|
575
|
+
|
|
490
576
|
declare class ZodSerializerInterceptor implements NestInterceptor {
|
|
491
577
|
private readonly reflector;
|
|
492
578
|
private readonly logOutputFailure;
|
|
@@ -619,4 +705,4 @@ declare class ZodNestDocumentError extends ZodNestError {
|
|
|
619
705
|
constructor(code: ZodNestDocumentErrorCode, message: string, details?: Record<string, unknown>);
|
|
620
706
|
}
|
|
621
707
|
|
|
622
|
-
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 OverrideJSONSchemaArg, type RegisterSchemaOptions, type ResponseStatusInput, type ResponseStatusWildcard, type ResponseVariant, type ResponseVariantKind, 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, overrideJSONSchema, registerSchema, resolveEffectiveStatus, toOpenApi };
|
|
708
|
+
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 OverrideJSONSchemaArg, type RegisterSchemaOptions, type ResponseStatusInput, type ResponseStatusWildcard, type ResponseVariant, type ResponseVariantKind, 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, ZodBody, type ZodBodyOptions, ZodCookies, type ZodCookiesOptions, type ZodDto, type ZodDtoMarker, ZodHeaders, type ZodHeadersOptions, ZodNestDocumentError, type ZodNestDocumentErrorCode, ZodNestError, ZodNestModule, type ZodNestModuleOptions, type ZodNestRegistry, ZodNestUnrepresentableError, ZodQuery, type ZodQueryOptions, 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, overrideJSONSchema, registerSchema, resolveEffectiveStatus, toOpenApi };
|
package/dist/index.js
CHANGED
|
@@ -119,7 +119,7 @@ var discoverDependents = /* @__PURE__ */ __name((schema) => {
|
|
|
119
119
|
}
|
|
120
120
|
visited.add(current);
|
|
121
121
|
for (const child of collectChildren(current)) {
|
|
122
|
-
if (visited.has(child)) {
|
|
122
|
+
if (child === void 0 || visited.has(child)) {
|
|
123
123
|
continue;
|
|
124
124
|
}
|
|
125
125
|
const id = readId(child);
|
|
@@ -1129,6 +1129,144 @@ var ZodResponse = /* @__PURE__ */ __name((opts) => {
|
|
|
1129
1129
|
});
|
|
1130
1130
|
};
|
|
1131
1131
|
}, "ZodResponse");
|
|
1132
|
+
|
|
1133
|
+
// src/decorators/internal/zod-schema-ref.ts
|
|
1134
|
+
var resolveSchemaRef = /* @__PURE__ */ __name((schema, options) => {
|
|
1135
|
+
const registry = options?.registry ?? defaultRegistry;
|
|
1136
|
+
const id = registerSchema(schema, registry, {
|
|
1137
|
+
id: options?.id
|
|
1138
|
+
});
|
|
1139
|
+
if (id !== void 0) {
|
|
1140
|
+
return {
|
|
1141
|
+
kind: "ref",
|
|
1142
|
+
ref: {
|
|
1143
|
+
$ref: `#/components/schemas/${id}`
|
|
1144
|
+
}
|
|
1145
|
+
};
|
|
1146
|
+
}
|
|
1147
|
+
for (const [child, childId] of discoverDependents(schema)) {
|
|
1148
|
+
registry.register(child, childId);
|
|
1149
|
+
}
|
|
1150
|
+
const { schema: body } = toOpenApi(schema, {
|
|
1151
|
+
io: "input",
|
|
1152
|
+
registry
|
|
1153
|
+
});
|
|
1154
|
+
return {
|
|
1155
|
+
kind: "inline",
|
|
1156
|
+
schema: body
|
|
1157
|
+
};
|
|
1158
|
+
}, "resolveSchemaRef");
|
|
1159
|
+
|
|
1160
|
+
// src/decorators/zod-body.decorator.ts
|
|
1161
|
+
var ZodBody = /* @__PURE__ */ __name((schema, options) => {
|
|
1162
|
+
const resolution = resolveSchemaRef(schema, {
|
|
1163
|
+
id: options?.id,
|
|
1164
|
+
registry: options?.registry
|
|
1165
|
+
});
|
|
1166
|
+
const apiBodySchema = resolution.kind === "ref" ? resolution.ref : resolution.schema;
|
|
1167
|
+
return swagger.ApiBody({
|
|
1168
|
+
schema: apiBodySchema,
|
|
1169
|
+
...options?.description !== void 0 ? {
|
|
1170
|
+
description: options.description
|
|
1171
|
+
} : {},
|
|
1172
|
+
required: options?.required ?? true
|
|
1173
|
+
});
|
|
1174
|
+
}, "ZodBody");
|
|
1175
|
+
|
|
1176
|
+
// src/decorators/internal/zod-param-expand.ts
|
|
1177
|
+
var isZodObject = /* @__PURE__ */ __name((schema) => schema._zod.def.type === "object", "isZodObject");
|
|
1178
|
+
var expandObjectSchema = /* @__PURE__ */ __name((schema, options) => {
|
|
1179
|
+
if (!isZodObject(schema)) {
|
|
1180
|
+
throw new ZodNestError(`${options.decoratorName} requires a \`z.object({...})\` schema (got \`${schema._zod.def.type}\`). Each property of the object becomes one OpenAPI parameter. For non-object body shapes (intersections, unions, primitives), use \`@ZodBody\` instead.`);
|
|
1181
|
+
}
|
|
1182
|
+
const registry = options.registry ?? defaultRegistry;
|
|
1183
|
+
registerSchema(schema, registry, {
|
|
1184
|
+
id: options.id
|
|
1185
|
+
});
|
|
1186
|
+
const result = [];
|
|
1187
|
+
for (const [name, propSchema] of Object.entries(schema.shape)) {
|
|
1188
|
+
const resolution = resolveSchemaRef(propSchema, {
|
|
1189
|
+
registry
|
|
1190
|
+
});
|
|
1191
|
+
const required = options.forceRequired === true || !isOptionalProp(propSchema);
|
|
1192
|
+
result.push({
|
|
1193
|
+
name,
|
|
1194
|
+
required,
|
|
1195
|
+
resolution
|
|
1196
|
+
});
|
|
1197
|
+
}
|
|
1198
|
+
return result;
|
|
1199
|
+
}, "expandObjectSchema");
|
|
1200
|
+
var paramSchemaBody = /* @__PURE__ */ __name((resolution) => resolution.kind === "ref" ? resolution.ref : resolution.schema, "paramSchemaBody");
|
|
1201
|
+
|
|
1202
|
+
// src/decorators/zod-query.decorator.ts
|
|
1203
|
+
var ZodQuery = /* @__PURE__ */ __name((schema, options) => {
|
|
1204
|
+
const expanded = expandObjectSchema(schema, {
|
|
1205
|
+
id: options?.id,
|
|
1206
|
+
registry: options?.registry,
|
|
1207
|
+
decoratorName: "@ZodQuery"
|
|
1208
|
+
});
|
|
1209
|
+
return common.applyDecorators(...expanded.map(({ name, required, resolution }) => swagger.ApiQuery({
|
|
1210
|
+
name,
|
|
1211
|
+
schema: paramSchemaBody(resolution),
|
|
1212
|
+
required
|
|
1213
|
+
})));
|
|
1214
|
+
}, "ZodQuery");
|
|
1215
|
+
|
|
1216
|
+
// src/decorators/internal/constants.ts
|
|
1217
|
+
var API_PARAMETERS_KEY = "swagger/apiParameters";
|
|
1218
|
+
|
|
1219
|
+
// src/decorators/zod-headers.decorator.ts
|
|
1220
|
+
var ZodHeaders = /* @__PURE__ */ __name((schema, options) => {
|
|
1221
|
+
const expanded = expandObjectSchema(schema, {
|
|
1222
|
+
id: options?.id,
|
|
1223
|
+
registry: options?.registry,
|
|
1224
|
+
decoratorName: "@ZodHeaders"
|
|
1225
|
+
});
|
|
1226
|
+
const newEntries = expanded.map(({ name, required, resolution }) => ({
|
|
1227
|
+
name,
|
|
1228
|
+
in: "header",
|
|
1229
|
+
required,
|
|
1230
|
+
schema: paramSchemaBody(resolution)
|
|
1231
|
+
}));
|
|
1232
|
+
return (_target, _propertyKey, descriptor) => {
|
|
1233
|
+
const handler = descriptor.value;
|
|
1234
|
+
if (typeof handler !== "function") {
|
|
1235
|
+
throw new TypeError("[zod-nest] @ZodHeaders can only be applied to methods.");
|
|
1236
|
+
}
|
|
1237
|
+
const existing = Reflect.getMetadata(API_PARAMETERS_KEY, handler) ?? [];
|
|
1238
|
+
Reflect.defineMetadata(API_PARAMETERS_KEY, [
|
|
1239
|
+
...existing,
|
|
1240
|
+
...newEntries
|
|
1241
|
+
], handler);
|
|
1242
|
+
};
|
|
1243
|
+
}, "ZodHeaders");
|
|
1244
|
+
|
|
1245
|
+
// src/decorators/zod-cookies.decorator.ts
|
|
1246
|
+
var ZodCookies = /* @__PURE__ */ __name((schema, options) => {
|
|
1247
|
+
const expanded = expandObjectSchema(schema, {
|
|
1248
|
+
id: options?.id,
|
|
1249
|
+
registry: options?.registry,
|
|
1250
|
+
decoratorName: "@ZodCookies"
|
|
1251
|
+
});
|
|
1252
|
+
const newEntries = expanded.map(({ name, required, resolution }) => ({
|
|
1253
|
+
name,
|
|
1254
|
+
in: "cookie",
|
|
1255
|
+
required,
|
|
1256
|
+
schema: paramSchemaBody(resolution)
|
|
1257
|
+
}));
|
|
1258
|
+
return (_target, _propertyKey, descriptor) => {
|
|
1259
|
+
const handler = descriptor.value;
|
|
1260
|
+
if (typeof handler !== "function") {
|
|
1261
|
+
throw new TypeError("[zod-nest] @ZodCookies can only be applied to methods.");
|
|
1262
|
+
}
|
|
1263
|
+
const existing = Reflect.getMetadata(API_PARAMETERS_KEY, handler) ?? [];
|
|
1264
|
+
Reflect.defineMetadata(API_PARAMETERS_KEY, [
|
|
1265
|
+
...existing,
|
|
1266
|
+
...newEntries
|
|
1267
|
+
], handler);
|
|
1268
|
+
};
|
|
1269
|
+
}, "ZodCookies");
|
|
1132
1270
|
function _ts_decorate2(decorators, target, key, desc) {
|
|
1133
1271
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1134
1272
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -1322,9 +1460,10 @@ var forEachOperation = /* @__PURE__ */ __name((doc, fn) => {
|
|
|
1322
1460
|
|
|
1323
1461
|
// src/document/collect-usage.ts
|
|
1324
1462
|
var isPlainRecord2 = /* @__PURE__ */ __name((value) => value !== null && typeof value === "object" && !Array.isArray(value), "isPlainRecord");
|
|
1325
|
-
var collectUsage = /* @__PURE__ */ __name((doc, app) => {
|
|
1463
|
+
var collectUsage = /* @__PURE__ */ __name((doc, app, registry) => {
|
|
1326
1464
|
const classToDtoId = buildClassToDtoIdMap(doc);
|
|
1327
|
-
const
|
|
1465
|
+
const knownIds = new Set(registry.ids());
|
|
1466
|
+
const inputExposedIds = collectInputExposedIds(doc, classToDtoId, knownIds);
|
|
1328
1467
|
const outputExposedIds = collectOutputExposedIds(app);
|
|
1329
1468
|
return {
|
|
1330
1469
|
inputExposedIds,
|
|
@@ -1359,7 +1498,7 @@ var readMarker = /* @__PURE__ */ __name((schema) => {
|
|
|
1359
1498
|
dtoId: marker.dtoId
|
|
1360
1499
|
};
|
|
1361
1500
|
}, "readMarker");
|
|
1362
|
-
var collectInputExposedIds = /* @__PURE__ */ __name((doc, classToDtoId) => {
|
|
1501
|
+
var collectInputExposedIds = /* @__PURE__ */ __name((doc, classToDtoId, knownIds) => {
|
|
1363
1502
|
const ids = /* @__PURE__ */ new Set();
|
|
1364
1503
|
const paths = doc.paths ?? {};
|
|
1365
1504
|
for (const pathItem of Object.values(paths)) {
|
|
@@ -1367,7 +1506,7 @@ var collectInputExposedIds = /* @__PURE__ */ __name((doc, classToDtoId) => {
|
|
|
1367
1506
|
continue;
|
|
1368
1507
|
}
|
|
1369
1508
|
for (const operation of operationsOf(pathItem)) {
|
|
1370
|
-
collectRefsFromOperation(operation, classToDtoId, ids);
|
|
1509
|
+
collectRefsFromOperation(operation, classToDtoId, knownIds, ids);
|
|
1371
1510
|
}
|
|
1372
1511
|
}
|
|
1373
1512
|
return ids;
|
|
@@ -1382,9 +1521,9 @@ var operationsOf = /* @__PURE__ */ __name((pathItem) => {
|
|
|
1382
1521
|
}
|
|
1383
1522
|
return out;
|
|
1384
1523
|
}, "operationsOf");
|
|
1385
|
-
var collectRefsFromOperation = /* @__PURE__ */ __name((operation, classToDtoId, ids) => {
|
|
1524
|
+
var collectRefsFromOperation = /* @__PURE__ */ __name((operation, classToDtoId, knownIds, ids) => {
|
|
1386
1525
|
if (isPlainRecord2(operation.requestBody)) {
|
|
1387
|
-
collectRefsFromContent(operation.requestBody.content, classToDtoId, ids);
|
|
1526
|
+
collectRefsFromContent(operation.requestBody.content, classToDtoId, knownIds, ids);
|
|
1388
1527
|
}
|
|
1389
1528
|
const parameters = operation.parameters;
|
|
1390
1529
|
if (Array.isArray(parameters)) {
|
|
@@ -1392,7 +1531,7 @@ var collectRefsFromOperation = /* @__PURE__ */ __name((operation, classToDtoId,
|
|
|
1392
1531
|
if (!isPlainRecord2(param)) {
|
|
1393
1532
|
continue;
|
|
1394
1533
|
}
|
|
1395
|
-
collectRefFromSchema(param.schema, classToDtoId, ids);
|
|
1534
|
+
collectRefFromSchema(param.schema, classToDtoId, knownIds, ids);
|
|
1396
1535
|
collectIdFromMarkerParam(param, ids);
|
|
1397
1536
|
}
|
|
1398
1537
|
}
|
|
@@ -1407,7 +1546,7 @@ var collectIdFromMarkerParam = /* @__PURE__ */ __name((param, ids) => {
|
|
|
1407
1546
|
}
|
|
1408
1547
|
ids.add(dtoId);
|
|
1409
1548
|
}, "collectIdFromMarkerParam");
|
|
1410
|
-
var collectRefsFromContent = /* @__PURE__ */ __name((content, classToDtoId, ids) => {
|
|
1549
|
+
var collectRefsFromContent = /* @__PURE__ */ __name((content, classToDtoId, knownIds, ids) => {
|
|
1411
1550
|
if (!isPlainRecord2(content)) {
|
|
1412
1551
|
return;
|
|
1413
1552
|
}
|
|
@@ -1415,10 +1554,10 @@ var collectRefsFromContent = /* @__PURE__ */ __name((content, classToDtoId, ids)
|
|
|
1415
1554
|
if (!isPlainRecord2(mediaType)) {
|
|
1416
1555
|
continue;
|
|
1417
1556
|
}
|
|
1418
|
-
collectRefFromSchema(mediaType.schema, classToDtoId, ids);
|
|
1557
|
+
collectRefFromSchema(mediaType.schema, classToDtoId, knownIds, ids);
|
|
1419
1558
|
}
|
|
1420
1559
|
}, "collectRefsFromContent");
|
|
1421
|
-
var collectRefFromSchema = /* @__PURE__ */ __name((schema, classToDtoId, ids) => {
|
|
1560
|
+
var collectRefFromSchema = /* @__PURE__ */ __name((schema, classToDtoId, knownIds, ids) => {
|
|
1422
1561
|
if (!isPlainRecord2(schema)) {
|
|
1423
1562
|
return;
|
|
1424
1563
|
}
|
|
@@ -1427,9 +1566,13 @@ var collectRefFromSchema = /* @__PURE__ */ __name((schema, classToDtoId, ids) =>
|
|
|
1427
1566
|
return;
|
|
1428
1567
|
}
|
|
1429
1568
|
const className = ref.slice(COMPONENTS_SCHEMAS_PREFIX.length);
|
|
1430
|
-
const
|
|
1431
|
-
if (
|
|
1432
|
-
ids.add(
|
|
1569
|
+
const renamed = classToDtoId.get(className);
|
|
1570
|
+
if (renamed !== void 0) {
|
|
1571
|
+
ids.add(renamed);
|
|
1572
|
+
return;
|
|
1573
|
+
}
|
|
1574
|
+
if (knownIds.has(className)) {
|
|
1575
|
+
ids.add(className);
|
|
1433
1576
|
}
|
|
1434
1577
|
}, "collectRefFromSchema");
|
|
1435
1578
|
var collectOutputExposedIds = /* @__PURE__ */ __name((app) => {
|
|
@@ -1913,7 +2056,7 @@ var stripMarkerFromSchema = /* @__PURE__ */ __name((schema) => {
|
|
|
1913
2056
|
var OPENAPI_VERSION = "3.1.0";
|
|
1914
2057
|
var applyZodNest = /* @__PURE__ */ __name((doc, opts) => {
|
|
1915
2058
|
const registry = opts.registry ?? defaultRegistry;
|
|
1916
|
-
const collected = collectUsage(doc, opts.app);
|
|
2059
|
+
const collected = collectUsage(doc, opts.app, registry);
|
|
1917
2060
|
const { inputSchemas, outputSchemas } = bulkEmit({
|
|
1918
2061
|
registry,
|
|
1919
2062
|
override: opts.override,
|
|
@@ -1955,10 +2098,14 @@ exports.ZOD_NEST_ERROR_DUPLICATE_ID = ZOD_NEST_ERROR_DUPLICATE_ID;
|
|
|
1955
2098
|
exports.ZOD_NEST_ERROR_EXTENSION = ZOD_NEST_ERROR_EXTENSION;
|
|
1956
2099
|
exports.ZOD_NEST_OPTIONS = ZOD_NEST_OPTIONS;
|
|
1957
2100
|
exports.ZOD_RESPONSES_METADATA_KEY = ZOD_RESPONSES_METADATA_KEY;
|
|
2101
|
+
exports.ZodBody = ZodBody;
|
|
2102
|
+
exports.ZodCookies = ZodCookies;
|
|
2103
|
+
exports.ZodHeaders = ZodHeaders;
|
|
1958
2104
|
exports.ZodNestDocumentError = ZodNestDocumentError;
|
|
1959
2105
|
exports.ZodNestError = ZodNestError;
|
|
1960
2106
|
exports.ZodNestModule = ZodNestModule;
|
|
1961
2107
|
exports.ZodNestUnrepresentableError = ZodNestUnrepresentableError;
|
|
2108
|
+
exports.ZodQuery = ZodQuery;
|
|
1962
2109
|
exports.ZodResponse = ZodResponse;
|
|
1963
2110
|
exports.ZodSerializationException = ZodSerializationException;
|
|
1964
2111
|
exports.ZodValidationException = ZodValidationException;
|