Compare commits

..

2 Commits

Author SHA1 Message Date
Kamil Myśliwiec
d7250e42e5 tests() exclude async hooks 2018-12-29 12:45:42 +01:00
Kamil Myśliwiec
6a084a36b6 feature() add async_hooks module (async storage) 2018-12-29 10:59:57 +01:00
2000 changed files with 135561 additions and 711144 deletions

View File

@@ -1,225 +0,0 @@
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'
aliases:
- &restore-cache
restore_cache:
key: dependency-cache-{{ checksum "package.json" }}
- &save-cache
save_cache:
key: dependency-cache-{{ checksum "package.json" }}
paths:
- ./node_modules
- &install-deps
run:
name: Install dependencies
command: npm ci --legacy-peer-deps
- &build-packages
run:
name: Build
command: npm run build
- &run-unit-tests
run:
name: Test
command: npm run test
jobs:
build:
working_directory: ~/nest
docker:
- image: cimg/node:<< pipeline.parameters.maintenance-node-version >>
steps:
- checkout
- run:
name: Update NPM version
command: 'sudo npm install -g npm@^9'
- *restore-cache
- *install-deps
- *save-cache
- *build-packages
test:
parameters:
node-version:
type: string
working_directory: ~/nest
docker:
- image: cimg/node:<< parameters.node-version >>
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
lint:
working_directory: ~/nest
docker:
- image: cimg/node:<< pipeline.parameters.maintenance-node-version >>
steps:
- checkout
- *restore-cache
- *install-deps
- run:
name: Lint
command: npm run lint
integration_tests:
working_directory: ~/nest
machine: true
steps:
- checkout
- 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:
name: Upgrade Node.js
command: |
nvm install << pipeline.parameters.maintenance-node-version >>
node -v
nvm alias default << pipeline.parameters.maintenance-node-version >>
- run:
name: Install Docker Compose
command: |
curl -L https://github.com/docker/compose/releases/download/1.19.0/docker-compose-`uname -s`-`uname -m` > ~/docker-compose
chmod +x ~/docker-compose
sudo mv ~/docker-compose /usr/local/bin/docker-compose
- *install-deps
- run:
name: Prepare tests
command: |
bash ./scripts/prepare.sh
sleep 10
- run:
name: List containers
command: docker ps
- run:
name: Integration tests
command: npm run test:integration
codechecks_benchmarks:
working_directory: ~/nest
docker:
- image: cimg/node:<< pipeline.parameters.maintenance-node-version >>
steps:
- checkout
- *restore-cache
- *install-deps
- *build-packages
- run:
name: Install native wrk
command: .circleci/install-wrk.sh
- run:
name: Run codechecks with benchmarks
command: yarn codechecks:benchmarks
samples:
working_directory: ~/nest
docker:
- image: cimg/node:<< pipeline.parameters.maintenance-node-version >>
environment:
DISABLE_OPENCOLLECTIVE: 'true'
steps:
- checkout
- *restore-cache
- *install-deps
- run:
name: Build all samples
command: npm run build:samples
workflows:
build-and-test:
jobs:
- build
- test:
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
- integration_tests:
requires:
- build
- samples:
requires:
- build
- codechecks_benchmarks:
requires:
- build

View File

@@ -1,13 +0,0 @@
#!/usr/bin/env bash
set -e
cd "$(dirname "$0")"
# based on https://medium.com/@felipedutratine/intelligent-benchmark-with-wrk-163986c1587f
cd /tmp/
sudo apt-get install build-essential libssl-dev git -y
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

View File

@@ -1,44 +0,0 @@
{
"extends": ["@commitlint/config-angular"],
"rules": {
"subject-case": [
2,
"always",
["sentence-case", "start-case", "pascal-case", "upper-case", "lower-case"]
],
"type-enum": [
2,
"always",
[
"build",
"chore",
"ci",
"docs",
"feat",
"fix",
"perf",
"refactor",
"revert",
"style",
"test",
"sample"
]
],
"scope-enum": [
1,
"always",
[
"common",
"core",
"sample",
"microservices",
"express",
"fastify",
"socket.io",
"ws",
"testing",
"websockets"
]
]
}
}

View File

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

View File

@@ -1,47 +0,0 @@
module.exports = {
root: true,
env: {
node: true,
},
plugins: ['@typescript-eslint/eslint-plugin'],
extends: [
'plugin:@typescript-eslint/recommended',
'prettier',
],
overrides: [
{
files: ['**/*.ts'],
parser: '@typescript-eslint/parser',
parserOptions: {
project: 'tsconfig.json',
sourceType: 'module',
},
rules: {
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-unused-vars': 'off',
'@typescript-eslint/ban-types': 'off',
'@typescript-eslint/no-array-constructor': 'off',
},
},
{
files: ['**/*.spec.ts', 'integration/**/*.ts'],
parser: '@typescript-eslint/parser',
parserOptions: {
project: 'tsconfig.spec.json',
sourceType: 'module',
},
rules: {
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-unused-vars': 'off',
'@typescript-eslint/ban-types': 'off',
'@typescript-eslint/no-empty-function': 'off',
},
}
]
};

4
.github/FUNDING.yml vendored
View File

@@ -1,4 +0,0 @@
# These are supported funding model platforms
github: [kamilmysliwiec]
open_collective: nest

46
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,46 @@
<!--
PLEASE HELP US PROCESS GITHUB ISSUES FASTER BY PROVIDING THE FOLLOWING INFORMATION.
ISSUES MISSING IMPORTANT INFORMATION MAY BE CLOSED WITHOUT INVESTIGATION.
-->
## I'm submitting a...
<!--
Please search GitHub for a similar issue or PR before submitting.
Check one of the following options with "x" -->
<pre><code>
[ ] Regression <!--(a behavior that used to work and stopped working in a new release)-->
[ ] Bug report
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.
</code></pre>
## Current behavior
<!-- Describe how the issue manifests. -->
## Expected behavior
<!-- Describe what the desired behavior would be. -->
## Minimal reproduction of the problem with instructions
<!-- Please share a repo, a gist, or step-by-step instructions. -->
## What is the motivation / use case for changing the behavior?
<!-- Describe the motivation or the concrete use case. -->
## Environment
<pre><code>
Nest version: X.Y.Z
<!-- Check whether this is still an issue in the most recent Nest version -->
For Tooling issues:
- Node version: XX <!-- run `node --version` -->
- Platform: <!-- Mac, Linux, Windows -->
Others:
<!-- Anything else relevant? Operating system version, IDE, package manager, ... -->
</code></pre>

View File

