zod-nest 0.6.0 → 0.8.1
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 +474 -0
- package/dist/index.d.mts +62 -34
- package/dist/index.d.ts +62 -34
- package/dist/index.js +166 -64
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +165 -65
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -2
package/README.md
ADDED
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
# zod-nest
|
|
2
|
+
|
|
3
|
+
> Modern **Zod v4** ↔ **NestJS** ↔ **OpenAPI 3.1** integration.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/zod-nest)
|
|
6
|
+
[](https://github.com/rodrigowbazevedo/zod-nest/actions/workflows/ci.yml)
|
|
7
|
+
[](https://codecov.io/gh/rodrigowbazevedo/zod-nest)
|
|
8
|
+
[](https://opensource.org/licenses/MIT)
|
|
9
|
+
|
|
10
|
+
Define your DTOs once with Zod, get validated request bodies, validated response bodies, and a correct OpenAPI 3.1 document — without the dual-codepath, post-process, or `@ts-ignore` baggage that comes with bolting Zod onto class-validator-shaped tooling.
|
|
11
|
+
|
|
12
|
+
## Why this exists
|
|
13
|
+
|
|
14
|
+
`zod-nest` is a fresh take on the idea pioneered by [`nestjs-zod`](https://github.com/BenLorantfy/nestjs-zod) — many thanks to that project and its maintainers; this library would not exist without it.
|
|
15
|
+
|
|
16
|
+
The difference is that `zod-nest` is Zod v4 only and OpenAPI 3.1 only. It drops `class-validator` / `class-transformer` coexistence, drops Zod v3 codepaths, drops `cleanupOpenApiDoc` as a separate post-process, and drops the 20-odd `@ts-ignore`s that the dual-version approach required. The result is a smaller surface, fully type-safe end to end, with extension points where you actually need them — exception factories, response status resolution, custom emission overrides.
|
|
17
|
+
|
|
18
|
+
For the long-form motivation, see [`docs/why-this-exists.md`](docs/why-this-exists.md).
|
|
19
|
+
|
|
20
|
+
## Features
|
|
21
|
+
|
|
22
|
+
- **Zod v4 only** — no v3 dual codepath, no compatibility shim.
|
|
23
|
+
- **OpenAPI 3.1 emission** — no post-processing, no spec downgrade, no leftover internal extension keys.
|
|
24
|
+
- **`createZodDto`** — class wrapper around a Zod schema with introspectable `schema`, `id`, `io`, and a sibling `Output` class when input/output diverge.
|
|
25
|
+
- **`ZodValidationPipe`** — auto-detects DTO from handler-arg metatype, accepts an explicit DTO or raw Zod schema, customizable exception factory.
|
|
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
|
+
- **`ZodSerializerInterceptor`** — response validation with a `passthroughOnError` escape hatch for untrusted upstream shapes.
|
|
28
|
+
- **`applyZodNest`** — one call after `SwaggerModule.createDocument(...)` replaces the entire `cleanupOpenApiDoc` ritual.
|
|
29
|
+
- **`ZodNestModule.forRoot`** — global pipe + interceptor + logging configuration in one place; optional (everything works standalone).
|
|
30
|
+
- **Validation logging** — opt-in, per-side (input/output), with case-insensitive deep-key redaction and oversize-value truncation.
|
|
31
|
+
- **Composition** — `extend` + `getLineage` emit OpenAPI `allOf` for derived schemas (`@experimental` — see [Composition](#composition-experimental)).
|
|
32
|
+
- **Custom registry support** — `createRegistry()` for explicit isolation, `defaultRegistry` for the common process-wide case.
|
|
33
|
+
- **Doc-build error reporting** — `ZodNestDocumentError` with codes `AMBIGUOUS_RENAME` and `DANGLING_REF` so registry mis-configurations fail in CI, not at runtime.
|
|
34
|
+
- **Strict-mode unrepresentable detection** — `ZodNestUnrepresentableError` surfaces bigint/date/transform constructs that JSON Schema can't represent (opt-out via `strict: false`).
|
|
35
|
+
- **Custom emission overrides** — `Override` callback for file uploads, opaque blobs, or anything else Zod doesn't model.
|
|
36
|
+
|
|
37
|
+
## Differences from `nestjs-zod`
|
|
38
|
+
|
|
39
|
+
A short list of behavioural differences you'll hit on day one. Full migration table is in [`MIGRATION.md`](MIGRATION.md).
|
|
40
|
+
|
|
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.
|
|
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
|
+
- **OpenAPI 3.1 only** — no `3.0` fallback. `$ref`s emit to the final location; `cleanupOpenApiDoc` is unnecessary.
|
|
45
|
+
- **Validation-failure logging out of the box** — `nestjs-zod` has none.
|
|
46
|
+
- **Customizable serialization exception** — both `ZodValidationPipe` and `ZodSerializerInterceptor` accept a factory. `nestjs-zod` only customized the input side.
|
|
47
|
+
- **DTO discriminator** — `Symbol.for('zod-nest.dto')` (cross-realm safe), not `MyDto.isZodDto`.
|
|
48
|
+
- **Codec mode in the schema** — express transforms via `z.pipe` / `z.transform`. No `{ codec: true }` flag.
|
|
49
|
+
- **Markers stripped** — the final document has zero `x-zod-nest-*` extensions. `nestjs-zod` left ~10 `x-nestjs_zod-*` keys behind.
|
|
50
|
+
|
|
51
|
+
## Non-goals (v0)
|
|
52
|
+
|
|
53
|
+
- **Zod v3 support** — Zod v4 only. Migrate first.
|
|
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
|
+
- **Hybrid DTO projects** — mixing `createZodDto` DTOs with plain `@ApiProperty` classes in the same controller is not tested.
|
|
57
|
+
- **Non-HTTP contexts** — WebSocket gateways, GraphQL resolvers, microservice handlers are out of scope.
|
|
58
|
+
|
|
59
|
+
## Quickstart
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npm i zod-nest zod @nestjs/swagger
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
// user.dto.ts
|
|
67
|
+
import { z } from 'zod';
|
|
68
|
+
import { createZodDto } from 'zod-nest';
|
|
69
|
+
|
|
70
|
+
const userSchema = z
|
|
71
|
+
.object({
|
|
72
|
+
id: z.string(),
|
|
73
|
+
email: z.email().transform((v) => v.toLowerCase()),
|
|
74
|
+
})
|
|
75
|
+
.meta({ id: 'User' });
|
|
76
|
+
|
|
77
|
+
export class UserDto extends createZodDto(userSchema) {}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
// users.controller.ts
|
|
82
|
+
import { Body, Controller, Get, Post } from '@nestjs/common';
|
|
83
|
+
import { ZodResponse } from 'zod-nest';
|
|
84
|
+
import { UserDto } from './user.dto';
|
|
85
|
+
|
|
86
|
+
@Controller('users')
|
|
87
|
+
export class UsersController {
|
|
88
|
+
@Get('single')
|
|
89
|
+
@ZodResponse({ type: UserDto })
|
|
90
|
+
single(): UserDto {
|
|
91
|
+
return { id: 'u1', email: 'A@B.COM' } as UserDto; // transform lowercases on the way out
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
@Post()
|
|
95
|
+
@ZodResponse({ type: UserDto })
|
|
96
|
+
create(@Body() body: UserDto): UserDto {
|
|
97
|
+
// body is already validated + parsed by ZodValidationPipe
|
|
98
|
+
return body;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
// app.module.ts
|
|
105
|
+
import { Module } from '@nestjs/common';
|
|
106
|
+
import { ZodNestModule } from 'zod-nest';
|
|
107
|
+
import { UsersController } from './users.controller';
|
|
108
|
+
|
|
109
|
+
@Module({
|
|
110
|
+
imports: [ZodNestModule.forRoot({ validationLogs: true })],
|
|
111
|
+
controllers: [UsersController],
|
|
112
|
+
})
|
|
113
|
+
export class AppModule {}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
// main.ts
|
|
118
|
+
import { NestFactory } from '@nestjs/core';
|
|
119
|
+
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
|
|
120
|
+
import { applyZodNest } from 'zod-nest';
|
|
121
|
+
import { AppModule } from './app.module';
|
|
122
|
+
|
|
123
|
+
async function bootstrap() {
|
|
124
|
+
const app = await NestFactory.create(AppModule);
|
|
125
|
+
|
|
126
|
+
const raw = SwaggerModule.createDocument(
|
|
127
|
+
app,
|
|
128
|
+
new DocumentBuilder().setTitle('Users').setVersion('1').build(),
|
|
129
|
+
);
|
|
130
|
+
const doc = applyZodNest(raw, { app });
|
|
131
|
+
SwaggerModule.setup('docs', app, doc);
|
|
132
|
+
|
|
133
|
+
await app.listen(3000);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
bootstrap();
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
That's the whole loop. Validation, response serialization, and a correct OpenAPI 3.1 document — all driven from one Zod schema per DTO.
|
|
140
|
+
|
|
141
|
+
## Core concepts
|
|
142
|
+
|
|
143
|
+
### Schema is the source of truth
|
|
144
|
+
|
|
145
|
+
Every DTO is one Zod schema wrapped in a class. The class exists so NestJS' introspection (parameter metatype, `@nestjs/swagger`) can find it; the validation and the OpenAPI emission both come from the schema directly. You don't repeat the shape with decorators.
|
|
146
|
+
|
|
147
|
+
### `createZodDto` is a thin bridge
|
|
148
|
+
|
|
149
|
+
The class returned by `createZodDto(schema)` carries `schema`, `id`, `io: 'input'`, and a lazy `Output` sibling. `parse` / `safeParse` are static methods on the class. The class is tagged with `Symbol.for('zod-nest.dto')` so `ZodValidationPipe` and `ZodSerializerInterceptor` can discriminate it from plain constructors. The id comes from `schema.meta({ id })` when present (preferred) or from the second-argument options.
|
|
150
|
+
|
|
151
|
+
See [`docs/dto.md`](docs/dto.md) for the full surface.
|
|
152
|
+
|
|
153
|
+
### I/O suffix rules
|
|
154
|
+
|
|
155
|
+
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.
|
|
156
|
+
|
|
157
|
+
You don't pick the behaviour with a flag — `applyZodNest` compares the emitted bodies and decides per DTO.
|
|
158
|
+
|
|
159
|
+
### Multi-status responses + status resolution
|
|
160
|
+
|
|
161
|
+
Stack `@ZodResponse` to declare multiple status codes on one handler:
|
|
162
|
+
|
|
163
|
+
```ts
|
|
164
|
+
@Get(':id')
|
|
165
|
+
@ZodResponse({ type: UserDto }) // success variant — status inferred (200 for GET)
|
|
166
|
+
@ZodResponse({ status: 404, type: ErrorDto })
|
|
167
|
+
@ZodResponse({ status: 500, type: FatalDto })
|
|
168
|
+
getUser(): void {}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
**Recommended style:** omit `status` for the success variant and let it infer from the route, then set `status` explicitly only for the off-happy-path variants. Keeps the signal-to-noise high — the explicit numbers in the snippet above are the ones the reader actually needs to scan for.
|
|
172
|
+
|
|
173
|
+
At request time, `ZodSerializerInterceptor` looks at `response.statusCode` and picks the matching variant. If you don't pass `status`, the variant matches on the handler's default (computed once at request time, in this order: `@HttpCode(n)` → `POST → 201`, everything else → `200`). `@ZodResponse` does **not** internally apply `@HttpCode` — you stay in charge of the actual HTTP status.
|
|
174
|
+
|
|
175
|
+
See [`docs/responses.md`](docs/responses.md) for the precedence chain and `passthroughOnError`.
|
|
176
|
+
|
|
177
|
+
## Usage
|
|
178
|
+
|
|
179
|
+
### Creating DTOs
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
import { z } from 'zod';
|
|
183
|
+
import { createZodDto } from 'zod-nest';
|
|
184
|
+
|
|
185
|
+
const userSchema = z.object({ id: z.uuid(), name: z.string() }).meta({ id: 'User' });
|
|
186
|
+
class UserDto extends createZodDto(userSchema) {}
|
|
187
|
+
|
|
188
|
+
UserDto.parse({ id: '00000000-0000-0000-0000-000000000000', name: 'Ada' });
|
|
189
|
+
// → { id: '...', name: 'Ada' }
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Setting the OpenAPI schema id
|
|
193
|
+
|
|
194
|
+
The id is what appears as the `components.schemas` key in the OpenAPI document and what `$ref`s point at. You can set it in two equivalent ways:
|
|
195
|
+
|
|
196
|
+
```ts
|
|
197
|
+
// Preferred — on the schema, via Zod's metadata
|
|
198
|
+
const userSchema = z.object({ /* ... */ }).meta({ id: 'User' });
|
|
199
|
+
class UserDto extends createZodDto(userSchema) {}
|
|
200
|
+
|
|
201
|
+
// Also valid — passed through createZodDto's options
|
|
202
|
+
class UserDto extends createZodDto(
|
|
203
|
+
z.object({ /* ... */ }),
|
|
204
|
+
{ id: 'User' },
|
|
205
|
+
) {}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Both produce the same OpenAPI output. `.meta({ id })` is preferred when the schema is hoisted into its own `const`, because the id stays with the schema — composition (`extend(parent, ...)`), shared input/output via `.meta({ id })` on the same schema reference, and any non-DTO use of the schema all pick up the same id without an extra hop through `createZodDto`'s options. Use the `createZodDto(schema, { id })` form when you don't own the schema (e.g. it comes from a third-party module) or when defining a small DTO with an inline schema, where chaining `.meta()` on the inline expression hurts readability.
|
|
209
|
+
|
|
210
|
+
If you pass neither, the class name is used as a fallback. Under minification — where class names become single mangled characters — `zod-nest` falls back to an `_AnonZodDto_N` id and prints a one-time console warning. Set an explicit id either way for production builds.
|
|
211
|
+
|
|
212
|
+
### Input validation
|
|
213
|
+
|
|
214
|
+
```ts
|
|
215
|
+
import { ZodValidationPipe } from 'zod-nest';
|
|
216
|
+
import { APP_PIPE } from '@nestjs/core';
|
|
217
|
+
|
|
218
|
+
@Controller('things')
|
|
219
|
+
class ThingsController {
|
|
220
|
+
@Post()
|
|
221
|
+
create(@Body() body: CreateThingDto) {
|
|
222
|
+
return { received: body };
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
@Module({
|
|
227
|
+
controllers: [ThingsController],
|
|
228
|
+
providers: [{ provide: APP_PIPE, useClass: ZodValidationPipe }],
|
|
229
|
+
})
|
|
230
|
+
class AppModule {}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Or use `ZodNestModule.forRoot()` — see [Module options](#module-options) below — to wire the pipe globally along with the response interceptor.
|
|
234
|
+
|
|
235
|
+
On failure the pipe throws `ZodValidationException` (HTTP 400, body `{ statusCode, message: 'Validation failed', errors: z.treeifyError(zodError) }`).
|
|
236
|
+
|
|
237
|
+
### Custom validation exception
|
|
238
|
+
|
|
239
|
+
```ts
|
|
240
|
+
import { HttpException, HttpStatus } from '@nestjs/common';
|
|
241
|
+
import { ZodValidationPipe } from 'zod-nest';
|
|
242
|
+
|
|
243
|
+
class UnprocessableEntityException extends HttpException {
|
|
244
|
+
constructor(issuesCount: number) {
|
|
245
|
+
super({ message: 'invalid input', issuesCount }, HttpStatus.UNPROCESSABLE_ENTITY);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const pipe = new ZodValidationPipe({
|
|
250
|
+
schema: CreateThingDto,
|
|
251
|
+
createValidationException: (zodError) => new UnprocessableEntityException(zodError.issues.length),
|
|
252
|
+
});
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
The factory receives `(zodError, argMetadata)` and returns anything `throw`-able. Wire it module-wide via `ZodNestModule.forRoot({ createValidationException: ... })`.
|
|
256
|
+
|
|
257
|
+
### Single-status response
|
|
258
|
+
|
|
259
|
+
```ts
|
|
260
|
+
@Controller('users')
|
|
261
|
+
class UsersController {
|
|
262
|
+
@Get('single')
|
|
263
|
+
@ZodResponse({ type: UserDto })
|
|
264
|
+
single(): UserDto {
|
|
265
|
+
return { id: 'u1', email: 'A@B.COM' };
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
The interceptor validates the return value against `UserDto.schema` and applies any `transform` / `pipe` Zod stages — in the example above, `email` is lowercased to `a@b.com` before the response leaves.
|
|
271
|
+
|
|
272
|
+
### Multi-status responses
|
|
273
|
+
|
|
274
|
+
Stack `@ZodResponse` per status code:
|
|
275
|
+
|
|
276
|
+
```ts
|
|
277
|
+
import { Get, HttpStatus } from '@nestjs/common';
|
|
278
|
+
import { ZodResponse } from 'zod-nest';
|
|
279
|
+
|
|
280
|
+
class UserDto extends createZodDto(z.object({ id: z.string() }), { id: 'User' }) {}
|
|
281
|
+
class ErrorDto extends createZodDto(z.object({ code: z.number() }), { id: 'Error' }) {}
|
|
282
|
+
class FatalDto extends createZodDto(z.object({ trace: z.string() }), { id: 'Fatal' }) {}
|
|
283
|
+
|
|
284
|
+
class UsersController {
|
|
285
|
+
@Get(':id')
|
|
286
|
+
@ZodResponse({ type: UserDto }) // 200 inferred
|
|
287
|
+
@ZodResponse({ status: HttpStatus.NOT_FOUND, type: ErrorDto })
|
|
288
|
+
@ZodResponse({ status: HttpStatus.INTERNAL_SERVER_ERROR, type: FatalDto })
|
|
289
|
+
getUser(): void {}
|
|
290
|
+
}
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
At runtime the interceptor matches `response.statusCode` against each variant's `status`. The OpenAPI doc emits three `responses[200|404|500]` entries with the right DTO ref under each. See [`docs/responses.md`](docs/responses.md) for the full mechanism.
|
|
294
|
+
|
|
295
|
+
### `passthroughOnError`
|
|
296
|
+
|
|
297
|
+
For an upstream shape you don't fully trust, set `passthroughOnError: true` on the variant. Validation failures are logged (if logging is on) but the original value passes through untouched:
|
|
298
|
+
|
|
299
|
+
```ts
|
|
300
|
+
@Get('proxied')
|
|
301
|
+
@ZodResponse({ type: ProxyDto, passthroughOnError: true })
|
|
302
|
+
proxied(): unknown {
|
|
303
|
+
return { upstream: 'value', extra: ['raw', 'shape'] };
|
|
304
|
+
}
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
Use this sparingly — it bypasses the contract you declared. Logging at `warn` severity makes the deviation visible without breaking the request.
|
|
308
|
+
|
|
309
|
+
### Array and tuple responses
|
|
310
|
+
|
|
311
|
+
```ts
|
|
312
|
+
@Get('list') @ZodResponse({ type: [UserDto] }) list(): UserDto[] { /* ... */ }
|
|
313
|
+
@Get('pair') @ZodResponse({ type: [UserDto, TagDto] }) pair(): unknown { /* ... */ }
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
`[Dto]` validates as `z.array(Dto.schema)` and surfaces as OpenAPI `type: array`. `[A, B, …]` validates as `z.tuple([A.schema, B.schema, …])` and surfaces as `prefixItems`. Empty arrays and non-DTO elements throw `TypeError` at decoration time, so typos surface at module load — not the first request.
|
|
317
|
+
|
|
318
|
+
### Swagger integration
|
|
319
|
+
|
|
320
|
+
```ts
|
|
321
|
+
import { applyZodNest } from 'zod-nest';
|
|
322
|
+
|
|
323
|
+
const raw = SwaggerModule.createDocument(app, config);
|
|
324
|
+
const doc = applyZodNest(raw, { app });
|
|
325
|
+
SwaggerModule.setup('docs', app, doc);
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
`applyZodNest` walks the doc, replaces every `x-zod-nest-dto` marker with the real Zod-derived JSON Schema, applies the I/O suffix truth table, strips the markers, and validates the final ref graph. Any dangling ref throws `ZodNestDocumentError({ code: 'DANGLING_REF' })` — the spec fails at boot, not at request time.
|
|
329
|
+
|
|
330
|
+
See [`docs/swagger-integration.md`](docs/swagger-integration.md) for `Override`, custom registries, and strict-mode behaviour.
|
|
331
|
+
|
|
332
|
+
### Module setup
|
|
333
|
+
|
|
334
|
+
```ts
|
|
335
|
+
import { ZodNestModule } from 'zod-nest';
|
|
336
|
+
|
|
337
|
+
@Module({
|
|
338
|
+
imports: [
|
|
339
|
+
ZodNestModule.forRoot({
|
|
340
|
+
validationLogs: { input: true, output: true },
|
|
341
|
+
redactKeys: ['password', 'token', 'sessionId'],
|
|
342
|
+
createSerializationException: (err, ctx) =>
|
|
343
|
+
new MyCustomFiveHundred(err, ctx),
|
|
344
|
+
}),
|
|
345
|
+
],
|
|
346
|
+
controllers: [UsersController],
|
|
347
|
+
})
|
|
348
|
+
class AppModule {}
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
`forRoot()` is optional — `ZodValidationPipe` and `ZodSerializerInterceptor` work standalone with safe defaults. Use `forRoot` when you want consistent logging, a custom logger, custom exceptions, or shared redaction across the pipe and the interceptor.
|
|
352
|
+
|
|
353
|
+
## Module options
|
|
354
|
+
|
|
355
|
+
| Option | Type | Default | What it does |
|
|
356
|
+
|---|---|---|---|
|
|
357
|
+
| `createValidationException` | `(err, argMetadata) => unknown` | uses `ZodValidationException` | Custom 400 exception for input failures |
|
|
358
|
+
| `createSerializationException` | `(err, executionContext) => unknown` | uses `ZodSerializationException` | Custom 500 exception for output failures (strict mode only) |
|
|
359
|
+
| `validationLogs` | `boolean \| { input?, output? }` | `false` | Opt-in failure-only logging |
|
|
360
|
+
| `logger` | `LoggerService` | NestJS `Logger` | Replace the logger (pino, winston, …) |
|
|
361
|
+
| `redactKeys` | `readonly string[]` | `DEFAULT_REDACT_KEYS` | Keys redacted in logs (replaces default list, no merge) |
|
|
362
|
+
| `maxLoggedValueBytes` | `number` | `4096` | Truncate oversize logged values |
|
|
363
|
+
|
|
364
|
+
`DEFAULT_REDACT_KEYS` includes `password`, `secret`, `apiKey`, `authorization`, `bearer`, `token`, `accessToken`, `refreshToken`, `jwt`, `cookie`, `set-cookie`. Matching is case-insensitive and applied at any depth in the logged value.
|
|
365
|
+
|
|
366
|
+
Full reference (with every interaction note) lives in [`docs/module-options.md`](docs/module-options.md).
|
|
367
|
+
|
|
368
|
+
## Logging
|
|
369
|
+
|
|
370
|
+
Validation logging fires **only on failure**, with side `'input'` or `'output'`. The default behaviour is off; opt in via `validationLogs: true` (both sides) or `validationLogs: { input: true }` / `{ output: true }` (granular).
|
|
371
|
+
|
|
372
|
+
A log entry carries:
|
|
373
|
+
|
|
374
|
+
- `side` — `'input'` or `'output'`
|
|
375
|
+
- `severity` — `'error'` for strict failures, `'warn'` for `passthroughOnError` failures
|
|
376
|
+
- `dto` — the DTO class name
|
|
377
|
+
- `value` — the offending value, redacted and truncated
|
|
378
|
+
- the treeified Zod error from `z.treeifyError(zodError)`
|
|
379
|
+
|
|
380
|
+
Redaction is **case-insensitive** at any depth — a key named `Password` deep in a nested object is replaced with `'[REDACTED]'` just like a top-level `password`. Truncation replaces values larger than `maxLoggedValueBytes` (UTF-8 bytes) with `{ _truncated: true, _originalBytes, _preview }` so you keep enough context to debug without flooding the logger.
|
|
381
|
+
|
|
382
|
+
Supplying `redactKeys` **replaces** the default list — there is no merge. If you want to *add* keys, spread `DEFAULT_REDACT_KEYS`:
|
|
383
|
+
|
|
384
|
+
```ts
|
|
385
|
+
import { DEFAULT_REDACT_KEYS, ZodNestModule } from 'zod-nest';
|
|
386
|
+
|
|
387
|
+
ZodNestModule.forRoot({
|
|
388
|
+
validationLogs: true,
|
|
389
|
+
redactKeys: [...DEFAULT_REDACT_KEYS, 'sessionId'],
|
|
390
|
+
});
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
See [`docs/logging.md`](docs/logging.md) for custom-logger adapters (pino, winston), structured-logging shape, and performance characteristics.
|
|
394
|
+
|
|
395
|
+
## Composition (experimental)
|
|
396
|
+
|
|
397
|
+
> **`@experimental`** — output shape may change as edge cases surface. Pin a minor version if you build on this surface.
|
|
398
|
+
|
|
399
|
+
`zod-nest` ships an `extend` helper that records a parent → child link and emits OpenAPI `allOf` for derived schemas:
|
|
400
|
+
|
|
401
|
+
```ts
|
|
402
|
+
import { extend, getLineage } from 'zod-nest';
|
|
403
|
+
|
|
404
|
+
const Base = z.object({ id: z.string() }).meta({ id: 'Base' });
|
|
405
|
+
const Child = extend(Base, (s) => s.extend({ role: z.string() }).meta({ id: 'Child' }));
|
|
406
|
+
|
|
407
|
+
getLineage(Child);
|
|
408
|
+
// → { op: 'extend', parent: Base }
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
The emitted `Child` schema is `allOf: [{ $ref: '#/components/schemas/Base' }, { type: 'object', properties: { role: { type: 'string' } }, required: ['role'] }]`. The parent must be registered (via `.meta({ id })` or `createZodDto`) for the `$ref` to resolve; anonymous parents fall back to flat emission.
|
|
412
|
+
|
|
413
|
+
See [`docs/composition.md`](docs/composition.md) for the full contract, current limitations, and the roadmap for non-`extend` operators.
|
|
414
|
+
|
|
415
|
+
## API reference
|
|
416
|
+
|
|
417
|
+
A compact, link-out index. Type signatures and detailed semantics live in the companion docs.
|
|
418
|
+
|
|
419
|
+
**DTO** — [`docs/dto.md`](docs/dto.md)
|
|
420
|
+
- `createZodDto(schema, options?)`, `isZodDto(value)`, `ZodDto<TSchema>`, `Io`
|
|
421
|
+
|
|
422
|
+
**Validation** — [`docs/validation-pipe.md`](docs/validation-pipe.md)
|
|
423
|
+
- `ZodValidationPipe`, `ZodValidationException`, `ZodValidationPipeOptions`, `CreateValidationException`
|
|
424
|
+
|
|
425
|
+
**Response** — [`docs/responses.md`](docs/responses.md)
|
|
426
|
+
- `@ZodResponse({ status?, type, description?, passthroughOnError? })`, `ZodSerializerInterceptor`, `ZodSerializationException`, `defaultStatusFor`, `resolveEffectiveStatus`, `ResponseVariant`, `ZOD_RESPONSES_METADATA_KEY`
|
|
427
|
+
|
|
428
|
+
**Document** — [`docs/swagger-integration.md`](docs/swagger-integration.md)
|
|
429
|
+
- `applyZodNest(rawDoc, options)`, `ApplyZodNestOptions`, `ZodNestDocumentError`
|
|
430
|
+
|
|
431
|
+
**Module** — [`docs/module-options.md`](docs/module-options.md) / [`docs/logging.md`](docs/logging.md)
|
|
432
|
+
- `ZodNestModule.forRoot(options?)`, `ZodNestModuleOptions`, `DEFAULT_REDACT_KEYS`, `DEFAULT_MAX_LOGGED_VALUE_BYTES`, `ZOD_NEST_OPTIONS`
|
|
433
|
+
|
|
434
|
+
**Schema engine** — single-schema mode and extension points
|
|
435
|
+
- `toOpenApi(schema, opts)`, `createRegistry()`, `defaultRegistry`, `ZodNestRegistry`, `Override`, `OverrideContext`, `ZodNestError`, `ZodNestUnrepresentableError`, `extend`, `getLineage`, `LineageEntry`
|
|
436
|
+
|
|
437
|
+
## Documentation
|
|
438
|
+
|
|
439
|
+
| Topic | Doc |
|
|
440
|
+
|---|---|
|
|
441
|
+
| Why this library exists | [`docs/why-this-exists.md`](docs/why-this-exists.md) |
|
|
442
|
+
| `createZodDto` in depth | [`docs/dto.md`](docs/dto.md) |
|
|
443
|
+
| Input validation | [`docs/validation-pipe.md`](docs/validation-pipe.md) |
|
|
444
|
+
| Responses, multi-status, status resolution | [`docs/responses.md`](docs/responses.md) |
|
|
445
|
+
| Module options reference | [`docs/module-options.md`](docs/module-options.md) |
|
|
446
|
+
| Validation logging | [`docs/logging.md`](docs/logging.md) |
|
|
447
|
+
| Swagger integration & custom emission | [`docs/swagger-integration.md`](docs/swagger-integration.md) |
|
|
448
|
+
| Composition (experimental) | [`docs/composition.md`](docs/composition.md) |
|
|
449
|
+
| Exception classes | [`docs/exceptions.md`](docs/exceptions.md) |
|
|
450
|
+
| Recipes | [`docs/recipes/`](docs/recipes/) |
|
|
451
|
+
|
|
452
|
+
## Migration from `nestjs-zod`
|
|
453
|
+
|
|
454
|
+
If you're coming from `nestjs-zod`, the headline changes are:
|
|
455
|
+
|
|
456
|
+
- Replace `cleanupOpenApiDoc(SwaggerModule.createDocument(app, config))` with `applyZodNest(SwaggerModule.createDocument(app, config), { app })`.
|
|
457
|
+
- Replace `@ApiOkResponse({ type: Dto }) + @ZodSerializerDto(Dto)` pairs with `@ZodResponse({ type: Dto })`.
|
|
458
|
+
- Drop `class-validator` / `class-transformer` if they were installed only for `nestjs-zod` interop.
|
|
459
|
+
- 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
|
+
|
|
462
|
+
Full guide with side-by-side diffs and a 19-row breaking-changes table in [`MIGRATION.md`](MIGRATION.md).
|
|
463
|
+
|
|
464
|
+
## Contributing
|
|
465
|
+
|
|
466
|
+
`zod-nest` is a young, single-maintainer OSS project — contributions and issues are welcome. The codebase is well-tested (>340 tests, full coverage on document/schema layers) and is meant to stay small enough that a first-time contributor can hold the whole surface in their head.
|
|
467
|
+
|
|
468
|
+
See [`CONTRIBUTING.md`](CONTRIBUTING.md) for local-dev setup, the test layout, and how to add a recipe. Reports and discussions go through [GitHub issues](https://github.com/rodrigowbazevedo/zod-nest/issues).
|
|
469
|
+
|
|
470
|
+
## License
|
|
471
|
+
|
|
472
|
+
MIT — see [`LICENSE`](LICENSE).
|
|
473
|
+
|
|
474
|
+
The names and patterns `createZodDto`, `ZodValidationPipe`, `ZodValidationException`, `ZodSerializerInterceptor`, `ZodSerializationException`, and `ZodResponse` originate in [`nestjs-zod`](https://github.com/BenLorantfy/nestjs-zod) (MIT). Attribution lives in [`NOTICE`](NOTICE).
|
package/dist/index.d.mts
CHANGED
|
@@ -12,10 +12,10 @@ declare const ZOD_NEST_ERROR_EXTENSION = "x-zod-nest-error";
|
|
|
12
12
|
/** Value of `x-zod-nest-error` when a registry id is claimed by more than one schema. */
|
|
13
13
|
declare const ZOD_NEST_ERROR_DUPLICATE_ID = "duplicate-id";
|
|
14
14
|
/**
|
|
15
|
-
* OpenAPI extension key used by `createZodDto` to mark a class for
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
15
|
+
* OpenAPI extension key used by `createZodDto` to mark a class for `applyZodNest`.
|
|
16
|
+
* The marker carries `{ __zodNestDto: true, dtoId, io }` so `applyZodNest` can
|
|
17
|
+
* locate every zod-nest DTO in the @nestjs/swagger document and inject the
|
|
18
|
+
* real Zod-derived schema.
|
|
19
19
|
*/
|
|
20
20
|
declare const ZOD_NEST_DTO_EXTENSION = "x-zod-nest-dto";
|
|
21
21
|
|
|
@@ -34,21 +34,50 @@ interface ZodNestRegistry {
|
|
|
34
34
|
hasCollision(id: string): boolean;
|
|
35
35
|
getCollisions(): ReadonlyMap<string, ReadonlySet<z.ZodType>>;
|
|
36
36
|
/**
|
|
37
|
-
* Snapshot of every id registered through this `ZodNestRegistry`.
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
37
|
+
* Snapshot of every id registered through this `ZodNestRegistry`. The
|
|
38
|
+
* underlying Zod registry is `z.globalRegistry`, which may hold third-party
|
|
39
|
+
* entries — bulk emission filters its output against this snapshot to keep
|
|
40
|
+
* only zod-nest-known ids.
|
|
41
41
|
*/
|
|
42
42
|
ids(): readonly string[];
|
|
43
43
|
}
|
|
44
44
|
declare const createRegistry: () => ZodNestRegistry;
|
|
45
|
+
/** Process-wide default registry, used when no explicit `options.registry` is passed. */
|
|
46
|
+
declare const defaultRegistry: ZodNestRegistry;
|
|
47
|
+
|
|
45
48
|
/**
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
* to v0.2.
|
|
49
|
+
* Composition layer — emits OpenAPI `allOf` for schemas derived via `extend`.
|
|
50
|
+
*
|
|
51
|
+
* **EXPERIMENTAL**: output shape may change as edge cases surface.
|
|
50
52
|
*/
|
|
51
|
-
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Lineage record for a composition-derived schema. Read by the override to
|
|
56
|
+
* emit `allOf` instead of a flat body.
|
|
57
|
+
*
|
|
58
|
+
* @experimental — shape may change.
|
|
59
|
+
*/
|
|
60
|
+
interface LineageEntry {
|
|
61
|
+
readonly op: 'extend';
|
|
62
|
+
readonly parent: z.ZodObject;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Wraps a derived `z.ZodObject` and records the parent → child link so
|
|
66
|
+
* emission rewrites the body to `allOf: [{ $ref: <parent> }, <delta>]`.
|
|
67
|
+
*
|
|
68
|
+
* @experimental — output shape may change as the surface stabilizes.
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* const Base = z.object({ id: z.string() }).meta({ id: 'Base' });
|
|
72
|
+
* const Child = extend(Base, (s) => s.extend({ role: z.string() }).meta({ id: 'Child' }));
|
|
73
|
+
*/
|
|
74
|
+
declare const extend: <P extends z.ZodObject, S extends z.ZodObject>(parent: P, build: (p: P) => S) => S;
|
|
75
|
+
/**
|
|
76
|
+
* Read the lineage entry for a composition-derived schema, or `undefined`.
|
|
77
|
+
*
|
|
78
|
+
* @experimental — `LineageEntry` shape may change.
|
|
79
|
+
*/
|
|
80
|
+
declare const getLineage: (schema: z.ZodType) => LineageEntry | undefined;
|
|
52
81
|
|
|
53
82
|
interface ToOpenApiOptions {
|
|
54
83
|
io: 'input' | 'output';
|
|
@@ -71,11 +100,7 @@ declare class ZodNestUnrepresentableError extends ZodNestError {
|
|
|
71
100
|
constructor(path: ReadonlyArray<string | number>, zodType: string);
|
|
72
101
|
}
|
|
73
102
|
|
|
74
|
-
/**
|
|
75
|
-
* Runtime detection marker placed on every class returned by `createZodDto`.
|
|
76
|
-
* Used by the validation pipe (Phase 2c), serializer (2d), and doc merger (2e)
|
|
77
|
-
* to discriminate zod-nest DTO classes from regular constructors.
|
|
78
|
-
*/
|
|
103
|
+
/** Runtime tag placed on every class returned by `createZodDto`. */
|
|
79
104
|
declare const ZOD_DTO_SYMBOL: unique symbol;
|
|
80
105
|
|
|
81
106
|
type Io = 'input' | 'output';
|
|
@@ -105,7 +130,7 @@ declare const createZodDto: <TSchema extends z.ZodType>(schema: TSchema, options
|
|
|
105
130
|
|
|
106
131
|
/**
|
|
107
132
|
* Payload of the `x-zod-nest-dto` placeholder property that
|
|
108
|
-
* `_OPENAPI_METADATA_FACTORY` returns.
|
|
133
|
+
* `_OPENAPI_METADATA_FACTORY` returns. `applyZodNest` reads this off
|
|
109
134
|
* each `components.schemas.<DtoName>.properties[x-zod-nest-dto]` entry,
|
|
110
135
|
* uses `dtoId` to look up the schema in the registry, and replaces the
|
|
111
136
|
* synthetic schema body with the real Zod-derived schema.
|
|
@@ -113,7 +138,7 @@ declare const createZodDto: <TSchema extends z.ZodType>(schema: TSchema, options
|
|
|
113
138
|
* `type` and `required` are benign filler that satisfy @nestjs/swagger's
|
|
114
139
|
* property-type guard (without them, the explorer throws "A circular
|
|
115
140
|
* dependency has been detected"). They have no semantic meaning and are
|
|
116
|
-
* stripped along with the rest of the marker by
|
|
141
|
+
* stripped along with the rest of the marker by `applyZodNest`.
|
|
117
142
|
*/
|
|
118
143
|
interface ZodDtoMarker {
|
|
119
144
|
readonly type: () => typeof Object;
|
|
@@ -123,14 +148,13 @@ interface ZodDtoMarker {
|
|
|
123
148
|
readonly io: Io;
|
|
124
149
|
}
|
|
125
150
|
declare const makeZodDtoMarker: (dtoId: string, io: Io) => ZodDtoMarker;
|
|
126
|
-
/** Phase 2e (and tests) use this to discriminate a marker from a real schema. */
|
|
127
151
|
declare const isZodDtoMarker: (value: unknown) => value is ZodDtoMarker;
|
|
128
152
|
|
|
129
153
|
/**
|
|
130
154
|
* Runtime guard: is `value` a class returned by `createZodDto`?
|
|
131
155
|
*
|
|
132
|
-
* Used by
|
|
133
|
-
*
|
|
156
|
+
* Used by `ZodValidationPipe`, `ZodSerializerInterceptor`, and `applyZodNest`
|
|
157
|
+
* to discriminate zod-nest DTOs from plain
|
|
134
158
|
* constructors, class-validator DTOs, primitives, and any other metatypes
|
|
135
159
|
* NestJS exposes via `ArgumentMetadata`.
|
|
136
160
|
*/
|
|
@@ -146,13 +170,18 @@ declare const isZodDto: (value: unknown) => value is ZodDto;
|
|
|
146
170
|
* {
|
|
147
171
|
* statusCode: 500,
|
|
148
172
|
* message: 'Response validation failed',
|
|
149
|
-
* errors: z.treeifyError(zodError),
|
|
150
173
|
* }
|
|
151
174
|
* ```
|
|
152
175
|
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
176
|
+
* The zod error tree is **deliberately not exposed in the response body** —
|
|
177
|
+
* a serialization failure is a server-side contract violation, and leaking
|
|
178
|
+
* the schema-shape error tree to clients discloses internal structure. The
|
|
179
|
+
* full treeified error is logged through `ZodNestModule`'s validation-log
|
|
180
|
+
* channel (with redaction + truncation) so operators get the diagnostic
|
|
181
|
+
* information without it reaching the wire.
|
|
182
|
+
*
|
|
183
|
+
* Custom exception filters can still introspect the failure: `zodError` and
|
|
184
|
+
* `executionContext` are kept as own properties on the instance.
|
|
156
185
|
*/
|
|
157
186
|
declare class ZodSerializationException extends InternalServerErrorException {
|
|
158
187
|
readonly zodError: z.ZodError;
|
|
@@ -294,7 +323,7 @@ declare const ZOD_RESPONSES_METADATA_KEY: unique symbol;
|
|
|
294
323
|
type ResponseVariantKind = 'single' | 'array' | 'tuple';
|
|
295
324
|
/**
|
|
296
325
|
* Description payload accepted by `@ZodResponse(...)` and passed through to
|
|
297
|
-
*
|
|
326
|
+
* `applyZodNest`'s `@ApiResponse(...)` emitter. String form is shorthand for
|
|
298
327
|
* `{ description }`; the object form lets users declare OpenAPI response
|
|
299
328
|
* `headers` / `links` alongside the description.
|
|
300
329
|
*/
|
|
@@ -305,8 +334,8 @@ type ZodResponseDescription = string | {
|
|
|
305
334
|
};
|
|
306
335
|
/**
|
|
307
336
|
* One variant record per `@ZodResponse(...)` call. `dto` is kept alongside
|
|
308
|
-
* `validationSchema` so
|
|
309
|
-
* unwrapping the runtime-only `z.array(...)` / `z.tuple([...])` wrapper.
|
|
337
|
+
* `validationSchema` so `applyZodNest` can emit `@ApiResponse({ type })`
|
|
338
|
+
* without unwrapping the runtime-only `z.array(...)` / `z.tuple([...])` wrapper.
|
|
310
339
|
*
|
|
311
340
|
* `status` is `undefined` when the user didn't pass one explicitly — the
|
|
312
341
|
* effective status is resolved lazily by `resolveEffectiveStatus(variant,
|
|
@@ -330,7 +359,7 @@ interface ResponseVariant {
|
|
|
330
359
|
* `@ApiResponse({ isArray: true })` convention without minting a separate
|
|
331
360
|
* `*sDto` id.
|
|
332
361
|
* - `[A, B, ...]` (length ≥ 2) → validates as `z.tuple([A.schema, B.schema, ...])`;
|
|
333
|
-
* surfaces as an OpenAPI 3.1 `prefixItems` tuple
|
|
362
|
+
* surfaces as an OpenAPI 3.1 `prefixItems` tuple via `applyZodNest`.
|
|
334
363
|
*
|
|
335
364
|
* Empty arrays and non-DTO elements throw `TypeError` at decoration time
|
|
336
365
|
* so typos surface at module load, not the first request.
|
|
@@ -417,8 +446,7 @@ interface ApplyZodNestOptions {
|
|
|
417
446
|
/**
|
|
418
447
|
* `ZodNestRegistry` instance that holds the zod-nest DTOs. Defaults to
|
|
419
448
|
* `defaultRegistry` (the process-wide singleton populated by `createZodDto`).
|
|
420
|
-
* Pass an explicit registry for multi-app isolation
|
|
421
|
-
* in v0.2).
|
|
449
|
+
* Pass an explicit registry for multi-app isolation.
|
|
422
450
|
*/
|
|
423
451
|
registry?: ZodNestRegistry;
|
|
424
452
|
/** User override pipe applied on top of the built-in override during emission. */
|
|
@@ -470,4 +498,4 @@ declare class ZodNestDocumentError extends ZodNestError {
|
|
|
470
498
|
constructor(code: ZodNestDocumentErrorCode, message: string, details?: Record<string, unknown>);
|
|
471
499
|
}
|
|
472
500
|
|
|
473
|
-
export { type ApplyZodNestOptions, COMPONENTS_SCHEMAS_PREFIX, type CreateSerializationException, type CreateValidationException, type CreateZodDtoOptions, DEFAULT_MAX_LOGGED_VALUE_BYTES, DEFAULT_REDACT_KEYS, type Io, 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, isZodDto, isZodDtoMarker, makeZodDtoMarker, resolveEffectiveStatus, toOpenApi };
|
|
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 };
|