zod-nest 0.3.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,6 +1,8 @@
1
1
  import { z } from 'zod';
2
2
  import { JSONSchema, $ZodTypes } from 'zod/v4/core';
3
- import { BadRequestException, ArgumentMetadata, PipeTransform } from '@nestjs/common';
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';
4
6
 
5
7
  /** OpenAPI 3.1 `$ref` prefix for entries in `components.schemas`. */
6
8
  declare const COMPONENTS_SCHEMAS_PREFIX = "#/components/schemas/";
@@ -126,6 +128,30 @@ declare const isZodDtoMarker: (value: unknown) => value is ZodDtoMarker;
126
128
  */
127
129
  declare const isZodDto: (value: unknown) => value is ZodDto;
128
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
+
129
155
  /**
130
156
  * Default exception thrown by `ZodValidationPipe` when input fails to parse.
131
157
  *
@@ -147,6 +173,78 @@ declare class ZodValidationException extends BadRequestException {
147
173
  constructor(zodError: z.ZodError, argMetadata?: ArgumentMetadata);
148
174
  }
149
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
+
150
248
  /**
151
249
  * Build the exception thrown by `ZodValidationPipe` on validation failure.
152
250
  * Receives Zod's error and the NestJS argument metadata; returns anything
@@ -168,11 +266,137 @@ type ZodValidationPipeArg = z.ZodType | ZodDto | ZodValidationPipeOptions;
168
266
 
169
267
  declare class ZodValidationPipe implements PipeTransform {
170
268
  private readonly explicitSchema;
269
+ private readonly explicitDtoName;
171
270
  private readonly createValidationException;
172
- constructor(arg?: ZodValidationPipeArg);
271
+ private readonly logInputFailure;
272
+ constructor(arg?: ZodValidationPipeArg, moduleOptions?: NormalizedZodNestOptions);
173
273
  transform(value: unknown, metadata: ArgumentMetadata): Promise<unknown>;
174
274
  private resolveSchema;
275
+ private resolveDtoLabel;
175
276
  private static parseArg;
176
277
  }
177
278
 
178
- export { COMPONENTS_SCHEMAS_PREFIX, type CreateValidationException, 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, ZodValidationException, ZodValidationPipe, type ZodValidationPipeArg, type ZodValidationPipeOptions, createRegistry, createZodDto, defaultRegistry, isZodDto, isZodDtoMarker, makeZodDtoMarker, toOpenApi };
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,6 +1,8 @@
1
1
  import { z } from 'zod';
2
2
  import { JSONSchema, $ZodTypes } from 'zod/v4/core';
3
- import { BadRequestException, ArgumentMetadata, PipeTransform } from '@nestjs/common';
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';
4
6
 
5
7
  /** OpenAPI 3.1 `$ref` prefix for entries in `components.schemas`. */
6
8
  declare const COMPONENTS_SCHEMAS_PREFIX = "#/components/schemas/";
@@ -126,6 +128,30 @@ declare const isZodDtoMarker: (value: unknown) => value is ZodDtoMarker;
126
128
  */
127
129
  declare const isZodDto: (value: unknown) => value is ZodDto;
128
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
+
129
155
  /**
130
156
  * Default exception thrown by `ZodValidationPipe` when input fails to parse.
131
157
  *
@@ -147,6 +173,78 @@ declare class ZodValidationException extends BadRequestException {
147
173
  constructor(zodError: z.ZodError, argMetadata?: ArgumentMetadata);
148
174
  }
149
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
+
150
248
  /**
151
249
  * Build the exception thrown by `ZodValidationPipe` on validation failure.
152
250
  * Receives Zod's error and the NestJS argument metadata; returns anything
@@ -168,11 +266,137 @@ type ZodValidationPipeArg = z.ZodType | ZodDto | ZodValidationPipeOptions;
168
266
 
169
267
  declare class ZodValidationPipe implements PipeTransform {
170
268
  private readonly explicitSchema;
269
+ private readonly explicitDtoName;
171
270
  private readonly createValidationException;
172
- constructor(arg?: ZodValidationPipeArg);
271
+ private readonly logInputFailure;
272
+ constructor(arg?: ZodValidationPipeArg, moduleOptions?: NormalizedZodNestOptions);
173
273
  transform(value: unknown, metadata: ArgumentMetadata): Promise<unknown>;
174
274
  private resolveSchema;
275
+ private resolveDtoLabel;
175
276
  private static parseArg;
176
277
  }
177
278
 
178
- export { COMPONENTS_SCHEMAS_PREFIX, type CreateValidationException, 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, ZodValidationException, ZodValidationPipe, type ZodValidationPipeArg, type ZodValidationPipeOptions, createRegistry, createZodDto, defaultRegistry, isZodDto, isZodDtoMarker, makeZodDtoMarker, toOpenApi };
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 };