@@ -1,146 +0,0 @@
name: "\U0001F41B Bug Report"
description: "If something isn't working as expected \U0001F914"
labels: ["needs triage"]
body:
- type: markdown
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
- use our [Discord community](https://discord.gg/NestJS)
- use [StackOverflow using the tag `nestjs`](https://stackoverflow.com/questions/tagged/nestjs)
- If it's just a quick question you can ping [our Twitter](https://twitter.com/nestframework)
**NOTE:** You don't need to answer questions that you know that aren't relevant.
---
- type: checkboxes
attributes:
label: "Is there an existing issue for this?"
description: "Please search [here](../issues?q=is%3Aissue) to see if an issue already exists for the bug you encountered"
options:
- label: "I have searched the existing issues"
required: true
- type: textarea
validations:
required: true
attributes:
label: "Current behavior"
description: "How the issue manifests?"
- type: input
validations:
required: true
attributes:
label: "Minimum reproduction code"
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
placeholder: |
1. `npm ci`
2. `npm start:dev`
3. See error...
- type: textarea
validations:
required: true
attributes:
label: "Expected behavior"
description: "A clear and concise description of what you expected to happened (or code)"
- type: markdown
attributes:
value: |
---
- type: checkboxes
validations:
required: true
attributes:
label: "Package"
description: |
Which package (or packages) do you think your issue is related to?
**Tip**: The first line of the stack trace can help you to figure out this
The package isn't listed below? Try to find its repository [here](https://github.com/orgs/nestjs/repositories) and open the issue there instead
options:
- label: "I don't know. Or some 3rd-party package"
- label: "<code>@nestjs/common</code>"
- label: "<code>@nestjs/core</code>"
- label: "<code>@nestjs/microservices</code>"
- label: "<code>@nestjs/platform-express</code>"
- label: "<code>@nestjs/platform-fastify</code>"
- label: "<code>@nestjs/platform-socket.io</code>"
- label: "<code>@nestjs/platform-ws</code>"
- label: "<code>@nestjs/testing</code>"
- label: "<code>@nestjs/websockets</code>"
- label: "Other (see below)"
- type: input
attributes:
label: "Other package"
description: "If your issue is related to some package that is not listed above nor under @nestjs org, write its name here"
- type: input
attributes:
label: "NestJS version"
description: |
Which version of `@nestjs/core` are you using?
**Tip**: Make sure that all of yours `@nestjs/*` dependencies are in sync!
placeholder: "8.1.3"
- type: textarea
validations:
required: true
attributes:
label: "Packages versions"
description: |
You could leave your whole `package.json` dependencies list here, or just indicate which version of `@nestjs/*` you are using
**Tip**: run _npx nest info_
value: |
```json
```
- type: input
attributes:
label: "Node.js version"
description: "Which version of Node.js are you using?"
placeholder: "14.17.6"
- type: checkboxes
validations:
required: true
attributes:
label: "In which operating systems have you tested?"
options:
- label: macOS
- label: Windows
- label: Linux
- type: markdown
attributes:
value: |
---
- type: textarea
attributes:
label: "Other"
description: |
Anything else relevant? eg: Logs, OS version, IDE, package manager, etc.
**Tip:** You can attach images, recordings or log files by clicking this area to highlight it and then dragging files in

View File

@@ -1,55 +0,0 @@
name: "\U0001F680 Feature Request"
description: "I have a suggestion \U0001F63B!"
labels: ["type: enhancement :wolf:", "needs triage"]
body:
- type: markdown
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
- use our [Discord community](https://discord.gg/NestJS)
- use [StackOverflow using the tag `nestjs`](https://stackoverflow.com/questions/tagged/nestjs)
- If it's just a quick question you can ping [our Twitter](https://twitter.com/nestframework)
---
- type: checkboxes
attributes:
label: "Is there an existing issue that is already proposing this?"
description: "Please search [here](../issues?q=is%3Aissue) to see if an issue already exists for the feature you are requesting"
options:
- label: "I have searched the existing issues"
required: true
- type: textarea
validations:
required: true
attributes:
label: "Is your feature request related to a problem? Please describe it"
description: "A clear and concise description of what the problem is"
placeholder: |
I have an issue when ...
- type: textarea
validations:
required: true
attributes:
label: "Describe the solution you'd like"
description: "A clear and concise description of what you want to happen. Add any considered drawbacks"
- type: textarea
validations:
required: true
attributes:
label: "Teachability, documentation, adoption, migration strategy"
description: "If you can, explain how users will be able to use this and possibly write out a version the docs. Maybe a screenshot or design?"
- type: textarea
validations:
required: true
attributes:
label: "What is the motivation / use case for changing the behavior?"
description: "Describe the motivation or the concrete use case"

View File

@@ -1,84 +0,0 @@
name: "\U0001F4A5 Regression"
description: "Report an unexpected while upgrading your Nest application!"
labels: ["type: bug :sob:", "needs triage"]
body:
- type: markdown
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
- use our [Discord community](https://discord.gg/NestJS)
- use [StackOverflow using the tag `nestjs`](https://stackoverflow.com/questions/tagged/nestjs)
- If it's just a quick question you can ping [our Twitter](https://twitter.com/nestframework)
**NOTE:** You don't need to answer questions that you know that aren't relevant.
---
- type: checkboxes
attributes:
label: "Did you read the migration guide?"
description: "Check out the [migration guide here](https://docs.nestjs.com/migration-guide)!"
options:
- label: "I have read the whole migration guide"
required: false
- type: checkboxes
attributes:
label: "Is there an existing issue that is already proposing this?"
description: "Please search [here](../issues?q=is%3Aissue) to see if an issue already exists for the feature you are requesting"
options:
- label: "I have searched the existing issues"
required: true
- type: input
attributes:
label: "Potential Commit/PR that introduced the regression"
description: "If you have time to investigate, what PR/date/version introduced this issue"
placeholder: "PR #123 or commit 5b3c4a4"
- type: input
validations:
required: true
attributes:
label: "NestJS version"
placeholder: "8.1.0 -> 8.1.3"
- type: textarea
validations:
required: true
attributes:
label: "Describe the regression"
description: "A clear and concise description of what the regression is"
- type: input
attributes:
label: "Minimum reproduction code"
description: "An URL to some git repository that reproduces this issue. [Wtf is a minimum reproduction?](https://jmcdo29.github.io/wtf-is-a-minimum-reproduction)"
placeholder: "https://github.com/..."
- type: textarea
attributes:
label: "Input code"
description: "Write some code snippets if you think it is worth it"
value: |
```ts
```
- type: textarea
validations:
required: true
attributes:
label: "Expected behavior"
description: "A clear and concise description of what you expected to happened (or code)"
- type: textarea
attributes:
label: "Other"
description: |
Anything else relevant? eg: Logs, OS version, IDE, package manager, etc.
**Tip:** You can attach images, recordings or log files by clicking this area to highlight it and then dragging files in

View File

@@ -1,48 +0,0 @@
title: "perf: "
name: "\U0001F525 Suggestion for Improving Performance"
description: "I have a suggestion that might improve the performance of Nest \U00002728"
labels: ["type: enhancement :wolf:", "needs triage"]
body:
- type: checkboxes
attributes:
label: "Is there an existing issue that is already proposing this?"
description: "Please search [here](../issues?q=is%3Aissue) to see if an issue already exists for this"
options:
- label: "I have searched the existing issues"
required: true
- type: input
validations:
required: true
attributes:
label: "NestJS version"
description: "Which version do you intend to improve?"
placeholder: "8.1.3"
- type: textarea
attributes:
label: "Is your performance suggestion related to a problem? Please describe it"
description: "A clear and concise description of what the problem is"
- type: textarea
validations:
required: true
attributes:
label: "Describe the performance enhancement you are proposing and how we can try it out"
placeholder: |
Cache `array.length` on the following lines ...
- type: textarea
validations:
required: true
attributes:
label: "Benchmarks result or another proof (eg: POC)"
description: |
If you've already prototyped a solution, share your results here
If not, what makes you believe there will be a performance improvement?
placeholder: |
```
```
MacBook Pro Mid 2014, 2.5 GHz Quad-Core Intel Core i7, 16 GB 1600 MHz DDR3, SSD

View File

@@ -1,10 +0,0 @@
## To encourage contributors to use issue templates, we don't allow blank issues
blank_issues_enabled: false
contact_links:
- name: "\u2049 FAQ"
url: "https://docs.nestjs.com/faq"
about: "Make sure you have read the Frequently Asked Questions page."
- name: "\u2753 Discord Community of NestJS"
url: "https://discord.gg/NestJS"
about: "Please ask support questions or discuss suggestions/enhancements here."

View File

@@ -10,13 +10,15 @@ Please check if your PR fulfills the following requirements:
What kind of change does this PR introduce?
<!-- Please check the one that applies to this PR using "x". -->
- [ ] Bugfix
- [ ] Feature
- [ ] Code style update (formatting, local variables)
- [ ] Refactoring (no functional changes, no api changes)
- [ ] Build related changes
- [ ] CI related changes
- [ ] Other... Please describe:
```
[ ] Bugfix
[ ] Feature
[ ] Code style update (formatting, local variables)
[ ] Refactoring (no functional changes, no api changes)
[ ] Build related changes
[ ] CI related changes
[ ] Other... Please describe:
```
## What is the current behavior?
<!-- Please describe the current behavior that you are modifying, or link to a relevant issue. -->
@@ -28,8 +30,10 @@ Issue Number: N/A
## Does this PR introduce a breaking change?
- [ ] Yes
- [ ] No
```
[ ] Yes
[ ] No
```
<!-- If this PR contains a breaking change, please describe the impact and migration path for existing applications below. -->

View File

@@ -1,12 +0,0 @@
version: 2
updates:
- package-ecosystem: npm
directory: "/"
schedule:
interval: daily
open-pull-requests-limit: 10
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: daily
open-pull-requests-limit: 10

36
.github/lock.yml vendored
View File

@@ -1,36 +0,0 @@
# Number of days of inactivity before a closed issue or pull request is locked
daysUntilLock: 90
# Skip issues and pull requests created before a given timestamp. Timestamp must
# follow ISO 8601 (`YYYY-MM-DD`). Set to `false` to disable
skipCreatedBefore: false
# Issues and pull requests with these labels will be ignored. Set to `[]` to disable
exemptLabels: []
# Label to add before locking, such as `outdated`. Set to `false` to disable
lockLabel: false
# Comment to post before locking. Set to `false` to disable
lockComment: >
This thread has been automatically locked since there has not been
any recent activity after it was closed. Please open a new issue for
related bugs.
# Assign `resolved` as the reason for locking. Set to `false` to disable
setLockReason: true
# Limit to only `issues` or `pulls`
# only: issues
# Optionally, specify configuration settings just for `issues` or `pulls`
# issues:
# exemptLabels:
# - help-wanted
# lockLabel: outdated
# pulls:
# daysUntilLock: 30
# Repository to extend settings from
# _extends: repo

View File

@@ -1,61 +0,0 @@
name: "CodeQL"
on:
push:
branches: [master, ]
pull_request:
# The branches below must be a subset of the branches above
branches: [master]
schedule:
- cron: '0 17 * * 4'
permissions:
contents: read
jobs:
analyse:
permissions:
security-events: write
name: Analyse
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
fetch-depth: 2
# If this run was triggered by a pull request event, then checkout
# the head of the pull request instead of the merge commit.
- run: git checkout HEAD^2
if: ${{ github.event_name == 'pull_request' }}
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
queries: +security-extended
# Override language selection by uncommenting this and choosing your languages
# with:
# languages: go, javascript, csharp, python, cpp, java
# 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
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3

23
.gitignore vendored
View File

@@ -1,5 +1,3 @@
packages/*/package-lock.json
# dependencies
node_modules/
@@ -7,18 +5,6 @@ node_modules/
/.idea
/.awcache
/.vscode
/.devcontainer
/.classpath
/.project
/.settings
*.code-workspace
# Vim
[._]*.s[a-v][a-z]
[._]*.sw[a-p]
[._]s[a-rt-v][a-z]
[._]ss[a-gi-z]
[._]sw[a-p]
# bundle
packages/**/*.d.ts
@@ -32,7 +18,6 @@ yarn-error.log
/**/npm-debug.log
/packages/**/.npmignore
/packages/**/LICENSE
*.tsbuildinfo
# example
/quick-start
@@ -41,12 +26,6 @@ yarn-error.log
# tests
/test
/benchmarks/memory
/coverage
/.nyc_output
/packages/graphql
/benchmarks/memory
build/config\.gypi
.npmrc
pnpm-lock.yaml
build/config\.gypi

View File

@@ -1 +0,0 @@
npx --no-install commitlint --edit $1

View File

@@ -1 +0,0 @@
npx lint-staged

View File

@@ -10,6 +10,4 @@
package-lock.json
tslint.json
tsconfig.json
.prettierrc
*.tsbuildinfo
.prettierrc

View File

@@ -1,3 +1,2 @@
packages/**/*.d.ts
packages/**/*.js
.nyc_output
packages/**/*.js

View File

@@ -1,5 +1,4 @@
{
"singleQuote": true,
"arrowParens": "avoid",
"trailingComma": "all"
}
}

24
.travis.yml Normal file
View File

@@ -0,0 +1,24 @@
language: node_js
node_js:
- "8"
- "9"
- "10"
cache:
directories:
- "node_modules"
git:
depth: 5
addons:
firefox: "latest"
before_script:
- export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start
before_install:
- npm i -g npm@latest
install:
- npm ci
- npm run build:dev
script:
- npm run lint
- npm test
after_success: npm run coverage

View File

@@ -1,76 +0,0 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at support@nestjs.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq

162
CONTRIBUTING.md Executable file → Normal file
View File

@@ -4,14 +4,13 @@ We would love for you to contribute to Nest and help make it even better than it
today! As a contributor, here are the guidelines we would like you to follow:
<!--* [Code of Conduct](#coc)-->
- [Question or Problem?](#question)
- [Issues and Bugs](#issue)
- [Feature Requests](#feature)
- [Submission Guidelines](#submit)
- [Development Setup](#development)
- [Coding Rules](#rules)
- [Commit Message Guidelines](#commit)
* [Question or Problem?](#question)
* [Issues and Bugs](#issue)
* [Feature Requests](#feature)
* [Submission Guidelines](#submit)
* [Development Setup](#development)
* [Coding Rules](#rules)
* [Commit Message Guidelines](#commit)
<!-- - [Signing the CLA](#cla) -->
<!-- ## <a name="coc"></a> Code of Conduct
@@ -19,18 +18,18 @@ Help us keep Nest open and inclusive. Please read and follow our [Code of Conduc
## <a name="question"></a> Got a Question or Problem?
**Do not open issues for general support questions as we want to keep GitHub issues for bug reports and feature requests.** You've got much better chances of getting your question answered on [Stack Overflow][stackoverflow] where the questions should be tagged with tag `nestjs`.
**Do not open issues for general support questions as we want to keep GitHub issues for bug reports and feature requests.** You've got much better chances of getting your question answered on [Stack Overflow](https://stackoverflow.com/questions/tagged/nestjs) where the questions should be tagged with tag `nestjs`.
Stack Overflow is a much better place to ask questions since:
<!-- - there are thousands of people willing to help on Stack Overflow [maybe one day] -->
- questions and answers stay available for public viewing so your question / answer might help someone else
- Stack Overflow's voting system assures that the best answers are prominently visible.
* questions and answers stay available for public viewing so your question / answer might help someone else
* Stack Overflow's voting system assures that the best answers are prominently visible.
To save your and our time, we will systematically close all issues that are requests for general support and redirect people to Stack Overflow.
If you would like to chat about the question in real-time, you can reach out via [our discord channel][discord].
If you would like to chat about the question in real-time, you can reach out via [our gitter channel][gitter].
## <a name="issue"></a> Found a Bug?
@@ -45,10 +44,10 @@ Repository. If you would like to _implement_ a new feature, please submit an iss
a proposal for your work first, to be sure that we can use it.
Please consider what kind of change it is:
- For a **Major Feature**, first open an issue and outline your proposal so that it can be
* For a **Major Feature**, first open an issue and outline your proposal so that it can be
discussed. This will also allow us to better coordinate our efforts, prevent duplication of work,
and help you to craft the change so that it is successfully accepted into the project. For your issue name, please prefix your proposal with `[discussion]`, for example "[discussion]: your feature idea".
- **Small Features** can be crafted and directly [submitted as a Pull Request](#submit-pr).
* **Small Features** can be crafted and directly [submitted as a Pull Request](#submit-pr).
## <a name="submit"></a> Submission Guidelines
@@ -58,9 +57,9 @@ Before you submit an issue, please search the issue tracker, maybe an issue for
We want to fix all the issues as soon as possible, but before fixing a bug we need to reproduce and confirm it. In order to reproduce bugs we will systematically ask you to provide a minimal reproduction scenario using a repository or [Gist](https://gist.github.com/). Having a live, reproducible scenario gives us wealth of important information without going back & forth to you with additional questions like:
- version of NestJS used
- 3rd-party libraries and their versions
- and most importantly - a use-case that fails
* version of NestJS used
* 3rd-party libraries and their versions
* and most importantly - a use-case that fails
<!--
// TODO we need to create a playground, similar to plunkr
@@ -69,9 +68,9 @@ A minimal reproduce scenario using a repository or Gist allows us to quickly con
<!-- We will be insisting on a minimal reproduce scenario in order to save maintainers time and ultimately be able to fix more bugs. Interestingly, from our experience users often find coding problems themselves while preparing a minimal plunk. We understand that sometimes it might be hard to extract essentials bits of code from a larger code-base but we really need to isolate the problem before we can fix it. -->
Unfortunately, we are not able to investigate / fix bugs without a minimal reproduction, so if we don't hear back from you we are going to close an issue that doesn't have enough info to be reproduced.
Unfortunately, we are not able to investigate / fix bugs without a minimal reproduction, so if we don't hear back from you we are going to close an issue that don't have enough info to be reproduced.
You can file new issues by filling out our [new issue form][new_issue].
You can file new issues by filling out our [new issue form](https://github.com/nestjs/nest/issues/new).
### <a name="submit-pr"></a> Submitting a Pull Request (PR)
@@ -84,9 +83,9 @@ To the first point
We cannot accept code without this.
-->
1. Search [GitHub Pull Requests][gh_prs] for an open or closed PR
1. Search [GitHub](https://github.com/nestjs/nest/pulls) for an open or closed PR
that relates to your submission. You don't want to duplicate effort.
1. Fork this repository.
1. Fork the nestjs/nest repo.
1. Make your changes in a new git branch:
```shell
@@ -95,7 +94,7 @@ We cannot accept code without this.
1. Create your patch, **including appropriate test cases**.
1. Follow our [Coding Rules](#rules).
1. Run the full Nest test suite (see [common scripts](#common-scripts)),
1. Run the full Nest test suite, as described in the [developer documentation][dev-doc],
and ensure that all tests pass.
1. Commit your changes using a descriptive commit message that follows our
[commit message conventions](#commit). Adherence to these conventions
@@ -115,11 +114,11 @@ We cannot accept code without this.
1. In GitHub, send a pull request to `nestjs:master`.
- If we suggest changes then:
* If we suggest changes then:
- Make the required updates.
- Re-run the Nest test suites to ensure tests are still passing.
- Rebase your branch and force push to your GitHub repository (this will update your Pull Request):
* Make the required updates.
* Re-run the Nest test suites to ensure tests are still passing.
* Rebase your branch and force push to your GitHub repository (this will update your Pull Request):
```shell
git rebase master -i
@@ -133,25 +132,25 @@ That's it! Thank you for your contribution!
After your pull request is merged, you can safely delete your branch and pull the changes
from the main (upstream) repository:
- Delete the remote branch on GitHub either through the GitHub web UI or your local shell as follows:
* Delete the remote branch on GitHub either through the GitHub web UI or your local shell as follows:
```shell
git push origin --delete my-fix-branch
```
- Check out the master branch:
* Check out the master branch:
```shell
git checkout master -f
```
- Delete the local branch:
* Delete the local branch:
```shell
git branch -D my-fix-branch
```
- Update your master with the latest upstream version:
* Update your master with the latest upstream version:
```shell
git pull --ff upstream master
@@ -159,12 +158,12 @@ from the main (upstream) repository:
## <a name="development"></a> Development Setup
You will need [Node.js](https://nodejs.org) version >= 10.13.0 (except for v13).
You will need Node.js version 8.9.0+.
1. After cloning the repo, run:
```bash
$ npm ci --legacy-peer-deps # (or yarn install)
$ npm i # (or yarn install)
```
2. In order to prepare your environment run `prepare.sh` shell script:
@@ -173,14 +172,19 @@ $ npm ci --legacy-peer-deps # (or yarn install)
$ sh scripts/prepare.sh
```
That will compile fresh packages and afterward, move them all to `sample` directories.
That will compile fresh packages and afterward, move them to all `sample` directories as well as integration tests.
### <a name="common-scripts"></a>Commonly used NPM scripts
### Commonly used NPM scripts
```bash
# build all packages and move to "sample" directories
# build all packages and put them near to their source .ts files
$ npm run build
# build all packages and move to "sample" and "integration" directories
# if cross-packages breaking changes were performed you may face irrelevant errors
# in order to verify the build, you can run this command again then
$ npm run build:dev
# run the full unit tests suite
$ npm run test
@@ -190,9 +194,6 @@ $ sh scripts/run-integration.sh
# run linter
$ npm run lint
# build all packages and put them near to their source .ts files
$ npm run build:prod
```
## <a name="rules"></a> Coding Rules
@@ -203,9 +204,10 @@ To ensure consistency throughout the source code, keep these rules in mind as yo
// We're working on auto-documentation.
* All public API methods **must be documented**. (Details TBC). -->
- All features or bug fixes **must be tested** by one or more specs (unit-tests).
- We follow [Google's JavaScript Style Guide][js-style-guide], but wrap all code at
**100 characters**. An automated formatter is available (`npm run format`).
* All features or bug fixes **must be tested** by one or more specs (unit-tests).
* We follow [Google's JavaScript Style Guide][js-style-guide], but wrap all code at
**100 characters**. An automated formatter is available, see
[DEVELOPER.md](docs/DEVELOPER.md#clang-format).
## <a name="commit"></a> Commit Message Guidelines
@@ -228,16 +230,16 @@ format that includes a **type**, a **scope** and a **subject**:
The **header** is mandatory and the **scope** of the header is optional.
Any line of the commit message cannot be longer than 100 characters! This allows the message to be easier
Any line of the commit message cannot be longer 100 characters! This allows the message to be easier
to read on GitHub as well as in various git tools.
Footer should contain a [closing reference to an issue](https://help.github.com/articles/closing-issues-via-commit-messages/) if any.
Samples: (even more [samples][commits_samples])
Samples: (even more [samples](https://github.com/nestjs/nest/commits/master))
```
docs(changelog): update change log to beta.5
fix(core): need to depend on latest rxjs and zone.js
docs(changelog) update change log to beta.5
bugfix(core) need to depend on latest rxjs and zone.js
```
### Revert
@@ -248,51 +250,44 @@ If the commit reverts a previous commit, it should begin with `revert:`, followe
Must be one of the following:
- **build**: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
- **chore**: Updating tasks etc; no production code change
- **ci**: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)
- **docs**: Documentation only changes
- **feat**: A new feature
- **fix**: A bug fix
- **perf**: A code change that improves performance
- **refactor**: A code change that neither fixes a bug nor adds a feature
- **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
- **test**: Adding missing tests or correcting existing tests
- **sample**: A change to the samples
* **build**: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
* **ci**: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)
* **docs**: Documentation only changes
* **feature**: A new feature
* **bugfix**: A bug fix
* **perf**: A code change that improves performance
* **refactor**: A code change that neither fixes a bug nor adds a feature
* **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
* **test**: Adding missing tests or correcting existing tests
### Scope
The scope should have the name of the npm package affected (as perceived by person reading changelog generated from commit messages).
The scope should be the name of the npm package affected (as perceived by person reading changelog generated from commit messages.
The following is the list of supported scopes:
- **common**: for changes made on `packages/common` directory
- **core**: for changes made on `packages/core` directory
- **sample**: for changes made on `packages/sample` directory
- **microservices**: for changes made on `packages/microservices` directory
- **express**: for changes made on `packages/platform-express` directory
- **fastify**: for changes made on `packages/platform-fastify` directory
- **socket.io**: for changes made on `packages/platform-socket.io` directory
- **ws**: for changes made on `packages/platform-ws` directory
- **testing**: for changes made on `packages/testing` directory
- **websockets**: for changes made on `packages/websockets` directory
If your change affect more than one package, separate the scopes with a comma (e.g. `common,core`).
* **common**
* **core**
* **sample**
* **microservices**
* **testing**
* **websockets**
There are currently a few exceptions to the "use package name" rule:
- **packaging**: used for changes that change the npm package layout in all of our packages, e.g. public path changes, package.json changes done to all packages, d.ts file/format changes, changes to bundles, etc.
- **changelog**: used for updating the release notes in CHANGELOG.md
- **sample/#**: for the example apps directory, replacing # with the example app number
- none/empty string: useful for `style`, `test` and `refactor` changes that are done across all packages (e.g. `style: add missing semicolons`)
* **packaging**: used for changes that change the npm package layout in all of our packages, e.g. public path changes, package.json changes done to all packages, d.ts file/format changes, changes to bundles, etc.
* **changelog**: used for updating the release notes in CHANGELOG.md
* **sample/#**: for the example apps directory, replacing # with the example app number
* none/empty string: useful for `style`, `test` and `refactor` changes that are done across all packages (e.g. `style: add missing semicolons`)
<!-- * **aio**: used for docs-app (angular.io) related changes within the /aio directory of the repo -->
### Subject
The subject contains succinct description of the change:
- use the imperative, present tense: "change" not "changed" nor "changes"
- don't capitalize first letter
- no dot (.) at the end
* use the imperative, present tense: "change" not "changed" nor "changes"
* don't capitalize first letter
* no dot (.) at the end
### Body
@@ -322,13 +317,14 @@ changes to be accepted, the CLA must be signed. It's a quick process, we promise
<!-- [coc]: https://github.com/angular/code-of-conduct/blob/master/CODE_OF_CONDUCT.md -->
[commit-message-format]: https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit#
<!-- [individual-cla]: http://code.google.com/legal/individual-cla-v1.0.html -->
<!-- [corporate-cla]: http://code.google.com/legal/corporate-cla-v1.0.html -->
[corporate-cla]: http://code.google.com/legal/corporate-cla-v1.0.html
[dev-doc]: https://github.com/nestjs/nest/blob/master/docs/DEVELOPER.md
[github]: https://github.com/nestjs/nest
[stackoverflow]: https://stackoverflow.com/questions/tagged/nestjs
[discord]: https://discordapp.com/invite/G7Qnnhy
[gitter]: https://gitter.im/nestjs/nest
[individual-cla]: http://code.google.com/legal/individual-cla-v1.0.html
[js-style-guide]: https://google.github.io/styleguide/jsguide.html
[new_issue]: https://github.com/nestjs/nest/issues/new
[gh_prs]: https://github.com/nestjs/nest/pulls
[commits_samples]: https://github.com/nestjs/nest/commits/master
[jsfiddle]: http://jsfiddle.net
[plunker]: http://plnkr.co/edit
[runnable]: http://runnable.com
<!-- [stackoverflow]: http://stackoverflow.com/questions/tagged/angular -->

View File

@@ -1,6 +1,6 @@
(The MIT License)
Copyright (c) 2017-2024 Kamil Mysliwiec <https://kamilmysliwiec.com>
Copyright (c) 2017 Kamil Myśliwiec <http://kamilmysliwiec.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

145
Readme.md
View File

@@ -1,150 +1,75 @@
<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_text.svg" width="320" 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
[travis-image]: https://api.travis-ci.org/nestjs/nest.svg?branch=master
[travis-url]: https://travis-ci.org/nestjs/nest
[linux-image]: https://img.shields.io/travis/nestjs/nest/master.svg?label=linux
[linux-url]: https://travis-ci.org/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, heavily inspired by <a href="https://angular.io" target="blank">Angular</a>.</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>
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/dm/@nestjs/common.svg" alt="NPM Downloads" /></a>
<a href="https://circleci.com/gh/nestjs/nest" target="_blank"><img src="https://img.shields.io/circleci/build/github/nestjs/nest/master" alt="CircleCI" /></a>
<a href="https://discord.gg/G7Qnnhy" target="_blank"><img src="https://img.shields.io/badge/discord-online-brightgreen.svg" alt="Discord"/></a>
<a href="https://opencollective.com/nest#backer" target="_blank"><img src="https://opencollective.com/nest/backers/badge.svg" alt="Backers on Open Collective" /></a>
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://opencollective.com/nest/sponsors/badge.svg" alt="Sponsors on Open Collective" /></a>
<a href="https://paypal.me/kamilmysliwiec" target="_blank"><img src="https://img.shields.io/badge/Donate-PayPal-ff3f59.svg"/></a>
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg" alt="Support us"></a>
<a href="https://twitter.com/nestframework" target="_blank"><img src="https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow"></a>
<a href="https://www.npmjs.com/~nestjscore"><img src="https://img.shields.io/npm/v/@nestjs/core.svg" alt="NPM Version" /></a>
<a href="https://www.npmjs.com/~nestjscore"><img src="https://img.shields.io/npm/l/@nestjs/core.svg" alt="Package License" /></a>
<a href="https://www.npmjs.com/~nestjscore"><img src="https://img.shields.io/npm/dm/@nestjs/core.svg" alt="NPM Downloads" /></a>
<a href="https://travis-ci.org/nestjs/nest"><img src="https://api.travis-ci.org/nestjs/nest.svg?branch=master" alt="Travis" /></a>
<a href="https://travis-ci.org/nestjs/nest"><img src="https://img.shields.io/travis/nestjs/nest/master.svg?label=linux" alt="Linux" /></a>
<a href="https://coveralls.io/github/nestjs/nest?branch=master"><img src="https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#8" alt="Coverage" /></a>
<a href="https://gitter.im/nestjs/nestjs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=body_badge"><img src="https://badges.gitter.im/nestjs/nestjs.svg" alt="Gitter" /></a>
<a href="https://opencollective.com/nest#backer"><img src="https://opencollective.com/nest/backers/badge.svg" alt="Backers on Open Collective" /></a>
<a href="https://opencollective.com/nest#sponsor"><img src="https://opencollective.com/nest/sponsors/badge.svg" alt="Sponsors on Open Collective" /></a>
<a href="https://paypal.me/kamilmysliwiec"><img src="https://img.shields.io/badge/Donate-PayPal-ff3f59.svg"/></a>
<a href="https://twitter.com/nestframework"><img src="https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow"></a>
</p>
<!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)
[![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->
## 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).
<p>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>
<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.</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:
## Questions
For questions and support please use the official [Discord channel](https://discord.gg/G7Qnnhy). The issue list of this repo is **exclusively** for bug reports and feature requests.
## Issues
Please make sure to read the [Issue Reporting Checklist](https://github.com/nestjs/nest/blob/master/CONTRIBUTING.md#-submitting-an-issue) before opening an issue. Issues not conforming to the guidelines may be closed immediately.
## Consulting
With official support, you can get expert help straight from Nest core team. We provide dedicated technical support, migration strategies, advice on best practices (and design decisions), PR reviews, and team augmentation. Read more about [support here](https://enterprise.nestjs.com).
* 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:
## Support
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).
Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).
#### Principal Sponsors
#### Principal Sponsor
<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>
<a href="https://valor-software.com/"><img src="https://docs.nestjs.com/assets/sponsors/valor-software.png" width="320" /></a>
#### 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>
<a href="http://xtremis.com/"><img src="https://nestjs.com/img/logo-xtremis.svg" width="220" /></a>
#### 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>
<a href="https://neoteric.eu/"><img src="https://nestjs.com/img/neoteric-cut.png" width="120" /></a> &nbsp;
<a href="http://gojob.com"><img src="http://nestjs.com/img/gojob-logo.png" valign="bottom" height="95" /></a> &nbsp; <a href="https://www.swingdev.io"><img src="https://nestjs.com/img/swingdev-logo.svg#1" width="150" /> </a>
#### 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>
<a href="https://scal.io"><img src="https://nestjs.com/img/scalio-logo.svg" width="110" /></a> &nbsp; <a href="http://angularity.io"><img src="http://angularity.io/media/logo.svg" height="30" /></a> &nbsp; <!--<a href="https://keycdn.com"><img src="https://nestjs.com/img/keycdn.svg" height="30" /></a> &nbsp;--> <a href="https://hostpresto.com"><img src="https://nestjs.com/img/hostpresto.png" height="30" /></a> &nbsp; <a href="https://genuinebee.com/"><img src="https://nestjs.com/img/genuinebee.svg" height="38" /></a> &nbsp; <a href="http://architectnow.net/"><img src="https://nestjs.com/img/architectnow.png" height="24" /></a> &nbsp; <a href="https://quander.io/"><img src="https://nestjs.com/img/quander.png" height="28" /></a>
## Backers
<a href="https://opencollective.com/nest" target="_blank"><img src="https://opencollective.com/nest/backers.svg?width=1000"></a>
<a href="https://opencollective.com/nest"><img src="https://opencollective.com/nest/backers.svg?width=890"></a>
## 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://kamilmysliwiec.com)
* Website - [https://nestjs.com](https://nestjs.com/)
* Twitter - [@nestframework](https://twitter.com/nestframework)
## License

View File

@@ -1,5 +0,0 @@
# Security Policy
## Reporting a Vulnerability
Please report security issues to `support@nestjs.com`.

View File

@@ -2,87 +2,47 @@
express
-----------------------
Running 10s test @ http://localhost:3000
1024 connections
┌─────────┬───────┬───────┬───────┬────────┬──────────┬──────────┬────────┐
│ Stat │ 2.5% │ 50% │ 97.5% │ 99% │ Avg │ Stdev │ Max │
├─────────┼───────┼───────┼───────┼────────┼──────────┼──────────┼────────┤
│ Latency │ 55 ms │ 58 ms │ 91 ms │ 138 ms │ 61.88 ms │ 23.95 ms │ 747 ms │
└─────────┴───────┴───────┴───────┴────────┴──────────┴──────────┴────────┘
┌───────────┬─────────┬─────────┬─────────┬─────────┬──────────┬─────────┬─────────┐
│ Stat │ 1% │ 2.5% │ 50% │ 97.5% │ Avg │ Stdev │ Min │
├───────────┼─────────┼─────────┼─────────┼─────────┼──────────┼─────────┼─────────┤
│ Req/Sec │ 8407 │ 8407 │ 17407 │ 17743 │ 16454.41 │ 2716.94 │ 8402 │
├───────────┼─────────┼─────────┼─────────┼─────────┼──────────┼─────────┼─────────┤
│ Bytes/Sec │ 1.81 MB │ 1.81 MB │ 3.74 MB │ 3.81 MB │ 3.54 MB │ 584 kB │ 1.81 MB │
└───────────┴─────────┴─────────┴─────────┴─────────┴──────────┴─────────┴─────────┘
Req/Bytes counts sampled once per second.
165k requests in 10.17s, 35.4 MB read
-----------------------
nest (with "@nestjs/platform-express")
-----------------------
Running 10s test @ http://localhost:3000
1024 connections
┌─────────┬───────┬───────┬───────┬───────┬──────────┬──────────┬────────┐
│ Stat │ 2.5% │ 50% │ 97.5% │ 99% │ Avg │ Stdev │ Max │
├─────────┼───────┼───────┼───────┼───────┼──────────┼──────────┼────────┤
│ Latency │ 61 ms │ 64 ms │ 71 ms │ 94 ms │ 65.44 ms │ 17.35 ms │ 325 ms │
└─────────┴───────┴───────┴───────┴───────┴──────────┴──────────┴────────┘
┌───────────┬─────────┬─────────┬─────────┬─────────┬─────────┬────────┬─────────┐
│ Stat │ 1% │ 2.5% │ 50% │ 97.5% │ Avg │ Stdev │ Min │
├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼────────┼─────────┤
│ Req/Sec │ 14183 │ 14183 │ 15767 │ 15991 │ 15640 │ 501.13 │ 14182 │
├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼────────┼─────────┤
│ Bytes/Sec │ 3.06 MB │ 3.06 MB │ 3.41 MB │ 3.45 MB │ 3.38 MB │ 108 kB │ 3.06 MB │
└───────────┴─────────┴─────────┴─────────┴─────────┴─────────┴────────┴─────────┘
Req/Bytes counts sampled once per second.
156k requests in 10.24s, 33.8 MB read
8 threads and 1024 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 47.78ms 19.09ms 212.47ms 66.94%
Req/Sec 1.31k 268.90 2.07k 72.38%
104687 requests in 10.02s, 21.47MB read
Socket errors: connect 0, read 877, write 0, timeout 0
Requests/sec: 10444.24
Transfer/sec: 2.14MB
-----------------------
fastify
-----------------------
Running 10s test @ http://localhost:3000
1024 connections
┌─────────┬───────┬───────┬───────┬───────┬──────────┬──────────┬─────────┐
│ Stat │ 2.5% │ 50% │ 97.5% │ 99% │ Avg │ Stdev │ Max │
├─────────┼───────┼───────┼───────┼───────┼──────────┼──────────┼─────────┤
│ Latency │ 27 ms │ 30 ms │ 39 ms │ 78 ms │ 31.62 ms │ 26.59 ms │ 1232 ms │
└─────────┴───────┴───────┴───────┴───────┴──────────┴──────────┴─────────┘
┌───────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┐
│ Stat │ 1% │ 2.5% │ 50% │ 97.5% │ Avg │ Stdev │ Min │
├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Req/Sec │ 19935 │ 19935 │ 33247 │ 34111 │ 32030.4 │ 4103.84 │ 19931 │
├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ Bytes/Sec │ 3.03 MB │ 3.03 MB │ 5.05 MB │ 5.19 MB │ 4.87 MB │ 624 kB │ 3.03 MB │
└───────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┘
Req/Bytes counts sampled once per second.
320k requests in 10.18s, 48.7 MB read
8 threads and 1024 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 21.80ms 8.73ms 78.12ms 55.78%
Req/Sec 2.99k 0.92k 5.67k 68.88%
238550 requests in 10.02s, 31.17MB read
Socket errors: connect 0, read 862, write 0, timeout 0
Requests/sec: 23795.79
Transfer/sec: 3.11MB
-----------------------
nest (with "@nestjs/platform-fastify")
nest
-----------------------
Running 10s test @ http://localhost:3000
1024 connections
┌─────────┬───────┬───────┬───────┬───────┬──────────┬──────────┬────────┐
│ Stat │ 2.5% │ 50% │ 97.5% │ 99% │ Avg │ Stdev │ Max │
├─────────┼───────┼───────┼───────┼───────┼──────────┼──────────┼────────┤
│ Latency │ 31 ms │ 33 ms │ 38 ms │ 52 ms │ 34.41 ms │ 11.73 ms │ 245 ms │
└─────────┴───────┴───────┴───────┴───────┴──────────┴──────────┴────────┘
┌───────────┬─────────┬─────────┬────────┬─────────┬─────────┬─────────┬─────────┐
│ Stat │ 1% │ 2.5% │ 50% │ 97.5% │ Avg │ Stdev │ Min │
├───────────┼─────────┼─────────┼────────┼─────────┼─────────┼─────────┼─────────┤
│ Req/Sec │ 24911 │ 24911 │ 30031 │ 30335 │ 29470.4 │ 1564.48 │ 24907 │
├───────────┼─────────┼─────────┼────────┼─────────┼─────────┼─────────┼─────────┤
│ Bytes/Sec │ 3.81 MB │ 3.81 MB │ 4.6 MB │ 4.64 MB │ 4.51 MB │ 239 kB │ 3.81 MB │
└───────────┴─────────┴─────────┴────────┴─────────┴─────────┴─────────┴─────────┘
Req/Bytes counts sampled once per second.
295k requests in 10.17s, 45.1 MB read
8 threads and 1024 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 54.00ms 22.33ms 200.25ms 62.23%
Req/Sec 1.15k 338.60 1.88k 66.12%
91348 requests in 10.05s, 18.82MB read
Socket errors: connect 0, read 983, write 0, timeout 0
Requests/sec: 9093.64
Transfer/sec: 1.87MB
-----------------------
nest-fastify
-----------------------
Running 10s test @ http://localhost:3000
8 threads and 1024 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 29.31ms 11.71ms 101.96ms 70.03%
Req/Sec 2.17k 0.93k 4.12k 63.13%
173241 requests in 10.05s, 22.80MB read
Socket errors: connect 0, read 934, write 0, timeout 0
Requests/sec: 17233.87
Transfer/sec: 2.27MB

View File

@@ -2,6 +2,4 @@
const fastify = require('fastify')();
fastify.get('/', async (req, reply) => reply.send('Hello world'));
fastify.listen({
port: 3000
});
fastify.listen(3000);

View File

@@ -1,14 +1,9 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
const core_1 = require('@nestjs/core');
const fastify_platform_1 = require('@nestjs/platform-fastify');
const app_module_1 = require('./nest/app.module');
core_1.NestFactory.create(
app_module_1.AppModule,
new fastify_platform_1.FastifyAdapter(),
{
logger: false,
bodyParser: false,
},
).then(app => app.listen(3000));
core_1.NestFactory.create(app_module_1.AppModule, new core_1.FastifyAdapter(), {
logger: false,
bodyParser: false,
}).then(app => app.listen(3000));
//# sourceMappingURL=main.js.map

View File

@@ -7,8 +7,8 @@ var __decorate =
c < 3
? target
: desc === null
? (desc = Object.getOwnPropertyDescriptor(target, key))
: desc,
? (desc = Object.getOwnPropertyDescriptor(target, key))
: desc,
d;
if (typeof Reflect === 'object' && typeof Reflect.decorate === 'function')
r = Reflect.decorate(decorators, target, key, desc);
@@ -42,6 +42,9 @@ __decorate(
'root',
null,
);
AppController = __decorate([common_1.Controller()], AppController);
AppController = __decorate(
[common_1.Controller({ scope: common_1.Scope.REQUEST })],
AppController,
);
exports.AppController = AppController;
//# sourceMappingURL=app.controller.js.map

14
benchmarks/run.sh Normal file
View File

@@ -0,0 +1,14 @@
#!/usr/bin/env bash
echo 'Library:' $1
node $1 &
pid=$!
sleep 2
wrk 'http://localhost:3000' \
-d 10 \
-c 1024 \
-t 8
kill $pid

23
benchmarks/run_all.sh Normal file
View File

@@ -0,0 +1,23 @@
#!/usr/bin/env bash
: > all_output.txt
lib=(express fastify nest nest-fastify)
for item in ${lib[*]}
do
echo '-----------------------' >> all_output.txt
echo $item >> all_output.txt
echo '-----------------------' >> all_output.txt
node $item &
pid=$!
sleep 2
wrk 'http://localhost:3000' \
-d 10 \
-c 1024 \
-t 8 >> all_output.txt
kill $pid
done

View File

@@ -1,16 +1,117 @@
'use strict';
/**
* Load the TypeScript compiler, then load the TypeScript gulpfile which simply loads all
* the tasks. The tasks are really inside tools/gulp/tasks.
*/
const fs = require('fs');
const path = require('path');
const gulp = require('gulp');
const ts = require('gulp-typescript');
const sourcemaps = require('gulp-sourcemaps');
const clean = require('gulp-clean');
const deleteEmpty = require('delete-empty');
const projectDir = __dirname;
const tsconfigPath = path.join(projectDir, 'tools/gulp/tsconfig.json');
const packages = {
common: ts.createProject('packages/common/tsconfig.json'),
core: ts.createProject('packages/core/tsconfig.json'),
microservices: ts.createProject('packages/microservices/tsconfig.json'),
websockets: ts.createProject('packages/websockets/tsconfig.json'),
testing: ts.createProject('packages/testing/tsconfig.json'),
'platform-express': ts.createProject(
'packages/platform-express/tsconfig.json',
),
'platform-fastify': ts.createProject(
'packages/platform-fastify/tsconfig.json',
),
'platform-socket.io': ts.createProject(
'packages/platform-socket.io/tsconfig.json',
),
'platform-ws': ts.createProject('packages/platform-ws/tsconfig.json'),
};
const modules = Object.keys(packages);
const source = 'packages';
const distId = process.argv.indexOf('--dist');
const dist = distId < 0 ? source : process.argv[distId + 1];
require('ts-node').register({
project: tsconfigPath
gulp.task('default', function() {
modules.forEach(module => {
gulp.watch(
[`${source}/${module}/**/*.ts`, `${source}/${module}/*.ts`],
[module],
);
});
});
require('./tools/gulp/gulpfile');
gulp.task('copy-misc', function() {
return gulp
.src(['Readme.md', 'LICENSE', '.npmignore'])
.pipe(gulp.dest(`${source}/common`))
.pipe(gulp.dest(`${source}/core`))
.pipe(gulp.dest(`${source}/microservices`))
.pipe(gulp.dest(`${source}/websockets`))
.pipe(gulp.dest(`${source}/testing`))
.pipe(gulp.dest(`${source}/platform-fastify`))
.pipe(gulp.dest(`${source}/platform-express`))
.pipe(gulp.dest(`${source}/platform-ws`))
.pipe(gulp.dest(`${source}/platform-socket.io`));
});
gulp.task('clean:output', function() {
return gulp
.src(
[`${source}/**/*.js`, `${source}/**/*.d.ts`, `${source}/**/*.js.map`],
{
read: false,
},
)
.pipe(clean());
});
gulp.task('clean:dirs', function(done) {
deleteEmpty.sync(`${source}/`);
done();
});
gulp.task('clean:bundle', gulp.series('clean:output', 'clean:dirs'));
modules.forEach(module => {
gulp.task(module, () => {
return packages[module]
.src()
.pipe(packages[module]())
.pipe(gulp.dest(`${dist}/${module}`));
});
});
modules.forEach(module => {
gulp.task(module + ':dev', () => {
return packages[module]
.src()
.pipe(sourcemaps.init())
.pipe(packages[module]())
.pipe(
sourcemaps.mapSources(sourcePath => './' + sourcePath.split('/').pop()),
)
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest(`${dist}/${module}`));
});
});
gulp.task('common:dev', gulp.series(modules.map(module => module + ':dev')));
gulp.task('build', gulp.series(modules));
gulp.task('build:dev', gulp.series('common:dev'));
function getFolders(dir) {
return fs.readdirSync(dir).filter(function(file) {
return fs.statSync(path.join(dir, file)).isDirectory();
});
}
gulp.task('move', function() {
const getDirs = base => getFolders(base).map(path => `${base}/${path}`);
const examplesDirs = getDirs('sample');
const integrationDirs = getDirs('integration');
const directories = examplesDirs.concat(integrationDirs);
let stream = gulp.src(['node_modules/@nestjs/**/*']);
directories.forEach(dir => {
stream = stream.pipe(gulp.dest(dir + '/node_modules/@nestjs'));
});
return stream;
});

View File

@@ -1,7 +0,0 @@
export const mochaHooks = (): Mocha.RootHookObject => {
return {
async beforeAll(this: Mocha.Context) {
await import('reflect-metadata');
},
};
};

View File

@@ -1,11 +0,0 @@
import { Injectable } from '@nestjs/common';
import { FooService } from './foo.service';
@Injectable()
export class BarService {
constructor(private readonly foo: FooService) {}
bar() {
this.foo.foo();
}
}

View File

@@ -1,8 +0,0 @@
import { Injectable } from '@nestjs/common';
@Injectable()
export class FooService {
foo() {
console.log('foo called');
}
}

View File

@@ -1,60 +0,0 @@
import { Test } from '@nestjs/testing';
import * as chai from 'chai';
import * as chaiAsPromised from 'chai-as-promised';
import * as sinon from 'sinon';
import { BarService } from '../src/bar.service';
import { FooService } from '../src/foo.service';
chai.use(chaiAsPromised);
const { expect } = chai;
describe('Auto-Mocking Bar Deps', () => {
let service: BarService;
let fooService: FooService;
const stub = sinon.stub();
beforeEach(async () => {
const moduleRef = await Test.createTestingModule({
providers: [BarService],
})
.useMocker(() => ({ foo: stub }))
.compile();
service = moduleRef.get(BarService);
fooService = moduleRef.get(FooService);
});
it('should be defined', () => {
expect(service).not.to.be.undefined;
expect(fooService).not.to.be.undefined;
});
it('should call bar.bar', () => {
service.bar();
expect(stub.called);
});
});
describe('Auto-Mocking with token in factory', () => {
it('can mock the dependencies', async () => {
const moduleRef = await Test.createTestingModule({
providers: [BarService],
})
.useMocker(token => {
if (token === FooService) {
return { foo: sinon.stub };
}
})
.compile();
const service = moduleRef.get(BarService);
const fooServ = moduleRef.get<{ foo: sinon.SinonStub }>(FooService as any);
service.bar();
expect(fooServ.foo.called);
});
it('cannot mock the dependencies', async () => {
const moduleRef = Test.createTestingModule({
providers: [BarService],
}).useMocker(token => {
if (token === FooService.name + 'something that fails the token') {
return { foo: sinon.stub };
}
}).compile;
expect(moduleRef()).to.eventually.throw();
});
});

View File

@@ -1,40 +0,0 @@
{
"compilerOptions": {
"module": "commonjs",
"declaration": false,
"noImplicitAny": false,
"removeComments": true,
"noLib": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "ES2021",
"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",
]
}

View File

@@ -1,177 +0,0 @@
import { NestExpressApplication } from '@nestjs/platform-express';
import { Test } from '@nestjs/testing';
import * as request from 'supertest';
import { AppModule } from '../src/app.module';
describe('Express Cors', () => {
let app: NestExpressApplication;
const configs = [
{
origin: 'example.com',
methods: 'GET',
credentials: true,
exposedHeaders: ['foo', 'bar'],
allowedHeaders: ['baz', 'woo'],
maxAge: 123,
},
{
origin: 'sample.com',
methods: 'GET',
credentials: true,
exposedHeaders: ['zoo', 'bar'],
allowedHeaders: ['baz', 'foo'],
maxAge: 321,
},
];
describe('Dynamic config', () => {
describe('enableCors', () => {
before(async () => {
const module = await Test.createTestingModule({
imports: [AppModule],
}).compile();
app = module.createNestApplication<NestExpressApplication>();
let requestId = 0;
const configDelegation = function (req, cb) {
const config = configs[requestId];
requestId++;
cb(null, config);
};
app.enableCors(configDelegation);
await app.init();
});
it(`should add cors headers based on the first config`, async () => {
return request(app.getHttpServer())
.get('/')
.expect('access-control-allow-origin', 'example.com')
.expect('vary', 'Origin')
.expect('access-control-allow-credentials', 'true')
.expect('access-control-expose-headers', 'foo,bar')
.expect('content-length', '0');
});
it(`should add cors headers based on the second config`, async () => {
return request(app.getHttpServer())
.options('/')
.expect('access-control-allow-origin', 'sample.com')
.expect('vary', 'Origin')
.expect('access-control-allow-credentials', 'true')
.expect('access-control-expose-headers', 'zoo,bar')
.expect('access-control-allow-methods', 'GET')
.expect('access-control-allow-headers', 'baz,foo')
.expect('access-control-max-age', '321')
.expect('content-length', '0');
});
after(async () => {
await app.close();
});
});
describe('Application Options', () => {
before(async () => {
const module = await Test.createTestingModule({
imports: [AppModule],
}).compile();
let requestId = 0;
const configDelegation = function (req, cb) {
const config = configs[requestId];
requestId++;
cb(null, config);
};
app = module.createNestApplication<NestExpressApplication>({
cors: configDelegation,
});
await app.init();
});
it(`should add cors headers based on the first config`, async () => {
return request(app.getHttpServer())
.get('/')
.expect('access-control-allow-origin', 'example.com')
.expect('vary', 'Origin')
.expect('access-control-allow-credentials', 'true')
.expect('access-control-expose-headers', 'foo,bar')
.expect('content-length', '0');
});
it(`should add cors headers based on the second config`, async () => {
return request(app.getHttpServer())
.options('/')
.expect('access-control-allow-origin', 'sample.com')
.expect('vary', 'Origin')
.expect('access-control-allow-credentials', 'true')
.expect('access-control-expose-headers', 'zoo,bar')
.expect('access-control-allow-methods', 'GET')
.expect('access-control-allow-headers', 'baz,foo')
.expect('access-control-max-age', '321')
.expect('content-length', '0');
});
after(async () => {
await app.close();
});
});
});
describe('Static config', () => {
describe('enableCors', () => {
before(async () => {
const module = await Test.createTestingModule({
imports: [AppModule],
}).compile();
app = module.createNestApplication<NestExpressApplication>();
app.enableCors(configs[0]);
await app.init();
});
it(`CORS headers`, async () => {
return request(app.getHttpServer())
.get('/')
.expect('access-control-allow-origin', 'example.com')
.expect('vary', 'Origin')
.expect('access-control-allow-credentials', 'true')
.expect('access-control-expose-headers', 'foo,bar')
.expect('content-length', '0');
});
});
after(async () => {
await app.close();
});
describe('Application Options', () => {
before(async () => {
const module = await Test.createTestingModule({
imports: [AppModule],
}).compile();
app = module.createNestApplication<NestExpressApplication>({
cors: configs[0],
});
await app.init();
});
it(`CORS headers`, async () => {
return request(app.getHttpServer())
.get('/')
.expect('access-control-allow-origin', 'example.com')
.expect('vary', 'Origin')
.expect('access-control-allow-credentials', 'true')
.expect('access-control-expose-headers', 'foo,bar')
.expect('content-length', '0');
});
after(async () => {
await app.close();
});
});
});
});

View File

@@ -1,191 +0,0 @@
import {
FastifyAdapter,
NestFastifyApplication,
} from '@nestjs/platform-fastify';
import { Test } from '@nestjs/testing';
import * as request from 'supertest';
import { AppModule } from '../src/app.module';
describe.skip('Fastify Cors', () => {
let app: NestFastifyApplication;
const configs = [
{
origin: 'example.com',
methods: 'GET',
credentials: true,
exposedHeaders: ['foo', 'bar'],
allowedHeaders: ['baz', 'woo'],
maxAge: 123,
},
{
origin: 'sample.com',
methods: 'GET',
credentials: true,
exposedHeaders: ['zoo', 'bar'],
allowedHeaders: ['baz', 'foo'],
maxAge: 321,
},
];
describe('Dynamic config', () => {
describe('enableCors', () => {
before(async () => {
const module = await Test.createTestingModule({
imports: [AppModule],
}).compile();
app = module.createNestApplication<NestFastifyApplication>(
new FastifyAdapter(),
);
let requestId = 0;
const configDelegation = function (req, cb) {
const config = configs[requestId];
requestId++;
cb(null, config);
};
app.enableCors(configDelegation);
await app.init();
});
it(`should add cors headers based on the first config`, async () => {
return request(app.getHttpServer())
.get('/')
.expect('access-control-allow-origin', 'example.com')
.expect('vary', 'Origin')
.expect('access-control-allow-credentials', 'true')
.expect('access-control-expose-headers', 'foo,bar')
.expect('content-length', '0');
});
it(`should add cors headers based on the second config`, async () => {
return request(app.getHttpServer())
.options('/')
.expect('access-control-allow-origin', 'sample.com')
.expect('vary', 'Origin')
.expect('access-control-allow-credentials', 'true')
.expect('access-control-expose-headers', 'zoo,bar')
.expect('access-control-allow-methods', 'GET')
.expect('access-control-allow-headers', 'baz,foo')
.expect('access-control-max-age', '321')
.expect('content-length', '0');
});
after(async () => {
await app.close();
});
});
describe('Application Options', () => {
before(async () => {
const module = await Test.createTestingModule({
imports: [AppModule],
}).compile();
let requestId = 0;
const configDelegation = function (req, cb) {
const config = configs[requestId];
requestId++;
cb(null, config);
};
app = module.createNestApplication<NestFastifyApplication>(
new FastifyAdapter(),
{
cors: configDelegation,
},
);
await app.init();
});
it(`should add cors headers based on the first config`, async () => {
return request(app.getHttpServer())
.get('/')
.expect('access-control-allow-origin', 'example.com')
.expect('vary', 'Origin')
.expect('access-control-allow-credentials', 'true')
.expect('access-control-expose-headers', 'foo,bar')
.expect('content-length', '0');
});
it(`should add cors headers based on the second config`, async () => {
return request(app.getHttpServer())
.options('/')
.expect('access-control-allow-origin', 'sample.com')
.expect('vary', 'Origin')
.expect('access-control-allow-credentials', 'true')
.expect('access-control-expose-headers', 'zoo,bar')
.expect('access-control-allow-methods', 'GET')
.expect('access-control-allow-headers', 'baz,foo')
.expect('access-control-max-age', '321')
.expect('content-length', '0');
});
after(async () => {
await app.close();
});
});
});
describe('Static config', () => {
describe('enableCors', () => {
before(async () => {
const module = await Test.createTestingModule({
imports: [AppModule],
}).compile();
app = module.createNestApplication<NestFastifyApplication>(
new FastifyAdapter(),
);
app.enableCors(configs[0]);
await app.init();
});
it(`CORS headers`, async () => {
return request(app.getHttpServer())
.get('/')
.expect('access-control-allow-origin', 'example.com')
.expect('vary', 'Origin')
.expect('access-control-allow-credentials', 'true')
.expect('access-control-expose-headers', 'foo,bar')
.expect('content-length', '0');
});
});
after(async () => {
await app.close();
});
describe('Application Options', () => {
before(async () => {
const module = await Test.createTestingModule({
imports: [AppModule],
}).compile();
app = module.createNestApplication<NestFastifyApplication>(
new FastifyAdapter(),
{
cors: configs[0],
},
);
await app.init();
});
it(`CORS headers`, async () => {
return request(app.getHttpServer())
.get('/')
.expect('access-control-allow-origin', 'example.com')
.expect('vary', 'Origin')
.expect('access-control-allow-credentials', 'true')
.expect('access-control-expose-headers', 'foo,bar')
.expect('content-length', '0');
});
});
after(async () => {
await app.close();
});
});
});

View File

@@ -1,9 +0,0 @@
import { Controller, Get } from '@nestjs/common';
@Controller()
export class AppController {
@Get()
getGlobals() {
return '';
}
}

View File

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

View File

@@ -1,40 +0,0 @@
{
"compilerOptions": {
"module": "commonjs",
"declaration": false,
"noImplicitAny": false,
"removeComments": true,
"noLib": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "ES2021",
"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",
]
}

View File

@@ -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([]);
});
});

View File

@@ -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 {}

View File

@@ -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();

View File

@@ -1,6 +0,0 @@
import { DiscoveryService } from '@nestjs/core';
export const Webhook = DiscoveryService.createDecorator<{ name: string }>();
export const WebhookHandler = DiscoveryService.createDecorator<{
event: string;
}>();

View File

@@ -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');
}
}

View File

@@ -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');
}
}

View File

@@ -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 {}

View File

@@ -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,
};
}),
};
});
}
}

View File

@@ -1,40 +0,0 @@
{
"compilerOptions": {
"module": "commonjs",
"declaration": false,
"noImplicitAny": false,
"removeComments": true,
"noLib": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "ES2021",
"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",
]
}

View File

@@ -17,15 +17,14 @@ services:
restart: always
mqtt:
container_name: test-mqtt
image: eclipse-mosquitto
volumes:
- ./mosquitto.conf:/mosquitto/config/mosquitto.conf
image: toke/mosquitto
ports:
- "1883:1883"
- "9001:9001"
restart: always
mysql:
image: mysql:8.3.0
image: mysql:5.7.22
restart: always
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: test
@@ -33,43 +32,15 @@ services:
- "3306:3306"
restart: always
mongodb:
container_name: test-mongodb
image: mongo:latest
environment:
- MONGODB_DATABASE="test"
ports:
- 27017:27017
rabbit:
container_name: test-rabbit
hostname: rabbit
image: "rabbitmq:management"
ports:
- "15672:15672"
- "5672:5672"
tty: true
zookeeper:
container_name: test-zookeeper
hostname: zookeeper
image: confluentinc/cp-zookeeper:7.5.3
ports:
- "2181:2181"
environment:
ZOOKEEPER_CLIENT_PORT: 2181
ZOOKEEPER_TICK_TIME: 2000
kafka:
container_name: test-kafka
hostname: kafka
image: confluentinc/cp-kafka:7.5.3
depends_on:
- zookeeper
ports:
- "29092:29092"
- "9092:9092"
environment:
KAFKA_BROKER_ID: 1
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0
KAFKA_DELETE_TOPIC_ENABLE: 'true'
tty: true

View File

@@ -1,36 +0,0 @@
import { INestApplication } from '@nestjs/common';
import { Test } from '@nestjs/testing';
import * as request from 'supertest';
import { AppModule } from '../src/app.module';
describe('GraphQL - Code-first', () => {
let app: INestApplication;
beforeEach(async () => {
const module = await Test.createTestingModule({
imports: [AppModule],
}).compile();
app = module.createNestApplication();
await app.init();
});
it(`should return query result`, () => {
return request(app.getHttpServer())
.post('/graphql')
.send({
operationName: null,
variables: {},
query: '{\n recipes {\n id\n }\n}\n',
})
.expect(200, {
data: {
recipes: [],
},
});
});
afterEach(async () => {
await app.close();
});
});

View File

@@ -1,49 +0,0 @@
import { INestApplication } from '@nestjs/common';
import { Test } from '@nestjs/testing';
import * as request from 'supertest';
import { AppModule } from '../src/app.module';
describe('GraphQL - Guards', () => {
let app: INestApplication;
beforeEach(async () => {
const module = await Test.createTestingModule({
imports: [AppModule],
}).compile();
app = module.createNestApplication();
await app.init();
});
it(`should throw an error`, () => {
return request(app.getHttpServer())
.post('/graphql')
.send({
operationName: null,
variables: {},
query: '{\n recipe(id: "3") {\n id\n }\n}\n',
})
.expect(200, {
data: null,
errors: [
{
message: 'Unauthorized error',
locations: [
{
line: 2,
column: 3,
},
],
path: ['recipe'],
extensions: {
code: 'INTERNAL_SERVER_ERROR',
},
},
],
});
});
afterEach(async () => {
await app.close();
});
});

View File

@@ -1,58 +0,0 @@
import { INestApplication, ValidationPipe } from '@nestjs/common';
import { Test } from '@nestjs/testing';
import * as request from 'supertest';
import { AppModule } from '../src/app.module';
describe('GraphQL Pipes', () => {
let app: INestApplication;
beforeEach(async () => {
const module = await Test.createTestingModule({
imports: [AppModule],
}).compile();
app = module.createNestApplication();
app.useGlobalPipes(new ValidationPipe());
await app.init();
});
it(`should throw an error`, () => {
return request(app.getHttpServer())
.post('/graphql')
.send({
operationName: null,
variables: {},
query:
'mutation {\n addRecipe(newRecipeData: {title: "test", ingredients: []}) {\n id\n }\n}\n',
})
.expect(200, {
data: null,
errors: [
{
extensions: {
code: 'BAD_REQUEST',
originalError: {
error: 'Bad Request',
message: [
'description must be longer than or equal to 30 characters',
],
statusCode: 400,
},
},
locations: [
{
column: 3,
line: 2,
},
],
message: 'Bad Request Exception',
path: ['addRecipe'],
},
],
});
});
afterEach(async () => {
await app.close();
});
});

View File

@@ -1,34 +0,0 @@
# ------------------------------------------------------
# THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY)
# ------------------------------------------------------
type Recipe {
id: ID!
title: String!
description: String
creationDate: Date!
ingredients: [String!]!
}
"""Date custom scalar type"""
scalar Date
type Query {
recipe(id: String!): Recipe!
recipes(skip: Int! = 0, take: Int! = 25): [Recipe!]!
}
type Mutation {
addRecipe(newRecipeData: NewRecipeInput!): Recipe!
removeRecipe(id: String!): Boolean!
}
input NewRecipeInput {
title: String!
description: String
ingredients: [String!]!
}
type Subscription {
recipeAdded: Recipe!
}

View File

@@ -1,21 +0,0 @@
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
import { Module } from '@nestjs/common';
import { GraphQLModule } from '@nestjs/graphql';
import { join } from 'path';
import { RecipesModule } from './recipes/recipes.module';
@Module({
imports: [
RecipesModule,
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
includeStacktraceInErrorResponses: false,
installSubscriptionHandlers: true,
autoSchemaFile: join(
process.cwd(),
'integration/graphql-code-first/schema.gql',
),
}),
],
})
export class AppModule {}

View File

@@ -1,9 +0,0 @@
import { ArgumentsHost, Catch, UnauthorizedException } from '@nestjs/common';
import { GqlExceptionFilter } from '@nestjs/graphql';
@Catch(UnauthorizedException)
export class UnauthorizedFilter implements GqlExceptionFilter {
catch(exception: any, host: ArgumentsHost) {
return new Error('Unauthorized error');
}
}

View File

@@ -1,18 +0,0 @@
import {
CanActivate,
ExecutionContext,
Injectable,
UnauthorizedException,
} from '@nestjs/common';
import { GqlExecutionContext } from '@nestjs/graphql';
@Injectable()
export class AuthGuard implements CanActivate {
async canActivate(context: ExecutionContext): Promise<boolean> {
const gqlContext = GqlExecutionContext.create(context);
if (gqlContext) {
throw new UnauthorizedException();
}
return true;
}
}

View File

@@ -1,15 +0,0 @@
import {
CallHandler,
ExecutionContext,
Injectable,
NestInterceptor,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
@Injectable()
export class DataInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
return next.handle().pipe(tap(data => data));
}
}

View File

@@ -1,18 +0,0 @@
import { Field, InputType } from '@nestjs/graphql';
import { Type } from 'class-transformer';
import { Length, MaxLength } from 'class-validator';
@InputType()
export class NewRecipeInput {
@Field()
@MaxLength(30)
title: string;
@Field({ nullable: true })
@Length(30, 255)
description?: string;
@Type(() => String)
@Field(type => [String])
ingredients: string[];
}

View File

@@ -1,14 +0,0 @@
import { ArgsType, Field, Int } from '@nestjs/graphql';
import { Max, Min } from 'class-validator';
@ArgsType()
export class RecipesArgs {
@Field(type => Int)
@Min(0)
skip = 0;
@Field(type => Int)
@Min(1)
@Max(50)
take = 25;
}

View File

@@ -1,19 +0,0 @@
import { Field, ID, ObjectType } from '@nestjs/graphql';
@ObjectType()
export class Recipe {
@Field(type => ID)
id: string;
@Field()
title: string;
@Field({ nullable: true })
description?: string;
@Field()
creationDate: Date;
@Field(type => [String])
ingredients: string[];
}

View File

@@ -1,19 +0,0 @@
import { Module } from '@nestjs/common';
import { APP_FILTER } from '@nestjs/core';
import { UnauthorizedFilter } from '../common/filters/unauthorized.filter';
import { DateScalar } from '../common/scalars/date.scalar';
import { RecipesResolver } from './recipes.resolver';
import { RecipesService } from './recipes.service';
@Module({
providers: [
RecipesResolver,
RecipesService,
DateScalar,
{
provide: APP_FILTER,
useClass: UnauthorizedFilter,
},
],
})
export class RecipesModule {}

View File

@@ -1,51 +0,0 @@
import { NotFoundException, UseGuards, UseInterceptors } from '@nestjs/common';
import { Args, Mutation, Query, Resolver, Subscription } from '@nestjs/graphql';
import { PubSub } from 'graphql-subscriptions';
import { AuthGuard } from '../common/guards/auth.guard';
import { DataInterceptor } from '../common/interceptors/data.interceptor';
import { NewRecipeInput } from './dto/new-recipe.input';
import { RecipesArgs } from './dto/recipes.args';
import { Recipe } from './models/recipe';
import { RecipesService } from './recipes.service';
const pubSub = new PubSub();
@UseInterceptors(DataInterceptor)
@Resolver(of => Recipe)
export class RecipesResolver {
constructor(private readonly recipesService: RecipesService) {}
@UseGuards(AuthGuard)
@Query(returns => Recipe)
async recipe(@Args('id') id: string): Promise<Recipe> {
const recipe = await this.recipesService.findOneById(id);
if (!recipe) {
throw new NotFoundException(id);
}
return recipe;
}
@Query(returns => [Recipe])
recipes(@Args() recipesArgs: RecipesArgs): Promise<Recipe[]> {
return this.recipesService.findAll(recipesArgs);
}
@Mutation(returns => Recipe)
async addRecipe(
@Args('newRecipeData') newRecipeData: NewRecipeInput,
): Promise<Recipe> {
const recipe = await this.recipesService.create(newRecipeData);
pubSub.publish('recipeAdded', { recipeAdded: recipe });
return recipe;
}
@Mutation(returns => Boolean)
async removeRecipe(@Args('id') id: string) {
return this.recipesService.remove(id);
}
@Subscription(returns => Recipe)
recipeAdded() {
return pubSub.asyncIterator('recipeAdded');
}
}

View File

@@ -1,31 +0,0 @@
import { Injectable } from '@nestjs/common';
import { NewRecipeInput } from './dto/new-recipe.input';
import { RecipesArgs } from './dto/recipes.args';
import { Recipe } from './models/recipe';
@Injectable()
export class RecipesService {
/**
* MOCK
* Put some real business logic here
* Left for demonstration purposes
*/
async create(data: NewRecipeInput): Promise<Recipe> {
return {
id: 3,
} as any;
}
async findOneById(id: string): Promise<Recipe> {
return {} as any;
}
async findAll(recipesArgs: RecipesArgs): Promise<Recipe[]> {
return [] as Recipe[];
}
async remove(id: string): Promise<boolean> {
return true;
}
}

View File

@@ -1,40 +0,0 @@
{
"compilerOptions": {
"module": "commonjs",
"declaration": false,
"noImplicitAny": false,
"removeComments": true,
"noLib": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "ES2021",
"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",
]
}

View File

@@ -1,62 +0,0 @@
import { ApolloDriver } from '@nestjs/apollo';
import { INestApplication } from '@nestjs/common';
import { GraphQLModule } from '@nestjs/graphql';
import { Test } from '@nestjs/testing';
import { expect } from 'chai';
import { join } from 'path';
import * as request from 'supertest';
import { CatsRequestScopedService } from '../src/cats/cats-request-scoped.service';
import { CatsModule } from '../src/cats/cats.module';
describe('GraphQL request scoped', () => {
let app: INestApplication;
beforeEach(async () => {
const module = await Test.createTestingModule({
imports: [
CatsModule.enableRequestScope(),
GraphQLModule.forRoot({
driver: ApolloDriver,
typePaths: [join(__dirname, '..', 'src', '**', '*.graphql')],
}),
],
}).compile();
app = module.createNestApplication();
await app.init();
const performHttpCall = end =>
request(app.getHttpServer())
.post('/graphql')
.send({
operationName: null,
variables: {},
query: '{\n getCats {\n id\n }\n}\n',
})
.expect(200, {
data: {
getCats: [
{
id: 1,
},
],
},
})
.end((err, res) => {
if (err) return end(err);
end();
});
await new Promise(resolve => performHttpCall(resolve));
await new Promise(resolve => performHttpCall(resolve));
await new Promise(resolve => performHttpCall(resolve));
});
it(`should create resolver for each incoming request`, () => {
expect(CatsRequestScopedService.COUNTER).to.be.eql(3);
});
afterEach(async () => {
await app.close();
});
});

View File

@@ -1,25 +0,0 @@
import { Injectable, Scope } from '@nestjs/common';
import { Cat } from './interfaces/cat.interface';
@Injectable({ scope: Scope.REQUEST })
export class CatsRequestScopedService {
static COUNTER = 0;
private readonly cats: Cat[] = [{ id: 1, name: 'Cat', age: 5 }];
constructor() {
CatsRequestScopedService.COUNTER++;
}
create(cat: Cat): Cat {
this.cats.push(cat);
return cat;
}
findAll(): Cat[] {
return this.cats;
}
findOneById(id: number): Cat {
return this.cats.find(cat => cat.id === id);
}
}

View File

@@ -1,22 +0,0 @@
import { DynamicModule, Module, Scope } from '@nestjs/common';
import { CatsRequestScopedService } from './cats-request-scoped.service';
import { CatsResolvers } from './cats.resolvers';
import { CatsService } from './cats.service';
@Module({
providers: [CatsService, CatsResolvers],
})
export class CatsModule {
static enableRequestScope(): DynamicModule {
return {
module: CatsModule,
providers: [
{
provide: CatsService,
useClass: CatsRequestScopedService,
scope: Scope.REQUEST,
},
],
};
}
}

View File

@@ -1,40 +0,0 @@
{
"compilerOptions": {
"module": "commonjs",
"declaration": false,
"noImplicitAny": false,
"removeComments": true,
"noLib": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "ES2021",
"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",
]
}

View File

@@ -1,4 +1,4 @@
import { INestApplication } from '@nestjs/common';
/*import { INestApplication } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import * as request from 'supertest';
import { AsyncClassApplicationModule } from '../src/async-options-class.module';
@@ -36,3 +36,4 @@ describe('GraphQL (async class)', () => {
await app.close();
});
});
*/

View File

@@ -1,4 +1,4 @@
import { INestApplication } from '@nestjs/common';
/*import { INestApplication } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import * as request from 'supertest';
import { AsyncExistingApplicationModule } from '../src/async-options-existing.module';
@@ -36,3 +36,4 @@ describe('GraphQL (async existing)', () => {
await app.close();
});
});
*/

View File

@@ -1,4 +1,4 @@
import { INestApplication } from '@nestjs/common';
/*import { INestApplication } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import * as request from 'supertest';
import { AsyncApplicationModule } from '../src/async-options.module';
@@ -34,3 +34,4 @@ describe('GraphQL (async configuration)', () => {
await app.close();
});
});
*/

View File

@@ -1,14 +1,14 @@
import { INestApplication } from '@nestjs/common';
/*import { INestApplication } from '@nestjs/common';
import { Test } from '@nestjs/testing';
import * as request from 'supertest';
import { AppModule } from '../src/app.module';
import { ApplicationModule } from '../src/app.module';
describe('GraphQL', () => {
let app: INestApplication;
beforeEach(async () => {
const module = await Test.createTestingModule({
imports: [AppModule],
imports: [ApplicationModule],
}).compile();
app = module.createNestApplication();
@@ -38,3 +38,4 @@ describe('GraphQL', () => {
await app.close();
});
});
*/

1959
integration/graphql/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,29 @@
{
"name": "nest-typescript-starter",
"version": "1.0.0",
"description": "Nest TypeScript starter repository",
"license": "MIT",
"scripts": {
"start": "ts-node src/main",
"prestart:prod": "tsc",
"start:prod": "node dist/main.js"
},
"dependencies": {
"@nestjs/common": "^5.1.0",
"@nestjs/core": "^5.1.0",
"@nestjs/graphql": "^5.0.0",
"apollo-server-express": "^2.0.4",
"graphql": "^0.13.2",
"graphql-tools": "^2.11.0",
"reflect-metadata": "^0.1.12",
"rxjs": "^6.0.0",
"subscriptions-transport-ws": "^0.9.5",
"typescript": "^3.1.0",
"ws": "^4.0.0"
},
"devDependencies": {
"@types/node": "^7.0.41",
"ts-node": "^6.0.0",
"tslint": "^5.9.1"
}
}

View File

@@ -1,4 +1,3 @@
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
import { Module } from '@nestjs/common';
import { GraphQLModule } from '@nestjs/graphql';
import { join } from 'path';
@@ -7,11 +6,9 @@ import { CatsModule } from './cats/cats.module';
@Module({
imports: [
CatsModule,
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
includeStacktraceInErrorResponses: true,
GraphQLModule.forRoot({
typePaths: [join(__dirname, '**', '*.graphql')],
}),
],
})
export class AppModule {}
export class ApplicationModule {}

View File

@@ -1,11 +1,14 @@
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
import { Module } from '@nestjs/common';
import { GqlOptionsFactory, GraphQLModule } from '@nestjs/graphql';
import {
GqlModuleOptions,
GqlOptionsFactory,
GraphQLModule,
} from '@nestjs/graphql';
import { join } from 'path';
import { CatsModule } from './cats/cats.module';
class ConfigService implements GqlOptionsFactory {
createGqlOptions(): ApolloDriverConfig {
createGqlOptions(): GqlModuleOptions {
return {
typePaths: [join(__dirname, '**', '*.graphql')],
};
@@ -15,8 +18,7 @@ class ConfigService implements GqlOptionsFactory {
@Module({
imports: [
CatsModule,
GraphQLModule.forRootAsync<ApolloDriverConfig>({
driver: ApolloDriver,
GraphQLModule.forRootAsync({
useClass: ConfigService,
}),
],

View File

@@ -1,4 +1,3 @@
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
import { Module } from '@nestjs/common';
import { GraphQLModule } from '@nestjs/graphql';
import { CatsModule } from './cats/cats.module';
@@ -8,8 +7,7 @@ import { ConfigService } from './config.service';
@Module({
imports: [
CatsModule,
GraphQLModule.forRootAsync<ApolloDriverConfig>({
driver: ApolloDriver,
GraphQLModule.forRootAsync({
imports: [ConfigModule],
useExisting: ConfigService,
}),

View File

@@ -1,4 +1,3 @@
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
import { Module } from '@nestjs/common';
import { GraphQLModule } from '@nestjs/graphql';
import { join } from 'path';
@@ -7,8 +6,7 @@ import { CatsModule } from './cats/cats.module';
@Module({
imports: [
CatsModule,
GraphQLModule.forRootAsync<ApolloDriverConfig>({
driver: ApolloDriver,
GraphQLModule.forRootAsync({
useFactory: async () => ({
typePaths: [join(__dirname, '**', '*.graphql')],
}),

View File

@@ -0,0 +1,8 @@
import { Module } from '@nestjs/common';
import { CatsService } from './cats.service';
import { CatsResolvers } from './cats.resolvers';
@Module({
providers: [CatsService, CatsResolvers],
})
export class CatsModule {}

View File

@@ -14,7 +14,7 @@ export class CatsResolvers {
@Query()
@UseGuards(CatsGuard)
async getCats() {
return this.catsService.findAll();
return await this.catsService.findAll();
}
@Query('cat')
@@ -22,7 +22,7 @@ export class CatsResolvers {
@Args('id', ParseIntPipe)
id: number,
): Promise<Cat> {
return this.catsService.findOneById(id);
return await this.catsService.findOneById(id);
}
@Mutation('createCat')
@@ -34,6 +34,8 @@ export class CatsResolvers {
@Subscription('catCreated')
catCreated() {
return pubSub.asyncIterator('catCreated');
return {
subscribe: () => pubSub.asyncIterator('catCreated'),
};
}
}

View File

@@ -3,13 +3,8 @@ import { Cat } from './interfaces/cat.interface';
@Injectable()
export class CatsService {
static COUNTER = 0;
private readonly cats: Cat[] = [{ id: 1, name: 'Cat', age: 5 }];
constructor() {
CatsService.COUNTER++;
}
create(cat: Cat): Cat {
this.cats.push(cat);
return cat;

View File

@@ -1,19 +1,19 @@
import { Scalar } from '@nestjs/graphql';
import { Kind, ValueNode } from 'graphql';
import { Scalar } from '@nestjs/graphql/dist/decorators/resolvers.decorators';
import { Kind } from 'graphql';
@Scalar('Date', type => Date)
@Scalar('Date')
export class DateScalar {
description = 'Date custom scalar type';
parseValue(value: any) {
parseValue(value) {
return new Date(value); // value from the client
}
serialize(value: any) {
serialize(value) {
return value.getTime(); // value sent to the client
}
parseLiteral(ast: ValueNode) {
parseLiteral(ast) {
if (ast.kind === Kind.INT) {
return parseInt(ast.value, 10); // ast value is always in string format
}

View File

@@ -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();

View File

@@ -4,20 +4,19 @@
"declaration": false,
"noImplicitAny": false,
"removeComments": true,
"lib": ["dom"],
"noLib": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "ES2021",
"target": "es6",
"sourceMap": true,
"allowJs": true,
"outDir": "./dist"
},
"include": [
"src/**/*",
"e2e/**/*"
"src/**/*"
],
"exclude": [
"node_modules"
"node_modules",
"**/*.spec.ts"
]
}
}

View File

@@ -0,0 +1,54 @@
{
"defaultSeverity": "error",
"extends": [
"tslint:recommended"
],
"jsRules": {
"no-unused-expression": true
},
"rules": {
"eofline": false,
"quotemark": [
true,
"single"
],
"indent": false,
"ordered-imports": [
false
],
"max-line-length": [
150
],
"member-ordering": [
false
],
"curly": false,
"interface-name": [
false
],
"array-type": [
false
],
"member-access": [
false
],
"no-empty-interface": false,
"no-empty": false,
"arrow-parens": false,
"object-literal-sort-keys": false,
"no-unused-expression": false,
"max-classes-per-file": [
false
],
"variable-name": [
false
],
"one-line": [
false
],
"one-variable-per-declaration": [
false
]
},
"rulesDirectory": []
}

View File

@@ -1,135 +1,46 @@
import { 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 { Test } from '@nestjs/testing';
import { INestApplication, HttpStatus } from '@nestjs/common';
import { ErrorsController } from '../src/errors/errors.controller';
describe('Error messages', () => {
let server: RawServerDefault;
let server;
let app: INestApplication;
describe('Express', () => {
let app: INestApplication;
beforeEach(async () => {
const module = await Test.createTestingModule({
controllers: [ErrorsController],
}).compile();
beforeEach(async () => {
const module = await Test.createTestingModule({
controllers: [ErrorsController],
})
.compile();
app = module.createNestApplication();
server = app.getHttpServer();
await app.init();
});
it(`/GET`, () => {
return request(server)
.get('/sync')
.expect(HttpStatus.BAD_REQUEST)
.expect({
statusCode: 400,
error: 'Bad Request',
message: 'Integration test',
});
});
it(`/GET (Promise/async)`, () => {
return request(server)
.get('/async')
.expect(HttpStatus.BAD_REQUEST)
.expect({
statusCode: 400,
error: 'Bad Request',
message: 'Integration test',
});
});
it(`/GET (InternalServerError despite custom content-type)`, async () => {
return request(server)
.get('/unexpected-error')
.expect(HttpStatus.INTERNAL_SERVER_ERROR)
.expect({
statusCode: 500,
message: 'Internal server error',
});
});
afterEach(async () => {
await app.close();
});
app = module.createNestApplication();
server = app.getHttpServer();
await app.init();
});
describe('Fastify', () => {
let app: NestFastifyApplication;
beforeEach(async () => {
const module = await Test.createTestingModule({
controllers: [ErrorsController],
}).compile();
it(`/GET`, () => {
return request(server)
.get('/sync')
.expect(HttpStatus.BAD_REQUEST)
.expect({
statusCode: 400,
error: 'Bad Request',
message: 'Integration test'
});
});
app = module.createNestApplication<NestFastifyApplication>(
new FastifyAdapter(),
);
server = app.getHttpServer();
await app.init();
});
it(`/GET (Promise/async)`, () => {
return request(server)
.get('/async')
.expect(HttpStatus.BAD_REQUEST)
.expect({
statusCode: 400,
error: 'Bad Request',
message: 'Integration test'
});
});
it(`/GET`, async () => {
return app
.inject({
method: 'GET',
url: '/sync',
})
.then(({ payload, statusCode }) => {
expect(statusCode).to.equal(HttpStatus.BAD_REQUEST);
expect(payload).to.equal(
JSON.stringify({
statusCode: 400,
error: 'Bad Request',
message: 'Integration test',
}),
);
});
});
it(`/GET (Promise/async)`, async () => {
return app
.inject({
method: 'GET',
url: '/sync',
})
.then(({ payload, statusCode }) => {
expect(statusCode).to.equal(HttpStatus.BAD_REQUEST);
expect(payload).to.equal(
JSON.stringify({
statusCode: 400,
error: 'Bad Request',
message: 'Integration test',
}),
);
});
});
it(`/GET (InternalServerError despite custom content-type)`, async () => {
return app
.inject({
method: 'GET',
url: '/unexpected-error',
})
.then(({ payload, statusCode }) => {
expect(statusCode).to.equal(HttpStatus.INTERNAL_SERVER_ERROR);
expect(payload).to.equal(
JSON.stringify({
statusCode: 500,
message: 'Internal server error',
}),
);
});
});
afterEach(async () => {
await app.close();
});
afterEach(async () => {
await app.close();
});
});

View File

@@ -1,132 +0,0 @@
import {
Controller,
Get,
INestApplication,
MiddlewareConsumer,
Module,
Post,
RequestMethod,
} from '@nestjs/common';
import {
FastifyAdapter,
NestFastifyApplication,
} from '@nestjs/platform-fastify';
import { Test } from '@nestjs/testing';
import * as request from 'supertest';
import { AppModule } from '../src/app.module';
const RETURN_VALUE = 'test';
const MIDDLEWARE_VALUE = 'middleware';
@Controller()
class TestController {
@Get('test')
test() {
return RETURN_VALUE;
}
@Get('test/test')
testTest() {
return RETURN_VALUE;
}
@Get('test2')
test2() {
return RETURN_VALUE;
}
@Get('middleware')
middleware() {
return RETURN_VALUE;
}
@Post('middleware')
noMiddleware() {
return RETURN_VALUE;
}
@Get('wildcard/overview')
testOverview() {
return RETURN_VALUE;
}
@Get('overview/:id')
overviewById() {
return RETURN_VALUE;
}
}
@Module({
imports: [AppModule],
controllers: [TestController],
})
class TestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply((req, res, next) => res.end(MIDDLEWARE_VALUE))
.exclude('test', 'overview/:id', 'wildcard/(.*)', {
path: 'middleware',
method: RequestMethod.POST,
})
.forRoutes('*');
}
}
describe('Exclude middleware (fastify)', () => {
let app: INestApplication;
beforeEach(async () => {
app = (
await Test.createTestingModule({
imports: [TestModule],
}).compile()
).createNestApplication<NestFastifyApplication>(new FastifyAdapter());
await app.init();
await app.getHttpAdapter().getInstance().ready();
});
it(`should exclude "/test" endpoint`, () => {
return request(app.getHttpServer()).get('/test').expect(200, RETURN_VALUE);
});
it(`should not exclude "/test/test" endpoint`, () => {
return request(app.getHttpServer())
.get('/test/test')
.expect(200, MIDDLEWARE_VALUE);
});
it(`should not exclude "/test2" endpoint`, () => {
return request(app.getHttpServer())
.get('/test2')
.expect(200, MIDDLEWARE_VALUE);
});
it(`should run middleware for "/middleware" endpoint`, () => {
return request(app.getHttpServer())
.get('/middleware')
.expect(200, MIDDLEWARE_VALUE);
});
it(`should exclude POST "/middleware" endpoint`, () => {
return request(app.getHttpServer())
.post('/middleware')
.expect(201, RETURN_VALUE);
});
it(`should exclude "/overview/:id" endpoint (by param)`, () => {
return request(app.getHttpServer())
.get('/overview/1')
.expect(200, RETURN_VALUE);
});
it(`should exclude "/wildcard/overview" endpoint (by wildcard)`, () => {
return request(app.getHttpServer())
.get('/wildcard/overview')
.expect(200, RETURN_VALUE);
});
afterEach(async () => {
await app.close();
});
});

View File

@@ -1,128 +0,0 @@
import {
Controller,
Get,
INestApplication,
MiddlewareConsumer,
Module,
Post,
RequestMethod,
} from '@nestjs/common';
import { Test } from '@nestjs/testing';
import * as request from 'supertest';
import { AppModule } from '../src/app.module';
const RETURN_VALUE = 'test';
const MIDDLEWARE_VALUE = 'middleware';
@Controller()
class TestController {
@Get('test')
test() {
return RETURN_VALUE;
}
@Get('test2')
test2() {
return RETURN_VALUE;
}
@Get('middleware')
middleware() {
return RETURN_VALUE;
}
@Post('middleware')
noMiddleware() {
return RETURN_VALUE;
}
@Get('wildcard/overview')
testOverview() {
return RETURN_VALUE;
}
@Get('overview/:id')
overviewById() {
return RETURN_VALUE;
}
@Get('multiple/exclude')
multipleExclude() {
return RETURN_VALUE;
}
}
@Module({
imports: [AppModule],
controllers: [TestController],
})
class TestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply((req, res, next) => res.send(MIDDLEWARE_VALUE))
.exclude('test', 'overview/:id', 'wildcard/(.*)', {
path: 'middleware',
method: RequestMethod.POST,
})
.exclude('multiple/exclude')
.forRoutes('*');
}
}
describe('Exclude middleware', () => {
let app: INestApplication;
beforeEach(async () => {
app = (
await Test.createTestingModule({
imports: [TestModule],
}).compile()
).createNestApplication();
await app.init();
});
it(`should exclude "/test" endpoint`, () => {
return request(app.getHttpServer()).get('/test').expect(200, RETURN_VALUE);
});
it(`should not exclude "/test2" endpoint`, () => {
return request(app.getHttpServer())
.get('/test2')
.expect(200, MIDDLEWARE_VALUE);
});
it(`should run middleware for "/middleware" endpoint`, () => {
return request(app.getHttpServer())
.get('/middleware')
.expect(200, MIDDLEWARE_VALUE);
});
it(`should exclude POST "/middleware" endpoint`, () => {
return request(app.getHttpServer())
.post('/middleware')
.expect(201, RETURN_VALUE);
});
it(`should exclude "/overview/:id" endpoint (by param)`, () => {
return request(app.getHttpServer())
.get('/overview/1')
.expect(200, RETURN_VALUE);
});
it(`should exclude "/wildcard/overview" endpoint (by wildcard)`, () => {
return request(app.getHttpServer())
.get('/wildcard/overview')
.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();
});
});

Some files were not shown because too many files have changed in this diff Show More