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 +227 -3
- package/dist/index.d.ts +227 -3
- package/dist/index.js +338 -10
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +331 -12
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -1
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 };
|