@nestjs/common 11.2.4 → 11.2.6
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/interfaces/http/cookie-options.interface.d.ts +79 -0
- package/interfaces/http/cookie-options.interface.js +1 -0
- package/interfaces/http/csrf-protection-options.interface.d.ts +47 -0
- package/interfaces/http/csrf-protection-options.interface.js +1 -0
- package/interfaces/http/security-headers-options.interface.d.ts +142 -0
- package/interfaces/http/security-headers-options.interface.js +1 -0
- package/interfaces/microservices/pre-request-hook.interface.d.ts +22 -0
- package/interfaces/microservices/pre-request-hook.interface.js +1 -0
- package/interfaces/microservices/transport-server.interface.d.ts +18 -0
- package/interfaces/microservices/transport-server.interface.js +1 -0
- package/interfaces/router-options.interface.d.ts +28 -0
- package/interfaces/router-options.interface.js +1 -0
- package/internal.d.ts +31 -0
- package/internal.js +20 -0
- package/package.json +2 -2
- package/pipes/standard-schema-validation.pipe.d.ts +88 -0
- package/pipes/standard-schema-validation.pipe.js +106 -0
- package/serializer/standard-schema-serializer.interceptor.d.ts +50 -0
- package/serializer/standard-schema-serializer.interceptor.js +75 -0
- package/serializer/standard-schema-serializer.interfaces.d.ts +18 -0
- package/serializer/standard-schema-serializer.interfaces.js +1 -0
- package/utils/parameter-decorator-options.util.d.ts +13 -0
- package/utils/parameter-decorator-options.util.js +22 -0
- package/utils/strip-proto-keys.util.d.ts +5 -0
- package/utils/strip-proto-keys.util.js +36 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Attributes of a `Set-Cookie` header written by `HttpServer.setCookie()` and
|
|
3
|
+
* `HttpServer.clearCookie()`.
|
|
4
|
+
*
|
|
5
|
+
* @see [RFC 6265, section 4.1](https://datatracker.ietf.org/doc/html/rfc6265#section-4.1)
|
|
6
|
+
*
|
|
7
|
+
* @publicApi
|
|
8
|
+
*/
|
|
9
|
+
export interface CookieSerializeOptions {
|
|
10
|
+
/**
|
|
11
|
+
* `Path` attribute.
|
|
12
|
+
*
|
|
13
|
+
* @default '/'
|
|
14
|
+
*/
|
|
15
|
+
path?: string;
|
|
16
|
+
/**
|
|
17
|
+
* `Domain` attribute. Omitted by default, which makes the cookie host-only.
|
|
18
|
+
*/
|
|
19
|
+
domain?: string;
|
|
20
|
+
/**
|
|
21
|
+
* `Max-Age` attribute, in **seconds**, as in RFC 6265 and `@fastify/cookie`.
|
|
22
|
+
* Must be an integer.
|
|
23
|
+
*
|
|
24
|
+
* **Not milliseconds**: Express' `res.cookie()` takes `maxAge` in
|
|
25
|
+
* milliseconds, so a value carried over from it would make the cookie live
|
|
26
|
+
* 1000 times longer. For one day, pass `60 * 60 * 24`.
|
|
27
|
+
*/
|
|
28
|
+
maxAge?: number;
|
|
29
|
+
/**
|
|
30
|
+
* `Expires` attribute. Browsers give precedence to `maxAge` when both are
|
|
31
|
+
* set.
|
|
32
|
+
*/
|
|
33
|
+
expires?: Date;
|
|
34
|
+
/**
|
|
35
|
+
* `HttpOnly` attribute.
|
|
36
|
+
*/
|
|
37
|
+
httpOnly?: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* `Secure` attribute.
|
|
40
|
+
*/
|
|
41
|
+
secure?: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* `SameSite` attribute. `'none'` requires `secure: true`, since browsers
|
|
44
|
+
* reject `SameSite=None` cookies that are not `Secure`.
|
|
45
|
+
*/
|
|
46
|
+
sameSite?: 'strict' | 'lax' | 'none';
|
|
47
|
+
/**
|
|
48
|
+
* `Partitioned` attribute (CHIPS). Requires `secure: true`, since browsers
|
|
49
|
+
* reject partitioned cookies that are not `Secure`.
|
|
50
|
+
*/
|
|
51
|
+
partitioned?: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* `Priority` attribute (non-standard, honored by Chromium).
|
|
54
|
+
*/
|
|
55
|
+
priority?: 'low' | 'medium' | 'high';
|
|
56
|
+
/**
|
|
57
|
+
* Whether to sign the value with the first secret configured through the
|
|
58
|
+
* `cookies.secret` application option. Signed cookies are read with the
|
|
59
|
+
* `@SignedCookies()` decorator.
|
|
60
|
+
*
|
|
61
|
+
* @default false
|
|
62
|
+
*/
|
|
63
|
+
signed?: boolean;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* The `cookies` option of `NestFactory.create()`.
|
|
67
|
+
*
|
|
68
|
+
* @publicApi
|
|
69
|
+
*/
|
|
70
|
+
export interface CookiesOptions {
|
|
71
|
+
/**
|
|
72
|
+
* Secret (or secrets) used to sign and verify cookies. When an array is
|
|
73
|
+
* given, cookies are signed with the first secret and verified against all
|
|
74
|
+
* of them, which allows rotating secrets without invalidating cookies
|
|
75
|
+
* signed with a previous one. An empty string, an empty array or an empty
|
|
76
|
+
* entry throws when the application is created.
|
|
77
|
+
*/
|
|
78
|
+
secret?: string | string[];
|
|
79
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { RouteInfo } from '../middleware/middleware-configuration.interface.js';
|
|
2
|
+
/**
|
|
3
|
+
* Options for `app.enableCsrfProtection()`.
|
|
4
|
+
*
|
|
5
|
+
* The protection is based on Fetch Metadata (`Sec-Fetch-Site`) with an
|
|
6
|
+
* `Origin`/`Host` fallback, following the algorithm of Go's
|
|
7
|
+
* `net/http.CrossOriginProtection`. It is not a token scheme: it relies on the
|
|
8
|
+
* browser telling the server where a request comes from, which every
|
|
9
|
+
* evergreen browser does since 2023.
|
|
10
|
+
*
|
|
11
|
+
* Browsers only send `Sec-Fetch-Site` to secure origins (HTTPS or
|
|
12
|
+
* `localhost`). Otherwise the `Origin` header is compared with the `Host`
|
|
13
|
+
* header the server receives (`X-Forwarded-Host` is ignored). Behind a proxy
|
|
14
|
+
* that rewrites `Host`, preserve it, or list the public origin in
|
|
15
|
+
* `trustedOrigins`.
|
|
16
|
+
*
|
|
17
|
+
* @publicApi
|
|
18
|
+
*/
|
|
19
|
+
export interface CsrfProtectionOptions<TRequest = any> {
|
|
20
|
+
/**
|
|
21
|
+
* Origins that may send cross-origin, state-changing requests, e.g.
|
|
22
|
+
* `https://admin.example.com`. Each entry must be a serialized origin:
|
|
23
|
+
* `scheme://host[:port]`, without a path, query string, fragment or
|
|
24
|
+
* wildcard. Entries are normalized the way browsers serialize `Origin`
|
|
25
|
+
* (lower-case, without the default port), and a request is exempt when its
|
|
26
|
+
* `Origin` header equals one of them.
|
|
27
|
+
*
|
|
28
|
+
* Origins allowed by CORS are not trusted implicitly: list them here too.
|
|
29
|
+
*/
|
|
30
|
+
trustedOrigins?: string[];
|
|
31
|
+
/**
|
|
32
|
+
* Requests that skip the protection altogether (for example webhook
|
|
33
|
+
* endpoints called by third-party servers that send a foreign `Origin`).
|
|
34
|
+
*
|
|
35
|
+
* Either a list of routes, or a predicate receiving the platform request
|
|
36
|
+
* object. Only consulted for requests that would otherwise be rejected.
|
|
37
|
+
*
|
|
38
|
+
* Routes are declared like `MiddlewareConsumer.exclude()`: a path, or
|
|
39
|
+
* `{ path, method, version? }` to narrow by method (and URI version),
|
|
40
|
+
* without the global prefix, which is added unless the route is excluded
|
|
41
|
+
* from it. Unlike `exclude()`, the match is exact: case-sensitive, without
|
|
42
|
+
* an optional trailing slash, and never for non-canonical request paths
|
|
43
|
+
* (`//`, dot segments, `;`, encoded `/` or `.`), which a router could
|
|
44
|
+
* resolve to a route that is not excluded.
|
|
45
|
+
*/
|
|
46
|
+
exclude?: (string | RouteInfo)[] | ((request: TRequest) => boolean);
|
|
47
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Value of a Content-Security-Policy directive:
|
|
3
|
+
*
|
|
4
|
+
* - a string or a list of strings: the directive's source expressions
|
|
5
|
+
* (keywords must be quoted, e.g. `"'self'"`);
|
|
6
|
+
* - `true` or an empty list: a directive without value (e.g.
|
|
7
|
+
* `upgrade-insecure-requests`);
|
|
8
|
+
* - `null` or `false`: removes the directive, including a default one.
|
|
9
|
+
*
|
|
10
|
+
* @publicApi
|
|
11
|
+
*/
|
|
12
|
+
export type ContentSecurityPolicyDirectiveValue = string | readonly string[] | boolean | null;
|
|
13
|
+
/**
|
|
14
|
+
* @publicApi
|
|
15
|
+
*/
|
|
16
|
+
export interface ContentSecurityPolicyOptions {
|
|
17
|
+
/**
|
|
18
|
+
* Whether `directives` are merged into the default directives. When
|
|
19
|
+
* `false`, only `directives` are sent, and they must include `default-src`
|
|
20
|
+
* (or remove it explicitly with `defaultSrc: null`).
|
|
21
|
+
*
|
|
22
|
+
* @default true
|
|
23
|
+
*/
|
|
24
|
+
useDefaults?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Directives keyed by name, in camelCase (`scriptSrc`) or kebab-case
|
|
27
|
+
* (`'script-src'`). A directive given here replaces the default directive
|
|
28
|
+
* of the same name.
|
|
29
|
+
*/
|
|
30
|
+
directives?: Record<string, ContentSecurityPolicyDirectiveValue>;
|
|
31
|
+
/**
|
|
32
|
+
* Sends `Content-Security-Policy-Report-Only` instead, so violations are
|
|
33
|
+
* reported (see the `report-to` directive) but not blocked.
|
|
34
|
+
*
|
|
35
|
+
* @default false
|
|
36
|
+
*/
|
|
37
|
+
reportOnly?: boolean;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Options for `app.useSecurityHeaders()`.
|
|
41
|
+
*
|
|
42
|
+
* Each key controls one header and accepts `false` to leave that header out,
|
|
43
|
+
* `true` for its default value (the same defaults as helmet 8), or an object
|
|
44
|
+
* to configure it. Option names match helmet's, so existing helmet
|
|
45
|
+
* configurations carry over, except for helmet's legacy aliases (`hsts`,
|
|
46
|
+
* `frameguard`, ...). Unknown options are rejected.
|
|
47
|
+
*
|
|
48
|
+
* @publicApi
|
|
49
|
+
*/
|
|
50
|
+
export interface SecurityHeadersOptions {
|
|
51
|
+
/**
|
|
52
|
+
* `Content-Security-Policy`. Default: `default-src 'self'; base-uri 'self';
|
|
53
|
+
* font-src 'self' https: data:; form-action 'self'; frame-ancestors 'self';
|
|
54
|
+
* img-src 'self' data:; object-src 'none'; script-src 'self';
|
|
55
|
+
* script-src-attr 'none'; style-src 'self' https: 'unsafe-inline';
|
|
56
|
+
* upgrade-insecure-requests` (serialized without spaces after `;`).
|
|
57
|
+
*/
|
|
58
|
+
contentSecurityPolicy?: boolean | ContentSecurityPolicyOptions;
|
|
59
|
+
/**
|
|
60
|
+
* `Cross-Origin-Embedder-Policy`. Not sent by default; `true` sends
|
|
61
|
+
* `require-corp`.
|
|
62
|
+
*/
|
|
63
|
+
crossOriginEmbedderPolicy?: boolean | {
|
|
64
|
+
policy?: 'require-corp' | 'credentialless' | 'unsafe-none';
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* `Cross-Origin-Opener-Policy`. Default: `same-origin`.
|
|
68
|
+
*/
|
|
69
|
+
crossOriginOpenerPolicy?: boolean | {
|
|
70
|
+
policy?: 'same-origin' | 'same-origin-allow-popups' | 'noopener-allow-popups' | 'unsafe-none';
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* `Cross-Origin-Resource-Policy`. Default: `same-origin`.
|
|
74
|
+
*/
|
|
75
|
+
crossOriginResourcePolicy?: boolean | {
|
|
76
|
+
policy?: 'same-origin' | 'same-site' | 'cross-origin';
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* `Origin-Agent-Cluster: ?1`.
|
|
80
|
+
*/
|
|
81
|
+
originAgentCluster?: boolean;
|
|
82
|
+
/**
|
|
83
|
+
* `Referrer-Policy`. Default: `no-referrer`. A list is sent as a fallback
|
|
84
|
+
* chain (the browser uses the last one it supports).
|
|
85
|
+
*/
|
|
86
|
+
referrerPolicy?: boolean | {
|
|
87
|
+
policy?: ReferrerPolicyToken | readonly ReferrerPolicyToken[];
|
|
88
|
+
};
|
|
89
|
+
/**
|
|
90
|
+
* `Strict-Transport-Security`. Default: `max-age=31536000;
|
|
91
|
+
* includeSubDomains`. Browsers ignore it over plain HTTP.
|
|
92
|
+
*/
|
|
93
|
+
strictTransportSecurity?: boolean | {
|
|
94
|
+
/** In seconds. @default 31536000 (365 days) */
|
|
95
|
+
maxAge?: number;
|
|
96
|
+
/** @default true */
|
|
97
|
+
includeSubDomains?: boolean;
|
|
98
|
+
/** @default false */
|
|
99
|
+
preload?: boolean;
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* `X-Content-Type-Options: nosniff`.
|
|
103
|
+
*/
|
|
104
|
+
xContentTypeOptions?: boolean;
|
|
105
|
+
/**
|
|
106
|
+
* `X-DNS-Prefetch-Control`. Default: `off`; `{ allow: true }` sends `on`.
|
|
107
|
+
*/
|
|
108
|
+
xDnsPrefetchControl?: boolean | {
|
|
109
|
+
allow?: boolean;
|
|
110
|
+
};
|
|
111
|
+
/**
|
|
112
|
+
* `X-Download-Options: noopen`.
|
|
113
|
+
*/
|
|
114
|
+
xDownloadOptions?: boolean;
|
|
115
|
+
/**
|
|
116
|
+
* `X-Frame-Options`. Default: `SAMEORIGIN`. Superseded by the CSP
|
|
117
|
+
* `frame-ancestors` directive, kept for older browsers.
|
|
118
|
+
*/
|
|
119
|
+
xFrameOptions?: boolean | {
|
|
120
|
+
action?: 'deny' | 'sameorigin';
|
|
121
|
+
};
|
|
122
|
+
/**
|
|
123
|
+
* `X-Permitted-Cross-Domain-Policies`. Default: `none`.
|
|
124
|
+
*/
|
|
125
|
+
xPermittedCrossDomainPolicies?: boolean | {
|
|
126
|
+
permittedPolicies?: 'none' | 'master-only' | 'by-content-type' | 'all';
|
|
127
|
+
};
|
|
128
|
+
/**
|
|
129
|
+
* Removes the `X-Powered-By` header (on Express, also disables the
|
|
130
|
+
* `x-powered-by` setting). `false` leaves it untouched.
|
|
131
|
+
*/
|
|
132
|
+
xPoweredBy?: boolean;
|
|
133
|
+
/**
|
|
134
|
+
* `X-XSS-Protection: 0`, which disables the legacy XSS auditor of old
|
|
135
|
+
* browsers (a source of vulnerabilities itself).
|
|
136
|
+
*/
|
|
137
|
+
xXssProtection?: boolean;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* @publicApi
|
|
141
|
+
*/
|
|
142
|
+
export type ReferrerPolicyToken = '' | 'no-referrer' | 'no-referrer-when-downgrade' | 'same-origin' | 'origin' | 'strict-origin' | 'origin-when-cross-origin' | 'strict-origin-when-cross-origin' | 'unsafe-url';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Observable } from 'rxjs';
|
|
2
|
+
import { ExecutionContext } from '../features/execution-context.interface.js';
|
|
3
|
+
/**
|
|
4
|
+
* Interface describing a global preRequest hook for microservices.
|
|
5
|
+
*
|
|
6
|
+
* Hooks are executed before guards, allowing setup of context (e.g. AsyncLocalStorage)
|
|
7
|
+
* that is available to all downstream enhancers.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* const als = new AsyncLocalStorage();
|
|
12
|
+
* app.registerPreRequestHook((context, next) => {
|
|
13
|
+
* als.enterWith({ correlationId: uuid() });
|
|
14
|
+
* return next();
|
|
15
|
+
* });
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* @publicApi
|
|
19
|
+
*/
|
|
20
|
+
export interface PreRequestHook {
|
|
21
|
+
(context: ExecutionContext, next: () => Observable<unknown>): Observable<unknown>;
|
|
22
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interface describing the shape of a transport server.
|
|
3
|
+
* Used as the return type of `getTransportServer()` to provide
|
|
4
|
+
* autocomplete without creating circular dependencies.
|
|
5
|
+
*
|
|
6
|
+
* @publicApi
|
|
7
|
+
*/
|
|
8
|
+
export interface ITransportServer {
|
|
9
|
+
/**
|
|
10
|
+
* Starts the transport server.
|
|
11
|
+
* @param callback Function to be called upon initialization
|
|
12
|
+
*/
|
|
13
|
+
listen(callback: (...optionalParams: unknown[]) => any): any;
|
|
14
|
+
/**
|
|
15
|
+
* Closes the transport server (stops listening on port/connection).
|
|
16
|
+
*/
|
|
17
|
+
close(): any;
|
|
18
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Severity level applied to a single kind of route conflict detected at
|
|
3
|
+
* bootstrap.
|
|
4
|
+
*
|
|
5
|
+
* @publicApi
|
|
6
|
+
*/
|
|
7
|
+
export type RouteConflictPolicyLevel = 'off' | 'warn' | 'error';
|
|
8
|
+
/**
|
|
9
|
+
* Per-kind policy for overlapping routes detected at bootstrap.
|
|
10
|
+
* `duplicate` covers identical (method, path, host, version) registrations.
|
|
11
|
+
* `shadow` covers patterns that can match the same request (for example
|
|
12
|
+
* `/users/me` vs `/users/:id`). Each kind defaults to `'off'`.
|
|
13
|
+
*
|
|
14
|
+
* @publicApi
|
|
15
|
+
*/
|
|
16
|
+
export interface RouteConflictPolicy {
|
|
17
|
+
duplicate?: RouteConflictPolicyLevel;
|
|
18
|
+
shadow?: RouteConflictPolicyLevel;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Order in which routes are registered on the underlying HTTP adapter.
|
|
22
|
+
* `'specificity'` registers literal segments before parametric and
|
|
23
|
+
* wildcard ones on order-sensitive adapters (such as Express). Defaults
|
|
24
|
+
* to `'declaration'`.
|
|
25
|
+
*
|
|
26
|
+
* @publicApi
|
|
27
|
+
*/
|
|
28
|
+
export type RouteResolutionStrategy = 'declaration' | 'specificity';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/internal.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal module - not part of the public API.
|
|
3
|
+
* These exports are used by sibling @nestjs packages.
|
|
4
|
+
* Do not depend on these in your application code.
|
|
5
|
+
* @internal
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
export * from './constants.js';
|
|
9
|
+
export { RouteParamtypes } from './enums/route-paramtypes.enum.js';
|
|
10
|
+
export * from './utils/shared.utils.js';
|
|
11
|
+
export * from './utils/parameter-decorator-options.util.js';
|
|
12
|
+
export * from './utils/load-package.util.js';
|
|
13
|
+
export * from './utils/cli-colors.util.js';
|
|
14
|
+
export * from './utils/random-string-generator.util.js';
|
|
15
|
+
export * from './utils/select-exception-filter-metadata.util.js';
|
|
16
|
+
export type { Controller, Injectable } from './interfaces/index.js';
|
|
17
|
+
export type { NestApplicationContextOptions } from './interfaces/nest-application-context-options.interface.js';
|
|
18
|
+
export type { NestMicroserviceOptions } from './interfaces/microservices/nest-microservice-options.interface.js';
|
|
19
|
+
export type { CorsOptions, CorsOptionsDelegate, CustomOrigin, } from './interfaces/external/cors-options.interface.js';
|
|
20
|
+
export type { ExceptionFilterMetadata } from './interfaces/exceptions/exception-filter-metadata.interface.js';
|
|
21
|
+
export type { RpcExceptionFilterMetadata } from './interfaces/exceptions/rpc-exception-filter-metadata.interface.js';
|
|
22
|
+
export type { VersionValue } from './interfaces/version-options.interface.js';
|
|
23
|
+
export type { GlobalPrefixOptions } from './interfaces/global-prefix-options.interface.js';
|
|
24
|
+
export type { MiddlewareConfiguration, RouteInfo, } from './interfaces/middleware/middleware-configuration.interface.js';
|
|
25
|
+
export type { MiddlewareConfigProxy } from './interfaces/middleware/middleware-config-proxy.interface.js';
|
|
26
|
+
export type { ModuleMetadata } from './interfaces/modules/module-metadata.interface.js';
|
|
27
|
+
export type { HttpArgumentsHost, RpcArgumentsHost, WsArgumentsHost, } from './interfaces/features/arguments-host.interface.js';
|
|
28
|
+
export type { RequestHandler, SecurityRequestHook, } from './interfaces/http/http-server.interface.js';
|
|
29
|
+
export type { GetOrResolveOptions, SelectOptions, } from './interfaces/nest-application-context.interface.js';
|
|
30
|
+
export type { ShutdownHooksOptions } from './interfaces/shutdown-hooks-options.interface.js';
|
|
31
|
+
export { assignMetadata } from './decorators/http/route-params.decorator.js';
|
package/internal.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal module - not part of the public API.
|
|
3
|
+
* These exports are used by sibling @nestjs packages.
|
|
4
|
+
* Do not depend on these in your application code.
|
|
5
|
+
* @internal
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
// Constants
|
|
9
|
+
export * from './constants.js';
|
|
10
|
+
// Enums (internal)
|
|
11
|
+
export { RouteParamtypes } from './enums/route-paramtypes.enum.js';
|
|
12
|
+
// Utils
|
|
13
|
+
export * from './utils/shared.utils.js';
|
|
14
|
+
export * from './utils/parameter-decorator-options.util.js';
|
|
15
|
+
export * from './utils/load-package.util.js';
|
|
16
|
+
export * from './utils/cli-colors.util.js';
|
|
17
|
+
export * from './utils/random-string-generator.util.js';
|
|
18
|
+
export * from './utils/select-exception-filter-metadata.util.js';
|
|
19
|
+
// Decorators (internal)
|
|
20
|
+
export { assignMetadata } from './decorators/http/route-params.decorator.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nestjs/common",
|
|
3
|
-
"version": "11.2.
|
|
3
|
+
"version": "11.2.6",
|
|
4
4
|
"description": "Nest - modern, fast, powerful node.js web framework (@common)",
|
|
5
5
|
"author": "Kamil Mysliwiec",
|
|
6
6
|
"homepage": "https://nestjs.com",
|
|
@@ -38,5 +38,5 @@
|
|
|
38
38
|
"optional": true
|
|
39
39
|
}
|
|
40
40
|
},
|
|
41
|
-
"gitHead": "
|
|
41
|
+
"gitHead": "c07cfb0be5e95ffa129da39ccc49a23cb64d49ff"
|
|
42
42
|
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { StandardSchemaV1 } from '@standard-schema/spec';
|
|
2
|
+
import { ArgumentMetadata, PipeTransform } from '../interfaces/features/pipe-transform.interface.js';
|
|
3
|
+
import { ErrorHttpStatusCode } from '../utils/http-error-by-code.util.js';
|
|
4
|
+
/**
|
|
5
|
+
* @publicApi
|
|
6
|
+
*/
|
|
7
|
+
export interface StandardSchemaValidationPipeOptions {
|
|
8
|
+
/**
|
|
9
|
+
* If true, the pipe will return the value produced by the schema
|
|
10
|
+
* (which may differ from the input if the schema coerces/transforms values).
|
|
11
|
+
* If false, the original input value is returned after successful validation.
|
|
12
|
+
* @default true
|
|
13
|
+
*/
|
|
14
|
+
transform?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* If true, the pipe will also validate parameters decorated with custom decorators
|
|
17
|
+
* (created with `createParamDecorator`). When false, custom parameters are skipped.
|
|
18
|
+
* @default false
|
|
19
|
+
*/
|
|
20
|
+
validateCustomDecorators?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Options to pass to the standard schema `validate` function.
|
|
23
|
+
* These options are forwarded as the second argument to the schema's `~standard.validate` method.
|
|
24
|
+
*/
|
|
25
|
+
validateOptions?: Record<string, unknown>;
|
|
26
|
+
/**
|
|
27
|
+
* The HTTP status code to be used in the response when the validation fails.
|
|
28
|
+
* @default HttpStatus.BAD_REQUEST
|
|
29
|
+
*/
|
|
30
|
+
errorHttpStatusCode?: ErrorHttpStatusCode;
|
|
31
|
+
/**
|
|
32
|
+
* A factory function that returns an exception object to be thrown
|
|
33
|
+
* if validation fails.
|
|
34
|
+
* @param issues The issues returned by the standard schema validation
|
|
35
|
+
* @returns The exception object
|
|
36
|
+
*/
|
|
37
|
+
exceptionFactory?: (issues: readonly StandardSchemaV1.Issue[]) => any;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Defines the built-in StandardSchemaValidation Pipe.
|
|
41
|
+
*
|
|
42
|
+
* Uses a standard schema object (conforming to the Standard Schema spec)
|
|
43
|
+
* attached to the parameter metadata to validate incoming values.
|
|
44
|
+
*
|
|
45
|
+
* @see [Standard Schema](https://github.com/standard-schema/standard-schema)
|
|
46
|
+
*
|
|
47
|
+
* @publicApi
|
|
48
|
+
*/
|
|
49
|
+
export declare class StandardSchemaValidationPipe implements PipeTransform {
|
|
50
|
+
protected readonly options?: StandardSchemaValidationPipeOptions | undefined;
|
|
51
|
+
protected isTransformEnabled: boolean;
|
|
52
|
+
protected validateCustomDecorators: boolean;
|
|
53
|
+
protected validateOptions: Record<string, unknown> | undefined;
|
|
54
|
+
protected exceptionFactory: (issues: readonly StandardSchemaV1.Issue[]) => any;
|
|
55
|
+
constructor(options?: StandardSchemaValidationPipeOptions | undefined);
|
|
56
|
+
/**
|
|
57
|
+
* Formats Standard Schema validation issues into a flat list of error messages.
|
|
58
|
+
* When an issue includes a path, the path is prefixed to the message.
|
|
59
|
+
*/
|
|
60
|
+
protected formatIssueMessages(issues: readonly StandardSchemaV1.Issue[]): string[];
|
|
61
|
+
/**
|
|
62
|
+
* Method that validates the incoming value against the standard schema
|
|
63
|
+
* provided in the parameter metadata.
|
|
64
|
+
*
|
|
65
|
+
* @param value currently processed route argument
|
|
66
|
+
* @param metadata contains metadata about the currently processed route argument
|
|
67
|
+
*/
|
|
68
|
+
transform<T = any>(value: T, metadata: ArgumentMetadata): Promise<T>;
|
|
69
|
+
/**
|
|
70
|
+
* Determines whether validation should be performed for the given metadata.
|
|
71
|
+
* Skips validation for custom decorators unless `validateCustomDecorators` is enabled.
|
|
72
|
+
*
|
|
73
|
+
* @param metadata contains metadata about the currently processed route argument
|
|
74
|
+
* @returns `true` if validation should be performed
|
|
75
|
+
*/
|
|
76
|
+
protected toValidate(metadata: ArgumentMetadata): boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Validates a value against a standard schema.
|
|
79
|
+
* Can be overridden to customize validation behavior.
|
|
80
|
+
*
|
|
81
|
+
* @param value The value to validate
|
|
82
|
+
* @param schema The standard schema to validate against
|
|
83
|
+
* @param options Optional options forwarded to the schema's validate method
|
|
84
|
+
* @returns The validation result
|
|
85
|
+
*/
|
|
86
|
+
protected validate<T = unknown>(value: unknown, schema: StandardSchemaV1, options?: Record<string, unknown>): Promise<StandardSchemaV1.Result<T>> | StandardSchemaV1.Result<T>;
|
|
87
|
+
protected stripProtoKeys(value: any): void;
|
|
88
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { __decorate, __metadata, __param } from "tslib";
|
|
2
|
+
import { Injectable } from '../decorators/core/injectable.decorator.js';
|
|
3
|
+
import { Optional } from '../decorators/core/optional.decorator.js';
|
|
4
|
+
import { HttpStatus } from '../enums/http-status.enum.js';
|
|
5
|
+
import { HttpErrorByCode, } from '../utils/http-error-by-code.util.js';
|
|
6
|
+
import { isObject } from '../utils/shared.utils.js';
|
|
7
|
+
import { stripProtoKeys } from '../utils/strip-proto-keys.util.js';
|
|
8
|
+
/**
|
|
9
|
+
* Defines the built-in StandardSchemaValidation Pipe.
|
|
10
|
+
*
|
|
11
|
+
* Uses a standard schema object (conforming to the Standard Schema spec)
|
|
12
|
+
* attached to the parameter metadata to validate incoming values.
|
|
13
|
+
*
|
|
14
|
+
* @see [Standard Schema](https://github.com/standard-schema/standard-schema)
|
|
15
|
+
*
|
|
16
|
+
* @publicApi
|
|
17
|
+
*/
|
|
18
|
+
let StandardSchemaValidationPipe = class StandardSchemaValidationPipe {
|
|
19
|
+
options;
|
|
20
|
+
isTransformEnabled;
|
|
21
|
+
validateCustomDecorators;
|
|
22
|
+
validateOptions;
|
|
23
|
+
exceptionFactory;
|
|
24
|
+
constructor(options) {
|
|
25
|
+
this.options = options;
|
|
26
|
+
const { transform = true, validateCustomDecorators = false, validateOptions, exceptionFactory, errorHttpStatusCode = HttpStatus.BAD_REQUEST, } = options || {};
|
|
27
|
+
this.isTransformEnabled = transform;
|
|
28
|
+
this.validateCustomDecorators = validateCustomDecorators;
|
|
29
|
+
this.validateOptions = validateOptions;
|
|
30
|
+
this.exceptionFactory =
|
|
31
|
+
exceptionFactory ||
|
|
32
|
+
(issues => {
|
|
33
|
+
const messages = this.formatIssueMessages(issues);
|
|
34
|
+
return new HttpErrorByCode[errorHttpStatusCode](messages);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Formats Standard Schema validation issues into a flat list of error messages.
|
|
39
|
+
* When an issue includes a path, the path is prefixed to the message.
|
|
40
|
+
*/
|
|
41
|
+
formatIssueMessages(issues) {
|
|
42
|
+
return issues.map(issue => {
|
|
43
|
+
if (issue.path?.length) {
|
|
44
|
+
const stringPath = issue.path
|
|
45
|
+
.map(segment => String(isObject(segment) ? segment.key : segment))
|
|
46
|
+
.join('.');
|
|
47
|
+
return `${stringPath}: ${issue.message}`;
|
|
48
|
+
}
|
|
49
|
+
return issue.message;
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Method that validates the incoming value against the standard schema
|
|
54
|
+
* provided in the parameter metadata.
|
|
55
|
+
*
|
|
56
|
+
* @param value currently processed route argument
|
|
57
|
+
* @param metadata contains metadata about the currently processed route argument
|
|
58
|
+
*/
|
|
59
|
+
async transform(value, metadata) {
|
|
60
|
+
const schema = metadata.schema;
|
|
61
|
+
if (!schema || !this.toValidate(metadata)) {
|
|
62
|
+
return value;
|
|
63
|
+
}
|
|
64
|
+
this.stripProtoKeys(value);
|
|
65
|
+
const result = await this.validate(value, schema, this.validateOptions);
|
|
66
|
+
if (result.issues) {
|
|
67
|
+
throw this.exceptionFactory(result.issues);
|
|
68
|
+
}
|
|
69
|
+
return this.isTransformEnabled ? result.value : value;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Determines whether validation should be performed for the given metadata.
|
|
73
|
+
* Skips validation for custom decorators unless `validateCustomDecorators` is enabled.
|
|
74
|
+
*
|
|
75
|
+
* @param metadata contains metadata about the currently processed route argument
|
|
76
|
+
* @returns `true` if validation should be performed
|
|
77
|
+
*/
|
|
78
|
+
toValidate(metadata) {
|
|
79
|
+
const { type } = metadata;
|
|
80
|
+
if (type === 'custom' && !this.validateCustomDecorators) {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Validates a value against a standard schema.
|
|
87
|
+
* Can be overridden to customize validation behavior.
|
|
88
|
+
*
|
|
89
|
+
* @param value The value to validate
|
|
90
|
+
* @param schema The standard schema to validate against
|
|
91
|
+
* @param options Optional options forwarded to the schema's validate method
|
|
92
|
+
* @returns The validation result
|
|
93
|
+
*/
|
|
94
|
+
validate(value, schema, options) {
|
|
95
|
+
return schema['~standard'].validate(value, options);
|
|
96
|
+
}
|
|
97
|
+
stripProtoKeys(value) {
|
|
98
|
+
stripProtoKeys(value);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
StandardSchemaValidationPipe = __decorate([
|
|
102
|
+
Injectable(),
|
|
103
|
+
__param(0, Optional()),
|
|
104
|
+
__metadata("design:paramtypes", [Object])
|
|
105
|
+
], StandardSchemaValidationPipe);
|
|
106
|
+
export { StandardSchemaValidationPipe };
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { StandardSchemaV1 } from '@standard-schema/spec';
|
|
2
|
+
import { Observable } from 'rxjs';
|
|
3
|
+
import { CallHandler, ExecutionContext, NestInterceptor } from '../interfaces/index.js';
|
|
4
|
+
import { StandardSchemaSerializerContextOptions } from './standard-schema-serializer.interfaces.js';
|
|
5
|
+
interface PlainLiteralObject {
|
|
6
|
+
[key: string]: any;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* @publicApi
|
|
10
|
+
*/
|
|
11
|
+
export interface StandardSchemaSerializerInterceptorOptions {
|
|
12
|
+
/**
|
|
13
|
+
* A default standard schema to use for serialization when no schema
|
|
14
|
+
* is provided via `@SerializeOptions()`.
|
|
15
|
+
*/
|
|
16
|
+
schema?: StandardSchemaV1;
|
|
17
|
+
/**
|
|
18
|
+
* Default options forwarded to the schema's `~standard.validate()` call.
|
|
19
|
+
* Can be overridden per-handler via `@SerializeOptions({ validateOptions })`.
|
|
20
|
+
*/
|
|
21
|
+
validateOptions?: StandardSchemaV1.Options;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* An interceptor that serializes outgoing responses using a Standard Schema.
|
|
25
|
+
*
|
|
26
|
+
* The schema can be provided either:
|
|
27
|
+
* - As a default option in the interceptor constructor
|
|
28
|
+
* - Per-handler or per-class via `@SerializeOptions({ schema })` decorator
|
|
29
|
+
*
|
|
30
|
+
* When a schema is present, the interceptor validates/transforms the response
|
|
31
|
+
* through the schema's `~standard.validate()` method. If validation fails,
|
|
32
|
+
* the issues are thrown as an error.
|
|
33
|
+
*
|
|
34
|
+
* @see [Standard Schema](https://github.com/standard-schema/standard-schema)
|
|
35
|
+
*
|
|
36
|
+
* @publicApi
|
|
37
|
+
*/
|
|
38
|
+
export declare class StandardSchemaSerializerInterceptor implements NestInterceptor {
|
|
39
|
+
protected readonly reflector: any;
|
|
40
|
+
protected readonly defaultOptions: StandardSchemaSerializerInterceptorOptions;
|
|
41
|
+
constructor(reflector: any, defaultOptions?: StandardSchemaSerializerInterceptorOptions);
|
|
42
|
+
intercept(context: ExecutionContext, next: CallHandler): Observable<any>;
|
|
43
|
+
/**
|
|
44
|
+
* Serializes responses that are non-null objects nor streamable files.
|
|
45
|
+
*/
|
|
46
|
+
serialize(response: PlainLiteralObject | Array<PlainLiteralObject>, schema: StandardSchemaV1 | undefined, validateOptions?: StandardSchemaV1.Options): PlainLiteralObject | Array<PlainLiteralObject> | Promise<PlainLiteralObject | Array<PlainLiteralObject>>;
|
|
47
|
+
transformToPlain(plainOrClass: any, schema: StandardSchemaV1, validateOptions?: StandardSchemaV1.Options): Promise<PlainLiteralObject>;
|
|
48
|
+
protected getContextOptions(context: ExecutionContext): StandardSchemaSerializerContextOptions | undefined;
|
|
49
|
+
}
|
|
50
|
+
export {};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { __decorate, __metadata, __param } from "tslib";
|
|
2
|
+
import { concatMap } from 'rxjs/operators';
|
|
3
|
+
import { Inject, Injectable, Optional } from '../decorators/core/index.js';
|
|
4
|
+
import { StreamableFile } from '../file-stream/index.js';
|
|
5
|
+
import { isObject } from '../utils/shared.utils.js';
|
|
6
|
+
import { CLASS_SERIALIZER_OPTIONS } from './class-serializer.constants.js';
|
|
7
|
+
// NOTE (external)
|
|
8
|
+
// We need to deduplicate them here due to the circular dependency
|
|
9
|
+
// between core and common packages
|
|
10
|
+
const REFLECTOR = 'Reflector';
|
|
11
|
+
/**
|
|
12
|
+
* An interceptor that serializes outgoing responses using a Standard Schema.
|
|
13
|
+
*
|
|
14
|
+
* The schema can be provided either:
|
|
15
|
+
* - As a default option in the interceptor constructor
|
|
16
|
+
* - Per-handler or per-class via `@SerializeOptions({ schema })` decorator
|
|
17
|
+
*
|
|
18
|
+
* When a schema is present, the interceptor validates/transforms the response
|
|
19
|
+
* through the schema's `~standard.validate()` method. If validation fails,
|
|
20
|
+
* the issues are thrown as an error.
|
|
21
|
+
*
|
|
22
|
+
* @see [Standard Schema](https://github.com/standard-schema/standard-schema)
|
|
23
|
+
*
|
|
24
|
+
* @publicApi
|
|
25
|
+
*/
|
|
26
|
+
let StandardSchemaSerializerInterceptor = class StandardSchemaSerializerInterceptor {
|
|
27
|
+
reflector;
|
|
28
|
+
defaultOptions;
|
|
29
|
+
constructor(reflector, defaultOptions = {}) {
|
|
30
|
+
this.reflector = reflector;
|
|
31
|
+
this.defaultOptions = defaultOptions;
|
|
32
|
+
}
|
|
33
|
+
intercept(context, next) {
|
|
34
|
+
const contextOptions = this.getContextOptions(context);
|
|
35
|
+
const schema = contextOptions?.schema ?? this.defaultOptions.schema;
|
|
36
|
+
const validateOptions = contextOptions?.validateOptions ?? this.defaultOptions.validateOptions;
|
|
37
|
+
return next
|
|
38
|
+
.handle()
|
|
39
|
+
.pipe(concatMap(async (res) => this.serialize(res, schema, validateOptions)));
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Serializes responses that are non-null objects nor streamable files.
|
|
43
|
+
*/
|
|
44
|
+
serialize(response, schema, validateOptions) {
|
|
45
|
+
if (!schema || !isObject(response) || response instanceof StreamableFile) {
|
|
46
|
+
return response;
|
|
47
|
+
}
|
|
48
|
+
return Array.isArray(response)
|
|
49
|
+
? Promise.all(response.map(item => this.transformToPlain(item, schema, validateOptions)))
|
|
50
|
+
: this.transformToPlain(response, schema, validateOptions);
|
|
51
|
+
}
|
|
52
|
+
async transformToPlain(plainOrClass, schema, validateOptions) {
|
|
53
|
+
if (!plainOrClass) {
|
|
54
|
+
return plainOrClass;
|
|
55
|
+
}
|
|
56
|
+
const result = await schema['~standard'].validate(plainOrClass, validateOptions);
|
|
57
|
+
if (result.issues) {
|
|
58
|
+
throw new Error(`Serialization failed: ${result.issues.map(i => i.message).join(', ')}`);
|
|
59
|
+
}
|
|
60
|
+
return result.value;
|
|
61
|
+
}
|
|
62
|
+
getContextOptions(context) {
|
|
63
|
+
return this.reflector.getAllAndOverride(CLASS_SERIALIZER_OPTIONS, [
|
|
64
|
+
context.getHandler(),
|
|
65
|
+
context.getClass(),
|
|
66
|
+
]);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
StandardSchemaSerializerInterceptor = __decorate([
|
|
70
|
+
Injectable(),
|
|
71
|
+
__param(0, Inject(REFLECTOR)),
|
|
72
|
+
__param(1, Optional()),
|
|
73
|
+
__metadata("design:paramtypes", [Object, Object])
|
|
74
|
+
], StandardSchemaSerializerInterceptor);
|
|
75
|
+
export { StandardSchemaSerializerInterceptor };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { StandardSchemaV1 } from '@standard-schema/spec';
|
|
2
|
+
/**
|
|
3
|
+
* Options for the `StandardSchemaSerializerInterceptor`, passed via
|
|
4
|
+
* `@SerializeOptions({ schema })`.
|
|
5
|
+
*
|
|
6
|
+
* @publicApi
|
|
7
|
+
*/
|
|
8
|
+
export interface StandardSchemaSerializerContextOptions {
|
|
9
|
+
/**
|
|
10
|
+
* A standard schema to use for serialization.
|
|
11
|
+
* Used by `StandardSchemaSerializerInterceptor` to validate/transform the response.
|
|
12
|
+
*/
|
|
13
|
+
schema?: StandardSchemaV1;
|
|
14
|
+
/**
|
|
15
|
+
* Optional options forwarded to the schema's `~standard.validate()` call.
|
|
16
|
+
*/
|
|
17
|
+
validateOptions?: StandardSchemaV1.Options;
|
|
18
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ParameterDecoratorOptions } from '../decorators/http/route-params.decorator.js';
|
|
2
|
+
/**
|
|
3
|
+
* Determines whether a parameter-decorator argument is a
|
|
4
|
+
* `ParameterDecoratorOptions` object rather than a pipe (instance or class).
|
|
5
|
+
*
|
|
6
|
+
* Kept in one place so every decorator (`@Query`, `@Body`, `@Param`,
|
|
7
|
+
* `@RawBody`, `@Payload`, `@MessageBody`, custom decorators, ...) classifies
|
|
8
|
+
* arguments identically: a pipe instance that happens to expose a `schema` or
|
|
9
|
+
* `pipes` property must never be mistaken for an options object.
|
|
10
|
+
*
|
|
11
|
+
* @internal
|
|
12
|
+
*/
|
|
13
|
+
export declare function isParameterDecoratorOptions(value: unknown): value is ParameterDecoratorOptions;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { isFunction } from './shared.utils.js';
|
|
2
|
+
const isPipeLike = (value) => isFunction(value?.transform) ||
|
|
3
|
+
(isFunction(value) &&
|
|
4
|
+
value.prototype &&
|
|
5
|
+
isFunction(value.prototype.transform));
|
|
6
|
+
/**
|
|
7
|
+
* Determines whether a parameter-decorator argument is a
|
|
8
|
+
* `ParameterDecoratorOptions` object rather than a pipe (instance or class).
|
|
9
|
+
*
|
|
10
|
+
* Kept in one place so every decorator (`@Query`, `@Body`, `@Param`,
|
|
11
|
+
* `@RawBody`, `@Payload`, `@MessageBody`, custom decorators, ...) classifies
|
|
12
|
+
* arguments identically: a pipe instance that happens to expose a `schema` or
|
|
13
|
+
* `pipes` property must never be mistaken for an options object.
|
|
14
|
+
*
|
|
15
|
+
* @internal
|
|
16
|
+
*/
|
|
17
|
+
export function isParameterDecoratorOptions(value) {
|
|
18
|
+
return (!!value &&
|
|
19
|
+
typeof value === 'object' &&
|
|
20
|
+
!isPipeLike(value) &&
|
|
21
|
+
('schema' in value || 'pipes' in value));
|
|
22
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { types } from 'util';
|
|
2
|
+
/**
|
|
3
|
+
* Built-in JavaScript types that should be excluded from prototype stripping
|
|
4
|
+
* to avoid conflicts with test frameworks like Jest's useFakeTimers
|
|
5
|
+
*/
|
|
6
|
+
const BUILT_IN_TYPES = [Date, RegExp, Error, Map, Set, WeakMap, WeakSet];
|
|
7
|
+
/**
|
|
8
|
+
* Strips dangerous prototype pollution keys (__proto__, prototype, constructor)
|
|
9
|
+
* from an object recursively.
|
|
10
|
+
*/
|
|
11
|
+
export function stripProtoKeys(value) {
|
|
12
|
+
if (value == null || typeof value !== 'object' || types.isTypedArray(value)) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
// Skip built-in JavaScript primitives to avoid Jest useFakeTimers conflicts
|
|
16
|
+
if (BUILT_IN_TYPES.some(type => value instanceof type)) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
if (Array.isArray(value)) {
|
|
20
|
+
for (const v of value) {
|
|
21
|
+
stripProtoKeys(v);
|
|
22
|
+
}
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
// Delete dangerous prototype pollution keys
|
|
26
|
+
delete value.__proto__;
|
|
27
|
+
delete value.prototype;
|
|
28
|
+
// Only delete constructor if it's NOT a built-in type
|
|
29
|
+
const constructorType = value?.constructor;
|
|
30
|
+
if (constructorType && !BUILT_IN_TYPES.includes(constructorType)) {
|
|
31
|
+
delete value.constructor;
|
|
32
|
+
}
|
|
33
|
+
for (const key in value) {
|
|
34
|
+
stripProtoKeys(value[key]);
|
|
35
|
+
}
|
|
36
|
+
}
|