mirror of
https://github.com/nestjs/nest.git
synced 2026-02-24 00:02:56 +00:00
Compare commits
1 Commits
feat/allow
...
revert-110
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b82d055a52 |
@@ -1,127 +1,86 @@
|
||||
version: 2.1
|
||||
|
||||
parameters:
|
||||
check-legacy-node-version:
|
||||
type: boolean
|
||||
default: false
|
||||
legacy-node-version:
|
||||
type: string
|
||||
default: '14.21.3'
|
||||
maintenance-node-version:
|
||||
type: string
|
||||
default: '16.20'
|
||||
active-node-version:
|
||||
type: string
|
||||
default: '18.17'
|
||||
current-node-version:
|
||||
type: string
|
||||
default: '20.5'
|
||||
version: 2
|
||||
|
||||
aliases:
|
||||
- &restore-cache
|
||||
restore_cache:
|
||||
key: dependency-cache-{{ checksum "package.json" }}
|
||||
- &save-cache
|
||||
save_cache:
|
||||
key: dependency-cache-{{ checksum "package.json" }}
|
||||
paths:
|
||||
- ./node_modules
|
||||
key: dependency-cache-{{ checksum "package.json" }}
|
||||
- &install-deps
|
||||
run:
|
||||
name: Install dependencies
|
||||
command: npm ci --legacy-peer-deps
|
||||
name: Install dependencies
|
||||
command: npm ci
|
||||
- &build-packages
|
||||
run:
|
||||
name: Build
|
||||
command: npm run build
|
||||
name: Build
|
||||
command: npm run build
|
||||
- &run-unit-tests
|
||||
run:
|
||||
name: Test
|
||||
command: npm run test
|
||||
name: Test
|
||||
command: npm run test
|
||||
|
||||
unit-tests-template: &unit-tests-template
|
||||
working_directory: ~/nest
|
||||
steps:
|
||||
- checkout
|
||||
- *restore-cache
|
||||
- *install-deps
|
||||
- *build-packages
|
||||
- *run-unit-tests
|
||||
|
||||
jobs:
|
||||
build:
|
||||
working_directory: ~/nest
|
||||
docker:
|
||||
- image: cimg/node:<< pipeline.parameters.maintenance-node-version >>
|
||||
- image: circleci/node:12
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Update NPM version
|
||||
command: 'sudo npm install -g npm@^9'
|
||||
- *restore-cache
|
||||
- *install-deps
|
||||
- *save-cache
|
||||
- *build-packages
|
||||
command: 'sudo npm install -g npm@^8'
|
||||
- restore_cache:
|
||||
key: dependency-cache-{{ checksum "package.json" }}
|
||||
- run:
|
||||
name: Install dependencies
|
||||
command: npm ci
|
||||
- save_cache:
|
||||
key: dependency-cache-{{ checksum "package.json" }}
|
||||
paths:
|
||||
- ./node_modules
|
||||
- run:
|
||||
name: Build
|
||||
command: npm run build
|
||||
|
||||
test_node_12:
|
||||
<<: *unit-tests-template
|
||||
docker:
|
||||
- image: circleci/node:12
|
||||
|
||||
test:
|
||||
parameters:
|
||||
node-version:
|
||||
type: string
|
||||
test_node_14:
|
||||
<<: *unit-tests-template
|
||||
docker:
|
||||
- image: circleci/node:14
|
||||
|
||||
test_node_16:
|
||||
working_directory: ~/nest
|
||||
docker:
|
||||
- image: cimg/node:<< parameters.node-version >>
|
||||
- image: circleci/node:16
|
||||
steps:
|
||||
- when:
|
||||
condition:
|
||||
and:
|
||||
- equal:
|
||||
[
|
||||
'<< parameters.node-version >>',
|
||||
'<< pipeline.parameters.legacy-node-version >>',
|
||||
]
|
||||
- not: << pipeline.parameters.check-legacy-node-version >>
|
||||
steps:
|
||||
- run:
|
||||
name: Skip
|
||||
command: |
|
||||
echo Skipping
|
||||
- when:
|
||||
condition:
|
||||
or:
|
||||
- not:
|
||||
equal:
|
||||
[
|
||||
'<< parameters.node-version >>',
|
||||
'<< pipeline.parameters.legacy-node-version >>',
|
||||
]
|
||||
- << pipeline.parameters.check-legacy-node-version >>
|
||||
steps:
|
||||
- checkout
|
||||
- *restore-cache
|
||||
- *install-deps
|
||||
- *build-packages
|
||||
- when:
|
||||
condition:
|
||||
equal:
|
||||
[
|
||||
'<< parameters.node-version >>',
|
||||
'<< pipeline.parameters.maintenance-node-version >>',
|
||||
]
|
||||
steps:
|
||||
- run:
|
||||
name: Test (coverage)
|
||||
command: npm run test:cov
|
||||
- run:
|
||||
name: Collect coverage
|
||||
command: npm run coverage
|
||||
- store_artifacts:
|
||||
path: coverage
|
||||
- when:
|
||||
condition:
|
||||
not:
|
||||
equal:
|
||||
[
|
||||
'<< parameters.node-version >>',
|
||||
'<< pipeline.parameters.maintenance-node-version >>',
|
||||
]
|
||||
steps:
|
||||
- *run-unit-tests
|
||||
- checkout
|
||||
- *restore-cache
|
||||
- *install-deps
|
||||
- *build-packages
|
||||
- run:
|
||||
name: Test (coverage)
|
||||
command: npm run test:cov
|
||||
- run:
|
||||
name: Collect coverage
|
||||
command: npm run coverage
|
||||
- store_artifacts:
|
||||
path: coverage
|
||||
|
||||
lint:
|
||||
working_directory: ~/nest
|
||||
docker:
|
||||
- image: cimg/node:<< pipeline.parameters.maintenance-node-version >>
|
||||
- image: circleci/node:16
|
||||
steps:
|
||||
- checkout
|
||||
- *restore-cache
|
||||
@@ -129,23 +88,26 @@ jobs:
|
||||
- run:
|
||||
name: Lint
|
||||
command: npm run lint
|
||||
- run:
|
||||
name: Lint commit
|
||||
command: ./node_modules/.bin/commitlint-circle -c .commitlintrc.json
|
||||
|
||||
integration_tests:
|
||||
working_directory: ~/nest
|
||||
machine: true
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
- run:
|
||||
name: Prepare nvm
|
||||
command: |
|
||||
echo 'export NVM_DIR="/opt/circleci/.nvm"' >> $BASH_ENV
|
||||
echo ' [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"' >> $BASH_ENV
|
||||
- run:
|
||||
- run:
|
||||
name: Upgrade Node.js
|
||||
command: |
|
||||
nvm install << pipeline.parameters.maintenance-node-version >>
|
||||
nvm install v12
|
||||
node -v
|
||||
nvm alias default << pipeline.parameters.maintenance-node-version >>
|
||||
nvm alias default v12
|
||||
- run:
|
||||
name: Install Docker Compose
|
||||
command: |
|
||||
@@ -164,11 +126,11 @@ jobs:
|
||||
- run:
|
||||
name: Integration tests
|
||||
command: npm run test:integration
|
||||
|
||||
|
||||
codechecks_benchmarks:
|
||||
working_directory: ~/nest
|
||||
docker:
|
||||
- image: cimg/node:<< pipeline.parameters.maintenance-node-version >>
|
||||
- image: circleci/node:16
|
||||
steps:
|
||||
- checkout
|
||||
- *restore-cache
|
||||
@@ -184,9 +146,9 @@ jobs:
|
||||
samples:
|
||||
working_directory: ~/nest
|
||||
docker:
|
||||
- image: cimg/node:<< pipeline.parameters.maintenance-node-version >>
|
||||
- image: circleci/node:16
|
||||
environment:
|
||||
DISABLE_OPENCOLLECTIVE: 'true'
|
||||
- DISABLE_OPENCOLLECTIVE: true
|
||||
steps:
|
||||
- checkout
|
||||
- *restore-cache
|
||||
@@ -196,21 +158,19 @@ jobs:
|
||||
command: npm run build:samples
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
build-and-test:
|
||||
jobs:
|
||||
- build
|
||||
- test:
|
||||
- test_node_16:
|
||||
requires:
|
||||
- build
|
||||
- test_node_14:
|
||||
requires:
|
||||
- build
|
||||
- test_node_12:
|
||||
requires:
|
||||
- build
|
||||
matrix:
|
||||
parameters:
|
||||
node-version:
|
||||
[
|
||||
'<< pipeline.parameters.legacy-node-version >>',
|
||||
'<< pipeline.parameters.maintenance-node-version >>',
|
||||
'<< pipeline.parameters.active-node-version >>',
|
||||
'<< pipeline.parameters.current-node-version >>',
|
||||
]
|
||||
- lint:
|
||||
requires:
|
||||
- build
|
||||
|
||||
@@ -6,8 +6,8 @@ cd "$(dirname "$0")"
|
||||
|
||||
cd /tmp/
|
||||
sudo apt-get install build-essential libssl-dev git -y
|
||||
git clone --depth=1 https://github.com/wg/wrk.git wrk
|
||||
git clone https://github.com/wg/wrk.git wrk
|
||||
cd wrk
|
||||
sudo make
|
||||
# move the executable to somewhere in your PATH, ex:
|
||||
sudo cp wrk /usr/local/bin
|
||||
sudo cp wrk /usr/local/bin
|
||||
@@ -23,7 +23,6 @@ module.exports = {
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||
'@typescript-eslint/no-unused-vars': 'off',
|
||||
'@typescript-eslint/ban-types': 'off',
|
||||
'@typescript-eslint/no-array-constructor': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
12
.github/ISSUE_TEMPLATE/Bug_report.yml
vendored
12
.github/ISSUE_TEMPLATE/Bug_report.yml
vendored
@@ -6,7 +6,7 @@ body:
|
||||
attributes:
|
||||
value: |
|
||||
## :warning: We use GitHub Issues to track bug reports, feature requests and regressions
|
||||
|
||||
|
||||
If you are not sure that your issue is a bug, you could:
|
||||
|
||||
- read the [FAQ's common errors](https://docs.nestjs.com/faq/common-errors) page
|
||||
@@ -38,19 +38,15 @@ body:
|
||||
required: true
|
||||
attributes:
|
||||
label: "Minimum reproduction code"
|
||||
description: "An URL to some Git repository/[StackBlitz](https://stackblitz.com/fork/github/nestjs/typescript-starter)/[CodeSandbox](https://codesandbox.io/s/github/nestjs/typescript-starter/tree/master) project that reproduces your issue. [Wtf is a minimum reproduction?](https://jmcdo29.github.io/wtf-is-a-minimum-reproduction)"
|
||||
placeholder: "https://github.com/..."
|
||||
description: |
|
||||
An URL to some Git repository/[StackBlitz](https://stackblitz.com/fork/github/nestjs/typescript-starter)/[CodeSandbox](https://codesandbox.io/s/github/nestjs/typescript-starter/tree/master) project that reproduces your issue. [What is a minimum reproduction?](https://jmcdo29.github.io/wtf-is-a-minimum-reproduction)
|
||||
|
||||
> [!WARNING]
|
||||
> We may close this Issue if we don't manage to reproduce the potential bug. [Read this](https://antfu.me/posts/why-reproductions-are-required) to understand why.
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: "Steps to reproduce"
|
||||
description: |
|
||||
How the issue manifests?
|
||||
You could leave this blank if you already write this in your reproduction code
|
||||
You could leave this blank if you alread write this in your reproduction code
|
||||
placeholder: |
|
||||
1. `npm ci`
|
||||
2. `npm start:dev`
|
||||
@@ -61,7 +57,7 @@ body:
|
||||
required: true
|
||||
attributes:
|
||||
label: "Expected behavior"
|
||||
description: "A clear and concise description of what you expected to happened (or code)"
|
||||
description: "A clear and concise description of what you expected to happend (or code)"
|
||||
|
||||
- type: markdown
|
||||
attributes:
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/Feature_request.yml
vendored
2
.github/ISSUE_TEMPLATE/Feature_request.yml
vendored
@@ -6,7 +6,7 @@ body:
|
||||
attributes:
|
||||
value: |
|
||||
## :warning: We use GitHub Issues to track bug reports, feature requests and regressions
|
||||
|
||||
|
||||
If you are not sure that your issue is a bug, you could:
|
||||
|
||||
- read the [FAQ's common errors](https://docs.nestjs.com/faq/common-errors) page
|
||||
|
||||
4
.github/ISSUE_TEMPLATE/Regression.yml
vendored
4
.github/ISSUE_TEMPLATE/Regression.yml
vendored
@@ -6,7 +6,7 @@ body:
|
||||
attributes:
|
||||
value: |
|
||||
## :warning: We use GitHub Issues to track bug reports, feature requests and regressions
|
||||
|
||||
|
||||
If you are not sure that your issue is a bug, you could:
|
||||
|
||||
- read the [FAQ's common errors](https://docs.nestjs.com/faq/common-errors) page
|
||||
@@ -74,7 +74,7 @@ body:
|
||||
required: true
|
||||
attributes:
|
||||
label: "Expected behavior"
|
||||
description: "A clear and concise description of what you expected to happened (or code)"
|
||||
description: "A clear and concise description of what you expected to happend (or code)"
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
|
||||
8
.github/workflows/codeql-analysis.yml
vendored
8
.github/workflows/codeql-analysis.yml
vendored
@@ -21,7 +21,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
# We must fetch at least the immediate parents so that if this is
|
||||
# a pull request then we can checkout the head.
|
||||
@@ -34,7 +34,7 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
queries: +security-extended
|
||||
# Override language selection by uncommenting this and choosing your languages
|
||||
@@ -44,7 +44,7 @@ jobs:
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v3
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
@@ -58,4 +58,4 @@ jobs:
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3
|
||||
uses: github/codeql-action/analyze@v2
|
||||
|
||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -1,5 +1,3 @@
|
||||
packages/*/package-lock.json
|
||||
|
||||
# dependencies
|
||||
node_modules/
|
||||
|
||||
@@ -8,9 +6,6 @@ node_modules/
|
||||
/.awcache
|
||||
/.vscode
|
||||
/.devcontainer
|
||||
/.classpath
|
||||
/.project
|
||||
/.settings
|
||||
*.code-workspace
|
||||
|
||||
# Vim
|
||||
@@ -47,6 +42,3 @@ yarn-error.log
|
||||
/packages/graphql
|
||||
/benchmarks/memory
|
||||
build/config\.gypi
|
||||
|
||||
.npmrc
|
||||
pnpm-lock.yaml
|
||||
|
||||
@@ -1 +1,4 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
npx --no-install commitlint --edit $1
|
||||
|
||||
@@ -1 +1,4 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
npx lint-staged
|
||||
|
||||
@@ -164,7 +164,7 @@ You will need [Node.js](https://nodejs.org) version >= 10.13.0 (except for v13).
|
||||
1. After cloning the repo, run:
|
||||
|
||||
```bash
|
||||
$ npm ci --legacy-peer-deps # (or yarn install)
|
||||
$ npm ci # (or yarn install)
|
||||
```
|
||||
|
||||
2. In order to prepare your environment run `prepare.sh` shell script:
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2017-2024 Kamil Mysliwiec <https://kamilmysliwiec.com>
|
||||
Copyright (c) 2017-2023 Kamil Mysliwiec <https://kamilmysliwiec.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
|
||||
167
Readme.md
167
Readme.md
@@ -1,11 +1,11 @@
|
||||
<p align="center">
|
||||
<a href="https://nestjs.com/" target="blank"><img src="https://nestjs.com/img/logo-small.svg" width="120" alt="Nest Logo" /></a>
|
||||
<a href="http://nestjs.com/" target="blank"><img src="https://nestjs.com/img/logo-small.svg" width="120" alt="Nest Logo" /></a>
|
||||
</p>
|
||||
|
||||
[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456
|
||||
[circleci-url]: https://circleci.com/gh/nestjs/nest
|
||||
|
||||
<p align="center">A progressive <a href="https://nodejs.org" target="_blank">Node.js</a> framework for building efficient and scalable server-side applications.</p>
|
||||
<p align="center">A progressive <a href="http://nodejs.org" target="_blank">Node.js</a> framework for building efficient and scalable server-side applications.</p>
|
||||
<p align="center">
|
||||
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/v/@nestjs/core.svg" alt="NPM Version" /></a>
|
||||
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/l/@nestjs/core.svg" alt="Package License" /></a>
|
||||
@@ -23,21 +23,21 @@
|
||||
|
||||
## Description
|
||||
|
||||
Nest is a framework for building efficient, scalable <a href="https://nodejs.org" target="_blank">Node.js</a> server-side applications. It uses modern JavaScript, is built with <a href="https://www.typescriptlang.org" target="_blank">TypeScript</a> (preserves compatibility with pure JavaScript) and combines elements of OOP (Object Oriented Programming), FP (Functional Programming), and FRP (Functional Reactive Programming).
|
||||
Nest is a framework for building efficient, scalable <a href="http://nodejs.org" target="_blank">Node.js</a> server-side applications. It uses modern JavaScript, is built with <a href="http://www.typescriptlang.org" target="_blank">TypeScript</a> (preserves compatibility with pure JavaScript) and combines elements of OOP (Object Oriented Programming), FP (Functional Programming), and FRP (Functional Reactive Programming).
|
||||
|
||||
<p>Under the hood, Nest makes use of <a href="https://expressjs.com/" target="_blank">Express</a>, but also provides compatibility with a wide range of other libraries, like <a href="https://github.com/fastify/fastify" target="_blank">Fastify</a>, allowing for easy use of the myriad of third-party plugins which are available.</p>
|
||||
<p>Under the hood, Nest makes use of <a href="https://expressjs.com/" target="_blank">Express</a>, but also, provides compatibility with a wide range of other libraries, like e.g. <a href="https://github.com/fastify/fastify" target="_blank">Fastify</a>, allowing for easy use of the myriad third-party plugins which are available.</p>
|
||||
|
||||
## Philosophy
|
||||
|
||||
<p>In recent years, thanks to Node.js, JavaScript has become the “lingua franca” of the web for both front and backend applications, giving rise to awesome projects like <a href="https://angular.io/" target="_blank">Angular</a>, <a href="https://github.com/facebook/react" target="_blank">React</a>, and <a href="https://github.com/vuejs/vue" target="_blank">Vue</a>, which improve developer productivity and enable the construction of fast, testable, and extensible frontend applications. However, on the server-side, while there are a lot of superb libraries, helpers, and tools for Node, none of them effectively solve the main problem - the architecture.</p>
|
||||
<p>Nest aims to provide an application architecture out of the box which allows for effortless creation of highly testable, scalable, and loosely coupled and easily maintainable applications. The architecture is heavily inspired by Angular.</p>
|
||||
<p>In recent years, thanks to Node.js, JavaScript has become the “lingua franca” of the web for both front and backend applications, giving rise to awesome projects like <a href="https://angular.io/" target="_blank">Angular</a>, <a href="https://github.com/facebook/react" target="_blank">React</a> and <a href="https://github.com/vuejs/vue" target="_blank">Vue</a> which improve developer productivity and enable the construction of fast, testable, extensible frontend applications. However, on the server-side, while there are a lot of superb libraries, helpers and tools for Node, none of them effectively solve the main problem - the architecture.</p>
|
||||
<p>Nest aims to provide an application architecture out of the box which allows for effortless creation of highly testable, scalable, loosely coupled and easily maintainable applications. The architecture is heavily inspired by Angular.</p>
|
||||
|
||||
## Getting started
|
||||
|
||||
- To check out the [guide](https://docs.nestjs.com), visit [docs.nestjs.com](https://docs.nestjs.com). :books:
|
||||
- 要查看中文 [指南](readme_zh.md), 请访问 [docs.nestjs.cn](https://docs.nestjs.cn). :books:
|
||||
- [가이드](readme_kr.md) 문서는 [docs.nestjs.com](https://docs.nestjs.com)에서 확인하실 수 있습니다. :books:
|
||||
- [ガイド](readme_jp.md)は [docs.nestjs.com](https://docs.nestjs.com)でご確認ください。 :books:
|
||||
* To check out the [guide](https://docs.nestjs.com), visit [docs.nestjs.com](https://docs.nestjs.com). :books:
|
||||
* 要查看中文 [指南](readme_zh.md), 请访问 [docs.nestjs.cn](https://docs.nestjs.cn). :books:
|
||||
* [가이드](readme_kr.md) 문서는 [docs.nestjs.com](https://docs.nestjs.com)에서 확인하실 수 있습니다. :books:
|
||||
* [ガイド](readme_jp.md)は [docs.nestjs.com](https://docs.nestjs.com)でご確認ください。 :books:
|
||||
|
||||
## Questions
|
||||
|
||||
@@ -56,85 +56,88 @@ With official support, you can get expert help straight from Nest core team. We
|
||||
Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support from the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).
|
||||
|
||||
#### Principal Sponsors
|
||||
|
||||
<table style="text-align:center;">
|
||||
<tr>
|
||||
<td><a href="https://trilon.io" target="_blank"><img src="https://nestjs.com/img/trilon.svg" width="200" valign="middle" /></a></td>
|
||||
<td><a href="https://microsoft.com/" target="_blank"><img src="https://nestjs.com/img/logos/microsoft-logo.png" width="180" valign="middle" /></a></td>
|
||||
<td><a href="https://mojam.co" target="_blank"><img src="https://nestjs.com/img/logos/mojam-logo.png" width="80" valign="middle" /></a></td>
|
||||
<td><a href="https://marblism.com?utm_source=nest" target="_blank"><img src="https://nestjs.com/img/logos/marblism-logo.png" width="180" valign="middle" /></a></td>
|
||||
<td><a href="https://valor-software.com/" target="_blank"><img src="https://docs.nestjs.com/assets/sponsors/valor-software.png" width="170" valign="middle" /></a></td>
|
||||
<td><a href="https://amplication.com/" target="_blank"><img src="https://nestjs.com/img/logos/amplication-logo.svg" width="190" valign="middle" /></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<table style="text-align:center;"><tr>
|
||||
<td><a href="https://trilon.io" target="_blank"><img src="https://nestjs.com/img/trilon.svg" width="200" valign="middle" /></a></td>
|
||||
<td><a href="https://www.redhat.com" target="_blank"><img src="https://nestjs.com/img/red-hat-logo.svg" width="200" valign="middle" /></a></td>
|
||||
<td>
|
||||
<a href="https://github.com/Sanofi-IADC" target="_blank"><img src="https://docs.nestjs.com/assets/sponsors/sanofi.png" width="180" valign="middle" /></a></td>
|
||||
<td>
|
||||
<a href="https://nx.dev" target="_blank"><img src="https://nestjs.com/img/nx-logo.png" height="45" valign="middle" /></a></td>
|
||||
<td>
|
||||
<a href="https://valor-software.com/" target="_blank"><img src="https://docs.nestjs.com/assets/sponsors/valor-software.png" width="170" valign="middle" /></a></td><td>
|
||||
<a href="https://amplication.com/" target="_blank"><img src="https://nestjs.com/img/amplication-logo.svg" width="190" valign="middle" /></a></td>
|
||||
</tr></table>
|
||||
|
||||
#### Gold Sponsors
|
||||
|
||||
<table style="text-align:center;">
|
||||
<tr>
|
||||
<td><a href="https://www.redhat.com" target="_blank"><img src="https://nestjs.com/img/logos/red-hat-logo.svg" width="200" valign="middle" /></a></td>
|
||||
<td><a href="https://github.com/Sanofi-IADC" target="_blank"><img src="https://docs.nestjs.com/assets/sponsors/sanofi.png" width="180" valign="middle" /></a></td>
|
||||
<td><a href="https://nx.dev" target="_blank"><img src="https://nestjs.com/img/logos/nx-logo.png" height="45" valign="middle" /></a></td>
|
||||
<td><a href="https://intrinsic.ventures/" target="_blank"><img src="https://nestjs.com/img/logos/intrinisic-logo.png" width="210" valign="middle" /></a></td>
|
||||
<td><a href="https://jetbrains.com/" target="_blank"><img src="https://nestjs.com/img/logos/jetbrains-logo.svg" width="90" valign="middle" /></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://snyk.co/nestjs" target="_blank"><img src="https://nestjs.com/img/logos/snyk-logo-black.png" width="185" valign="middle" /></a></td>
|
||||
<td><a href="https://fuseautotech.com/" target="_blank"><img src="https://nestjs.com/img/logos/fuse-logo.svg" width="105" valign="middle" /></a></td>
|
||||
<td><a href="https://ridicorp.com/career/" target="_blank"><img src="https://nestjs.com/img/logos/ridi-logo.svg" width="105" valign="middle" /></a></td>
|
||||
<td><a href="https://www.movavi.com/imovie-for-windows.html" target="_blank"><img src="https://nestjs.com/img/logos/movavi-logo.svg" width="105" valign="middle" /></a></td>
|
||||
<td><a href="https://skunk.team" target="_blank"><img src="https://nestjs.com/img/logos/skunk-logo.png" height="60" valign="middle" /></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<table style="text-align:center;"><tr><td>
|
||||
<a href="https://weld.app/" target="_blank"><img src="https://nestjs.com/img/weld-logo.svg" width="140" valign="middle" /></a></td>
|
||||
<td>
|
||||
<a href="https://intrinsic.ventures/" target="_blank"><img src="https://nestjs.com/img/intrinisic-logo.png" width="210" valign="middle" /></a></td>
|
||||
<td>
|
||||
<a href="https://jetbrains.com/" target="_blank"><img src="https://nestjs.com/img/jetbrains-logo.svg" width="110" valign="middle" /></a></td><td>
|
||||
<a href="https://snyk.co/nestjs" target="_blank"><img src="https://nestjs.com/img/snyk-logo-black.png" width="185" valign="middle" /></a></td><td>
|
||||
<a href="https://fuseautotech.com/" target="_blank"><img src="https://nestjs.com/img/fuse-logo.svg" width="105" valign="middle" /></a></td>
|
||||
<td>
|
||||
<a href="https://ridicorp.com/career/" target="_blank"><img src="https://nestjs.com/img/ridi-logo.svg" width="105" valign="middle" /></a></td><td>
|
||||
<a href="https://www.movavi.com/imovie-for-windows.html" target="_blank"><img src="https://nestjs.com/img/movavi-logo.svg" width="105" valign="middle" /></a></td></</tr></table>
|
||||
|
||||
#### Silver Sponsors
|
||||
|
||||
<table style="text-align:center;">
|
||||
<tr>
|
||||
<td><a href="https://www.mercedes-benz.com/" target="_blank"><img src="https://nestjs.com/img/logos/mercedes-logo.png" width="100" valign="middle" /></a></td>
|
||||
<td><a href="https://www.dinii.jp/" target="_blank"><img src="https://nestjs.com/img/logos/dinii-logo.png" width="65" valign="middle" /></a></td>
|
||||
<td><a href="https://bloodycase.com/?promocode=NEST" target="_blank"><img src="https://nestjs.com/img/logos/bloodycase-logo.png" width="65" valign="middle" /></a></td>
|
||||
<td><a href="https://handsontable.com/docs/react-data-grid/?utm_source=NestJS_GH&utm_medium=sponsorship&utm_campaign=library_sponsorship_2024" target="_blank"><img src="https://nestjs.com/img/logos/handsontable-dark-logo.svg#2" width="150" valign="middle" /></a></td>
|
||||
<td align="center" valign="middle"><a href="https://www.itflashcards.com/" target="_blank"><img src="https://nestjs.com/img/logos/it_flashcards-logo.png" width="170" valign="middle" /></a></td>
|
||||
<td align="center" valign="middle"><a href="https://arcjet.com/?ref=nestjs" target="_blank"><img src="https://nestjs.com/img/logos/arcjet-logo.svg" width="170" valign="middle" /></a></td>
|
||||
</tr>
|
||||
<table style="text-align:center;"><tr><td>
|
||||
<a href="https://neoteric.eu/" target="_blank"><img src="https://nestjs.com/img/neoteric-cut.png" width="120" valign="middle" /></a> </td><td>
|
||||
<a href="http://gojob.com" target="_blank"><img src="http://nestjs.com/img/gojob-logo.png" valign="middle" width="100" /></a> </td><td>
|
||||
<a href="https://www.myleodsc.com/" target="_blank"><img src="https://nestjs.com/img/myleo-logo.png" width="180" valign="middle" /></td><td>
|
||||
<a href="https://careers.meetdandy.com/?gh_src=063ba61e3us" target="_blank"><img src="https://nestjs.com/img/dandy-roles-logo.svg" width="150" valign="middle" /></td><td>
|
||||
<a href="https://www.castlecraft.in" target="_blank"><img src="https://nestjs.com/img/castlecraft-logo.png" width="150" valign="middle" /></td>
|
||||
<td><a href="https://www.tinystacks.com" target="_blank"><img src="https://nestjs.com/img/tinystacks-logo.png#1" width="140" valign="middle" /></td>
|
||||
<td><a href="https://n.inc" target="_blank"><img src="https://nestjs.com/img/n-inc-logo.svg" width="120" valign="middle" /></td></tr><tr>
|
||||
<td><a href="https://bilberrry.com/" target="_blank"><img src="https://nestjs.com/img/bilberrry-logo.svg" width="180" valign="middle" /></td>
|
||||
<td><a href="https://ipinfo.ai/" target="_blank"><img src="https://nestjs.com/img/ipinfo-logo.png" width="130" valign="middle" /></td>
|
||||
<td><a href="https://chax.at" target="_blank"><img src="https://nestjs.com/img/chaxat-logo.png" width="100" valign="middle" /></td></tr>
|
||||
</table>
|
||||
|
||||
#### Sponsors
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td align="center" valign="middle"><a href="https://www.swingdev.io" target="_blank"><img src="https://nestjs.com/img/logos/swingdev-logo.svg#1" width="110" valign="middle" /></a></td>
|
||||
<td align="center" valign="middle"><a href="https://www.novologic.com/" target="_blank"><img src="https://nestjs.com/img/logos/novologic.png" width="110" valign="middle" /></a></td>
|
||||
<td align="center" valign="middle"><a href="https://mantro.net/" target="_blank"><img src="https://nestjs.com/img/logos/mantro-logo.svg" width="95" valign="middle" /></a></td>
|
||||
<td align="center" valign="middle"><a href="https://triplebyte.com/" target="_blank"><img src="https://nestjs.com/img/logos/triplebyte.png" width="107" valign="middle" /></a></td>
|
||||
<td align="center" valign="middle"><a href="https://nearpod.com/" target="_blank"><img src="https://nestjs.com/img/logos/nearpod-logo.svg" width="100" valign="middle" /></a></td>
|
||||
<td align="center" valign="middle"><a href="https://genuinebee.com/" target="_blank"><img src="https://nestjs.com/img/logos/genuinebee.svg" width="97" valign="middle" /></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle"><a href="https://vpn-review.com/vpn-for-torrenting" target="_blank"><img src="https://nestjs.com/img/logos/vpn-review-logo.png" width="85" valign="middle" /></a></td>
|
||||
<td align="center" valign="middle"><a href="https://lambda-it.ch/" target="_blank"><img src="https://nestjs.com/img/logos/lambda-it-logo.svg" width="115" valign="middle" /></a></td>
|
||||
<td align="center" valign="middle"><a href="https://rocketech.it/cases/?utm_source=google&utm_medium=badge&utm_campaign=nestjs" target="_blank"><img src="https://nestjs.com/img/logos/rocketech-logo.svg" width="110" valign="middle" /></a></td>
|
||||
<td align="center" valign="middle"><a href="https://www.anonymistic.com/" target="_blank"><img src="https://nestjs.com/img/logos/anonymistic-logo.png" width="125" valign="middle" /></a></td>
|
||||
<td align="center" valign="middle"><a href="https://www.naologic.com/" target="_blank"><img src="https://nestjs.com/img/logos/naologic-logo.svg" width="125" valign="middle" /></a></td>
|
||||
<td align="center" valign="middle"><a href="https://triplecore.io" target="_blank"><img src="https://nestjs.com/img/logos/triplecore-logo.svg" width="50" valign="middle" /></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle"><a href="https://thecasinowizard.com/bonuses/no-deposit-bonuses/" target="_blank"><img src="https://nestjs.com/img/logos/casinowizard-logo.png" width="120" valign="middle" /></a></td>
|
||||
<td align="center" valign="middle"><a href="https://polygon-software.ch/" target="_blank"><img src="https://nestjs.com/img/logos/polygon-logo.svg" width="120" valign="middle" /></a></td>
|
||||
<td align="center" valign="middle"><a href="https://boringowl.io/" target="_blank"><img src="https://nestjs.com/img/logos/boringowl-logo.svg" width="120" valign="middle" /></a></td>
|
||||
<td align="center" valign="middle"><a href="https://nordbot.app/" target="_blank"><img src="https://nestjs.com/img/logos/nordbot-logo.png" width="120" valign="middle" /></a></td>
|
||||
<td align="center" valign="middle"><a href="https://doppio.sh/" target="_blank"><img src="https://nestjs.com/img/logos/dopiosh-logo.png" width="50" valign="middle" /></a></td>
|
||||
<td align="center" valign="middle"><a href="https://www.hingehealth.com/" target="_blank"><img src="https://nestjs.com/img/logos/hinge-health-logo.svg" width="100" valign="middle" /></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle"><a href="https://julienferand.dev/" target="_blank"><img src="https://nestjs.com/img/logos/julienferand-logo.jpeg" width="55" valign="middle" /></a></td>
|
||||
<td align="center" valign="middle"><a href="https://www.tripoffice.com/" target="_blank"><img src="https://nestjs.com/img/logos/tripoffice-logo.png" width="140" valign="middle" /></a></td>
|
||||
<td align="center" valign="middle"><a href="https://solcellsforetag.se/" target="_blank"><img src="https://nestjs.com/img/logos/solcellsforetag-logo.svg" width="140" valign="middle" /></a></td>
|
||||
<td align="center" valign="middle"><a href="https://www.route4me.com/" target="_blank"><img src="https://nestjs.com/img/logos/route4me-logo.svg" width="100" valign="middle" /></a></td>
|
||||
<td align="center" valign="middle"><a href="https://www.slotsup.com/" target="_blank"><img src="https://nestjs.com/img/logos/slotsup-logo.png" width="60" valign="middle" /></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<table><tr><td align="center" valign="middle">
|
||||
<a href="https://www.swingdev.io" target="_blank"><img src="https://nestjs.com/img/swingdev-logo.svg#1" width="110" valign="middle" /> </a></td><td align="center" valign="middle">
|
||||
<a href="https://www.novologic.com/" target="_blank"><img src="https://nestjs.com/img/novologic.png" width="110" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://ever.co/" target="_blank"><img src="https://nestjs.com/img/ever-logo.png" width="72" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://blokt.com" target="_blank"><img src="https://nestjs.com/img/blokt-logo.png" width="120" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="http://architectnow.net/" target="_blank"><img src="https://nestjs.com/img/architectnow.png" width="125" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://quander.io/" target="_blank"><img src="https://nestjs.com/img/quander.png" width="100" valign="middle" /></a> </td></tr><tr><td align="center" valign="middle">
|
||||
<a href="https://mantro.net/" target="_blank"><img src="https://nestjs.com/img/mantro-logo.svg" width="95" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://triplebyte.com/" target="_blank"><img src="https://nestjs.com/img/triplebyte.png" width="107" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://reposit.co.uk/" target="_blank"><img src="https://nestjs.com/img/reposit-logo.png" width="71" valign="middle" /></a></td><td align="center" valign="middle">
|
||||
<a href="https://nearpod.com/" target="_blank"><img src="https://nestjs.com/img/nearpod-logo.svg" width="100" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://clay.global/" target="_blank"><img src="https://nestjs.com/img/clay-logo.svg" width="75" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://firesticktricks.com" target="_blank"><img src="https://nestjs.com/img/firesticktricks-logo.png" width="120" valign="middle" /></a></td></tr><tr><td align="center" valign="middle">
|
||||
<a href="https://www.codeguesser.co.uk" target="_blank"><img src="https://nestjs.com/img/codeguesser-logo.svg" width="120" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://f-a.nz/" target="_blank"><img src="https://nestjs.com/img/franz.svg" width="80" valign="middle" /></a> </td><td align="center" valign="middle">
|
||||
<a href="https://sparkfabrik.com/" target="_blank"><img src="https://nestjs.com/img/sparkfabrik-logo.png" width="120" valign="middle" /></a></td><td align="center" valign="middle"><a href="https://www.thebigphonestore.co.uk/" target="_blank"><img src="https://nestjs.com/img/the-big-phone-store-logo.png" width="65" valign="middle" /></a></td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://genuinebee.com/" target="_blank"><img src="https://nestjs.com/img/genuinebee.svg" width="97" valign="middle" /></a> </td>
|
||||
<td align="center" valign="middle"><a href="https://sanyodigital.com/" target="_blank"><img src="https://nestjs.com/img/sanyo-digital.png" width="130" valign="middle" /></a></td></tr><tr><td align="center" valign="middle"><a href="https://vpn-review.com/vpn-for-torrenting" target="_blank"><img src="https://nestjs.com/img/vpn-review-logo.png" width="85" valign="middle" /></a></td><td align="center" valign="middle"><a href="https://lambda-it.ch/" target="_blank"><img src="https://nestjs.com/img/lambda-it-logo.svg" width="115" valign="middle" /></a></td><td align="center" valign="middle"><a href="https://pickwriters.com/top-10-translation-services" target="_blank"><img src="https://nestjs.com/img/pickwriters-logo.png" width="40" valign="middle" /></a></td><td align="center" valign="middle"><a href="https://thewordpoint.com/services/localization" target="_blank"><img src="https://nestjs.com/img/thewordpoint-logo.png" width="40" valign="middle" /></a></td>
|
||||
<td align="center" valign="middle"><a href="https://meercode.io/" target="_blank"><img src="https://nestjs.com/img/meercode-logo.png" width="60" valign="middle" /></a></td>
|
||||
<td align="center" valign="middle"><a href="https://www.najlepszeplatformyforex.pl/blog/broker-xtb/" target="_blank"><img src="https://nestjs.com/img/npf-logo.jpg" width="200" valign="middle" /></a></td></tr><tr>
|
||||
<td align="center" valign="middle"><a href="https://thestandarddaily.com/" target="_blank"><img src="https://nestjs.com/img/the-standard-daily-logo.png" width="180" valign="middle" /></a></td>
|
||||
<td align="center" valign="middle"><a href="https://houseofangular.io/" target="_blank"><img src="https://nestjs.com/img/house-of-angular.png" width="100" valign="middle" /></a></td>
|
||||
<td align="center" valign="middle"><a href="https://rocketech.it/cases/?utm_source=google&utm_medium=badge&utm_campaign=nestjs" target="_blank"><img src="https://nestjs.com/img/rocketech-logo.svg" width="110" valign="middle" /></a></td>
|
||||
<td align="center" valign="middle"><a href="https://www.bystored.com/" target="_blank"><img src="https://nestjs.com/img/stored-logo.svg" width="110" valign="middle" /></a></td>
|
||||
<td align="center" valign="middle"><a href="https://studyclerk.com/pay-for-research-paper" target="_blank"><img src="https://nestjs.com/img/studyclerk-logo.png" width="125" valign="middle" /></a></td><td align="center" valign="middle"><a href="https://xyndata.com" target="_blank"><img src="https://nestjs.com/img/xyndata-logo.png" width="125" valign="middle" /></a></td></tr><tr>
|
||||
<td align="center" valign="middle"><a href="https://www.anonymistic.com/" target="_blank"><img src="https://nestjs.com/img/anonymistic-logo.png" width="125" valign="middle" /></a></td>
|
||||
<td align="center" valign="middle"><a href="https://www.naologic.com/" target="_blank"><img src="https://nestjs.com/img/naologic-logo.svg" width="125" valign="middle" /></a></td>
|
||||
<td align="center" valign="middle"><a href="https://messaged.com/" target="_blank"><img src="https://nestjs.com/img/messaged-logo.png" width="50" valign="middle" /></a></td>
|
||||
<td align="center" valign="middle"><a href="https://triplecore.io" target="_blank"><img src="https://nestjs.com/img/triplecore-logo.svg" width="50" valign="middle" /></a></td>
|
||||
<td align="center" valign="middle"><a href="https://klqc.de" target="_blank"><img src="https://nestjs.com/img/klcqcl-logo.png" width="120" valign="middle" /></a></td>
|
||||
<td align="center" valign="middle"><a href="https://thecasinowizard.com/bonuses/no-deposit-bonuses/" target="_blank"><img src="https://nestjs.com/img/casinowizard-logo.png" width="120" valign="middle" /></a></td></tr><tr>
|
||||
<td align="center" valign="middle"><a href="https://polygon-software.ch/" target="_blank"><img src="https://nestjs.com/img/polygon-logo.svg" width="120" valign="middle" /></a></td>
|
||||
<td align="center" valign="middle"><a href="https://mobilereality.pl/" target="_blank"><img src="https://nestjs.com/img/mobile-reality-logo.png" width="45" valign="middle" /></a></td>
|
||||
<td align="center" valign="middle"><a href="https://boringowl.io/" target="_blank"><img src="https://nestjs.com/img/boringowl-logo.svg" width="120" valign="middle" /></a></td>
|
||||
<td align="center" valign="middle"><a href="https://www.mobilefactory.jp/" target="_blank"><img src="https://nestjs.com/img/mobilefactory-logo.png" width="100" valign="middle" /></a></td>
|
||||
<td align="center" valign="middle"><a href="https://nordbot.app/" target="_blank"><img src="https://nestjs.com/img/nordbot-logo.png" width="120" valign="middle" /></a></td>
|
||||
<td align="center" valign="middle"><a href="https://doppio.sh/" target="_blank"><img src="https://nestjs.com/img/dopiosh-logo.png" width="50" valign="middle" /></a></td>
|
||||
</tr></table>
|
||||
|
||||
## Backers
|
||||
|
||||
@@ -142,9 +145,9 @@ Nest is an MIT-licensed open source project. It can grow thanks to the sponsors
|
||||
|
||||
## Stay in touch
|
||||
|
||||
- Author - [Kamil Myśliwiec](https://x.com/kammysliwiec)
|
||||
- Website - [https://nestjs.com](https://nestjs.com/)
|
||||
- X - [@nestframework](https://x.com/nestframework)
|
||||
* Author - [Kamil Myśliwiec](https://twitter.com/kammysliwiec)
|
||||
* Website - [https://nestjs.com](https://nestjs.com/)
|
||||
* Twitter - [@nestframework](https://twitter.com/nestframework)
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"noLib": false,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"target": "ES2021",
|
||||
"target": "es6",
|
||||
"sourceMap": true,
|
||||
"allowJs": true,
|
||||
"outDir": "./dist",
|
||||
|
||||
39
integration/cache/e2e/async-register-extra-providers.ts
vendored
Normal file
39
integration/cache/e2e/async-register-extra-providers.ts
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
import { CACHE_MANAGER, INestApplication } from '@nestjs/common';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import * as request from 'supertest';
|
||||
import { AsyncRegisterExtraModule } from '../src/async-register-extra-providers/async-register-extra.module';
|
||||
import { Cache } from 'cache-manager';
|
||||
import { assert } from 'chai';
|
||||
|
||||
describe('Async Register Extra Providers', () => {
|
||||
let server;
|
||||
let app: INestApplication;
|
||||
let cacheManager: Cache;
|
||||
|
||||
before(async () => {
|
||||
const module = await Test.createTestingModule({
|
||||
imports: [AsyncRegisterExtraModule],
|
||||
}).compile();
|
||||
|
||||
cacheManager = module.get<Cache>(CACHE_MANAGER);
|
||||
app = module.createNestApplication();
|
||||
server = app.getHttpServer();
|
||||
await app.init();
|
||||
});
|
||||
|
||||
it('should be defined', async () => {
|
||||
assert.isDefined(cacheManager);
|
||||
});
|
||||
|
||||
it(`should return empty`, async () => {
|
||||
return request(server).get('/').expect(200, 'Not found');
|
||||
});
|
||||
|
||||
it(`should return data`, async () => {
|
||||
return request(server).get('/').expect(200, 'value');
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await app.close();
|
||||
});
|
||||
});
|
||||
39
integration/cache/e2e/async-register.spec.ts
vendored
Normal file
39
integration/cache/e2e/async-register.spec.ts
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
import { CACHE_MANAGER, INestApplication } from '@nestjs/common';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import * as request from 'supertest';
|
||||
import { AsyncRegisterModule } from '../src/async-register/async-register.module';
|
||||
import { Cache } from 'cache-manager';
|
||||
import { assert } from 'chai';
|
||||
|
||||
describe('Async Register', () => {
|
||||
let server;
|
||||
let app: INestApplication;
|
||||
let cacheManager: Cache;
|
||||
|
||||
before(async () => {
|
||||
const module = await Test.createTestingModule({
|
||||
imports: [AsyncRegisterModule],
|
||||
}).compile();
|
||||
|
||||
cacheManager = module.get<Cache>(CACHE_MANAGER);
|
||||
app = module.createNestApplication();
|
||||
server = app.getHttpServer();
|
||||
await app.init();
|
||||
});
|
||||
|
||||
it('should be defined', async () => {
|
||||
assert.isDefined(cacheManager);
|
||||
});
|
||||
|
||||
it(`should return empty`, async () => {
|
||||
return request(server).get('/').expect(200, 'Not found');
|
||||
});
|
||||
|
||||
it(`should return data`, async () => {
|
||||
return request(server).get('/').expect(200, 'value');
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await app.close();
|
||||
});
|
||||
});
|
||||
31
integration/cache/e2e/multi-store.spec.ts
vendored
Normal file
31
integration/cache/e2e/multi-store.spec.ts
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import * as request from 'supertest';
|
||||
import { MultiStoreModule } from '../src/multi-store/multi-store.module';
|
||||
|
||||
describe('Caching Multi Store', () => {
|
||||
let server;
|
||||
let app: INestApplication;
|
||||
|
||||
before(async () => {
|
||||
const module = await Test.createTestingModule({
|
||||
imports: [MultiStoreModule],
|
||||
}).compile();
|
||||
|
||||
app = module.createNestApplication();
|
||||
server = app.getHttpServer();
|
||||
await app.init();
|
||||
});
|
||||
|
||||
it(`should return empty`, async () => {
|
||||
return request(server).get('/').expect(200, '');
|
||||
});
|
||||
|
||||
it(`should return data`, async () => {
|
||||
return request(server).get('/').expect(200, 'multi-store-value');
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await app.close();
|
||||
});
|
||||
});
|
||||
16
integration/cache/src/async-register-extra-providers/async-register-extra.controller.ts
vendored
Normal file
16
integration/cache/src/async-register-extra-providers/async-register-extra.controller.ts
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
import { Controller, Get, Inject, CACHE_MANAGER } from '@nestjs/common';
|
||||
import { Cache } from 'cache-manager';
|
||||
|
||||
@Controller()
|
||||
export class AsyncRegisterExtraController {
|
||||
constructor(@Inject(CACHE_MANAGER) private cacheManager: Cache) {}
|
||||
|
||||
@Get()
|
||||
async getFromStore(): Promise<string> {
|
||||
const value: string | undefined = await this.cacheManager.get('key');
|
||||
if (!value) {
|
||||
await this.cacheManager.set('key', 'value');
|
||||
}
|
||||
return value ?? 'Not found';
|
||||
}
|
||||
}
|
||||
16
integration/cache/src/async-register-extra-providers/async-register-extra.module.ts
vendored
Normal file
16
integration/cache/src/async-register-extra-providers/async-register-extra.module.ts
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
import { CacheModule, Module } from '@nestjs/common';
|
||||
import { AsyncRegisterExtraController } from './async-register-extra.controller';
|
||||
import { CacheConfig } from './config/cache.config';
|
||||
import { ConfigModule } from './config/config.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
CacheModule.registerAsync({
|
||||
extraProviders: [ConfigModule],
|
||||
isGlobal: true,
|
||||
useClass: CacheConfig,
|
||||
}),
|
||||
],
|
||||
controllers: [AsyncRegisterExtraController],
|
||||
})
|
||||
export class AsyncRegisterExtraModule {}
|
||||
17
integration/cache/src/async-register-extra-providers/config/cache.config.ts
vendored
Normal file
17
integration/cache/src/async-register-extra-providers/config/cache.config.ts
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
import {
|
||||
CacheModuleOptions,
|
||||
CacheOptionsFactory,
|
||||
Injectable,
|
||||
} from '@nestjs/common';
|
||||
import { ConfigService } from './config.service';
|
||||
|
||||
@Injectable()
|
||||
export class CacheConfig implements CacheOptionsFactory {
|
||||
constructor(private readonly configService: ConfigService) {}
|
||||
|
||||
createCacheOptions(): CacheModuleOptions {
|
||||
const ttl = this.configService.getTtl();
|
||||
|
||||
return { ttl };
|
||||
}
|
||||
}
|
||||
8
integration/cache/src/async-register-extra-providers/config/config.module.ts
vendored
Normal file
8
integration/cache/src/async-register-extra-providers/config/config.module.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ConfigService } from './config.service';
|
||||
|
||||
@Module({
|
||||
providers: [ConfigService],
|
||||
exports: [ConfigService],
|
||||
})
|
||||
export class ConfigModule {}
|
||||
8
integration/cache/src/async-register-extra-providers/config/config.service.ts
vendored
Normal file
8
integration/cache/src/async-register-extra-providers/config/config.service.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class ConfigService {
|
||||
public getTtl(): number {
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
"noLib": false,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"target": "ES2021",
|
||||
"target": "es6",
|
||||
"sourceMap": true,
|
||||
"allowJs": true,
|
||||
"outDir": "./dist",
|
||||
@@ -37,4 +37,4 @@
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
]
|
||||
}
|
||||
}
|
||||
16
integration/cache/src/async-register/async-register.controller.ts
vendored
Normal file
16
integration/cache/src/async-register/async-register.controller.ts
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
import { Controller, Get, Inject, CACHE_MANAGER } from '@nestjs/common';
|
||||
import { Cache } from 'cache-manager';
|
||||
|
||||
@Controller()
|
||||
export class AsyncRegisterController {
|
||||
constructor(@Inject(CACHE_MANAGER) private cacheManager: Cache) {}
|
||||
|
||||
@Get()
|
||||
async getFromStore(): Promise<string> {
|
||||
const value: string | undefined = await this.cacheManager.get('key');
|
||||
if (!value) {
|
||||
await this.cacheManager.set('key', 'value');
|
||||
}
|
||||
return value ?? 'Not found';
|
||||
}
|
||||
}
|
||||
14
integration/cache/src/async-register/async-register.module.ts
vendored
Normal file
14
integration/cache/src/async-register/async-register.module.ts
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
import { CacheModule, Module } from '@nestjs/common';
|
||||
import { AsyncRegisterController } from './async-register.controller';
|
||||
import { CacheConfig } from './config/cache.config';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
CacheModule.registerAsync({
|
||||
isGlobal: true,
|
||||
useClass: CacheConfig,
|
||||
}),
|
||||
],
|
||||
controllers: [AsyncRegisterController],
|
||||
})
|
||||
export class AsyncRegisterModule {}
|
||||
14
integration/cache/src/async-register/config/cache.config.ts
vendored
Normal file
14
integration/cache/src/async-register/config/cache.config.ts
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
import {
|
||||
CacheModuleOptions,
|
||||
CacheOptionsFactory,
|
||||
Injectable,
|
||||
} from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class CacheConfig implements CacheOptionsFactory {
|
||||
createCacheOptions(): CacheModuleOptions {
|
||||
const ttl = 100;
|
||||
|
||||
return { ttl };
|
||||
}
|
||||
}
|
||||
40
integration/cache/src/async-register/tsconfig.json
vendored
Normal file
40
integration/cache/src/async-register/tsconfig.json
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"declaration": false,
|
||||
"noImplicitAny": false,
|
||||
"removeComments": true,
|
||||
"noLib": false,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"target": "es6",
|
||||
"sourceMap": true,
|
||||
"allowJs": true,
|
||||
"outDir": "./dist",
|
||||
"paths": {
|
||||
"@nestjs/common": ["../../packages/common"],
|
||||
"@nestjs/common/*": ["../../packages/common/*"],
|
||||
"@nestjs/core": ["../../packages/core"],
|
||||
"@nestjs/core/*": ["../../packages/core/*"],
|
||||
"@nestjs/microservices": ["../../packages/microservices"],
|
||||
"@nestjs/microservices/*": ["../../packages/microservices/*"],
|
||||
"@nestjs/websockets": ["../../packages/websockets"],
|
||||
"@nestjs/websockets/*": ["../../packages/websockets/*"],
|
||||
"@nestjs/testing": ["../../packages/testing"],
|
||||
"@nestjs/testing/*": ["../../packages/testing/*"],
|
||||
"@nestjs/platform-express": ["../../packages/platform-express"],
|
||||
"@nestjs/platform-express/*": ["../../packages/platform-express/*"],
|
||||
"@nestjs/platform-socket.io": ["../../packages/platform-socket.io"],
|
||||
"@nestjs/platform-socket.io/*": ["../../packages/platform-socket.io/*"],
|
||||
"@nestjs/platform-ws": ["../../packages/platform-ws"],
|
||||
"@nestjs/platform-ws/*": ["../../packages/platform-ws/*"]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"src/**/*",
|
||||
"e2e/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
]
|
||||
}
|
||||
16
integration/cache/src/multi-store/multi-store.controller.ts
vendored
Normal file
16
integration/cache/src/multi-store/multi-store.controller.ts
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
import { Controller, Get, Inject, CACHE_MANAGER } from '@nestjs/common';
|
||||
import { Cache } from 'cache-manager';
|
||||
|
||||
@Controller()
|
||||
export class MultiStoreController {
|
||||
constructor(@Inject(CACHE_MANAGER) private cacheManager: Cache) {}
|
||||
|
||||
@Get()
|
||||
async getFromMultiStore(): Promise<unknown> {
|
||||
const value = await this.cacheManager.get('multi-store-key');
|
||||
if (!value) {
|
||||
await this.cacheManager.set('multi-store-key', 'multi-store-value');
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
24
integration/cache/src/multi-store/multi-store.module.ts
vendored
Normal file
24
integration/cache/src/multi-store/multi-store.module.ts
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
import { CacheModule, Module } from '@nestjs/common';
|
||||
import { redisStore } from 'cache-manager-redis-store';
|
||||
import { MultiStoreController } from './multi-store.controller';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
CacheModule.register([
|
||||
{
|
||||
store: 'memory',
|
||||
max: 100,
|
||||
ttl: 10,
|
||||
},
|
||||
{
|
||||
store: redisStore,
|
||||
host: 'localhost',
|
||||
port: 6379,
|
||||
db: 0,
|
||||
ttl: 600,
|
||||
},
|
||||
]),
|
||||
],
|
||||
controllers: [MultiStoreController],
|
||||
})
|
||||
export class MultiStoreModule {}
|
||||
40
integration/cache/src/multi-store/tsconfig.json
vendored
Normal file
40
integration/cache/src/multi-store/tsconfig.json
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"declaration": false,
|
||||
"noImplicitAny": false,
|
||||
"removeComments": true,
|
||||
"noLib": false,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"target": "es6",
|
||||
"sourceMap": true,
|
||||
"allowJs": true,
|
||||
"outDir": "./dist",
|
||||
"paths": {
|
||||
"@nestjs/common": ["../../packages/common"],
|
||||
"@nestjs/common/*": ["../../packages/common/*"],
|
||||
"@nestjs/core": ["../../packages/core"],
|
||||
"@nestjs/core/*": ["../../packages/core/*"],
|
||||
"@nestjs/microservices": ["../../packages/microservices"],
|
||||
"@nestjs/microservices/*": ["../../packages/microservices/*"],
|
||||
"@nestjs/websockets": ["../../packages/websockets"],
|
||||
"@nestjs/websockets/*": ["../../packages/websockets/*"],
|
||||
"@nestjs/testing": ["../../packages/testing"],
|
||||
"@nestjs/testing/*": ["../../packages/testing/*"],
|
||||
"@nestjs/platform-express": ["../../packages/platform-express"],
|
||||
"@nestjs/platform-express/*": ["../../packages/platform-express/*"],
|
||||
"@nestjs/platform-socket.io": ["../../packages/platform-socket.io"],
|
||||
"@nestjs/platform-socket.io/*": ["../../packages/platform-socket.io/*"],
|
||||
"@nestjs/platform-ws": ["../../packages/platform-ws"],
|
||||
"@nestjs/platform-ws/*": ["../../packages/platform-ws/*"]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"src/**/*",
|
||||
"e2e/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
]
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
"noLib": false,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"target": "ES2021",
|
||||
"target": "es6",
|
||||
"sourceMap": true,
|
||||
"allowJs": true,
|
||||
"outDir": "./dist",
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { DiscoveryService } from '@nestjs/core';
|
||||
import { expect } from 'chai';
|
||||
import { AppModule } from '../src/app.module';
|
||||
import { WebhooksExplorer } from '../src/webhooks.explorer';
|
||||
import { NonAppliedDecorator } from '../src/decorators/non-applied.decorator';
|
||||
|
||||
describe('DiscoveryModule', () => {
|
||||
let moduleRef: TestingModule;
|
||||
|
||||
beforeEach(async () => {
|
||||
moduleRef = await Test.createTestingModule({
|
||||
imports: [AppModule],
|
||||
}).compile();
|
||||
});
|
||||
|
||||
it('should discover all providers & handlers with corresponding annotations', async () => {
|
||||
const webhooksExplorer = moduleRef.get(WebhooksExplorer);
|
||||
|
||||
expect(webhooksExplorer.getWebhooks()).to.be.eql([
|
||||
{
|
||||
handlers: [
|
||||
{
|
||||
event: 'start',
|
||||
methodName: 'onStart',
|
||||
},
|
||||
],
|
||||
name: 'cleanup',
|
||||
},
|
||||
{
|
||||
handlers: [
|
||||
{
|
||||
event: 'start',
|
||||
methodName: 'onStart',
|
||||
},
|
||||
],
|
||||
name: 'flush',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should return an empty array if no providers were found for a given discoverable decorator', () => {
|
||||
const discoveryService = moduleRef.get(DiscoveryService);
|
||||
|
||||
const providers = discoveryService.getProviders({
|
||||
metadataKey: NonAppliedDecorator.KEY,
|
||||
});
|
||||
expect(providers).to.be.eql([]);
|
||||
});
|
||||
|
||||
it('should return an empty array if no controllers were found for a given discoverable decorator', () => {
|
||||
const discoveryService = moduleRef.get(DiscoveryService);
|
||||
|
||||
const controllers = discoveryService.getControllers({
|
||||
metadataKey: NonAppliedDecorator.KEY,
|
||||
});
|
||||
expect(controllers).to.be.eql([]);
|
||||
});
|
||||
});
|
||||
@@ -1,10 +0,0 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { DiscoveryModule } from '@nestjs/core';
|
||||
import { MyWebhookModule } from './my-webhook/my-webhook.module';
|
||||
import { WebhooksExplorer } from './webhooks.explorer';
|
||||
|
||||
@Module({
|
||||
imports: [MyWebhookModule, DiscoveryModule],
|
||||
providers: [WebhooksExplorer],
|
||||
})
|
||||
export class AppModule {}
|
||||
@@ -1,9 +0,0 @@
|
||||
import { DiscoveryService } from '@nestjs/core';
|
||||
|
||||
/**
|
||||
* This decorator must not be used anywhere!
|
||||
*
|
||||
* This will be used to test the scenario where we are trying to retrieving
|
||||
* metadata for a discoverable decorator that was not applied to any class.
|
||||
*/
|
||||
export const NonAppliedDecorator = DiscoveryService.createDecorator();
|
||||
@@ -1,6 +0,0 @@
|
||||
import { DiscoveryService } from '@nestjs/core';
|
||||
|
||||
export const Webhook = DiscoveryService.createDecorator<{ name: string }>();
|
||||
export const WebhookHandler = DiscoveryService.createDecorator<{
|
||||
event: string;
|
||||
}>();
|
||||
@@ -1,9 +0,0 @@
|
||||
import { Webhook, WebhookHandler } from '../decorators/webhook.decorators';
|
||||
|
||||
@Webhook({ name: 'cleanup' })
|
||||
export class CleanupWebhook {
|
||||
@WebhookHandler({ event: 'start' })
|
||||
onStart() {
|
||||
console.log('cleanup started');
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import { Webhook, WebhookHandler } from '../decorators/webhook.decorators';
|
||||
|
||||
@Webhook({ name: 'flush' })
|
||||
export class FlushWebhook {
|
||||
@WebhookHandler({ event: 'start' })
|
||||
onStart() {
|
||||
console.log('flush started');
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { CleanupWebhook } from './cleanup.webhook';
|
||||
import { FlushWebhook } from './flush.webhook';
|
||||
|
||||
@Module({ providers: [CleanupWebhook, FlushWebhook] })
|
||||
export class MyWebhookModule {}
|
||||
@@ -1,39 +0,0 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { DiscoveryService, MetadataScanner } from '@nestjs/core';
|
||||
import { Webhook, WebhookHandler } from './decorators/webhook.decorators';
|
||||
|
||||
@Injectable()
|
||||
export class WebhooksExplorer {
|
||||
constructor(
|
||||
private readonly discoveryService: DiscoveryService,
|
||||
private readonly metadataScanner: MetadataScanner,
|
||||
) {}
|
||||
|
||||
getWebhooks() {
|
||||
const webhooks = this.discoveryService.getProviders({
|
||||
metadataKey: Webhook.KEY,
|
||||
});
|
||||
return webhooks.map(wrapper => {
|
||||
const { name } = this.discoveryService.getMetadataByDecorator(
|
||||
Webhook,
|
||||
wrapper,
|
||||
);
|
||||
return {
|
||||
name,
|
||||
handlers: this.metadataScanner
|
||||
.getAllMethodNames(wrapper.metatype.prototype)
|
||||
.map(methodName => {
|
||||
const { event } = this.discoveryService.getMetadataByDecorator(
|
||||
WebhookHandler,
|
||||
wrapper,
|
||||
methodName,
|
||||
);
|
||||
return {
|
||||
methodName,
|
||||
event,
|
||||
};
|
||||
}),
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ services:
|
||||
- "9001:9001"
|
||||
restart: always
|
||||
mysql:
|
||||
image: mysql:8.3.0
|
||||
image: mysql:8.0.30
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: root
|
||||
MYSQL_DATABASE: test
|
||||
@@ -50,7 +50,7 @@ services:
|
||||
zookeeper:
|
||||
container_name: test-zookeeper
|
||||
hostname: zookeeper
|
||||
image: confluentinc/cp-zookeeper:7.5.3
|
||||
image: confluentinc/cp-zookeeper:7.0.1
|
||||
ports:
|
||||
- "2181:2181"
|
||||
environment:
|
||||
@@ -59,7 +59,7 @@ services:
|
||||
kafka:
|
||||
container_name: test-kafka
|
||||
hostname: kafka
|
||||
image: confluentinc/cp-kafka:7.5.3
|
||||
image: confluentinc/cp-kafka:7.0.1
|
||||
depends_on:
|
||||
- zookeeper
|
||||
ports:
|
||||
|
||||
@@ -30,8 +30,8 @@ describe('GraphQL Pipes', () => {
|
||||
errors: [
|
||||
{
|
||||
extensions: {
|
||||
code: 'BAD_REQUEST',
|
||||
originalError: {
|
||||
code: 'BAD_USER_INPUT',
|
||||
response: {
|
||||
error: 'Bad Request',
|
||||
message: [
|
||||
'description must be longer than or equal to 30 characters',
|
||||
@@ -39,14 +39,7 @@ describe('GraphQL Pipes', () => {
|
||||
statusCode: 400,
|
||||
},
|
||||
},
|
||||
locations: [
|
||||
{
|
||||
column: 3,
|
||||
line: 2,
|
||||
},
|
||||
],
|
||||
message: 'Bad Request Exception',
|
||||
path: ['addRecipe'],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
@@ -31,4 +31,4 @@ input NewRecipeInput {
|
||||
|
||||
type Subscription {
|
||||
recipeAdded: Recipe!
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import { RecipesModule } from './recipes/recipes.module';
|
||||
RecipesModule,
|
||||
GraphQLModule.forRoot<ApolloDriverConfig>({
|
||||
driver: ApolloDriver,
|
||||
includeStacktraceInErrorResponses: false,
|
||||
debug: false,
|
||||
installSubscriptionHandlers: true,
|
||||
autoSchemaFile: join(
|
||||
process.cwd(),
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { ValidationPipe } from '@nestjs/common';
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import { AppModule } from './app.module';
|
||||
import { ApplicationModule } from './app.module';
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create(AppModule);
|
||||
const app = await NestFactory.create(ApplicationModule);
|
||||
app.useGlobalPipes(new ValidationPipe());
|
||||
await app.listen(3000);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"noLib": false,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"target": "ES2021",
|
||||
"target": "es6",
|
||||
"sourceMap": true,
|
||||
"allowJs": true,
|
||||
"outDir": "./dist",
|
||||
|
||||
@@ -9,7 +9,6 @@ import { CatsModule } from './cats/cats.module';
|
||||
CatsModule,
|
||||
GraphQLModule.forRoot<ApolloDriverConfig>({
|
||||
driver: ApolloDriver,
|
||||
includeStacktraceInErrorResponses: true,
|
||||
typePaths: [join(__dirname, '**', '*.graphql')],
|
||||
}),
|
||||
],
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import { AppModule } from './app.module';
|
||||
import { ApplicationModule } from './app.module';
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create(AppModule);
|
||||
const app = await NestFactory.create(ApplicationModule);
|
||||
await app.listen(3000);
|
||||
}
|
||||
bootstrap();
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"noLib": false,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"target": "ES2021",
|
||||
"target": "es6",
|
||||
"sourceMap": true,
|
||||
"allowJs": true,
|
||||
"outDir": "./dist",
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
import { HttpStatus, INestApplication } from '@nestjs/common';
|
||||
import { HttpServer, HttpStatus, INestApplication } from '@nestjs/common';
|
||||
import {
|
||||
FastifyAdapter,
|
||||
NestFastifyApplication,
|
||||
} from '@nestjs/platform-fastify';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { expect } from 'chai';
|
||||
import { RawServerDefault } from 'fastify';
|
||||
import * as request from 'supertest';
|
||||
import { ErrorsController } from '../src/errors/errors.controller';
|
||||
|
||||
describe('Error messages', () => {
|
||||
let server: RawServerDefault;
|
||||
let server: HttpServer;
|
||||
|
||||
describe('Express', () => {
|
||||
let app: INestApplication;
|
||||
|
||||
@@ -45,11 +45,6 @@ class TestController {
|
||||
overviewById() {
|
||||
return RETURN_VALUE;
|
||||
}
|
||||
|
||||
@Get('multiple/exclude')
|
||||
multipleExclude() {
|
||||
return RETURN_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
@Module({
|
||||
@@ -64,7 +59,6 @@ class TestModule {
|
||||
path: 'middleware',
|
||||
method: RequestMethod.POST,
|
||||
})
|
||||
.exclude('multiple/exclude')
|
||||
.forRoutes('*');
|
||||
}
|
||||
}
|
||||
@@ -116,12 +110,6 @@ describe('Exclude middleware', () => {
|
||||
.expect(200, RETURN_VALUE);
|
||||
});
|
||||
|
||||
it(`should exclude "/multiple/exclude" endpoint`, () => {
|
||||
return request(app.getHttpServer())
|
||||
.get('/multiple/exclude')
|
||||
.expect(200, RETURN_VALUE);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await app.close();
|
||||
});
|
||||
|
||||
@@ -45,10 +45,6 @@ describe('Hello world (express instance)', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('/HEAD should respond to with a 200', () => {
|
||||
return request(server).head('/hello').expect(200);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await app.close();
|
||||
});
|
||||
|
||||
@@ -87,15 +87,6 @@ describe('Hello world (fastify adapter)', () => {
|
||||
.then(({ payload }) => expect(payload).to.be.eql('Hello world!'));
|
||||
});
|
||||
|
||||
it('/HEAD should respond to with a 200', () => {
|
||||
return app
|
||||
.inject({
|
||||
method: 'HEAD',
|
||||
url: '/hello',
|
||||
})
|
||||
.then(({ statusCode }) => expect(statusCode).to.be.eq(200));
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await app.close();
|
||||
});
|
||||
|
||||
@@ -3,10 +3,7 @@ import {
|
||||
Get,
|
||||
MiddlewareConsumer,
|
||||
Module,
|
||||
NestMiddleware,
|
||||
NestModule,
|
||||
Query,
|
||||
Req,
|
||||
RequestMethod,
|
||||
} from '@nestjs/common';
|
||||
import {
|
||||
@@ -17,385 +14,178 @@ import { Test } from '@nestjs/testing';
|
||||
import { expect } from 'chai';
|
||||
import { AppModule } from '../src/app.module';
|
||||
|
||||
const INCLUDED_VALUE = 'test_included';
|
||||
const QUERY_VALUE = 'test_query';
|
||||
const REQ_URL_VALUE = 'test_req_url';
|
||||
const RETURN_VALUE = 'test';
|
||||
const SCOPED_VALUE = 'test_scoped';
|
||||
const WILDCARD_VALUE = 'test_wildcard';
|
||||
|
||||
@Controller()
|
||||
class TestController {
|
||||
@Get('express_style_wildcard/wildcard_nested')
|
||||
express_style_wildcard() {
|
||||
return RETURN_VALUE;
|
||||
}
|
||||
|
||||
@Get('test')
|
||||
test() {
|
||||
return RETURN_VALUE;
|
||||
}
|
||||
|
||||
@Get('query')
|
||||
query() {
|
||||
return RETURN_VALUE;
|
||||
}
|
||||
|
||||
@Get('tests/wildcard_nested')
|
||||
wildcard_nested() {
|
||||
return RETURN_VALUE;
|
||||
}
|
||||
|
||||
@Get('tests/included')
|
||||
included() {
|
||||
return RETURN_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
@Controller(QUERY_VALUE)
|
||||
class TestQueryController {
|
||||
@Get()
|
||||
[QUERY_VALUE](@Query('test') test: string) {
|
||||
return test;
|
||||
}
|
||||
}
|
||||
|
||||
@Module({
|
||||
imports: [AppModule],
|
||||
controllers: [TestController, TestQueryController],
|
||||
})
|
||||
class TestModule {
|
||||
configure(consumer: MiddlewareConsumer) {
|
||||
consumer
|
||||
.apply((req, res, next) => res.end(INCLUDED_VALUE))
|
||||
.forRoutes({ path: 'tests/included', method: RequestMethod.POST })
|
||||
.apply((req, res, next) => res.end(`${REQ_URL_VALUE}${req.url}`))
|
||||
.forRoutes('req/url/')
|
||||
.apply((req, res, next) => res.end(WILDCARD_VALUE))
|
||||
.forRoutes('express_style_wildcard/*', 'tests/(.*)')
|
||||
.apply((req, res, next) => res.end(QUERY_VALUE))
|
||||
.forRoutes('query')
|
||||
.apply((req, res, next) => next())
|
||||
.forRoutes(TestQueryController)
|
||||
.apply((req, res, next) => res.end(SCOPED_VALUE))
|
||||
.forRoutes(TestController)
|
||||
.apply((req, res, next) => res.end(RETURN_VALUE))
|
||||
.exclude({ path: QUERY_VALUE, method: -1 })
|
||||
.forRoutes('(.*)');
|
||||
}
|
||||
}
|
||||
|
||||
describe('Middleware (FastifyAdapter)', () => {
|
||||
let app: NestFastifyApplication;
|
||||
|
||||
describe('should return expected values depending on the route', () => {
|
||||
const INCLUDED_VALUE = 'test_included';
|
||||
const QUERY_VALUE = 'test_query';
|
||||
const REQ_URL_VALUE = 'test_req_url';
|
||||
const RETURN_VALUE = 'test';
|
||||
const SCOPED_VALUE = 'test_scoped';
|
||||
const WILDCARD_VALUE = 'test_wildcard';
|
||||
beforeEach(async () => {
|
||||
app = (
|
||||
await Test.createTestingModule({
|
||||
imports: [TestModule],
|
||||
}).compile()
|
||||
).createNestApplication<NestFastifyApplication>(new FastifyAdapter());
|
||||
|
||||
@Controller()
|
||||
class TestController {
|
||||
@Get('express_style_wildcard/wildcard_nested')
|
||||
express_style_wildcard() {
|
||||
return RETURN_VALUE;
|
||||
}
|
||||
|
||||
@Get('test')
|
||||
test() {
|
||||
return RETURN_VALUE;
|
||||
}
|
||||
|
||||
@Get('query')
|
||||
query() {
|
||||
return RETURN_VALUE;
|
||||
}
|
||||
|
||||
@Get('tests/wildcard_nested')
|
||||
wildcard_nested() {
|
||||
return RETURN_VALUE;
|
||||
}
|
||||
|
||||
@Get('tests/included')
|
||||
included() {
|
||||
return RETURN_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
@Controller(QUERY_VALUE)
|
||||
class TestQueryController {
|
||||
@Get()
|
||||
[QUERY_VALUE](@Query('test') test: string) {
|
||||
return test;
|
||||
}
|
||||
}
|
||||
|
||||
@Module({
|
||||
imports: [AppModule],
|
||||
controllers: [TestController, TestQueryController],
|
||||
})
|
||||
class TestModule {
|
||||
configure(consumer: MiddlewareConsumer) {
|
||||
consumer
|
||||
.apply((req, res, next) => res.end(INCLUDED_VALUE))
|
||||
.forRoutes({ path: 'tests/included', method: RequestMethod.POST })
|
||||
.apply((req, res, next) => res.end(REQ_URL_VALUE))
|
||||
.forRoutes('req/url/(.*)')
|
||||
.apply((req, res, next) => res.end(WILDCARD_VALUE))
|
||||
.forRoutes('express_style_wildcard/*', 'tests/(.*)')
|
||||
.apply((req, res, next) => res.end(QUERY_VALUE))
|
||||
.forRoutes('query')
|
||||
.apply((req, res, next) => next())
|
||||
.forRoutes(TestQueryController)
|
||||
.apply((req, res, next) => res.end(SCOPED_VALUE))
|
||||
.forRoutes(TestController)
|
||||
.apply((req, res, next) => res.end(RETURN_VALUE))
|
||||
.exclude({ path: QUERY_VALUE, method: -1 as any })
|
||||
.forRoutes('(.*)');
|
||||
}
|
||||
}
|
||||
|
||||
beforeEach(async () => {
|
||||
app = (
|
||||
await Test.createTestingModule({
|
||||
imports: [TestModule],
|
||||
}).compile()
|
||||
).createNestApplication<NestFastifyApplication>(new FastifyAdapter());
|
||||
|
||||
await app.init();
|
||||
});
|
||||
|
||||
it(`forRoutes((.*))`, () => {
|
||||
return app
|
||||
.inject({
|
||||
method: 'GET',
|
||||
url: '/hello',
|
||||
})
|
||||
.then(({ payload }) => expect(payload).to.be.eql(RETURN_VALUE));
|
||||
});
|
||||
|
||||
it(`forRoutes(TestController)`, () => {
|
||||
return app
|
||||
.inject({
|
||||
method: 'GET',
|
||||
url: '/test',
|
||||
})
|
||||
.then(({ payload }) => expect(payload).to.be.eql(SCOPED_VALUE));
|
||||
});
|
||||
|
||||
it(`query?test=${QUERY_VALUE} forRoutes(query)`, () => {
|
||||
return app
|
||||
.inject({
|
||||
method: 'GET',
|
||||
url: '/query',
|
||||
query: {
|
||||
test: QUERY_VALUE,
|
||||
},
|
||||
})
|
||||
.then(({ payload }) => expect(payload).to.be.eql(QUERY_VALUE));
|
||||
});
|
||||
|
||||
it(`${QUERY_VALUE}?test=${QUERY_VALUE} forRoutes(${QUERY_VALUE})`, () => {
|
||||
return app
|
||||
.inject({
|
||||
method: 'GET',
|
||||
url: QUERY_VALUE,
|
||||
query: {
|
||||
test: QUERY_VALUE,
|
||||
},
|
||||
})
|
||||
.then(({ payload }) => expect(payload).to.be.eql(QUERY_VALUE));
|
||||
});
|
||||
|
||||
it(`forRoutes(tests/(.*))`, () => {
|
||||
return app
|
||||
.inject({
|
||||
method: 'GET',
|
||||
url: '/tests/wildcard_nested',
|
||||
})
|
||||
.then(({ payload }) => expect(payload).to.be.eql(WILDCARD_VALUE));
|
||||
});
|
||||
|
||||
it(`forRoutes(express_style_wildcard/*)`, () => {
|
||||
return app
|
||||
.inject({
|
||||
method: 'GET',
|
||||
url: '/express_style_wildcard/wildcard_nested',
|
||||
})
|
||||
.then(({ payload }) => expect(payload).to.be.eql(WILDCARD_VALUE));
|
||||
});
|
||||
|
||||
it(`forRoutes(req/url/)`, () => {
|
||||
const reqUrl = '/test';
|
||||
return app
|
||||
.inject({
|
||||
method: 'GET',
|
||||
url: `/req/url${reqUrl}`,
|
||||
})
|
||||
.then(({ payload }) => expect(payload).to.be.eql(REQ_URL_VALUE));
|
||||
});
|
||||
|
||||
it(`GET forRoutes(POST tests/included)`, () => {
|
||||
return app
|
||||
.inject({
|
||||
method: 'GET',
|
||||
url: '/tests/included',
|
||||
})
|
||||
.then(({ payload }) => expect(payload).to.be.eql(WILDCARD_VALUE));
|
||||
});
|
||||
|
||||
it(`POST forRoutes(POST tests/included)`, () => {
|
||||
return app
|
||||
.inject({
|
||||
method: 'POST',
|
||||
url: '/tests/included',
|
||||
})
|
||||
.then(({ payload }) => expect(payload).to.be.eql(INCLUDED_VALUE));
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await app.close();
|
||||
});
|
||||
await app.init();
|
||||
});
|
||||
|
||||
describe('should execute middleware only once for given routes', () => {
|
||||
class Middleware implements NestMiddleware {
|
||||
use(request: any, reply: any, next: () => void) {
|
||||
if (request.middlewareExecutionCount === undefined) {
|
||||
request.middlewareExecutionCount = 1;
|
||||
} else {
|
||||
request.middlewareExecutionCount++;
|
||||
}
|
||||
next();
|
||||
}
|
||||
}
|
||||
it(`forRoutes((.*))`, () => {
|
||||
return app
|
||||
.inject({
|
||||
method: 'GET',
|
||||
url: '/hello',
|
||||
})
|
||||
.then(({ payload }) => expect(payload).to.be.eql(RETURN_VALUE));
|
||||
});
|
||||
|
||||
@Controller()
|
||||
class AbcController {
|
||||
@Get('/a')
|
||||
async a(@Req() request: any) {
|
||||
return this.validateExecutionCount({
|
||||
request,
|
||||
expected: 1,
|
||||
});
|
||||
}
|
||||
it(`forRoutes(TestController)`, () => {
|
||||
return app
|
||||
.inject({
|
||||
method: 'GET',
|
||||
url: '/test',
|
||||
})
|
||||
.then(({ payload }) => expect(payload).to.be.eql(SCOPED_VALUE));
|
||||
});
|
||||
|
||||
@Get('/a/b')
|
||||
async ab(@Req() request: any) {
|
||||
return this.validateExecutionCount({
|
||||
request,
|
||||
expected: 1,
|
||||
});
|
||||
}
|
||||
it(`query?test=${QUERY_VALUE} forRoutes(query)`, () => {
|
||||
return app
|
||||
.inject({
|
||||
method: 'GET',
|
||||
url: '/query',
|
||||
query: {
|
||||
test: QUERY_VALUE,
|
||||
},
|
||||
})
|
||||
.then(({ payload }) => expect(payload).to.be.eql(QUERY_VALUE));
|
||||
});
|
||||
|
||||
@Get('/a/b/c')
|
||||
async abc(@Req() request: any) {
|
||||
return this.validateExecutionCount({
|
||||
request,
|
||||
expected: 1,
|
||||
});
|
||||
}
|
||||
it(`${QUERY_VALUE}?test=${QUERY_VALUE} forRoutes(${QUERY_VALUE})`, () => {
|
||||
return app
|
||||
.inject({
|
||||
method: 'GET',
|
||||
url: QUERY_VALUE,
|
||||
query: {
|
||||
test: QUERY_VALUE,
|
||||
},
|
||||
})
|
||||
.then(({ payload }) => expect(payload).to.be.eql(QUERY_VALUE));
|
||||
});
|
||||
|
||||
@Get('/similar')
|
||||
async withSimilar(@Req() request: any) {
|
||||
return this.validateExecutionCount({
|
||||
request,
|
||||
expected: 1,
|
||||
});
|
||||
}
|
||||
it(`forRoutes(tests/(.*))`, () => {
|
||||
return app
|
||||
.inject({
|
||||
method: 'GET',
|
||||
url: '/tests/wildcard_nested',
|
||||
})
|
||||
.then(({ payload }) => expect(payload).to.be.eql(WILDCARD_VALUE));
|
||||
});
|
||||
|
||||
@Get('/similar/test')
|
||||
async withSimilarTest(@Req() request: any) {
|
||||
return this.validateExecutionCount({
|
||||
request,
|
||||
expected: 1,
|
||||
});
|
||||
}
|
||||
it(`forRoutes(express_style_wildcard/*)`, () => {
|
||||
return app
|
||||
.inject({
|
||||
method: 'GET',
|
||||
url: '/express_style_wildcard/wildcard_nested',
|
||||
})
|
||||
.then(({ payload }) => expect(payload).to.be.eql(WILDCARD_VALUE));
|
||||
});
|
||||
|
||||
@Get('/similar/:id')
|
||||
async withSimilarId(@Req() request: any) {
|
||||
return this.validateExecutionCount({
|
||||
request,
|
||||
expected: 1,
|
||||
});
|
||||
}
|
||||
it(`forRoutes(req/url/)`, () => {
|
||||
const reqUrl = '/test';
|
||||
return app
|
||||
.inject({
|
||||
method: 'GET',
|
||||
url: `/req/url${reqUrl}`,
|
||||
})
|
||||
.then(({ payload }) =>
|
||||
expect(payload).to.be.eql(`${REQ_URL_VALUE}${reqUrl}`),
|
||||
);
|
||||
});
|
||||
|
||||
private validateExecutionCount({
|
||||
request,
|
||||
expected,
|
||||
}: {
|
||||
request: any;
|
||||
expected: number;
|
||||
}) {
|
||||
let actual: number | undefined;
|
||||
actual = request.raw.middlewareExecutionCount;
|
||||
actual ??= 0;
|
||||
it(`GET forRoutes(POST tests/included)`, () => {
|
||||
return app
|
||||
.inject({
|
||||
method: 'GET',
|
||||
url: '/tests/included',
|
||||
})
|
||||
.then(({ payload }) => expect(payload).to.be.eql(WILDCARD_VALUE));
|
||||
});
|
||||
|
||||
return {
|
||||
success: actual === expected,
|
||||
actual,
|
||||
expected,
|
||||
};
|
||||
}
|
||||
}
|
||||
it(`POST forRoutes(POST tests/included)`, () => {
|
||||
return app
|
||||
.inject({
|
||||
method: 'POST',
|
||||
url: '/tests/included',
|
||||
})
|
||||
.then(({ payload }) => expect(payload).to.be.eql(INCLUDED_VALUE));
|
||||
});
|
||||
|
||||
@Module({
|
||||
controllers: [AbcController],
|
||||
})
|
||||
class TestModule implements NestModule {
|
||||
configure(consumer: MiddlewareConsumer) {
|
||||
consumer.apply(Middleware).forRoutes(AbcController);
|
||||
}
|
||||
}
|
||||
|
||||
beforeEach(async () => {
|
||||
app = (
|
||||
await Test.createTestingModule({
|
||||
imports: [TestModule],
|
||||
}).compile()
|
||||
).createNestApplication<NestFastifyApplication>(new FastifyAdapter());
|
||||
|
||||
await app.init();
|
||||
});
|
||||
|
||||
it(`GET forRoutes(/a/b/c)`, () => {
|
||||
return app
|
||||
.inject({
|
||||
method: 'GET',
|
||||
url: '/a/b/c',
|
||||
})
|
||||
.then(({ payload }) => {
|
||||
expect(payload).to.be.eql(
|
||||
JSON.stringify({
|
||||
success: true,
|
||||
actual: 1,
|
||||
expected: 1,
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it(`GET forRoutes(/a/b)`, () => {
|
||||
return app
|
||||
.inject({
|
||||
method: 'GET',
|
||||
url: '/a/b',
|
||||
})
|
||||
.then(({ payload }) =>
|
||||
expect(payload).to.be.eql(
|
||||
JSON.stringify({
|
||||
success: true,
|
||||
actual: 1,
|
||||
expected: 1,
|
||||
}),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
it(`GET forRoutes(/a)`, () => {
|
||||
return app
|
||||
.inject({
|
||||
method: 'GET',
|
||||
url: '/a',
|
||||
})
|
||||
.then(({ payload }) =>
|
||||
expect(payload).to.be.eql(
|
||||
JSON.stringify({
|
||||
success: true,
|
||||
actual: 1,
|
||||
expected: 1,
|
||||
}),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
it(`GET forRoutes(/similar)`, () => {
|
||||
return app
|
||||
.inject({
|
||||
method: 'GET',
|
||||
url: '/similar',
|
||||
})
|
||||
.then(({ payload }) =>
|
||||
expect(payload).to.be.eql(
|
||||
JSON.stringify({
|
||||
success: true,
|
||||
actual: 1,
|
||||
expected: 1,
|
||||
}),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
it(`GET forRoutes(/similar/test)`, () => {
|
||||
return app
|
||||
.inject({
|
||||
method: 'GET',
|
||||
url: '/similar/test',
|
||||
})
|
||||
.then(({ payload }) =>
|
||||
expect(payload).to.be.eql(
|
||||
JSON.stringify({
|
||||
success: true,
|
||||
actual: 1,
|
||||
expected: 1,
|
||||
}),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
it(`GET forRoutes(/similar/arbitrary)`, () => {
|
||||
return app
|
||||
.inject({
|
||||
method: 'GET',
|
||||
url: '/similar/arbitrary',
|
||||
})
|
||||
.then(({ payload }) =>
|
||||
expect(payload).to.be.eql(
|
||||
JSON.stringify({
|
||||
success: true,
|
||||
actual: 1,
|
||||
expected: 1,
|
||||
}),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await app.close();
|
||||
});
|
||||
afterEach(async () => {
|
||||
await app.close();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
INestApplication,
|
||||
Injectable,
|
||||
MiddlewareConsumer,
|
||||
NestMiddleware,
|
||||
Module,
|
||||
} from '@nestjs/common';
|
||||
import { Test } from '../../../packages/testing';
|
||||
import * as request from 'supertest';
|
||||
import { expect } from 'chai';
|
||||
|
||||
/**
|
||||
* Number of times that the middleware was executed.
|
||||
*/
|
||||
let triggerCounter = 0;
|
||||
@Injectable()
|
||||
class Middleware implements NestMiddleware {
|
||||
use(req, res, next) {
|
||||
triggerCounter++;
|
||||
next();
|
||||
}
|
||||
}
|
||||
|
||||
@Controller()
|
||||
class TestController {
|
||||
@Get('/test')
|
||||
testA() {}
|
||||
|
||||
@Get('/:id')
|
||||
testB() {}
|
||||
|
||||
@Get('/static/route')
|
||||
testC() {}
|
||||
|
||||
@Get('/:id/:nested')
|
||||
testD() {}
|
||||
}
|
||||
|
||||
@Module({
|
||||
controllers: [TestController],
|
||||
})
|
||||
class TestModule {
|
||||
configure(consumer: MiddlewareConsumer) {
|
||||
consumer.apply(Middleware).forRoutes(TestController);
|
||||
}
|
||||
}
|
||||
|
||||
describe('Middleware (run on route match)', () => {
|
||||
let app: INestApplication;
|
||||
|
||||
beforeEach(async () => {
|
||||
triggerCounter = 0;
|
||||
app = (
|
||||
await Test.createTestingModule({
|
||||
imports: [TestModule],
|
||||
}).compile()
|
||||
).createNestApplication();
|
||||
|
||||
await app.init();
|
||||
});
|
||||
|
||||
it(`forRoutes(TestController) should execute middleware once when request url is equal match`, () => {
|
||||
return request(app.getHttpServer())
|
||||
.get('/test')
|
||||
.expect(200)
|
||||
.then(() => {
|
||||
expect(triggerCounter).to.be.eq(1);
|
||||
});
|
||||
});
|
||||
|
||||
it(`forRoutes(TestController) should execute middleware once when request url is not equal match`, () => {
|
||||
return request(app.getHttpServer())
|
||||
.get('/1')
|
||||
.expect(200)
|
||||
.then(() => {
|
||||
expect(triggerCounter).to.be.eq(1);
|
||||
});
|
||||
});
|
||||
|
||||
it(`forRoutes(TestController) should execute middleware once when request url is not of nested params`, () => {
|
||||
return request(app.getHttpServer())
|
||||
.get('/static/route')
|
||||
.expect(200)
|
||||
.then(() => {
|
||||
expect(triggerCounter).to.be.eq(1);
|
||||
});
|
||||
});
|
||||
|
||||
it(`forRoutes(TestController) should execute middleware once when request url is of nested params`, () => {
|
||||
return request(app.getHttpServer())
|
||||
.get('/1/abc')
|
||||
.expect(200)
|
||||
.then(() => {
|
||||
expect(triggerCounter).to.be.eq(1);
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await app.close();
|
||||
});
|
||||
});
|
||||
@@ -7,7 +7,7 @@
|
||||
"noLib": false,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"target": "ES2021",
|
||||
"target": "es6",
|
||||
"sourceMap": true,
|
||||
"allowJs": true,
|
||||
"outDir": "./dist",
|
||||
|
||||
@@ -43,7 +43,10 @@ describe('OnModuleDestroy', () => {
|
||||
it('should sort modules by distance (topological sort) - DESC order', async () => {
|
||||
@Injectable()
|
||||
class BB implements OnModuleDestroy {
|
||||
onModuleDestroy = Sinon.spy();
|
||||
public field: string;
|
||||
async onModuleDestroy() {
|
||||
this.field = 'b-field';
|
||||
}
|
||||
}
|
||||
|
||||
@Module({
|
||||
@@ -54,10 +57,13 @@ describe('OnModuleDestroy', () => {
|
||||
|
||||
@Injectable()
|
||||
class AA implements OnModuleDestroy {
|
||||
public field: string;
|
||||
constructor(private bb: BB) {}
|
||||
onModuleDestroy = Sinon.spy();
|
||||
}
|
||||
|
||||
async onModuleDestroy() {
|
||||
this.field = this.bb.field + '_a-field';
|
||||
}
|
||||
}
|
||||
@Module({
|
||||
imports: [B],
|
||||
providers: [AA],
|
||||
@@ -72,8 +78,7 @@ describe('OnModuleDestroy', () => {
|
||||
await app.init();
|
||||
await app.close();
|
||||
|
||||
const aa = module.get(AA);
|
||||
const bb = module.get(BB);
|
||||
Sinon.assert.callOrder(aa.onModuleDestroy, bb.onModuleDestroy);
|
||||
const instance = module.get(AA);
|
||||
expect(instance.field).to.equal('b-field_a-field');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -39,39 +39,11 @@ describe('OnModuleInit', () => {
|
||||
});
|
||||
|
||||
it('should sort modules by distance (topological sort) - DESC order', async () => {
|
||||
@Injectable()
|
||||
class CC implements OnModuleInit {
|
||||
public field: string;
|
||||
|
||||
async onModuleInit() {
|
||||
this.field = 'c-field';
|
||||
}
|
||||
}
|
||||
|
||||
@Module({})
|
||||
class C {
|
||||
static forRoot() {
|
||||
return {
|
||||
module: C,
|
||||
global: true,
|
||||
providers: [
|
||||
{
|
||||
provide: CC,
|
||||
useValue: new CC(),
|
||||
},
|
||||
],
|
||||
exports: [CC],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
class BB implements OnModuleInit {
|
||||
public field: string;
|
||||
constructor(private cc: CC) {}
|
||||
|
||||
async onModuleInit() {
|
||||
this.field = this.cc.field + '_b-field';
|
||||
this.field = 'b-field';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,19 +68,14 @@ describe('OnModuleInit', () => {
|
||||
})
|
||||
class A {}
|
||||
|
||||
@Module({
|
||||
imports: [A, C.forRoot()],
|
||||
})
|
||||
class AppModule {}
|
||||
|
||||
const module = await Test.createTestingModule({
|
||||
imports: [AppModule],
|
||||
imports: [A],
|
||||
}).compile();
|
||||
|
||||
const app = module.createNestApplication();
|
||||
await app.init();
|
||||
|
||||
const instance = module.get(AA);
|
||||
expect(instance.field).to.equal('c-field_b-field_a-field');
|
||||
expect(instance.field).to.equal('b-field_a-field');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"noLib": false,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"target": "ES2021",
|
||||
"target": "es6",
|
||||
"sourceMap": true,
|
||||
"allowJs": true,
|
||||
"outDir": "./dist",
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { expect } from 'chai';
|
||||
|
||||
import { Controller, Injectable, Module } from '@nestjs/common';
|
||||
|
||||
class B {}
|
||||
|
||||
@Injectable()
|
||||
class A {
|
||||
constructor(b: B) {}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
class BImpl {
|
||||
constructor(a: A) {}
|
||||
}
|
||||
|
||||
@Controller()
|
||||
class AppController {
|
||||
constructor(a: A) {}
|
||||
}
|
||||
|
||||
@Module({
|
||||
imports: [],
|
||||
controllers: [AppController],
|
||||
providers: [A, { provide: B, useClass: BImpl }],
|
||||
})
|
||||
export class AppModule {}
|
||||
|
||||
describe('Circular custom providers', () => {
|
||||
it('should throw an exception (useClass + regular provider)', async () => {
|
||||
try {
|
||||
const builder = Test.createTestingModule({
|
||||
imports: [AppModule],
|
||||
});
|
||||
await builder.compile();
|
||||
|
||||
expect(true).to.be.eql(false);
|
||||
} catch (err) {
|
||||
expect(err.message).to.be.eql(
|
||||
'A circular dependency has been detected inside "A". Please, make sure that each side of a bidirectional relationships are decorated with "forwardRef()". Note that circular relationships between custom providers (e.g., factories) are not supported since functions cannot be called more than once.',
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it('should throw an exception (2 factories)', async () => {
|
||||
try {
|
||||
const builder = Test.createTestingModule({
|
||||
providers: [
|
||||
{ provide: 'ABC', useFactory: () => ({}), inject: ['DEF'] },
|
||||
{ provide: 'DEF', useFactory: () => ({}), inject: ['ABC'] },
|
||||
],
|
||||
});
|
||||
await builder.compile();
|
||||
|
||||
expect(true).to.be.eql(false);
|
||||
} catch (err) {
|
||||
expect(err.message).to.be.eql(
|
||||
'A circular dependency has been detected inside "ABC". Please, make sure that each side of a bidirectional relationships are decorated with "forwardRef()". Note that circular relationships between custom providers (e.g., factories) are not supported since functions cannot be called more than once.',
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -118,14 +118,14 @@ describe('Optional factory provider deps', () => {
|
||||
} catch (err) {
|
||||
expect(err).to.be.instanceOf(UnknownDependenciesException);
|
||||
expect(err.message).to
|
||||
.equal(`Nest can't resolve dependencies of the POSSIBLY_MISSING_DEP (?). Please make sure that the argument "MISSING_DEP" at index [0] is available in the RootTestModule context.
|
||||
.equal(`Nest can't resolve dependencies of the POSSIBLY_MISSING_DEP (?). Please make sure that the argument MISSING_DEP at index [0] is available in the RootTestModule context.
|
||||
|
||||
Potential solutions:
|
||||
- Is RootTestModule a valid NestJS module?
|
||||
- If "MISSING_DEP" is a provider, is it part of the current RootTestModule?
|
||||
- If "MISSING_DEP" is exported from a separate @Module, is that module imported within RootTestModule?
|
||||
- If MISSING_DEP is a provider, is it part of the current RootTestModule?
|
||||
- If MISSING_DEP is exported from a separate @Module, is that module imported within RootTestModule?
|
||||
@Module({
|
||||
imports: [ /* the Module containing "MISSING_DEP" */ ]
|
||||
imports: [ /* the Module containing MISSING_DEP */ ]
|
||||
})
|
||||
`);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ class ServiceInjectingItself {
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
class ServiceInjectingItselfForward {
|
||||
class ServiceInjectingItselfForwared {
|
||||
constructor(
|
||||
@Inject(forwardRef(() => ServiceInjectingItself))
|
||||
private readonly coreService: ServiceInjectingItself,
|
||||
@@ -24,7 +24,7 @@ class ServiceInjectingItselfViaCustomToken {
|
||||
export class SelfInjectionProviderModule {}
|
||||
|
||||
@Module({
|
||||
providers: [ServiceInjectingItselfForward],
|
||||
providers: [ServiceInjectingItselfForwared],
|
||||
})
|
||||
export class SelfInjectionForwardProviderModule {}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"noLib": false,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"target": "ES2021",
|
||||
"target": "es6",
|
||||
"sourceMap": true,
|
||||
"allowJs": true,
|
||||
"outDir": "./dist",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,10 @@
|
||||
import { ValidationPipe } from '@nestjs/common';
|
||||
import { Injector } from '@nestjs/core/injector/injector';
|
||||
import { SerializedGraph } from '@nestjs/core/inspector/serialized-graph';
|
||||
import { MicroserviceOptions, Transport } from '@nestjs/microservices';
|
||||
import { Transport } from '@nestjs/microservices';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { expect } from 'chai';
|
||||
import { readFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
import * as sinon from 'sinon';
|
||||
import { AppModule } from '../src/app.module';
|
||||
import { HttpExceptionFilter } from '../src/common/filters/http-exception.filter';
|
||||
import { TimeoutInterceptor } from '../src/common/interceptors/timeout.interceptor';
|
||||
@@ -15,8 +13,6 @@ describe('Graph inspector', () => {
|
||||
let testingModule: TestingModule;
|
||||
|
||||
before(async () => {
|
||||
sinon.stub(Injector.prototype as any, 'getNowTimestamp').callsFake(() => 0);
|
||||
|
||||
testingModule = await Test.createTestingModule({
|
||||
imports: [AppModule],
|
||||
}).compile({ snapshot: true });
|
||||
@@ -45,10 +41,7 @@ describe('Graph inspector', () => {
|
||||
app.useGlobalFilters(new HttpExceptionFilter());
|
||||
app.useGlobalInterceptors(new TimeoutInterceptor());
|
||||
app.enableVersioning();
|
||||
app.connectMicroservice<MicroserviceOptions>({
|
||||
transport: Transport.TCP,
|
||||
options: {},
|
||||
});
|
||||
app.connectMicroservice({ transport: Transport.TCP, options: {} });
|
||||
await app.init();
|
||||
|
||||
const graph = testingModule.get(SerializedGraph);
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"noLib": false,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"target": "ES2021",
|
||||
"target": "es6",
|
||||
"sourceMap": true,
|
||||
"allowJs": true,
|
||||
"outDir": "./dist",
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import * as chai from 'chai';
|
||||
import { expect } from 'chai';
|
||||
import chaiAsPromised = require('chai-as-promised');
|
||||
import { AppModule } from '../src/app.module';
|
||||
chai.use(chaiAsPromised);
|
||||
|
||||
describe('Lazy imports', () => {
|
||||
let server;
|
||||
let app: INestApplication;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module = await Test.createTestingModule({
|
||||
imports: [AppModule],
|
||||
}).compile();
|
||||
|
||||
app = module.createNestApplication();
|
||||
server = app.getHttpAdapter().getInstance();
|
||||
});
|
||||
|
||||
it(`should allow imports of global modules`, async () => {
|
||||
await expect(app.init()).to.eventually.be.fulfilled;
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await app.close();
|
||||
});
|
||||
});
|
||||
@@ -1,16 +0,0 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { LazyModuleLoader } from '@nestjs/core';
|
||||
import { EagerModule } from './eager.module';
|
||||
import { GlobalModule } from './global.module';
|
||||
import { LazyModule } from './lazy.module';
|
||||
|
||||
@Module({
|
||||
imports: [GlobalModule, EagerModule],
|
||||
})
|
||||
export class AppModule {
|
||||
constructor(public loader: LazyModuleLoader) {}
|
||||
|
||||
async onApplicationBootstrap() {
|
||||
await this.loader.load(() => LazyModule);
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
import { Module, Injectable } from '@nestjs/common';
|
||||
import { GlobalService } from './global.module';
|
||||
|
||||
@Injectable()
|
||||
export class EagerService {
|
||||
constructor(public globalService: GlobalService) {}
|
||||
}
|
||||
|
||||
@Module({
|
||||
providers: [EagerService],
|
||||
})
|
||||
export class EagerModule {}
|
||||
@@ -1,13 +0,0 @@
|
||||
import { Module, Injectable, Global } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class GlobalService {
|
||||
constructor() {}
|
||||
}
|
||||
|
||||
@Global()
|
||||
@Module({
|
||||
providers: [GlobalService],
|
||||
exports: [GlobalService],
|
||||
})
|
||||
export class GlobalModule {}
|
||||
@@ -1,12 +0,0 @@
|
||||
import { Module, Injectable } from '@nestjs/common';
|
||||
import { GlobalService } from './global.module';
|
||||
|
||||
@Injectable()
|
||||
export class LazyService {
|
||||
constructor(public globalService: GlobalService) {}
|
||||
}
|
||||
|
||||
@Module({
|
||||
providers: [LazyService],
|
||||
})
|
||||
export class LazyModule {}
|
||||
@@ -1,8 +0,0 @@
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import { AppModule } from './app.module';
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create(AppModule);
|
||||
await app.listen(3000);
|
||||
}
|
||||
bootstrap();
|
||||
@@ -1,5 +1,5 @@
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import { MicroserviceOptions, Transport } from '@nestjs/microservices';
|
||||
import { Transport } from '@nestjs/microservices';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import * as request from 'supertest';
|
||||
import { MqttBroadcastController } from '../src/mqtt/mqtt-broadcast.controller';
|
||||
@@ -16,13 +16,13 @@ describe('MQTT transport', () => {
|
||||
app = module.createNestApplication();
|
||||
server = app.getHttpAdapter().getInstance();
|
||||
|
||||
app.connectMicroservice<MicroserviceOptions>({
|
||||
app.connectMicroservice({
|
||||
transport: Transport.MQTT,
|
||||
options: {
|
||||
host: '0.0.0.0',
|
||||
},
|
||||
});
|
||||
app.connectMicroservice<MicroserviceOptions>({
|
||||
app.connectMicroservice({
|
||||
transport: Transport.MQTT,
|
||||
options: {
|
||||
host: '0.0.0.0',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import { MicroserviceOptions, Transport } from '@nestjs/microservices';
|
||||
import { Transport } from '@nestjs/microservices';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import * as request from 'supertest';
|
||||
import { NatsBroadcastController } from '../src/nats/nats-broadcast.controller';
|
||||
@@ -16,13 +16,13 @@ describe('NATS transport', () => {
|
||||
app = module.createNestApplication();
|
||||
server = app.getHttpAdapter().getInstance();
|
||||
|
||||
app.connectMicroservice<MicroserviceOptions>({
|
||||
app.connectMicroservice({
|
||||
transport: Transport.NATS,
|
||||
options: {
|
||||
servers: 'nats://0.0.0.0:4222',
|
||||
},
|
||||
});
|
||||
app.connectMicroservice<MicroserviceOptions>({
|
||||
app.connectMicroservice({
|
||||
transport: Transport.NATS,
|
||||
options: {
|
||||
servers: 'servers://0.0.0.0:4222',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import { MicroserviceOptions, Transport } from '@nestjs/microservices';
|
||||
import { Transport } from '@nestjs/microservices';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import * as request from 'supertest';
|
||||
import { RedisBroadcastController } from '../src/redis/redis-broadcast.controller';
|
||||
@@ -16,18 +16,16 @@ describe('REDIS transport', () => {
|
||||
app = module.createNestApplication();
|
||||
server = app.getHttpAdapter().getInstance();
|
||||
|
||||
app.connectMicroservice<MicroserviceOptions>({
|
||||
app.connectMicroservice({
|
||||
transport: Transport.REDIS,
|
||||
options: {
|
||||
host: '0.0.0.0',
|
||||
port: 6379,
|
||||
url: 'redis://0.0.0.0:6379',
|
||||
},
|
||||
});
|
||||
app.connectMicroservice<MicroserviceOptions>({
|
||||
app.connectMicroservice({
|
||||
transport: Transport.REDIS,
|
||||
options: {
|
||||
host: '0.0.0.0',
|
||||
port: 6379,
|
||||
url: 'redis://0.0.0.0:6379',
|
||||
},
|
||||
});
|
||||
await app.startAllMicroservices();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { INestApplication, Logger } from '@nestjs/common';
|
||||
import { MicroserviceOptions, Transport } from '@nestjs/microservices';
|
||||
import { Transport } from '@nestjs/microservices';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { Admin, ITopicMetadata, Kafka } from 'kafkajs';
|
||||
import * as request from 'supertest';
|
||||
@@ -37,7 +37,7 @@ describe.skip('Kafka concurrent', function () {
|
||||
|
||||
const server = app.getHttpAdapter().getInstance();
|
||||
|
||||
app.connectMicroservice<MicroserviceOptions>({
|
||||
app.connectMicroservice({
|
||||
transport: Transport.KAFKA,
|
||||
options: {
|
||||
client: {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import { MicroserviceOptions, Transport } from '@nestjs/microservices';
|
||||
import { Transport } from '@nestjs/microservices';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import * as request from 'supertest';
|
||||
import { MqttController } from '../src/mqtt/mqtt.controller';
|
||||
@@ -16,7 +16,7 @@ describe('MQTT transport', () => {
|
||||
app = module.createNestApplication();
|
||||
server = app.getHttpAdapter().getInstance();
|
||||
|
||||
app.connectMicroservice<MicroserviceOptions>({
|
||||
app.connectMicroservice({
|
||||
transport: Transport.MQTT,
|
||||
options: {
|
||||
url: 'mqtt://0.0.0.0:1883',
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as GRPC from '@grpc/grpc-js';
|
||||
import * as ProtoLoader from '@grpc/proto-loader';
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import { MicroserviceOptions, Transport } from '@nestjs/microservices';
|
||||
import { Transport } from '@nestjs/microservices';
|
||||
import { ExpressAdapter } from '@nestjs/platform-express';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { fail } from 'assert';
|
||||
@@ -26,7 +26,7 @@ describe('Advanced GRPC transport', () => {
|
||||
/*
|
||||
* Create microservice configuration
|
||||
*/
|
||||
app.connectMicroservice<MicroserviceOptions>({
|
||||
app.connectMicroservice({
|
||||
transport: Transport.GRPC,
|
||||
options: {
|
||||
url: 'localhost:5001',
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
import * as GRPC from '@grpc/grpc-js';
|
||||
import * as ProtoLoader from '@grpc/proto-loader';
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import { MicroserviceOptions, Transport } from '@nestjs/microservices';
|
||||
import { Transport } from '@nestjs/microservices';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { fail } from 'assert';
|
||||
import { expect, use } from 'chai';
|
||||
import * as chaiAsPromised from 'chai-as-promised';
|
||||
import { expect } from 'chai';
|
||||
import { join } from 'path';
|
||||
import * as sinon from 'sinon';
|
||||
import * as request from 'supertest';
|
||||
import { GrpcController } from '../src/grpc/grpc.controller';
|
||||
|
||||
use(chaiAsPromised);
|
||||
|
||||
describe('GRPC transport', () => {
|
||||
let server;
|
||||
let app: INestApplication;
|
||||
@@ -26,7 +22,7 @@ describe('GRPC transport', () => {
|
||||
app = module.createNestApplication();
|
||||
server = app.getHttpAdapter().getInstance();
|
||||
|
||||
app.connectMicroservice<MicroserviceOptions>({
|
||||
app.connectMicroservice({
|
||||
transport: Transport.GRPC,
|
||||
options: {
|
||||
package: ['math', 'math2'],
|
||||
@@ -36,7 +32,6 @@ describe('GRPC transport', () => {
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
// Start gRPC microservice
|
||||
await app.startAllMicroservices();
|
||||
await app.init();
|
||||
@@ -133,71 +128,6 @@ describe('GRPC transport', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it(`GRPC with backpressure control`, async function () {
|
||||
// This test hit the gRPC server with 1000 messages, but the server
|
||||
// has to process large (> 1MB) messages, so it will definitely hit
|
||||
// issues where writing to the stream needs to be paused until a drain
|
||||
// event. Prior to this test, a bug existed where the server would
|
||||
// send the incorrect number of messages due to improper backpressure
|
||||
// handling that wrote messages more than once.
|
||||
this.timeout(10000);
|
||||
|
||||
const largeMessages = client.streamLargeMessages();
|
||||
// [0, 1, 2, ..., 999]
|
||||
const expectedIds = Array.from({ length: 1000 }, (_, n) => n);
|
||||
const receivedIds: number[] = [];
|
||||
|
||||
await largeMessages.forEach(msg => {
|
||||
receivedIds.push(msg.id);
|
||||
});
|
||||
|
||||
expect(receivedIds).to.deep.equal(expectedIds);
|
||||
});
|
||||
|
||||
describe('streaming calls that error', () => {
|
||||
// We want to assert that the application does not crash when an error is encountered with an unhandledRejection
|
||||
// the best way to do that is to listen for the unhandledRejection event and fail the test if it is called
|
||||
let processSpy: sinon.SinonSpy;
|
||||
|
||||
beforeEach(() => {
|
||||
processSpy = sinon.spy();
|
||||
process.on('unhandledRejection', processSpy);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
process.off('unhandledRejection', processSpy);
|
||||
});
|
||||
|
||||
it('should not crash when replying with an error', async () => {
|
||||
const call = new Promise<void>((resolve, reject) => {
|
||||
const stream = client.streamDivide({
|
||||
data: [{ dividend: 1, divisor: 0 }],
|
||||
});
|
||||
|
||||
stream.on('data', () => {
|
||||
fail('Stream should not have emitted any data');
|
||||
});
|
||||
|
||||
stream.on('error', err => {
|
||||
if (err.code !== GRPC.status.CANCELLED) {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
|
||||
stream.on('end', () => {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
await expect(call).to.eventually.be.rejectedWith(
|
||||
'3 INVALID_ARGUMENT: dividing by 0 is not possible',
|
||||
);
|
||||
|
||||
// if this fails the application has crashed
|
||||
expect(processSpy.called).to.be.false;
|
||||
});
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await app.close();
|
||||
});
|
||||
@@ -1,5 +1,5 @@
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import { MicroserviceOptions, Transport } from '@nestjs/microservices';
|
||||
import { Transport } from '@nestjs/microservices';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { expect } from 'chai';
|
||||
import * as request from 'supertest';
|
||||
@@ -29,7 +29,7 @@ describe.skip('Kafka transport', function () {
|
||||
app = module.createNestApplication();
|
||||
server = app.getHttpAdapter().getInstance();
|
||||
|
||||
app.connectMicroservice<MicroserviceOptions>({
|
||||
app.connectMicroservice({
|
||||
transport: Transport.KAFKA,
|
||||
options: {
|
||||
client: {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import { MicroserviceOptions, Transport } from '@nestjs/microservices';
|
||||
import { Transport } from '@nestjs/microservices';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { expect } from 'chai';
|
||||
import * as request from 'supertest';
|
||||
@@ -17,7 +17,7 @@ describe('MQTT transport', () => {
|
||||
app = module.createNestApplication();
|
||||
server = app.getHttpAdapter().getInstance();
|
||||
|
||||
app.connectMicroservice<MicroserviceOptions>({
|
||||
app.connectMicroservice({
|
||||
transport: Transport.MQTT,
|
||||
options: {
|
||||
url: 'mqtt://0.0.0.0:1883',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import { MicroserviceOptions, Transport } from '@nestjs/microservices';
|
||||
import { Transport } from '@nestjs/microservices';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { expect } from 'chai';
|
||||
import * as request from 'supertest';
|
||||
@@ -19,7 +19,7 @@ describe('NATS transport', () => {
|
||||
app = module.createNestApplication();
|
||||
server = app.getHttpAdapter().getInstance();
|
||||
|
||||
app.connectMicroservice<MicroserviceOptions>({
|
||||
app.connectMicroservice({
|
||||
transport: Transport.NATS,
|
||||
options: {
|
||||
servers: 'nats://0.0.0.0:4222',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import { MicroserviceOptions, Transport } from '@nestjs/microservices';
|
||||
import { Transport } from '@nestjs/microservices';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { expect } from 'chai';
|
||||
import * as request from 'supertest';
|
||||
@@ -17,11 +17,10 @@ describe('REDIS transport', () => {
|
||||
app = module.createNestApplication();
|
||||
server = app.getHttpAdapter().getInstance();
|
||||
|
||||
app.connectMicroservice<MicroserviceOptions>({
|
||||
app.connectMicroservice({
|
||||
transport: Transport.REDIS,
|
||||
options: {
|
||||
host: '0.0.0.0',
|
||||
port: 6379,
|
||||
url: 'redis://0.0.0.0:6379',
|
||||
},
|
||||
});
|
||||
await app.startAllMicroservices();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import { MicroserviceOptions, Transport } from '@nestjs/microservices';
|
||||
import { Transport } from '@nestjs/microservices';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { expect } from 'chai';
|
||||
import * as request from 'supertest';
|
||||
@@ -17,7 +17,7 @@ describe('RabbitMQ transport', () => {
|
||||
app = module.createNestApplication();
|
||||
server = app.getHttpAdapter().getInstance();
|
||||
|
||||
app.connectMicroservice<MicroserviceOptions>({
|
||||
app.connectMicroservice({
|
||||
transport: Transport.RMQ,
|
||||
options: {
|
||||
urls: [`amqp://0.0.0.0:5672`],
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
import {
|
||||
Controller,
|
||||
INestMicroservice,
|
||||
Injectable,
|
||||
Module,
|
||||
} from '@nestjs/common';
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import {
|
||||
AsyncOptions,
|
||||
ClientTCP,
|
||||
ClientsModule,
|
||||
MessagePattern,
|
||||
MicroserviceOptions,
|
||||
Payload,
|
||||
TcpOptions,
|
||||
Transport,
|
||||
} from '@nestjs/microservices';
|
||||
import { expect } from 'chai';
|
||||
|
||||
let port: number;
|
||||
|
||||
do {
|
||||
port = Math.round(Math.random() * 10000);
|
||||
} while (port < 1000);
|
||||
|
||||
@Injectable()
|
||||
class RpcOptionsProvider {
|
||||
getOptions(): TcpOptions {
|
||||
return {
|
||||
transport: Transport.TCP,
|
||||
options: {
|
||||
port,
|
||||
host: '0.0.0.0',
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Controller()
|
||||
class RpcController {
|
||||
@MessagePattern({ cmd: 'sum' })
|
||||
sumPayload(@Payload() payload: number[]) {
|
||||
return payload.reduce((a, b) => a + b, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
ClientsModule.register([
|
||||
{
|
||||
name: 'RPC_CLIENT',
|
||||
transport: Transport.TCP,
|
||||
options: {
|
||||
port,
|
||||
host: '0.0.0.0',
|
||||
},
|
||||
},
|
||||
]),
|
||||
],
|
||||
controllers: [RpcController],
|
||||
providers: [RpcOptionsProvider],
|
||||
})
|
||||
class RpcModule {}
|
||||
|
||||
describe('RPC Async transport', () => {
|
||||
let app: INestMicroservice;
|
||||
let client: ClientTCP;
|
||||
|
||||
beforeEach(async () => {
|
||||
app = await NestFactory.createMicroservice<
|
||||
AsyncOptions<MicroserviceOptions>
|
||||
>(RpcModule, {
|
||||
logger: false,
|
||||
inject: [RpcOptionsProvider],
|
||||
useFactory: (optionsProvider: RpcOptionsProvider) =>
|
||||
optionsProvider.getOptions(),
|
||||
});
|
||||
|
||||
await app.listen();
|
||||
client = app.get('RPC_CLIENT', { strict: false });
|
||||
});
|
||||
|
||||
it(`/POST`, done => {
|
||||
let retData = 0;
|
||||
client.send({ cmd: 'sum' }, [1, 2, 3, 4, 5]).subscribe({
|
||||
next: val => (retData += val),
|
||||
error: done,
|
||||
complete: () => {
|
||||
expect(retData).to.eq(15);
|
||||
done();
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await app.close();
|
||||
});
|
||||
});
|
||||
@@ -1,142 +0,0 @@
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import { Transport } from '@nestjs/microservices';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { expect } from 'chai';
|
||||
import * as request from 'supertest';
|
||||
import { AppController } from '../src/tcp-tls/app.controller';
|
||||
import { ApplicationModule } from '../src/tcp-tls/app.module';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
describe('RPC TLS transport', () => {
|
||||
let server;
|
||||
let app: INestApplication;
|
||||
let key: string;
|
||||
let cert: string;
|
||||
|
||||
before(() => {
|
||||
// Generate a self-signed key pair
|
||||
key = fs
|
||||
.readFileSync(path.join(__dirname, '../src/tcp-tls/privkey.pem'), 'utf8')
|
||||
.toString();
|
||||
cert = fs
|
||||
.readFileSync(path.join(__dirname, '../src/tcp-tls/ca.cert.pem'), 'utf8')
|
||||
.toString();
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
const module = await Test.createTestingModule({
|
||||
imports: [ApplicationModule],
|
||||
}).compile();
|
||||
|
||||
app = module.createNestApplication();
|
||||
server = app.getHttpAdapter().getInstance();
|
||||
|
||||
app.connectMicroservice({
|
||||
transport: Transport.TCP,
|
||||
options: {
|
||||
host: '0.0.0.0',
|
||||
tlsOptions: { key: key, cert: cert },
|
||||
},
|
||||
});
|
||||
await app.startAllMicroservices();
|
||||
await app.init();
|
||||
});
|
||||
|
||||
it(`/POST TLS`, () => {
|
||||
return request(server)
|
||||
.post('/?command=sum')
|
||||
.send([1, 2, 3, 4, 5])
|
||||
.expect(200, '15');
|
||||
});
|
||||
|
||||
it(`/POST (Promise/async)`, () => {
|
||||
return request(server)
|
||||
.post('/?command=asyncSum')
|
||||
.send([1, 2, 3, 4, 5])
|
||||
.expect(200)
|
||||
.expect(200, '15');
|
||||
});
|
||||
|
||||
it(`/POST (Observable stream)`, () => {
|
||||
return request(server)
|
||||
.post('/?command=streamSum')
|
||||
.send([1, 2, 3, 4, 5])
|
||||
.expect(200, '15');
|
||||
});
|
||||
|
||||
it(`/POST (useFactory client)`, () => {
|
||||
return request(server)
|
||||
.post('/useFactory?command=sum')
|
||||
.send([1, 2, 3, 4, 5])
|
||||
.expect(200, '15');
|
||||
});
|
||||
|
||||
it(`/POST (useClass client)`, () => {
|
||||
return request(server)
|
||||
.post('/useClass?command=sum')
|
||||
.send([1, 2, 3, 4, 5])
|
||||
.expect(200, '15');
|
||||
});
|
||||
|
||||
it(`/POST (concurrent)`, () => {
|
||||
return request(server)
|
||||
.post('/concurrent')
|
||||
.send([
|
||||
Array.from({ length: 10 }, (v, k) => k + 1),
|
||||
Array.from({ length: 10 }, (v, k) => k + 11),
|
||||
Array.from({ length: 10 }, (v, k) => k + 21),
|
||||
Array.from({ length: 10 }, (v, k) => k + 31),
|
||||
Array.from({ length: 10 }, (v, k) => k + 41),
|
||||
Array.from({ length: 10 }, (v, k) => k + 51),
|
||||
Array.from({ length: 10 }, (v, k) => k + 61),
|
||||
Array.from({ length: 10 }, (v, k) => k + 71),
|
||||
Array.from({ length: 10 }, (v, k) => k + 81),
|
||||
Array.from({ length: 10 }, (v, k) => k + 91),
|
||||
])
|
||||
.expect(200, 'true');
|
||||
});
|
||||
|
||||
it(`/POST (streaming)`, () => {
|
||||
return request(server)
|
||||
.post('/stream')
|
||||
.send([1, 2, 3, 4, 5])
|
||||
.expect(200, '15');
|
||||
});
|
||||
|
||||
it(`/POST (pattern not found)`, () => {
|
||||
return request(server).post('/?command=test').expect(500);
|
||||
});
|
||||
|
||||
it(`/POST (event notification)`, done => {
|
||||
request(server)
|
||||
.post('/notify')
|
||||
.send([1, 2, 3, 4, 5])
|
||||
.end(() => {
|
||||
setTimeout(() => {
|
||||
expect(AppController.IS_NOTIFIED).to.be.true;
|
||||
done();
|
||||
}, 1000);
|
||||
});
|
||||
});
|
||||
|
||||
it('/POST (custom client)', () => {
|
||||
return request(server)
|
||||
.post('/error?client=custom')
|
||||
.send({})
|
||||
.expect(200)
|
||||
.expect('true');
|
||||
});
|
||||
|
||||
it('/POST (standard client)', () => {
|
||||
return request(server)
|
||||
.post('/error?client=standard')
|
||||
.send({})
|
||||
.expect(200)
|
||||
.expect('false');
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await app.close();
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,5 @@
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import { MicroserviceOptions, Transport } from '@nestjs/microservices';
|
||||
import { Transport } from '@nestjs/microservices';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { expect } from 'chai';
|
||||
import * as request from 'supertest';
|
||||
@@ -18,7 +18,7 @@ describe('RPC transport', () => {
|
||||
app = module.createNestApplication();
|
||||
server = app.getHttpAdapter().getInstance();
|
||||
|
||||
app.connectMicroservice<MicroserviceOptions>({
|
||||
app.connectMicroservice({
|
||||
transport: Transport.TCP,
|
||||
options: {
|
||||
host: '0.0.0.0',
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
RpcException,
|
||||
} from '@nestjs/microservices';
|
||||
import { join } from 'path';
|
||||
import { Observable, of, catchError, from, mergeMap } from 'rxjs';
|
||||
import { Observable, of, catchError } from 'rxjs';
|
||||
|
||||
class ErrorHandlingProxy extends ClientGrpcProxy {
|
||||
serializeError(err) {
|
||||
@@ -107,17 +107,6 @@ export class GrpcController {
|
||||
};
|
||||
}
|
||||
|
||||
// contrived example meant to show when an error is encountered, like dividing by zero, the
|
||||
// application does not crash and the error is returned appropriately to the client
|
||||
@GrpcMethod('Math', 'StreamDivide')
|
||||
streamDivide({
|
||||
data,
|
||||
}: {
|
||||
data: { dividend: number; divisor: number }[];
|
||||
}): Observable<any> {
|
||||
return from(data).pipe(mergeMap(request => this.divide(request)));
|
||||
}
|
||||
|
||||
@GrpcMethod('Math2')
|
||||
async sum2({ data }: { data: number[] }): Promise<any> {
|
||||
return of({
|
||||
@@ -139,27 +128,6 @@ export class GrpcController {
|
||||
return svc.sum2({ data });
|
||||
}
|
||||
|
||||
@GrpcMethod('Math')
|
||||
streamLargeMessages(_req: unknown, _meta: unknown) {
|
||||
// Send 1000 messages of >1MB each relatively fast
|
||||
// This should be enough to trigger backpressure issues
|
||||
// while writing to the socket.
|
||||
return new Observable(subscriber => {
|
||||
let n = 0;
|
||||
const interval = setInterval(() => {
|
||||
// We'll be checking the ids. The `data` is just to make the
|
||||
// message large enough to trigger backpressure issues.
|
||||
subscriber.next({ id: n++, data: 'a'.repeat(1024 * 1024) });
|
||||
if (n === 1000) {
|
||||
subscriber.complete();
|
||||
}
|
||||
}, 0);
|
||||
return () => {
|
||||
clearInterval(interval);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@Post('error')
|
||||
@HttpCode(200)
|
||||
serializeError(
|
||||
|
||||
@@ -7,18 +7,8 @@ service Math {
|
||||
rpc SumStream(stream RequestSum) returns(stream SumResult);
|
||||
rpc SumStreamPass(stream RequestSum) returns(stream SumResult);
|
||||
rpc Divide (RequestDivide) returns (DivideResult);
|
||||
rpc StreamLargeMessages(Empty) returns (stream BackpressureData);
|
||||
/* Given a series of dividend and divisor, stream back the division results for each */
|
||||
rpc StreamDivide (StreamDivideRequest) returns (stream StreamDivideResponse);
|
||||
}
|
||||
|
||||
message BackpressureData {
|
||||
int32 id = 1;
|
||||
string data = 2;
|
||||
}
|
||||
|
||||
message Empty {}
|
||||
|
||||
message SumResult {
|
||||
int32 result = 1;
|
||||
}
|
||||
@@ -35,11 +25,3 @@ message RequestDivide {
|
||||
message DivideResult {
|
||||
int32 result = 1;
|
||||
}
|
||||
|
||||
message StreamDivideRequest {
|
||||
repeated RequestDivide data = 1;
|
||||
}
|
||||
|
||||
message StreamDivideResponse {
|
||||
DivideResult data = 1;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import { Observable } from 'rxjs';
|
||||
import { SumDto } from './dto/sum.dto';
|
||||
|
||||
/**
|
||||
* The following function explicitly sends messages to the key representing the partition.
|
||||
* The following function explicity sends messages to the key representing the partition.
|
||||
*/
|
||||
const explicitPartitioner = () => {
|
||||
return ({ message }: PartitionerArgs) => {
|
||||
|
||||
@@ -1,141 +0,0 @@
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
HttpCode,
|
||||
Inject,
|
||||
Post,
|
||||
Query,
|
||||
} from '@nestjs/common';
|
||||
import {
|
||||
Client,
|
||||
ClientProxy,
|
||||
EventPattern,
|
||||
MessagePattern,
|
||||
RpcException,
|
||||
Transport,
|
||||
} from '@nestjs/microservices';
|
||||
import { from, lastValueFrom, Observable, of, throwError } from 'rxjs';
|
||||
import { catchError, scan } from 'rxjs/operators';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
@Controller()
|
||||
export class AppController {
|
||||
constructor(
|
||||
@Inject('USE_CLASS_CLIENT') private useClassClient: ClientProxy,
|
||||
@Inject('USE_FACTORY_CLIENT') private useFactoryClient: ClientProxy,
|
||||
@Inject('CUSTOM_PROXY_CLIENT') private customClient: ClientProxy,
|
||||
) {}
|
||||
static IS_NOTIFIED = false;
|
||||
|
||||
@Client({
|
||||
transport: Transport.TCP,
|
||||
options: {
|
||||
tlsOptions: {
|
||||
ca: [
|
||||
fs
|
||||
.readFileSync(path.join(__dirname, 'ca.cert.pem'), 'utf-8')
|
||||
.toString(),
|
||||
],
|
||||
},
|
||||
},
|
||||
})
|
||||
client: ClientProxy;
|
||||
|
||||
@Post()
|
||||
@HttpCode(200)
|
||||
call(@Query('command') cmd, @Body() data: number[]): Observable<number> {
|
||||
return this.client.send<number>({ cmd }, data);
|
||||
}
|
||||
|
||||
@Post('useFactory')
|
||||
@HttpCode(200)
|
||||
callWithClientUseFactory(
|
||||
@Query('command') cmd,
|
||||
@Body() data: number[],
|
||||
): Observable<number> {
|
||||
return this.useFactoryClient.send<number>({ cmd }, data);
|
||||
}
|
||||
|
||||
@Post('useClass')
|
||||
@HttpCode(200)
|
||||
callWithClientUseClass(
|
||||
@Query('command') cmd,
|
||||
@Body() data: number[],
|
||||
): Observable<number> {
|
||||
return this.useClassClient.send<number>({ cmd }, data);
|
||||
}
|
||||
|
||||
@Post('stream')
|
||||
@HttpCode(200)
|
||||
stream(@Body() data: number[]): Observable<number> {
|
||||
return this.client
|
||||
.send<number>({ cmd: 'streaming' }, data)
|
||||
.pipe(scan((a, b) => a + b));
|
||||
}
|
||||
|
||||
@Post('concurrent')
|
||||
@HttpCode(200)
|
||||
concurrent(@Body() data: number[][]): Promise<boolean> {
|
||||
const send = async (tab: number[]) => {
|
||||
const expected = tab.reduce((a, b) => a + b);
|
||||
const result = await lastValueFrom(
|
||||
this.client.send<number>({ cmd: 'sum' }, tab),
|
||||
);
|
||||
|
||||
return result === expected;
|
||||
};
|
||||
return data
|
||||
.map(async tab => send(tab))
|
||||
.reduce(async (a, b) => (await a) && b);
|
||||
}
|
||||
|
||||
@Post('error')
|
||||
@HttpCode(200)
|
||||
serializeError(
|
||||
@Query('client') query: 'custom' | 'standard' = 'standard',
|
||||
@Body() body: Record<string, any>,
|
||||
): Observable<boolean> {
|
||||
const client = query === 'custom' ? this.customClient : this.client;
|
||||
return client.send({ cmd: 'err' }, {}).pipe(
|
||||
catchError(err => {
|
||||
return of(err instanceof RpcException);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@MessagePattern({ cmd: 'sum' })
|
||||
sum(data: number[]): number {
|
||||
return (data || []).reduce((a, b) => a + b);
|
||||
}
|
||||
|
||||
@MessagePattern({ cmd: 'asyncSum' })
|
||||
async asyncSum(data: number[]): Promise<number> {
|
||||
return (data || []).reduce((a, b) => a + b);
|
||||
}
|
||||
|
||||
@MessagePattern({ cmd: 'streamSum' })
|
||||
streamSum(data: number[]): Observable<number> {
|
||||
return of((data || []).reduce((a, b) => a + b));
|
||||
}
|
||||
|
||||
@MessagePattern({ cmd: 'streaming' })
|
||||
streaming(data: number[]): Observable<number> {
|
||||
return from(data);
|
||||
}
|
||||
|
||||
@MessagePattern({ cmd: 'err' })
|
||||
throwAnError() {
|
||||
return throwError(() => new Error('err'));
|
||||
}
|
||||
|
||||
@Post('notify')
|
||||
async sendNotification(): Promise<any> {
|
||||
return this.client.emit<number>('notification', true);
|
||||
}
|
||||
|
||||
@EventPattern('notification')
|
||||
eventHandler(data: boolean) {
|
||||
AppController.IS_NOTIFIED = data;
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
import { Injectable, Module } from '@nestjs/common';
|
||||
import {
|
||||
ClientOptions,
|
||||
ClientsModule,
|
||||
ClientsModuleOptionsFactory,
|
||||
ClientTCP,
|
||||
RpcException,
|
||||
Transport,
|
||||
} from '@nestjs/microservices';
|
||||
import { AppController } from './app.controller';
|
||||
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
const caCert = fs.readFileSync(path.join(__dirname, 'ca.cert.pem')).toString();
|
||||
|
||||
class ErrorHandlingProxy extends ClientTCP {
|
||||
constructor() {
|
||||
super({
|
||||
tlsOptions: { ca: caCert },
|
||||
});
|
||||
}
|
||||
|
||||
serializeError(err) {
|
||||
return new RpcException(err);
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
class ConfigService {
|
||||
private readonly config = {
|
||||
transport: Transport.TCP,
|
||||
};
|
||||
get(key: string, defaultValue?: any) {
|
||||
return this.config[key] || defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
@Module({
|
||||
providers: [ConfigService],
|
||||
exports: [ConfigService],
|
||||
})
|
||||
class ConfigModule {}
|
||||
|
||||
@Injectable()
|
||||
class ClientOptionService implements ClientsModuleOptionsFactory {
|
||||
constructor(private readonly configService: ConfigService) {}
|
||||
createClientOptions(): Promise<ClientOptions> | ClientOptions {
|
||||
return {
|
||||
transport: this.configService.get('transport'),
|
||||
options: {
|
||||
tlsOptions: { ca: caCert },
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
ClientsModule.registerAsync([
|
||||
{
|
||||
imports: [ConfigModule],
|
||||
name: 'USE_FACTORY_CLIENT',
|
||||
useFactory: (configService: ConfigService) => ({
|
||||
transport: configService.get('transport'),
|
||||
options: {
|
||||
tlsOptions: { ca: caCert },
|
||||
},
|
||||
}),
|
||||
inject: [ConfigService],
|
||||
},
|
||||
{
|
||||
imports: [ConfigModule],
|
||||
name: 'USE_CLASS_CLIENT',
|
||||
useClass: ClientOptionService,
|
||||
inject: [ConfigService],
|
||||
},
|
||||
{
|
||||
imports: [ConfigModule],
|
||||
inject: [ConfigService],
|
||||
name: 'CUSTOM_PROXY_CLIENT',
|
||||
useFactory: (config: ConfigService) => ({
|
||||
customClass: ErrorHandlingProxy,
|
||||
}),
|
||||
},
|
||||
]),
|
||||
],
|
||||
controllers: [AppController],
|
||||
})
|
||||
export class ApplicationModule {}
|
||||
@@ -1,17 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICpDCCAYwCCQCyP27z3r0PFjANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAls
|
||||
b2NhbGhvc3QwHhcNMjIxMjAyMDQ0NTQ1WhcNMzIxMTI5MDQ0NTQ1WjAUMRIwEAYD
|
||||
VQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ
|
||||
1IdZZXqrwXql4AIOJnlfpoGKOKoIalnK7KaKHTsq1QOF8z2abFuNBVIIrO0etQ/0
|
||||
PPAaFGkXl6HHBuA5PrFpsw3V1wSnNs1Cns9NhvypHI2V71lkwBJrEaSicNWL2AOE
|
||||
QkQ9cZ4YsTGd0BrM8D5VvgXdrC7gOXfj7Hx3E4K+wFO/Gi4AUXl5CXxleSFcW4U+
|
||||
jFulfq/DE8rBZXs29IsGeVkkgUoICjQ4Ey4zE6EY7f3SPKgU8gfgzYyGSd/ZZ/E7
|
||||
6M2yakEUX448Nl4BeuNWroBHVm1pSiMo+Cm1g34pJScPrx1yw6qquziCc/2n1M6O
|
||||
B4WGIZAmJDWnAOEjjrxFAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAABGByZZUjaq
|
||||
ZygICSH2qUGHPPIyrfaCe0qM7de6kYfxxPYQQZb0HDynzv780Lq1002XeT02fNR+
|
||||
5sBCVFuKvS8BNvTq6kHzO1FiWIk/E5fQcYNToYSeEcXgWFLhJMty7+R6sIc9y8PH
|
||||
2YNehf78Jjm9ukM52sLc4+JWl7AEeqPrOHZdh/ve8M2gTfimFKTrW5cEAVPIOPhp
|
||||
2t5BdDKt8ZxgrGC7iRxga+v80VUOHRGfrd3hf3NlDQZO8upVGY8DdJhPRDB72+R0
|
||||
kzJ7eyQwlGXM20atiFxPk43h0f273MneIJG8NgGiVU0ND4XnZkAB3KSAu7pB+nEw
|
||||
QRYMYDgo/8Q=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,28 +0,0 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDZ1IdZZXqrwXql
|
||||
4AIOJnlfpoGKOKoIalnK7KaKHTsq1QOF8z2abFuNBVIIrO0etQ/0PPAaFGkXl6HH
|
||||
BuA5PrFpsw3V1wSnNs1Cns9NhvypHI2V71lkwBJrEaSicNWL2AOEQkQ9cZ4YsTGd
|
||||
0BrM8D5VvgXdrC7gOXfj7Hx3E4K+wFO/Gi4AUXl5CXxleSFcW4U+jFulfq/DE8rB
|
||||
ZXs29IsGeVkkgUoICjQ4Ey4zE6EY7f3SPKgU8gfgzYyGSd/ZZ/E76M2yakEUX448
|
||||
Nl4BeuNWroBHVm1pSiMo+Cm1g34pJScPrx1yw6qquziCc/2n1M6OB4WGIZAmJDWn
|
||||
AOEjjrxFAgMBAAECggEANUKZtWnyjHxKGLSkzADsPE7h7YHdUSFvwwYJ0ktDZD2h
|
||||
FudacJ994wUiAa0GbTOoKvebXUUQTQxuKdOsj1Kc3lNBVr+0C46CsX9TAIm4zUCF
|
||||
/dr/6HpuBm/R6UXdcMvoUDZDqSJWnYL1trhjVSiIlT5ZANJQw9JJVhlEdXj3xtuc
|
||||
I9aC+33f9hKO1wzei/mTjIRGyRIeKselZPpA7qJnE4s3hmZxnO/rSqyPIvh1XLfZ
|
||||
3Eoyyg+xNpTZ8JqlHB5d7hDSnj8cjboa7IYpHJDXN3r8Aui+R9e/sQkezHbF7fR0
|
||||
xHpBVYQvGMuqSnTBkdJfq4qPAR1K49UrpEXB2GHaIQKBgQDs3t/ZUA138AiPIeLd
|
||||
aTsEPhf5dWEZynfNvXZ0VcoSr8ckaiaq9OEllprAriYWj+XphTDsBUAh/R7KlOR4
|
||||
eb+m6OwH7LseGiLIEr54GGP0LzVXAkfH2/uR1cak8qAmHB00jNEg7sj0eVAsHO3f
|
||||
WQm67f+RNP/IgAa+V8JKIkgTwwKBgQDrbAH8eAQsq9rjpxcic1EUI7uFHzr+cKf/
|
||||
4Y8ThLUNAzNfAbQWRBYjS1R8GM79Wiuh+WT1ooHKLryuLF7LVukvKHJ5GiNFBmaO
|
||||
llf72Zf1y4tBE2RCXQbf6h8+ohSDC/hwYy+w20/i2KzSBKkS0+gQuAX/HzfTpRd3
|
||||
q3/uEniXVwKBgDNnElDIbIPQlSrqgZ7mzSXYi79Y15+PLnx5VxFb5KQ1fRPL7WRA
|
||||
C/PqQN77a8yNoakRfFJbuVUm5t2zffkfApYoCcCWgOzBYzbjym2pbVd6PysIlacr
|
||||
d+Zn69mzxUk/5J6YyHFLIFTdVqacCIrleZUVPNa4F6HdFpmL1d/cnKOdAoGAMDuB
|
||||
sKsaF9jh0LBkEf/URa8IdT6vxH9qPAeHW7VdrpvQQ4/CyKkMbBC772zZw5hcxiOl
|
||||
Zpnzw2uN5pVamohk3++GfH85aKPmESKGRigPdSFNl3iUmvAaP3flDN0CHNMwBD6d
|
||||
/7r/A/fmeGTSCvR1YC+DswA/XNI/G5p8bFdGc6MCgYBd9oQiZlkYMiDGPUAjx+DO
|
||||
kqtAmc8DLJEanSbWdIxL2bGL04cgBRPssM4m0UScx4PucvqWEPdN/5Ug0z5TrD77
|
||||
2K5nZSBUdy4DunBImz1NHRQEiytkrYX0LesGr02QlzIH4wmwb1TFu7rLkr6KfNuV
|
||||
xqWi+JVY8N4vuHAxCeEALw==
|
||||
-----END PRIVATE KEY-----
|
||||
@@ -7,7 +7,7 @@
|
||||
"noLib": false,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"target": "ES2021",
|
||||
"target": "es6",
|
||||
"sourceMap": true,
|
||||
"allowJs": true,
|
||||
"outDir": "./dist",
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"noLib": false,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"target": "ES2021",
|
||||
"target": "es6",
|
||||
"sourceMap": true,
|
||||
"allowJs": true,
|
||||
"outDir": "./dist",
|
||||
|
||||
@@ -4,7 +4,9 @@ import { CatsModule } from './cats/cats.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
MongooseModule.forRoot('mongodb://localhost:27017/test'),
|
||||
MongooseModule.forRoot('mongodb://localhost:27017/test', {
|
||||
useNewUrlParser: true,
|
||||
}),
|
||||
CatsModule,
|
||||
],
|
||||
})
|
||||
|
||||
@@ -10,6 +10,7 @@ class ConfigService implements MongooseOptionsFactory {
|
||||
createMongooseOptions(): MongooseModuleOptions {
|
||||
return {
|
||||
uri: 'mongodb://localhost:27017/test',
|
||||
useNewUrlParser: true,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ class ConfigService implements MongooseOptionsFactory {
|
||||
createMongooseOptions(): MongooseModuleOptions {
|
||||
return {
|
||||
uri: 'mongodb://localhost:27017/test',
|
||||
useNewUrlParser: true,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import { CatsModule } from './cats/cats.module';
|
||||
imports: [
|
||||
MongooseModule.forRootAsync({
|
||||
useFactory: () => ({
|
||||
useNewUrlParser: true,
|
||||
uri: 'mongodb://localhost:27017/test',
|
||||
}),
|
||||
}),
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user