Compare commits

...

72 Commits

Author SHA1 Message Date
Kamil Myśliwiec
eba8f15683 chore(@nestjs) publish v9.3.0 release 2023-02-01 15:00:02 +01:00
Kamil Mysliwiec
2310c56f4c Merge pull request #10997 from nestjs/dependabot/npm_and_yarn/sample/04-grpc/json5-1.0.2
chore(deps): bump json5 from 1.0.1 to 1.0.2 in /sample/04-grpc
2023-02-01 14:58:03 +01:00
Kamil Mysliwiec
06ea451f1f Merge pull request #11000 from nestjs/dependabot/npm_and_yarn/sample/01-cats-app/json5-1.0.2
chore(deps): bump json5 from 1.0.1 to 1.0.2 in /sample/01-cats-app
2023-02-01 14:57:57 +01:00
dependabot[bot]
b2c55a6f79 chore(deps): bump json5 from 1.0.1 to 1.0.2 in /sample/01-cats-app
Bumps [json5](https://github.com/json5/json5) from 1.0.1 to 1.0.2.
- [Release notes](https://github.com/json5/json5/releases)
- [Changelog](https://github.com/json5/json5/blob/main/CHANGELOG.md)
- [Commits](https://github.com/json5/json5/compare/v1.0.1...v1.0.2)

---
updated-dependencies:
- dependency-name: json5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-01 13:35:50 +00:00
dependabot[bot]
3d366ce5c5 chore(deps): bump json5 from 1.0.1 to 1.0.2 in /sample/04-grpc
Bumps [json5](https://github.com/json5/json5) from 1.0.1 to 1.0.2.
- [Release notes](https://github.com/json5/json5/releases)
- [Changelog](https://github.com/json5/json5/blob/main/CHANGELOG.md)
- [Commits](https://github.com/json5/json5/compare/v1.0.1...v1.0.2)

---
updated-dependencies:
- dependency-name: json5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-01 13:35:48 +00:00
Kamil Mysliwiec
f7e366600f Merge pull request #10999 from nestjs/dependabot/npm_and_yarn/sample/02-gateways/json5-1.0.2
chore(deps): bump json5 from 1.0.1 to 1.0.2 in /sample/02-gateways
2023-02-01 14:35:10 +01:00
Kamil Mysliwiec
55bc840edb Merge pull request #10998 from nestjs/dependabot/npm_and_yarn/sample/03-microservices/json5-1.0.2
chore(deps): bump json5 from 1.0.1 to 1.0.2 in /sample/03-microservices
2023-02-01 14:35:03 +01:00
Kamil Mysliwiec
22c3175552 Merge pull request #10982 from Inoir/fix/kafka-rpc-exception-stall
fix: kafka rpc exception not resolved
2023-02-01 14:31:43 +01:00
Kamil Myśliwiec
c1815d2f8c fix: revert #10801 2023-02-01 14:29:21 +01:00
Dominik Koller
34654244a7 put resolve in else block 2023-02-01 14:10:57 +01:00
Kamil Myśliwiec
2924c03aa3 fix: apply uuid factory strategy in testing module, update snapshots 2023-02-01 14:03:05 +01:00
Kamil Myśliwiec
d1ec9db5f2 fix(core): revert the original metadata scanner 2023-02-01 13:47:38 +01:00
Kamil Myśliwiec
cb7e10dbc3 Merge branch 'master' of https://github.com/nestjs/nest 2023-02-01 13:40:38 +01:00
Kamil Myśliwiec
511e7162a6 style: fix lint errors, ignore js and d.ts files 2023-02-01 13:40:29 +01:00
Kamil Mysliwiec
32b0d9c600 Merge pull request #10737 from mahkassem/Parse-File-Pipe-Fix
Parse file pipe fix (multiple files validation)
2023-02-01 13:20:06 +01:00
Kamil Mysliwiec
967a136834 Merge pull request #10201 from nkitku/patch-1
Fix HTTPException on minifying class names, its not match regex expre…
2023-02-01 13:17:30 +01:00
dependabot[bot]
1aadd30f46 chore(deps): bump json5 from 1.0.1 to 1.0.2 in /sample/02-gateways
Bumps [json5](https://github.com/json5/json5) from 1.0.1 to 1.0.2.
- [Release notes](https://github.com/json5/json5/releases)
- [Changelog](https://github.com/json5/json5/blob/main/CHANGELOG.md)
- [Commits](https://github.com/json5/json5/compare/v1.0.1...v1.0.2)

---
updated-dependencies:
- dependency-name: json5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-01 12:16:41 +00:00
dependabot[bot]
ae76b521d6 chore(deps): bump json5 from 1.0.1 to 1.0.2 in /sample/03-microservices
Bumps [json5](https://github.com/json5/json5) from 1.0.1 to 1.0.2.
- [Release notes](https://github.com/json5/json5/releases)
- [Changelog](https://github.com/json5/json5/blob/main/CHANGELOG.md)
- [Commits](https://github.com/json5/json5/compare/v1.0.1...v1.0.2)

---
updated-dependencies:
- dependency-name: json5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-01 12:16:27 +00:00
Kamil Mysliwiec
38c365215a Merge pull request #10531 from ChrisiPK/patch-logger-error-call
fix(common): correct order for logger error parameters
2023-02-01 13:14:17 +01:00
Kamil Mysliwiec
80b8c86c68 Merge pull request #10557 from weal1312/fix/cache_manager_store
fix(common): CacheStoreFactory type
2023-02-01 13:10:07 +01:00
Kamil Myśliwiec
8756ed3d68 Merge branch 'e-dot-master' 2023-02-01 13:09:27 +01:00
Kamil Myśliwiec
d616861698 style: minor formatting tweaks 2023-02-01 13:09:18 +01:00
Kamil Myśliwiec
c64312fded Merge branch 'master' of github.com:e-dot/nest into e-dot-master 2023-02-01 13:08:15 +01:00
Kamil Myśliwiec
304e6bf5bb Merge branch 'master' of https://github.com/nestjs/nest 2023-02-01 13:03:41 +01:00
Kamil Myśliwiec
161198379a Merge branch 'tolgap-fix/10471-use-body-parser' 2023-02-01 13:03:34 +01:00
Kamil Myśliwiec
661104d981 chore: resolve merge conflicts 2023-02-01 13:03:19 +01:00
Kamil Mysliwiec
f71554ca96 Merge pull request #10696 from kos984/fix/NestApplicationContext-listenToShutdownSignals
fix(core): process exit before shutdown hook end
2023-02-01 13:01:01 +01:00
Kamil Myśliwiec
a986e7e907 Merge branch 'master' of https://github.com/nestjs/nest 2023-02-01 13:00:10 +01:00
Kamil Myśliwiec
920f430d4d Merge branch 'zanminkian-zmj-fix_gloabl_prefix' 2023-02-01 13:00:03 +01:00
Kamil Myśliwiec
cd0462fbcb style: minor formatting tweaks 2023-02-01 12:59:40 +01:00
Kamil Myśliwiec
b9910a400a Merge branch 'zmj-fix_gloabl_prefix' of github.com:zanminkian/nest into zanminkian-zmj-fix_gloabl_prefix 2023-02-01 12:58:09 +01:00
Kamil Mysliwiec
6d88e3cd3c Merge pull request #10809 from micalevisk/fix/durable-payload-regression
fix(core,microservices): inject the context when the tree is not durable
2023-02-01 12:56:47 +01:00
Kamil Myśliwiec
fbf1ab7a81 fix(core): minor fix - reset to random if snapshot is off 2023-02-01 12:55:27 +01:00
Kamil Myśliwiec
868bbcd8b9 Merge branch 'master' of https://github.com/nestjs/nest 2023-02-01 12:53:19 +01:00
Kamil Myśliwiec
4e783852b3 feat(core): use deterministic uuids if absolutely necessary 2023-02-01 12:53:08 +01:00
Kamil Mysliwiec
07a84ae224 Merge pull request #10888 from Tony133/refactor/improvements-imports
refactor(): improvements the imports
2023-02-01 12:39:36 +01:00
Kamil Myśliwiec
7bc72671b6 build: fix ts build error 2023-02-01 12:38:47 +01:00
Kamil Myśliwiec
a560c3466a Merge branch 'H4ad-perf/metadata-scanner' 2023-02-01 12:36:49 +01:00
Kamil Myśliwiec
f10c917b71 style: change inline ifs to code blocks 2023-02-01 12:36:36 +01:00
Kamil Myśliwiec
208d8ca184 Merge branch 'perf/metadata-scanner' of github.com:H4ad/nest into H4ad-perf/metadata-scanner 2023-02-01 12:35:27 +01:00
Kamil Myśliwiec
32aeb7a8a3 Merge branch 'H4ad-perf/random-string-generator' 2023-02-01 12:32:55 +01:00
Antonio Tripodi
a185e63281 Merge branch 'master' into refactor/improvements-imports 2023-02-01 11:40:47 +01:00
Dominik Koller
0b395d1f59 resolve on error 2023-02-01 03:07:35 +01:00
Micael Levi L. Cavalcante
f396dc1ddf refactor(core): extract get context id logic into its own method 2023-01-27 12:08:12 -04:00
Micael Levi L. Cavalcante
aafdac62a0 fix(core,microservices): inject the context when the tree is not durable 2023-01-27 12:08:10 -04:00
Tony133
e8944675cb refactor(): improvements the imports 2023-01-16 22:27:58 +01:00
Tony133
4d4f3f82de refactor(): improvements the imports 2023-01-16 16:08:53 +01:00
Vinícius Lourenço
994f8c4e42 perf(core): better performance to get method names 2023-01-06 22:13:23 -03:00
曾明健
58ee3bf2f3 test: fix testing problem 2023-01-04 10:12:16 +00:00
曾明健
5deabef549 fix(core): fix global prefix not working 2023-01-04 10:05:05 +00:00
e-dot
9a47a6ce70 Merge branch 'master' of https://github.com/e-dot/nest 2022-12-14 14:07:25 +01:00
e-dot
eee8968d82 Fix port = 0 issue
When a user passes port:0 to this function, it's legit : in order to detect the presence of attributes, we use another comparison with !== undefined (works with 0).
See PR review here: 35357053b1
2022-12-14 14:06:19 +01:00
e-dot
35357053b1 Update packages/platform-fastify/adapters/fastify-adapter.ts
Ok - code has been rewritten afterwards - with better type support

Co-authored-by: Micael Levi L. Cavalcante <mllc@icomp.ufam.edu.br>
2022-12-12 17:45:03 +01:00
Konstantin Upir
ceea86d6ed fix(core): process exit before shutdown hook end 2022-12-12 12:37:08 +01:00
Mahmoud Kassem
452f19461c fix(parse-file): remove object case 2022-12-08 08:23:08 +02:00
Mahmoud Kassem
7792c43b93 fix(parse-file): multi files validation 2022-12-07 23:17:27 +02:00
Tolga Paksoy
363ab79b5f chore(platform): use type imports 2022-12-07 17:32:39 +01:00
Tolga Paksoy
9efb84fc22 refactor(platform): add example and simplify types 2022-12-07 17:32:36 +01:00
Tolga Paksoy
1b90339d8b fix(core): remove empty optional adapter method 2022-12-07 17:05:00 +01:00
Tolga Paksoy
a25bfa86ed refactor(platform): extract platform implementation detail to interfaces 2022-12-05 18:03:10 +01:00
Tolga Paksoy
d5e1cd18fc refactor(fastify): re-use use body parser function 2022-12-05 18:03:08 +01:00
Tolga Paksoy
9b073748cb test(): add integration test for raw body 2022-12-05 17:52:11 +01:00
Tolga Paksoy
0444f9c89e feat(platform): enable body parser with raw body support 2022-12-05 17:52:08 +01:00
e-dot
1b9bb76d07 Merge branch 'master' of https://github.com/e-dot/nest 2022-12-02 18:50:17 +01:00
e-dot
c817014c7d Windows IIS Compatibility : listen(FastifyListenOptions)
Adapt the fastify adapter to be compatible with Microsoft IIS : requires the new listen() API with a FastifyListenOptions parameter
2022-12-02 18:48:21 +01:00
e-dot
accb1dc014 Adapt Fastify Adapter (!) to use listen options
Improve the fastify adapter to use an object (FastifyListenOptions) in order to be able to totally configure fastify. In particular, enable use of "named pipes" for port, and render nestJs compatible with IIS and IISNode on Windows.
2022-11-30 10:08:24 +01:00
e-dot
1755537a77 Improve type checking
Use class FastifyListenOptions to restrict type checking
And check that one of the attributes is really defined (path port or host) in order to use it as the listen option
2022-11-29 16:23:44 +01:00
e-dot
7b81d0571d Merge pull request #1 from e-dot/e-dot-patch-1
Compatibility with Microsoft IIS, iisnode and fastify
2022-11-25 18:01:59 +01:00
e-dot
7afed825be Compatibility with Microsoft IIS, iisnode and fastify
To enable compatibilty with iisnode and fastify, you need to enable use of an object - passed as-is to the fastify listen function (see https://www.fastify.io/docs/latest/Reference/Server/#listen)
2022-11-25 17:56:51 +01:00
weal1312
d6097a10ac fix(common): CacheStoreFactory type 2022-11-12 04:04:56 +08:00
ChrisiPK
584015bc77 fix(common): correct order for logger error parameters
The error() function of a logger has two optional parameters: the trace and the context. The logger
now no longer passes the global context as the first optional parameter when there are is no value
supplied for the trace parameter. Instead, the trace parameter is passed as undefined and the
context is passed as the second optional parameter.

This fixes a bug where the trace is overwritten by the context when passed to custom loggers.
Fixes gremo/nest-winston#473
2022-11-07 21:28:41 +00:00
nkitku
f3e6c54b3e Fix HTTPException on minifying class names, its not match regex expression
```js
"BadRequest".match(/[A-Z][a-z]+|[0-9]+/g).join(' ') // this is ok 
// but on minify 
"t".match(/[A-Z][a-z]+|[0-9]+/g).join(' ') // throws error
// Uncaught TypeError: Cannot read properties of null (reading 'join')
```
2022-08-30 11:47:26 +05:30
57 changed files with 1516 additions and 1002 deletions

View File

@@ -1 +1,3 @@
**/node_modules/**
**/node_modules/**
*.d.ts
*.js

View File

@@ -15,7 +15,7 @@ scalar Date
type Query {
recipe(id: String!): Recipe!
recipes(skip: Int = 0, take: Int = 25): [Recipe!]!
recipes(skip: Int! = 0, take: Int! = 25): [Recipe!]!
}
type Mutation {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,95 @@
import { NestExpressApplication } from '@nestjs/platform-express';
import { Test } from '@nestjs/testing';
import { OptionsUrlencoded } from 'body-parser';
import { expect } from 'chai';
import * as request from 'supertest';
import { AppModule } from '../src/app.module';
describe('Body Parser (Express Application)', () => {
const moduleFixture = Test.createTestingModule({
imports: [AppModule],
});
let app: NestExpressApplication;
afterEach(async () => {
await app.close();
});
describe('application/json', () => {
const stringLimit = '{ "msg": "Hello, World" }';
const stringOverLimit = '{ "msg": "Hello, World!" }';
beforeEach(async () => {
const testFixture = await moduleFixture.compile();
app = testFixture
.createNestApplication<NestExpressApplication>({
rawBody: true,
logger: false,
})
.useBodyParser('json', { limit: Buffer.from(stringLimit).byteLength });
await app.init();
});
it('should allow request with matching body limit', async () => {
const response = await request(app.getHttpServer())
.post('/')
.set('Content-Type', 'application/json')
.send(stringLimit)
.expect(201);
expect(response.body).to.eql({
raw: stringLimit,
});
});
it('should fail if post body is larger than limit', async () => {
await request(app.getHttpServer())
.post('/')
.set('Content-Type', 'application/json')
.send(stringOverLimit)
.expect(413);
});
});
describe('application/x-www-form-urlencoded', () => {
const stringLimit = 'msg=Hello, World';
const stringOverLimit = 'msg=Hello, World!';
beforeEach(async () => {
const testFixture = await moduleFixture.compile();
app = testFixture
.createNestApplication<NestExpressApplication>({
rawBody: true,
logger: false,
})
.useBodyParser<OptionsUrlencoded>('urlencoded', {
limit: Buffer.from(stringLimit).byteLength,
extended: true,
});
await app.init();
});
it('should allow request with matching body limit', async () => {
const response = await request(app.getHttpServer())
.post('/')
.set('Content-Type', 'application/x-www-form-urlencoded')
.send(stringLimit)
.expect(201);
expect(response.body).to.eql({
raw: stringLimit,
});
});
it('should fail if post body is larger than limit', async () => {
await request(app.getHttpServer())
.post('/')
.set('Content-Type', 'application/x-www-form-urlencoded')
.send(stringOverLimit)
.expect(413);
});
});
});

View File

@@ -0,0 +1,106 @@
import {
FastifyAdapter,
NestFastifyApplication,
} from '@nestjs/platform-fastify';
import { Test } from '@nestjs/testing';
import { expect } from 'chai';
import { AppModule } from '../src/app.module';
describe('Body Parser (Fastify Application)', () => {
const moduleFixture = Test.createTestingModule({
imports: [AppModule],
});
let app: NestFastifyApplication;
afterEach(async () => {
await app.close();
});
describe('application/json', () => {
const stringLimit = '{ "msg": "Hello, World" }';
const stringOverLimit = '{ "msg": "Hello, World!" }';
beforeEach(async () => {
const testFixture = await moduleFixture.compile();
app = testFixture
.createNestApplication<NestFastifyApplication>(new FastifyAdapter(), {
rawBody: true,
logger: false,
})
.useBodyParser('application/json', {
bodyLimit: Buffer.from(stringLimit).byteLength,
});
await app.init();
});
it('should allow request with matching body limit', async () => {
const response = await app.inject({
method: 'POST',
url: '/',
headers: { 'content-type': 'application/json' },
payload: stringLimit,
});
expect(JSON.parse(response.body)).to.eql({
raw: stringLimit,
});
});
it('should fail if post body is larger than limit', async () => {
const response = await app.inject({
method: 'POST',
url: '/',
headers: { 'content-type': 'application/json' },
payload: stringOverLimit,
});
expect(response.statusCode).to.equal(413);
});
});
describe('application/x-www-form-urlencoded', () => {
const stringLimit = 'msg=Hello, World';
const stringOverLimit = 'msg=Hello, World!';
beforeEach(async () => {
const testFixture = await moduleFixture.compile();
app = testFixture
.createNestApplication<NestFastifyApplication>(new FastifyAdapter(), {
rawBody: true,
logger: false,
})
.useBodyParser('application/x-www-form-urlencoded', {
bodyLimit: Buffer.from(stringLimit).byteLength,
});
await app.init();
});
it('should allow request with matching body limit', async () => {
const response = await app.inject({
method: 'POST',
url: '/',
headers: { 'content-type': 'application/x-www-form-urlencoded' },
payload: stringLimit,
});
expect(JSON.parse(response.body)).to.eql({
raw: stringLimit,
});
});
it('should fail if post body is larger than limit', async () => {
const response = await app.inject({
method: 'POST',
url: '/',
headers: { 'content-type': 'application/x-www-form-urlencoded' },
payload: stringOverLimit,
});
expect(response.statusCode).to.equal(413);
});
});
});

View File

@@ -0,0 +1,12 @@
import { Controller, Post, Req, RawBodyRequest } from '@nestjs/common';
import { IncomingMessage } from 'http';
@Controller()
export class AppController {
@Post()
index(@Req() req: RawBodyRequest<IncomingMessage>) {
return {
raw: req.rawBody?.toString(),
};
}
}

View File

@@ -0,0 +1,7 @@
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
@Module({
controllers: [AppController],
})
export class AppModule {}

View File

@@ -0,0 +1,23 @@
{
"compilerOptions": {
"module": "commonjs",
"declaration": false,
"noImplicitAny": false,
"removeComments": true,
"lib": ["dom"],
"noLib": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "es6",
"sourceMap": true,
"allowJs": true,
"outDir": "./dist"
},
"include": [
"src/**/*",
"e2e/**/*"
],
"exclude": [
"node_modules"
]
}

View File

@@ -3,5 +3,5 @@
"packages": [
"packages/*"
],
"version": "9.3.0-beta.3"
"version": "9.3.0"
}

View File

@@ -47,15 +47,17 @@ export interface CacheStoreSetOptions<T> {
*
* @publicApi
*/
export interface CacheStoreFactory {
/**
* Return a configured cache store.
*
* @param args Cache manager options received from `CacheModule.register()`
* or `CacheModule.registerAsync()`
*/
create(args: LiteralObject): CacheStore;
}
export type CacheStoreFactory =
| {
/**
* Return a configured cache store.
*
* @param args Cache manager options received from `CacheModule.register()`
* or `CacheModule.registerAsync()`
*/
create(args: LiteralObject): CacheStore;
}
| ((args: LiteralObject) => CacheStore | Promise<CacheStore>);
/**
* Interface defining Cache Manager configuration options.

View File

@@ -101,7 +101,7 @@ export class HttpException extends Error {
} else if (this.constructor) {
this.message = this.constructor.name
.match(/[A-Z][a-z]+|[0-9]+/g)
.join(' ');
?.join(' ') ?? 'Error';
}
}

View File

@@ -30,6 +30,7 @@ export interface HttpServer<TRequest = any, TResponse = any> {
| RequestHandler<TRequest, TResponse>
| ErrorHandler<TRequest, TResponse>,
): any;
useBodyParser?(...args: any[]): any;
get(handler: RequestHandler<TRequest, TResponse>): any;
get(path: string, handler: RequestHandler<TRequest, TResponse>): any;
post(handler: RequestHandler<TRequest, TResponse>): any;

View File

@@ -205,7 +205,7 @@ export class ConfigurableModuleBuilder<
static [self.staticMethodKey](
options: ModuleOptions & ExtraModuleDefinitionOptions,
): DynamicModule {
const providers = [
const providers: Array<Provider> = [
{
provide: self.options.optionsInjectionToken,
useValue: this.omitExtras(options, self.extras),

View File

@@ -1,6 +1,6 @@
{
"name": "@nestjs/common",
"version": "9.3.0-beta.3",
"version": "9.3.0",
"description": "Nest - modern, fast, powerful node.js web framework (@common)",
"author": "Kamil Mysliwiec",
"homepage": "https://nestjs.com",

View File

@@ -1,10 +1,10 @@
import { isUndefined } from '../../utils/shared.utils';
import { Injectable, Optional } from '../../decorators/core';
import { HttpStatus } from '../../enums';
import { PipeTransform } from '../../interfaces/features/pipe-transform.interface';
import { HttpErrorByCode } from '../../utils/http-error-by-code.util';
import { FileValidator } from './file-validator.interface';
import { ParseFileOptions } from './parse-file-options.interface';
import { isEmpty, isObject } from 'class-validator';
/**
* Defines the built-in ParseFile Pipe. This pipe can be used to validate incoming files
@@ -39,20 +39,36 @@ export class ParseFilePipe implements PipeTransform<any> {
}
async transform(value: any): Promise<any> {
if (isUndefined(value)) {
if (this.thereAreNoFilesIn(value)) {
if (this.fileIsRequired) {
throw this.exceptionFactory('File is required');
}
return value;
}
if (this.validators.length) {
await this.validate(value);
if (Array.isArray(value)) {
await this.validateFiles(value);
} else {
await this.validate(value);
}
}
return value;
}
private validateFiles(files: any[]): Promise<any[]> {
return Promise.all(files.map(f => this.validate(f)));
}
private thereAreNoFilesIn(value: any): boolean {
if (Array.isArray(value)) {
return value.length === 0;
} else {
return isEmpty(value);
}
}
protected async validate(file: any): Promise<any> {
for (const validator of this.validators) {
await this.validateOrThrow(file, validator);

View File

@@ -1,5 +1,4 @@
import { Injectable } from '../decorators/core/injectable.decorator';
import { Optional } from '../decorators/core/optional.decorator';
import { Injectable, Optional } from '../decorators/core';
import { isObject } from '../utils/shared.utils';
import { ConsoleLogger } from './console-logger.service';
import { isLogLevelEnabled } from './utils';
@@ -126,7 +125,9 @@ export class Logger implements LoggerService {
@Logger.WrapBuffer
error(message: any, ...optionalParams: any[]) {
optionalParams = this.context
? optionalParams.concat(this.context)
? (optionalParams.length ? optionalParams : [undefined]).concat(
this.context,
)
: optionalParams;
this.localInstance?.error(message, ...optionalParams);

View File

@@ -480,43 +480,87 @@ describe('Logger', () => {
warn(message: any, context?: string) {}
}
const customLogger = new CustomLogger();
const originalLogger = new Logger();
describe('with global context', () => {
const customLogger = new CustomLogger();
const globalContext = 'RandomContext';
const originalLogger = new Logger(globalContext);
let previousLoggerRef: LoggerService;
let previousLoggerRef: LoggerService;
beforeEach(() => {
previousLoggerRef =
Logger['localInstanceRef'] || Logger['staticInstanceRef'];
Logger.overrideLogger(customLogger);
beforeEach(() => {
previousLoggerRef =
Logger['localInstanceRef'] || Logger['staticInstanceRef'];
Logger.overrideLogger(customLogger);
});
afterEach(() => {
Logger.overrideLogger(previousLoggerRef);
});
it('should call custom logger "#log()" method with context as second argument', () => {
const message = 'random log message with global context';
const customLoggerLogSpy = sinon.spy(customLogger, 'log');
originalLogger.log(message);
expect(customLoggerLogSpy.called).to.be.true;
expect(customLoggerLogSpy.calledWith(message, globalContext)).to.be
.true;
});
it('should call custom logger "#error()" method with context as third argument', () => {
const message = 'random error message with global context';
const customLoggerErrorSpy = sinon.spy(customLogger, 'error');
originalLogger.error(message);
expect(customLoggerErrorSpy.called).to.be.true;
expect(
customLoggerErrorSpy.calledWith(message, undefined, globalContext),
).to.be.true;
});
});
describe('without global context', () => {
const customLogger = new CustomLogger();
const originalLogger = new Logger();
afterEach(() => {
Logger.overrideLogger(previousLoggerRef);
});
let previousLoggerRef: LoggerService;
it('should call custom logger "#log()" method', () => {
const message = 'random message';
const context = 'RandomContext';
beforeEach(() => {
previousLoggerRef =
Logger['localInstanceRef'] || Logger['staticInstanceRef'];
Logger.overrideLogger(customLogger);
});
const customLoggerLogSpy = sinon.spy(customLogger, 'log');
afterEach(() => {
Logger.overrideLogger(previousLoggerRef);
});
originalLogger.log(message, context);
it('should call custom logger "#log()" method', () => {
const message = 'random message';
const context = 'RandomContext';
expect(customLoggerLogSpy.called).to.be.true;
expect(customLoggerLogSpy.calledWith(message, context)).to.be.true;
});
const customLoggerLogSpy = sinon.spy(customLogger, 'log');
it('should call custom logger "#error()" method', () => {
const message = 'random message';
const context = 'RandomContext';
originalLogger.log(message, context);
const customLoggerErrorSpy = sinon.spy(customLogger, 'error');
expect(customLoggerLogSpy.called).to.be.true;
expect(customLoggerLogSpy.calledWith(message, context)).to.be.true;
});
originalLogger.error(message, context);
it('should call custom logger "#error()" method', () => {
const message = 'random message';
const context = 'RandomContext';
expect(customLoggerErrorSpy.called).to.be.true;
expect(customLoggerErrorSpy.calledWith(message, context)).to.be.true;
const customLoggerErrorSpy = sinon.spy(customLogger, 'error');
originalLogger.error(message, undefined, context);
expect(customLoggerErrorSpy.called).to.be.true;
expect(customLoggerErrorSpy.calledWith(message, undefined, context))
.to.be.true;
});
});
});
});

View File

@@ -9,16 +9,16 @@ import { isEmpty } from '@nestjs/common/utils/shared.utils';
import { lastValueFrom, isObservable } from 'rxjs';
import { ExternalExceptionFilterContext } from '../exceptions/external-exception-filter-context';
import { FORBIDDEN_MESSAGE } from '../guards/constants';
import { GuardsConsumer } from '../guards/guards-consumer';
import { GuardsContextCreator } from '../guards/guards-context-creator';
import { GuardsConsumer, GuardsContextCreator } from '../guards';
import { STATIC_CONTEXT } from '../injector/constants';
import { NestContainer } from '../injector/container';
import { ContextId } from '../injector/instance-wrapper';
import { ModulesContainer } from '../injector/modules-container';
import { InterceptorsConsumer } from '../interceptors/interceptors-consumer';
import { InterceptorsContextCreator } from '../interceptors/interceptors-context-creator';
import { PipesConsumer } from '../pipes/pipes-consumer';
import { PipesContextCreator } from '../pipes/pipes-context-creator';
import {
InterceptorsConsumer,
InterceptorsContextCreator,
} from '../interceptors';
import { PipesConsumer, PipesContextCreator } from '../pipes';
import { ContextUtils, ParamProperties } from './context-utils';
import { ExternalErrorProxy } from './external-proxy';
import { HandlerMetadataStorage } from './handler-metadata-storage';

View File

@@ -9,7 +9,7 @@ import {
isUndefined,
} from '@nestjs/common/utils/shared.utils';
import { iterate } from 'iterare';
import { DeterministicUuidRegistry } from '../inspector/deterministic-uuid-registry';
import { UuidFactory } from '../inspector/uuid-factory';
import { STATIC_CONTEXT } from './constants';
import {
isClassProvider,
@@ -469,6 +469,6 @@ export class InstanceWrapper<T = any> {
let key = this.name?.toString() ?? this.token?.toString();
key += this.host?.name ?? '';
return key ? DeterministicUuidRegistry.get(key) : randomStringGenerator();
return key ? UuidFactory.get(key) : randomStringGenerator();
}
}

View File

@@ -30,11 +30,11 @@ import {
import { createContextId } from '../helpers/context-id-factory';
import { getClassScope } from '../helpers/get-class-scope';
import { isDurable } from '../helpers/is-durable';
import { DeterministicUuidRegistry } from '../inspector/deterministic-uuid-registry';
import { UuidFactory } from '../inspector/uuid-factory';
import { CONTROLLER_ID_KEY } from './constants';
import { NestContainer } from './container';
import { InstanceWrapper } from './instance-wrapper';
import { ModuleRefGetOrResolveOpts, ModuleRef } from './module-ref';
import { ModuleRef, ModuleRefGetOrResolveOpts } from './module-ref';
/**
* @note
@@ -626,8 +626,6 @@ export class Module {
private generateUuid(): string {
const UUID_NAMESPACE = 'fb848993-0c82-4b9e-ae95-3c3c1dbe3d6b';
const key = this.name?.toString() ?? this.token?.toString();
return key
? DeterministicUuidRegistry.get(key, UUID_NAMESPACE)
: randomStringGenerator();
return key ? UuidFactory.get(key, UUID_NAMESPACE) : randomStringGenerator();
}
}

View File

@@ -0,0 +1,21 @@
import { randomStringGenerator } from '../../common/utils/random-string-generator.util';
import { DeterministicUuidRegistry } from './deterministic-uuid-registry';
export enum UuidFactoryMode {
Random = 'random',
Deterministic = 'deterministic',
}
export class UuidFactory {
private static _mode = UuidFactoryMode.Random;
static set mode(value: UuidFactoryMode) {
this._mode = value;
}
static get(key = '', namespace?: string) {
return this._mode === UuidFactoryMode.Deterministic
? DeterministicUuidRegistry.get(key, namespace)
: randomStringGenerator();
}
}

View File

@@ -18,7 +18,7 @@ import { ExecutionContextHost } from '../helpers/execution-context-host';
import { STATIC_CONTEXT } from '../injector/constants';
import { NestContainer } from '../injector/container';
import { Injector } from '../injector/injector';
import { InstanceWrapper } from '../injector/instance-wrapper';
import { ContextId, InstanceWrapper } from '../injector/instance-wrapper';
import { InstanceToken, Module } from '../injector/module';
import { GraphInspector } from '../inspector/graph-inspector';
import {
@@ -250,6 +250,9 @@ export class MiddlewareModule<
const proxy = await this.createProxy(instance);
return this.registerHandler(applicationRef, routeInfo, proxy);
}
const isTreeDurable = wrapper.isDependencyTreeDurable();
await this.registerHandler(
applicationRef,
routeInfo,
@@ -259,19 +262,7 @@ export class MiddlewareModule<
next: () => void,
) => {
try {
const contextId = ContextIdFactory.getByRequest(req);
if (!req[REQUEST_CONTEXT_ID]) {
Object.defineProperty(req, REQUEST_CONTEXT_ID, {
value: contextId,
enumerable: false,
writable: false,
configurable: false,
});
this.container.registerRequestProvider(
contextId.getParent ? contextId.payload : req,
contextId,
);
}
const contextId = this.getContextId(req, isTreeDurable);
const contextInstance = await this.injector.loadPerContext(
instance,
moduleRef,
@@ -325,10 +316,11 @@ export class MiddlewareModule<
) {
const prefix = this.config.getGlobalPrefix();
const excludedRoutes = this.config.getGlobalPrefixOptions().exclude;
const isAWildcard = ['*', '/*', '(.*)', '/(.*)'].includes(path);
if (
(Array.isArray(excludedRoutes) &&
isRouteExcluded(excludedRoutes, path, method)) ||
['*', '/*', '(.*)', '/(.*)'].includes(path)
isAWildcard
) {
path = addLeadingSlash(path);
} else {
@@ -352,20 +344,36 @@ export class MiddlewareModule<
const isMethodAll = isRequestMethodAll(method);
const requestMethod = RequestMethod[method];
const router = await applicationRef.createMiddlewareFactory(method);
router(
path,
isMethodAll
? proxy
: <TRequest, TResponse>(
req: TRequest,
res: TResponse,
next: () => void,
) => {
if (applicationRef.getRequestMethod(req) === requestMethod) {
return proxy(req, res, next);
}
return next();
},
);
const middlewareFunction = isMethodAll
? proxy
: <TRequest, TResponse>(
req: TRequest,
res: TResponse,
next: () => void,
) => {
if (applicationRef.getRequestMethod(req) === requestMethod) {
return proxy(req, res, next);
}
return next();
};
router(path, middlewareFunction);
}
private getContextId(request: unknown, isTreeDurable: boolean): ContextId {
const contextId = ContextIdFactory.getByRequest(request);
if (!request[REQUEST_CONTEXT_ID]) {
Object.defineProperty(request, REQUEST_CONTEXT_ID, {
value: contextId,
enumerable: false,
writable: false,
configurable: false,
});
const requestProviderValue = isTreeDurable ? contextId.payload : request;
this.container.registerRequestProvider(requestProviderValue, contextId);
}
return contextId;
}
}

View File

@@ -13,6 +13,7 @@ export const mapToExcludeRoute = (
return routes.map(({ path, method }) => ({
pathRegex: pathToRegexp(path),
requestMethod: method,
path,
}));
};

View File

@@ -323,13 +323,20 @@ export class NestApplicationContext<
* @param {string[]} signals The system signals it should listen to
*/
protected listenToShutdownSignals(signals: string[]) {
let receivedSignal = false;
const cleanup = async (signal: string) => {
try {
signals.forEach(sig => process.removeListener(sig, cleanup));
if (receivedSignal) {
// If we receive another signal while we're waiting
// for the server to stop, just ignore it.
return;
}
receivedSignal = true;
await this.callDestroyHook();
await this.callBeforeShutdownHook(signal);
await this.dispose();
await this.callShutdownHook(signal);
signals.forEach(sig => process.removeListener(sig, cleanup));
process.kill(process.pid, signal);
} catch (err) {
Logger.error(

View File

@@ -266,6 +266,20 @@ export class NestApplication
return this;
}
public useBodyParser(...args: [any, any?]): this {
if (!('useBodyParser' in this.httpAdapter)) {
this.logger.warn('Your HTTP Adapter does not support `.useBodyParser`.');
return this;
}
const [parserType, ...otherArgs] = args;
const rawBody = !!this.appOptions.rawBody;
this.httpAdapter.useBodyParser(...[parserType, rawBody, ...otherArgs]);
return this;
}
public enableCors(options?: CorsOptions | CorsOptionsDelegate<any>): void {
this.httpAdapter.enableCors(options);
}
@@ -364,11 +378,13 @@ export class NestApplication
return {
requestMethod: RequestMethod.ALL,
pathRegex: pathToRegexp(addLeadingSlash(route)),
path: route,
};
}
return {
requestMethod: route.method,
pathRegex: pathToRegexp(addLeadingSlash(route.path)),
path: route.path,
};
},
);

View File

@@ -21,6 +21,7 @@ import { Injector } from './injector/injector';
import { InstanceLoader } from './injector/instance-loader';
import { GraphInspector } from './inspector/graph-inspector';
import { NoopGraphInspector } from './inspector/noop-graph-inspector';
import { UuidFactory, UuidFactoryMode } from './inspector/uuid-factory';
import { MetadataScanner } from './metadata-scanner';
import { NestApplication } from './nest-application';
import { NestApplicationContext } from './nest-application-context';
@@ -195,6 +196,10 @@ export class NestFactoryStatic {
options: NestApplicationContextOptions = {},
httpServer: HttpServer = null,
) {
UuidFactory.mode = options.snapshot
? UuidFactoryMode.Deterministic
: UuidFactoryMode.Random;
const injector = new Injector({ preview: options.preview });
const instanceLoader = new InstanceLoader(
container,

View File

@@ -1,6 +1,6 @@
{
"name": "@nestjs/core",
"version": "9.3.0-beta.3",
"version": "9.3.0",
"description": "Nest - modern, fast, powerful node.js web framework (@core)",
"author": "Kamil Mysliwiec",
"license": "MIT",
@@ -36,7 +36,7 @@
"uuid": "9.0.0"
},
"devDependencies": {
"@nestjs/common": "^9.3.0-beta.3"
"@nestjs/common": "9.3.0"
},
"peerDependencies": {
"@nestjs/common": "^9.0.0",

View File

@@ -1,6 +1,7 @@
import { RequestMethod } from '@nestjs/common';
export interface ExcludeRouteMetadata {
path: string;
/**
* Regular expression representing the route path.
*/

View File

@@ -13,8 +13,7 @@ import {
import * as pathToRegexp from 'path-to-regexp';
import { ApplicationConfig } from '../application-config';
import { UnknownRequestMappingException } from '../errors/exceptions/unknown-request-mapping.exception';
import { GuardsConsumer } from '../guards/guards-consumer';
import { GuardsContextCreator } from '../guards/guards-context-creator';
import { GuardsConsumer, GuardsContextCreator } from '../guards';
import { ContextIdFactory } from '../helpers/context-id-factory';
import { ExecutionContextHost } from '../helpers/execution-context-host';
import {
@@ -27,16 +26,17 @@ import { NestContainer } from '../injector/container';
import { Injector } from '../injector/injector';
import { ContextId, InstanceWrapper } from '../injector/instance-wrapper';
import { Module } from '../injector/module';
import {
InterceptorsConsumer,
InterceptorsContextCreator,
} from '../interceptors';
import { GraphInspector } from '../inspector/graph-inspector';
import {
Entrypoint,
HttpEntrypointMetadata,
} from '../inspector/interfaces/entrypoint.interface';
import { InterceptorsConsumer } from '../interceptors/interceptors-consumer';
import { InterceptorsContextCreator } from '../interceptors/interceptors-context-creator';
import { MetadataScanner } from '../metadata-scanner';
import { PipesConsumer } from '../pipes/pipes-consumer';
import { PipesContextCreator } from '../pipes/pipes-context-creator';
import { PipesConsumer, PipesContextCreator } from '../pipes';
import { ExceptionsFilter } from './interfaces/exceptions-filter.interface';
import { RoutePathMetadata } from './interfaces/route-path-metadata.interface';
import { PathsExplorer } from './paths-explorer';
@@ -355,13 +355,16 @@ export class RouterExplorer {
) {
const { instance } = instanceWrapper;
const collection = moduleRef.controllers;
const isTreeDurable = instanceWrapper.isDependencyTreeDurable();
return async <TRequest extends Record<any, any>, TResponse>(
req: TRequest,
res: TResponse,
next: () => void,
) => {
try {
const contextId = this.getContextId(req);
const contextId = this.getContextId(req, isTreeDurable);
const contextInstance = await this.injector.loadPerContext(
instance,
moduleRef,
@@ -397,6 +400,7 @@ export class RouterExplorer {
private getContextId<T extends Record<any, unknown> = any>(
request: T,
isTreeDurable: boolean,
): ContextId {
const contextId = ContextIdFactory.getByRequest(request);
if (!request[REQUEST_CONTEXT_ID as any]) {
@@ -406,10 +410,9 @@ export class RouterExplorer {
writable: false,
configurable: false,
});
this.container.registerRequestProvider(
contextId.getParent ? contextId.payload : request,
contextId,
);
const requestProviderValue = isTreeDurable ? contextId.payload : request;
this.container.registerRequestProvider(requestProviderValue, contextId);
}
return contextId;
}

View File

@@ -23,10 +23,11 @@ import {
PipeTransform,
Scope,
ValueProvider,
Controller,
Injectable,
Type,
} from '@nestjs/common/interfaces';
import { Controller } from '@nestjs/common/interfaces/controllers/controller.interface';
import { Injectable } from '@nestjs/common/interfaces/injectable.interface';
import { Type } from '@nestjs/common/interfaces/type.interface';
import { randomStringGenerator } from '@nestjs/common/utils/random-string-generator.util';
import {
isFunction,
isNil,
@@ -50,8 +51,8 @@ import { NestContainer } from './injector/container';
import { InstanceWrapper } from './injector/instance-wrapper';
import { InternalCoreModuleFactory } from './injector/internal-core-module/internal-core-module-factory';
import { Module } from './injector/module';
import { DeterministicUuidRegistry } from './inspector/deterministic-uuid-registry';
import { GraphInspector } from './inspector/graph-inspector';
import { UuidFactory } from './inspector/uuid-factory';
import { MetadataScanner } from './metadata-scanner';
interface ApplicationProviderWrapper {
@@ -410,7 +411,7 @@ export class DependenciesScanner {
if (!providersKeys.includes(type as string)) {
return this.container.addProvider(provider as any, token);
}
const uuid = DeterministicUuidRegistry.get(type.toString());
const uuid = UuidFactory.get(type.toString());
const providerToken = `${type as string} (UUID: ${uuid})`;
let scope = (provider as ClassProvider | FactoryProvider).scope;

View File

@@ -23,7 +23,11 @@ describe('ApplicationConfig', () => {
it('should set global path options', () => {
const options: GlobalPrefixOptions<ExcludeRouteMetadata> = {
exclude: [
{ pathRegex: new RegExp(/health/), requestMethod: RequestMethod.GET },
{
pathRegex: new RegExp(/health/),
requestMethod: RequestMethod.GET,
path: 'health',
},
],
};
appConfig.setGlobalPrefixOptions(options);

View File

@@ -6,6 +6,7 @@ import { Injector } from '../injector/injector';
import { InstanceLoader } from '../injector/instance-loader';
import { GraphInspector } from '../inspector/graph-inspector';
import { NestApplicationContext } from '../nest-application-context';
import * as sinon from 'sinon';
describe('NestApplicationContext', () => {
class A {}
@@ -49,6 +50,54 @@ describe('NestApplicationContext', () => {
return applicationContext;
}
describe('listenToShutdownSignals', () => {
it('shutdown process should not be interrupted by another handler', async () => {
const signal = 'SIGTERM';
let processUp = true;
let promisesResolved = false;
const applicationContext = await testHelper(A, Scope.DEFAULT);
applicationContext.enableShutdownHooks([signal]);
const waitProcessDown = new Promise(resolve => {
const shutdownCleanupRef = applicationContext['shutdownCleanupRef'];
const handler = () => {
if (
!process
.listeners(signal)
.find(handler => handler == shutdownCleanupRef)
) {
processUp = false;
process.removeListener(signal, handler);
resolve(undefined);
}
return undefined;
};
process.on(signal, handler);
});
// add some third party handler
process.on(signal, signal => {
// do some work
process.kill(process.pid, signal);
});
const hookStub = sinon
.stub(applicationContext as any, 'callShutdownHook')
.callsFake(async () => {
// run some async code
await new Promise(resolve => setImmediate(() => resolve(undefined)));
if (processUp) {
promisesResolved = true;
}
});
process.kill(process.pid, signal);
await waitProcessDown;
hookStub.restore();
expect(processUp).to.be.false;
expect(promisesResolved).to.be.true;
});
});
describe('get', () => {
describe('when scope = DEFAULT', () => {
it('should get value with function injection key', async () => {

View File

@@ -249,6 +249,7 @@ describe('RoutePathFactory', () => {
{
pathRegex: pathToRegexp('/random'),
requestMethod: RequestMethod.ALL,
path: '/random',
},
],
});
@@ -267,6 +268,7 @@ describe('RoutePathFactory', () => {
{
pathRegex: pathToRegexp('/cats'),
requestMethod: RequestMethod.ALL,
path: '/cats',
},
],
});
@@ -285,6 +287,7 @@ describe('RoutePathFactory', () => {
{
pathRegex: pathToRegexp('/cats'),
requestMethod: RequestMethod.GET,
path: '/cats',
},
],
});

View File

@@ -205,13 +205,15 @@ export class ListenersController {
const collection = moduleRef.controllers;
const { instance } = wrapper;
const isTreeDurable = wrapper.isDependencyTreeDurable();
const requestScopedHandler: MessageHandler = async (...args: unknown[]) => {
try {
let contextId: ContextId;
let [dataOrContextHost] = args;
if (dataOrContextHost instanceof RequestContextHost) {
contextId = this.getContextId(dataOrContextHost);
contextId = this.getContextId(dataOrContextHost, isTreeDurable);
args.shift();
} else {
const [data, reqCtx] = args;
@@ -220,11 +222,7 @@ export class ListenersController {
data,
reqCtx as BaseRpcContext,
);
contextId = this.getContextId(request);
this.container.registerRequestProvider(
contextId.getParent ? contextId.payload : request,
contextId,
);
contextId = this.getContextId(request, isTreeDurable);
dataOrContextHost = request;
}
const contextInstance = await this.injector.loadPerContext(
@@ -270,7 +268,10 @@ export class ListenersController {
return requestScopedHandler;
}
private getContextId<T extends RequestContext = any>(request: T): ContextId {
private getContextId<T extends RequestContext = any>(
request: T,
isTreeDurable: boolean,
): ContextId {
const contextId = ContextIdFactory.getByRequest(request);
if (!request[REQUEST_CONTEXT_ID as any]) {
Object.defineProperty(request, REQUEST_CONTEXT_ID, {
@@ -279,10 +280,9 @@ export class ListenersController {
writable: false,
configurable: false,
});
this.container.registerRequestProvider(
contextId.getParent ? contextId.payload : request,
contextId,
);
const requestProviderValue = isTreeDurable ? contextId.payload : request;
this.container.registerRequestProvider(requestProviderValue, contextId);
}
return contextId;
}

View File

@@ -1,6 +1,6 @@
{
"name": "@nestjs/microservices",
"version": "9.3.0-beta.3",
"version": "9.3.0",
"description": "Nest - modern, fast, powerful node.js web framework (@microservices)",
"author": "Kamil Mysliwiec",
"license": "MIT",
@@ -21,8 +21,8 @@
"tslib": "2.4.1"
},
"devDependencies": {
"@nestjs/common": "^9.3.0-beta.3",
"@nestjs/core": "^9.3.0-beta.3"
"@nestjs/common": "9.3.0",
"@nestjs/core": "9.3.0"
},
"peerDependencies": {
"@grpc/grpc-js": "*",

View File

@@ -218,6 +218,8 @@ export class ServerKafka extends Server implements CustomTransportStrategy {
if (err instanceof KafkaRetriableException && !isPromiseResolved) {
isPromiseResolved = true;
reject(err);
} else {
resolve()
}
replayStream$.error(err);
},

View File

@@ -29,11 +29,13 @@ import {
OptionsUrlencoded,
urlencoded as bodyParserUrlencoded,
} from 'body-parser';
import * as bodyparser from 'body-parser';
import * as cors from 'cors';
import * as express from 'express';
import * as http from 'http';
import * as https from 'https';
import { Duplex, pipeline } from 'stream';
import { NestExpressBodyParserOptions } from '../interfaces/nest-express-body-parser-options.interface';
import { ServeStaticOptions } from '../interfaces/serve-static-options.interface';
import { getBodyParserOptions } from './utils/get-body-parser-options.util';
@@ -235,6 +237,19 @@ export class ExpressAdapter extends AbstractHttpAdapter {
.forEach(parserKey => this.use(parserMiddleware[parserKey]));
}
public useBodyParser<Options extends bodyparser.Options = bodyparser.Options>(
type: keyof bodyparser.BodyParser,
rawBody: boolean,
options?: NestExpressBodyParserOptions<Options>,
): this {
const parserOptions = getBodyParserOptions(rawBody, options || {});
const parser = bodyparser[type](parserOptions);
this.use(parser);
return this;
}
public setLocal(key: string, value: any) {
this.instance.locals[key] = value;
return this;

View File

@@ -1 +1,2 @@
export * from './nest-express-application.interface';
export * from './nest-express-body-parser-options.interface';

View File

@@ -1,5 +1,7 @@
import { Server } from 'net';
import { INestApplication } from '@nestjs/common';
import * as bodyparser from 'body-parser';
import { NestExpressBodyParserOptions } from './nest-express-body-parser-options.interface';
import { ServeStaticOptions } from './serve-static-options.interface';
/**
@@ -73,6 +75,24 @@ export interface NestExpressApplication extends INestApplication {
*/
useStaticAssets(path: string, options?: ServeStaticOptions): this;
/**
* Register Express body parsers on the fly. Will respect
* the application's `rawBody` option.
*
* @example
* const app = await NestFactory.create<NestExpressApplication>(
* AppModule,
* { rawBody: true }
* );
* app.useBodyParser('json', { limit: '50mb' });
*
* @returns {this}
*/
useBodyParser<Options extends bodyparser.Options = bodyparser.Options>(
parser: keyof bodyparser.BodyParser,
options?: NestExpressBodyParserOptions<Options>,
): this;
/**
* Sets one or multiple base directories for templates (views).
*

View File

@@ -0,0 +1,6 @@
import type { Options } from 'body-parser';
export type NestExpressBodyParserOptions<T extends Options = Options> = Omit<
T,
'verify'
>;

View File

@@ -1,6 +1,6 @@
{
"name": "@nestjs/platform-express",
"version": "9.3.0-beta.3",
"version": "9.3.0",
"description": "Nest - modern, fast, powerful node.js web framework (@platform-express)",
"author": "Kamil Mysliwiec",
"license": "MIT",
@@ -24,8 +24,8 @@
"tslib": "2.4.1"
},
"devDependencies": {
"@nestjs/common": "^9.3.0-beta.3",
"@nestjs/core": "^9.3.0-beta.3"
"@nestjs/common": "9.3.0",
"@nestjs/core": "9.3.0"
},
"peerDependencies": {
"@nestjs/common": "^9.0.0",

View File

@@ -18,9 +18,10 @@ import { isString, isUndefined } from '@nestjs/common/utils/shared.utils';
import { AbstractHttpAdapter } from '@nestjs/core/adapters/http-adapter';
import {
fastify,
FastifyBaseLogger,
FastifyBodyParser,
FastifyInstance,
FastifyBaseLogger,
FastifyListenOptions,
FastifyPluginAsync,
FastifyPluginCallback,
FastifyRegister,
@@ -45,6 +46,7 @@ import {
} from 'light-my-request';
// `querystring` is used internally in fastify for registering urlencoded body parser.
import { parse as querystringParse } from 'querystring';
import { NestFastifyBodyParserOptions } from '../interfaces';
import {
FastifyStaticOptions,
FastifyViewOptions,
@@ -227,12 +229,27 @@ export class FastifyAdapter<
hostname: string,
callback?: () => void,
): void;
public listen(port: string | number, ...args: any[]): void {
public listen(
listenOptions: string | number | FastifyListenOptions,
...args: any[]
): void {
const isFirstArgTypeofFunction = typeof args[0] === 'function';
const callback = isFirstArgTypeofFunction ? args[0] : args[1];
const options: Record<string, any> = {
port: +port,
};
let options: Record<string, any>;
if (
typeof listenOptions === 'object' &&
(listenOptions.host !== undefined ||
listenOptions.port !== undefined ||
listenOptions.path !== undefined)
) {
// First parameter is an object with a path, port and/or host attributes
options = listenOptions;
} else {
options = {
port: +listenOptions,
};
}
if (!isFirstArgTypeofFunction) {
options.host = args[0];
}
@@ -465,6 +482,43 @@ export class FastifyAdapter<
this._isParserRegistered = true;
}
public useBodyParser(
type: string | string[] | RegExp,
rawBody: boolean,
options?: NestFastifyBodyParserOptions,
parser?: FastifyBodyParser<Buffer, TServer>,
) {
const parserOptions = {
...(options || {}),
parseAs: 'buffer' as const,
};
this.getInstance().addContentTypeParser<Buffer>(
type,
parserOptions,
(
req: RawBodyRequest<FastifyRequest<unknown, TServer, TRawRequest>>,
body: Buffer,
done,
) => {
if (rawBody === true && Buffer.isBuffer(body)) {
req.rawBody = body;
}
if (parser) {
parser(req, body, done);
return;
}
done(null, body);
},
);
// To avoid the Nest application init to override our custom
// body parser, we mark the parsers as registered.
this._isParserRegistered = true;
}
public async createMiddlewareFactory(
requestMethod: RequestMethod,
): Promise<(path: string, callback: Function) => any> {
@@ -510,20 +564,15 @@ export class FastifyAdapter<
}
private registerJsonContentParser(rawBody?: boolean) {
const contentType = 'application/json';
const withRawBody = !!rawBody;
const { bodyLimit } = this.getInstance().initialConfig;
this.getInstance().addContentTypeParser<Buffer>(
'application/json',
{ parseAs: 'buffer', bodyLimit },
(
req: RawBodyRequest<FastifyRequest<unknown, TServer, TRawRequest>>,
body: Buffer,
done,
) => {
if (rawBody === true && Buffer.isBuffer(body)) {
req.rawBody = body;
}
this.useBodyParser(
contentType,
withRawBody,
{ bodyLimit },
(req, body, done) => {
const { onProtoPoisoning, onConstructorPoisoning } =
this.instance.initialConfig;
const defaultJsonParser = this.instance.getDefaultJsonParser(
@@ -536,20 +585,15 @@ export class FastifyAdapter<
}
private registerUrlencodedContentParser(rawBody?: boolean) {
const contentType = 'application/x-www-form-urlencoded';
const withRawBody = !!rawBody;
const { bodyLimit } = this.getInstance().initialConfig;
this.getInstance().addContentTypeParser<Buffer>(
'application/x-www-form-urlencoded',
{ parseAs: 'buffer', bodyLimit },
(
req: RawBodyRequest<FastifyRequest<unknown, TServer, TRawRequest>>,
body: Buffer,
done,
) => {
if (rawBody === true && Buffer.isBuffer(body)) {
req.rawBody = body;
}
this.useBodyParser(
contentType,
withRawBody,
{ bodyLimit },
(_req, body, done) => {
done(null, querystringParse(body.toString()));
},
);

View File

@@ -1 +1,2 @@
export * from './nest-fastify-application.interface';
export * from './nest-fastify-body-parser-options.interface';

View File

@@ -1,10 +1,12 @@
import { INestApplication } from '@nestjs/common';
import {
FastifyBodyParser,
FastifyInstance,
FastifyPluginAsync,
FastifyPluginCallback,
FastifyPluginOptions,
FastifyRegisterOptions,
RawServerBase,
} from 'fastify';
import {
Chain as LightMyRequestChain,
@@ -12,6 +14,7 @@ import {
Response as LightMyRequestResponse,
} from 'light-my-request';
import { FastifyStaticOptions, FastifyViewOptions } from './external';
import { NestFastifyBodyParserOptions } from './nest-fastify-body-parser-options.interface';
export interface NestFastifyApplication extends INestApplication {
/**
@@ -28,6 +31,27 @@ export interface NestFastifyApplication extends INestApplication {
opts?: FastifyRegisterOptions<Options>,
): Promise<FastifyInstance>;
/**
* Register Fastify body parsers on the fly. Will respect
* the application's `rawBody` option.
*
* @example
* const app = await NestFactory.create<NestFastifyApplication>(
* AppModule,
* new FastifyAdapter(),
* { rawBody: true }
* );
* // enable the json parser with a parser limit of 50mb
* app.useBodyParser('application/json', { bodyLimit: 50 * 1000 * 1024 });
*
* @returns {this}
*/
useBodyParser<TServer extends RawServerBase = RawServerBase>(
type: string | string[] | RegExp,
options?: NestFastifyBodyParserOptions,
parser?: FastifyBodyParser<Buffer, TServer>,
): this;
/**
* Sets a base directory for public assets.
* Example `app.useStaticAssets({ root: 'public' })`

View File

@@ -0,0 +1,6 @@
import type { AddContentTypeParser } from 'fastify';
export type NestFastifyBodyParserOptions = Omit<
Parameters<AddContentTypeParser>[1],
'parseAs'
>;

View File

@@ -1,6 +1,6 @@
{
"name": "@nestjs/platform-fastify",
"version": "9.3.0-beta.3",
"version": "9.3.0",
"description": "Nest - modern, fast, powerful node.js web framework (@platform-fastify)",
"author": "Kamil Mysliwiec",
"license": "MIT",

View File

@@ -1,6 +1,6 @@
{
"name": "@nestjs/platform-socket.io",
"version": "9.3.0-beta.3",
"version": "9.3.0",
"description": "Nest - modern, fast, powerful node.js web framework (@platform-socket.io)",
"author": "Kamil Mysliwiec",
"license": "MIT",

View File

@@ -1,6 +1,6 @@
{
"name": "@nestjs/platform-ws",
"version": "9.3.0-beta.3",
"version": "9.3.0",
"description": "Nest - modern, fast, powerful node.js web framework (@platform-ws)",
"author": "Kamil Mysliwiec",
"license": "MIT",

View File

@@ -1,6 +1,6 @@
{
"name": "@nestjs/testing",
"version": "9.3.0-beta.3",
"version": "9.3.0",
"description": "Nest - modern, fast, powerful node.js web framework (@testing)",
"author": "Kamil Mysliwiec",
"license": "MIT",

View File

@@ -1,10 +1,13 @@
import { Logger, LoggerService, Module } from '@nestjs/common';
import { ModuleMetadata } from '@nestjs/common/interfaces';
import { Logger, LoggerService, Module, ModuleMetadata } from '@nestjs/common';
import { NestApplicationContextOptions } from '@nestjs/common/interfaces/nest-application-context-options.interface';
import { ApplicationConfig } from '@nestjs/core/application-config';
import { NestContainer } from '@nestjs/core/injector/container';
import { GraphInspector } from '@nestjs/core/inspector/graph-inspector';
import { NoopGraphInspector } from '@nestjs/core/inspector/noop-graph-inspector';
import {
UuidFactory,
UuidFactoryMode,
} from '@nestjs/core/inspector/uuid-factory';
import { MetadataScanner } from '@nestjs/core/metadata-scanner';
import { DependenciesScanner } from '@nestjs/core/scanner';
import {
@@ -68,9 +71,14 @@ export class TestingModuleBuilder {
): Promise<TestingModule> {
this.applyLogger();
const graphInspector = options?.snapshot
? new GraphInspector(this.container)
: NoopGraphInspector;
let graphInspector: GraphInspector;
if (options?.snapshot) {
graphInspector = new GraphInspector(this.container);
UuidFactory.mode = UuidFactoryMode.Deterministic;
} else {
graphInspector = NoopGraphInspector;
UuidFactory.mode = UuidFactoryMode.Random;
}
const scanner = new DependenciesScanner(
this.container,
@@ -81,17 +89,7 @@ export class TestingModuleBuilder {
await scanner.scan(this.module);
this.applyOverloadsMap();
const instanceLoader = new TestingInstanceLoader(
this.container,
this.injector,
graphInspector,
);
await instanceLoader.createInstancesOfDependencies(
this.container.getModules(),
this.mocker,
);
await this.createInstancesOfDependencies(graphInspector);
scanner.applyApplicationProviders();
const root = this.getRootModule();
@@ -136,6 +134,18 @@ export class TestingModuleBuilder {
return modules.next().value;
}
private async createInstancesOfDependencies(graphInspector: GraphInspector) {
const instanceLoader = new TestingInstanceLoader(
this.container,
this.injector,
graphInspector,
);
await instanceLoader.createInstancesOfDependencies(
this.container.getModules(),
this.mocker,
);
}
private createModule(metadata: ModuleMetadata) {
class RootTestModule {}
Module(metadata)(RootTestModule);

View File

@@ -18,10 +18,11 @@ import {
import { ExecutionContextHost } from '@nestjs/core/helpers/execution-context-host';
import { HandlerMetadataStorage } from '@nestjs/core/helpers/handler-metadata-storage';
import { ParamsMetadata } from '@nestjs/core/helpers/interfaces';
import { InterceptorsConsumer } from '@nestjs/core/interceptors/interceptors-consumer';
import { InterceptorsContextCreator } from '@nestjs/core/interceptors/interceptors-context-creator';
import { PipesConsumer } from '@nestjs/core/pipes/pipes-consumer';
import { PipesContextCreator } from '@nestjs/core/pipes/pipes-context-creator';
import {
InterceptorsConsumer,
InterceptorsContextCreator,
} from '@nestjs/core/interceptors';
import { PipesConsumer, PipesContextCreator } from '@nestjs/core/pipes';
import { PARAM_ARGS_METADATA } from '../constants';
import { WsException } from '../errors/ws-exception';
import { WsParamsFactory } from '../factories/ws-params-factory';

View File

@@ -1,6 +1,6 @@
{
"name": "@nestjs/websockets",
"version": "9.3.0-beta.3",
"version": "9.3.0",
"description": "Nest - modern, fast, powerful node.js web framework (@websockets)",
"author": "Kamil Mysliwiec",
"license": "MIT",
@@ -17,8 +17,8 @@
"tslib": "2.4.1"
},
"devDependencies": {
"@nestjs/common": "^9.3.0-beta.3",
"@nestjs/core": "^9.3.0-beta.3"
"@nestjs/common": "9.3.0",
"@nestjs/core": "9.3.0"
},
"peerDependencies": {
"@nestjs/common": "^9.0.0",

View File

@@ -1440,9 +1440,9 @@
}
},
"node_modules/@nestjs/cli/node_modules/json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"dependencies": {
"minimist": "^1.2.0"
@@ -3792,9 +3792,9 @@
}
},
"node_modules/eslint-plugin-import/node_modules/json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"dependencies": {
"minimist": "^1.2.0"
@@ -5957,9 +5957,9 @@
"dev": true
},
"node_modules/json5": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true,
"bin": {
"json5": "lib/cli.js"
@@ -8076,9 +8076,9 @@
}
},
"node_modules/tsconfig-paths-webpack-plugin/node_modules/json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"dependencies": {
"minimist": "^1.2.0"
@@ -9654,9 +9654,9 @@
}
},
"json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"requires": {
"minimist": "^1.2.0"
@@ -11547,9 +11547,9 @@
}
},
"json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"requires": {
"minimist": "^1.2.0"
@@ -13079,9 +13079,9 @@
"dev": true
},
"json5": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true
},
"jsonc-parser": {
@@ -14619,9 +14619,9 @@
},
"dependencies": {
"json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"requires": {
"minimist": "^1.2.0"

View File

@@ -1365,9 +1365,9 @@
}
},
"node_modules/@nestjs/cli/node_modules/json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"dependencies": {
"minimist": "^1.2.0"
@@ -3843,9 +3843,9 @@
}
},
"node_modules/eslint-plugin-import/node_modules/json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"dependencies": {
"minimist": "^1.2.0"
@@ -5990,9 +5990,9 @@
"dev": true
},
"node_modules/json5": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true,
"bin": {
"json5": "lib/cli.js"
@@ -6376,12 +6376,6 @@
"lodash": "^4.17.21"
}
},
"node_modules/node-emoji/node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
},
"node_modules/node-fetch": {
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
@@ -8153,9 +8147,9 @@
}
},
"node_modules/tsconfig-paths-webpack-plugin/node_modules/json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"dependencies": {
"minimist": "^1.2.0"
@@ -9711,9 +9705,9 @@
}
},
"json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"requires": {
"minimist": "^1.2.0"
@@ -11689,9 +11683,9 @@
}
},
"json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"requires": {
"minimist": "^1.2.0"
@@ -13236,9 +13230,9 @@
"dev": true
},
"json5": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true
},
"jsonc-parser": {
@@ -13530,14 +13524,6 @@
"dev": true,
"requires": {
"lodash": "^4.17.21"
},
"dependencies": {
"lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
}
}
},
"node-fetch": {
@@ -14824,9 +14810,9 @@
},
"dependencies": {
"json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"requires": {
"minimist": "^1.2.0"

View File

@@ -1349,9 +1349,9 @@
}
},
"node_modules/@nestjs/cli/node_modules/json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"dependencies": {
"minimist": "^1.2.0"
@@ -3709,9 +3709,9 @@
}
},
"node_modules/eslint-plugin-import/node_modules/json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"dependencies": {
"minimist": "^1.2.0"
@@ -5841,9 +5841,9 @@
"dev": true
},
"node_modules/json5": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true,
"bin": {
"json5": "lib/cli.js"
@@ -6227,12 +6227,6 @@
"lodash": "^4.17.21"
}
},
"node_modules/node-emoji/node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
},
"node_modules/node-fetch": {
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
@@ -7956,9 +7950,9 @@
}
},
"node_modules/tsconfig-paths-webpack-plugin/node_modules/json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"dependencies": {
"minimist": "^1.2.0"
@@ -9472,9 +9466,9 @@
}
},
"json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"requires": {
"minimist": "^1.2.0"
@@ -11332,9 +11326,9 @@
}
},
"json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"requires": {
"minimist": "^1.2.0"
@@ -12867,9 +12861,9 @@
"dev": true
},
"json5": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true
},
"jsonc-parser": {
@@ -13161,14 +13155,6 @@
"dev": true,
"requires": {
"lodash": "^4.17.21"
},
"dependencies": {
"lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
}
}
},
"node-fetch": {
@@ -14415,9 +14401,9 @@
},
"dependencies": {
"json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"requires": {
"minimist": "^1.2.0"

View File

@@ -1429,9 +1429,9 @@
}
},
"node_modules/@nestjs/cli/node_modules/json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"dependencies": {
"minimist": "^1.2.0"
@@ -3839,9 +3839,9 @@
}
},
"node_modules/eslint-plugin-import/node_modules/json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"dependencies": {
"minimist": "^1.2.0"
@@ -6060,9 +6060,9 @@
"dev": true
},
"node_modules/json5": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true,
"bin": {
"json5": "lib/cli.js"
@@ -6462,12 +6462,6 @@
"lodash": "^4.17.21"
}
},
"node_modules/node-emoji/node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
},
"node_modules/node-fetch": {
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
@@ -8147,9 +8141,9 @@
}
},
"node_modules/tsconfig-paths-webpack-plugin/node_modules/json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"dependencies": {
"minimist": "^1.2.0"
@@ -9717,9 +9711,9 @@
}
},
"json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"requires": {
"minimist": "^1.2.0"
@@ -11606,9 +11600,9 @@
}
},
"json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"requires": {
"minimist": "^1.2.0"
@@ -13228,9 +13222,9 @@
"dev": true
},
"json5": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true
},
"jsonc-parser": {
@@ -13540,14 +13534,6 @@
"dev": true,
"requires": {
"lodash": "^4.17.21"
},
"dependencies": {
"lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
}
}
},
"node-fetch": {
@@ -14755,9 +14741,9 @@
},
"dependencies": {
"json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"requires": {
"minimist": "^1.2.0"