@nestjs/common 12.1.1 → 12.1.3

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.
@@ -44,7 +44,10 @@ export function Inject(token) {
44
44
  return;
45
45
  }
46
46
  let properties = Reflect.getMetadata(PROPERTY_DEPS_METADATA, target.constructor) || [];
47
- properties = [...properties, { key, type }];
47
+ properties = [
48
+ ...properties.filter(property => property.key !== key),
49
+ { key, type },
50
+ ];
48
51
  Reflect.defineMetadata(PROPERTY_DEPS_METADATA, properties, target.constructor);
49
52
  };
50
53
  }
@@ -20,7 +20,7 @@ export function Optional() {
20
20
  Reflect.defineMetadata(OPTIONAL_DEPS_METADATA, [...args, index], target);
21
21
  return;
22
22
  }
23
- const properties = Reflect.getOwnMetadata(OPTIONAL_PROPERTY_DEPS_METADATA, target.constructor) || [];
23
+ const properties = Reflect.getMetadata(OPTIONAL_PROPERTY_DEPS_METADATA, target.constructor) || [];
24
24
  Reflect.defineMetadata(OPTIONAL_PROPERTY_DEPS_METADATA, [...properties, key], target.constructor);
25
25
  };
26
26
  }
@@ -24,8 +24,19 @@ export function createParamDecorator(factory, enhancers = []) {
24
24
  const hasParamData = isNil(data) || !isPipe(data);
25
25
  const paramData = hasParamData ? data : undefined;
26
26
  const paramPipes = hasParamData ? pipes : [data, ...pipes];
27
- // Check if data itself is an options object (when used as the first argument)
28
- const isDataOptions = hasParamData && !isNil(data) && isParameterDecoratorOptions(data);
27
+ // Custom data may also contain schema or pipes properties, so only treat
28
+ // the first argument as options when those are its only keys and their
29
+ // values, if defined, are a Standard Schema and an array of pipes.
30
+ const isDataOptions = hasParamData &&
31
+ !isNil(data) &&
32
+ isParameterDecoratorOptions(data) &&
33
+ Object.keys(data).every(key => key === 'schema' || key === 'pipes') &&
34
+ (data.schema === undefined ||
35
+ isFunction(data.schema?.['~standard']?.validate)) &&
36
+ (data.pipes === undefined ||
37
+ (Array.isArray(data.pipes) &&
38
+ // Falsy entries are allowed, as the pipes context filters them out
39
+ data.pipes.every(pipe => isNil(pipe) || isPipe(pipe))));
29
40
  // Check if the last pipe argument is actually an options object
30
41
  const lastPipeArg = paramPipes.length > 0 ? paramPipes[paramPipes.length - 1] : undefined;
31
42
  const isLastPipeOptions = !isDataOptions && isParameterDecoratorOptions(lastPipeArg);
@@ -32,7 +32,10 @@ export class StreamableFile {
32
32
  this.stream = new Readable();
33
33
  this.stream.push(bufferOrReadStream);
34
34
  this.stream.push(null);
35
- this.options.length ??= bufferOrReadStream.length;
35
+ this.options = {
36
+ ...this.options,
37
+ length: this.options.length ?? bufferOrReadStream.length,
38
+ };
36
39
  }
37
40
  else if (bufferOrReadStream.pipe && isFunction(bufferOrReadStream.pipe)) {
38
41
  this.stream = bufferOrReadStream;
@@ -1,4 +1,5 @@
1
1
  import { RequestMethod } from '../../enums/index.js';
2
+ import { RouteInfo } from '../middleware/middleware-configuration.interface.js';
2
3
  import { NestApplicationOptions } from '../../interfaces/nest-application-options.interface.js';
3
4
  import { VersionValue, VersioningOptions } from '../version-options.interface.js';
4
5
  import { CookieSerializeOptions } from './cookie-options.interface.js';
@@ -419,8 +420,14 @@ export interface HttpServer<TRequest = any, TResponse = any, ServerInstance = an
419
420
  *
420
421
  * @param handler The `(req, res, next)` callback.
421
422
  * @param prefix The global prefix (`app.setGlobalPrefix()`), when set.
422
- */
423
- setNotFoundHandler?(handler: Function, prefix?: string): any;
423
+ * @param excludedRoutes The routes `app.setGlobalPrefix()` excluded from the
424
+ * prefix, when any. They live at the root, so an adapter that scopes the
425
+ * handler by `prefix` should also mount it on each of these paths, for
426
+ * every method: with `exclude: ['hello']` and only `GET /hello` declared,
427
+ * `POST /hello` is still an unmatched request for a route Nest owns. Paths
428
+ * arrive already converted to the framework's route syntax.
429
+ */
430
+ setNotFoundHandler?(handler: Function, prefix?: string, excludedRoutes?: RouteInfo[]): any;
424
431
  /**
425
432
  * Serves static files; pass-through for `app.useStaticAssets()`. The
426
433
  * arguments are platform-specific. When not implemented,
@@ -57,19 +57,19 @@ export interface INestApplicationContext {
57
57
  get<TInput = any, TResult = TInput>(typeOrToken: Type<TInput> | Function | string | symbol, options?: GetOrResolveOptions): TResult | Array<TResult>;
58
58
  /**
59
59
  * Resolves transient or request-scoped instance of either injectable or controller, otherwise, throws exception.
60
- * @returns {Array<TResult>}
60
+ * @returns {Promise<TResult>}
61
61
  */
62
62
  resolve<TInput = any, TResult = TInput>(typeOrToken: Type<TInput> | Function | string | symbol): Promise<TResult>;
63
63
  /**
64
64
  * Resolves transient or request-scoped instance of either injectable or controller, otherwise, throws exception.
65
- * @returns {Array<TResult>}
65
+ * @returns {Promise<TResult>}
66
66
  */
67
67
  resolve<TInput = any, TResult = TInput>(typeOrToken: Type<TInput> | Function | string | symbol, contextId?: {
68
68
  id: number;
69
69
  }): Promise<TResult>;
70
70
  /**
71
71
  * Resolves transient or request-scoped instance of either injectable or controller, otherwise, throws exception.
72
- * @returns {Array<TResult>}
72
+ * @returns {Promise<TResult>}
73
73
  */
74
74
  resolve<TInput = any, TResult = TInput>(typeOrToken: Type<TInput> | Function | string | symbol, contextId?: {
75
75
  id: number;
@@ -79,7 +79,7 @@ export interface INestApplicationContext {
79
79
  }): Promise<TResult>;
80
80
  /**
81
81
  * Resolves transient or request-scoped instances of either injectables or controllers, otherwise, throws exception.
82
- * @returns {Array<TResult>}
82
+ * @returns {Promise<Array<TResult>>}
83
83
  */
84
84
  resolve<TInput = any, TResult = TInput>(typeOrToken: Type<TInput> | Function | string | symbol, contextId?: {
85
85
  id: number;
@@ -22,10 +22,11 @@ export function getInjectionProviders(providers, tokens) {
22
22
  const match = (providers ?? []).filter(p => !result.includes(p) && // this prevents circular loops and duplication
23
23
  (search.includes(p) || search.includes(p?.provide)));
24
24
  result.push(...match);
25
- // get injection tokens of the matched providers, if any
25
+ // Follow factory dependencies and aliases to existing providers.
26
26
  search = match
27
- .filter(p => p?.inject)
28
- .flatMap(p => p.inject)
27
+ .flatMap(p => p?.useExisting !== undefined
28
+ ? [p.useExisting]
29
+ : (p?.inject ?? []))
29
30
  .map(mapInjectToTokens);
30
31
  }
31
32
  return result;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nestjs/common",
3
- "version": "12.1.1",
3
+ "version": "12.1.3",
4
4
  "description": "Nest - modern, fast, powerful node.js web framework (@common)",
5
5
  "author": "Kamil Mysliwiec",
6
6
  "homepage": "https://nestjs.com",
@@ -47,5 +47,5 @@
47
47
  "optional": true
48
48
  }
49
49
  },
50
- "gitHead": "9feedffde8ef8c86f0cd521153740575dc579d88"
50
+ "gitHead": "4514623279f6087808e3c8f08fbf9f37d3c17482"
51
51
  }
@@ -107,6 +107,9 @@ export class FileTypeValidator extends FileValidator {
107
107
  if (typeof fileType === 'string' && mimetype === fileType) {
108
108
  return true;
109
109
  }
110
- return !!mimetype.match(fileType);
110
+ // Stateful expressions must start at zero for each file, without changing
111
+ // the caller's lastIndex (the validator can be reused across uploads).
112
+ const pattern = typeof fileType === 'string' ? fileType : new RegExp(fileType);
113
+ return !!mimetype.match(pattern);
111
114
  }
112
115
  }
@@ -66,7 +66,9 @@ let ParseArrayPipe = class ParseArrayPipe {
66
66
  };
67
67
  const isExpectedTypePrimitive = this.isExpectedTypePrimitive();
68
68
  const toClassInstance = (item, index) => {
69
- if (this.options.items !== String) {
69
+ // `JSON.parse` stringifies its argument first, so an array holding a
70
+ // single item (`[1]` becomes `'1'`) would be parsed as that item.
71
+ if (this.options.items !== String && isString(item)) {
70
72
  try {
71
73
  item = JSON.parse(item);
72
74
  }
@@ -1,5 +1,9 @@
1
1
  import { ArgumentMetadata, PipeTransform } from '../interfaces/features/pipe-transform.interface.js';
2
2
  import { ErrorHttpStatusCode } from '../utils/http-error-by-code.util.js';
3
+ /**
4
+ * @publicApi
5
+ */
6
+ export type UUIDVersion = '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 'all';
3
7
  /**
4
8
  * @publicApi
5
9
  */
@@ -7,7 +11,7 @@ export interface ParseUUIDPipeOptions {
7
11
  /**
8
12
  * UUID version to validate
9
13
  */
10
- version?: '3' | '4' | '5' | '7';
14
+ version?: UUIDVersion;
11
15
  /**
12
16
  * The HTTP status code to be used in the response when the validation fails.
13
17
  */
@@ -34,16 +38,10 @@ export interface ParseUUIDPipeOptions {
34
38
  */
35
39
  export declare class ParseUUIDPipe implements PipeTransform {
36
40
  protected readonly options?: ParseUUIDPipeOptions | undefined;
37
- protected static uuidRegExps: {
38
- 3: RegExp;
39
- 4: RegExp;
40
- 5: RegExp;
41
- 7: RegExp;
42
- all: RegExp;
43
- };
41
+ protected static uuidRegExps: Record<UUIDVersion, RegExp>;
44
42
  private readonly version;
45
43
  protected exceptionFactory: (errors: string) => any;
46
44
  constructor(options?: ParseUUIDPipeOptions | undefined);
47
45
  transform(value: unknown, metadata: ArgumentMetadata): Promise<string | undefined | null>;
48
- protected isUUID(str: unknown, version?: string): any;
46
+ protected isUUID(str: unknown, version?: UUIDVersion): boolean;
49
47
  }
@@ -16,10 +16,14 @@ let ParseUUIDPipe = class ParseUUIDPipe {
16
16
  static { ParseUUIDPipe_1 = this; }
17
17
  options;
18
18
  static uuidRegExps = {
19
+ 1: /^[0-9A-F]{8}-[0-9A-F]{4}-1[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i,
20
+ 2: /^[0-9A-F]{8}-[0-9A-F]{4}-2[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i,
19
21
  3: /^[0-9A-F]{8}-[0-9A-F]{4}-3[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i,
20
22
  4: /^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i,
21
23
  5: /^[0-9A-F]{8}-[0-9A-F]{4}-5[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i,
24
+ 6: /^[0-9A-F]{8}-[0-9A-F]{4}-6[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i,
22
25
  7: /^[0-9A-F]{8}-[0-9A-F]{4}-7[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i,
26
+ 8: /^[0-9A-F]{8}-[0-9A-F]{4}-8[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i,
23
27
  // Versions 1-8 with the RFC variant, or the Nil and Max UUIDs (RFC 9562, sections 5.9, 5.10)
24
28
  all: /^(?:[0-9A-F]{8}-[0-9A-F]{4}-[1-8][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}|00000000-0000-0000-0000-000000000000|FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF)$/i,
25
29
  };
@@ -39,7 +43,7 @@ let ParseUUIDPipe = class ParseUUIDPipe {
39
43
  return value;
40
44
  }
41
45
  if (!this.isUUID(value, this.version)) {
42
- throw this.exceptionFactory(`Validation failed (uuid${this.version ? ` v ${this.version}` : ''} is expected)`);
46
+ throw this.exceptionFactory(`Validation failed (uuid${this.version && this.version !== 'all' ? ` v ${this.version}` : ''} is expected)`);
43
47
  }
44
48
  return value;
45
49
  }
@@ -216,18 +216,20 @@ let ValidationPipe = class ValidationPipe {
216
216
  return result;
217
217
  }
218
218
  mapChildrenToValidationErrors(error, parentPath) {
219
+ const currentError = parentPath
220
+ ? this.prependConstraintsWithParentProp(parentPath, error)
221
+ : error;
219
222
  if (!(error.children && error.children.length)) {
220
- return [error];
223
+ return [currentError];
221
224
  }
222
- const validationErrors = [];
225
+ const validationErrors = error.constraints
226
+ ? [currentError]
227
+ : [];
223
228
  parentPath = parentPath
224
229
  ? `${parentPath}.${error.property}`
225
230
  : error.property;
226
231
  for (const item of error.children) {
227
- if (item.children && item.children.length) {
228
- validationErrors.push(...this.mapChildrenToValidationErrors(item, parentPath));
229
- }
230
- validationErrors.push(this.prependConstraintsWithParentProp(parentPath, item));
232
+ validationErrors.push(...this.mapChildrenToValidationErrors(item, parentPath));
231
233
  }
232
234
  return validationErrors;
233
235
  }
@@ -8,6 +8,9 @@ import type { ParameterDecoratorOptions } from '../decorators/http/route-params.
8
8
  * arguments identically: a pipe instance that happens to expose a `schema` or
9
9
  * `pipes` property must never be mistaken for an options object.
10
10
  *
11
+ * `createParamDecorator` applies a stricter check to its first argument, since
12
+ * that argument may also be arbitrary custom data.
13
+ *
11
14
  * @internal
12
15
  */
13
16
  export declare function isParameterDecoratorOptions(value: unknown): value is ParameterDecoratorOptions;
@@ -12,6 +12,9 @@ const isPipeLike = (value) => isFunction(value?.transform) ||
12
12
  * arguments identically: a pipe instance that happens to expose a `schema` or
13
13
  * `pipes` property must never be mistaken for an options object.
14
14
  *
15
+ * `createParamDecorator` applies a stricter check to its first argument, since
16
+ * that argument may also be arbitrary custom data.
17
+ *
15
18
  * @internal
16
19
  */
17
20
  export function isParameterDecoratorOptions(value) {