zod-nest 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -1,5 +1,8 @@
1
1
  import { z } from 'zod';
2
2
  import { JSONSchema, $ZodTypes } from 'zod/v4/core';
3
+ import { InternalServerErrorException, ExecutionContext, BadRequestException, ArgumentMetadata, LoggerService, PipeTransform, NestInterceptor, CallHandler, DynamicModule } from '@nestjs/common';
4
+ import { Reflector } from '@nestjs/core';
5
+ import { Observable } from 'rxjs';
3
6
 
4
7
  /** OpenAPI 3.1 `$ref` prefix for entries in `components.schemas`. */
5
8
  declare const COMPONENTS_SCHEMAS_PREFIX = "#/components/schemas/";
@@ -115,4 +118,285 @@ declare const makeZodDtoMarker: (dtoId: string, io: Io) => ZodDtoMarker;
115
118
  /** Phase 2e (and tests) use this to discriminate a marker from a real schema. */
116
119
  declare const isZodDtoMarker: (value: unknown) => value is ZodDtoMarker;
117
120
 
118
- export { COMPONENTS_SCHEMAS_PREFIX, type CreateZodDtoOptions, type Io, type Override, type OverrideContext, type SchemaObject, type ToOpenApiOptions, type ToOpenApiResult, ZOD_DTO_SYMBOL, ZOD_NEST_DTO_EXTENSION, ZOD_NEST_ERROR_DUPLICATE_ID, ZOD_NEST_ERROR_EXTENSION, type ZodDto, type ZodDtoMarker, ZodNestError, type ZodNestRegistry, ZodNestUnrepresentableError, createRegistry, createZodDto, defaultRegistry, isZodDtoMarker, makeZodDtoMarker, toOpenApi };
121
+ /**
122
+ * Runtime guard: is `value` a class returned by `createZodDto`?
123
+ *
124
+ * Used by the validation pipe (Phase 2c), the serializer interceptor (2d),
125
+ * and the doc merger (2e) to discriminate zod-nest DTOs from plain
126
+ * constructors, class-validator DTOs, primitives, and any other metatypes
127
+ * NestJS exposes via `ArgumentMetadata`.
128
+ */
129
+ declare const isZodDto: (value: unknown) => value is ZodDto;
130
+
131
+ /**
132
+ * Default exception thrown by `ZodSerializerInterceptor` in strict mode
133
+ * (i.e. when `@ZodResponse({ passthroughOnError: true })` is NOT set) on
134
+ * response-validation failure.
135
+ *
136
+ * Body shape (returned by `getResponse()`):
137
+ * ```
138
+ * {
139
+ * statusCode: 500,
140
+ * message: 'Response validation failed',
141
+ * errors: z.treeifyError(zodError),
142
+ * }
143
+ * ```
144
+ *
145
+ * Carries `zodError` and `executionContext` so custom exception filters
146
+ * can introspect the original validation failure and the request that
147
+ * produced it.
148
+ */
149
+ declare class ZodSerializationException extends InternalServerErrorException {
150
+ readonly zodError: z.ZodError;
151
+ readonly executionContext?: ExecutionContext;
152
+ constructor(zodError: z.ZodError, executionContext?: ExecutionContext);
153
+ }
154
+
155
+ /**
156
+ * Default exception thrown by `ZodValidationPipe` when input fails to parse.
157
+ *
158
+ * Body shape (returned by `getResponse()`):
159
+ * ```
160
+ * {
161
+ * statusCode: 400,
162
+ * message: 'Validation failed',
163
+ * errors: z.treeifyError(zodError),
164
+ * }
165
+ * ```
166
+ *
167
+ * Carries `zodError` and `argMetadata` so custom exception filters can
168
+ * introspect the original validation failure.
169
+ */
170
+ declare class ZodValidationException extends BadRequestException {
171
+ readonly zodError: z.ZodError;
172
+ readonly argMetadata?: ArgumentMetadata;
173
+ constructor(zodError: z.ZodError, argMetadata?: ArgumentMetadata);
174
+ }
175
+
176
+ interface ValidationLogContext {
177
+ /** Which side of the request emitted the failure. */
178
+ side: 'input' | 'output';
179
+ /** Severity to log at; the formatter does not decide this. */
180
+ severity: 'warn' | 'error';
181
+ /** Pre-formatted DTO label, e.g. `'UserDto'`, `'[UserDto]'`, `'[A, B]'`. */
182
+ dto: string;
183
+ /** Output side only — HTTP response status code. */
184
+ status?: number;
185
+ /** Output side only — `Controller.method` best-effort. */
186
+ handler?: string;
187
+ /** Input side only — `body` / `query` / `param` / `custom`. */
188
+ argType?: string;
189
+ }
190
+ type LogValidationFailure = (err: z.ZodError, value: unknown, ctx: ValidationLogContext) => void;
191
+
192
+ /**
193
+ * Module-scope factory for the exception thrown by `ZodValidationPipe` on
194
+ * input validation failure. Mirrors the existing per-pipe option but lives
195
+ * at module scope; per-instance constructor arg wins.
196
+ */
197
+ type CreateValidationException$1 = (err: z.ZodError, argMetadata: ArgumentMetadata) => unknown;
198
+ /**
199
+ * Module-scope factory for the exception thrown by `ZodSerializerInterceptor`
200
+ * on output validation failure (strict mode only). Soft mode never calls
201
+ * this factory.
202
+ */
203
+ type CreateSerializationException = (err: z.ZodError, executionContext: ExecutionContext) => unknown;
204
+ /** Public options accepted by `ZodNestModule.forRoot()`. */
205
+ interface ZodNestModuleOptions {
206
+ createValidationException?: CreateValidationException$1;
207
+ createSerializationException?: CreateSerializationException;
208
+ /**
209
+ * Failure-only validation logging. `true` enables both input and output;
210
+ * the granular form lets each side be toggled independently. Default: off.
211
+ */
212
+ validationLogs?: boolean | {
213
+ input?: boolean;
214
+ output?: boolean;
215
+ };
216
+ /** Override Nest's built-in `Logger` (e.g. pino/winston adapter). */
217
+ logger?: LoggerService;
218
+ /**
219
+ * Keys whose values get scrubbed from logged input/response objects.
220
+ * Matched case-insensitively at any depth. Supplying this option
221
+ * REPLACES the default list (no merge).
222
+ */
223
+ redactKeys?: readonly string[];
224
+ /**
225
+ * Maximum size in bytes (UTF-8) for any single logged value. Oversized
226
+ * values become `{ _truncated: true, _originalBytes, _preview }`.
227
+ */
228
+ maxLoggedValueBytes?: number;
229
+ }
230
+ /**
231
+ * Resolved options consumed by pipe + interceptor. `forRoot()` builds this
232
+ * once and stuffs it into a provider for the `ZOD_NEST_OPTIONS` injection
233
+ * token; downstream code never re-checks the raw `validationLogs` flag.
234
+ */
235
+ interface NormalizedZodNestOptions {
236
+ createValidationException: CreateValidationException$1 | undefined;
237
+ createSerializationException: CreateSerializationException | undefined;
238
+ /** No-op when `validationLogs.input` resolved to false. */
239
+ logInputFailure: LogValidationFailure;
240
+ /** No-op when `validationLogs.output` resolved to false. */
241
+ logOutputFailure: LogValidationFailure;
242
+ }
243
+ declare const DEFAULT_REDACT_KEYS: readonly string[];
244
+ declare const DEFAULT_MAX_LOGGED_VALUE_BYTES = 4096;
245
+ /** DI token for `NormalizedZodNestOptions`. */
246
+ declare const ZOD_NEST_OPTIONS: unique symbol;
247
+
248
+ /**
249
+ * Build the exception thrown by `ZodValidationPipe` on validation failure.
250
+ * Receives Zod's error and the NestJS argument metadata; returns anything
251
+ * `throw`-able (typically a NestJS `HttpException` subclass).
252
+ */
253
+ type CreateValidationException = (zodError: z.ZodError, argMetadata: ArgumentMetadata) => unknown;
254
+ interface ZodValidationPipeOptions {
255
+ schema?: z.ZodType | ZodDto;
256
+ createValidationException?: CreateValidationException;
257
+ }
258
+ /**
259
+ * Constructor input for `ZodValidationPipe`. Discriminated at runtime:
260
+ * - `undefined` → metatype-driven (read DTO from handler arg's metatype)
261
+ * - a class with `[ZOD_DTO_SYMBOL]` → explicit DTO
262
+ * - a Zod schema (has `_zod` internals) → raw schema
263
+ * - anything else → options object
264
+ */
265
+ type ZodValidationPipeArg = z.ZodType | ZodDto | ZodValidationPipeOptions;
266
+
267
+ declare class ZodValidationPipe implements PipeTransform {
268
+ private readonly explicitSchema;
269
+ private readonly explicitDtoName;
270
+ private readonly createValidationException;
271
+ private readonly logInputFailure;
272
+ constructor(arg?: ZodValidationPipeArg, moduleOptions?: NormalizedZodNestOptions);
273
+ transform(value: unknown, metadata: ArgumentMetadata): Promise<unknown>;
274
+ private resolveSchema;
275
+ private resolveDtoLabel;
276
+ private static parseArg;
277
+ }
278
+
279
+ /**
280
+ * Public metadata key for the array of `ResponseVariant` records attached
281
+ * to handler methods by `@ZodResponse(...)`. Symbol.for() so external
282
+ * consumers (e.g. custom interceptors or doc builders) can read the same
283
+ * registry across realms.
284
+ */
285
+ declare const ZOD_RESPONSES_METADATA_KEY: unique symbol;
286
+ type ResponseVariantKind = 'single' | 'array' | 'tuple';
287
+ /**
288
+ * Description payload accepted by `@ZodResponse(...)` and passed through to
289
+ * Phase 2e's `@ApiResponse(...)` emitter. String form is shorthand for
290
+ * `{ description }`; the object form lets users declare OpenAPI response
291
+ * `headers` / `links` alongside the description.
292
+ */
293
+ type ZodResponseDescription = string | {
294
+ description: string;
295
+ headers?: Record<string, unknown>;
296
+ links?: Record<string, unknown>;
297
+ };
298
+ /**
299
+ * One variant record per `@ZodResponse(...)` call. `dto` is kept alongside
300
+ * `validationSchema` so Phase 2e can emit `@ApiResponse({ type })` without
301
+ * unwrapping the runtime-only `z.array(...)` / `z.tuple([...])` wrapper.
302
+ *
303
+ * `status` is `undefined` when the user didn't pass one explicitly — the
304
+ * effective status is resolved lazily by `resolveEffectiveStatus(variant,
305
+ * handler)` because `@ZodResponse` runs *before* NestJS' route decorators
306
+ * (`@Get`, `@Post`, ...) under TypeScript's bottom-up application order,
307
+ * so `METHOD_METADATA` is not yet set when the decorator evaluates.
308
+ */
309
+ interface ResponseVariant {
310
+ status: number | undefined;
311
+ kind: ResponseVariantKind;
312
+ dto: ZodDto | readonly ZodDto[];
313
+ validationSchema: z.ZodType;
314
+ description?: ZodResponseDescription;
315
+ passthroughOnError: boolean;
316
+ }
317
+
318
+ /**
319
+ * Accepted shapes for `@ZodResponse({ type })`:
320
+ * - `Dto` → validates as `Dto.schema` (single-DTO response).
321
+ * - `[Dto]` (length 1) → validates as `z.array(Dto.schema)`; matches Nest's
322
+ * `@ApiResponse({ isArray: true })` convention without minting a separate
323
+ * `*sDto` id.
324
+ * - `[A, B, ...]` (length ≥ 2) → validates as `z.tuple([A.schema, B.schema, ...])`;
325
+ * surfaces as an OpenAPI 3.1 `prefixItems` tuple in Phase 2e.
326
+ *
327
+ * Empty arrays and non-DTO elements throw `TypeError` at decoration time
328
+ * so typos surface at module load, not the first request.
329
+ */
330
+ type ZodResponseType = ZodDto | readonly [ZodDto, ...ZodDto[]];
331
+ interface ZodResponseOptions {
332
+ status?: number;
333
+ type: ZodResponseType;
334
+ description?: ZodResponseDescription;
335
+ passthroughOnError?: boolean;
336
+ }
337
+ /**
338
+ * Method-only decorator. Declares a typed response variant for the handler.
339
+ * Stack multiple decorations to declare per-status types; lookup at runtime
340
+ * is by `response.statusCode === variant.status`.
341
+ *
342
+ * The wrapped Zod schema (array / tuple) is built once at decoration time
343
+ * and stored on the variant record — no per-request schema construction.
344
+ */
345
+ declare const ZodResponse: (opts: ZodResponseOptions) => MethodDecorator;
346
+
347
+ declare class ZodSerializerInterceptor implements NestInterceptor {
348
+ private readonly reflector;
349
+ private readonly logOutputFailure;
350
+ private readonly createSerializationException;
351
+ constructor(reflector: Reflector, options?: NormalizedZodNestOptions);
352
+ intercept(context: ExecutionContext, next: CallHandler): Observable<unknown>;
353
+ private transform;
354
+ }
355
+
356
+ /**
357
+ * Compute the default HTTP status code for a handler when `@ZodResponse(...)`
358
+ * is invoked without an explicit `status`. Lookup order (highest → lowest):
359
+ *
360
+ * 1. `@HttpCode(n)` on the handler — explicit per-handler status override.
361
+ * NestJS sets `HTTP_CODE_METADATA` to the numeric status when present.
362
+ * 2. HTTP method default — `POST` → `201`, everything else → `200`.
363
+ *
364
+ * The method default itself falls back to `200` when `METHOD_METADATA` is
365
+ * absent — pinned by tests so a future NestJS rename surfaces as a test
366
+ * failure rather than a silent regression.
367
+ */
368
+ declare const defaultStatusFor: (handler: object) => number;
369
+ /**
370
+ * Resolve the effective status code for a variant. Precedence chain:
371
+ *
372
+ * 1. Explicit `@ZodResponse({ status })` on the decorator call — `variant.status`.
373
+ * 2. `@HttpCode(n)` on the handler — read via `defaultStatusFor()` at runtime.
374
+ * 3. HTTP method default (POST → 201, others → 200) — also via `defaultStatusFor()`.
375
+ *
376
+ * Resolution is deferred to request time because `@ZodResponse` runs before
377
+ * NestJS' route + `@HttpCode` decorators — none of their metadata is set
378
+ * when the decorator evaluates.
379
+ */
380
+ declare const resolveEffectiveStatus: (variant: ResponseVariant, handler: object) => number;
381
+
382
+ /**
383
+ * Central wiring for the zod-nest pipe + interceptor. Call
384
+ * `ZodNestModule.forRoot(options?)` from your root `AppModule` to register
385
+ * `APP_PIPE` (`ZodValidationPipe`) and `APP_INTERCEPTOR`
386
+ * (`ZodSerializerInterceptor`) globally, with shared options for
387
+ * validation logging, redaction, and exception factories.
388
+ *
389
+ * `forRoot()` is optional — the pipe and interceptor also work as
390
+ * regular `APP_PIPE` / `APP_INTERCEPTOR` providers if you prefer to
391
+ * wire them manually; `@Optional()` injection of `ZOD_NEST_OPTIONS`
392
+ * falls through to safe defaults.
393
+ *
394
+ * Marked `global` so the `ZOD_NEST_OPTIONS` token is injectable from
395
+ * feature modules (e.g. a custom pipe that wants the same logger /
396
+ * redact list as the module-wired one).
397
+ */
398
+ declare class ZodNestModule {
399
+ static forRoot(options?: ZodNestModuleOptions): DynamicModule;
400
+ }
401
+
402
+ export { 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, ZodNestError, ZodNestModule, type ZodNestModuleOptions, type ZodNestRegistry, ZodNestUnrepresentableError, ZodResponse, type ZodResponseDescription, type ZodResponseOptions, type ZodResponseType, ZodSerializationException, ZodSerializerInterceptor, ZodValidationException, ZodValidationPipe, type ZodValidationPipeArg, type ZodValidationPipeOptions, createRegistry, createZodDto, defaultRegistry, defaultStatusFor, isZodDto, isZodDtoMarker, makeZodDtoMarker, resolveEffectiveStatus, toOpenApi };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,8 @@
1
1
  import { z } from 'zod';
2
2
  import { JSONSchema, $ZodTypes } from 'zod/v4/core';
3
+ import { InternalServerErrorException, ExecutionContext, BadRequestException, ArgumentMetadata, LoggerService, PipeTransform, NestInterceptor, CallHandler, DynamicModule } from '@nestjs/common';
4
+ import { Reflector } from '@nestjs/core';
5
+ import { Observable } from 'rxjs';
3
6
 
4
7
  /** OpenAPI 3.1 `$ref` prefix for entries in `components.schemas`. */
5
8
  declare const COMPONENTS_SCHEMAS_PREFIX = "#/components/schemas/";
@@ -115,4 +118,285 @@ declare const makeZodDtoMarker: (dtoId: string, io: Io) => ZodDtoMarker;
115
118
  /** Phase 2e (and tests) use this to discriminate a marker from a real schema. */
116
119
  declare const isZodDtoMarker: (value: unknown) => value is ZodDtoMarker;
117
120
 
118
- export { COMPONENTS_SCHEMAS_PREFIX, type CreateZodDtoOptions, type Io, type Override, type OverrideContext, type SchemaObject, type ToOpenApiOptions, type ToOpenApiResult, ZOD_DTO_SYMBOL, ZOD_NEST_DTO_EXTENSION, ZOD_NEST_ERROR_DUPLICATE_ID, ZOD_NEST_ERROR_EXTENSION, type ZodDto, type ZodDtoMarker, ZodNestError, type ZodNestRegistry, ZodNestUnrepresentableError, createRegistry, createZodDto, defaultRegistry, isZodDtoMarker, makeZodDtoMarker, toOpenApi };
121
+ /**
122
+ * Runtime guard: is `value` a class returned by `createZodDto`?
123
+ *
124
+ * Used by the validation pipe (Phase 2c), the serializer interceptor (2d),
125
+ * and the doc merger (2e) to discriminate zod-nest DTOs from plain
126
+ * constructors, class-validator DTOs, primitives, and any other metatypes
127
+ * NestJS exposes via `ArgumentMetadata`.
128
+ */
129
+ declare const isZodDto: (value: unknown) => value is ZodDto;
130
+
131
+ /**
132
+ * Default exception thrown by `ZodSerializerInterceptor` in strict mode
133
+ * (i.e. when `@ZodResponse({ passthroughOnError: true })` is NOT set) on
134
+ * response-validation failure.
135
+ *
136
+ * Body shape (returned by `getResponse()`):
137
+ * ```
138
+ * {
139
+ * statusCode: 500,
140
+ * message: 'Response validation failed',
141
+ * errors: z.treeifyError(zodError),
142
+ * }
143
+ * ```
144
+ *
145
+ * Carries `zodError` and `executionContext` so custom exception filters
146
+ * can introspect the original validation failure and the request that
147
+ * produced it.
148
+ */
149
+ declare class ZodSerializationException extends InternalServerErrorException {
150
+ readonly zodError: z.ZodError;
151
+ readonly executionContext?: ExecutionContext;
152
+ constructor(zodError: z.ZodError, executionContext?: ExecutionContext);
153
+ }
154
+
155
+ /**
156
+ * Default exception thrown by `ZodValidationPipe` when input fails to parse.
157
+ *
158
+ * Body shape (returned by `getResponse()`):
159
+ * ```
160
+ * {
161
+ * statusCode: 400,
162
+ * message: 'Validation failed',
163
+ * errors: z.treeifyError(zodError),
164
+ * }
165
+ * ```
166
+ *
167
+ * Carries `zodError` and `argMetadata` so custom exception filters can
168
+ * introspect the original validation failure.
169
+ */
170
+ declare class ZodValidationException extends BadRequestException {
171
+ readonly zodError: z.ZodError;
172
+ readonly argMetadata?: ArgumentMetadata;
173
+ constructor(zodError: z.ZodError, argMetadata?: ArgumentMetadata);
174
+ }
175
+
176
+ interface ValidationLogContext {
177
+ /** Which side of the request emitted the failure. */
178
+ side: 'input' | 'output';
179
+ /** Severity to log at; the formatter does not decide this. */
180
+ severity: 'warn' | 'error';
181
+ /** Pre-formatted DTO label, e.g. `'UserDto'`, `'[UserDto]'`, `'[A, B]'`. */
182
+ dto: string;
183
+ /** Output side only — HTTP response status code. */
184
+ status?: number;
185
+ /** Output side only — `Controller.method` best-effort. */
186
+ handler?: string;
187
+ /** Input side only — `body` / `query` / `param` / `custom`. */
188
+ argType?: string;
189
+ }
190
+ type LogValidationFailure = (err: z.ZodError, value: unknown, ctx: ValidationLogContext) => void;
191
+
192
+ /**
193
+ * Module-scope factory for the exception thrown by `ZodValidationPipe` on
194
+ * input validation failure. Mirrors the existing per-pipe option but lives
195
+ * at module scope; per-instance constructor arg wins.
196
+ */
197
+ type CreateValidationException$1 = (err: z.ZodError, argMetadata: ArgumentMetadata) => unknown;
198
+ /**
199
+ * Module-scope factory for the exception thrown by `ZodSerializerInterceptor`
200
+ * on output validation failure (strict mode only). Soft mode never calls
201
+ * this factory.
202
+ */
203
+ type CreateSerializationException = (err: z.ZodError, executionContext: ExecutionContext) => unknown;
204
+ /** Public options accepted by `ZodNestModule.forRoot()`. */
205
+ interface ZodNestModuleOptions {
206
+ createValidationException?: CreateValidationException$1;
207
+ createSerializationException?: CreateSerializationException;
208
+ /**
209
+ * Failure-only validation logging. `true` enables both input and output;
210
+ * the granular form lets each side be toggled independently. Default: off.
211
+ */
212
+ validationLogs?: boolean | {
213
+ input?: boolean;
214
+ output?: boolean;
215
+ };
216
+ /** Override Nest's built-in `Logger` (e.g. pino/winston adapter). */
217
+ logger?: LoggerService;
218
+ /**
219
+ * Keys whose values get scrubbed from logged input/response objects.
220
+ * Matched case-insensitively at any depth. Supplying this option
221
+ * REPLACES the default list (no merge).
222
+ */
223
+ redactKeys?: readonly string[];
224
+ /**
225
+ * Maximum size in bytes (UTF-8) for any single logged value. Oversized
226
+ * values become `{ _truncated: true, _originalBytes, _preview }`.
227
+ */
228
+ maxLoggedValueBytes?: number;
229
+ }
230
+ /**
231
+ * Resolved options consumed by pipe + interceptor. `forRoot()` builds this
232
+ * once and stuffs it into a provider for the `ZOD_NEST_OPTIONS` injection
233
+ * token; downstream code never re-checks the raw `validationLogs` flag.
234
+ */
235
+ interface NormalizedZodNestOptions {
236
+ createValidationException: CreateValidationException$1 | undefined;
237
+ createSerializationException: CreateSerializationException | undefined;
238
+ /** No-op when `validationLogs.input` resolved to false. */
239
+ logInputFailure: LogValidationFailure;
240
+ /** No-op when `validationLogs.output` resolved to false. */
241
+ logOutputFailure: LogValidationFailure;
242
+ }
243
+ declare const DEFAULT_REDACT_KEYS: readonly string[];
244
+ declare const DEFAULT_MAX_LOGGED_VALUE_BYTES = 4096;
245
+ /** DI token for `NormalizedZodNestOptions`. */
246
+ declare const ZOD_NEST_OPTIONS: unique symbol;
247
+
248
+ /**
249
+ * Build the exception thrown by `ZodValidationPipe` on validation failure.
250
+ * Receives Zod's error and the NestJS argument metadata; returns anything
251
+ * `throw`-able (typically a NestJS `HttpException` subclass).
252
+ */
253
+ type CreateValidationException = (zodError: z.ZodError, argMetadata: ArgumentMetadata) => unknown;
254
+ interface ZodValidationPipeOptions {
255
+ schema?: z.ZodType | ZodDto;
256
+ createValidationException?: CreateValidationException;
257
+ }
258
+ /**
259
+ * Constructor input for `ZodValidationPipe`. Discriminated at runtime:
260
+ * - `undefined` → metatype-driven (read DTO from handler arg's metatype)
261
+ * - a class with `[ZOD_DTO_SYMBOL]` → explicit DTO
262
+ * - a Zod schema (has `_zod` internals) → raw schema
263
+ * - anything else → options object
264
+ */
265
+ type ZodValidationPipeArg = z.ZodType | ZodDto | ZodValidationPipeOptions;
266
+
267
+ declare class ZodValidationPipe implements PipeTransform {
268
+ private readonly explicitSchema;
269
+ private readonly explicitDtoName;
270
+ private readonly createValidationException;
271
+ private readonly logInputFailure;
272
+ constructor(arg?: ZodValidationPipeArg, moduleOptions?: NormalizedZodNestOptions);
273
+ transform(value: unknown, metadata: ArgumentMetadata): Promise<unknown>;
274
+ private resolveSchema;
275
+ private resolveDtoLabel;
276
+ private static parseArg;
277
+ }
278
+
279
+ /**
280
+ * Public metadata key for the array of `ResponseVariant` records attached
281
+ * to handler methods by `@ZodResponse(...)`. Symbol.for() so external
282
+ * consumers (e.g. custom interceptors or doc builders) can read the same
283
+ * registry across realms.
284
+ */
285
+ declare const ZOD_RESPONSES_METADATA_KEY: unique symbol;
286
+ type ResponseVariantKind = 'single' | 'array' | 'tuple';
287
+ /**
288
+ * Description payload accepted by `@ZodResponse(...)` and passed through to
289
+ * Phase 2e's `@ApiResponse(...)` emitter. String form is shorthand for
290
+ * `{ description }`; the object form lets users declare OpenAPI response
291
+ * `headers` / `links` alongside the description.
292
+ */
293
+ type ZodResponseDescription = string | {
294
+ description: string;
295
+ headers?: Record<string, unknown>;
296
+ links?: Record<string, unknown>;
297
+ };
298
+ /**
299
+ * One variant record per `@ZodResponse(...)` call. `dto` is kept alongside
300
+ * `validationSchema` so Phase 2e can emit `@ApiResponse({ type })` without
301
+ * unwrapping the runtime-only `z.array(...)` / `z.tuple([...])` wrapper.
302
+ *
303
+ * `status` is `undefined` when the user didn't pass one explicitly — the
304
+ * effective status is resolved lazily by `resolveEffectiveStatus(variant,
305
+ * handler)` because `@ZodResponse` runs *before* NestJS' route decorators
306
+ * (`@Get`, `@Post`, ...) under TypeScript's bottom-up application order,
307
+ * so `METHOD_METADATA` is not yet set when the decorator evaluates.
308
+ */
309
+ interface ResponseVariant {
310
+ status: number | undefined;
311
+ kind: ResponseVariantKind;
312
+ dto: ZodDto | readonly ZodDto[];
313
+ validationSchema: z.ZodType;
314
+ description?: ZodResponseDescription;
315
+ passthroughOnError: boolean;
316
+ }
317
+
318
+ /**
319
+ * Accepted shapes for `@ZodResponse({ type })`:
320
+ * - `Dto` → validates as `Dto.schema` (single-DTO response).
321
+ * - `[Dto]` (length 1) → validates as `z.array(Dto.schema)`; matches Nest's
322
+ * `@ApiResponse({ isArray: true })` convention without minting a separate
323
+ * `*sDto` id.
324
+ * - `[A, B, ...]` (length ≥ 2) → validates as `z.tuple([A.schema, B.schema, ...])`;
325
+ * surfaces as an OpenAPI 3.1 `prefixItems` tuple in Phase 2e.
326
+ *
327
+ * Empty arrays and non-DTO elements throw `TypeError` at decoration time
328
+ * so typos surface at module load, not the first request.
329
+ */
330
+ type ZodResponseType = ZodDto | readonly [ZodDto, ...ZodDto[]];
331
+ interface ZodResponseOptions {
332
+ status?: number;
333
+ type: ZodResponseType;
334
+ description?: ZodResponseDescription;
335
+ passthroughOnError?: boolean;
336
+ }
337
+ /**
338
+ * Method-only decorator. Declares a typed response variant for the handler.
339
+ * Stack multiple decorations to declare per-status types; lookup at runtime
340
+ * is by `response.statusCode === variant.status`.
341
+ *
342
+ * The wrapped Zod schema (array / tuple) is built once at decoration time
343
+ * and stored on the variant record — no per-request schema construction.
344
+ */
345
+ declare const ZodResponse: (opts: ZodResponseOptions) => MethodDecorator;
346
+
347
+ declare class ZodSerializerInterceptor implements NestInterceptor {
348
+ private readonly reflector;
349
+ private readonly logOutputFailure;
350
+ private readonly createSerializationException;
351
+ constructor(reflector: Reflector, options?: NormalizedZodNestOptions);
352
+ intercept(context: ExecutionContext, next: CallHandler): Observable<unknown>;
353
+ private transform;
354
+ }
355
+
356
+ /**
357
+ * Compute the default HTTP status code for a handler when `@ZodResponse(...)`
358
+ * is invoked without an explicit `status`. Lookup order (highest → lowest):
359
+ *
360
+ * 1. `@HttpCode(n)` on the handler — explicit per-handler status override.
361
+ * NestJS sets `HTTP_CODE_METADATA` to the numeric status when present.
362
+ * 2. HTTP method default — `POST` → `201`, everything else → `200`.
363
+ *
364
+ * The method default itself falls back to `200` when `METHOD_METADATA` is
365
+ * absent — pinned by tests so a future NestJS rename surfaces as a test
366
+ * failure rather than a silent regression.
367
+ */
368
+ declare const defaultStatusFor: (handler: object) => number;
369
+ /**
370
+ * Resolve the effective status code for a variant. Precedence chain:
371
+ *
372
+ * 1. Explicit `@ZodResponse({ status })` on the decorator call — `variant.status`.
373
+ * 2. `@HttpCode(n)` on the handler — read via `defaultStatusFor()` at runtime.
374
+ * 3. HTTP method default (POST → 201, others → 200) — also via `defaultStatusFor()`.
375
+ *
376
+ * Resolution is deferred to request time because `@ZodResponse` runs before
377
+ * NestJS' route + `@HttpCode` decorators — none of their metadata is set
378
+ * when the decorator evaluates.
379
+ */
380
+ declare const resolveEffectiveStatus: (variant: ResponseVariant, handler: object) => number;
381
+
382
+ /**
383
+ * Central wiring for the zod-nest pipe + interceptor. Call
384
+ * `ZodNestModule.forRoot(options?)` from your root `AppModule` to register
385
+ * `APP_PIPE` (`ZodValidationPipe`) and `APP_INTERCEPTOR`
386
+ * (`ZodSerializerInterceptor`) globally, with shared options for
387
+ * validation logging, redaction, and exception factories.
388
+ *
389
+ * `forRoot()` is optional — the pipe and interceptor also work as
390
+ * regular `APP_PIPE` / `APP_INTERCEPTOR` providers if you prefer to
391
+ * wire them manually; `@Optional()` injection of `ZOD_NEST_OPTIONS`
392
+ * falls through to safe defaults.
393
+ *
394
+ * Marked `global` so the `ZOD_NEST_OPTIONS` token is injectable from
395
+ * feature modules (e.g. a custom pipe that wants the same logger /
396
+ * redact list as the module-wired one).
397
+ */
398
+ declare class ZodNestModule {
399
+ static forRoot(options?: ZodNestModuleOptions): DynamicModule;
400
+ }
401
+
402
+ export { 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, ZodNestError, ZodNestModule, type ZodNestModuleOptions, type ZodNestRegistry, ZodNestUnrepresentableError, ZodResponse, type ZodResponseDescription, type ZodResponseOptions, type ZodResponseType, ZodSerializationException, ZodSerializerInterceptor, ZodValidationException, ZodValidationPipe, type ZodValidationPipeArg, type ZodValidationPipeOptions, createRegistry, createZodDto, defaultRegistry, defaultStatusFor, isZodDto, isZodDtoMarker, makeZodDtoMarker, resolveEffectiveStatus, toOpenApi };